<?php
/* ##########################
[client_email]
[dev_email]
[dev_signature]
[dev_ip]
[dev_timestamp]
[dev_timestamp_offset]
[dev_name]
[client_name]
################################### */

//error_reporting(E_ERROR | E_PARSE);
error_reporting(E_ALL);
ini_set("display_errors", 1);

date_default_timezone_set("Australia/Hobart");
ini_set("default_charset", "UTF-8");
mb_internal_encoding("UTF-8");

require_once __DIR__ . "/Parsedown.php";
require_once __DIR__ . "/dompdf/autoload.inc.php";

use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\SMTP;
use PHPMailer\PHPMailer\Exception;
require_once "../internal/phpmailer/src/Exception.php";
require_once "../internal/phpmailer/src/PHPMailer.php";
require_once "../internal/phpmailer/src/SMTP.php";

// at the top, before any output
session_start();
if ($_SERVER["REQUEST_METHOD"] === "POST") {
    $ok = isset($_POST["csrf"], $_SESSION["csrf"]) && hash_equals($_SESSION["csrf"], $_POST["csrf"]);
    if (!$ok) {
        http_response_code(403);
        exit("Invalid CSRF token");
    }
}

if (empty($_SESSION["csrf"])) {
    $_SESSION["csrf"] = bin2hex(random_bytes(32));
}
/* ------------------------------- CSRF (same) ---------------------------------- */
$cfg 				= @include __DIR__ . "/config.php";
$cfg 				= is_array($cfg) ? $cfg : [];
$csrf 				= htmlspecialchars($_SESSION["csrf"] ?? "", ENT_QUOTES, "UTF-8");

// Behavior flags
$redirectToSigned 	= true; // keep this true
$allowSelfDelete  	= (bool)($cfg['self_delete'] ?? false);  // default off

$fromAddress 		= $cfg["from_address"] ?? "drafting@modulosdesign.com.au";

$clientIdRaw 		= $_GET['clientid'] ?? '';
$clientId    		= preg_match('/^[A-Za-z0-9_-]{1,64}$/', $clientIdRaw) ? $clientIdRaw : 'unknown';

$devName     		= $cfg['dev_name'] ?? 'Modulos Design';
$devEmail 			= $cfg["dev_email"] ?? 'drafting@modulosdesign.com.au';
$devEmail 			= preg_replace('/[\r\n]+/', "", $devEmail);
$devSig 			= $cfg["dev_signature"] ?? "";
$devPhone      		= $cfg['dev_phone']      ?? '';
$devAddress    		= $cfg['dev_address']    ?? '';

$clientName  		= $_GET['client_name'] ?? '';
$clientEmail 		= $_POST['client_email'] ?? $_GET['client_email'] ?? '';
$clientEmail 		= trim(preg_replace('/[\r\n]+/', '', (string)$clientEmail)); // strip CRLF + trim

$clientPhone   		= $_GET['client_phone']   ?? '';
$clientAddress 		= $_GET['client_address'] ?? '';

// 🔧 Fallback to front matter if still empty
if ($clientEmail === '') {
    $meta = parseFrontMatterForId($clientId);
    $clientEmailFromMd = '';
    if (is_array($meta)) {
        // prefer nested client.email, but accept client_email if present
        $clientEmailFromMd = (string)(
            getByPath($meta, 'client.email', '') ?:
            ($meta['client']['email'] ?? '') ?:
            ($meta['client_email'] ?? '')
        );
    }
    if ($clientEmailFromMd !== '') {
        $clientEmail = trim(preg_replace('/[\r\n]+/', '', $clientEmailFromMd));
    }
}



if (is_string($devSig) && $devSig !== '') {
    // Can be a data: URL or a normal URL; both are fine
    $DEV_SIGNATURE = '<img id="dev_signature" src="' . htmlspecialchars($devSig, ENT_QUOTES, 'UTF-8') . '" style="max-height: 117px;padding: 10px;" alt="Client Relations Signature">';
} elseif (!empty($devSigPath) && is_file($devSigPath)) {
    // Fallback: original file-path logic
    $abs = realpath($devSigPath) ?: $devSigPath;
    $prefix = rtrim($_SERVER["DOCUMENT_ROOT"] ?? "", "/");
    $devSigUrl = str_replace($prefix, "", $abs);
    if ($devSigUrl === $abs) {
        // fallback if the file is outside docroot
        $devSigUrl = $abs;
    }
    $DEV_SIGNATURE = '<img id="dev_signature" src="' . htmlspecialchars($devSigUrl, ENT_QUOTES, "UTF-8") . '" style="max-height: 117px;padding: 10px;" alt="Client Relations Signature">';
}

function loadContractHtml(?string $clientId, array $overrides = []): string {
    $safeId = preg_match('/^[A-Za-z0-9_-]{1,64}$/', (string)$clientId) ? (string)$clientId : 'default';
	$path   = __DIR__ . '/contracts/' . $safeId . '.md';
    if (!is_file($path)) $path = __DIR__ . '/contracts/default.md';

    $md = file_get_contents($path);

    // 1) Split front matter and body
    $vars = [];
    $body = $md;
    if (preg_match('/^\s*---\s*\n(.*?)\n---\s*\n(.*)$/s', $md, $m)) {
        $front = $m[1];
        $body  = $m[2];
        $vars  = parseFrontMatter($front);
    }

    // 2) Defaults available to every document
    $base = [
        'dev' => [
            'name'    => $GLOBALS['devName']    ?? 'Modulos Design',
            'email'   => $GLOBALS['devEmail']   ?? 'drafting@modulosdesign.com.au',
            'phone'   => $GLOBALS['devPhone']   ?? '',
            'address' => $GLOBALS['devAddress'] ?? '',
        ],
        'client' => [
            'name'    => $GLOBALS['clientName']    ?? '',
            'email'   => $GLOBALS['clientEmail']   ?? '',
            'phone'   => $GLOBALS['clientPhone']   ?? '',
            'address' => $GLOBALS['clientAddress'] ?? '',
        ],
        'today' => date('F j, Y'),
    ];

    // 3) Merge: URL or POST overrides > front matter > base
    $merged = array_replace_recursive($base, $vars, $overrides);

    // 4) Also allow flat GET overrides like client_name=...
    foreach (['client_name' => 'client.name', 'client_email' => 'client.email', 'client_phone' => 'client.phone'] as $q => $pathKey) {
        if (isset($_GET[$q]) && $_GET[$q] !== '') {
            setByPath($merged, $pathKey, (string)$_GET[$q]);
        }
    }

    // 5) Replace [path.to.value] placeholders in the Markdown body
    $body = preg_replace_callback('/\[([a-zA-Z0-9_.-]+)\]/', function ($m) use ($merged) {
        $val = getByPath($merged, $m[1]);
        return is_scalar($val) ? (string)$val : '';
    }, $body);

    // 6) Convert to HTML
    $Parsedown = new Parsedown();
    $Parsedown->setSafeMode(true);
    return $Parsedown->text($body);
}

function parseFrontMatter(string $text): array {
    // If the PECL yaml extension is available, use it
    if (function_exists('yaml_parse')) {
        $arr = @yaml_parse($text);
        return is_array($arr) ? $arr : [];
    }

    // Minimal indentation-aware parser for nested maps and simple lists
    $lines = preg_split('/\R/', rtrim($text));
    $root  = [];
    $stack = [ ['indent' => -1, 'ref' => &$root] ];

    foreach ($lines as $raw) {
        if ($raw === '') continue;
        $trimmed = ltrim($raw, ' ');
        if ($trimmed === '' || $trimmed[0] === '#') continue;

        $indent = strlen($raw) - strlen($trimmed);
        // climb up to the correct parent by indent
        while (count($stack) > 1 && $indent <= $stack[array_key_last($stack)]['indent']) {
            array_pop($stack);
        }
        $parent =& $stack[array_key_last($stack)]['ref'];

        // List item
        if (preg_match('/^-\s*(.*)$/', $trimmed, $m)) {
            $val = $m[1];
            if (!is_array($parent)) $parent = [];
            if ($val === '') {
                $parent[] = [];
                $stack[] = ['indent' => $indent, 'ref' => &$parent[array_key_last($parent)]];
            } else {
                $parent[] = _fm_trim_quotes($val);
            }
            continue;
        }

        // Key: value or Key:
        if (preg_match('/^([A-Za-z0-9_.-]+):\s*(.*)$/', $trimmed, $m)) {
            $key = $m[1];
            $val = $m[2];
            if ($val === '') {
                if (!isset($parent[$key]) || !is_array($parent[$key])) {
                    $parent[$key] = [];
                }
                $stack[] = ['indent' => $indent, 'ref' => &$parent[$key]];
            } else {
                $parent[$key] = _fm_trim_quotes($val);
            }
        }
    }
    return $root;
}

function parseFrontMatterForId(?string $clientId): array {
    $safeId = preg_match('/^[A-Za-z0-9_-]{1,64}$/', (string)$clientId) ? (string)$clientId : 'default';
    $path   = __DIR__ . '/contracts/' . $safeId . '.md';
    if (!is_file($path)) $path = __DIR__ . '/contracts/default.md';
    $md = @file_get_contents($path);
    if ($md && preg_match('/^\s*---\s*\n(.*?)\n---\s*\n/s', $md, $m)) {
        return parseFrontMatter($m[1]);
    }
    return [];
}

function getPreparedDateFromMd(string $clientId): string {
    $safe = preg_match('/^[A-Za-z0-9_-]{1,64}$/', $clientId) ? $clientId : 'default';
	$path = __DIR__ . '/contracts/' . $safe . '.md';
    if (!is_file($path)) $path = __DIR__ . '/contracts/default.md';

    $md = file_get_contents($path);
    if (preg_match('/^\s*---\s*\n(.*?)\n---/s', $md, $m)) {
        $meta = parseFrontMatter($m[1]);
        $prepared = getByPath($meta, 'dates.prepared', '');
        return is_string($prepared) ? $prepared : '';
    }
    return '';
}

function _fm_trim_quotes(string $v): string {
    $v = trim($v);
    if ($v !== '' && $v[0] === "'" && substr($v, -1) === "'") return stripslashes(substr($v, 1, -1));
    if ($v !== '' && $v[0] === '"' && substr($v, -1) === '"') return stripslashes(substr($v, 1, -1));
    return $v;
}


function getByPath(array $arr, string $path, $default = '') {
    $keys = explode('.', $path);
    foreach ($keys as $k) {
        if ($k === '') continue;
        if (is_array($arr) && array_key_exists($k, $arr)) {
            $arr = $arr[$k];
        } else {
            return $default;
        }
    }
    return $arr;
}

function setByPath(array &$arr, string $path, $value): void {
    $keys = explode('.', $path);
    $ref =& $arr;
    foreach ($keys as $k) {
        if ($k === '') continue;
        if (!isset($ref[$k]) || !is_array($ref[$k])) $ref[$k] = [];
        $ref =& $ref[$k];
    }
    $ref = $value;
}

// Gets the current file URL and replaces the .php extension with .html
function getHtmlUrl(string $htmlName): string {
    $https  = !empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off';
    $scheme = $https ? 'https' : 'https';
    $host   = $_SERVER['HTTP_HOST'] ?? 'localhost';
    $dir    = rtrim(dirname($_SERVER['SCRIPT_NAME'] ?? ''), '/\\');
    return $scheme . '://' . $host . ($dir ? $dir : '') . '/' . $htmlName;
}

function getClientIp(): string {
    // 2) X-Forwarded-For: "client, proxy1, proxy2"
    if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
        $parts = array_map('trim', explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']));
        foreach ($parts as $ip) {
            if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
                return $ip; // first public address
            }
        }
        // if nothing public, take the first valid one
        foreach ($parts as $ip) {
            if (filter_var($ip, FILTER_VALIDATE_IP)) {
                return $ip;
            }
        }
    }

    // 3) X-Real-IP
    if (!empty($_SERVER['HTTP_X_REAL_IP']) &&
        filter_var($_SERVER['HTTP_X_REAL_IP'], FILTER_VALIDATE_IP)) {
        return $_SERVER['HTTP_X_REAL_IP'];
    }

    // 4) Fallback
    if (!empty($_SERVER['REMOTE_ADDR']) &&
        filter_var($_SERVER['REMOTE_ADDR'], FILTER_VALIDATE_IP)) {
        return $_SERVER['REMOTE_ADDR'];
    }

    return 'UNKNOWN';
}

// Build overrides only when values are non-empty
$ov = ['client' => [], 'dev' => []];

if ($clientName   !== '') $ov['client']['name']    = $clientName;
if ($clientEmail  !== '') $ov['client']['email']   = $clientEmail;
if ($clientPhone  !== '') $ov['client']['phone']   = $clientPhone;
if ($clientAddress!== '') $ov['client']['address'] = $clientAddress;

if ($devName      !== '') $ov['dev']['name']       = $devName;
if ($devEmail     !== '') $ov['dev']['email']      = $devEmail;
if ($devPhone     !== '') $ov['dev']['phone']      = $devPhone;
if ($devAddress   !== '') $ov['dev']['address']    = $devAddress;

$CONTRACT_HTML = loadContractHtml($_GET['clientid'] ?? null, $ov);

$CLIENT_SIGNATURE = $_POST["client_signature"] ?? null;

if ( is_string($CLIENT_SIGNATURE) && str_starts_with($CLIENT_SIGNATURE, "data:image/png;base64,") ) {
    // Size guard, rejects very large data URIs
    if (strlen($CLIENT_SIGNATURE) > 2 * 1024 * 1024) { 
        http_response_code(413);
        exit("Signature too large");
    }
    $CLIENT_SIGNATURE = '<img id="hk" src="' . htmlspecialchars($CLIENT_SIGNATURE, ENT_QUOTES, "UTF-8") . '">';
} else {
    $CLIENT_SIGNATURE = null;
}

/* -------------------------------------------------------------------------- */
/*                              SECURITY AND ACCESS                           */
/* -------------------------------------------------------------------------- */

// Optional config
$cfg = @include __DIR__ . '/config.php';
$cfg = is_array($cfg) ? $cfg : [];

// Optional admin creds for Basic Auth or old token scheme
$ADMIN_USER = $cfg['admin_user']   ?? ($ADMIN_USER   ?? '');
$ADMIN_PASS = $cfg['admin_pass']   ?? ($ADMIN_PASS   ?? '');
$SECRET_KEY = $cfg['admin_secret'] ?? ($SECRET_KEY   ?? ''); // old global secret, if you still use it

// Front matter helpers reused from your client file
if (!function_exists('_fm_trim_quotes')) {
    function _fm_trim_quotes(string $v) {
        $v = trim($v);
        if ($v === '') return '';
        $q = $v[0];
        if (($q === '"' || $q === "'") && substr($v, -1) === $q) return substr($v, 1, -1);
        return $v;
    }
}
if (!function_exists('parseFrontMatter')) {
    function parseFrontMatter(string $text): array {
        if (function_exists('yaml_parse')) {
            $arr = @yaml_parse($text);
            return is_array($arr) ? $arr : [];
        }
        $lines = preg_split('/\R/', rtrim($text));
        $root  = [];
        $stack = [ ['indent' => -1, 'ref' => &$root] ];
        foreach ($lines as $raw) {
            if ($raw === '') continue;
            $trim = ltrim($raw, ' ');
            if ($trim === '' || $trim[0] === '#') continue;
            $indent = strlen($raw) - strlen($trim);
            while (count($stack) > 1 && $indent <= $stack[array_key_last($stack)]['indent']) array_pop($stack);
            $parent =& $stack[array_key_last($stack)]['ref'];
            if (preg_match('/^-\s*(.*)$/', $trim, $m)) {
                $val = $m[1];
                if (!is_array($parent)) $parent = [];
                if ($val === '') {
                    $parent[] = [];
                    $stack[] = ['indent' => $indent, 'ref' => &$parent[array_key_last($parent)]];
                } else {
                    $parent[] = _fm_trim_quotes($val);
                }
                continue;
            }
            if (preg_match('/^([A-Za-z0-9_.-]+):\s*(.*)$/', $trim, $m)) {
                $key = $m[1];
                $val = $m[2];
                if ($val === '') {
                    if (!isset($parent[$key]) || !is_array($parent[$key])) $parent[$key] = [];
                    $stack[] = ['indent' => $indent, 'ref' => &$parent[$key]];
                } else {
                    $parent[$key] = _fm_trim_quotes($val);
                }
            }
        }
        return $root;
    }
}
if (!function_exists('parseFrontMatterForId')) {
    function parseFrontMatterForId(?string $clientId): array {
        $safeId = preg_match('/^[A-Za-z0-9_-]{1,64}$/', (string)$clientId) ? $clientId : 'default';
        $path   = __DIR__ . '/contracts/' . $safeId . '.md';
        if (!is_file($path)) $path = __DIR__ . '/contracts/default.md';
        $md = @file_get_contents($path);
        if ($md && preg_match('/^\s*---\s*\n(.*?)\n---\s*\n/s', $md, $m)) {
            return parseFrontMatter($m[1]);
        }
        return [];
    }
}
function fm_admin_secret_for(string $clientId): string {
    $fm = parseFrontMatterForId($clientId);
    // support either nested admin.secret or a flat admin_secret
    if (!empty($fm['admin']) && is_array($fm['admin']) && !empty($fm['admin']['secret'])) {
        return (string)$fm['admin']['secret'];
    }
    if (!empty($fm['admin_secret'])) return (string)$fm['admin_secret'];
    return '';
}

/**
 * Accept both link formats:
 * 1) New style:  contract.php?clientid=3043&token=HMAC_SHA256(clientid, fm_admin_secret)
 * 2) Old style:  contract.php?token=HMAC_SHA256(ADMIN_USER|ADMIN_PASS|expires, SECRET_KEY)&expires=UNIX
 */
function access_allowed_by_token(): bool {
    global $ADMIN_USER, $ADMIN_PASS, $SECRET_KEY;

    $clientId = $_GET['clientid'] ?? '';
    $token    = $_GET['token']    ?? '';
    $expires  = isset($_GET['expires']) ? (int)$_GET['expires'] : 0;

    if ($token === '') return false;

    // Old scheme with expiry and global secret
    if ($expires > 0 && $ADMIN_USER !== '' && $ADMIN_PASS !== '' && $SECRET_KEY !== '') {
        if ($expires < time()) return false;
        $expected = hash_hmac('sha256', $ADMIN_USER . '|' . $ADMIN_PASS . '|' . $expires, $SECRET_KEY);
        if (hash_equals($expected, $token)) return true;
    }

    // New scheme with per-client secret in front matter
    if ($clientId !== '') {
        $secret = fm_admin_secret_for($clientId);
        if ($secret !== '') {
            $expected2 = hash_hmac('sha256', $clientId, $secret);
            if (hash_equals($expected2, $token)) return true;
        }
    }

    return false;
}

function require_admin_auth(): void {
    global $ADMIN_USER, $ADMIN_PASS;

    // Allow valid token to bypass auth for clients
    if (access_allowed_by_token()) return;

    // If admin creds are not configured, block
    if ($ADMIN_USER === '' || $ADMIN_PASS === '') {
        http_response_code(401);
        echo 'Auth required';
        exit;
    }

    // Basic Auth for admins
    if (!isset($_SERVER['PHP_AUTH_USER'])) {
        header('WWW-Authenticate: Basic realm="Contracts Admin"');
        header('HTTP/1.0 401 Unauthorized');
        echo 'Auth required';
        exit;
    }
    if ($_SERVER['PHP_AUTH_USER'] !== $ADMIN_USER || ($_SERVER['PHP_AUTH_PW'] ?? '') !== $ADMIN_PASS) {
        header('WWW-Authenticate: Basic realm="Contracts Admin"');
        header('HTTP/1.0 401 Unauthorized');
        echo 'Invalid credentials';
        exit;
    }
}

require_admin_auth();


/** The HTML code (and some PHP) is kept in PHP variables like $CONTRACT_HTML, $FOOTER, $CONTRACT_SIGNED_PHP, and $CLIENT_DATE_IP_COMPILED. **/

function headerWithTitle(
    string $title,
    ?string $clientId = null,
    ?string $preparedDate = null,
    string $context = 'web' // 'web' or 'pdf'
): string {
    $safeTitle        = htmlspecialchars($title, ENT_QUOTES, 'UTF-8');
    $safeJob          = htmlspecialchars((string)$clientId, ENT_QUOTES, 'UTF-8');
    $safePreparedDate = htmlspecialchars((string)$preparedDate, ENT_QUOTES, 'UTF-8');

    $baseHref = htmlspecialchars(
        ((!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https' : 'https')
        . '://' . ($_SERVER['HTTP_HOST'] ?? 'localhost')
        . rtrim(dirname($_SERVER['SCRIPT_NAME'] ?? ''), '/\\') . '/',
        ENT_QUOTES,
        'UTF-8'
    );

    // CSS includes differ by context
    $cssLinks = $context === 'web'
        ? <<<HTML
  <link rel="preconnect" href="https://cdn.jsdelivr.net">
  <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.7/dist/css/bootstrap.min.css" rel="stylesheet">
  <link href="../internal/css/blueprint.css" rel="stylesheet">
  <link href="../internal/css/print.css" rel="stylesheet" media="print">
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css">
  <link href="style.css" rel="stylesheet">
HTML
        : <<<HTML
  <!-- Minimal CSS for PDF -->
  <link href="../internal/css/blueprint.css" rel="stylesheet">
  <link href="style.css" rel="stylesheet">
  <style>
    @page { margin: 5mm 10mm 10mm 10mm; }
    body { background:#fff;}
    .container { max-width: 780px; margin: 0 auto; font-size:0.7rem; }
    .shadow-sm { box-shadow: none !important; }
    .rounded-3 { border-radius: 0 !important; }
    .bg-white { background: #fff !important; }
    .d-print-none, .noprint { display: none !important; }
    .img-logo { max-height: 40px; }
    .page-header { display: table; width: 100%; table-layout: fixed; }
    .page-header > .col-4 { display: table-cell; width: 33.333%; vertical-align: middle; padding: 0 8px; }
    .page-header .text-start { text-align: left; }
    .page-header .text-center { text-align: center; }
    .page-header .text-end { text-align: right; }
    .compiled-signatures { display: table; width: 100%; table-layout: fixed; margin-top: 1rem; }
    .compiled-signatures .compiled-signature { display: table-cell; width: 35%; vertical-align: bottom; padding: 0 8px; }
    .compiled-signatures img { max-width: 100%; height: auto; }
  </style>
HTML;

    // No JS in PDF
    $jsLinks = $context === 'web'
        ? <<<HTML
  <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.7/dist/js/bootstrap.bundle.min.js"></script>
HTML
        : '';

    // Navbar only for web
    $nav = $context === 'web'
        ? <<<HTML
  <nav class="navbar bg-brown-dark brown-light border-bottom border-body d-print-none" data-bs-theme="dark">
    <div class="container-fluid">
      <a class="navbar-brand brown-light" href="#">
        <img src="../internal/images/blueprint-logo-light.png" alt="Modulos Design" width="30" height="24" class="d-inline-block align-text-top" >
        Modulos Design
      </a>
    </div>
  </nav>
HTML
        : '';

    return <<<HTML
<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>{$safeJob} - {$safeTitle}</title>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <meta name="robots" content="noindex">
  <link rel="shortcut icon" href="../internal/images/blueprint.ico" type="image/x-icon">
  <base href="{$baseHref}">
{$cssLinks}
{$jsLinks}
</head>
<body>
{$nav}
  <main class="container my-4">
    <div class="bg-white p-4 p-md-5 rounded-0 shadow-sm">
      <div class="row align-items-center page-header">
        <div class="col-12 col-md-6 text-start">
          <img class="img-fluid pt-2 img-logo" src="../internal/images/blueprint-full-logo-medium.png" height="100" alt="Modulos Design">
        </div>
        <div class="col-12 col-md-6 text-end pt-3">
          <h3 class="fw-bold mb-1" style="color:#373a3c;">Job: {$safeJob}</h3>
          <h4 class="mb-1"><span class="fw-bold text-secondary">{$safePreparedDate}</span></h4>
        </div>
      </div>
HTML;
}

function footerFor(string $context = 'web'): string {
    $extra = $context === 'web'
        ? <<<HTML
  <script>
    function printContract(){ window.print(); }
  </script>
HTML
        : ''; // no JS for PDF

    return <<<HTML
    </div> <!-- /.rounded-3 -->
  </main>
{$extra}
</body>
</html>
HTML;
}


if ($CLIENT_SIGNATURE == null) {
    /** ⌛ Waiting for Client to sign: include signature elements and javascript **/
    // If a signed file already exists for this client, send them there
    if ($redirectToSigned) {
        $pattern = __DIR__ . "/{$clientId}_signed_contract*.html";
        $matches = glob($pattern);
        if ($matches) {
            usort($matches, fn($a, $b) => filemtime($b) <=> filemtime($a));
            $latest = basename($matches[0]);
            header("Location: " . $latest . "#hk", true, 302);
            exit;
        }
    }

    if (!headers_sent()) {
        header('Content-Type: text/html; charset=UTF-8');
    }

    $preparedDate = $_GET['prepared'] ?? getPreparedDateFromMd($clientId) ?: date('F j, Y');

    $HEADER = headerWithTitle(
        'Unsigned Contract',
        $clientId,       // show this as “Job: …”
        $preparedDate,    // show this as the date
        'web'
    );


    //$clientEmailInit = htmlspecialchars($_GET['client_email'] ?? '', ENT_QUOTES, 'UTF-8');

    $FOOTER = <<<HTML
  <div id="ui-unsigned"> 
    <form method="post" class="noprint" id="signature_form">
        <div id="signature-container">
            <div id="canvas-container">
                <canvas id="signature-pad" class="signature-pad" width="188" height="58.66"></canvas>
            </div>
        </div>

        <div class="animate slide">
            <div id="signature-controls" class="d-flex gap-2 justify-content-center mt-3">
              <button id="reset" type="button" class="btn btn-warning rounded-0">Clear</button>
              <button data-bs-toggle="modal" data-bs-target="#modal-qr" type="button" class="btn btn-secondary rounded-0">Sign on mobile</button>
              <button id="confirm" type="submit" class="btn btn-success rounded-0" disabled>Sign</button>
            </div>
        </div>

        <div class="flow" style="max-width: 330px; margin-inline-start: auto;">
            <h3 class="margin-top loading-signed hidden | animate slide" style="color: var(--clr-green-500); font-weight: 700;">Saving contract…</h3>
            <small class="loading-signed hidden | animate slide delay-16"
                style="font-weight: 600; color: var(--clr-blue-700);">
                This shouldn't take more than a minute.
            </small>
        </div>

        <input type="hidden" name="client_email" value="{$clientEmail}">
        <input type="hidden" name="csrf" value="{$csrf}">
        <input type="hidden" id="client_signature" name="client_signature" />
        <input type="hidden" name="client_tz" value="">
    </form>


    <div class="modal fade" tabindex="-1" id="modal-qr" aria-labelledby="modal-qrLabel" aria-hidden="true">
        <div class="modal-dialog modal-dialog-centered">
        <div class="modal-content">
        <div class="modal-body qr-code-container">
            <button id="close-modal-qr" type="button" class="btn-close" data-bs-dismiss="modal-qr" aria-label="Close"></button>
            <canvas id="qr-code"></canvas>
        </div>
        </div>
        </div>
    </div>

  </div>
  </div>
  </main>
  <script src="https://cdn.jsdelivr.net/npm/signature_pad@4.1.7/dist/signature_pad.umd.min.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/qrious@4.0.2/dist/qrious.min.js"></script>
  <script id="contract_script_unsigned" type="module">
  signature("#signature-pad")
  function signature(selector) {

      if (!document.querySelector(selector)) return

      const canvas = document.querySelector(selector)

      // https://github.com/szimek/signature_pad#options
      const clientSignaturePad = new SignaturePad(canvas, {
          penColor: "hsl(200, 100%, 30%)",
          minDistance: 2,
      })

      resizeCanvas()

      if (localStorage.getItem("client_signature")) {
          document.querySelector("#confirm").disabled = false
          // document.querySelector("#reset").disabled = false
      }


      // event listeners

      // save signature to localStorage on change
      clientSignaturePad.addEventListener("afterUpdateStroke", () => {
          let data = clientSignaturePad.toDataURL("image/png")

          document.querySelector("#client_signature").value = data
          localStorage.setItem("client_signature", data)

          // ! probably remove these:
          document.querySelector("#confirm").disabled = false
          // document.querySelector("#reset").disabled = false
      })

      // button to reset signature
      document.querySelector("#reset")?.addEventListener("click", (e) => {
          clientSignaturePad.clear()
          localStorage.removeItem("client_signature")
          document.querySelector("#client_signature").value = null
          document.querySelector("#confirm").disabled = true
          // document.querySelector("#reset").disabled = true
      })

      // form submit
      document.querySelector("#signature_form").addEventListener("submit", (e) => {
          // e.preventDefault();

          e.target.querySelectorAll(".loading-signed").forEach((el) => {
              el.classList.remove("hidden")
          })

          e.target.querySelector("#canvas-container").classList.add("just-signed")

          let otherElements = document.querySelectorAll("#content > *:not(#ui-unsigned, #dev_signature)")
          otherElements.forEach(element => {
              // element.style.cssText = `opacity: .5;`
              element.style.opacity = "0.5"
          })

      })

      window.onresize = resizeCanvas


      // needed for retina displays
      function resizeCanvas() {
          const ratio = Math.max(window.devicePixelRatio || 1, 1)
          canvas.width = canvas.offsetWidth * ratio
          canvas.height = canvas.offsetHeight * ratio
          canvas.getContext("2d").scale(ratio, ratio)

          let data = localStorage.getItem("client_signature");
          if (data) {
              // console.log(data)
              clientSignaturePad.fromDataURL(data)
              // disableResetButtonIfSignatureIsEmpty(data)
              document.querySelector("#client_signature").value = data
          }
      }

  }
  </script>
  <script>
(function () {
  const modal = document.getElementById('modal-qr')
  const btnOpen = document.getElementById('show-modal-qr')
  const btnClose = document.getElementById('close-modal-qr')
  const canvas = document.getElementById('qr-code')

  if (canvas && window.QRious) {
    new QRious({
      element: canvas,
      value: window.location.href,
      foreground: 'hsl(200, 30%, 20%)',
      padding: 0,
      size: 500
    })
  }

  if (btnOpen && modal) {
    btnOpen.addEventListener('click', function (e) {
      e.preventDefault()
      try {
        if (typeof modal.showModal === 'function') {
          modal.showModal()
        } else {
          // very old browser fallback
          modal.setAttribute('open', '')
        }
      } catch (err) {
        modal.setAttribute('open', '')
      }
    })
  }

  btnClose?.addEventListener('click', function () {
    try {
      if (modal.open) modal.close()
      else modal.removeAttribute('open')
    } catch (e) {
      modal.removeAttribute('open')
    }
  })

  // click outside to close
  modal?.addEventListener('click', function (e) {
    const r = modal.getBoundingClientRect()
    const inside = e.clientY >= r.top && e.clientY <= r.bottom && e.clientX >= r.left && e.clientX <= r.right
    if (!inside) {
      try { modal.close() } catch (err) { modal.removeAttribute('open') }
    }
  })
})()
</script>
  <script>
document.addEventListener('DOMContentLoaded', function () {
  try {
    var tz = Intl.DateTimeFormat().resolvedOptions().timeZone || ''
    var tzField = document.querySelector('input[name="client_tz"]')
    if (tzField) tzField.value = tz
  } catch (e) {}
})
</script>
  </body>
</html>
HTML;

    echo $HEADER;
    echo $CONTRACT_HTML;
    //echo $DEV_SIGNATURE;
    echo $FOOTER;


} else {
    /** Contract was just signed: put $CLIENT_SIGNATURE and the other parts in the .html file  **/
    // Build dev signature meta
    $devTimestamp = date('F j, Y \a\t g:i:s A T');
    $devIP        = $_SERVER['SERVER_ADDR'] ?? 'UNKNOWN';
    $DEV_SIGNATURE .=
        '<div class="date-ip">' .
        '<strong>Signed on:</strong> ' . htmlspecialchars($devTimestamp, ENT_QUOTES, 'UTF-8') . '<br>' .
        '</div>';

    // Client signed date and IP
    $clientTz = $_POST['client_tz'] ?? '';
    if ($clientTz && in_array($clientTz, timezone_identifiers_list(), true)) {
        $tz = new DateTimeZone($clientTz);
        $clientDate = (new DateTime('now', $tz))->format('F j, Y \a\t g:i:s A T');
    } else {
        $clientDate = gmdate('F j, Y \a\t g:i:s A \G\M\T');
    }
    //$clientIp = $_SERVER['HTTP_CF_CONNECTING_IP'] ?? $_SERVER['HTTP_X_FORWARDED_FOR'] ?? $_SERVER['REMOTE_ADDR'] ?? 'UNKNOWN';
    $clientIp = getClientIp();

    $CLIENT_SIGNATURE .=
        '<div id="date-ip" class="date-ip">' .
        '<strong>Signed on:</strong> ' . htmlspecialchars($clientDate, ENT_QUOTES, 'UTF-8') . '<br>' .
        '<strong>Client IP:</strong> ' . htmlspecialchars($clientIp, ENT_QUOTES, 'UTF-8') .
        '</div>';

    // Optional names above signatures (prefer MD front-matter, then querystring/config)
    $meta = parseFrontMatterForId($_GET['clientid'] ?? null);

    // try client.name in the MD front-matter
    $clientNameFromMd = '';
    if (is_array($meta)) {
        $clientNameFromMd = (string) (getByPath($meta, 'client.name', '') ?: ($meta['client']['name'] ?? ''));
    }
    $clientNameResolved = $clientName !== '' ? $clientName : $clientNameFromMd;

    // likewise for dev.name (in case you ever move it to the MD)
    $devNameFromMd = '';
    if (is_array($meta)) {
        $devNameFromMd = (string) (getByPath($meta, 'dev.name', '') ?: ($meta['dev']['name'] ?? ''));
    }
    $devNameResolved = $devName !== '' ? $devName : $devNameFromMd;

    if ($devNameResolved !== '') {
        $DEV_SIGNATURE = '<strong>' . htmlspecialchars($devNameResolved, ENT_QUOTES, 'UTF-8') . '</strong>' . $DEV_SIGNATURE;
    }
    if ($clientNameResolved !== '') {
        $CLIENT_SIGNATURE = '<strong>' . htmlspecialchars($clientNameResolved, ENT_QUOTES, 'UTF-8') . '</strong>' . $CLIENT_SIGNATURE;
    }

    $preparedDate = getPreparedDateFromMd($clientId) ?: $clientDate;
    // Assemble final HTML
    $HEADER = headerWithTitle(
        'Signed Contract',
        $clientId,
        $preparedDate      // you already computed this above
    );

    $CONTRACT_HTML = loadContractHtml($_GET['clientid'] ?? null);

    $compiled = <<<HTML
    <div class="row compiled-signatures align-items-end">
      <div class="col compiled-signature">{$DEV_SIGNATURE}</div>
      <div class="col compiled-signature">{$CLIENT_SIGNATURE}</div>
    </div>
	<br>
    <div class="row download-pdf d-print-none">
    	<a href="contracts/{$clientId}_signed_contract.pdf" download class="btn btn-light rounded-0" id="downloadpdf">Download PDF</a>
    </div>
HTML;

    $closing = <<<HTML
    </div>
  </main>
  <script>
    function printContract(){ window.print(); }
  </script>
</body>
</html>
HTML;

    // Build a unique filename like 3043_signed_contract_20250812-184501.html
    $timestamp = date('Ymd-His');
    //$htmlName  = "{$clientId}_signed_contract_{$timestamp}.html";
    $htmlName = "{$clientId}_signed_contract.html";
    if (file_exists($htmlName)) {
        $htmlName = "{$clientId}_signed_contract_" . date('Ymd-His') . ".html";
    }

    //$output = $HEADER . $CONTRACT_HTML . $compiled . $closing;
    // 1) WEB HTML to save
    $preparedDate = getByPath(parseFrontMatterForId($_GET['clientid'] ?? null), 'dates.prepared', date('F j, Y'));

    $headerWeb  = headerWithTitle("{$clientId} - Signed Contract", $clientId, $preparedDate, 'web');
    $footerWeb  = footerFor('web');
    $outputWeb  = $headerWeb . $CONTRACT_HTML . $compiled . $footerWeb;

    file_put_contents($htmlName, $outputWeb);

    // 2) PDF HTML (lean) to render
    $headerPdf = headerWithTitle("{$clientId} - Signed Contract", $clientId, $preparedDate, 'pdf');
    $footerPdf = footerFor('pdf');
    $outputPdf = $headerPdf . $CONTRACT_HTML . $compiled . $footerPdf;

    // Save HTML file
    file_put_contents($htmlName, $outputWeb);

    $options = new \Dompdf\Options();
    $options->set('defaultFont', 'Helvetica');
    $options->set('isRemoteEnabled', true);

    $dompdf = new \Dompdf\Dompdf($options);
    $dompdf->loadHtml($outputPdf, 'UTF-8');
    $dompdf->setPaper('A4', 'portrait');
    // Helpful for resolving relative paths in CSS/images:
    $host = $_SERVER['HTTP_HOST'] ?? 'localhost';
    $dir  = rtrim(dirname($_SERVER['SCRIPT_NAME'] ?? ''), '/\\') . '/';
    $dompdf->setBasePath('https://' . $host . $dir);

    $dompdf->render();

    $pdfPath = 'contracts/' . $clientId . '_signed_contract.pdf';
    file_put_contents($pdfPath, $dompdf->output());

    //error_log("$clientId - Finished creating html and pdf, Create email next.\r\n", 3, "error_log");
    error_log("$clientId - About to call sendEmails with clientEmail='{$clientEmail}' devEmail='{$devEmail}'\r\n", 3, "error_log");
    // Now send emails (and attach PDF)
    sendEmails($clientEmail, $devEmail, $fromAddress, $htmlName, $clientId, $pdfPath);

    //error_log("$clientId - Finished creating email. Redirect to HTML NOW.\r\n", 3, "error_log");

    // Redirect last
    header('Location: ' . $htmlName . '#hk', true, 303);
    exit;
}

// Function to email notifications; gets called when Client signs
function sendEmails(
    string $clientEmail,
    string $devEmail,
    string $fromAddress,
    string $htmlName,
    string $clientId,
    string $pdfPath = ''
): void {
    global $cfg;

    // 1) Clean + validate addresses
    $clientEmail = preg_replace('/[\r\n]+/', '', $clientEmail);
    $devEmail    = preg_replace('/[\r\n]+/', '', $devEmail);
    $clientEmail = filter_var($clientEmail, FILTER_VALIDATE_EMAIL) ?: '';
    $devEmail    = filter_var($devEmail, FILTER_VALIDATE_EMAIL) ?: '';
    if (!$clientEmail && !$devEmail) return;

    // 2) Inputs for the email template
    $viewUrl      = htmlspecialchars(getHtmlUrl($htmlName), ENT_QUOTES, 'UTF-8');
    $company      = $cfg['dev_name'] ?? 'Modulos Design';
    $preparedDate = getPreparedDateFromMd($clientId) ?: date('F j, Y');

    // Try to greet the client by name (from front-matter)
    $meta             = parseFrontMatterForId($clientId);
    $clientNameFromMd = is_array($meta) ? (string)(getByPath($meta, 'client.name', '')) : '';
	$clientCompanyFromMd = is_array($meta) ? (string)(getByPath($meta, 'client.company', '')) : $clientNameFromMd;
    $clientNameSafe   = $clientNameFromMd;

    // Build a simple target list
    $targets = [];
    if ($clientEmail) $targets[] = ['to' => $clientEmail, 'kind' => 'client'];
    if ($devEmail)    $targets[] = ['to' => $devEmail,    'kind' => 'dev'];

    foreach ($targets as $t) {
        // 3) Make the mailer
        $mail = new PHPMailer(true);
        $mail->SMTPDebug = SMTP::DEBUG_OFF;
        $mail->isSMTP();
        $mail->Host       = $cfg['smtp_host'] ?? '';
        $mail->SMTPAuth   = true;
        $mail->Username   = $cfg['smtp_username'] ?? '';
        $mail->Password   = $cfg['smtp_password'] ?? '';
        $mail->SMTPSecure = PHPMailer::ENCRYPTION_SMTPS; // 465/SSL
        $mail->Port       = $cfg['smtp_port'] ?? 465;

        $mail->CharSet  = 'UTF-8';
        $mail->Encoding = 'base64';
        $mail->setFrom($fromAddress, $company);

        // sensible reply-to
        if ($t['kind'] === 'client' && $devEmail)  $mail->addReplyTo($devEmail);
        if ($t['kind'] === 'dev'    && $clientEmail) $mail->addReplyTo($clientEmail);

        $mail->addAddress($t['to']);
        $mail->isHTML(true);

        // 4) Embed the logo **on this exact $mail** and get the <img> tag
        $logoHtml = email_logo_png_cid($mail, $cfg['dark_logo'] ?? '', $company, 200);
        $safeSignature = email_logo_png_cid($mail, $cfg['dev_signature'] ?? '', $company, 100);

        // 5) Build the body with correct argument order
        [$subject, $html, $alt] = buildSignedContractEmail(
            $logoHtml,        // <- first param is the HTML for the CID <img>
            $viewUrl,
            $clientId,
            $clientNameSafe,
            $preparedDate,
            $company,
        	$safeSignature
        );

        // Developer copy tweaks
        if ($t['kind'] === 'dev') {
            $subject = $clientId . ' ' . $clientCompanyFromMd . ' – Contract has been signed';
            $signedBy = htmlspecialchars($clientEmail ?: 'unknown', ENT_QUOTES, 'UTF-8');
            $inject   = '<tr><td style="padding:4px 24px 0;font-size:14px;color:#444;">Signed by: ' . $signedBy . '</td></tr>';
            // try to insert after the first <tr> block; fallback to simple boundary replace
            $html = preg_replace('/(<tr>\s*<td[^>]*>.*?<\/td>\s*<\/tr>)/s', '$1' . $inject, $html, 1)
                 ?: str_replace('</tr><tr>', '</tr>' . $inject . '<tr>', $html);
            $alt .= "\n\nSigned by: " . ($clientEmail ?: 'unknown');
        }

        $mail->Subject = $subject;
        $mail->Body    = $html;
        if (!empty($alt)) $mail->AltBody = $alt;

        // Optional BCC + attachment
        $mail->addBCC('drafting@modulosdesign.com.au');
        if ($pdfPath !== '' && is_file($pdfPath)) {
            $mail->addAttachment($pdfPath, basename($pdfPath));
        }

        try {
            $mail->send();
        } catch (Exception $e) {
            error_log("Mailer error to {$t['to']}: {$mail->ErrorInfo}\n", 3, "error_log");
        }
    }
}


function salutationFromName(string $fullName): string {
    // Normalize whitespace (incl. non-breaking space) and collapse runs
    $name = str_replace("\xC2\xA0", ' ', $fullName);        // NBSP → space
    $name = trim(preg_replace('/\s+/u', ' ', $name));
    if ($name === '') return 'there';

    // Strip common trailing suffixes like ", MD", ", PhD", "Jr.", etc.
    $name = preg_replace(
        '/,?\s*(Jr\.?|Sr\.?|II|III|IV|MD|Ph\.?D|Esq\.?|J\.?D\.?|M\.?B\.?A\.?|RN|DDS|DMD)\s*$/iu',
        '',
        $name
    );

    // Remove one or more leading honorifics (with optional dot), incl. unicode spaces
    $honorifics = '(mr|mrs|ms|miss|mx|dr|prof|sir|dame|lord|lady|hon|rev|fr|father|pastor|rabbi|imam|capt|cpt|gen|col|maj|sgt|officer|chief|coach|pres|sen|rep)';
    $name = preg_replace('/^(?:' . $honorifics . ')\.?[\s\x{00A0}]+/iu', '', $name);
    while (preg_match('/^' . $honorifics . '\.?[\s\x{00A0}]+/iu', $name)) {
        $name = preg_replace('/^' . $honorifics . '(\.?)[\s\x{00A0}]+/iu', '', $name, 1);
    }

    // First non-initial token becomes the salutation
    $tokens = preg_split('/[\s\x{00A0}]+/u', $name);
    if (!$tokens) return 'there';
    foreach ($tokens as $tok) {
        $t = rtrim($tok, '.');                    // drop trailing dot from initials
        if (!preg_match('/^[A-Za-z]\.?$/u', $t))  // skip single-letter initials
            return $t;
    }
    return $tokens[0] ?: 'there';
}

function email_logo_png_cid(PHPMailer $mail, string $dataUrl, string $alt = 'Modulos Design', int $width = 140): string {
    if ($dataUrl === '') return '';

    // Handle minor whitespace/newlines in config values
    $dataUrl = trim($dataUrl);

    $prefix = 'data:image/png;base64,';
    if (stripos($dataUrl, $prefix) !== 0) return '';

    $bin = base64_decode(substr($dataUrl, strlen($prefix)), true);
    if ($bin === false || $bin === '') return '';

    // Deterministic CID so forwards/replies still render
    $cid = 'logo_' . substr(sha1($bin), 0, 12) . '@modulos';

    // This is the crucial bit you commented out
    $mail->addStringEmbeddedImage($bin, $cid, 'logo.png', 'base64', 'image/png');

    return '<img src="cid:' . $cid . '" alt="' . htmlspecialchars($alt, ENT_QUOTES, 'UTF-8') . '" width="' . (int)$width . '" style="display:block;border:0;outline:0;text-decoration:none;height:auto;">';
}

function buildSignedContractEmail(
    string $logoHtml,
    string $viewUrl,
    string $clientId,
    string $clientName = '',
    string $preparedDate = '',
    string $company = 'Modulos Design',
	string $safeSignature
): array {
    $firstName     = salutationFromName($clientName);
    $firstNameSafe = htmlspecialchars($firstName, ENT_QUOTES, 'UTF-8');
    $safeUrl       = htmlspecialchars($viewUrl, ENT_QUOTES, 'UTF-8');
    $safeCompany   = htmlspecialchars($company, ENT_QUOTES, 'UTF-8');
    $safeJob       = htmlspecialchars($clientId, ENT_QUOTES, 'UTF-8');
    $safePrepared  = htmlspecialchars($preparedDate, ENT_QUOTES, 'UTF-8');
    $preparedPart  = $preparedDate ? " (prepared {$safePrepared})" : '';

    $subject = "{$safeJob} – Copy of Signed Contract";

    $html = <<<HTML
<!-- Preheader stays hidden at 0px -->
<div style="display:none;max-height:0;overflow:hidden;opacity:0;mso-hide:all;font-size:0;line-height:0;">
  Thank you for signing your contract — here’s your copy and access link.
</div>

<div style="background:#f6f7fb;padding:24px;font-size:14px;line-height:1.6;">
  <table role="presentation" cellspacing="0" cellpadding="0" border="0" align="center" width="600"
         style="width:600px;max-width:100%;background:#ffffff;border-radius:8px;overflow:hidden;
                font-size:14px;line-height:1.6;font-family:Arial,Helvetica,sans-serif;">
    <tr>
      <td style="font-size:14px;line-height:1.6;padding:20px 24px;background:#D9CCC1;color:#ffffff;">
        <table role="presentation" width="100%" cellpadding="0" cellspacing="0" border="0" style="font-size:14px;line-height:1.6;">
          <tr>
            <td style="font-size:14px;line-height:1.6;">$logoHtml</td>
            <td align="right" style="font-weight:700;font-size:14px;line-height:1.6;">Job #$safeJob</td>
          </tr>
        </table>
      </td>
    </tr>

    <tr>
      <td style="padding:28px 24px 8px;line-height:1.6;color:#635A4A;font-size:14px;">
        <div style="font-size:14px;margin-bottom:8px;line-height:1.6;">Hello {$firstNameSafe},</div>
        <div style="font-size:14px;line-height:1.6;">
          Thank you for signing the contract{$preparedPart}. A copy is attached for your records,
          and you can view or download it anytime using the link below:
        </div>
      </td>
    </tr>

    <tr>
      <td align="center" style="padding:20px 24px 8px;font-size:14px;line-height:1.6;">
        <!--[if mso]>
        <v:rect xmlns:v="urn:schemas-microsoft-com:vml" xmlns:w="urn:schemas-microsoft-com:office:word"
                href="$safeUrl"
                style="height:42px;v-text-anchor:middle;width:240px;"
                stroked="f" fillcolor="#635A4A">
          <w:anchorlock/>
          <center style="color:#ffffff;font-family:Arial,sans-serif;font-size:16px;line-height:1.6;">View Contract</center>
        </v:rect>
        <![endif]-->

        <!--[if !mso]><!-- -->
        <a href="$safeUrl"
           style="background:#635A4A;border-radius:0;display:inline-block;padding:12px 24px;color:#ffffff;
                  text-decoration:none;font-weight:700;font-size:14px;line-height:1.6;mso-hide:all"
           target="_blank" rel="noopener">View Contract</a>
        <!--<![endif]-->
      </td>
    </tr>

    <tr>
      <td style="padding:8px 24px 24px;font-size:14px;line-height:1.6;color:#635A4A;">
        <div style="font-size:14px;line-height:1.6;">
          If the button doesn’t work, copy and paste this link into your browser:<br>
          <span style="word-break:break-all;color:#635A4A;font-size:14px;line-height:1.6;">$safeUrl</span>
        </div>
        <div style="font-size:14px;line-height:1.6;margin-top:18px;">
          Thanks again — we’re excited to be working with you and looking forward to getting started.<br><br>
          <b>Kind Regards,</b><br><br>$safeSignature<br>Benjamin Harris<br>Modulos Design<br>0402 984 082  |  drafting@modulosdesign.com.au
        </div>
      </td>
    </tr>

    <tr>
      <td style="padding:12px 24px;background:#28261E;color:#D9CCC1;font-size:14px;line-height:1.6;">
        This is an automated message. Please reply to this email if you have any questions.
      </td>
    </tr>
  </table>
</div>
HTML;

    $alt = "Hello {$firstName},\n\nThe contract has been signed{$preparedPart}.\n\nView/download: {$viewUrl}\n\nThanks,\n{$company}";

    return [$subject, $html, $alt];
}
?>