/* ============================================================================
   PayFlow — shared stylesheet
   ----------------------------------------------------------------------------
   Loaded by every surface: landing, checkout, merchant dashboard, admin.
   Surface-specific rules live in their own files (checkout.css, dashboard.css)
   so a phone loading the payment page does not download the admin panel's CSS.

   Written by hand, no build step: the deployment story is "upload the files".
   Custom properties are the whole theming system — change the tokens below and
   every surface follows.
   ========================================================================= */

/* ------------------------------------------------------------------ tokens */
:root {
    /* Brand. One hue, used sparingly — money pages should look calm. */
    --brand:            #1f4fd8;
    --brand-dark:       #1a41b0;
    --brand-light:      #eaf0ff;
    --brand-contrast:   #ffffff;

    /* Semantic tones, matching status_tone() in the view helpers. */
    --ok:               #0f8a4d;
    --ok-bg:            #e6f6ed;
    --warn:             #b45309;
    --warn-bg:          #fef3e2;
    --bad:              #c0342c;
    --bad-bg:           #fdeceb;
    --info:            #1f6feb;
    --info-bg:          #e8f1fe;
    --neutral:          #5a6478;
    --neutral-bg:       #eef0f4;

    /* Ink and surfaces. */
    --ink:              #161c2b;
    --ink-soft:         #4a5568;
    --ink-faint:        #8792a8;
    --line:             #e3e7ef;
    --line-strong:      #cbd2e0;
    --surface:          #ffffff;
    --surface-sunk:     #f5f7fb;
    --surface-raised:   #ffffff;

    /* Type. System fonts only: nothing to host, nothing to wait for. */
    --font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
    --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;

    /* Spacing scale. */
    --sp-1: 4px;
    --sp-2: 8px;
    --sp-3: 12px;
    --sp-4: 16px;
    --sp-5: 24px;
    --sp-6: 32px;
    --sp-7: 48px;
    --sp-8: 64px;

    /* Shape and depth. */
    --r-sm: 6px;
    --r-md: 10px;
    --r-lg: 14px;
    --r-pill: 999px;
    --shadow-sm: 0 1px 2px rgba(16, 24, 40, .06), 0 1px 3px rgba(16, 24, 40, .08);
    --shadow-md: 0 4px 8px rgba(16, 24, 40, .05), 0 12px 28px rgba(16, 24, 40, .07);
    --shadow-lg: 0 8px 16px rgba(16, 24, 40, .06), 0 24px 48px rgba(16, 24, 40, .10);

    --focus: 0 0 0 3px rgba(31, 79, 216, .28);

    --max-w: 1160px;
}

/* ---------------------------------------------------------------- baseline */
*,
*::before,
*::after { box-sizing: border-box; }

html {
    -webkit-text-size-adjust: 100%;
    scroll-behavior: smooth;
}

body {
    margin: 0;
    font-family: var(--font);
    font-size: 16px;
    line-height: 1.55;
    color: var(--ink);
    background: var(--surface-sunk);
    -webkit-font-smoothing: antialiased;
}

h1, h2, h3, h4 {
    margin: 0 0 var(--sp-3);
    line-height: 1.25;
    letter-spacing: -0.011em;
    font-weight: 650;
}

h1 { font-size: 1.75rem; }
h2 { font-size: 1.35rem; }
h3 { font-size: 1.1rem; }
h4 { font-size: 0.95rem; }

p { margin: 0 0 var(--sp-3); }

a {
    color: var(--brand);
    text-decoration: none;
}

a:hover { text-decoration: underline; }

small { font-size: 0.825rem; }

code, pre, .mono {
    font-family: var(--mono);
    font-size: 0.86em;
}

pre {
    margin: 0;
    padding: var(--sp-4);
    overflow-x: auto;
    background: #10182a;
    color: #e6ebf5;
    border-radius: var(--r-md);
    line-height: 1.5;
}

pre code { color: inherit; }

hr {
    height: 1px;
    margin: var(--sp-5) 0;
    border: 0;
    background: var(--line);
}

img, svg { max-width: 100%; }

/* Anything focusable gets a visible ring — never remove it, only restyle it. */
:focus-visible {
    outline: 2px solid transparent;
    box-shadow: var(--focus);
    border-radius: var(--r-sm);
}

/* Screen-reader-only, for labels that must exist but not be seen. */
.sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
    border: 0;
}

/* ------------------------------------------------------------------- layout */
.wrap {
    width: 100%;
    max-width: var(--max-w);
    margin: 0 auto;
    padding: 0 var(--sp-4);
}

.wrap--narrow { max-width: 760px; }
.wrap--tight  { max-width: 480px; }

.stack > * + * { margin-top: var(--sp-4); }
.stack-sm > * + * { margin-top: var(--sp-2); }
.stack-lg > * + * { margin-top: var(--sp-6); }

.row {
    display: flex;
    flex-wrap: wrap;
    gap: var(--sp-3);
    align-items: center;
}

.row--between { justify-content: space-between; }
.row--end     { justify-content: flex-end; }
.row--top     { align-items: flex-start; }

.grid {
    display: grid;
    gap: var(--sp-4);
}

.grid--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.grid--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.grid--4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }

@media (max-width: 900px) {
    .grid--3, .grid--4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 560px) {
    .grid--2, .grid--3, .grid--4 { grid-template-columns: minmax(0, 1fr); }
}

.spacer { flex: 1 1 auto; }

/* -------------------------------------------------------------------- cards */
.card {
    background: var(--surface-raised);
    border: 1px solid var(--line);
    border-radius: var(--r-lg);
    box-shadow: var(--shadow-sm);
}

.card__head {
    display: flex;
    flex-wrap: wrap;
    gap: var(--sp-3);
    align-items: center;
    justify-content: space-between;
    padding: var(--sp-4) var(--sp-5);
    border-bottom: 1px solid var(--line);
}

.card__head h2,
.card__head h3 { margin: 0; }

.card__body { padding: var(--sp-5); }
.card__body--flush { padding: 0; }

.card__foot {
    padding: var(--sp-4) var(--sp-5);
    border-top: 1px solid var(--line);
    background: var(--surface-sunk);
    border-radius: 0 0 var(--r-lg) var(--r-lg);
}

/* A single headline number: balance, today's volume, pending payouts. */
.stat {
    padding: var(--sp-5);
    background: var(--surface-raised);
    border: 1px solid var(--line);
    border-radius: var(--r-lg);
    box-shadow: var(--shadow-sm);
}

.stat__label {
    margin: 0 0 var(--sp-2);
    font-size: 0.8rem;
    font-weight: 600;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: var(--ink-faint);
}

.stat__value {
    font-size: 1.65rem;
    font-weight: 680;
    letter-spacing: -0.02em;
    line-height: 1.15;
}

.stat__hint {
    margin: var(--sp-2) 0 0;
    font-size: 0.85rem;
    color: var(--ink-soft);
}

/* ------------------------------------------------------------------ buttons */
.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--sp-2);
    padding: 11px 18px;
    border: 1px solid transparent;
    border-radius: var(--r-md);
    font: inherit;
    font-weight: 600;
    line-height: 1.2;
    color: var(--brand-contrast);
    background: var(--brand);
    cursor: pointer;
    text-decoration: none;
    transition: background-color .15s ease, border-color .15s ease, transform .05s ease;
}

.btn:hover {
    background: var(--brand-dark);
    text-decoration: none;
}

.btn:active { transform: translateY(1px); }

.btn[disabled],
.btn[aria-disabled="true"] {
    opacity: .55;
    cursor: not-allowed;
    transform: none;
}

.btn--ghost {
    color: var(--ink);
    background: var(--surface);
    border-color: var(--line-strong);
}

.btn--ghost:hover { background: var(--surface-sunk); }

.btn--danger { background: var(--bad); }
.btn--danger:hover { background: #a12b24; }

.btn--quiet {
    color: var(--ink-soft);
    background: transparent;
    border-color: transparent;
    padding: 6px 10px;
}

.btn--quiet:hover { background: var(--neutral-bg); }

.btn--block { width: 100%; }
.btn--lg { padding: 14px 22px; font-size: 1.02rem; }
.btn--sm { padding: 7px 12px; font-size: .875rem; }

/* -------------------------------------------------------------------- forms */
.field { margin-bottom: var(--sp-4); }

.field > label,
.label {
    display: block;
    margin-bottom: 6px;
    font-size: .9rem;
    font-weight: 600;
    color: var(--ink);
}

.input,
.select,
.textarea {
    display: block;
    width: 100%;
    padding: 11px 13px;
    font: inherit;
    color: var(--ink);
    background: var(--surface);
    border: 1px solid var(--line-strong);
    border-radius: var(--r-md);
    transition: border-color .15s ease, box-shadow .15s ease;
}

.input:focus,
.select:focus,
.textarea:focus {
    outline: none;
    border-color: var(--brand);
    box-shadow: var(--focus);
}

.input[readonly] { background: var(--surface-sunk); color: var(--ink-soft); }
.input--error,
.select--error { border-color: var(--bad); }

.textarea { min-height: 96px; resize: vertical; }

/* 16px minimum on mobile, or iOS zooms the page on focus. */
@media (max-width: 560px) {
    .input, .select, .textarea { font-size: 16px; }
}

.hint {
    margin: 6px 0 0;
    font-size: .84rem;
    color: var(--ink-soft);
}

.error-text {
    margin: 6px 0 0;
    font-size: .84rem;
    font-weight: 500;
    color: var(--bad);
}

/* A checkbox and its wording on one line, with the box aligned to the first
   line of text rather than the middle of a wrapped paragraph. */
.check {
    display: flex;
    gap: var(--sp-2);
    align-items: flex-start;
    margin-bottom: var(--sp-4);
}

.check input[type="checkbox"] {
    flex: 0 0 auto;
    width: 16px;
    height: 16px;
    margin: 2px 0 0;
    accent-color: var(--brand);
}

/* Overrides the bold, block label of .field — this one is a sentence, not a
   field name, and it sits beside its control instead of above it. */
.check label {
    margin: 0;
    font-size: .9rem;
    font-weight: 400;
    line-height: 1.45;
    color: var(--ink);
}

/* ------------------------------------------------------------- choice tiles
   A radio group where the whole row is the target rather than the 16px circle.
   Used where each option needs a sentence of explanation: "sole proprietor"
   means nothing to most people until you say "you have an NTN in the business
   name", and a bare <select> has nowhere to put that. */
.choice {
    display: flex;
    flex-direction: column;
    gap: var(--sp-3);
    margin-bottom: var(--sp-4);
}

.choice__item {
    display: flex;
    gap: var(--sp-3);
    padding: var(--sp-3) var(--sp-4);
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--r-md);
    cursor: pointer;
}

.choice__item:hover { border-color: var(--line-strong); }

.choice__item:has(input:checked) {
    background: var(--brand-light);
    border-color: var(--brand);
}

.choice__item:has(input:focus-visible) { box-shadow: var(--focus); }

.choice__item input[type="radio"] {
    flex: 0 0 auto;
    width: 16px;
    height: 16px;
    margin: 3px 0 0;
    accent-color: var(--brand);
}

.choice__title {
    display: block;
    font-size: .95rem;
    font-weight: 600;
}

.choice__hint {
    display: block;
    margin-top: 2px;
    font-size: .86rem;
    color: var(--ink-soft);
}

/* ------------------------------------------------------------ file uploads
   The native control, restyled rather than replaced. A scripted uploader would
   be a JavaScript dependency on the one screen where the merchant is most
   likely to be on a phone and a poor connection — and the native input already
   offers the camera, which is what most of them will use. */
.file {
    display: block;
    width: 100%;
    padding: var(--sp-3);
    font: inherit;
    font-size: .92rem;
    color: var(--ink);
    background: var(--surface-sunk);
    border: 1px dashed var(--line-strong);
    border-radius: var(--r-md);
}

.file:focus-visible {
    outline: none;
    border-color: var(--brand);
    box-shadow: var(--focus);
}

.file--error { border-color: var(--bad); }

.file::file-selector-button {
    margin-right: var(--sp-3);
    padding: 6px 12px;
    font: inherit;
    font-size: .88rem;
    font-weight: 600;
    color: var(--brand);
    background: var(--brand-light);
    border: 0;
    border-radius: var(--r-sm);
    cursor: pointer;
}

/* ------------------------------------------------------- pills and alerts */
.pill {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 3px 10px;
    border-radius: var(--r-pill);
    font-size: .78rem;
    font-weight: 650;
    letter-spacing: .01em;
    white-space: nowrap;
    color: var(--neutral);
    background: var(--neutral-bg);
}

.pill--ok      { color: var(--ok);      background: var(--ok-bg); }
.pill--warn    { color: var(--warn);    background: var(--warn-bg); }
.pill--bad     { color: var(--bad);     background: var(--bad-bg); }
.pill--info    { color: var(--info);    background: var(--info-bg); }
.pill--neutral { color: var(--neutral); background: var(--neutral-bg); }

.alert {
    padding: var(--sp-3) var(--sp-4);
    border: 1px solid transparent;
    border-radius: var(--r-md);
    font-size: .93rem;
}

.alert p:last-child { margin-bottom: 0; }

.alert--ok   { color: #0b5f37; background: var(--ok-bg);   border-color: #b8e3ca; }
.alert--warn { color: #8a4308; background: var(--warn-bg); border-color: #f3d6a8; }
.alert--bad  { color: #8f2620; background: var(--bad-bg);  border-color: #f2c2be; }
.alert--info { color: #14458f; background: var(--info-bg); border-color: #c2d8fb; }

/* Toasts for flashed messages: visible, dismissible, never blocking. */
.flashes {
    position: fixed;
    top: var(--sp-4);
    right: var(--sp-4);
    z-index: 60;
    display: flex;
    flex-direction: column;
    gap: var(--sp-2);
    max-width: min(380px, calc(100vw - 32px));
}

.flashes .alert { box-shadow: var(--shadow-md); }

/* ------------------------------------------------------------------- tables */
.table-scroll {
    width: 100%;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
}

.table {
    width: 100%;
    border-collapse: collapse;
    font-size: .92rem;
}

.table th,
.table td {
    padding: 11px var(--sp-4);
    text-align: left;
    vertical-align: middle;
    border-bottom: 1px solid var(--line);
    white-space: nowrap;
}

.table th {
    font-size: .78rem;
    font-weight: 650;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: var(--ink-faint);
    background: var(--surface-sunk);
}

.table tbody tr:last-child td { border-bottom: 0; }
.table tbody tr:hover { background: #fafbfe; }

.table .num { text-align: right; font-variant-numeric: tabular-nums; }
.table .wrap-cell { white-space: normal; min-width: 220px; }

/* For a table whose rows are uneven: one audit line records five changed fields
   while the next records none, and a middle-aligned timestamp against a five-line
   cell reads as though it belongs to the row below. */
.table--top td { vertical-align: top; }

/* A tick box in the first column, for a table whose rows are a selection rather
   than only a list. Sized and coloured like .check so the two read as the same
   control; narrower padding because the cell holds nothing else. */
.table .pick { width: 1%; padding-right: 0; }

.table .pick input[type="checkbox"] {
    width: 16px;
    height: 16px;
    margin: 0;
    accent-color: var(--brand);
}

.table--empty td {
    padding: var(--sp-7) var(--sp-4);
    text-align: center;
    color: var(--ink-faint);
    white-space: normal;
}

/* A totals row that has to read as a sum of what is above it, not as one more
   data row: heavier rule on top, sunk background, no bottom border. */
.table tfoot td {
    border-top: 2px solid var(--line-strong);
    border-bottom: 0;
    background: var(--surface-sunk);
}

/* A one-button form inside a table cell. Without this the form's own margin
   pushes the row taller than every other row in the table. */
.cell-form {
    display: inline;
    margin: 0;
}

/* --------------------------------------------------------------- pagination */
.pager {
    display: flex;
    gap: var(--sp-2);
    align-items: center;
    justify-content: space-between;
    padding: var(--sp-3) var(--sp-5);
    border-top: 1px solid var(--line);
    font-size: .9rem;
    color: var(--ink-soft);
}

/* ------------------------------------------------------ definition lists */
.dl {
    display: grid;
    grid-template-columns: minmax(140px, 200px) 1fr;
    gap: var(--sp-2) var(--sp-4);
    margin: 0;
    font-size: .93rem;
}

.dl dt {
    color: var(--ink-faint);
    font-weight: 600;
}

.dl dd {
    margin: 0;
    color: var(--ink);
    word-break: break-word;
}

@media (max-width: 560px) {
    .dl { grid-template-columns: minmax(0, 1fr); gap: 2px var(--sp-4); }
    .dl dd { margin-bottom: var(--sp-3); }
}

/* ------------------------------------------------------ copyable secrets */
.copy-row {
    display: flex;
    gap: var(--sp-2);
    align-items: stretch;
}

.copy-row .input {
    font-family: var(--mono);
    font-size: .84rem;
}

/* ----------------------------------------------------------- payment link QR */
/* The white plate is not decoration. The encoder draws the four-module quiet
   zone, but a scanner also wants the paper it sits on to be plain, and this card
   has a tinted background on a dark theme. Same reasoning as .co-wait__qr on the
   checkout, restated here because the dashboard does not load checkout.css. */
.paylink-qr {
    display: flex;
    justify-content: center;
    width: fit-content;
    padding: var(--sp-3);
    margin: 0 auto var(--sp-2);
    background: #fff;
    border: 1px solid var(--line);
    border-radius: var(--r-md);
}

.paylink-qr svg {
    display: block;
    width: 200px;
    height: 200px;
}

@media (max-width: 480px) {
    .paylink-qr svg { width: 170px; height: 170px; }
}

/* ------------------------------------------------------------------ utility */
.muted     { color: var(--ink-soft); }
.faint     { color: var(--ink-faint); }
.strong    { font-weight: 650; }
.nowrap    { white-space: nowrap; }
.tabular   { font-variant-numeric: tabular-nums; }
.center    { text-align: center; }
.right     { text-align: right; }
.hidden    { display: none !important; }
.mt-0 { margin-top: 0; }
.mb-0 { margin-bottom: 0; }

/* -------------------------------------------------------------- brand marks */
.brandmark {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-2);
    font-weight: 700;
    font-size: 1.05rem;
    letter-spacing: -0.02em;
    color: var(--ink);
    text-decoration: none;
}

.brandmark:hover { text-decoration: none; }

.brandmark__dot {
    display: inline-block;
    width: 22px;
    height: 22px;
    border-radius: 7px;
    background: linear-gradient(135deg, var(--brand) 0%, #4d7bf3 100%);
}

/* A padlock line, used on checkout and auth pages. */
.secure-note {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: .82rem;
    color: var(--ink-faint);
}

/* ------------------------------------------------------- reduced motion */
@media (prefers-reduced-motion: reduce) {
    html { scroll-behavior: auto; }

    *,
    *::before,
    *::after {
        animation-duration: .001ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: .001ms !important;
    }
}

/* ------------------------------------------------------------------- print */
@media print {
    body { background: #fff; }
    .no-print { display: none !important; }
    .card { box-shadow: none; border-color: #ccc; }
}

/* --------------------------------------------------------------------- auth
   Signup, sign-in and password reset. One centred column, nothing else on the
   page: these screens have a single job and a wide layout only gives the eye
   somewhere else to go. Scoped under .auth so none of it can reach a dashboard
   page, which shares this stylesheet. */
.auth__page {
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 100vh;
    padding: var(--sp-6) var(--sp-4);
}

.auth__box {
    width: 100%;
    max-width: 430px;
}

.auth__brand {
    display: flex;
    justify-content: center;
    margin-bottom: var(--sp-5);
    font-size: 1.2rem;
}

.auth__title {
    margin: 0 0 var(--sp-1);
    font-size: 1.4rem;
    letter-spacing: -0.02em;
}

.auth__lead {
    margin: 0;
    color: var(--ink-soft);
    font-size: .94rem;
}

.auth__alt {
    margin: 0;
    text-align: center;
    font-size: .93rem;
}

.auth__foot,
.auth__legal {
    margin: var(--sp-4) 0 0;
    text-align: center;
    font-size: .84rem;
    color: var(--ink-soft);
}

.auth__legal {
    margin-top: var(--sp-2);
    color: var(--ink-faint);
}

/* The form's own submit is the primary action; the last field should not sit
   flush against it. */
.auth__box form > .field:last-of-type { margin-bottom: var(--sp-5); }

@media (max-width: 480px) {
    .auth__page { padding: var(--sp-5) var(--sp-3); align-items: flex-start; }
}

/* ============================================================================
   The signed-in shell — layouts/app.php
   ----------------------------------------------------------------------------
   A top bar, a row of section links, the page, a footer. The nav is a real
   horizontal row that scrolls sideways when it does not fit, because a drawer
   would need JavaScript to open and these links have to work without it.
   ========================================================================= */

/* Visible only once focused, which is the whole point: a keyboard user gets
   past the nav in one press, a mouse user never sees it. */
.skip-link {
    position: absolute;
    left: var(--sp-3);
    top: -60px;
    z-index: 60;
    padding: var(--sp-2) var(--sp-4);
    border-radius: var(--r-sm);
    background: var(--ink);
    color: #fff;
    font-size: .9rem;
    text-decoration: none;
    transition: top .12s ease-in;
}

.skip-link:focus {
    top: var(--sp-3);
    outline: none;
    box-shadow: var(--focus);
}

/* Footer sits at the bottom on a short page instead of floating mid-screen. */
body.app {
    display: flex;
    flex-direction: column;
    min-height: 100vh;
    background: var(--surface-sunk);
}

.app__top {
    background: var(--surface);
    border-bottom: 1px solid var(--line);
}

.app__top-inner {
    display: flex;
    align-items: center;
    gap: var(--sp-4);
    padding-top: var(--sp-3);
    padding-bottom: var(--sp-3);
}

/* The identity block takes the slack, so the brand stays left and the sign-out
   button stays right however long the business name is. */
.app__who {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 2px;
    align-items: flex-end;
    text-align: right;
}

.app__who-name {
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-weight: 600;
    font-size: .94rem;
    color: var(--ink);
}

.app__who-meta {
    display: flex;
    align-items: center;
    gap: var(--sp-2);
    font-size: .78rem;
    color: var(--ink-faint);
}

.app__signout { flex: 0 0 auto; margin: 0; }

.app__nav {
    position: sticky;
    top: 0;
    z-index: 20;
    background: var(--surface);
    border-bottom: 1px solid var(--line);
}

.app__nav-inner {
    display: flex;
    gap: var(--sp-1);
    overflow-x: auto;
    /* Hide the scrollbar but keep the scrolling: on a phone the row is dragged,
       and a permanent bar under eight links looks like a broken layout. */
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
}

.app__nav-inner::-webkit-scrollbar { display: none; }

.app__nav-link {
    flex: 0 0 auto;
    padding: var(--sp-3) var(--sp-3);
    border-bottom: 2px solid transparent;
    color: var(--ink-soft);
    font-size: .92rem;
    font-weight: 550;
    text-decoration: none;
    white-space: nowrap;
}

.app__nav-link:hover {
    color: var(--ink);
    text-decoration: none;
}

.app__nav-link:focus-visible {
    outline: none;
    box-shadow: var(--focus);
    border-radius: var(--r-sm);
}

.app__nav-link.is-active {
    color: var(--brand);
    border-bottom-color: var(--brand);
}

.app__main {
    flex: 1 0 auto;
    padding: var(--sp-6) 0 var(--sp-7);
}

.app__foot {
    border-top: 1px solid var(--line);
    background: var(--surface);
    padding: var(--sp-4) 0;
    font-size: .84rem;
    color: var(--ink-faint);
}

.app__foot p { margin: 0; }

/* The page title row most dashboard screens open with: heading on the left,
   an action or two on the right, stacking on a narrow screen. */
.page-head {
    display: flex;
    flex-wrap: wrap;
    gap: var(--sp-3);
    align-items: flex-end;
    justify-content: space-between;
}

.page-head h1 {
    margin: 0;
    font-size: 1.35rem;
    letter-spacing: -0.02em;
}

.page-head p {
    margin: var(--sp-1) 0 0;
    color: var(--ink-soft);
    font-size: .92rem;
}

.page-head__actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--sp-2);
}

@media (max-width: 620px) {
    /* Brand and sign-out keep the first line; the identity block drops to its
       own line and left-aligns, which reads better than an ellipsis. */
    .app__top-inner { flex-wrap: wrap; gap: var(--sp-2) var(--sp-3); }
    .brandmark { flex: 1 1 auto; }

    .app__who {
        order: 3;
        flex-basis: 100%;
        align-items: flex-start;
        text-align: left;
    }

    .app__main { padding: var(--sp-5) 0 var(--sp-6); }
    .page-head h1 { font-size: 1.2rem; }
}

/* ----------------------------------------------------- onboarding checklist */
.steps {
    margin: 0;
    padding: 0;
    list-style: none;
    display: flex;
    flex-direction: column;
    gap: var(--sp-4);
}

.steps__item {
    display: flex;
    gap: var(--sp-3);
    align-items: center;
}

.steps__mark {
    flex: 0 0 auto;
    width: 24px;
    height: 24px;
    border-radius: 50%;
    border: 2px solid var(--line-strong);
    display: grid;
    place-items: center;
    font-size: .8rem;
    line-height: 1;
    color: #fff;
}

.steps__item.is-done .steps__mark {
    background: var(--ok);
    border-color: var(--ok);
}

.steps__text { flex: 1 1 auto; min-width: 0; }

.steps__title {
    margin: 0;
    font-weight: 600;
    font-size: .95rem;
}

.steps__hint {
    margin: 2px 0 0;
    font-size: .86rem;
    color: var(--ink-soft);
}

.steps__item.is-done .steps__title { color: var(--ink-soft); }

@media (max-width: 560px) {
    .steps__item { flex-wrap: wrap; }
    .steps__item .btn { margin-left: 36px; }
}

/* ------------------------------------------------------------- filter bars */
.filters {
    display: grid;
    grid-template-columns: minmax(180px, 2fr) repeat(5, minmax(110px, 1fr)) auto;
    gap: var(--sp-3);
    align-items: end;
}

/* The bar is one row, so the per-field bottom margin would push the controls
   out of alignment with each other. */
.filters .field { margin-bottom: 0; }

.filters__actions {
    display: flex;
    gap: var(--sp-2);
    align-items: end;
}

@media (max-width: 1000px) {
    .filters { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .filters__actions { grid-column: 1 / -1; }
}

@media (max-width: 480px) {
    .filters { grid-template-columns: minmax(0, 1fr); }
    .filters__actions { flex-direction: column; }
}

@media print {
    .app__nav,
    .app__signout,
    .skip-link,
    .flashes { display: none !important; }

    body.app { background: #fff; }
    .app__top { border-bottom: 1px solid #ccc; }
}

/* ============================================================================
   The public shell — layouts/site.php
   ----------------------------------------------------------------------------
   The landing page and the API reference: the two surfaces a stranger sees. One
   bar, the page, one footer. No sticky nav here — a documentation page is read
   by scrolling, and a bar pinned over it just takes 56px off every screenful.
   ========================================================================= */
body.site {
    display: flex;
    flex-direction: column;
    min-height: 100vh;
    background: var(--surface);
}

.site__bar {
    background: var(--surface);
    border-bottom: 1px solid var(--line);
}

.site__bar .row {
    padding-top: var(--sp-4);
    padding-bottom: var(--sp-4);
}

.site__nav {
    display: flex;
    align-items: center;
    gap: var(--sp-2);
}

/* The one button in the header never wraps. It is the shortest label on the page
   and it sits beside two links, so at phone widths it is the thing that gives:
   "Create an / account" over two lines, fifty pixels tall, next to two single-line
   links. Kept on one line the row stays level, and the nav wraps as a whole if it
   has to. Scoped to this nav rather than .btn, because a long label inside a card
   footer is better wrapped than clipped. */
.site__nav .btn { white-space: nowrap; }

.site__link {
    padding: var(--sp-2) var(--sp-3);
    border-radius: var(--r-sm);
    color: var(--ink-soft);
    font-size: .93rem;
    font-weight: 550;
    text-decoration: none;
    white-space: nowrap;
}

.site__link:hover {
    color: var(--ink);
    background: var(--surface-sunk);
    text-decoration: none;
}

.site__link:focus-visible {
    outline: none;
    box-shadow: var(--focus);
}

.site__link.is-current { color: var(--brand); }

.site__main { flex: 1 0 auto; }

.site__foot {
    border-top: 1px solid var(--line);
    background: var(--surface-sunk);
    padding: var(--sp-5) 0;
    font-size: .86rem;
}

@media (max-width: 640px) {
    /* The brand keeps the first line and the nav drops below it, centred: three
       items do not fit beside a wordmark on a 360px screen without ellipsis. */
    .site__bar .row { flex-wrap: wrap; gap: var(--sp-3); }
    .site__nav { flex-basis: 100%; justify-content: center; }
    .site__foot .row { flex-direction: column; gap: var(--sp-1); text-align: center; }
}

/* ----------------------------------------------------------- API reference
   Two columns: a table of contents that stays put, and the prose. The sidebar
   is a sibling rather than a fixed overlay so it scrolls its own overflow and
   cannot cover the content on a short window.

   Below 900px it becomes an ordinary block above the article — a 20-item index
   is worth scrolling past once, and a collapsible one would need JavaScript. */
.docs {
    display: grid;
    grid-template-columns: 232px minmax(0, 1fr);
    gap: var(--sp-7);
    padding-top: var(--sp-6);
    padding-bottom: var(--sp-8);
}

.docs__side {
    position: sticky;
    top: var(--sp-5);
    align-self: start;
    max-height: calc(100vh - var(--sp-7));
    overflow-y: auto;
    /* Its own scrollbar, so a long index does not drag the page with it. */
    overscroll-behavior: contain;
}

.docs__sidehead {
    margin: var(--sp-5) 0 var(--sp-2);
    font-size: .74rem;
    font-weight: 700;
    letter-spacing: .08em;
    text-transform: uppercase;
    color: var(--ink-faint);
}

.docs__sidehead:first-child { margin-top: 0; }

.docs__list {
    margin: 0 0 var(--sp-2);
    padding: 0;
    list-style: none;
    border-left: 1px solid var(--line);
}

.docs__list a {
    display: block;
    padding: 5px var(--sp-3);
    margin-left: -1px;
    border-left: 2px solid transparent;
    color: var(--ink-soft);
    font-size: .89rem;
    line-height: 1.4;
    text-decoration: none;
}

.docs__list a:hover {
    color: var(--brand);
    border-left-color: var(--line-strong);
    text-decoration: none;
}

.docs__list a:focus-visible {
    outline: none;
    box-shadow: var(--focus);
    border-radius: var(--r-sm);
}

/* :target is what makes the index feel like it did something: click "Errors"
   and the section you land on is marked without a line of JavaScript. Two
   selectors because the endpoint sections are cards, whose heading sits inside
   .card__head rather than directly under the section. */
.docs__body > section:target > h2,
.docs__body > section:target > .card__head > h2 { color: var(--brand); }

/* html { scroll-behavior: smooth } plus this keeps a jumped-to heading clear of
   the top edge rather than flush against it. */
.docs__body > section { scroll-margin-top: var(--sp-5); }

/* Every section heading is the same size whether the section is prose or an
   endpoint card, so the page reads as one outline. Only the prose ones get the
   rule underneath — a card already has a border under its head. */
.docs__body > section h2 { font-size: 1.3rem; }

.docs__body > section > h2 {
    margin-bottom: var(--sp-2);
    padding-bottom: var(--sp-3);
    border-bottom: 1px solid var(--line);
}

/* The opening paragraph of a page or a section: one size up, one tone lighter,
   and narrow enough to stay readable across a wide screen. */
.lede {
    max-width: 68ch;
    color: var(--ink-soft);
    font-size: 1.02rem;
}

@media (max-width: 900px) {
    .docs {
        grid-template-columns: minmax(0, 1fr);
        gap: var(--sp-5);
        padding-top: var(--sp-5);
        padding-bottom: var(--sp-6);
    }

    .docs__side {
        position: static;
        max-height: none;
        overflow: visible;
        padding-bottom: var(--sp-4);
        border-bottom: 1px solid var(--line);
    }
}

@media print {
    /* The index is a list of links to a page that is already in the reader's
       hand, and the two-column grid wastes half of it. */
    .docs__side,
    .site__bar,
    .site__foot { display: none !important; }

    .docs { display: block; padding: 0; }
    body.site { background: #fff; }
    .docs__body > section > h2 { border-bottom: 1px solid #ccc; }
    pre { background: #f4f4f4; color: #111; border: 1px solid #ccc; }
}

/* ==========================================================================
   Landing page (§11)

   Sections alternate white / sunk so the page has a rhythm without a rule
   between every band, and every section shares one head block so the outline
   is the same shape whether the section holds cards, a list or a price.

   No animation and no scroll-triggered anything: the audience includes a
   merchant on a 3G connection in Karachi deciding whether we look like people
   who can hold their money, and a page that jumps around while it loads is a
   worse answer to that question than a page that simply arrives.
   ========================================================================== */

.section { padding: var(--sp-8) 0; }

.section--sunk {
    background: var(--surface-sunk);
    border-top: 1px solid var(--line);
    border-bottom: 1px solid var(--line);
}

.section__head {
    max-width: 62ch;
    margin-bottom: var(--sp-6);
}

.section__head h2 {
    margin-bottom: var(--sp-2);
    font-size: 1.6rem;
    letter-spacing: -.01em;
}

.section__head .lede { margin-bottom: 0; }

/* ------------------------------------------------------------------- hero */

.hero {
    border-bottom: 1px solid var(--line);

    /* A tint rather than an image: one gradient costs nothing to download and
       cannot fail to load, and the page is legible before any paint. */
    background:
        radial-gradient(1200px 400px at 15% -10%, var(--brand-light), transparent 70%),
        var(--surface);
}

.hero__inner {
    max-width: 900px;
    padding-top: var(--sp-8);
    padding-bottom: var(--sp-8);
}

.hero__eyebrow {
    margin-bottom: var(--sp-3);
    color: var(--brand);
    font-size: .8rem;
    font-weight: 700;
    letter-spacing: .09em;
    text-transform: uppercase;
}

.hero__title {
    max-width: 22ch;
    margin-bottom: var(--sp-4);

    /* clamp() so the headline fills a laptop without wrapping to five lines on
       a handset. The middle term is the one that matters — 4.6vw keeps it to
       two lines at 360px, which is where most of this traffic will read it. */
    font-size: clamp(1.9rem, 4.6vw, 3.1rem);
    line-height: 1.12;
    letter-spacing: -.02em;
}

.hero__lede {
    max-width: 60ch;
    margin-bottom: var(--sp-6);
    font-size: 1.08rem;
}

.hero__actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--sp-3);
    margin-bottom: var(--sp-5);
}

.hero__note {
    margin-bottom: 0;
    color: var(--ink-soft);
    font-size: .92rem;
}

/* ---------------------------------------------------------- payment methods */

.method__mark {
    display: inline-grid;
    place-items: center;
    width: 44px;
    height: 44px;
    margin-bottom: var(--sp-4);
    border-radius: var(--r-md);
    font-size: .92rem;
    font-weight: 700;
    letter-spacing: .04em;
}

/* Wordmarks in the wallet's own colour family, which is as close to their
   branding as we get without permission to ship their artwork. The tones reuse
   the status palette rather than introducing three more colours: JazzCash red,
   EasyPaisa green, and our own blue for the QR. */
.method__mark--bad  { background: var(--bad-bg);  color: var(--bad); }
.method__mark--ok   { background: var(--ok-bg);   color: var(--ok); }
.method__mark--info { background: var(--info-bg); color: var(--info); }

/* And once a wallet's own artwork is dropped into assets/img/, the same box holds
   it: no tinted background to fight the logo, and object-fit so a file that is not
   square is letterboxed rather than stretched. */
.method__mark--logo {
    display: block;
    background: none;
    object-fit: contain;
}

.method__name {
    margin-bottom: var(--sp-2);
    font-size: 1.06rem;
}

/* ---------------------------------------------------------- how it works */

.how {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
    gap: var(--sp-6);
    margin: 0;
    padding: 0;

    /* The numbers are rendered as content, so the marker would be a second
       numbering of the same three steps read aloud. */
    list-style: none;
}

.how__step {
    padding-top: var(--sp-4);
    border-top: 2px solid var(--brand);
}

.how__num {
    margin-bottom: var(--sp-2);
    color: var(--brand);
    font-size: 1.5rem;
    font-weight: 700;
    line-height: 1;
}

.how__title {
    margin-bottom: var(--sp-2);
    font-size: 1.06rem;
}

/* ---------------------------------------------------------------- pricing */

.price {
    background: var(--brand-light);
    border-radius: var(--r-lg) var(--r-lg) 0 0;
    text-align: center;
}

.price__figure {
    margin-bottom: var(--sp-1);
    color: var(--brand);
    font-size: clamp(2.8rem, 9vw, 4rem);
    font-weight: 700;
    line-height: 1;
    letter-spacing: -.03em;
}

.price__unit {
    margin-left: 2px;
    font-size: .38em;
    font-weight: 600;
    vertical-align: super;
}

.price__caption {
    color: var(--ink-soft);
    font-size: .92rem;
}

.price__work { border-top: 1px solid var(--line); }

/* The worked example is arithmetic, so the figures line up on their right edge
   and the total sits under the parts, the way it would on a statement. */
.price__work .dl { margin-bottom: var(--sp-4); }
.price__work .dl dt { color: var(--ink-soft); }
.price__work .dl dd { text-align: right; }

/* -------------------------------------------------------------------- FAQ */

.faq { border-top: 1px solid var(--line); }

.faq__item { border-bottom: 1px solid var(--line); }

.faq__q {
    display: flex;
    gap: var(--sp-4);
    align-items: baseline;
    justify-content: space-between;
    padding: var(--sp-4) 0;
    font-weight: 600;
    cursor: pointer;

    /* Both are needed to drop the disclosure triangle: the modern property and
       the WebKit pseudo-element older Safari still uses. The sign added below
       replaces it, so nothing is lost. */
    list-style: none;
}

.faq__q::-webkit-details-marker { display: none; }

.faq__q::after {
    content: "+";
    flex: 0 0 auto;
    color: var(--brand);
    font-size: 1.25rem;
    font-weight: 400;
    line-height: 1;
}

.faq__item[open] .faq__q { color: var(--brand); }

/* An en dash, not a hyphen: at this size a hyphen reads as a speck. */
.faq__item[open] .faq__q::after { content: "\2013"; }

.faq__a {
    max-width: 70ch;
    padding-bottom: var(--sp-4);
    color: var(--ink-soft);
}

.faq__more {
    margin-top: var(--sp-5);
    margin-bottom: 0;
    color: var(--ink-soft);
    font-size: .93rem;
}

/* ------------------------------------------------------------- closing CTA */

/* A tint rather than a solid brand band. Inverting the palette here would mean
   overriding the colour of every link, button and hint inside it, and one of
   them would eventually be missed and fail contrast on the last thing a
   visitor reads before deciding. */
.section--cta {
    border-top: 1px solid var(--line);
    background:
        radial-gradient(900px 300px at 50% 120%, var(--brand-light), transparent 70%),
        var(--surface-sunk);
}

.section--cta h2 {
    font-size: clamp(1.6rem, 4vw, 2.1rem);
    letter-spacing: -.02em;
}

/* .lede is left-aligned by default and centred text needs its own centring of
   the box, not just the glyphs. */
.section--cta .lede {
    margin-left: auto;
    margin-right: auto;
}

/* ------------------------------------------------------- terms and privacy */

.legal h1 { font-size: clamp(1.8rem, 4vw, 2.3rem); }

.legal h2 {
    margin-top: var(--sp-7);
    margin-bottom: var(--sp-3);
    padding-bottom: var(--sp-2);
    border-bottom: 1px solid var(--line);
    font-size: 1.15rem;
}

.legal p,
.legal .dl dd { color: var(--ink-soft); }

.legal p { max-width: 74ch; }

.legal .dl { margin-bottom: var(--sp-4); }

/* The draft notice. Deliberately the loudest thing on the page: it is the one
   statement on a terms page that must not be skimmed past. */
.legal__flag {
    margin-bottom: var(--sp-6);
    padding: var(--sp-4) var(--sp-5);
    border-left: 3px solid var(--warn);
    border-radius: 0 var(--r-md) var(--r-md) 0;
    background: var(--warn-bg);
    font-size: .95rem;
}

.legal__flag p { color: var(--ink); }

/* An unresolved point, marked so it can be found by eye and by grep. mark's
   default yellow-on-black is overridden rather than inherited — it would read
   as a highlighter pen over finished text, which is the opposite of true. */
.legal__todo {
    padding: 1px 4px;
    border-radius: var(--r-sm);
    background: var(--warn-bg);
    box-shadow: inset 0 -1px 0 var(--warn);
    color: var(--warn);
    font-style: italic;
}

/* ---------------------------------------------------------- public footer */

.site__foot-inner {
    display: flex;
    flex-wrap: wrap;
    gap: var(--sp-3) var(--sp-5);
    align-items: center;
    justify-content: space-between;
}

.site__foot-nav {
    display: flex;
    flex-wrap: wrap;
    gap: var(--sp-2) var(--sp-4);
}

.site__foot-nav a { color: var(--ink-soft); }
.site__foot-nav a:hover { color: var(--brand); }

@media (max-width: 640px) {
    .section { padding: var(--sp-7) 0; }

    .hero__inner {
        padding-top: var(--sp-7);
        padding-bottom: var(--sp-7);
    }

    .how { gap: var(--sp-5); }

    .site__foot-inner {
        flex-direction: column;
        align-items: flex-start;
    }
}










/* ------------------------------------------------- front-page picker (admin)
   Radio cards for choosing which landing theme / serves. The <input> stays in
   the DOM and only its ring is hidden, so the group is still reachable and
   operable with a keyboard and still announces as a radio group; :focus-visible
   on it draws the ring on the label instead. */
.theme-pick {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 260px), 1fr));
    gap: var(--sp-3);
    border: 0;
    margin: 0;
    padding: 0;
}

.theme-pick__opt {
    position: relative;
    display: flex;
    gap: var(--sp-3);
    padding: var(--sp-4);
    border: 1px solid var(--line-strong);
    border-radius: var(--r-md);
    background: var(--surface);
    cursor: pointer;
    transition: border-color .15s ease, box-shadow .15s ease;
}

.theme-pick__opt:hover { border-color: var(--brand); }

.theme-pick__opt.is-on {
    border-color: var(--brand);
    box-shadow: 0 0 0 1px var(--brand) inset;
    background: var(--brand-light);
}

.theme-pick__opt input {
    margin: 2px 0 0;
    flex: none;
    accent-color: var(--brand);
}

.theme-pick__opt:has(input:focus-visible) { box-shadow: var(--focus); }

.theme-pick__body { display: grid; gap: 4px; }

.theme-pick__name {
    display: flex;
    align-items: center;
    gap: var(--sp-2);
    font-weight: 600;
}

.theme-pick__blurb {
    color: var(--ink-soft);
    font-size: .9rem;
    line-height: 1.5;
}

.theme-pick__see {
    font-size: .85rem;
    justify-self: start;
    margin-top: 2px;
}
