<?php
require_once __DIR__ . '/../../includes/bootstrap.php';
require_login();

$pageTitle = 'Night Audit';

if (!function_exists('h')) {
    function h($value): string { return htmlspecialchars((string)$value, ENT_QUOTES, 'UTF-8'); }
}
if (!function_exists('money_fmt')) {
    function money_fmt($amount): string { return number_format((float)$amount, 2); }
}
if (!function_exists('na_table_exists')) {
    function na_table_exists(PDO $pdo, string $table): bool {
        static $cache = [];
        if (array_key_exists($table, $cache)) return $cache[$table];
        try {
            $stmt = $pdo->prepare("SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = :t");
            $stmt->execute([':t' => $table]);
            return $cache[$table] = ((int)$stmt->fetchColumn() > 0);
        } catch (Throwable $e) { return $cache[$table] = false; }
    }
}
if (!function_exists('na_column_exists')) {
    function na_column_exists(PDO $pdo, string $table, string $column): bool {
        static $cache = [];
        $key = $table . '.' . $column;
        if (array_key_exists($key, $cache)) return $cache[$key];
        try {
            $stmt = $pdo->prepare("SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = :t AND COLUMN_NAME = :c");
            $stmt->execute([':t' => $table, ':c' => $column]);
            return $cache[$key] = ((int)$stmt->fetchColumn() > 0);
        } catch (Throwable $e) { return $cache[$key] = false; }
    }
}
if (!function_exists('na_first_existing_column')) {
    function na_first_existing_column(PDO $pdo, string $table, array $columns): string {
        foreach ($columns as $column) {
            if (na_column_exists($pdo, $table, $column)) {
                return $column;
            }
        }
        return '';
    }
}

if (!function_exists('na_badge')) {
    function na_badge(bool $ok, string $okText = 'OK', string $badText = 'Review'): string {
        return $ok
            ? '<span class="badge text-bg-success"><i class="bi bi-check2-circle me-1"></i>' . h($okText) . '</span>'
            : '<span class="badge text-bg-danger"><i class="bi bi-exclamation-triangle me-1"></i>' . h($badText) . '</span>';
    }
}
if (!function_exists('na_tx_bucket_case_sql')) {
    function na_tx_bucket_case_sql(): string {
        return "CASE
            WHEN LOWER(COALESCE(ft.tx_type,'')) IN ('room_charge','accommodation','accommodation_charge','room','room_night','nightly') OR LOWER(COALESCE(ft.source_table,'')) IN ('rel_orders_prices') OR LOWER(COALESCE(ft.description,'')) LIKE '%room charge%' OR LOWER(COALESCE(ft.description,'')) LIKE '%accommodation%' THEN 'accommodation'
            WHEN LOWER(COALESCE(ft.tx_type,'')) LIKE '%restaurant%' OR LOWER(COALESCE(eci.category_name,'')) LIKE '%restaurant%' OR LOWER(COALESCE(eci.category_name,'')) LIKE '%food%' THEN 'restaurant'
            WHEN LOWER(COALESCE(ft.tx_type,'')) LIKE '%bar%' OR LOWER(COALESCE(ft.tx_type,'')) LIKE '%drink%' OR LOWER(COALESCE(eci.category_name,'')) LIKE '%bar%' OR LOWER(COALESCE(eci.category_name,'')) LIKE '%drink%' THEN 'bar'
            WHEN LOWER(COALESCE(ft.tx_type,'')) LIKE '%spa%' OR LOWER(COALESCE(ft.tx_type,'')) LIKE '%spar%' OR LOWER(COALESCE(eci.category_name,'')) LIKE '%spa%' OR LOWER(COALESCE(eci.category_name,'')) LIKE '%spar%' THEN 'spa'
            WHEN LOWER(COALESCE(ft.tx_type,'')) LIKE '%curio%' OR LOWER(COALESCE(eci.category_name,'')) LIKE '%curio%' OR LOWER(COALESCE(ft.source_table,'')) = 'inventory_items' THEN 'curio'
            WHEN LOWER(COALESCE(ft.tx_type,'')) LIKE '%minibar%' OR LOWER(COALESCE(eci.category_name,'')) LIKE '%minibar%' THEN 'minibar'
            WHEN LOWER(COALESCE(ft.tx_type,'')) LIKE '%laundry%' OR LOWER(COALESCE(eci.category_name,'')) LIKE '%laundry%' THEN 'laundry'
            WHEN LOWER(COALESCE(ft.tx_type,'')) IN ('payment','receipt','deposit','payment_received','folio_payment','guest_payment') OR LOWER(COALESCE(ft.source_table,'')) IN ('payment','payments','receipt','receipts') THEN 'payments'
            WHEN LOWER(COALESCE(ft.tx_type,'')) IN ('payment_void','void_payment','payment_reversal','reversal','refund','payment_refund') OR LOWER(COALESCE(ft.description,'')) LIKE '%void%' OR LOWER(COALESCE(ft.description,'')) LIKE '%reversal%' OR LOWER(COALESCE(ft.description,'')) LIKE '%refund%' THEN 'reversals'
            ELSE 'other'
        END";
    }
}
if (!function_exists('na_live_folio_totals_sql')) {
    function na_live_folio_totals_sql(string $orderAlias = 'o'): string {
        return "
            SELECT
                COALESCE(SUM(CASE
                    WHEN COALESCE(ft.is_voided,0)=0
                     AND LOWER(COALESCE(ft.tx_type,'')) NOT IN ('payment','receipt','deposit','payment_received','folio_payment','guest_payment','payment_void','void_payment','payment_reversal','reversal','refund','payment_refund')
                     AND LOWER(COALESCE(ft.source_table,'')) NOT IN ('payment','payments','receipt','receipts')
                    THEN COALESCE(ft.debit,0) ELSE 0 END),0) AS charges,
                GREATEST(0, COALESCE(SUM(CASE
                    WHEN COALESCE(ft.is_voided,0)=0
                     AND (LOWER(COALESCE(ft.tx_type,'')) IN ('payment','receipt','deposit','payment_received','folio_payment','guest_payment') OR LOWER(COALESCE(ft.source_table,'')) IN ('payment','payments','receipt','receipts'))
                     AND COALESCE(ft.credit,0) > 0 THEN COALESCE(ft.credit,0)
                    WHEN COALESCE(ft.is_voided,0)=0
                     AND (LOWER(COALESCE(ft.tx_type,'')) IN ('payment_void','void_payment','payment_reversal','reversal','refund','payment_refund') OR LOWER(COALESCE(ft.description,'')) LIKE '%void%' OR LOWER(COALESCE(ft.description,'')) LIKE '%reversal%' OR LOWER(COALESCE(ft.description,'')) LIKE '%refund%')
                     AND COALESCE(ft.debit,0) > 0 THEN -1 * COALESCE(ft.debit,0)
                    ELSE 0 END),0)) AS payments
            FROM folio_transactions ft
            WHERE ft.order_id = {$orderAlias}.id
        ";
    }
}

$auditDate = trim((string)($_GET['audit_date'] ?? date('Y-m-d')));
$propertyId = (int)($_GET['property_id'] ?? 0);
$highBalanceLimit = (float)($_GET['high_balance_limit'] ?? 500);
$exportQuery = http_build_query(['audit_date' => $auditDate, 'property_id' => $propertyId]);

$errors = [];
$properties = [];
$summary = [
    'rooms_total'=>0,'rooms_occupied'=>0,'rooms_vacant'=>0,'arrivals_pending'=>0,'departures_pending'=>0,
    'dirty_rooms'=>0,'ooo_rooms'=>0,'sleepers'=>0,'skippers'=>0,'open_balance_bookings'=>0,'high_balance_bookings'=>0,
    'no_shows'=>0,'no_show_fees_missing'=>0,'missing_room_charges'=>0,'late_fb_charges'=>0,'unposted_restaurant'=>0,
    'revenue_charges'=>0,'revenue_payments'=>0,'revenue_variance'=>0
];

$arrivalsPending=[];$departuresPending=[];$openBalanceBookings=[];$highBalanceBookings=[];$dirtyRooms=[];$outOfOrderRooms=[];
$sleepers=[];$skippers=[];$missingRoomCharges=[];$noShows=[];$lateFbCharges=[];$unpostedRestaurant=[];$departmentRevenue=[];$stockVariance=[];$restaurantTopItems=[];$paymentSummary=[];

try {
    $properties = $pdo->query("SELECT id, name, code FROM properties WHERE is_active = 1 ORDER BY name ASC")->fetchAll(PDO::FETCH_ASSOC);
} catch (Throwable $e) { $properties = []; }

$roomPropertySql = $propertyId > 0 ? " AND r.property_id = :property_id " : '';
$orderPropertySql = $propertyId > 0 ? " AND o.property_id = :property_id " : '';

try {
    $stmt=$pdo->prepare("SELECT COUNT(*) FROM rooms r WHERE 1=1 $roomPropertySql");
    if($propertyId>0)$stmt->bindValue(':property_id',$propertyId,PDO::PARAM_INT);
    $stmt->execute(); $summary['rooms_total']=(int)$stmt->fetchColumn();
} catch(Throwable $e){$errors[]='Rooms Total: '.$e->getMessage();}

try {
    $sql="SELECT COUNT(DISTINCT rmg.room_id)
          FROM order_rooming rmg
          INNER JOIN orders o ON o.id=rmg.order_id
          INNER JOIN rooms r ON r.id=rmg.room_id
          WHERE DATE(o.check_in)<=:d1 AND DATE(o.check_out)>:d2 AND COALESCE(rmg.checked_out_status,0)=0 AND rmg.room_id IS NOT NULL $orderPropertySql";
    $stmt=$pdo->prepare($sql); $stmt->bindValue(':d1',$auditDate); $stmt->bindValue(':d2',$auditDate); if($propertyId>0)$stmt->bindValue(':property_id',$propertyId,PDO::PARAM_INT); $stmt->execute();
    $summary['rooms_occupied']=(int)$stmt->fetchColumn();
} catch(Throwable $e){$errors[]='Rooms Occupied: '.$e->getMessage();}
$summary['rooms_vacant']=max(0,$summary['rooms_total']-$summary['rooms_occupied']);

try {
    $sql="SELECT o.*,p.name property_name,p.code property_code,g.firstname,g.lastname,CONCAT(COALESCE(a.firstname,''),' ',COALESCE(a.lastname,'')) agent_name,
        (SELECT COUNT(*) FROM order_rooming r1 WHERE r1.order_id=o.id) room_slots_total,
        (SELECT COUNT(*) FROM order_rooming r2 WHERE r2.order_id=o.id AND COALESCE(r2.checked_in_status,0)=1) room_slots_checked_in
        FROM orders o LEFT JOIN properties p ON p.id=o.property_id LEFT JOIN guests g ON g.id=o.guest_id LEFT JOIN agents a ON a.id=o.agent_id
        WHERE DATE(o.check_in)=:d $orderPropertySql ORDER BY p.name,o.id DESC";
    $stmt=$pdo->prepare($sql); $stmt->bindValue(':d',$auditDate); if($propertyId>0)$stmt->bindValue(':property_id',$propertyId,PDO::PARAM_INT); $stmt->execute();
    foreach($stmt->fetchAll(PDO::FETCH_ASSOC) as $row){$total=(int)$row['room_slots_total'];$checked=(int)$row['room_slots_checked_in']; if($total===0||$checked<$total)$arrivalsPending[]=$row;}
    $summary['arrivals_pending']=count($arrivalsPending);
} catch(Throwable $e){$errors[]='Arrivals Pending: '.$e->getMessage();}

try {
    $live=na_live_folio_totals_sql('o');
    $sql="SELECT o.*,p.name property_name,p.code property_code,g.firstname,g.lastname,CONCAT(COALESCE(a.firstname,''),' ',COALESCE(a.lastname,'')) agent_name,
        (SELECT COUNT(*) FROM order_rooming r1 WHERE r1.order_id=o.id) room_slots_total,
        (SELECT COUNT(*) FROM order_rooming r2 WHERE r2.order_id=o.id AND COALESCE(r2.checked_out_status,0)=1) room_slots_checked_out,
        (SELECT charges-payments FROM ($live) live_totals) booking_balance
        FROM orders o LEFT JOIN properties p ON p.id=o.property_id LEFT JOIN guests g ON g.id=o.guest_id LEFT JOIN agents a ON a.id=o.agent_id
        WHERE DATE(o.check_out)=:d $orderPropertySql ORDER BY p.name,o.id DESC";
    $stmt=$pdo->prepare($sql); $stmt->bindValue(':d',$auditDate); if($propertyId>0)$stmt->bindValue(':property_id',$propertyId,PDO::PARAM_INT); $stmt->execute();
    foreach($stmt->fetchAll(PDO::FETCH_ASSOC) as $row){$total=(int)$row['room_slots_total'];$checked=(int)$row['room_slots_checked_out']; if($total===0||$checked<$total)$departuresPending[]=$row;}
    $summary['departures_pending']=count($departuresPending);
} catch(Throwable $e){$errors[]='Departures Pending: '.$e->getMessage();}

try {
    $live=na_live_folio_totals_sql('o');
    $sql="SELECT o.*,p.name property_name,p.code property_code,g.firstname,g.lastname,CONCAT(COALESCE(a.firstname,''),' ',COALESCE(a.lastname,'')) agent_name,
        (SELECT charges FROM ($live) live_totals) booking_charges,
        (SELECT payments FROM ($live) live_totals) booking_payments,
        (SELECT charges-payments FROM ($live) live_totals) booking_balance
        FROM orders o LEFT JOIN properties p ON p.id=o.property_id LEFT JOIN guests g ON g.id=o.guest_id LEFT JOIN agents a ON a.id=o.agent_id
        WHERE DATE(o.check_in)<=:d1 AND DATE(o.check_out)>:d2 $orderPropertySql ORDER BY p.name,o.check_out,o.id DESC";
    $stmt=$pdo->prepare($sql); $stmt->bindValue(':d1',$auditDate); $stmt->bindValue(':d2',$auditDate); if($propertyId>0)$stmt->bindValue(':property_id',$propertyId,PDO::PARAM_INT); $stmt->execute();
    foreach($stmt->fetchAll(PDO::FETCH_ASSOC) as $row){$bal=(float)$row['booking_balance']; if(abs($bal)>0.00001)$openBalanceBookings[]=$row; if($bal>$highBalanceLimit)$highBalanceBookings[]=$row;}
    $summary['open_balance_bookings']=count($openBalanceBookings); $summary['high_balance_bookings']=count($highBalanceBookings);
} catch(Throwable $e){$errors[]='Open Balances: '.$e->getMessage();}

try {
    $statusExpr = na_column_exists($pdo,'rooms','housekeeping_status') ? "LOWER(COALESCE(r.housekeeping_status,r.status,''))" : "LOWER(COALESCE(r.status,''))";
    $stmt=$pdo->prepare("SELECT r.*,p.name property_name,p.code property_code,rt.title room_type FROM rooms r LEFT JOIN properties p ON p.id=r.property_id LEFT JOIN room_types rt ON rt.id=r.room_type_id WHERE $statusExpr='dirty' $roomPropertySql ORDER BY p.name,r.room_no");
    if($propertyId>0)$stmt->bindValue(':property_id',$propertyId,PDO::PARAM_INT); $stmt->execute(); $dirtyRooms=$stmt->fetchAll(PDO::FETCH_ASSOC); $summary['dirty_rooms']=count($dirtyRooms);
    $stmt=$pdo->prepare("SELECT r.*,p.name property_name,p.code property_code,rt.title room_type FROM rooms r LEFT JOIN properties p ON p.id=r.property_id LEFT JOIN room_types rt ON rt.id=r.room_type_id WHERE $statusExpr IN ('out_of_order','ooo','maintenance','blocked') $roomPropertySql ORDER BY p.name,r.room_no");
    if($propertyId>0)$stmt->bindValue(':property_id',$propertyId,PDO::PARAM_INT); $stmt->execute(); $outOfOrderRooms=$stmt->fetchAll(PDO::FETCH_ASSOC); $summary['ooo_rooms']=count($outOfOrderRooms);

    $stmt=$pdo->prepare("SELECT r.*,p.name property_name,p.code property_code,rt.title room_type FROM rooms r LEFT JOIN properties p ON p.id=r.property_id LEFT JOIN room_types rt ON rt.id=r.room_type_id WHERE $statusExpr IN ('occupied','in_house') AND NOT EXISTS (SELECT 1 FROM order_rooming rmg INNER JOIN orders o ON o.id=rmg.order_id WHERE rmg.room_id=r.id AND DATE(o.check_in)<=:d1 AND DATE(o.check_out)>:d2 AND COALESCE(rmg.checked_out_status,0)=0) $roomPropertySql ORDER BY p.name,r.room_no");
    $stmt->bindValue(':d1',$auditDate);$stmt->bindValue(':d2',$auditDate); if($propertyId>0)$stmt->bindValue(':property_id',$propertyId,PDO::PARAM_INT); $stmt->execute(); $sleepers=$stmt->fetchAll(PDO::FETCH_ASSOC); $summary['sleepers']=count($sleepers);

    $stmt=$pdo->prepare("SELECT r.*,p.name property_name,p.code property_code,rt.title room_type,o.order_no,g.firstname,g.lastname FROM order_rooming rmg INNER JOIN orders o ON o.id=rmg.order_id INNER JOIN rooms r ON r.id=rmg.room_id LEFT JOIN properties p ON p.id=r.property_id LEFT JOIN room_types rt ON rt.id=r.room_type_id LEFT JOIN guests g ON g.id=o.guest_id WHERE DATE(o.check_in)<=:d1 AND DATE(o.check_out)>:d2 AND COALESCE(rmg.checked_out_status,0)=0 AND $statusExpr IN ('vacant','clean','vacant_clean') $orderPropertySql ORDER BY p.name,r.room_no");
    $stmt->bindValue(':d1',$auditDate);$stmt->bindValue(':d2',$auditDate); if($propertyId>0)$stmt->bindValue(':property_id',$propertyId,PDO::PARAM_INT); $stmt->execute(); $skippers=$stmt->fetchAll(PDO::FETCH_ASSOC); $summary['skippers']=count($skippers);
} catch(Throwable $e){$errors[]='Room Status Audit: '.$e->getMessage();}

try {
    $sql="SELECT o.*,p.name property_name,p.code property_code,g.firstname,g.lastname,
        COALESCE((SELECT SUM(debit) FROM folio_transactions ft WHERE ft.order_id=o.id AND COALESCE(ft.is_voided,0)=0 AND (LOWER(COALESCE(ft.tx_type,'')) IN ('room_charge','accommodation','accommodation_charge','room_night','nightly') OR LOWER(COALESCE(ft.source_table,''))='rel_orders_prices')),0) posted_room_charges,
        COALESCE((SELECT SUM(total) FROM rel_orders_prices rp WHERE rp.order_id=o.id AND DATE(rp.date)=:rpdate),0) expected_room_charges
        FROM orders o LEFT JOIN properties p ON p.id=o.property_id LEFT JOIN guests g ON g.id=o.guest_id
        WHERE DATE(o.check_in)<=:d1 AND DATE(o.check_out)>:d2 $orderPropertySql
        HAVING expected_room_charges>0 AND posted_room_charges<=0 ORDER BY p.name,o.id DESC";
    $stmt=$pdo->prepare($sql); $stmt->bindValue(':rpdate',$auditDate);$stmt->bindValue(':d1',$auditDate);$stmt->bindValue(':d2',$auditDate); if($propertyId>0)$stmt->bindValue(':property_id',$propertyId,PDO::PARAM_INT); $stmt->execute();
    $missingRoomCharges=$stmt->fetchAll(PDO::FETCH_ASSOC); $summary['missing_room_charges']=count($missingRoomCharges);
} catch(Throwable $e){$errors[]='Missing Room Charges: '.$e->getMessage();}

try {
    $live=na_live_folio_totals_sql('o');
    $sql="SELECT o.*,p.name property_name,p.code property_code,g.firstname,g.lastname,(SELECT charges-payments FROM ($live) live_totals) booking_balance,
        COALESCE((SELECT SUM(debit) FROM folio_transactions ft LEFT JOIN extra_charge_items eci ON eci.folio_transaction_id=ft.id WHERE ft.order_id=o.id AND DATE(ft.tx_date)>DATE(o.check_out) AND COALESCE(ft.is_voided,0)=0 AND (LOWER(COALESCE(ft.tx_type,'')) LIKE '%restaurant%' OR LOWER(COALESCE(ft.tx_type,'')) LIKE '%bar%' OR LOWER(COALESCE(eci.category_name,'')) IN ('restaurant','bar','food','drinks'))),0) late_fb_amount
        FROM orders o LEFT JOIN properties p ON p.id=o.property_id LEFT JOIN guests g ON g.id=o.guest_id
        WHERE DATE(o.check_out)<=:d $orderPropertySql HAVING late_fb_amount>0 ORDER BY late_fb_amount DESC";
    $stmt=$pdo->prepare($sql);$stmt->bindValue(':d',$auditDate); if($propertyId>0)$stmt->bindValue(':property_id',$propertyId,PDO::PARAM_INT); $stmt->execute(); $lateFbCharges=$stmt->fetchAll(PDO::FETCH_ASSOC); $summary['late_fb_charges']=count($lateFbCharges);
} catch(Throwable $e){$errors[]='Late F&B Charges: '.$e->getMessage();}

try {
    $live=na_live_folio_totals_sql('o');
    $statusCol=na_column_exists($pdo,'orders','status')?'status':'';
    $sql="SELECT o.*,p.name property_name,p.code property_code,g.firstname,g.lastname,(SELECT charges-payments FROM ($live) live_totals) booking_balance,
        COALESCE((SELECT SUM(debit) FROM folio_transactions ft WHERE ft.order_id=o.id AND COALESCE(ft.is_voided,0)=0 AND (LOWER(COALESCE(ft.tx_type,'')) LIKE '%no_show%' OR LOWER(COALESCE(ft.description,'')) LIKE '%no show%' OR LOWER(COALESCE(ft.description,'')) LIKE '%cancellation%')),0) no_show_fee
        FROM orders o LEFT JOIN properties p ON p.id=o.property_id LEFT JOIN guests g ON g.id=o.guest_id
        WHERE DATE(o.check_in)<:d $orderPropertySql AND NOT EXISTS (SELECT 1 FROM order_rooming rmg WHERE rmg.order_id=o.id AND COALESCE(rmg.checked_in_status,0)=1)";
    if($statusCol!=='') $sql .= " AND LOWER(COALESCE(o.status,'')) NOT IN ('checked_out','cancelled','canceled','closed','completed') ";
    $sql .= " ORDER BY p.name,o.check_in DESC,o.id DESC LIMIT 200";
    $stmt=$pdo->prepare($sql);$stmt->bindValue(':d',$auditDate); if($propertyId>0)$stmt->bindValue(':property_id',$propertyId,PDO::PARAM_INT); $stmt->execute(); $noShows=$stmt->fetchAll(PDO::FETCH_ASSOC);
    $summary['no_shows']=count($noShows); foreach($noShows as $ns){ if((float)($ns['no_show_fee']??0)<=0) $summary['no_show_fees_missing']++; }
} catch(Throwable $e){$errors[]='No Show Audit: '.$e->getMessage();}

try {
    $bucket=na_tx_bucket_case_sql();
    $dateExpr = na_column_exists($pdo,'folio_transactions','tx_date') ? 'ft.tx_date' : 'ft.created_at';
    $joinEci = na_table_exists($pdo,'extra_charge_items') ? ' LEFT JOIN extra_charge_items eci ON eci.folio_transaction_id=ft.id ' : " LEFT JOIN (SELECT NULL folio_transaction_id, NULL category_name) eci ON 1=0 ";
    $propJoin = " LEFT JOIN orders o ON o.id=ft.order_id ";
    $sql="SELECT bucket, SUM(charges) charges, SUM(payments) payments FROM (
        SELECT $bucket bucket,
        CASE WHEN COALESCE(ft.is_voided,0)=0 AND LOWER(COALESCE(ft.tx_type,'')) NOT IN ('payment','receipt','deposit','payment_received','folio_payment','guest_payment','payment_void','void_payment','payment_reversal','reversal','refund','payment_refund') AND LOWER(COALESCE(ft.source_table,'')) NOT IN ('payment','payments','receipt','receipts') THEN COALESCE(ft.debit,0) ELSE 0 END charges,
        CASE WHEN COALESCE(ft.is_voided,0)=0 AND (LOWER(COALESCE(ft.tx_type,'')) IN ('payment','receipt','deposit','payment_received','folio_payment','guest_payment') OR LOWER(COALESCE(ft.source_table,'')) IN ('payment','payments','receipt','receipts')) THEN COALESCE(ft.credit,0) ELSE 0 END payments
        FROM folio_transactions ft $joinEci $propJoin WHERE DATE($dateExpr)=:d " . ($propertyId>0 ? " AND o.property_id=:property_id " : "") . ") x GROUP BY bucket ORDER BY charges DESC";
    $stmt=$pdo->prepare($sql);$stmt->bindValue(':d',$auditDate); if($propertyId>0)$stmt->bindValue(':property_id',$propertyId,PDO::PARAM_INT); $stmt->execute();
    foreach($stmt->fetchAll(PDO::FETCH_ASSOC) as $r){$departmentRevenue[$r['bucket']]=$r; $summary['revenue_charges']+=(float)$r['charges']; $summary['revenue_payments']+=(float)$r['payments'];}
    $summary['revenue_variance']=$summary['revenue_charges']-$summary['revenue_payments'];
} catch(Throwable $e){$errors[]='Department Revenue: '.$e->getMessage();}

try {
    if(na_table_exists($pdo,'restaurant_orders')){
        $sql="SELECT close_method, COUNT(*) orders, COALESCE(SUM(total_amount),0) amount FROM restaurant_orders ro WHERE DATE(ro.created_at)=:d AND ro.status='closed'" . ($propertyId>0 && na_column_exists($pdo,'restaurant_orders','property_id') ? " AND ro.property_id=:property_id " : "") . " GROUP BY close_method ORDER BY amount DESC";
        $stmt=$pdo->prepare($sql);$stmt->bindValue(':d',$auditDate); if($propertyId>0 && na_column_exists($pdo,'restaurant_orders','property_id'))$stmt->bindValue(':property_id',$propertyId,PDO::PARAM_INT); $stmt->execute(); $paymentSummary=$stmt->fetchAll(PDO::FETCH_ASSOC);
        $sql="SELECT ro.* FROM restaurant_orders ro WHERE DATE(ro.created_at)=:d AND ro.status IN ('open','preparing','served','bill_requested')" . ($propertyId>0 && na_column_exists($pdo,'restaurant_orders','property_id') ? " AND ro.property_id=:property_id " : "") . " ORDER BY ro.created_at ASC";
        $stmt=$pdo->prepare($sql);$stmt->bindValue(':d',$auditDate); if($propertyId>0 && na_column_exists($pdo,'restaurant_orders','property_id'))$stmt->bindValue(':property_id',$propertyId,PDO::PARAM_INT); $stmt->execute(); $unpostedRestaurant=$stmt->fetchAll(PDO::FETCH_ASSOC); $summary['unposted_restaurant']=count($unpostedRestaurant);
    }
} catch(Throwable $e){$errors[]='Restaurant Audit: '.$e->getMessage();}

try {
    if(na_table_exists($pdo,'restaurant_order_items')){
        $stmt=$pdo->prepare("SELECT item_name, SUM(quantity) qty, SUM(line_total) total FROM restaurant_order_items WHERE DATE(created_at)=:d GROUP BY item_name ORDER BY total DESC LIMIT 15");
        $stmt->execute([':d'=>$auditDate]); $restaurantTopItems=$stmt->fetchAll(PDO::FETCH_ASSOC);
    }
} catch(Throwable $e){}

try {
    if (na_table_exists($pdo, 'stock_take_lines') && na_table_exists($pdo, 'inventory_items')) {
        /*
           Stock take schemas differ between installs.
           Do not hard-code physical_qty/system_qty because some versions use
           counted_qty, physical_count, book_qty, expected_qty, qty_on_hand, etc.
        */
        $itemColumn = na_first_existing_column($pdo, 'stock_take_lines', ['item_id', 'inventory_item_id', 'product_id']);
        $physicalColumn = na_first_existing_column($pdo, 'stock_take_lines', [
            'physical_qty', 'physical_quantity', 'counted_qty', 'count_qty',
            'qty_counted', 'physical_count', 'actual_qty', 'actual_quantity',
            'new_qty', 'quantity_counted'
        ]);
        $systemColumn = na_first_existing_column($pdo, 'stock_take_lines', [
            'system_qty', 'system_quantity', 'book_qty', 'book_quantity',
            'expected_qty', 'expected_quantity', 'theoretical_qty',
            'theoretical_quantity', 'qty_on_hand', 'on_hand_qty', 'current_qty'
        ]);
        $dateColumn = na_first_existing_column($pdo, 'stock_take_lines', [
            'count_date', 'stock_take_date', 'take_date', 'movement_date',
            'created_at', 'updated_at'
        ]);

        $inventoryNameColumn = na_first_existing_column($pdo, 'inventory_items', [
            'item_name', 'name', 'description'
        ]);
        if ($inventoryNameColumn === '') {
            $inventoryNameColumn = 'id';
        }

        if ($itemColumn !== '' && $physicalColumn !== '') {
            $physicalExpr = "COALESCE(stl.`$physicalColumn`, 0)";
            $systemExpr = $systemColumn !== '' ? "COALESCE(stl.`$systemColumn`, 0)" : "0";
            $dateFilter = '';
            if ($dateColumn !== '') {
                $dateFilter = " AND DATE(stl.`$dateColumn`) = :d ";
            }

            $stmt = $pdo->prepare("
                SELECT
                    i.`$inventoryNameColumn` AS item_name,
                    $systemExpr AS system_qty,
                    $physicalExpr AS physical_qty,
                    ($physicalExpr - $systemExpr) AS variance_qty
                FROM stock_take_lines stl
                INNER JOIN inventory_items i ON i.id = stl.`$itemColumn`
                WHERE 1=1
                  $dateFilter
                  AND ABS($physicalExpr - $systemExpr) > 0.0001
                ORDER BY ABS($physicalExpr - $systemExpr) DESC
                LIMIT 50
            ");
            if ($dateFilter !== '') {
                $stmt->bindValue(':d', $auditDate);
            }
            $stmt->execute();
            $stockVariance = $stmt->fetchAll(PDO::FETCH_ASSOC);
        }
    }
} catch(Throwable $e){$errors[]='Stock Variance: '.$e->getMessage();}


$checklist = [
    ['Room status reconciled', $summary['sleepers']===0 && $summary['skippers']===0],
    ['Arrivals checked in', $summary['arrivals_pending']===0],
    ['Departures checked out', $summary['departures_pending']===0],
    ['Room charges posted', $summary['missing_room_charges']===0],
    ['Restaurant/Bar/Spa/Curio charges reviewed', $summary['unposted_restaurant']===0 && $summary['late_fb_charges']===0],
    ['No-shows reviewed', $summary['no_show_fees_missing']===0],
    ['High balances reviewed', $summary['high_balance_bookings']===0],
    ['Stock variances reviewed', count($stockVariance)===0],
    ['Revenue balanced', abs((float)$summary['revenue_variance']) < 0.00001],
];
$canClose = true; foreach($checklist as $c){ if(!$c[1]){$canClose=false;break;} }

require_once __DIR__ . '/../../includes/header.php';
?>

<div class="hero-band night-audit-hero compact-hero">
    <div class="row g-2 align-items-center">
        <div class="col-lg-7">
            <div class="page-eyebrow text-white-50"><i class="bi bi-moon-stars"></i> End of Day</div>
            <div class="hero-title mt-1">Night Audit</div>
            <div class="hero-subtitle mt-1">Room status, folios, restaurant, bar, spa, curio, stock, no-shows, and end-of-day controls.</div>
        </div>
        <div class="col-lg-5 text-lg-end">
            <div class="hero-actions d-flex flex-wrap gap-2 justify-content-lg-end">
                <a href="/rooms/modules/payments/night_audit_pdf.php?<?php echo h($exportQuery); ?>" target="_blank" class="btn btn-light btn-sm"><i class="bi bi-file-earmark-pdf me-1"></i>PDF</a>
                <a href="/rooms/modules/payments/night_audit_excel.php?<?php echo h($exportQuery); ?>" class="btn btn-success btn-sm"><i class="bi bi-file-earmark-excel me-1"></i>Excel</a>
                <button onclick="window.print()" class="btn btn-outline-light btn-sm"><i class="bi bi-printer me-1"></i>Print</button>
                <a href="/rooms/modules/restaurant/reports.php?from=<?php echo urlencode($auditDate); ?>&to=<?php echo urlencode($auditDate); ?>" class="btn btn-outline-light btn-sm"><i class="bi bi-cup-hot me-1"></i>Restaurant Audit</a>
                <a href="/rooms/modules/payments/frontdesk_dashboard.php" class="btn btn-outline-light btn-sm"><i class="bi bi-arrow-left me-1"></i>Front Desk</a>
            </div>
        </div>
    </div>
</div>

<?php if ($errors): ?><div class="alert alert-danger"><div class="fw-bold mb-2">Please fix the following:</div><ul class="mb-0"><?php foreach($errors as $err): ?><li><?php echo h($err); ?></li><?php endforeach; ?></ul></div><?php endif; ?>

<div class="card panel-card mb-3 no-print"><div class="card-body"><form method="get" class="row g-2 align-items-end">
    <div class="col-md-3"><label class="form-label">Audit Date</label><input type="date" name="audit_date" class="form-control" value="<?php echo h($auditDate); ?>"></div>
    <div class="col-md-4"><label class="form-label">Property</label><select name="property_id" class="form-select"><option value="0">All properties</option><?php foreach($properties as $p): ?><option value="<?php echo (int)$p['id']; ?>" <?php echo $propertyId===(int)$p['id']?'selected':''; ?>><?php echo h($p['name']); ?><?php echo !empty($p['code'])?' - '.h($p['code']):''; ?></option><?php endforeach; ?></select></div>
    <div class="col-md-3"><label class="form-label">High Balance Limit</label><input type="number" step="0.01" name="high_balance_limit" class="form-control" value="<?php echo h((string)$highBalanceLimit); ?>"></div>
    <div class="col-md-2 d-grid"><button class="btn btn-primary">Run Audit</button></div>
</form></div></div>

<div class="row g-2 mb-3">
<?php $cards=[['Rooms','rooms_total','grid','primary'],['Occupied','rooms_occupied','house-door','danger'],['Vacant','rooms_vacant','door-open','success'],['Pending Arrivals','arrivals_pending','person-check','warning'],['Pending Departures','departures_pending','box-arrow-right','info'],['Open Balances','open_balance_bookings','cash-stack','secondary'],['Sleepers','sleepers','eye','danger'],['No-shows','no_shows','person-x','dark']]; foreach($cards as $c): ?>
<div class="col-sm-6 col-xl-3"><div class="metric-card compact-metric"><div class="metric-icon bg-<?php echo h($c[3]); ?>-subtle text-<?php echo h($c[3]); ?>"><i class="bi bi-<?php echo h($c[2]); ?>"></i></div><div><div class="metric-label"><?php echo h($c[0]); ?></div><div class="metric-value"><?php echo number_format((float)$summary[$c[1]]); ?></div></div></div></div>
<?php endforeach; ?>
</div>

<div class="card panel-card mb-3"><div class="card-header d-flex justify-content-between align-items-center"><h5 class="mb-0">Night Audit Completion Checklist</h5><?php echo $canClose ? '<span class="badge text-bg-success px-3 py-2">Ready for End of Day</span>' : '<span class="badge text-bg-danger px-3 py-2">Review Required</span>'; ?></div><div class="card-body"><div class="row g-2">
<?php foreach($checklist as $item): ?><div class="col-md-6 col-xl-4"><div class="audit-check"><span><?php echo h($item[0]); ?></span><?php echo na_badge((bool)$item[1]); ?></div></div><?php endforeach; ?>
</div><div class="mt-3 d-flex gap-2 flex-wrap"><button class="btn <?php echo $canClose?'btn-success':'btn-secondary'; ?>" <?php echo $canClose?'':'disabled'; ?>><i class="bi bi-calendar2-check me-1"></i>Run End Of Day</button><span class="text-muted small align-self-center">End-of-day is disabled until all control checks are clear.</span></div></div></div>

<div class="row g-3 mb-3">
    <div class="col-xl-6"><div class="card panel-card h-100"><div class="card-header"><h5 class="mb-0">Revenue vs Payments</h5></div><div class="card-body"><div class="totals-panel"><div><span>Total Charges</span><strong><?php echo money_fmt($summary['revenue_charges']); ?></strong></div><div><span>Total Payments</span><strong><?php echo money_fmt($summary['revenue_payments']); ?></strong></div><div><span>Variance</span><strong class="<?php echo abs($summary['revenue_variance'])>0.00001?'text-danger':'text-success'; ?>"><?php echo money_fmt($summary['revenue_variance']); ?></strong></div></div></div></div></div>
    <div class="col-xl-6"><div class="card panel-card h-100"><div class="card-header"><h5 class="mb-0">Department Revenue</h5></div><div class="card-body p-0"><table class="table table-modern mb-0"><thead><tr><th>Department</th><th class="text-end">Charges</th><th class="text-end">Payments</th></tr></thead><tbody><?php foreach(['accommodation','restaurant','bar','spa','curio','minibar','laundry','other','payments'] as $b): $r=$departmentRevenue[$b]??['charges'=>0,'payments'=>0]; if((float)$r['charges']==0 && (float)$r['payments']==0) continue; ?><tr><td><?php echo h(ucwords(str_replace('_',' ',$b))); ?></td><td class="text-end"><?php echo money_fmt($r['charges']); ?></td><td class="text-end"><?php echo money_fmt($r['payments']); ?></td></tr><?php endforeach; ?></tbody></table></div></div></div>
</div>

<?php function na_guest_name($row){$n=trim(($row['firstname']??'').' '.($row['lastname']??'')); return $n!==''?$n:'Guest';} function na_property_label($row){$p=trim((string)($row['property_name']??'')); if(!empty($row['property_code']))$p.=($p!==''?' ('.$row['property_code'].')':$row['property_code']); return $p!==''?$p:'Not set';} ?>

<div class="row g-3 mb-3">
    <div class="col-xl-6"><div class="card panel-card h-100"><div class="card-header"><h5 class="mb-0">Sleepers / Skippers</h5></div><div class="card-body p-0"><table class="table table-modern mb-0"><thead><tr><th>Type</th><th>Room</th><th>Property</th><th>Details</th></tr></thead><tbody><?php if(!$sleepers && !$skippers): ?><tr><td colspan="4" class="text-center text-muted py-4">No sleeper/skipper discrepancies.</td></tr><?php endif; foreach($sleepers as $r): ?><tr><td><span class="badge text-bg-danger">Sleeper</span></td><td><strong><?php echo h($r['room_no']??''); ?></strong></td><td><?php echo h(na_property_label($r)); ?></td><td>Room marked occupied but no active PMS booking.</td></tr><?php endforeach; foreach($skippers as $r): ?><tr><td><span class="badge text-bg-warning text-dark">Skipper</span></td><td><strong><?php echo h($r['room_no']??''); ?></strong></td><td><?php echo h(na_property_label($r)); ?></td><td><?php echo h(($r['order_no']??'').' '.na_guest_name($r)); ?></td></tr><?php endforeach; ?></tbody></table></div></div></div>
    <div class="col-xl-6"><div class="card panel-card h-100"><div class="card-header"><h5 class="mb-0">Missing Room Charges</h5></div><div class="card-body p-0"><table class="table table-modern mb-0"><thead><tr><th>Booking</th><th>Guest</th><th class="text-end">Expected</th><th class="text-end">Posted</th></tr></thead><tbody><?php if(!$missingRoomCharges): ?><tr><td colspan="4" class="text-center text-muted py-4">All occupied rooms have room charges.</td></tr><?php else: foreach($missingRoomCharges as $r): ?><tr><td><strong><?php echo h($r['order_no']?:('#'.$r['id'])); ?></strong></td><td><?php echo h(na_guest_name($r)); ?></td><td class="text-end"><?php echo money_fmt($r['expected_room_charges']); ?></td><td class="text-end"><?php echo money_fmt($r['posted_room_charges']); ?></td></tr><?php endforeach; endif; ?></tbody></table></div></div></div>
</div>

<div class="row g-3 mb-3">
    <div class="col-xl-6"><div class="card panel-card h-100"><div class="card-header d-flex justify-content-between"><h5 class="mb-0">Restaurant / F&B Exceptions</h5><a class="btn btn-sm btn-outline-primary" href="/rooms/modules/restaurant/reports.php?from=<?php echo urlencode($auditDate); ?>&to=<?php echo urlencode($auditDate); ?>">Open Reports</a></div><div class="card-body p-0"><table class="table table-modern mb-0"><thead><tr><th>Issue</th><th>Order/Booking</th><th class="text-end">Amount</th></tr></thead><tbody><?php if(!$unpostedRestaurant && !$lateFbCharges): ?><tr><td colspan="3" class="text-center text-muted py-4">No active/unposted or late F&B exceptions.</td></tr><?php endif; foreach($unpostedRestaurant as $r): ?><tr><td><span class="badge text-bg-warning text-dark">Open POS Tab</span></td><td><?php echo h($r['order_no']??('#'.$r['id'])); ?></td><td class="text-end"><?php echo money_fmt($r['total_amount']??0); ?></td></tr><?php endforeach; foreach($lateFbCharges as $r): ?><tr><td><span class="badge text-bg-danger">Late F&B</span></td><td><?php echo h(($r['order_no']??('#'.$r['id'])).' - '.na_guest_name($r)); ?></td><td class="text-end"><?php echo money_fmt($r['late_fb_amount']); ?></td></tr><?php endforeach; ?></tbody></table></div></div></div>
    <div class="col-xl-6"><div class="card panel-card h-100"><div class="card-header"><h5 class="mb-0">Top Restaurant Items</h5></div><div class="card-body p-0"><table class="table table-modern mb-0"><thead><tr><th>Item</th><th class="text-end">Qty</th><th class="text-end">Value</th></tr></thead><tbody><?php if(!$restaurantTopItems): ?><tr><td colspan="3" class="text-center text-muted py-4">No restaurant item sales.</td></tr><?php else: foreach($restaurantTopItems as $i): ?><tr><td><?php echo h($i['item_name']); ?></td><td class="text-end"><?php echo money_fmt($i['qty']); ?></td><td class="text-end fw-bold"><?php echo money_fmt($i['total']); ?></td></tr><?php endforeach; endif; ?></tbody></table></div></div></div>
</div>

<div class="row g-3 mb-3">
    <div class="col-xl-6"><div class="card panel-card h-100"><div class="card-header"><h5 class="mb-0">High Balance / Credit Review</h5></div><div class="card-body p-0"><table class="table table-modern mb-0"><thead><tr><th>Booking</th><th>Guest</th><th>Check Out</th><th class="text-end">Balance</th></tr></thead><tbody><?php if(!$highBalanceBookings): ?><tr><td colspan="4" class="text-center text-muted py-4">No balances above limit.</td></tr><?php else: foreach($highBalanceBookings as $r): ?><tr><td><strong><?php echo h($r['order_no']?:('#'.$r['id'])); ?></strong></td><td><?php echo h(na_guest_name($r)); ?></td><td><?php echo h($r['check_out']??''); ?></td><td class="text-end text-danger fw-bold"><?php echo money_fmt($r['booking_balance']); ?></td></tr><?php endforeach; endif; ?></tbody></table></div></div></div>
    <div class="col-xl-6"><div class="card panel-card h-100"><div class="card-header"><h5 class="mb-0">No Show Audit</h5></div><div class="card-body p-0"><table class="table table-modern mb-0"><thead><tr><th>Booking</th><th>Guest</th><th>Arrival</th><th>Fee Posted</th></tr></thead><tbody><?php if(!$noShows): ?><tr><td colspan="4" class="text-center text-muted py-4">No no-show exceptions.</td></tr><?php else: foreach($noShows as $r): ?><tr><td><strong><?php echo h($r['order_no']?:('#'.$r['id'])); ?></strong></td><td><?php echo h(na_guest_name($r)); ?></td><td><?php echo h($r['check_in']??''); ?></td><td><?php echo ((float)($r['no_show_fee']??0)>0)?'<span class="badge text-bg-success">Yes</span>':'<span class="badge text-bg-danger">Missing</span>'; ?></td></tr><?php endforeach; endif; ?></tbody></table></div></div></div>
</div>

<div class="row g-3 mb-3">
    <div class="col-xl-6"><div class="card panel-card h-100"><div class="card-header"><h5 class="mb-0">Stock Variance</h5></div><div class="card-body p-0"><table class="table table-modern mb-0"><thead><tr><th>Item</th><th class="text-end">System</th><th class="text-end">Physical</th><th class="text-end">Variance</th></tr></thead><tbody><?php if(!$stockVariance): ?><tr><td colspan="4" class="text-center text-muted py-4">No stock variance data found for the day.</td></tr><?php else: foreach($stockVariance as $r): ?><tr><td><?php echo h($r['item_name']); ?></td><td class="text-end"><?php echo money_fmt($r['system_qty']); ?></td><td class="text-end"><?php echo money_fmt($r['physical_qty']); ?></td><td class="text-end <?php echo (float)$r['variance_qty']<0?'text-danger':'text-success'; ?> fw-bold"><?php echo money_fmt($r['variance_qty']); ?></td></tr><?php endforeach; endif; ?></tbody></table></div></div></div>
    <div class="col-xl-6"><div class="card panel-card h-100"><div class="card-header"><h5 class="mb-0">Payment / Close Method Summary</h5></div><div class="card-body p-0"><table class="table table-modern mb-0"><thead><tr><th>Close Method</th><th class="text-end">Orders</th><th class="text-end">Amount</th></tr></thead><tbody><?php if(!$paymentSummary): ?><tr><td colspan="3" class="text-center text-muted py-4">No closed restaurant orders.</td></tr><?php else: foreach($paymentSummary as $r): ?><tr><td><?php echo h(ucwords(str_replace('_',' ',(string)$r['close_method']))); ?></td><td class="text-end"><?php echo (int)$r['orders']; ?></td><td class="text-end fw-bold"><?php echo money_fmt($r['amount']); ?></td></tr><?php endforeach; endif; ?></tbody></table></div></div></div>
</div>

<div class="row g-3">
    <div class="col-xl-6"><div class="card panel-card"><div class="card-header d-flex justify-content-between"><h5 class="mb-0">Dirty Rooms</h5><a href="/rooms/modules/payments/housekeeping_board.php?filter_status=vacant_dirty<?php echo $propertyId>0?'&property_id='.$propertyId:''; ?>&view_date=<?php echo urlencode($auditDate); ?>" class="btn btn-sm btn-outline-primary">Open Housekeeping</a></div><div class="card-body p-0"><table class="table table-modern mb-0"><thead><tr><th>Room</th><th>Property</th><th>Type</th></tr></thead><tbody><?php if(!$dirtyRooms): ?><tr><td colspan="3" class="text-center text-muted py-4">No dirty rooms.</td></tr><?php else: foreach($dirtyRooms as $r): ?><tr><td><strong><?php echo h($r['room_no']??''); ?></strong></td><td><?php echo h(na_property_label($r)); ?></td><td><?php echo h($r['room_type']??''); ?></td></tr><?php endforeach; endif; ?></tbody></table></div></div></div>
    <div class="col-xl-6"><div class="card panel-card"><div class="card-header d-flex justify-content-between"><h5 class="mb-0">Out of Order Rooms</h5><a href="/rooms/modules/payments/housekeeping_board.php?filter_status=ooo<?php echo $propertyId>0?'&property_id='.$propertyId:''; ?>&view_date=<?php echo urlencode($auditDate); ?>" class="btn btn-sm btn-outline-primary">Open Housekeeping</a></div><div class="card-body p-0"><table class="table table-modern mb-0"><thead><tr><th>Room</th><th>Property</th><th>Type</th></tr></thead><tbody><?php if(!$outOfOrderRooms): ?><tr><td colspan="3" class="text-center text-muted py-4">No out of order rooms.</td></tr><?php else: foreach($outOfOrderRooms as $r): ?><tr><td><strong><?php echo h($r['room_no']??''); ?></strong></td><td><?php echo h(na_property_label($r)); ?></td><td><?php echo h($r['room_type']??''); ?></td></tr><?php endforeach; endif; ?></tbody></table></div></div></div>
</div>

<style>
.compact-hero{padding:10px 14px!important;margin-bottom:10px!important;border-radius:16px!important}.compact-hero .hero-title{font-size:1.28rem!important;line-height:1.1!important;margin:2px 0 0!important}.compact-hero .hero-subtitle{font-size:.82rem!important;line-height:1.25!important;margin-top:2px!important;opacity:.9}.compact-hero .page-eyebrow{font-size:.68rem!important;letter-spacing:.06em!important;text-transform:uppercase}.compact-hero .hero-actions .btn{padding:5px 10px!important;border-radius:9px!important;font-size:.78rem!important;font-weight:700!important}.compact-metric{padding:10px 12px!important;border-radius:15px!important;min-height:64px!important}.compact-metric .metric-icon{width:36px!important;height:36px!important;border-radius:11px!important}.compact-metric .metric-label{font-size:.72rem!important;margin-bottom:0!important}.compact-metric .metric-value{font-size:1.05rem!important;line-height:1.1!important}.audit-check{border:1px solid #e5e7eb;background:#fff;border-radius:14px;padding:10px 12px;display:flex;justify-content:space-between;align-items:center;gap:8px;min-height:46px}.audit-check span{font-weight:800;font-size:.82rem;color:#0f172a}.totals-panel{display:grid;grid-template-columns:repeat(3,1fr);gap:10px}.totals-panel div{border:1px solid #e5e7eb;border-radius:16px;padding:14px;background:#f8fafc}.totals-panel span{display:block;font-size:.72rem;text-transform:uppercase;letter-spacing:.05em;color:#64748b;font-weight:900}.totals-panel strong{display:block;font-size:1.3rem;margin-top:4px}.table-modern thead th{background:#f8fafc;font-size:.72rem;text-transform:uppercase;color:#64748b;letter-spacing:.04em}.table-modern td,.table-modern th{padding:.58rem .68rem;border-bottom:1px solid #eef2f7;font-size:.84rem}.panel-card{border-radius:18px!important;overflow:hidden!important}.panel-card>.card-header{background:#fff!important;border-bottom:1px solid #eef2f7!important;padding:.7rem .9rem!important}.panel-card h5{font-size:.98rem;font-weight:900}@media(max-width:767.98px){.totals-panel{grid-template-columns:1fr}}@media print{.hero-actions,.no-print,.btn{display:none!important}.hero-band{background:#fff!important;color:#111!important;box-shadow:none!important;border:0!important}.text-white-50{color:#555!important}.card{break-inside:avoid}}
</style>

<?php require_once __DIR__ . '/../../includes/footer.php'; ?>
