=== /home/def/otb_billing/templates/portal_login.html ===
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Client Portal - OutsideTheBox</title>
    <link rel="stylesheet" href="/static/css/style.css">
    <style>
        .portal-wrap { max-width: 760px; margin: 2.5rem auto; padding: 1.5rem; }
        .portal-card {
            border: 1px solid rgba(255,255,255,0.16);
            border-radius: 16px;
            padding: 1.4rem;
            background: rgba(255,255,255,0.03);
            box-shadow: 0 10px 24px rgba(0,0,0,0.18);
        }
        .portal-card h1 { margin-top: 0; margin-bottom: 0.45rem; }
        .portal-sub { opacity: 0.9; margin-bottom: 1.25rem; }
        .portal-form { display: grid; gap: 0.9rem; }
        .portal-form label { display: block; font-weight: 600; margin-bottom: 0.35rem; }
        .portal-form input {
            width: 100%;
            padding: 0.8rem 0.9rem;
            border-radius: 10px;
            border: 1px solid rgba(255,255,255,0.18);
            background: rgba(255,255,255,0.05);
            color: inherit;
            box-sizing: border-box;
        }
        .portal-actions { display: flex; gap: 0.8rem; flex-wrap: wrap; margin-top: 0.4rem; }
        .portal-btn {
            display: inline-block;
            padding: 0.8rem 1rem;
            border-radius: 10px;
            text-decoration: none;
            border: 1px solid rgba(255,255,255,0.18);
            background: rgba(255,255,255,0.06);
            color: inherit;
            cursor: pointer;
        }
        .portal-note { margin-top: 1rem; opacity: 0.88; font-size: 0.95rem; }
        .portal-links { margin-top: 1rem; }
        .portal-links a { margin-right: 1rem; }
        .portal-msg {
            margin-bottom: 1rem;
            padding: 0.85rem 1rem;
            border-radius: 10px;
            border: 1px solid rgba(255,255,255,0.16);
            background: rgba(255,255,255,0.04);
        }
    </style>
    <link rel="icon" type="image/png" href="/static/favicon.png">
</head>
<body>
<div style="background:#111827;padding:10px 20px;">
  <a href="https://outsidethebox.top" style="color:#60a5fa;text-decoration:none;font-weight:bold;">
    ← OutsideTheBox Home
  </a>
</div>

<div class="portal-wrap">
    <div class="portal-card">
        <h1>OutsideTheBox Client Portal</h1>
        <p class="portal-sub">Secure access for invoices, balances, and account information.</p>

        {% if portal_message %}
        <div class="portal-msg">{{ portal_message }}</div>
        {% endif %}

        <form class="portal-form" method="post" action="/portal/login">
            <div>
                <label for="email">Email Address</label>
                <input id="email" name="email" type="email" placeholder="client@example.com" value="{{ portal_email or '' }}" required>
            </div>

            <div>
                <label for="credential">Access Code or Password</label>
                <input id="credential" name="credential" type="password" placeholder="Enter your one-time access code or password" required>
            </div>

            <div class="portal-actions">
                <button class="portal-btn" type="submit">Sign In</button>
                <a class="portal-btn" href="https://outsidethebox.top/">Home</a>
                <a class="portal-btn" href="mailto:support@outsidethebox.top?subject=Portal%20Support">Contact Support</a>
            </div>
        </form>


        <div style="margin-top:15px;">
            <a href="/portal/forgot-password">Forgot your password?</a>
        </div>

        <p class="portal-note">
            First-time users should sign in with the one-time access code provided by OutsideTheBox, then set a password.
            This access code is single-use and is cleared after password setup. Future logins use your email address and password.
        </p>
    </div>
</div>

{% include "footer.html" %}
</body>
</html>

=== /home/def/otb_billing/templates/portal_dashboard.html ===
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Client Dashboard - OutsideTheBox</title>
    <link rel="stylesheet" href="/static/css/style.css">
    <style>
        .portal-wrap { max-width: 1100px; margin: 2rem auto; padding: 1.25rem; }
        .portal-top {
            display:flex; justify-content:space-between; align-items:center; gap:1rem; flex-wrap:wrap;
            margin-bottom: 1rem;
        }
        .portal-actions a {
            margin-left: 0.75rem;
            text-decoration: underline;
        }
        .summary-grid {
            display:grid;
            grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
            gap:1rem;
            margin: 1rem 0 1.25rem 0;
        }
        .summary-card {
            border: 1px solid rgba(255,255,255,0.16);
            border-radius: 14px;
            padding: 1rem;
            background: rgba(255,255,255,0.03);
        }
        .summary-card h3 { margin-top:0; margin-bottom:0.4rem; }
        table.portal-table {
            width: 100%;
            border-collapse: collapse;
        }
        table.portal-table th, table.portal-table td {
            padding: 0.8rem;
            border-bottom: 1px solid rgba(255,255,255,0.12);
            text-align: left;
        }
        table.portal-table th {
            background: #e9eef7;
            color: #10203f;
        }
        .invoice-link {
            color: inherit;
            text-decoration: underline;
            font-weight: 600;
        }
        .status-badge {
            display: inline-block;
            padding: 0.18rem 0.55rem;
            border-radius: 999px;
            font-size: 0.86rem;
            font-weight: 700;
        }
        .status-paid {
            background: rgba(34, 197, 94, 0.18);
            color: #4ade80;
        }
        .status-pending {
            background: rgba(245, 158, 11, 0.20);
            color: #fbbf24;
        }
        .status-overdue {
            background: rgba(239, 68, 68, 0.18);
            color: #f87171;
        }
        .status-other {
            background: rgba(148, 163, 184, 0.20);
            color: #cbd5e1;
        }
    </style>
    <link rel="icon" type="image/png" href="/static/favicon.png">
</head>
<body>
<div style="background:#111827;padding:10px 20px;">
  <a href="https://outsidethebox.top" style="color:#60a5fa;text-decoration:none;font-weight:bold;">
    ← OutsideTheBox Home
  </a>
</div>

<div class="portal-wrap">
    <div class="portal-top">
        <div>
            <h1>Client Dashboard</h1>
            <p>{{ client.company_name or client.contact_name or client.email }}</p>
        </div>
        <div class="portal-actions">
            <a href="/portal/invoices/download-all">Download All Invoices (ZIP)</a>
            <a href="https://outsidethebox.top/">Home</a>
            <a href="mailto:support@outsidethebox.top?subject=Portal%20Support">Contact Support</a>
            <a href="/portal/logout">Logout</a>
        </div>
    </div>

    <div class="summary-grid">
        <div class="summary-card">
            <h3>Total Invoices</h3>
            <div>{{ invoice_count }}</div>
        </div>
        <div class="summary-card">
            <h3>Total Outstanding</h3>
            <div>{{ total_outstanding }}</div>
        </div>
        <div class="summary-card">
            <h3>Total Paid</h3>
            <div>{{ total_paid }}</div>
        </div>
    </div>

    <h2>Invoices</h2>
    <table class="portal-table">
        <thead>
            <tr>
                <th>Invoice</th>
                <th>Status</th>
                <th>Created</th>
                <th>Total</th>
                <th>Paid</th>
                <th>Outstanding</th>
            </tr>
        </thead>
        <tbody>
            {% for row in invoices %}
            <tr>
                <td>
                    <a class="invoice-link" href="/portal/invoice/{{ row.id }}">
                        {{ row.invoice_number or ("INV-" ~ row.id) }}
                    </a>
                </td>
                <td>
                    {% set s = (row.status or "")|lower %}
                    {% if s == "paid" %}
                        <span class="status-badge status-paid">{{ row.status }}</span>
                    {% elif s == "pending" %}
                        <span class="status-badge status-pending">{{ row.status }}</span>
                    {% elif s == "overdue" %}
                        <span class="status-badge status-overdue">{{ row.status }}</span>
                    {% else %}
                        <span class="status-badge status-other">{{ row.status }}</span>
                    {% endif %}
                </td>
                <td>{{ row.created_at }}</td>
                <td>{{ row.total_amount }}</td>
                <td>{{ row.amount_paid }}</td>
                <td>{{ row.outstanding }}</td>
            </tr>
            {% else %}
            <tr>
                <td colspan="6">No invoices available.</td>
            </tr>
            {% endfor %}
        </tbody>
    </table>
</div>


<script>
(function() {
    setTimeout(function() {
        window.location.reload();
    }, 20000);
})();
</script>

{% include "footer.html" %}
</body>
</html>

=== /home/def/otb_billing/templates/portal_invoice_detail.html ===
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Invoice Detail - OutsideTheBox</title>
    <link rel="stylesheet" href="/static/css/style.css">
    <style>
        .portal-wrap { max-width: 1100px; margin: 2rem auto; padding: 1.25rem; }
        .portal-top { display:flex; justify-content:space-between; align-items:center; gap:1rem; flex-wrap:wrap; margin-bottom: 1rem; }
        .portal-actions a { margin-left: 0.75rem; text-decoration: underline; }
        .detail-grid { display:grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap:1rem; margin: 1rem 0 1.25rem 0; }
        .detail-card { border: 1px solid rgba(255,255,255,0.16); border-radius: 14px; padding: 1rem; background: rgba(255,255,255,0.03); margin-bottom: 1rem; }
        .detail-card h3 { margin-top: 0; margin-bottom: 0.4rem; }
        table.portal-table { width: 100%; border-collapse: collapse; margin-top: 1rem; }
        table.portal-table th, table.portal-table td { padding: 0.8rem; border-bottom: 1px solid rgba(255,255,255,0.12); text-align: left; }
        table.portal-table th { background: #e9eef7; color: #10203f; }
        .status-badge { display: inline-block; padding: 0.18rem 0.55rem; border-radius: 999px; font-size: 0.86rem; font-weight: 700; }
        .status-paid { background: rgba(34, 197, 94, 0.18); color: #4ade80; }
        .status-pending { background: rgba(245, 158, 11, 0.20); color: #fbbf24; }
        .status-overdue { background: rgba(239, 68, 68, 0.18); color: #f87171; }
        .status-other { background: rgba(148, 163, 184, 0.20); color: #cbd5e1; }

        .pay-card { border: 1px solid rgba(255,255,255,0.16); border-radius: 14px; padding: 1rem; background: rgba(255,255,255,0.03); margin-top: 1.25rem; }
        .pay-selector-row { display:flex; gap:0.75rem; align-items:center; flex-wrap:wrap; margin-top:0.75rem; }
        .pay-selector { padding: 10px 12px; min-width: 220px; border-radius: 8px; }
        .pay-panel { margin-top: 1rem; padding: 1rem; border: 1px solid rgba(255,255,255,0.12); border-radius: 12px; background: rgba(255,255,255,0.02); }
        .pay-panel.hidden { display: none; }

        .pay-btn {
            display:inline-block;
            padding:12px 18px;
            color:#ffffff;
            text-decoration:none;
            border-radius:8px;
            font-weight:700;
            border:none;
            cursor:pointer;
            margin:8px 0 0 0;
        }
        .pay-btn-square { background:#16a34a; }
        .pay-btn-wallet { background:#2563eb; }
        .pay-btn-mobile { background:#7c3aed; }
        .pay-btn-copy { background:#374151; }

        .error-box { border: 1px solid rgba(239, 68, 68, 0.55); background: rgba(127, 29, 29, 0.22); color: #fecaca; border-radius: 10px; padding: 12px 14px; margin-bottom: 1rem; }
        .success-box { border: 1px solid rgba(34, 197, 94, 0.55); background: rgba(22, 101, 52, 0.18); color: #dcfce7; border-radius: 10px; padding: 12px 14px; margin-bottom: 1rem; }

        .snapshot-wrap { position: relative; margin-top: 1rem; border: 1px solid rgba(255,255,255,0.14); border-radius: 14px; padding: 1rem; background: rgba(255,255,255,0.02); }
        .snapshot-header { display:flex; justify-content:space-between; gap:1rem; align-items:flex-start; }
        .snapshot-meta { flex: 1 1 auto; min-width: 0; line-height: 1.65; }
        .snapshot-timer-box {
            width: 220px;
            min-height: 132px;
            border: 1px solid rgba(255,255,255,0.16);
            border-radius: 14px;
            background: rgba(0,0,0,0.18);
            display:flex;
            flex-direction:column;
            justify-content:center;
            align-items:center;
            text-align:center;
            padding: 0.9rem;
        }
        .snapshot-timer-value { font-size: 2rem; font-weight: 800; line-height: 1.1; }
        .snapshot-timer-label { margin-top: 0.55rem; font-size: 0.95rem; opacity: 0.95; }
        .snapshot-timer-expired { color: #f87171; }

        .quote-table { width: 100%; border-collapse: collapse; margin-top: 1rem; }
        .quote-table th, .quote-table td { padding: 0.75rem; border-bottom: 1px solid rgba(255,255,255,0.12); text-align: left; vertical-align: top; }
        .quote-table th { background: #e9eef7; color: #10203f; }
        .quote-badge { display: inline-block; padding: 0.14rem 0.48rem; border-radius: 999px; font-size: 0.78rem; font-weight: 700; margin-left: 0.4rem; }
        .quote-live { background: rgba(34, 197, 94, 0.18); color: #4ade80; }
        .quote-stale { background: rgba(239, 68, 68, 0.18); color: #f87171; }
        .quote-pick-btn { padding: 8px 12px; border-radius: 8px; border: none; background: #2563eb; color: #fff; font-weight: 700; cursor: pointer; }
        .quote-pick-btn[disabled] { opacity: 0.5; cursor: not-allowed; }

        .lock-box { margin-top: 1rem; border: 1px solid rgba(34, 197, 94, 0.28); background: rgba(22, 101, 52, 0.16); border-radius: 12px; padding: 1rem; }
        .lock-box.expired { border-color: rgba(239, 68, 68, 0.55); background: rgba(127, 29, 29, 0.22); }
        .lock-grid { display:grid; grid-template-columns: 1fr 220px; gap:1rem; align-items:start; }
        .lock-code { display:block; margin-top:0.35rem; padding:0.65rem 0.8rem; background: rgba(0,0,0,0.22); border-radius: 8px; overflow-wrap:anywhere; }

        .wallet-actions {
            display:flex;
            gap:0.75rem;
            flex-wrap:wrap;
            margin-top:0.9rem;
            align-items:center;
        }
        .wallet-help {
            margin-top: 0.85rem;
            padding: 0.9rem 1rem;
            border-radius: 10px;
            background: rgba(255,255,255,0.04);
            border: 1px solid rgba(255,255,255,0.10);
        }
        .wallet-help h4 {
            margin: 0 0 0.55rem 0;
            font-size: 1rem;
        }
        .wallet-help p {
            margin: 0.35rem 0;
        }
        .wallet-note { opacity:0.9; margin-top:0.65rem; }
        .mono { font-family: monospace; }
        .copy-row {
            display:flex;
            gap:0.5rem;
            flex-wrap:wrap;
            align-items:center;
            margin-top:0.65rem;
        }
        .copy-target {
            flex: 1 1 420px;
            min-width: 220px;
        }
        .copy-status {
            display:inline-block;
            margin-left: 0.5rem;
            opacity: 0.9;
        }

        @media (max-width: 820px) {
            .snapshot-header, .lock-grid { grid-template-columns: 1fr; display:block; }
            .snapshot-timer-box { width: 100%; margin-top: 1rem; min-height: 110px; }
        }
    </style>
    <link rel="icon" type="image/png" href="/static/favicon.png">
</head>
<body>
<div style="background:#111827;padding:10px 20px;">
  <a href="https://outsidethebox.top" style="color:#60a5fa;text-decoration:none;font-weight:bold;">
    ← OutsideTheBox Home
  </a>
</div>

<div class="portal-wrap">
    <div class="portal-top">
        <div>
            <h1>Invoice Detail</h1>
            <p>{{ client.company_name or client.contact_name or client.email }}</p>
        </div>
        <div class="portal-actions">
            <a href="/portal/dashboard">Back to Dashboard</a>
            <a href="https://outsidethebox.top/">Home</a>
            <a href="mailto:support@outsidethebox.top?subject=Portal%20Support">Contact Support</a>
            <a href="/portal/logout">Logout</a>
        </div>
    </div>

    {% if (invoice.status or "")|lower == "paid" %}
    <div class="success-box">✓ This invoice has been paid. Thank you!</div>
    {% endif %}

    {% if crypto_error %}
    <div class="error-box">{{ crypto_error }}</div>
    {% endif %}

    <div class="detail-grid">
        <div class="detail-card"><h3>Invoice</h3><div>{{ invoice.invoice_number or ("INV-" ~ invoice.id) }}</div></div>
        <div class="detail-card">
            <h3>Status</h3>
            {% set s = (invoice.status or "")|lower %}
            {% if pending_crypto_payment and pending_crypto_payment.txid and not pending_crypto_payment.processing_expired and s != "paid" %}
                <span class="status-badge status-pending">processing</span>
            {% elif s == "paid" %}<span class="status-badge status-paid">{{ invoice.status }}</span>
            {% elif s == "pending" %}<span class="status-badge status-pending">{{ invoice.status }}</span>
            {% elif s == "overdue" %}<span class="status-badge status-overdue">{{ invoice.status }}</span>
            {% else %}<span class="status-badge status-other">{{ invoice.status }}</span>{% endif %}
        </div>
        <div class="detail-card"><h3>Created</h3><div>{{ invoice.created_at }}</div></div>
        <div class="detail-card"><h3>Total</h3><div>{{ invoice.total_amount }}</div></div>
        <div class="detail-card"><h3>Paid</h3><div>{{ invoice.amount_paid }}</div></div>
        <div class="detail-card"><h3>Outstanding</h3><div>{{ invoice.outstanding }}</div></div>
    </div>

    <h2>Invoice Items</h2>
    <table class="portal-table">
        <thead><tr><th>Description</th><th>Qty</th><th>Unit Price</th><th>Line Total</th></tr></thead>
        <tbody>
            {% for item in items %}
            <tr><td>{{ item.description }}</td><td>{{ item.quantity }}</td><td>{{ item.unit_price }}</td><td>{{ item.line_total }}</td></tr>
            {% else %}
            <tr><td colspan="4">No invoice line items found.</td></tr>
            {% endfor %}
        </tbody>
    </table>

    {% if (invoice.status or "")|lower != "paid" and invoice.outstanding != "0.00" %}
    <div class="pay-card">
        <h3>Pay Now</h3>
        <div class="pay-selector-row">
            <label for="payMethodSelect"><strong>Choose payment method:</strong></label>
            <select id="payMethodSelect" class="pay-selector">
                <option value="" {% if not pay_mode %}selected{% endif %}>Select…</option>
                <option value="etransfer" {% if pay_mode == "etransfer" %}selected{% endif %}>e-Transfer</option>
                <option value="square" {% if pay_mode == "square" %}selected{% endif %}>Credit Card</option>
                <option value="crypto" {% if pay_mode == "crypto" %}selected{% endif %}>Crypto</option>
            </select>
        </div>

        <div id="panel-etransfer" class="pay-panel{% if pay_mode != 'etransfer' %} hidden{% endif %}">
            <p><strong>Interac e-Transfer</strong><br>Send payment to:<br>payment@outsidethebox.top<br>Reference: Invoice {{ invoice.invoice_number or ("INV-" ~ invoice.id) }}</p>
        </div>

        <div id="panel-square" class="pay-panel{% if pay_mode != 'square' %} hidden{% endif %}">
            <p><strong>Credit Card (Square)</strong></p>
            <a href="/portal/invoice/{{ invoice.id }}/pay-square" target="_blank" rel="noopener noreferrer" class="pay-btn pay-btn-square">Pay with Credit Card</a>
        </div>

        <div id="panel-crypto" class="pay-panel{% if pay_mode != 'crypto' %} hidden{% endif %}">
            {% if invoice.oracle_quote and invoice.oracle_quote.quotes and crypto_options %}
                <div class="snapshot-wrap">
                    <div class="snapshot-header">
                        <div class="snapshot-meta">
                            <h3 style="margin-top:0;">Crypto Quote Snapshot</h3>
                            <div><strong>Quoted At:</strong> {{ invoice.oracle_quote.quoted_at or "—" }}</div>
                            <div><strong>Source Status:</strong> {{ invoice.oracle_quote.source_status or "—" }}</div>
                            <div><strong>Frozen Amount:</strong> {{ invoice.oracle_quote.amount or invoice.quote_fiat_amount or invoice.total_amount }} {{ invoice.oracle_quote.fiat or invoice.quote_fiat_currency or "CAD" }}</div>
                            {% if pending_crypto_payment %}
                                <div style="margin-top:0.75rem;"><strong>Your quote is protected after acceptance.</strong></div>
                            {% else %}
                                <div style="margin-top:0.75rem;"><strong>Select a crypto asset to accept the quote.</strong></div>
                            {% endif %}
                        </div>

                        {% if pending_crypto_payment and pending_crypto_payment.txid %}
                        <div class="snapshot-timer-box">
                            <div id="processingTimerValue" class="snapshot-timer-value" data-expiry="{{ pending_crypto_payment.processing_expires_at_iso }}">--:--</div>
                            <div id="processingTimerLabel" class="snapshot-timer-label">Watching transaction / waiting for confirmation</div>
                        </div>
                        {% elif pending_crypto_payment %}
                        <div class="snapshot-timer-box">
                            <div id="lockTimerValue" class="snapshot-timer-value" data-expiry="{{ pending_crypto_payment.lock_expires_at_iso }}">--:--</div>
                            <div id="lockTimerLabel" class="snapshot-timer-label">Quote protected while you open wallet</div>
                        </div>
                        {% else %}
                        <div class="snapshot-timer-box">
                            <div id="quoteTimerValue" class="snapshot-timer-value" data-expiry="{{ crypto_quote_window_expires_iso }}">--:--</div>
                            <div id="quoteTimerLabel" class="snapshot-timer-label">This price times out:</div>
                        </div>
                        {% endif %}
                    </div>

                    {% if pending_crypto_payment and selected_crypto_option %}
                    <div id="lockBox" class="lock-box{% if pending_crypto_payment.lock_expired or pending_crypto_payment.processing_expired %} expired{% endif %}">
                        <div class="lock-grid">
                            <div>
                                <h3 style="margin-top:0;">{{ selected_crypto_option.label }} Payment Instructions</h3>
                                <div><strong>Send exactly:</strong> {{ pending_crypto_payment.payment_amount }} {{ pending_crypto_payment.payment_currency }}</div>
                                <div style="margin-top:0.65rem;"><strong>Destination wallet:</strong></div>
                                <code id="walletAddressText" class="lock-code copy-target">{{ pending_crypto_payment.wallet_address }}</code>
                                <div style="margin-top:0.65rem;"><strong>Reference / Invoice:</strong></div>
                                <code id="invoiceRefText" class="lock-code copy-target">{{ pending_crypto_payment.reference }}</code>

                                {% if selected_crypto_option.wallet_capable and not pending_crypto_payment.txid and not pending_crypto_payment.lock_expired %}
                                <div class="wallet-actions">
                                    <button
                                        type="button"
                                        id="walletPayButton"

=== /home/def/otb_billing/templates/portal_forgot_password.html ===
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Forgot Portal Password - OutsideTheBox</title>
    <link rel="stylesheet" href="/static/css/style.css">
    <style>
        .portal-wrap { max-width: 760px; margin: 2.5rem auto; padding: 1.5rem; }
        .portal-card {
            border: 1px solid rgba(255,255,255,0.16);
            border-radius: 16px;
            padding: 1.4rem;
            background: rgba(255,255,255,0.03);
            box-shadow: 0 10px 24px rgba(0,0,0,0.18);
        }
        .portal-card h1 { margin-top: 0; margin-bottom: 0.45rem; }
        .portal-sub { opacity: 0.9; margin-bottom: 1.25rem; }
        .portal-form { display: grid; gap: 0.9rem; }
        .portal-form label { display: block; font-weight: 600; margin-bottom: 0.35rem; }
        .portal-form input {
            width: 100%;
            padding: 0.8rem 0.9rem;
            border-radius: 10px;
            border: 1px solid rgba(255,255,255,0.18);
            background: rgba(255,255,255,0.05);
            color: inherit;
            box-sizing: border-box;
        }
        .portal-actions { display: flex; gap: 0.8rem; flex-wrap: wrap; margin-top: 0.4rem; }
        .portal-btn {
            display: inline-block;
            padding: 0.8rem 1rem;
            border-radius: 10px;
            text-decoration: none;
            border: 1px solid rgba(255,255,255,0.18);
            background: rgba(255,255,255,0.06);
            color: inherit;
            cursor: pointer;
        }
        .portal-msg {
            margin-bottom: 1rem;
            padding: 0.85rem 1rem;
            border-radius: 10px;
            border: 1px solid rgba(255,255,255,0.16);
            background: rgba(255,255,255,0.04);
        }
    </style>
    <link rel="icon" type="image/png" href="/static/favicon.png">
</head>
<body>
<div style="background:#111827;padding:10px 20px;">
  <a href="https://outsidethebox.top" style="color:#60a5fa;text-decoration:none;font-weight:bold;">
    ← OutsideTheBox Home
  </a>
</div>

<div class="portal-wrap">
    <div class="portal-card">
        <h1>Reset Portal Password</h1>
        <p class="portal-sub">Enter your email address and a new single-use access code will be sent if your account exists.</p>

        {% if error %}
        <div class="portal-msg">{{ error }}</div>
        {% endif %}

        {% if message %}
        <div class="portal-msg">{{ message }}</div>
        {% endif %}

        <form class="portal-form" method="post" action="/portal/forgot-password">
            <div>
                <label for="email">Email Address</label>
                <input id="email" name="email" type="email" value="{{ form_email or '' }}" required>
            </div>

            <div class="portal-actions">
                <button class="portal-btn" type="submit">Send Reset Code</button>
                <a class="portal-btn" href="/portal">Back to Portal Login</a>
                <a class="portal-btn" href="mailto:support@outsidethebox.top?subject=Portal%20Support">Contact Support</a>
            </div>
        </form>
    </div>
</div>

{% include "footer.html" %}
</body>
</html>

=== /home/def/otb_billing/templates/portal_set_password.html ===
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Set Portal Password - OutsideTheBox</title>
    <link rel="stylesheet" href="/static/css/style.css">
    <style>
        .portal-wrap { max-width: 760px; margin: 2.5rem auto; padding: 1.5rem; }
        .portal-card {
            border: 1px solid rgba(255,255,255,0.16);
            border-radius: 16px;
            padding: 1.4rem;
            background: rgba(255,255,255,0.03);
            box-shadow: 0 10px 24px rgba(0,0,0,0.18);
        }
        .portal-form { display: grid; gap: 0.9rem; }
        .portal-form label { display: block; font-weight: 600; margin-bottom: 0.35rem; }
        .portal-form input {
            width: 100%;
            padding: 0.8rem 0.9rem;
            border-radius: 10px;
            border: 1px solid rgba(255,255,255,0.18);
            background: rgba(255,255,255,0.05);
            color: inherit;
            box-sizing: border-box;
        }
        .portal-btn {
            display: inline-block;
            padding: 0.8rem 1rem;
            border-radius: 10px;
            text-decoration: none;
            border: 1px solid rgba(255,255,255,0.18);
            background: rgba(255,255,255,0.06);
            color: inherit;
            cursor: pointer;
        }
        .portal-msg {
            margin-bottom: 1rem;
            padding: 0.85rem 1rem;
            border-radius: 10px;
            border: 1px solid rgba(255,255,255,0.16);
            background: rgba(255,255,255,0.04);
        }
    </style>
    <link rel="icon" type="image/png" href="/static/favicon.png">
</head>
<body>
<div style="background:#111827;padding:10px 20px;">
  <a href="https://outsidethebox.top" style="color:#60a5fa;text-decoration:none;font-weight:bold;">
    ← OutsideTheBox Home
  </a>
</div>

<div class="portal-wrap">
    <div class="portal-card">
        <h1>Create Your Portal Password</h1>
        <p>Welcome, {{ client_name }}. Your one-time access code worked. Please create a password for future logins.</p>

        {% if portal_message %}
        <div class="portal-msg">{{ portal_message }}</div>
        {% endif %}

        <form class="portal-form" method="post" action="/portal/set-password">
            <div>
                <label for="password">New Password</label>
                <input id="password" name="password" type="password" required>
            </div>
            <div>
                <label for="password2">Confirm Password</label>
                <input id="password2" name="password2" type="password" required>
            </div>
            <div>
                <button class="portal-btn" type="submit">Set Password</button>
            </div>
        </form>
    </div>
</div>

{% include "footer.html" %}
</body>
</html>
