D:\host\scoreman.in\highrange2026\functions.php

<?php
 
require_once 'PHPMailer/PHPMailer.php';
require_once 'PHPMailer/SMTP.php';
require_once 'PHPMailer/Exception.php';

use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\Exception;


function buildIDCardsHTML(
    mysqli $con,
    $repdistrict = '',
    $discipline = '',
    array $onlyAppnos = null,
    $bgPath = 'idbg.jpg',
    $certPrefix = 'HR2026/'
) {
    // --- Championship (for header text + district for logo slug) ---
    $evt = ['championshiptitle'=>'','dates'=>'','venue'=>'','district'=>$repdistrict];
    if ($repdistrict !== '' && ($st = mysqli_prepare($con,
        "SELECT championshiptitle, dates, venue, district
         FROM championships WHERE district=? ORDER BY id DESC LIMIT 1"))) {
        mysqli_stmt_bind_param($st, "s", $repdistrict);
        mysqli_stmt_execute($st);
        mysqli_stmt_store_result($st);
        mysqli_stmt_bind_result($st, $evt['championshiptitle'], $evt['dates'], $evt['venue'], $evt['district']);
        mysqli_stmt_fetch($st);
        mysqli_stmt_close($st);
    }
    $districtSlug = preg_replace('/[^A-Za-z0-9_-]/', '_', (string)$evt['district']);

    // --- columns we need (kept light but complete for the face) ---
    $cols = [
        'appno','sname','skaterid','chno',
        'dob','age','agegroup','gender',
        'club','clubname','photourl','agorder','skatertype',
        // for special age labels:
        'rollerderby','scooterpark','scooterstreet'
    ];
    $select = '`'.implode('`,`',$cols).'`';

    // --- filtering ---
    $where = "order_status='Success'";
   // if ($repdistrict !== '') $where .= " AND repdistrict='".mysqli_real_escape_string($con,$repdistrict)."'";
   if ($discipline !== '')  $where .= " AND skatertype='".mysqli_real_escape_string($con,$discipline)."'";
     //  if ($discipline !== '')  $where .= " AND skatertype NOT LIKE 'Speed%'";
    if ($onlyAppnos && count($onlyAppnos)) {
        $ids = [];
        foreach ($onlyAppnos as $a) $ids[] = "'".mysqli_real_escape_string($con,(string)$a)."'";
        $where .= " AND appno IN (".implode(',',$ids).")";
    }

    // Sort: club → discipline → agorder → gender → appno (numeric)
    $sql = "
        SELECT $select
        FROM applications
        WHERE $where
        ORDER BY
          IFNULL(NULLIF(clubname,''), club),
          FIELD(skatertype,
            'Speed-Quad','Speed-Inline','Artistic','Roller-Hockey','Inline-Hockey','Inline-Freestyle','Other','Other-Games'
          ),
          IFNULL(agorder,999999)+0,
          gender DESC,
          CAST(appno AS UNSIGNED), appno
    ";
    $res = mysqli_query($con, $sql);
    if (!$res) return '<p>Query failed: '.htmlspecialchars(mysqli_error($con),ENT_QUOTES,'UTF-8').'</p>';

    // --- helpers (reuse from certificate logic) ---
    $genderWord = function($g){
        $g = strtolower(trim((string)$g));
        if (in_array($g,['f','female','girl','girls','women','woman'],true)) return 'Girls';
        if (in_array($g,['m','male','boy','boys','men','man'],true))         return 'Boys';
        return ucfirst($g);
    };
    $computeAge = function($ageStr, $dobStr, $eventDateStr){
        $age = (int)$ageStr;
        if ($age > 0) return $age;
        $dobTs = strtotime($dobStr);
        if ($dobTs === false) return 0;
        $refTs = strtotime($eventDateStr);
        if ($refTs === false) $refTs = time();
        $y1=(int)date('Y',$refTs); $m1=(int)date('n',$refTs); $d1=(int)date('j',$refTs);
        $y0=(int)date('Y',$dobTs); $m0=(int)date('n',$dobTs); $d0=(int)date('j',$dobTs);
        $age = $y1 - $y0; if ($m1<$m0 || ($m1==$m0 && $d1<$d0)) $age--; return max(0,$age);
    };
    $specialAgeGroup = function($skatertype, $ageYears, $row){
        $st = trim((string)$skatertype);
        $age = (int)$ageYears;
        $hasDerby = !empty($row['rollerderby']);
        $hasScooter = !empty($row['scooter']) || !empty($row['scooter']);

        if ($st === 'Roller-Hockey' || $st === 'Inline-Hockey') {
            if ($age >= 6 && $age < 9)  return '6 to 9 Cadet Tiny Tots';
            if ($age >= 9 && $age < 12) return '9 to 12 Cadet';
            return null;
        }
        if (($st === 'Other' || $st === 'Other-Games') && $hasDerby) {
            if ($age >= 12 && $age < 18) return '12 to 18 Junior';
            return null;
        }
        if (($st === 'Other' || $st === 'Other-Games') && $hasScooter) {
            if ($age >= 12) return 'Above 12';
            return null;
        }
        return null;
    };

    // --- CSS (9cm x 13cm cards, centered) ---
    $css = <<<CSS
<style>
  :root{
    --w: 9cm;        /* card width  */
    --h: 13cm;       /* card height */
    --pad: 8mm;
    --ink:#0b2a6f; --accent:#274b9a;
  }
  @page { size: auto; margin: 8mm; } /* suitable for A3 or 13x19in; printers can scale 100% */
  *{box-sizing:border-box}
  body{ margin:0; font-family: Arial, Helvetica, sans-serif; color: var(--ink); -webkit-print-color-adjust:exact; print-color-adjust:exact; }
  .grid{
    display:flex; flex-wrap:wrap; justify-content:center; gap:6mm;
    padding:6mm;
  }

/* keep the card transparent so the bg shows */
.card{
  position:relative;
  width:var(--w); height:var(--h);
  background:transparent;
  overflow:hidden; display:flex; flex-direction:column; align-items:center; justify-content:flex-start;
  border-radius:6mm; box-shadow:0 0 0 0.5mm #ddd;
  page-break-inside:avoid; break-inside:avoid;
}

/* background image stays under the content */
.bg{
  position:absolute; inset:0; width:100%; height:100%;
  object-fit:cover; border-radius:inherit;
  pointer-events:none;
  z-index:0 !important;        /* <-- force it below */
}

/* put all normal children above the bg (but not the bg itself) */
.card > :not(.bg){
  position:relative;
  z-index:1;
}



  .logo{ margin-top:6mm; height:14mm; }
  .hdrTxt{ text-align:center; margin:3mm 8mm 0; font-weight:800; font-size:11pt; color:#12306e; }
  .sub{ text-align:center; font-size:9pt; margin-top:1mm; color:#334 }
  .photoRing{
    margin-top:5mm; width:34mm; height:34mm; padding:1mm; border-radius:6mm;
    background:linear-gradient(135deg,#7a2cff, #ff3aa6 50%, #3a8dff);
  }
  .photo{
    width:100%; height:100%; border-radius:6mm; object-fit:cover; background:#fff; display:hidden;
  }
  .photo.ph { display:flex; align-items:center; justify-content:center; font-weight:700; color:#345; background:#eef3ff; }

  .name{ margin-top:4mm; font-weight:900; font-size:14pt; letter-spacing:.4px; text-align:center; padding:0 8mm; text-transform:uppercase; }
  .line{ margin-top:1.4mm; font-size:10.5pt; text-align:center; padding:0 8mm; }
  .tiny{ font-size:9pt; color:#456; }

  .chip{
    margin-top:4mm; display:inline-block; padding:2mm 4mm; border:1px solid #c2ceed; border-radius:5mm; font-size:9.5pt; background:#f6f9ff;
  }

  /* footer band */
  .band{
    margin-top:auto; width:100%; padding:3mm 6mm; display:flex; align-items:center; justify-content:space-between;
    background:linear-gradient(90deg, rgba(122,44,255,.10), rgba(58,141,255,.10));
    font-size:9pt;
  }

  /* crop marks — drawn outside the rounded card edge */
  .card:before, .card:after { content:""; position:absolute; inset:0; pointer-events:none; }
  .card:before{
    /* corner ticks */
    background:
      linear-gradient(#000,#000) left 3mm top 0 / 18mm 0.25mm,
      linear-gradient(#000,#000) left 0 top 3mm / 0.25mm 18mm,
      linear-gradient(#000,#000) right 3mm top 0 / 18mm 0.25mm,
      linear-gradient(#000,#000) right 0 top 3mm / 0.25mm 18mm,
      linear-gradient(#000,#000) left 3mm bottom 0 / 18mm 0.25mm,
      linear-gradient(#000,#000) left 0 bottom 3mm / 0.25mm 18mm,
      linear-gradient(#000,#000) right 3mm bottom 0 / 18mm 0.25mm,
      linear-gradient(#000,#000) right 0 bottom 3mm / 0.25mm 18mm;
    background-repeat:no-repeat;
  }
</style>
CSS;

    $logoHtml = $districtSlug!=='' ? '<img class="logo" src="districtlogos/'.$districtSlug.'.png" alt="" onerror="this.style.display=\'none\'" />' : '';

    $html = $css . '<div class="grid">';

    while ($r = mysqli_fetch_assoc($res)) {
        $team  = ($r['clubname']!=='') ? $r['clubname'] : $r['club'];
        $name  = htmlspecialchars($r['sname'],ENT_QUOTES,'UTF-8');
        $teamH = htmlspecialchars($team,ENT_QUOTES,'UTF-8');
        $disc  = htmlspecialchars($r['skatertype'],ENT_QUOTES,'UTF-8');
        $gen   = htmlspecialchars($genderWord($r['gender']),ENT_QUOTES,'UTF-8');
        $appNo = htmlspecialchars($certPrefix.$r['appno'],ENT_QUOTES,'UTF-8');
        $race  = htmlspecialchars((string)$r['chno'],ENT_QUOTES,'UTF-8');
        $rsfi  = htmlspecialchars((string)$r['skaterid'],ENT_QUOTES,'UTF-8');

        // photo (base64 or dataURL)
        $photo = trim((string)$r['photourl']);
        if ($photo!=='' && strpos($photo,'data:image/')!==0) $photo='data:image/png;base64,'.$photo;
        $photoTag = ($photo!=='')
            ? '<img class="photo" src="'.htmlspecialchars($photo,ENT_QUOTES,'UTF-8').'" />'
            : '<div class="photo ph">PHOTO</div>';

        // special age label
        $ageYears = $computeAge(isset($r['age'])?$r['age']:'', isset($r['dob'])?$r['dob']:'', $evt['dates']);
        $agOverride = $specialAgeGroup($r['skatertype'], $ageYears, $r);
        $agDisplay  = ($agOverride !== null && $agOverride !== '') ? $agOverride : (string)$r['agegroup'];
        $agH        = htmlspecialchars($agDisplay,ENT_QUOTES,'UTF-8');

        $title = htmlspecialchars($evt['championshiptitle'],ENT_QUOTES,'UTF-8');
        $when  = htmlspecialchars($evt['dates'],ENT_QUOTES,'UTF-8');

        $html .=
        '<div class="card">'.
            '<img class="bg" src="'.htmlspecialchars($bgPath,ENT_QUOTES,'UTF-8').'" alt="" />'.
            $logoHtml.
            '<div class="hdrTxt">'.$title.'</div>'.
            '<div class="sub">'.$when.'</div>'.

            '<div class="photoRing">'.$photoTag.'</div>'.

            '<div class="name">'.$name.'</div>'.
            '<div class="line tiny">'.$disc.' • '.$gen.'</div>'.
            '<div class="line"><b>'.$agH.'</b></div>'.
            '<div class="line tiny">'. $teamH .'</div>'.

            '<div class="chip">App: '.$appNo.($race!=='' ? ' &nbsp;|&nbsp; Race: <b>'.$race.'</b>' : '').($rsfi!=='' ? ' &nbsp;|&nbsp; RSFI: '.$rsfi : '').'</div>'.
        '</div>';
    }
    mysqli_free_result($res);

    $html .= '</div>';
    return $html;
}

function buildChampionshipPointsTables(mysqli $con, $repdistrict = '') {
    // ---- event sets ----
    $speedQuad = ['rink1','rink2','rink3','road1','road2'];
    $speedInlineAll = ['rink4','rink5','rink6','rink7','p2p','elim','road3','road4','road5','p2prd','elimrd','relay','mixedrelay','marathon'];
    $inlineNoPoints = ['relay','mixedrelay','marathon']; // exclude from points

    $artistic = ['figure','free','pair','solodance','pairdance','inlinefree','quartet','precisionskating','showgroup'];
    $rollerHockey = ['quadhockey','mixedrollerhockey'];
    $inlineHockey = ['inlinehockey'];
    $freestyle = ['speedslalom','classicslalom','pairslalom'];
    $otherGames = ['alpine','downhill','rollerderby','rollerfreestylepark','skateboardingpark','scooterpark','rollerfreestylestreet','skateboardingstreet','scooterstreet'];

    $all = array_merge($speedQuad, $speedInlineAll, $artistic, $rollerHockey, $inlineHockey, $freestyle, $otherGames);

    // columns we need
    $cols = array_merge(['club','clubname','repdistrict','order_status'], $all);
    $select = '`'.implode('`,`',$cols).'`';

    // query
    $where = "order_status='Success'";
    $types = ''; $vals = [];
    if ($repdistrict !== '') { $where .= " AND repdistrict=?"; $types .= 's'; $vals[] = $repdistrict; }

    $sql = "SELECT $select FROM applications WHERE $where";
    $stmt = mysqli_prepare($con, $sql);
    if (!$stmt) return '<p>Query error: '.htmlspecialchars(mysqli_error($con),ENT_QUOTES,'UTF-8').'</p>';
    if ($types !== '') {
        $refs = [ &$types ];
        foreach ($vals as $i => $v) { $refs[] = &$vals[$i]; }
        call_user_func_array('mysqli_stmt_bind_param', array_merge([$stmt], $refs));
    }
    if (!mysqli_stmt_execute($stmt)) {
        return '<p>Query exec error: '.htmlspecialchars(mysqli_stmt_error($stmt),ENT_QUOTES,'UTF-8').'</p>';
    }

    $rows = [];
    if (function_exists('mysqli_stmt_get_result')) {
        $res = mysqli_stmt_get_result($stmt);
        while ($r = mysqli_fetch_assoc($res)) { $rows[] = $r; }
        if ($res) mysqli_free_result($res);
    } else {
        mysqli_stmt_store_result($stmt);
        // bind all columns dynamically
        $meta = mysqli_stmt_result_metadata($stmt);
        $fields=[]; $tmp=[]; $bind=[]; 
        while ($f = mysqli_fetch_field($meta)) { $fields[] = $f->name; $bind[] = &$tmp[$f->name]; }
        call_user_func_array('mysqli_stmt_bind_result', array_merge([$stmt], $bind));
        while (mysqli_stmt_fetch($stmt)) {
            $r = []; foreach ($fields as $f) { $r[$f] = $tmp[$f]; }
            $rows[] = $r;
        }
    }
    mysqli_stmt_close($stmt);

    // helpers
    $teamName = function($club, $clubname) {
        $club = trim((string)$club); $clubname = trim((string)$clubname);
        return ($clubname !== '') ? $clubname : $club;
    };
    // Map DB codes to medal bucket; IMPORTANT: 'S' means Selected (NOT Silver).
    $medalOf = function($raw) {
        $c = strtoupper(trim((string)$raw));
        if ($c === '1' || $c === 'G' || $c === 'GOLD')   return 'gold';
        if ($c === '2' || $c === 'SILVER')               return 'silver';
        if ($c === '3' || $c === 'B' || $c === 'BRONZE') return 'bronze';
        return null; // ignore P, A, NR, S (Selected), F (Forward), empty, etc.
    };

    // tallies
    $speed = [];   // team => [gold,silver,bronze,points]
    $overall = []; // team => [gold,silver,bronze,points]

    // iterate
    foreach ($rows as $r) {
        $team = $teamName($r['club'], $r['clubname']);
        if ($team === '') continue;

        // speed set = Speed-Quad + Speed-Inline (excluding relay/mixedrelay/marathon)
        foreach ($speedQuad as $col) {
            if (!array_key_exists($col,$r)) continue;
            $m = $medalOf($r[$col]); if (!$m) continue;
            if (!isset($speed[$team])) $speed[$team] = ['gold'=>0,'silver'=>0,'bronze'=>0,'points'=>0];
            $speed[$team][$m]++; // points after loop
        }
        foreach ($speedInlineAll as $col) {
            if (in_array($col, $inlineNoPoints, true)) continue; // excluded for points & medal counts
            if (!array_key_exists($col,$r)) continue;
            $m = $medalOf($r[$col]); if (!$m) continue;
            if (!isset($speed[$team])) $speed[$team] = ['gold'=>0,'silver'=>0,'bronze'=>0,'points'=>0];
            $speed[$team][$m]++;
        }

        // overall: all disciplines; still exclude inline relay/mixedrelay/marathon
        foreach ($all as $col) {
            if (in_array($col, $inlineNoPoints, true)) {
                // Exclude only for the inline trio; for other disciplines let medals count.
                continue;
            }
            if (!array_key_exists($col,$r)) continue;
            $m = $medalOf($r[$col]); if (!$m) continue;
            if (!isset($overall[$team])) $overall[$team] = ['gold'=>0,'silver'=>0,'bronze'=>0,'points'=>0];
            $overall[$team][$m]++;
        }
    }

    // compute points (5/3/1)
    $score = function(&$tab){
        foreach ($tab as $t => $v) {
            $g = (int)$v['gold']; $s = (int)$v['silver']; $b = (int)$v['bronze'];
            $tab[$t]['points'] = 5*$g + 3*$s + 1*$b;
        }
    };
    $score($speed); $score($overall);

    // sort: points desc, gold desc, silver desc, bronze desc, team asc
    $sortTab = function(&$tab){
        uasort($tab, function($A,$B){
            if ($A['points'] !== $B['points']) return $B['points'] - $A['points'];
            if ($A['gold']   !== $B['gold'])   return $B['gold']   - $A['gold'];
            if ($A['silver'] !== $B['silver']) return $B['silver'] - $A['silver'];
            if ($A['bronze'] !== $B['bronze']) return $B['bronze'] - $A['bronze'];
            // keys not available here; keep stable
            return 0;
        });
        // reindex with rank
        $ranked = [];
        $rk = 1;
        foreach ($tab as $team=>$row) {
            $row['_team'] = $team;
            $row['_rank'] = $rk++;
            $ranked[] = $row;
        }
        return $ranked;
    };

    $speedRanked   = $sortTab($speed);
    $overallRanked = $sortTab($overall);

    // render
    date_default_timezone_set('Asia/Kolkata');
    $printedOn = 'Printed On : ' . date('d-m-Y h:i:sa');

    $css = <<<CSS
<style>
  body { font-family: Arial, sans-serif; font-size: 12pt; }
  h3 { margin: 8px 0 4px; }
  table { border-collapse: collapse; width: 100%; margin: 6px 0 14px; }
  th, td { border: 1px solid #444; padding: 6px 8px; text-align: left; }
  th.rank, td.rank { width: 8%; text-align: center; }
  th.team, td.team { width: 52%; }
  th.g, th.s, th.b, th.pts, td.g, td.s, td.b, td.pts { width: 10%; text-align: right; }
  .medal { font-weight: 700; }
  .g { background:#fff6cc; } .s { background:#eef1f6; } .b { background:#f6e4d9; }
  .pts { background:#f2f8ff; font-weight:700; }
  @media print {
    table { break-inside: avoid; page-break-inside: avoid; }
  }
</style>
CSS;

    $tbl = function($title, $rows){
        if (empty($rows)) return "<h3>$title</h3><p>No results found.</p>";
        $h  = "<h3>$title</h3>";
        $h .= "<table><thead><tr>"
            .  "<th class='rank'>Rank</th>"
            .  "<th class='team'>Team</th>"
            .  "<th class='g'>Gold</th>"
            .  "<th class='s'>Silver</th>"
            .  "<th class='b'>Bronze</th>"
            .  "<th class='pts'>Points</th>"
            .  "</tr></thead><tbody>";
        foreach ($rows as $r) {
            $h .= "<tr>"
                .  "<td class='rank'>".(int)$r['_rank']."</td>"
                .  "<td class='team'>".htmlspecialchars($r['_team'],ENT_QUOTES,'UTF-8')."</td>"
                .  "<td class='g'>".(int)$r['gold']."</td>"
                .  "<td class='s'>".(int)$r['silver']."</td>"
                .  "<td class='b'>".(int)$r['bronze']."</td>"
                .  "<td class='pts'>".(int)$r['points']."</td>"
                .  "</tr>";
        }
        $h .= "</tbody></table>";
        return $h;
    };

    $html  = $css;
    $html .= $tbl('Speed Skating Championship Points (Quad + Inline)', $speedRanked);
    $html .= $tbl('Overall Championship Points (All Disciplines)',     $overallRanked);
    $html .= "<div style='margin-top:6px;font-size:10pt;color:#333;'>".htmlspecialchars($printedOn,ENT_QUOTES,'UTF-8')."</div>";

    return $html;
}


function buildSpeedEventSummary(mysqli $con, $repdistrict = '')
{
    // ---- header info (championships) ----
    $eventtitle = $eventdate = '';
    if ($repdistrict !== '') {
        $sqlC = 'SELECT championshiptitle, dates FROM championships WHERE district = ? ORDER BY id DESC LIMIT 1';
        if ($st = mysqli_prepare($con, $sqlC)) {
            mysqli_stmt_bind_param($st, 's', $repdistrict);
            mysqli_stmt_execute($st);
            if (function_exists('mysqli_stmt_get_result')) {
                $rs = mysqli_stmt_get_result($st);
                if ($row = mysqli_fetch_assoc($rs)) {
                    $eventtitle = trim($row['championshiptitle']);
                    $eventdate  = trim($row['dates']);
                }
                if ($rs) mysqli_free_result($rs);
            }
            mysqli_stmt_close($st);
        }
    }

    // ---- speed events order (quad first, then inline) ----
    $events = array(
        'rink1' => 'rink1', 'rink2' => 'rink2', 'rink3' => 'rink3',
        'road1' => 'road1', 'road2' => 'road2',
        'rink4' => 'rink4', 'rink5' => 'rink5', 'rink6' => 'rink6', 'rink7' => 'rink7',
        'p2p'   => 'p2p',   'elim'  => 'elim',
        'road3' => 'road3', 'road4' => 'road4', 'road5' => 'road5',
        'p2prd' => 'p2prd', 'elimrd'=> 'elimrd',
        'relay' => 'relay', 'mixedrelay' => 'mixedrelay'
        // 'marathon' // omit if not required
    );

    // ---- fetch all needed data ----
    $cols = array_merge(array('agegroup','agorder','gender'), array_keys($events));
    $select = '`' . implode('`,`', $cols) . '`';

    $where = 'order_status="Success"';
    $types = '';
    $params = array();

    if ($repdistrict !== '') {
       // $where .= ' AND repdistrict = ?';
        $types .= 's';
        $params[] = $repdistrict;
    }

    // optional: ignore blank chno entries if you prefer
    // $where .= ' AND chno <> ""';

    $sql = "SELECT $select FROM applications WHERE $where";
    $sql .= " ORDER BY agorder+0, gender DESC"; // Cadet.. Senior by agorder; Boys after Girls (DESC -> M,F depends on your data)

    $rows = array();
    if ($st = mysqli_prepare($con, $sql)) {
        if ($types !== '') {
            $bind = array($st, $types);
            foreach ($params as $k => $v) { $bind[] = &$params[$k]; }
            call_user_func_array('mysqli_stmt_bind_param', $bind);
        }
        mysqli_stmt_execute($st);

        if (function_exists('mysqli_stmt_get_result')) {
            $rs = mysqli_stmt_get_result($st);
            while ($r = mysqli_fetch_assoc($rs)) $rows[] = $r;
            if ($rs) mysqli_free_result($rs);
        } else {
            mysqli_stmt_store_result($st);
            $meta = mysqli_stmt_result_metadata($st);
            $fields = array(); $cur = array(); $bindRes = array();
            while ($f = mysqli_fetch_field($meta)) { $fields[] = $f->name; $bindRes[] = &$cur[$f->name]; }
            call_user_func_array('mysqli_stmt_bind_result', array_merge(array($st), $bindRes));
            while (mysqli_stmt_fetch($st)) {
                $rr = array();
                foreach ($fields as $f) $rr[$f] = $cur[$f];
                $rows[] = $rr;
            }
        }
        mysqli_stmt_close($st);
    }

    // ---- accumulate counts: summary[agorder]['label'] + ['Female'|'Male'][event] ----
    $summary = array();     // agorder => ['agegroup'=>..., 'Female'=>[], 'Male'=>[]]
    $grand   = array();     // event => total
    foreach ($events as $ev => $lbl) { $grand[$ev] = 0; }

    // helper to decide if a cell counts as an entry
    $countsAsEntry = function($v) {
        if ($v === null) return false;
        $v = strtoupper(trim((string)$v));
        // count entries that are participating or placed; ignore explicit Absent
        return ($v === 'P' || $v === '1' || $v === '2' || $v === '3' || $v === 'G' || $v === 'S' || $v === 'B' || $v === 'A');
    };

    foreach ($rows as $r) {
        $agorder = isset($r['agorder']) ? trim($r['agorder']) : '999';
        if (!isset($summary[$agorder])) {
            $summary[$agorder] = array(
                'agegroup' => trim($r['agegroup']),
                'Female'   => array(),
                'Male'     => array(),
            );
            foreach (array('Female','Male') as $g) {
                foreach ($events as $ev => $lbl) $summary[$agorder][$g][$ev] = 0;
            }
        }

        $gender = strtolower(trim($r['gender']));
        $gkey = (in_array($gender, array('f','female','girl','girls','women','woman'), true)) ? 'Female' : 'Male';

        foreach ($events as $ev => $lbl) {
            if ($countsAsEntry(isset($r[$ev]) ? $r[$ev] : null)) {
                $summary[$agorder][$gkey][$ev] += 1;
                $grand[$ev] += 1;
            }
        }
    }

    // ---- render HTML ----
    ob_start();
    ?>
    <style>
        .evt-sum { width: 100%; border-collapse: collapse; font-family: Arial, sans-serif; font-size: 12px; }
        .evt-sum th, .evt-sum td { border: 1px solid #333; padding: 4px 6px; text-align: right; }
        .evt-sum th:first-child, .evt-sum td:first-child { text-align: left; }
        .evt-sum thead th { background: #f2f2f2; font-weight: bold; }
        .evt-sum .ag { font-weight: bold; text-align: left; }
        .evt-sum .sex { text-align: left; width: 80px; }
        .evt-title { text-align:center; font-weight:bold; font-size:16px; margin:4px 0 10px; }
        .evt-sub { text-align:center; font-size:12px; margin-top:-6px; margin-bottom:10px; }
        .evt-sum tfoot td { font-weight: bold; background:#f7f7f7; }
        /* optional: rotate headers */
        .vhead { writing-mode: vertical-rl; transform: rotate(180deg); white-space:nowrap; padding:6px 2px; min-width:16px; }
        @media print {
            .evt-title { margin-top:0 }
        }
    </style>
    <div class="evt-title"><?php echo htmlspecialchars($eventtitle !== '' ? $eventtitle : 'EVENT SUMMARY', ENT_QUOTES, 'UTF-8'); ?></div>
    <div class="evt-sub">EVENT SUMMARY - SPEED<?php echo $eventdate ? ' &nbsp;|&nbsp; ' . htmlspecialchars($eventdate, ENT_QUOTES, 'UTF-8') : ''; ?></div>

    <table class="evt-sum">
        <thead>
            <tr>
                <th>Age Group</th>
                <th class="sex">Gender</th>
                <?php foreach ($events as $ev => $lbl): ?>
                    <th><span class="vhead"><?php echo htmlspecialchars($lbl, ENT_QUOTES, 'UTF-8'); ?></span></th>
                <?php endforeach; ?>
            </tr>
        </thead>
        <tbody>
        <?php
        ksort($summary, SORT_NATURAL);
        foreach ($summary as $agorder => $blk):
            $agegroup = $blk['agegroup'];
            ?>
            <tr>
                <td class="ag" rowspan="2"><?php echo htmlspecialchars($agegroup, ENT_QUOTES, 'UTF-8'); ?></td>
                <td class="sex">Female</td>
                <?php foreach ($events as $ev => $lbl): ?>
                    <td><?php echo (int)$blk['Female'][$ev]; ?></td>
                <?php endforeach; ?>
            </tr>
            <tr>
                <td class="sex">Male</td>
                <?php foreach ($events as $ev => $lbl): ?>
                    <td><?php echo (int)$blk['Male'][$ev]; ?></td>
                <?php endforeach; ?>
            </tr>
        <?php endforeach; ?>
        </tbody>
        <tfoot>
            <tr>
                <td colspan="2">Grand Total</td>
                <?php foreach ($events as $ev => $lbl): ?>
                    <td><?php echo (int)$grand[$ev]; ?></td>
                <?php endforeach; ?>
            </tr>
        </tfoot>
    </table>
    <?php
    return ob_get_clean();
}

function buildCertificatesHTML(
    mysqli $con,
    $repdistrict = 'Idukki',
    $discipline = '',
    array $onlyAppnos = null,
    $certPrefix = 'HR2026',
    $bgPath = 'certbg.jpg'
) {
    // Normalise prefix (no trailing /)
    $certPrefix = rtrim((string)$certPrefix, '/');

    // ---- read championships (by district; no global fallback) ----
    $eventTitle = ''; $eventDate = ''; $eventVenue = ''; $president = ''; $secretary = ''; $districtSafe = $repdistrict;

    $champ = null;
    if ($repdistrict !== '' && ($st = mysqli_prepare($con, "SELECT championshiptitle, dates, venue, president, secretary, district FROM championships WHERE district=? ORDER BY id DESC LIMIT 1"))) {
        mysqli_stmt_bind_param($st, "s", $repdistrict);
        mysqli_stmt_execute($st);
        mysqli_stmt_store_result($st);
        $title=''; $dates=''; $venue=''; $pres=''; $sec=''; $dist='';
        mysqli_stmt_bind_result($st, $title, $dates, $venue, $pres, $sec, $dist);
        if (mysqli_stmt_fetch($st)) {
            $champ = array(
                'championshiptitle'=>$title,
                'dates'=>$dates,
                'venue'=>$venue,
                'president'=>$pres,
                'secretary'=>$sec,
                'district'=>$dist
            );
        }
        mysqli_stmt_close($st);
    }
    if ($champ) {
        $eventTitle   = isset($champ['championshiptitle']) ? (string)$champ['championshiptitle'] : '';
        $eventDate    = isset($champ['dates'])             ? (string)$champ['dates']             : '';
        $eventVenue   = isset($champ['venue'])             ? (string)$champ['venue']             : '';
        $president    = isset($champ['president'])         ? (string)$champ['president']         : '';
        $secretary    = isset($champ['secretary'])         ? (string)$champ['secretary']         : '';
        $districtSafe = isset($champ['district'])          ? (string)$champ['district']          : $repdistrict;
    }

    // Super-discipline (for grouping only)
    $discSuperNames = array(
        'S' => 'Speed Skating',
        'A' => 'Artistic Skating',
        'H' => 'Roller / Inline Hockey',
        'O' => 'Other Games'
    );

    // Exact discipline labels you want on the certificate body
    $discLabelMap = array(
        'Speed-Quad'       => 'Speed-Quad',
        'Speed-Inline'     => 'Speed-Inline',
        'Beginner-Quad'       => 'Beginner-Quad',
        'Beginner-Inline'     => 'Beginner-Inline',
        'Roller-Hockey'    => 'Roller-Hockey',
        'Inline-Hockey'    => 'Inline-Hockey',
        'Artistic'         => 'Artistic',
        'Inline-Freestyle' => 'Inline-Freestyle',
        'Inline-Alpine'    => 'Inline-Alpine',
        'Inline-Downhill'  => 'Inline-Downhill',
        'Skateboarding'    => 'Skateboarding',
        'Roller-Scooter'   => 'Roller-Scooter',
        'Roller-Derby'     => 'Roller-Derby'
    );

    // Short codes for certificate numbers (per discipline)
    $certCodeMap = array(
        'Speed-Quad'       => 'SQ',
        'Speed-Inline'     => 'SI',
        'Roller-Hockey'    => 'RH',
        'Inline-Hockey'    => 'IH',
        'Artistic'         => 'AR',
        'Inline-Freestyle' => 'IF',
        'Inline-Alpine'    => 'IA',
        'Inline-Downhill'  => 'ID',
        'Skateboarding'    => 'SB',
        'Roller-Scooter'   => 'RS',
        'Roller-Derby'     => 'RD',
        'Other'            => 'OG',
        'Other-Games'      => 'OG'
    );

    // Per-discipline serial counters (SQ/SI/RH/…)
    $serialCounters = array();
    foreach ($certCodeMap as $code) {
        $serialCounters[$code] = 0;
    }
    // generic fallback
    if (!isset($serialCounters['OG'])) {
        $serialCounters['OG'] = 0;
    }

    // Prepared statement for storing issued certificates (ignore failure if table missing)
    $storeStmt = mysqli_prepare(
        $con,
        "INSERT INTO certificates_issued
         (district, appno, discipline_code, discipline_name, event_code, event_label,
          result_raw, result_label, cert_number, cert_type)
         VALUES (?,?,?,?,?,?,?,?,?,?)"
    );

    // ---- columns to fetch (ALL disciplines) ----
    $eventCols = array(
        // Speed-Quad
        'rink1','rink2','rink3','road1','road2',
         'u8race1q','u8race2q','u8race1i','u8race1i',
        // Speed-Inline
        'rink4','rink5','rink6','rink7','p2p','elim','relay','mixedrelay',
        'road3','road4','road5','p2prd','elimrd','marathon',
        // Artistic
        'figure','free','pair','solodance','pairdance','inlinefree',
        'quartet','precisionskating','showgroup',
        // Hockey
        'quadhockey','mixedrollerhockey','inlinehockey',
        // Inline-Freestyle
        'speedslalom','classicslalom','pairslalom',
        // Other Games
        'alpine','downhill','rollerderby','rollerfreestylepark','skateboardingpark','scooterpark',
        'rollerfreestylestreet','skateboardingstreet','scooterstreet'
    );

    // NOTE: include age + agorder + skatertype
    $cols = array_merge(
        array('appno','sname','dob','age','agegroup','gender','club','clubname','photourl','agorder','skatertype'),
        $eventCols
    );
    $select = '`'.implode('`,`',$cols).'`';

    $where = "order_status='Success' and status<>'Delete'";
    // if ($discipline!==''){
    //     $where.=" AND skatertype='".mysqli_real_escape_string($con,$discipline)."'";
    // }
    if ($onlyAppnos && count($onlyAppnos)){
        $ids = array();
        foreach($onlyAppnos as $a){ $ids[]="'".mysqli_real_escape_string($con,(string)$a)."'"; }
        $where.=" AND appno IN (".implode(',',$ids).")";
    }

    // Sorting remains: team → discipline → agorder → gender → appno
    $sql = "
        SELECT $select
        FROM applications
        WHERE $where
        ORDER BY
          IFNULL(NULLIF(clubname,''), club),
          FIELD(skatertype,
            'Speed-Quad','Speed-Inline','Artistic','Roller-Hockey','Inline-Hockey','Inline-Freestyle','Other','Other-Games','Beginner-Quad','Beginner-Inline'
          ),
          IFNULL(agorder,999999)+0,
          gender DESC,
          CAST(appno AS UNSIGNED), appno
    ";

    $res = mysqli_query($con,$sql);
    if (!$res) {
        if ($storeStmt) mysqli_stmt_close($storeStmt);
        return '<p>Query failed: '.htmlspecialchars(mysqli_error($con),ENT_QUOTES,'UTF-8').'</p>';
    }

    // ---- helpers ----
    $resultLabel = function($v){
        $v = strtoupper(trim((string)$v));
        if ($v==='1' || $v==='G') return 'FIRST';
        if ($v==='2'             ) return 'SECOND';
        if ($v==='3' || $v==='B') return 'THIRD';
        if ($v==='S'             ) return 'SELECTED';
        if ($v==='F'             ) return 'NIL';
        if ($v==='P'             ) return 'PARTICIPATED';
        if ($v==='A' || $v==='NR') return 'NIL'; // ABSENT treated as NIL
        return 'NIL';
    };
    $isMerit = function($lbl){
        return ($lbl==='FIRST' || $lbl==='SECOND' || $lbl==='THIRD');
    };
    $genderWord = function($g){
        $g=strtolower(trim((string)$g));
        if (in_array($g,array('f','female','girl','girls','women','woman'),true)) return 'Girls';
        if (in_array($g,array('m','male','boy','boys','men','man'),true))         return 'Boys';
        return ucfirst($g);
    };

    // Age compute (fallback to DOB if age missing)
    $computeAge = function($ageStr, $dobStr, $eventDateStr){
        $age = (int)$ageStr;
        if ($age > 0) return $age;
        $dobTs = strtotime($dobStr);
        if ($dobTs === false) return 0;
        $refTs = strtotime($eventDateStr);
        if ($refTs === false) $refTs = time();
        $y1 = (int)date('Y',$refTs); $m1=(int)date('n',$refTs); $d1=(int)date('j',$refTs);
        $y0 = (int)date('Y',$dobTs); $m0=(int)date('n',$dobTs); $d0=(int)date('j',$dobTs);
        $age = $y1 - $y0;
        if ($m1 < $m0 || ($m1==$m0 && $d1 < $d0)) $age--;
        return ($age<0?0:$age);
    };

    // Special age-group display by discipline
    $specialAgeGroup = function($skatertype, $ageYears, $row){
        $st = trim((string)$skatertype);
        $age = (int)$ageYears;

        // Detect per-event participation for Other-Games cases
        $hasDerby   = isset($row['rollerderby']) && trim($row['rollerderby']) !== '';
        $hasScooter = isset($row['scooterpark']) && trim($row['scooterpark']) !== '';

        if ($st === 'Roller-Hockey' || $st === 'Inline-Hockey') {
            if ($age >= 6 && $age < 9)  return '6 to 9 Cadet Tiny Tots';
            if ($age >= 9 && $age < 12) return '9 to 12 Cadet';
            return null; // fallback to default printed agegroup
        }

        // If discipline is "Other"/"Other-Games", check which event is actually present
        if (($st === 'Other' || $st === 'Other-Games') && $hasDerby) {
            if ($age >= 12 && $age < 18) return '12 to 18 Junior';
            return null;
        }
        if (($st === 'Other' || $st === 'Other-Games') && $hasScooter) {
            if ($age >= 12) return 'Above 12';
            return null;
        }

        return null; // no override
    };

    // ---- discipline maps (same as before) ----
    $quadMap = array(
        'rink1'=>'RINK - I','rink2'=>'RINK - II','rink3'=>'RINK - III','road1'=>'ROAD - I','road2'=>'ROAD - II'
    );
      $beginnerMap = array(
        'u8race1q'=>'Beginner Quad Race I','u8race2q'=>'Beginner Quad Race II','u8race1i'=>'Beginner Inline Race I','u8race2i'=>'Beginner Inline Race II'
    );
    $inlineMap = array(
        'p2p'=>'POINTS (TRACK)','elim'=>'ELIMINATION (RINK)',
        'rink4'=>'RINK - IV','rink5'=>'RINK - V','rink6'=>'RINK - VI','rink7'=>'RINK - VII (Dual TT)',
        'road3'=>'ROAD - III','road4'=>'ROAD - IV','road5'=>'ROAD - V',
        'p2prd'=>'POINT TO POINT (ROAD)','elimrd'=>'ELIMINATION (ROAD)','relay'=>'RELAY','mixedrelay'=>'MIXED RELAY','marathon'=>'MARATHON'
    );
    $artisticMap = array(
        'figure'=>'FIGURE','free'=>'FREE','pair'=>'PAIR','solodance'=>'SOLODANCE','pairdance'=>'PAIRDANCE',
        'inlinefree'=>'INLINE FREE','quartet'=>'QUARTET','precisionskating'=>'PRECISION','showgroup'=>'SHOW GROUP'
    );
    $rollerHockeyMap = array(
        'quadhockey'=>'ROLLER HOCKEY','mixedrollerhockey'=>'ROLLER HOCKEY (MIXED)'
    );
    $inlineHockeyMap = array(
        'inlinehockey'=>'INLINE HOCKEY'
    );
    $freestyleMap = array(
        'speedslalom'=>'SPEED SLALOM','classicslalom'=>'CLASSIC SLALOM','pairslalom'=>'PAIR SLALOM'
    );
    $otherGamesMap = array(
        'alpine'=>'ALPINE','downhill'=>'DOWNHILL','rollerderby'=>'ROLLER DERBY','rollerfreestylepark'=>'ROLLER FREESTYLE - PARK',
        'skateboardingpark'=>'SKATEBOARDING - PARK','scooterpark'=>'SCOOTER-PARK','rollerfreestylestreet'=>'ROLLER FREESTYLE - STREET',
        'skateboardingstreet'=>'SKATEBOARDING - STREET','scooterstreet'=>'SCOOTER-STREET'
    );

    $districtSlug = preg_replace('/[^A-Za-z0-9_-]/','_',$districtSafe);
    $bgAttr = htmlspecialchars($bgPath,ENT_QUOTES,'UTF-8');

    $css = '<style>
      :root{
        --ink:#0b2a6f; --title:#12306e; --accent:#274b9a;
        --line:#c3d2f2; --sig-bottom:65mm; --hdr-top:10mm; --hdr-bottom:4mm; --logo-max-h:28mm;
        --photo-size:34mm; --name-size:20pt; --title-size:26pt; --ring:1mm; --corner:4mm;
        --grad-a:#7a2cff; --grad-b:#ff3aa6; --grad-c:#3a8dff;
      }
      *{box-sizing:border-box}
      @page{ size:A4; margin:0 }
      html,body{ height:100% }
      body{ font-family:Arial,Helvetica,sans-serif; color:var(--ink); margin:0; -webkit-print-color-adjust:exact; print-color-adjust:exact; }
      .certpage{ page-break-after:always } .certpage:last-child{ page-break-after:auto }

      .sheet{ position:relative; width:210mm; height:297mm; overflow:hidden; display:grid; grid-template-rows:auto 1fr auto; }
      .pagebg{ position:absolute; inset:0; width:100%; height:100%; object-fit:cover; z-index:-1; }

      .hdr{ text-align:center; padding:var(--hdr-top) 16mm var(--hdr-bottom) }
      .logoCenter{ display:block; margin:0 auto 4mm; width:95%; height:auto; max-height:var(--logo-max-h) }
      .titleCert{ font-size:var(--title-size); font-weight:900; letter-spacing:.4px; margin:0; color:var(--title); text-transform:uppercase }
      .certno{ font-size:10pt; margin:2px 0 5mm }

      .content{ display:flex; flex-direction:column; align-items:center; padding:0 16mm; padding-bottom: calc(var(--sig-bottom) + 6mm); }
      .content-inner{ max-width:158mm; text-align:center; width:100% }
      .idrow{ display:flex; justify-content:center; margin:4mm 0 }
      .photoFrame{ width:var(--photo-size); height:var(--photo-size); padding:var(--ring); border-radius:var(--corner);
                   background:linear-gradient(135deg,var(--grad-a) 0%,var(--grad-b) 45%,var(--grad-c) 100%); box-shadow:0 .8mm 2mm rgba(0,0,0,.12);}
      .photo{ width:100%; height:100%; border-radius:var(--corner); object-fit:cover; background:#fff; display:block; }
      .photo.ph{ display:flex; align-items:center; justify-content:center; background:#eef3ff; color:#0b2a6f; font-weight:700; border-radius:var(--corner) }
      .name{ font-size:var(--name-size); font-weight:900; letter-spacing:.8px; margin:1.6mm 0 2.6mm; text-transform:uppercase }
      .line{ margin:1.6mm 0 }

      .events{ display:flex; gap:6mm; justify-content:center; margin-top:4mm; flex-wrap:wrap }
      .blk{ width:520mm }
      .blk h4{ margin:0 0 2mm; font-size:11.5pt; text-transform:uppercase; border-bottom:1px solid var(--accent); padding-bottom:2px; color:var(--accent) }
      table.ev{ width:100%; border-collapse:collapse; font-size:10.5pt }
      table.ev td{ border-bottom:2px dotted var(--line); padding:2.5px 2px }
     
 

      .footer{ position:absolute; left:16mm; right:16mm; bottom:var(--sig-bottom); z-index:1; }
      .signs{ display:flex; justify-content:space-between; align-items:flex-end; gap:10mm }
      .sigbox{
        width:46%; text-align:center;
        display:flex; flex-direction:column; align-items:center; justify-content:flex-end;
      }
      .sigpad{
        height:16mm;
        width:100%;
        display:flex; align-items:flex-end; justify-content:center;
        margin-bottom:2mm;
      }
      .sigimg{
        max-height:14mm;
        width:auto; object-fit:contain; display:block;
      }
      .signame{ font-weight:800; margin:0 }
      .sigrole{ margin-top:1.2mm }
    </style>';

    $pages = array();

    while ($r = mysqli_fetch_assoc($res)) {

        $clubDisplay = ($r['clubname']!=='') ? $r['clubname'] : $r['club'];
        $dobStr = (!empty($r['dob']) && ($ts=strtotime($r['dob'])))
                    ? date('d-M-Y',$ts)
                    : htmlspecialchars($r['dob'],ENT_QUOTES,'UTF-8');
        $name   = htmlspecialchars($r['sname'],ENT_QUOTES,'UTF-8');
        $team   = htmlspecialchars($clubDisplay,ENT_QUOTES,'UTF-8');
        $agRaw  = isset($r['agegroup']) ? (string)$r['agegroup'] : '';
        $gender = htmlspecialchars($genderWord($r['gender']),ENT_QUOTES,'UTF-8');
        $appno  = (string)$r['appno'];
        $skatertype = isset($r['skatertype']) ? trim((string)$r['skatertype']) : '';

        // photo
        $photo = trim((string)$r['photourl']);
        if ($photo!=='' && strpos($photo,'data:image/')!==0) $photo='data:image/png;base64,'.$photo;
        $photoTag = ($photo!=='')
          ? '<div class="photoFrame"><img class="photo" src="'.htmlspecialchars($photo,ENT_QUOTES,'UTF-8').'" alt=""></div>'
          : '<div class="photoFrame"><div class="photo ph">PHOTO</div></div>';

        // fully-absent check across all events (keep if any positive)
        $sawAbsent=false; $sawPositive=false;
        foreach ($eventCols as $ek) {
            if (!array_key_exists($ek,$r)) continue;
            $lbl = $resultLabel($r[$ek]);
            if ($lbl==='NIL') $sawAbsent = true;
            if (in_array($lbl, array('FIRST','SECOND','THIRD','PARTICIPATED','SELECTED'), true)) $sawPositive = true;
        }
        if (!$sawPositive && $sawAbsent) { continue; }

        // special age group text by discipline
        $ageYears = $computeAge(isset($r['age'])?$r['age']:'', isset($r['dob'])?$r['dob']:'', $eventDate);
        $agOverride = $specialAgeGroup($skatertype, $ageYears, $r);
        $agDisplay  = ($agOverride !== null && $agOverride !== '') ? $agOverride : $agRaw;
        $agHtml     = htmlspecialchars($agDisplay, ENT_QUOTES, 'UTF-8');

        // Collect events by super-discipline: S/A/H/O
        $eventsByDisc = array(
            'S' => array('name'=>$discSuperNames['S'],'events'=>array()),
            'A' => array('name'=>$discSuperNames['A'],'events'=>array()),
            'H' => array('name'=>$discSuperNames['H'],'events'=>array()),
            'O' => array('name'=>$discSuperNames['O'],'events'=>array())
        );
        $discHasMerit = array('S'=>false,'A'=>false,'H'=>false,'O'=>false);
        $discHasParticipation = array('S'=>false,'A'=>false,'H'=>false,'O'=>false);
        $anyEvent = false;
        $anyMeritGlobal = false;

        $collect = function($map, $discCode) use (
            &$eventsByDisc, &$discHasMerit, &$discHasParticipation,
            &$anyEvent, &$anyMeritGlobal, $r, $resultLabel, $isMerit
        ){
            foreach ($map as $k=>$label) {
                if (!isset($r[$k])) continue;
                $raw = $r[$k];
                $lbl = $resultLabel($raw);
                if ($lbl==='NIL') continue;
                $anyEvent = true;

                $mer = $isMerit($lbl);
                if ($mer) {
                    $discHasMerit[$discCode] = true;
                    $anyMeritGlobal = true;
                } elseif (in_array($lbl, array('PARTICIPATED','SELECTED'), true)) {
                    $discHasParticipation[$discCode] = true;
                }

                $eventsByDisc[$discCode]['events'][] = array(
                    'code'   => $k,
                    'label'  => $label,
                    'raw'    => $raw,
                    'result' => $lbl,
                    'isMerit'=> $mer
                );
            }
        };

        // Map event groups to super-disciplines
        $collect($quadMap,        'S');
        $collect($beginnerMap,        'S');
        $collect($inlineMap,      'S');
        $collect($freestyleMap,   'S');
        $collect($artisticMap,    'A');
        $collect($rollerHockeyMap,'H');
        $collect($inlineHockeyMap,'H');
        $collect($otherGamesMap,  'O');

        if (!$anyEvent) continue; // nothing to show

        // Determine row's main super-discipline code for grouping logic
        $rowDiscCode = null;
        switch ($skatertype) {
            case 'Beginner-Quad':
            case 'Beginner-Quad':
            case 'Speed-Quad':
            case 'Speed-Inline':
            case 'Inline-Freestyle':
                $rowDiscCode = 'S'; break;
            case 'Artistic':
                $rowDiscCode = 'A'; break;
            case 'Roller-Hockey':
            case 'Inline-Hockey':
                $rowDiscCode = 'H'; break;
            case 'Inline-Alpine':
            case 'Inline-Downhill':
            case 'Skateboarding':
            case 'Roller-Scooter':
            case 'Roller-Derby':
            case 'Other':
            case 'Other-Games':
                $rowDiscCode = 'O'; break;
        }
        if ($rowDiscCode === null) {
            foreach (array('S','A','H','O') as $dc) {
                if ($discHasMerit[$dc] || $discHasParticipation[$dc]) { $rowDiscCode=$dc; break; }
            }
        }
        if ($rowDiscCode === null) {
            // Cannot classify discipline -> skip
            continue;
        }

        // Decide discipline label to show on certificate body
        $discLabel = $skatertype;
        if (isset($discLabelMap[$skatertype])) {
            $discLabel = $discLabelMap[$skatertype];
        } elseif ($rowDiscCode === 'O') {
            // Try to infer from Other-Games events
            $discLabel = ''; // will fill from events if possible
            $ogEvents = $eventsByDisc['O']['events'];
            foreach ($ogEvents as $ev) {
                switch ($ev['code']) {
                    case 'rollerderby':
                        $discLabel = 'Roller-Derby'; break 2;
                    case 'alpine':
                        $discLabel = 'Inline-Alpine'; break 2;
                    case 'downhill':
                        $discLabel = 'Inline-Downhill'; break 2;
                    case 'skateboardingpark':
                    case 'skateboardingstreet':
                        $discLabel = 'Skateboarding'; break 2;
                    case 'scooterpark':
                    case 'scooterstreet':
                        $discLabel = 'Roller-Scooter'; break 2;
                }
            }
            if ($discLabel === '') {
                // fallback if nothing matched
                $discLabel = isset($discSuperNames[$rowDiscCode]) ? $discSuperNames[$rowDiscCode] : 'Other-Games';
            }
        } else {
            // fallback for unknown non-Other discipline
            if ($discLabel === '' && isset($discSuperNames[$rowDiscCode])) {
                $discLabel = $discSuperNames[$rowDiscCode];
            }
        }

        // Code used in certificate number (SQ, SI, RH, …)
        $certDiscCode = 'OG';
        if (isset($certCodeMap[$discLabel])) {
            $certDiscCode = $certCodeMap[$discLabel];
        } elseif (isset($certCodeMap[$skatertype])) {
            $certDiscCode = $certCodeMap[$skatertype];
        }

        // Kerala hard-coded (your original logic)
        $districtSafe = "Kerala";
        $districtSlug = preg_replace('/[^A-Za-z0-9_-]/','_',$districtSafe);
        $logo = '<br/><br/><img src="districtlogos/Kerala.png" class="logoCenter" alt="" onerror="this.style.display=\'none\'">';

        $titleLine = 'in the '.htmlspecialchars($eventTitle,ENT_QUOTES,'UTF-8');
        $heldLine  = ($eventVenue!=='')
            ? 'Held at '.htmlspecialchars($eventVenue,ENT_QUOTES,'UTF-8').' on '.htmlspecialchars($eventDate,ENT_QUOTES,'UTF-8')
            : 'Held on '.htmlspecialchars($eventDate,ENT_QUOTES,'UTF-8');

        // Build signature <img>; if it fails to load we keep the pad height
        $presImg = $districtSlug!=='' ?
          '<img class="sigimg" src="signs/'.$districtSlug.'-president.png" alt="President Signature"
                onerror="this.style.visibility=\'hidden\'">' : '';

        $secImg  = $districtSlug!=='' ?
          '<img class="sigimg" src="signs/'.$districtSlug.'-secretary.png" alt="Secretary Signature"
                onerror="this.style.visibility=\'hidden\'">' : '';

        // Helper to actually append a certificate page + store DB row
        $appendCert = function(
            $certType,      // 'MERIT' or 'PARTICIPATION'
            $discCode,      // 'SQ','SI','RH','IH','AR','IF','IA','ID','SB','RS','RD','OG'
            $discName,      // visible discipline label (Speed-Inline, Roller-Derby, etc.)
            $certNumber,
            $eventInfo      // null OR ['code','label','raw','result']
        ) use (
            &$pages, $bgAttr, $logo, $name, $dobStr, $team, $agHtml, $gender,
            $titleLine, $heldLine, $presImg, $secImg, $president, $secretary,
            $storeStmt, $districtSafe, $appno, $photoTag
        ){
            $certType = 'MERIT';
            $certTitle = ($certType === 'MERIT') ? 'CERTIFICATE OF MERIT' : 'CERTIFICATE OF PARTICIPATION';

            // Lines inside body differ slightly
            $linesHtml =
                '<div class="line">( born on '.$dobStr.' )</div>'.
                '<div class="line">representing _________________________________________</div>'.
                '<div class="line">in '.$agHtml.' '.$gender.' Age Group</div>'.
                '<div class="line">'.$titleLine.'</div>'.
                '<div class="line">'.$heldLine.'</div>';

            $eventsBlock = '';

                   $linesHtml .= '<div class="line">has participated in '.htmlspecialchars($discName,ENT_QUOTES,'UTF-8').' and attained the following ranking.</div>';
                $eventsBlock =
                    '<div class="events">'.
                      '<div class="blk">'.
                       '<table class="ev">'.
                          '<tr>'.
                            '<td>Beginner Quad - Race I&Tab;&Tab;-</td><td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</td>'.
                        
                             '<td>Beginner Inline - Race I&Tab;&Tab;-</td><td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</td>'.
                             '<tr>'.
                                 '<td>Beginner Quad - Race II&Tab;&Tab;-</td><td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</td>'.
                            '<td>Beginner Inline - Race II&Tab;&Tab;-</td><td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</td>'.
                          '</tr>'.
                        '</table><br/>'.
                              '<table class="ev">'.
                          '<tr>'.
                            '<td>Speed Quad - Rink I&Tab;&Tab;-</td><td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</td>'.
                             '<td>Speed Inline - Rink IV&Tab;&Tab;-</td><td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</td>'.
                              '</tr><tr>'.
                              '<td>Speed Quad - Rink II&Tab;&Tab;-</td><td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</td>'.
                              '<td>Speed Inline - Rink V&Tab;&Tab;-</td><td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</td>'.
                               '</tr><tr>'.
                             '<td>Speed Quad - Rink III&Tab;&Tab;-</td><td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</td>'.
                             '<td>Speed Inline - Rink VI&Tab;&Tab;-</td><td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</td>'.
                              '</tr><tr>'.
                       '</table>'.
                      '</div>'.
                    '</div>';


            // if ($certType === 'MERIT' && $eventInfo !== null) {
            //     // For merit, print discipline + single event row with ranking
         
            // } else {
            //     // Pure participation – mention only discipline, no events table
            //     $linesHtml .= '<div class="line">has participated in '.htmlspecialchars($discName,ENT_QUOTES,'UTF-8').' events.</div>';
            //     $eventsBlock = '<div class="events"></div>';
            // }

            $certNoHtml = htmlspecialchars($certNumber,ENT_QUOTES,'UTF-8');
            $pages[] =
              '<div class="certpage"><div class="sheet">'.
                '<img class="pagebg" src="'.$bgAttr.'" alt="" aria-hidden="true">'.
                '<div class="hdr"><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><div class="titleCert">CERTIFICATE</div><b>OF MERIT / PARTICIPATION</b><div class="certno"><br/>Cert. No.: '.$certNoHtml.'</div></div>'.
                '<div class="content"><div class="content-inner">'.
                           '<div class="name">'.strtoupper($name).'</div>'.
                    $linesHtml.
                    $eventsBlock.
                '</div></div>'.
                '<div class="footer"><div class="signs">'.
                  '<div class="sigbox"><div class="sigpad">'.$presImg.'</div><div class="signame">'.htmlspecialchars($president,ENT_QUOTES,'UTF-8').'</div><div class="sigrole"></div></div>'.
                  '<div class="sigbox"><div class="sigpad">'.$secImg .'</div><div class="signame">'.htmlspecialchars($secretary,ENT_QUOTES,'UTF-8').'</div><div class="sigrole">Principal - Carmel CMI Public School</div></div>'.
                '</div></div>'.
              '</div></div>';

            // Store in DB
            if ($storeStmt) {
                $districtDb = $districtSafe;
                $discCodeDb = $discCode;
                $discNameDb = $discName;
                $eventCodeDb  = ($eventInfo !== null) ? $eventInfo['code']   : null;
                $eventLabelDb = ($eventInfo !== null) ? $eventInfo['label']  : null;
                $resultRawDb  = ($eventInfo !== null) ? (string)$eventInfo['raw'] : null;
                $resultLblDb  = ($eventInfo !== null) ? $eventInfo['result'] : null;
                $certTypeDb   = $certType;

                mysqli_stmt_bind_param(
                    $storeStmt,
                    "ssssssssss",
                    $districtDb, $appno, $discCodeDb, $discNameDb,
                    $eventCodeDb, $eventLabelDb, $resultRawDb, $resultLblDb,
                    $certNumber, $certTypeDb
                );
                @mysqli_stmt_execute($storeStmt);
            }
        };

        // --- CERTIFICATE GENERATION LOGIC ---

        if ($anyMeritGlobal) {
            // #1: Individual certificate for EVERY merit, for THIS row's main super-discipline only
            if ($discHasMerit[$rowDiscCode]) {
                foreach ($eventsByDisc[$rowDiscCode]['events'] as $ev) {
                    if (!$ev['isMerit']) continue;

                    $discCode = $certDiscCode; // SQ / SI / RH / ...
                    if (!isset($serialCounters[$discCode])) {
                        $serialCounters[$discCode] = 0;
                    }
                    $serialCounters[$discCode]++;
                    $serial = str_pad($serialCounters[$discCode], 3, '0', STR_PAD_LEFT);
                    $certNumber = $certPrefix.'/'.$appno.'/'.$serial;

                    $appendCert('MERIT', $discCode, $discLabel, $certNumber, $ev);
                }
            }
        } else {
            // #2: Participation-only case – exactly ONE certificate for this skatertype row
            if ($discHasParticipation[$rowDiscCode]) {
                $discCode = $certDiscCode;
                if (!isset($serialCounters[$discCode])) {
                    $serialCounters[$discCode] = 0;
                }
                $serialCounters[$discCode]++;
                $serial = str_pad($serialCounters[$discCode], 3, '0', STR_PAD_LEFT);
                $certNumber = $certPrefix.'/'.$appno.'/'.$serial;

                // No event details passed – discipline-only participation cert
                $appendCert('PARTICIPATION', $discCode, $discLabel, $certNumber, null);
            }
        }
    }

    mysqli_free_result($res);
    if ($storeStmt) mysqli_stmt_close($storeStmt);

    if (empty($pages)) return '<p>No eligible certificate pages (all fully absent or no records).</p>';

    return $css.implode("\n",$pages);
}


// function buildCertificatesHTML(
//     mysqli $con,
//     $repdistrict = 'Kerala',
//     $discipline='',
//     array $onlyAppnos = null,
//     $certPrefix = 'KSRSC2025/',
//     $bgPath = 'certbg.jpg'
// ) {
//     // ---- read championships (by district; no global fallback) ----
//     $eventTitle=''; $eventDate=''; $eventVenue=''; $president=''; $secretary=''; $districtSafe=$repdistrict;

//     $champ = null;
//     if ($repdistrict !== '' && ($st = mysqli_prepare($con, "SELECT championshiptitle, dates, venue, president, secretary, district FROM championships WHERE district=? ORDER BY id DESC LIMIT 1"))) {
//         mysqli_stmt_bind_param($st, "s", $repdistrict);
//         mysqli_stmt_execute($st);
//         mysqli_stmt_store_result($st);
//         $title=''; $dates=''; $venue=''; $pres=''; $sec=''; $dist='';
//         mysqli_stmt_bind_result($st, $title, $dates, $venue, $pres, $sec, $dist);
//         if (mysqli_stmt_fetch($st)) { $champ = array('championshiptitle'=>$title,'dates'=>$dates,'venue'=>$venue,'president'=>$pres,'secretary'=>$sec,'district'=>$dist); }
//         mysqli_stmt_close($st);
//     }
//     if ($champ) {
//         $eventTitle   = isset($champ['championshiptitle']) ? (string)$champ['championshiptitle'] : '';
//         $eventDate    = isset($champ['dates'])             ? (string)$champ['dates']             : '';
//         $eventVenue   = isset($champ['venue'])             ? (string)$champ['venue']             : '';
//         $president    = isset($champ['president'])         ? (string)$champ['president']         : '';
//         $secretary    = isset($champ['secretary'])         ? (string)$champ['secretary']         : '';
//         $districtSafe = isset($champ['district'])          ? (string)$champ['district']          : $repdistrict;
//     }

//     // ---- columns to fetch (ALL disciplines) ----
//     $eventCols = array(
//         // Speed-Quad
//         'rink1','rink2','rink3','road1','road2',
//         // Speed-Inline
//         'rink4','rink5','rink6','rink7','p2p','elim','relay','mixedrelay','road3','road4','road5','p2prd','elimrd','marathon',
//         // Artistic
//         'figure','free','pair','solodance','pairdance','inlinefree','quartet','precisionskating','showgroup',
//         // Hockey
//         'quadhockey','mixedrollerhockey','inlinehockey',
//         // Inline-Freestyle
//         'speedslalom','classicslalom','pairslalom',
//         // Other Games
//         'alpine','downhill','rollerderby','rollerfreestylepark','skateboardingpark','scooterpark','rollerfreestylestreet','skateboardingstreet','scooterstreet'
//     );

//     // NOTE: include age + agorder + skatertype
//     $cols = array_merge(
//         array('appno','sname','dob','age','agegroup','gender','club','clubname','photourl','agorder','skatertype'),
//         $eventCols
//     );
//     $select = '`'.implode('`,`',$cols).'`';

//     $where = "order_status='Success' and status<>'Delete'";
//  //   if ($repdistrict!==''){ $where.=" AND repdistrict='".mysqli_real_escape_string($con,$repdistrict)."'"; }
//     if ($discipline!==''){ $where.=" AND skatertype='".mysqli_real_escape_string($con,$discipline)."'"; }
//     if ($onlyAppnos && count($onlyAppnos)){
//         $ids = array();
//         foreach($onlyAppnos as $a){ $ids[]="'".mysqli_real_escape_string($con,(string)$a)."'"; }
//         $where.=" AND appno IN (".implode(',',$ids).")";
//     }

//     // Sorting remains: team → discipline → agorder → gender → appno
//     $sql = "
//         SELECT $select
//         FROM applications
//         WHERE $where
//         ORDER BY
//           IFNULL(NULLIF(clubname,''), club),
//           FIELD(skatertype,
//             'Speed-Quad','Speed-Inline','Artistic','Roller-Hockey','Inline-Hockey','Inline-Freestyle','Other','Other-Games'
//           ),
//           IFNULL(agorder,999999)+0,
//           gender DESC,
//           CAST(appno AS UNSIGNED), appno
//     ";

//     //echo $sql;
//     $res = mysqli_query($con,$sql);
//     if (!$res) return '<p>Query failed: '.htmlspecialchars(mysqli_error($con),ENT_QUOTES,'UTF-8').'</p>';

//     // ---- helpers ----
//     $resultLabel = function($v){
//         $v = strtoupper(trim((string)$v));
//         if ($v==='1' || $v==='G') return 'FIRST';
//         if ($v==='2'             ) return 'SECOND';
//         if ($v==='3' || $v==='B') return 'THIRD';
//         if ($v==='S'             ) return 'SELECTED';
//         if ($v==='F'             ) return 'NIL';
//         if ($v==='P'             ) return 'PARTICIPATED';
//         if ($v==='A' || $v==='NR') return 'NIL'; // ABSENT treated as NIL for display rows
//         return 'NIL';
//     };
//     $isMerit = function($lbl){ return ($lbl==='FIRST' || $lbl==='SECOND' || $lbl==='THIRD'); };
//     $isPositive = function($lbl){
//         return in_array($lbl, array('FIRST','SECOND','THIRD','PARTICIPATED','SELECTED'), true);
//     };
//     $genderWord = function($g){
//         $g=strtolower(trim((string)$g));
//         if (in_array($g,array('f','female','girl','girls','women','woman'),true)) return 'Girls';
//         if (in_array($g,array('m','male','boy','boys','men','man'),true))         return 'Boys';
//         return ucfirst($g);
//     };

//     // Age compute (fallback to DOB if age missing)
//     $computeAge = function($ageStr, $dobStr, $eventDateStr){
//         $age = (int)$ageStr;
//         if ($age > 0) return $age;
//         $dobTs = strtotime($dobStr);
//         if ($dobTs === false) return 0;
//         $refTs = strtotime($eventDateStr);
//         if ($refTs === false) $refTs = time();
//         $y1 = (int)date('Y',$refTs); $m1=(int)date('n',$refTs); $d1=(int)date('j',$refTs);
//         $y0 = (int)date('Y',$dobTs); $m0=(int)date('n',$dobTs); $d0=(int)date('j',$dobTs);
//         $age = $y1 - $y0;
//         if ($m1 < $m0 || ($m1==$m0 && $d1 < $d0)) $age--;
//         return ($age<0?0:$age);
//     };

//     // Special age-group display by discipline
//     $specialAgeGroup = function($skatertype, $ageYears, $row){
//         $st = trim((string)$skatertype);
//         $age = (int)$ageYears;

//         // Detect per-event participation for Other-Games cases
//         $hasDerby   = isset($row['rollerderby']) && trim($row['rollerderby']) !== '';
//         $hasScooter = isset($row['scooterpark']) && trim($row['scooterpark'])     !== '';

//         if ($st === 'Roller-Hockey' || $st === 'Inline-Hockey') {
//             if ($age >= 6 && $age < 9)  return '6 to 9 Cadet Tiny Tots';
//             if ($age >= 9 && $age < 12) return '9 to 12 Cadet';
//             return null; // fallback to default printed agegroup
//         }

//         // If discipline is "Other"/"Other-Games", check which event is actually present
//         if (($st === 'Other' || $st === 'Other-Games') && $hasDerby) {
//             if ($age >= 12 && $age < 18) return '12 to 18 Junior';
//             return null;
//         }
//         if (($st === 'Other' || $st === 'Other-Games') && $hasScooter) {
//             if ($age >= 12) return 'Above 12';
//             return null;
//         }

//         return null; // no override
//     };

//     // ---- discipline maps (display blocks) ----
//     $quadMap = array(
//         'rink1'=>'RINK - I','rink2'=>'RINK - II','rink3'=>'RINK - III','road1'=>'ROAD - I','road2'=>'ROAD - II'
//     );
//     $inlineMap = array(
//         'p2p'=>'POINTS (TRACK)','elim'=>'ELIMINATION (RINK)',
//         'rink4'=>'RINK - IV','rink5'=>'RINK - V','rink6'=>'RINK - VI','rink7'=>'RINK - VII (Dual TT)',
//         'road3'=>'ROAD - III','road4'=>'ROAD - IV','road5'=>'ROAD - V',
//         'p2prd'=>'POINT TO POINT (ROAD)','elimrd'=>'ELIMINATION (ROAD)','relay'=>'RELAY','mixedrelay'=>'MIXED RELAY','marathon'=>'MARATHON'
//     );
//     $artisticMap = array(
//         'figure'=>'FIGURE','free'=>'FREE','pair'=>'PAIR','solodance'=>'SOLODANCE','pairdance'=>'PAIRDANCE',
//         'inlinefree'=>'INLINE FREE','quartet'=>'QUARTET','precisionskating'=>'PRECISION','showgroup'=>'SHOW GROUP'
//     );
//     $rollerHockeyMap = array(
//         'quadhockey'=>'ROLLER HOCKEY','mixedrollerhockey'=>'MIXED ROLLER HOCKEY'
//     );
//     $inlineHockeyMap = array(
//         'inlinehockey'=>'INLINE HOCKEY'
//     );
//     $freestyleMap = array(
//         'speedslalom'=>'SPEED SLALOM','classicslalom'=>'CLASSIC SLALOM','pairslalom'=>'PAIR SLALOM'
//     );
//     $otherGamesMap = array(
//         'alpine'=>'ALPINE','downhill'=>'DOWNHILL','rollerderby'=>'ROLLER DERBY','rollerfreestylepark'=>'ROLLER FREESTYLE - PARK',
//         'skateboardingpark'=>'SKATEBOARDING - PARK','scooterpark'=>'SCOOTER-PARK','rollerfreestylestreet'=>'ROLLER FREESTYLE - STREET',
//         'skateboardingstreet'=>'SKATEBOARDING - STREET','scooterstreet'=>'SCOOTER-STREET'
//     );

//     $districtSlug = preg_replace('/[^A-Za-z0-9_-]/','_',$districtSafe);
//     $bgAttr = htmlspecialchars($bgPath,ENT_QUOTES,'UTF-8');

//     $css = '<style>
//       :root{
//         --ink:#0b2a6f; --title:#12306e; --accent:#274b9a;
//         --line:#c3d2f2; --sig-bottom:68mm; --hdr-top:10mm; --hdr-bottom:4mm; --logo-max-h:28mm;
//         --photo-size:34mm; --name-size:20pt; --title-size:24pt; --ring:1mm; --corner:4mm;
//         --grad-a:#7a2cff; --grad-b:#ff3aa6; --grad-c:#3a8dff;
//       }
//       *{box-sizing:border-box}
//       @page{ size:A4; margin:0 }
//       html,body{ height:100% }
//       body{ font-family:Arial,Helvetica,sans-serif; color:var(--ink); margin:0; -webkit-print-color-adjust:exact; print-color-adjust:exact; }
//       .certpage{ page-break-after:always } .certpage:last-child{ page-break-after:auto }

//       .sheet{ position:relative; width:210mm; height:297mm; overflow:hidden; display:grid; grid-template-rows:auto 1fr auto; }
//       .pagebg{ position:absolute; inset:0; width:100%; height:100%; object-fit:cover; z-index:-1; }

//       .hdr{ text-align:center; padding:var(--hdr-top) 16mm var(--hdr-bottom) }
//       .logoCenter{ display:block; margin:0 auto 4mm; width:85%; height:auto; max-height:var(--logo-max-h) }
//       .titleCert{ font-size:var(--title-size); font-weight:900; letter-spacing:.4px; margin:0; color:var(--title); text-transform:uppercase }
//       .certno{ font-size:10pt; margin:2px 0 5mm }

//       .content{ display:flex; flex-direction:column; align-items:center; padding:0 16mm; padding-bottom: calc(var(--sig-bottom) + 6mm); }
//       .content-inner{ max-width:138mm; text-align:center; width:100% }
//       .idrow{ display:flex; justify-content:center; margin:4mm 0 }
//       .photoFrame{ width:var(--photo-size); height:var(--photo-size); padding:var(--ring); border-radius:var(--corner);
//                    background:linear-gradient(135deg,var(--grad-a) 0%,var(--grad-b) 45%,var(--grad-c) 100%); box-shadow:0 .8mm 2mm rgba(0,0,0,.12);}
//       .photo{ width:100%; height:100%; border-radius:var(--corner); object-fit:cover; background:#fff; display:block; }
//       .photo.ph{ display:flex; align-items:center; justify-content:center; background:#eef3ff; color:#0b2a6f; font-weight:700; border-radius:var(--corner) }
//       .name{ font-size:var(--name-size); font-weight:900; letter-spacing:.8px; margin:1.6mm 0 2.6mm; text-transform:uppercase }
//       .line{ margin:1.6mm 0 }

//       .events{ display:flex; gap:6mm; justify-content:center; margin-top:4mm; flex-wrap:wrap }
//       .blk{ width:70mm }
//       .blk h4{ margin:0 0 2mm; font-size:11.5pt; text-transform:uppercase; border-bottom:1px solid var(--accent); padding-bottom:2px; color:var(--accent) }
//       table.ev{ width:100%; border-collapse:collapse; font-size:10.5pt }
//       table.ev td{ border-bottom:0.8px dotted var(--line); padding:2.5px 2px }
//       table.ev td:first-child{ text-align:left; width:62% }
//       table.ev td:last-child{ text-align:right; width:38%; font-weight:800 }

//    .footer{ position:absolute; left:16mm; right:16mm; bottom:var(--sig-bottom); z-index:1; }
//   .signs{ display:flex; justify-content:space-between; align-items:flex-end; gap:10mm }
//   .sigbox{
//     width:46%; text-align:center;
//     display:flex; flex-direction:column; align-items:center; justify-content:flex-end;
//   }
//   /* Reserve space for signature scans so layout is identical even if an image is missing */
//   .sigpad{
//     height:16mm;               /* reserved height for the scan */
//     width:100%;
//     display:flex; align-items:flex-end; justify-content:center;
//     margin-bottom:2mm;
//   }
//   .sigimg{
//     max-height:14mm;           /* actual scan size */
//     width:auto; object-fit:contain; display:block;
//   }
//   .signame{ font-weight:800; margin:0 }
//   .sigrole{ margin-top:1.2mm }
//     </style>';

//     $pages = array();

//     $mkRows = function($map,$row,&$hasMerit) use($resultLabel,$isMerit){
//         $h=''; foreach($map as $k=>$label){
//             $v = isset($row[$k]) ? $row[$k] : '';
//             $lbl = $resultLabel($v);
//             if ($lbl==='NIL') continue;
//             if ($isMerit($lbl)) $hasMerit=true;
//             $h.='<tr><td>'.htmlspecialchars($label,ENT_QUOTES,'UTF-8').'</td><td>'.htmlspecialchars($lbl,ENT_QUOTES,'UTF-8').'</td></tr>';
//         } return $h;
//     };

//     while ($r = mysqli_fetch_assoc($res)) {
//         $clubDisplay = ($r['clubname']!=='') ? $r['clubname'] : $r['club'];
//         $dobStr = (!empty($r['dob']) && ($ts=strtotime($r['dob']))) ? date('d-M-Y',$ts) : htmlspecialchars($r['dob'],ENT_QUOTES,'UTF-8');
//         $name   = htmlspecialchars($r['sname'],ENT_QUOTES,'UTF-8');
//         $team   = htmlspecialchars($clubDisplay,ENT_QUOTES,'UTF-8');
//         $agRaw  = isset($r['agegroup']) ? (string)$r['agegroup'] : '';
//         $gender = htmlspecialchars($genderWord($r['gender']),ENT_QUOTES,'UTF-8');
//         $certNo = htmlspecialchars($certPrefix.$r['appno'],ENT_QUOTES,'UTF-8');

//         // photo
//         $photo = trim((string)$r['photourl']);
//         if ($photo!=='' && strpos($photo,'data:image/')!==0) $photo='data:image/png;base64,'.$photo;
//         $photoTag = ($photo!=='')
//           ? '<div class="photoFrame"><img class="photo" src="'.htmlspecialchars($photo,ENT_QUOTES,'UTF-8').'" alt=""></div>'
//           : '<div class="photoFrame"><div class="photo ph">PHOTO</div></div>';

//         // fully-absent check across all events
//         $sawAbsent=false; $sawPositive=false;
//         foreach ($eventCols as $ek) {
//             if (!array_key_exists($ek,$r)) continue;
//             $lbl = $resultLabel($r[$ek]);
//             if ($lbl==='NIL') $sawAbsent = true;
//             if (in_array($lbl, array('FIRST','SECOND','THIRD','PARTICIPATED','SELECTED'), true)) $sawPositive = true;
//         }
//         if (!$sawPositive && $sawAbsent) { continue; }

//         // special age group text by discipline
//         $ageYears = $computeAge(isset($r['age'])?$r['age']:'', isset($r['dob'])?$r['dob']:'', $eventDate);
//         $agOverride = $specialAgeGroup(isset($r['skatertype'])?$r['skatertype']:'', $ageYears, $r);
//         $agDisplay  = ($agOverride !== null && $agOverride !== '') ? $agOverride : $agRaw;
//         $agHtml     = htmlspecialchars($agDisplay, ENT_QUOTES, 'UTF-8');

//         // Build blocks for ALL disciplines (show only present ones)
//         $hasMerit=false; $blocks = '';
//         $quadRows   = $mkRows($quadMap,        $r, $hasMerit);
//         $inlineRows = $mkRows($inlineMap,      $r, $hasMerit);
//         $artRows    = $mkRows($artisticMap,    $r, $hasMerit);
//         $rhRows     = $mkRows($rollerHockeyMap,$r, $hasMerit);
//         $ihRows     = $mkRows($inlineHockeyMap,$r, $hasMerit);
//         $fsRows     = $mkRows($freestyleMap,   $r, $hasMerit);
//         $ogRows     = $mkRows($otherGamesMap,  $r, $hasMerit);

//         if ($quadRows   !== '') $blocks .= '<div class="blk"><h4>Speed-Quad</h4><table class="ev">'.$quadRows.'</table></div>';
//         if ($inlineRows !== '') $blocks .= '<div class="blk"><h4>Speed-Inline</h4><table class="ev">'.$inlineRows.'</table></div>';
//         if ($artRows    !== '') $blocks .= '<div class="blk"><h4>Artistic</h4><table class="ev">'.$artRows.'</table></div>';
//         if ($rhRows     !== '') $blocks .= '<div class="blk"><h4>Roller-Hockey</h4><table class="ev">'.$rhRows.'</table></div>';
//         if ($ihRows     !== '') $blocks .= '<div class="blk"><h4>Inline-Hockey</h4><table class="ev">'.$ihRows.'</table></div>';
//         if ($fsRows     !== '') $blocks .= '<div class="blk"><h4>Inline-Freestyle</h4><table class="ev">'.$fsRows.'</table></div>';
//         if ($ogRows     !== '') $blocks .= '<div class="blk"><h4>Other-Games</h4><table class="ev">'.$ogRows.'</table></div>';

//         if ($blocks==='') {
//             $blocks = '<div class="blk"><h4>Events</h4><table class="ev"><tr><td>—</td><td>NIL</td></tr></table></div>';
//         }

//         $certTitle  = $hasMerit ? 'CERTIFICATE OF MERIT' : 'CERTIFICATE OF PARTICIPATION';
// $districtSafe="Kerala";
//         $districtSlug = preg_replace('/[^A-Za-z0-9_-]/','_',$districtSafe);
//         $logo = '<img src="districtlogos/Kerala.png" class="logoCenter" alt="" onerror="this.style.display=\'none\'">' ;
//         $titleLine = 'in the '.htmlspecialchars($eventTitle,ENT_QUOTES,'UTF-8');
//         $heldLine  = ($eventVenue!=='')
//             ? 'Held at '.htmlspecialchars($eventVenue,ENT_QUOTES,'UTF-8').' on '.htmlspecialchars($eventDate,ENT_QUOTES,'UTF-8')
//             : 'Held on '.htmlspecialchars($eventDate,ENT_QUOTES,'UTF-8');

//       // Build signature <img>; if it fails to load we keep the pad height
// $presImg = $districtSlug!=='' ? 
//   '<img class="sigimg" src="signs/'.$districtSlug.'-president.png" alt="President Signature"
//         onerror="this.style.visibility=\'hidden\'">' : '';

// $secImg  = $districtSlug!=='' ? 
//   '<img class="sigimg" src="signs/'.$districtSlug.'-secretary.png" alt="Secretary Signature"
//         onerror="this.style.visibility=\'hidden\'">' : '';


//     $pages[] =
//   '<div class="certpage"><div class="sheet">'.
//     '<img class="pagebg" src="'.htmlspecialchars($bgPath,ENT_QUOTES,'UTF-8').'" alt="" aria-hidden="true">'.
//     '<div class="hdr">'.$logo.'<div class="titleCert">'.$certTitle.'</div><div class="certno">Cert. No.: '.$certNo.'</div></div>'.
//     '<div class="content"><div class="content-inner">'.
//                  '<div class="idrow">'.$photoTag.'</div>'.
//             '<div class="name">'.strtoupper($name).'</div>'.
//             '<div class="line">( born on '.$dobStr.' )</div>'.
//             '<div class="line">representing '.$team.'</div>'.
//             '<div class="line">in '.$agHtml.' '.$gender.' Age Group</div>'.
//             '<div class="line">'.$titleLine.'</div>'.
//             '<div class="line">'.$heldLine.'</div>'.
//             '<div class="line">has participated and attained the following ranking.</div>'.
//             '<div class="events">'.$blocks.'</div>'.
//     '</div></div>'.
//     '<div class="footer"><div class="signs">'.
//       '<div class="sigbox"><div class="sigpad">'.$presImg.'</div><div class="signame">'.htmlspecialchars($president,ENT_QUOTES,'UTF-8').'</div><div class="sigrole">President</div></div>'.
//       '<div class="sigbox"><div class="sigpad">'.$secImg .'</div><div class="signame">'.htmlspecialchars($secretary,ENT_QUOTES,'UTF-8').'</div><div class="sigrole">Hon. Gen. Secretary</div></div>'.
//     '</div></div>'.
//   '</div></div>';

//     }

//     mysqli_free_result($res);

//     if (empty($pages)) return '<p>No eligible certificate pages (all fully absent or no records).</p>';

//     return $css.implode("\n",$pages);
// }


// function buildCertificateData(mysqli $con, $appno, $repdistrict = null) {
//     // Championships (title, dates, district, president, secretary)
//     $sqlC = "SELECT championshiptitle, dates, district, venue, president, secretary
//              FROM championships
//              WHERE district = ?
//              ORDER BY id DESC LIMIT 1";
//     $stmtC = mysqli_prepare($con, $sqlC);

//     $dist = ($repdistrict !== null) ? $repdistrict : '';
//     mysqli_stmt_bind_param($stmtC, "s", $dist);
//     mysqli_stmt_execute($stmtC);
//     $evt = array('championshiptitle'=>'', 'dates'=>'', 'district'=>$dist, 'venue'=>'', 'president'=>'', 'secretary'=>'');
//     if (function_exists('mysqli_stmt_get_result')) {
//         $res = mysqli_stmt_get_result($stmtC);
//         if ($row = mysqli_fetch_assoc($res)) $evt = $row;
//         if ($res) mysqli_free_result($res);
//     } else {
//         mysqli_stmt_bind_result($stmtC, $evt['championshiptitle'], $evt['dates'], $evt['district'], $evt['venue'], $evt['president'], $evt['secretary']);
//         mysqli_stmt_fetch($stmtC);
//     }
//     mysqli_stmt_close($stmtC);

//     // Skater/application – include ALL event columns
//     $cols = array(
//         'appno','sname','dob','agegroup','gender','club','clubname','photourl',
//         // Speed-Quad
//         'rink1','rink2','rink3','road1','road2',
//         // Speed-Inline
//         'rink4','rink5','rink6','rink7','p2p','elim','relay','mixedrelay','road3','road4','road5','p2prd','elimrd','marathon',
//         // Artistic
//         'figure','free','pair','solodance','pairdance','inlinefree','quartet','precisionskating','showgroup',
//         // Hockey
//         'quadhockey','mixedrollerhockey','inlinehockey',
//         // Freestyle
//         'speedslalom','classicslalom','pairslalom',
//         // Other Games
//         'alpine','downhill','rollerderby','rollerfreestylepark','skateboardingpark','scooterpark','rollerfreestylestreet','skateboardingstreet','scooterstreet'
//     );
//     $select = '`'.implode('`,`',$cols).'`';
//     $sqlA = "SELECT $select FROM applications
//              WHERE appno = ? AND order_status='Success'".
//              " LIMIT 1";
//     $stmtA = mysqli_prepare($con, $sqlA);
//     if ($repdistrict!==null && $repdistrict!=='') {
//         mysqli_stmt_bind_param($stmtA, "ss", $appno, $repdistrict);
//     } else {
//         mysqli_stmt_bind_param($stmtA, "s", $appno);
//     }
//     mysqli_stmt_execute($stmtA);

//     $app = null;
//     if (function_exists('mysqli_stmt_get_result')) {
//         $res = mysqli_stmt_get_result($stmtA);
//         $app = mysqli_fetch_assoc($res);
//         if ($res) mysqli_free_result($res);
//     } else {
//         mysqli_stmt_store_result($stmtA);
//         $meta = mysqli_stmt_result_metadata($stmtA);
//         $fields = array(); $row = array(); $bindRes = array();
//         while ($f = mysqli_fetch_field($meta)) { $fields[] = $f->name; $bindRes[] = &$row[$f->name]; }
//         call_user_func_array('mysqli_stmt_bind_result', array_merge(array($stmtA), $bindRes));
//         if (mysqli_stmt_fetch($stmtA)) { $app = array(); foreach ($fields as $f) $app[$f] = $row[$f]; }
//     }
//     mysqli_stmt_close($stmtA);
//     if (!$app) { return null; }

//     // Helpers
//     // $gsb = function($v){
//     //     $v = strtoupper(trim((string)$v));
//     //     if ($v==='1') return 'G'; if ($v==='2') return 'S'; if ($v==='3') return 'B';
//     //     if (in_array($v, array('G','S','B','P','A'), true)) return $v; // include P/A
//     //     return 'NL';
//     // };

//     $gsb = function($v){
//     $v = strtoupper(trim((string)$v));
//     // Keep known raw codes as-is; avoid mapping 2 -> 'S'
//     if (in_array($v, array('1','2','3','P','A','S','F','G','B'), true)) return $v;
//     return 'NL';
// };


//     $genderWord = function($g){
//         $g = strtolower(trim((string)$g));
//         if (in_array($g, array('f','female','girl','girls','women','woman'), true)) return 'Girls';
//         if (in_array($g, array('m','male','boy','boys','men','man'), true))       return 'Boys';
//         return ucfirst($g);
//     };
//     $clubDisplay = ($app['clubname']!=='') ? $app['clubname'] : $app['club'];

//     // Maps (matching HTML function)
//     $quadMap = array(
//         'rink1'=>'RINK - I', 'rink2'=>'RINK - II', 'rink3'=>'RINK - III',
//         'road1'=>'ROAD - I', 'road2'=>'ROAD - II'
//     );
//     $inlineMap = array(
//         'p2p'=>'POINTS (TRACK)',
//         'elim'=>'ELIMINATION (RINK)',
//         'rink4'=>'RINK - IV', 'rink5'=>'RINK - V', 'rink6'=>'RINK - VI', 'rink7'=>'RINK - VII (Dual TT)',
//         'road3'=>'ROAD - III', 'road4'=>'ROAD - IV', 'road5'=>'ROAD - V',
//         'p2prd'=>'POINT TO POINT (ROAD)', 'elimrd'=>'ELIMINATION (ROAD)',
//         'relay'=>'RELAY', 'mixedrelay'=>'MIXED RELAY', 'marathon'=>'MARATHON'
//     );
//     $artisticMap = array(
//         'figure'=>'FIGURE','free'=>'FREE','pair'=>'PAIR','solodance'=>'SOLO DANCE','pairdance'=>'PAIR DANCE',
//         'inlinefree'=>'INLINE FREE','quartet'=>'QUARTET','precisionskating'=>'PRECISION SKATING','showgroup'=>'SHOW GROUP'
//     );
//     $rollerHockeyMap = array(
//         'quadhockey'=>'ROLLER HOCKEY','mixedrollerhockey'=>'MIXED ROLLER HOCKEY'
//     );
//     $inlineHockeyMap = array(
//         'inlinehockey'=>'INLINE HOCKEY'
//     );
//     $freestyleMap = array(
//         'speedslalom'=>'SPEED SLALOM','classicslalom'=>'CLASSIC SLALOM','pairslalom'=>'PAIR SLALOM'
//     );
//     $otherGamesMap = array(
//         'alpine'=>'ALPINE','downhill'=>'DOWNHILL','rollerderby'=>'ROLLER DERBY','rollerfreestylepark'=>'ROLLER FREESTYLE - PARK',
//         'skateboardingpark'=>'SKATEBOARDING - PARK','scooterpark'=>'SCOOTER - PARK','rollerfreestylestreet'=>'ROLLER FREESTYLE - STREET',
//         'skateboardingstreet'=>'SKATEBOARDING - STREET','scooterstreet'=>'SCOOTER - STREET'
//     );

//     // Build arrays (keep even P/A; drop only NL)
//     $mkArr = function($map) use ($app,$gsb){
//         $out = array();
//         foreach ($map as $k=>$label) {
//             $val = isset($app[$k]) ? $app[$k] : '';
//             $code = $gsb($val);
//             if ($code==='NL') continue;
//             $out[] = array('label'=>$label,'val'=>$code);
//         }
//         return $out;
//     };

//     return array(
//         'event'  => $evt,
//         'skater' => array(
//             'appno'=>$app['appno'],
//             'name'=>$app['sname'],
//             'dob'=>$app['dob'],
//             'agegroup'=>$app['agegroup'],
//             'gender'=>$genderWord($app['gender']),
//             'team'=>$clubDisplay,
//             'photo'=>$app['photourl']
//         ),
//         'quad'         => $mkArr($quadMap),
//         'inline'       => $mkArr($inlineMap),
//         'artistic'     => $mkArr($artisticMap),
//         'rollerhockey' => $mkArr($rollerHockeyMap),
//         'inlinehockey' => $mkArr($inlineHockeyMap),
//         'freestyle'    => $mkArr($freestyleMap),
//         'othergames'   => $mkArr($otherGamesMap)
//     );
// }


function renderPointsProbables(array $groups, $eventTitle, $discipline, $repdistrict = '') {
    $genderLabel = function($g){
        $gl = strtolower(trim((string)$g));
        if (in_array($gl, array('f','female','girl','girls','women','woman'), true)) return 'Girls';
        if (in_array($gl, array('m','male','boy','boys','men','man'), true))       return 'Boys';
        return $g ?: '';
    };
    $initials = function($name){
        $n = trim($name); if ($n==='') return '';
        $parts = preg_split('/\s+/', $n);
        $first = strtoupper(mb_substr($parts[0],0,1,'UTF-8'));
        $last  = isset($parts[count($parts)-1]) ? strtoupper(mb_substr($parts[count($parts)-1],0,1,'UTF-8')) : '';
        return $first.$last;
    };
    $photoSrc = function($raw){
        $raw = trim((string)$raw);
        if ($raw==='') return '';
        if (strpos($raw, 'data:image/') === 0) return $raw;
        return 'data:image/png;base64,'.$raw;
    };

    date_default_timezone_set('Asia/Kolkata');
    $printedOn = 'Printed On : ' . date('d-m-Y h:i:sa');
    $logoSafe  = preg_replace('/[^A-Za-z0-9_-]/', '_', (string)$repdistrict);
    $logoHtml  = $logoSafe!=='' ? "<div class='logo'><img src=\"districtlogos/".htmlspecialchars($logoSafe,ENT_QUOTES,'UTF-8').".png\" style=\"width:75%;height:auto;\" onerror=\"this.style.display='none'\" /></div>" : "";
    $subtitle  = strtoupper(str_replace('-', ' - ', $discipline)).' - POINTS & PROBABLES';

    $css = <<<CSS
<style>
  *{box-sizing:border-box}
  body{font-family:Arial,sans-serif;font-size:12pt;margin:0.6cm}
  table{border-collapse:collapse;width:100%;table-layout:fixed;margin:6px 0 12px}
  th,td{border:1px solid #444;vertical-align:middle;overflow:hidden}
  th{background:#e6e6e6}

  .header{text-align:center;margin-bottom:6px}
  .header .logo{display:none} @media print{.header .logo{display:block;margin:0 auto 6px}}
  .group{margin:8px 0 12px;break-inside:avoid;page-break-inside:avoid}
  .groupTitle{font-weight:bold;margin:4px 0 6px}

  .w-race{width:52px;text-align:center}
  .w-name{width:28%; padding:6px 8px; white-space:normal; word-break:break-word}
  .w-team{width:16%; padding:6px 8px; white-space:normal; word-break:break-word}

  .vcol{width:24px; text-align:center; font-size:11pt}
  .vcol th, .vcol td { padding:3px 2px !important }
  .vhead{writing-mode:vertical-rl; transform:rotate(180deg); white-space:nowrap; line-height:1}

  .w-pts{width:28px; text-align:center; font-size:11pt}
  .w-prob{width:28px; text-align:center; font-size:11pt}
  .w-pts th, .w-prob th, .w-pts td, .w-prob td { padding:3px 2px !important }

  .namewrap{display:inline-flex;align-items:center;gap:6px}
  .avatar{width:18px;height:18px;border-radius:50%;object-fit:cover;display:inline-block}
  .avatar.initials{background:#ddd;color:#555;font-weight:bold;font-size:9px;display:inline-flex;align-items:center;justify-content:center}

  tr.top3{background:#fff59d}        /* selected slots highlight */
  tr.tie{background:#ffe9cc}         /* tie rows (overlay-ish) */
  tr.top3.tie{background:#ffdca8}    /* tie + selected => deeper tone */

  .footer{display:flex;flex-direction:column;color:#000;font-size:11pt;margin-top:10px}
  .sigrow{display:flex;justify-content:space-between}
  .printed{margin-top:4px;font-size:9pt}
</style>
CSS;

    $out = $css;
    $out .= "<div class='header'>".$logoHtml
          . "<center><h3>".htmlspecialchars($eventTitle,ENT_QUOTES,'UTF-8')."</h3></center>"
          . "<center><h5>".htmlspecialchars($subtitle,ENT_QUOTES,'UTF-8')."</h5></center></div>";

    if (empty($groups)) {
        $out .= "<p>No data.</p>";
    } else {
        foreach ($groups as $G) {
            if (empty($G['items'])) continue;
            $ag = $G['agegroup']; $gLbl = $genderLabel($G['gender']);
            $events = $G['eventCols']; $labels = $G['labels'];

            $out .= "<div class='group'>";
            $out .= "<div class='groupTitle'>".htmlspecialchars($ag,ENT_QUOTES,'UTF-8')." - ".htmlspecialchars($gLbl,ENT_QUOTES,'UTF-8')."</div>";

            $out .= "<table><colgroup><col class='w-race'><col class='w-name'><col class='w-team'>";
            foreach ($events as $_) $out .= "<col class='vcol'>";
            $out .= "<col class='w-pts'><col class='w-prob'></colgroup>";

            // header row (vertical labels for event + points/prob)
            $out .= "<thead><tr>"
                  . "<th class='w-race'>Race&nbsp;No</th>"
                  . "<th class='w-name'>Skater Name</th>"
                  . "<th class='w-team'>Team</th>";
            foreach ($events as $ev) {
                $lab = isset($labels[$ev]) ? $labels[$ev] : strtoupper($ev);
                $out .= "<th class='vcol'><div class='vhead'>".htmlspecialchars($lab,ENT_QUOTES,'UTF-8')."</div></th>";
            }
            $out .= "<th class='w-pts'><div class='vhead'>Points</div></th>"
                  . "<th class='w-prob'><div class='vhead'>Probable</div></th>"
                  . "</tr></thead><tbody>";

            foreach ($G['items'] as $r) {
                $rowCls = array();
                if (!empty($r['prob'])) $rowCls[] = 'top3';
                if (!empty($r['is_tie'])) $rowCls[] = 'tie';
                $cls = empty($rowCls)?'':" class='".implode(' ', $rowCls)."'";

                $src = $photoSrc(isset($r['photo']) ? $r['photo'] : '');
                $avatar = $src!=='' 
                    ? '<img class="avatar" src="'.htmlspecialchars($src,ENT_QUOTES,'UTF-8').'" alt="" onerror="this.style.display=\'none\'">'
                    : '<span class="avatar initials">'.htmlspecialchars($initials($r['name']),ENT_QUOTES,'UTF-8').'</span>';

                $out .= "<tr{$cls}>"
                      .   "<td class='w-race'>".htmlspecialchars($r['chno'],ENT_QUOTES,'UTF-8')."</td>"
                      .   "<td class='w-name'><span class='namewrap'>{$avatar}<span>".htmlspecialchars($r['name'],ENT_QUOTES,'UTF-8')."</span></span></td>"
                      .   "<td class='w-team'>".htmlspecialchars($r['team'],ENT_QUOTES,'UTF-8')."</td>";
                foreach ($events as $ev) {
                    $cell = isset($r['per'][$ev]) && $r['per'][$ev] !== '' ? $r['per'][$ev] : '&nbsp;';
                    $out .= "<td class='vcol'>".$cell."</td>";
                }
                $probTxt = '';
                if (!empty($r['prob'])) {
                    $probTxt = $r['prob'];
                    if (!empty($r['is_tie'])) $probTxt .= ' – Tie';
                }
                $out .=   "<td class='w-pts'>".(int)$r['pts']."</td>"
                      .   "<td class='w-prob'>".htmlspecialchars($probTxt,ENT_QUOTES,'UTF-8')."</td>"
                      . "</tr>";
            }

            $out .= "</tbody></table></div>";
        }
    }

    $out .= "<div class='footer'><div class='sigrow'><span>Sign.</span><span>Chief.</span></div>"
          . "<div class='printed'>".htmlspecialchars($printedOn,ENT_QUOTES,'UTF-8')."</div></div>";

    return $out;
}


function buildPointsProbables(mysqli $db, $discipline, $repdistrict = null) {
    // Column labels
    $labels = array(
        'rink1'=>'RINK - I (1 LAP / 200M)','rink2'=>'RINK - II (500+D)','rink3'=>'RINK - III (1000M)',
        'road1'=>'ROAD - I (1 LAP)','road2'=>'ROAD - II (1500/3000M)',
        'rink4'=>'RINK - IV (1 LAP / 200M)','rink5'=>'RINK - V (500+D)','rink6'=>'RINK - VI (1000M)',
        'rink7'=>'RINK - VII Dual TT (200M)',
        'p2p'=>'POINT TO POINT (TRACK) (5000M)','elim'=>'ELIMINATION (RINK) (10000M)',
        'road3'=>'ROAD - III (100M)','road4'=>'ROAD - IV (1 LAP)','road5'=>'ROAD - V (3000M)',
        'p2prd'=>'POINT TO POINT (ROAD) (10000M)','elimrd'=>'ELIMINATION (ROAD) (15000M)',
        'relay'=>'RELAY (3000M)','mixedrelay'=>'MIXED RELAY (4000M)','marathon'=>'MARATHON'
    );

    // Display + scoring columns per discipline
    if ($discipline === 'Speed-Quad') {
        $displayCols = array('rink1','rink2','rink3','road1','road2');
        $pointsCols  = $displayCols;
    } elseif ($discipline === 'Speed-Inline') {
        // Track points/elim BEFORE road
        $displayCols = array('rink4','rink5','rink6','rink7','p2p','elim','road3','road4','road5','p2prd','elimrd','relay','mixedrelay','marathon');
        // No points for relay/mixedrelay/marathon
        $pointsCols  = array('rink4','rink5','rink6','rink7','p2p','elim','road3','road4','road5','p2prd','elimrd');
    } else {
        throw new InvalidArgumentException('Unknown discipline: '.$discipline);
    }

    // Build query
    $selectCols = implode('`,`', $displayCols);
    $sql = "SELECT appno, chno, sname, club, clubname, agegroup, gender,
                   IFNULL(agorder,999999) AS agorder, `$selectCols`, photourl
            FROM applications
            WHERE skatertype = ?
              AND COALESCE(chno,'') <> ''
              AND order_status='Success'";

    $types = 's';
    $vals  = array($discipline);
    if ($repdistrict !== null && $repdistrict !== '') {
        $sql   .= " AND repdistrict = ?";
        $types .= 's';
        $vals[] = $repdistrict;
    }
    $sql .= " ORDER BY IFNULL(agorder,999999), agegroup, gender, CAST(chno AS UNSIGNED), sname";

    $stmt = mysqli_prepare($db, $sql);
    if (!$stmt) { throw new RuntimeException('Prepare failed: '.mysqli_error($db)); }

    $bind = array(&$types); foreach ($vals as $i => $v) { $bind[] = &$vals[$i]; }
    call_user_func_array('mysqli_stmt_bind_param', array_merge(array($stmt), $bind));

    if (!mysqli_stmt_execute($stmt)) {
        throw new RuntimeException('Execute failed: '.mysqli_stmt_error($stmt));
    }

    // Fetch
    $rows = array();
    if (function_exists('mysqli_stmt_get_result')) {
        $res = mysqli_stmt_get_result($stmt);
        if ($res) {
            while ($r = mysqli_fetch_assoc($res)) { $rows[] = $r; }
            mysqli_free_result($res);
        }
    } else {
        mysqli_stmt_store_result($stmt);
        $meta = mysqli_stmt_result_metadata($stmt);
        $fields = array(); $row = array(); $bindRes = array();
        if ($meta) {
            while ($f = mysqli_fetch_field($meta)) {
                $fields[] = $f->name;
                $bindRes[] = &$row[$f->name];
            }
            call_user_func_array('mysqli_stmt_bind_result', array_merge(array($stmt), $bindRes));
            while (mysqli_stmt_fetch($stmt)) {
                $r = array();
                foreach ($fields as $f) { $r[$f] = $row[$f]; }
                $rows[] = $r;
            }
        }
    }
    mysqli_stmt_close($stmt);

    // Helpers
    $toGSB = function($v) {
        $v = strtoupper(trim((string)$v));
        if ($v === '1') return 'G';
        if ($v === '2') return 'S';
        if ($v === '3') return 'B';
        if ($v === 'G' || $v === 'S' || $v === 'B') return $v;
        return ''; // ignore P/A/-
    };
    $pointsFor = function($gsb) {
        return ($gsb==='G') ? 5 : (($gsb==='S') ? 3 : (($gsb==='B') ? 1 : 0));
    };
    $probableSlots = function($discipline, $agegroup) {
        $ag = strtolower((string)$agegroup);
        if ($discipline === 'Speed-Inline' && ($ag==='12 to 15 - sub junior' || $ag==='15 to 18 - junior' || $ag==='above 18 - senior')) return 4; // Sub-Junior Inline
        if (strpos($ag, 'cadet') !== false) return 3; // Cadet
        return 3; // default
    };

    // Group by AgeGroup|Gender
    $groups = array();
    foreach ($rows as $r) {
        $key = $r['agegroup'].'|'.$r['gender'];
        if (!isset($groups[$key])) {
            $groups[$key] = array(
                'agegroup' => $r['agegroup'],
                'gender'   => $r['gender'],
                'agorder'  => (int)$r['agorder'],
                'eventCols'=> $displayCols,
                'labels'   => $labels,
                'items'    => array()
            );
        }
        $team = ($r['clubname'] !== '' ? $r['clubname'] : $r['club']);

        $perEvent = array(); $tot=0; $g=0; $s=0; $b=0;
        foreach ($displayCols as $col) {
            $gsb = isset($r[$col]) ? $toGSB($r[$col]) : '';
            $perEvent[$col] = $gsb;
            if (in_array($col, $pointsCols, true)) {
                $pt = $pointsFor($gsb); $tot += $pt;
                if ($gsb==='G') $g++; elseif ($gsb==='S') $s++; elseif ($gsb==='B') $b++;
            }
        }

        $groups[$key]['items'][] = array(
            'appno' => $r['appno'],
            'chno'  => $r['chno'],
            'name'  => $r['sname'],
            'team'  => $team,
            'per'   => $perEvent,
            'pts'   => $tot,
            'g'     => $g,
            's'     => $s,
            'b'     => $b,
            'photo' => isset($r['photourl']) ? $r['photourl'] : ''
        );
    }

    // Filter pts>0, sort, and assign selection with SLOT CONSUMPTION + ties
    foreach ($groups as &$G) {
        // remove zero-point rows
        $G['items'] = array_values(array_filter($G['items'], function($it){ return (int)$it['pts'] > 0; }));
        if (empty($G['items'])) continue;

        // sort by pts desc, then G/S/B counts, then chno asc, then name
        usort($G['items'], function($a,$b){
            if ($a['pts'] !== $b['pts']) return $b['pts'] - $a['pts'];
            if ($a['g']   !== $b['g'])   return $b['g'] - $a['g'];
            if ($a['s']   !== $b['s'])   return $b['s'] - $a['s'];
            if ($a['b']   !== $b['b'])   return $b['b'] - $a['b'];
            $ac=(int)$a['chno']; $bc=(int)$b['chno']; if ($ac!==$bc) return $ac - $bc;
            return strcasecmp($a['name'],$b['name']);
        });

        // Group indices by DISTINCT points (tie blocks)
        $byPoints = array(); // pts => [rowIndex,...]
        foreach ($G['items'] as $idx => $it) {
            $p = (int)$it['pts'];
            if (!isset($byPoints[$p])) $byPoints[$p] = array();
            $byPoints[$p][] = $idx;
        }
        // Highest points first
        krsort($byPoints, SORT_NUMERIC);

        $slots = $probableSlots($discipline, $G['agegroup']); // e.g., 3 or 4
        $roman = array(1=>'I',2=>'II',3=>'III',4=>'IV',5=>'V');

        $consumed = 0;  // how many skaters taken so far
        $rank     = 0;  // I, II, III... by block
        foreach ($byPoints as $p => $idxs) {
            $rank++;
            $blockSize = count($idxs);
            $selected  = ($consumed < $slots); // if still room, take the whole block (tie at cutoff allowed)

            foreach ($idxs as $i) {
                $G['items'][$i]['rank']   = $rank;
                $G['items'][$i]['is_tie'] = ($blockSize > 1);
                $G['items'][$i]['prob']   = ($selected && isset($roman[$rank])) ? $roman[$rank] : '';
            }
            // ties consume all their spots
            $consumed += $blockSize;
        }
    }
    unset($G);

    // Drop empty groups and order groups
    foreach ($groups as $k=>$G) if (empty($G['items'])) unset($groups[$k]);
    uasort($groups, function($A,$B){
        if ($A['agorder'] !== $B['agorder']) return $A['agorder'] - $B['agorder'];
        if ($A['agegroup'] !== $B['agegroup']) return strcmp($A['agegroup'], $B['agegroup']);
        return strcmp($A['gender'], $B['gender']);
    });

    return array_values($groups);
}


// PHP 5.6+ compatible: no scalar type hints
function consolidateResults($db, $racename, $repdistrict = null) {
    // Whitelist event columns you actually store results in
    $allowed = array(
        'rink1','rink2','rink3','road1','road2','rink4','rink5','rink6','rink7',
        'p2p','elim','relay','mixedrelay','road3','road4','road5','p2prd','elimrd',
        'marathon','figure','free','pair','solodance','pairdance','inlinefree',
        'quartet','precisionskating','showgroup','quadhockey','inlinehockey',
        'mixedrollerhockey','speedslalom','pairslalom','classicslalom','alpine',
        'downhill','rollerderby','rollerfreestylepark','skateboardingpark','scooterpark','rollerfreestylestreet','skateboardingstreet','scooterstreet'
    );
    if (!in_array($racename, $allowed, true)) {
        throw new InvalidArgumentException("Invalid event column: ".$racename);
    }

    // WHERE: medal winners only; chest number NOT required
    $where = "COALESCE(`$racename`, '') IN ('1','2','3')
              AND order_status='Success'";
    $types = '';
    $vals  = array();
    if ($repdistrict !== null && $repdistrict !== '') {
        $where .= " AND repdistrict = ?";
        $types .= 's';
        $vals[] = $repdistrict;
    }

    // Pull medal winners + photourl
    $sql = "
      SELECT
        appno, chno, sname, club, clubname, agegroup, gender,
        IFNULL(agorder, 999999) AS agorder,
        `$racename` AS pos_code,
        photourl
      FROM applications
      WHERE $where
      ORDER BY
        IFNULL(agorder,999999),
        agegroup, gender,
        CAST(`$racename` AS UNSIGNED),
        CAST(NULLIF(chno,'') AS UNSIGNED), chno
    ";

    $stmt = mysqli_prepare($db, $sql);
    if (!$stmt) { throw new RuntimeException('Prepare failed: '.mysqli_error($db)); }
    if ($types !== '') {
        $refs = array(&$types);
        foreach ($vals as $i => $v) { $refs[] = &$vals[$i]; }
        call_user_func_array('mysqli_stmt_bind_param', array_merge(array($stmt), $refs));
    }
    if (!mysqli_stmt_execute($stmt)) {
        throw new RuntimeException('Execute failed: '.mysqli_stmt_error($stmt));
    }

    $rows = array();
    if (function_exists('mysqli_stmt_get_result')) {
        $res = mysqli_stmt_get_result($stmt);
        while ($r = mysqli_fetch_assoc($res)) { $rows[] = $r; }
        if ($res) mysqli_free_result($res);
    } else {
        mysqli_stmt_store_result($stmt);
        mysqli_stmt_bind_result($stmt, $appno, $chno, $sname, $club, $clubname, $agegroup, $gender, $agorder, $pos_code, $photourl);
        while (mysqli_stmt_fetch($stmt)) {
            $rows[] = compact('appno','chno','sname','club','clubname','agegroup','gender','agorder','pos_code','photourl');
        }
    }
    mysqli_stmt_close($stmt);

    // Group + team points
    $groups = array();
    foreach ($rows as $r) {
        $key = $r['agegroup'].'|'.$r['gender'];
        if (!isset($groups[$key])) {
            $groups[$key] = array(
                'agegroup'   => $r['agegroup'],
                'gender'     => $r['gender'],
                'agorder'    => (int)$r['agorder'],
                'items'      => array(),
                'scoreboard' => array()
            );
        }
        $pos   = (string)$r['pos_code']; // 1/2/3
        $team  = ($r['clubname'] !== '' ? $r['clubname'] : $r['club']);
        $pts   = ($pos==='1') ? 5 : (($pos==='2') ? 3 : 1);

        $groups[$key]['items'][] = array(
            'appno' => $r['appno'],
            'chno'  => $r['chno'],       // may be empty now
            'name'  => $r['sname'],
            'team'  => $team,
            'pos'   => $pos,
            'photo' => $r['photourl'],
        );
        if (!isset($groups[$key]['scoreboard'][$team])) { $groups[$key]['scoreboard'][$team] = 0; }
        $groups[$key]['scoreboard'][$team] += $pts;
    }

    foreach ($groups as &$G) {
        usort($G['items'], function($a,$b){
            $pa = (int)$a['pos']; $pb = (int)$b['pos'];
            if ($pa !== $pb) return $pa - $pb;
            // safe compare on chno even if empty/non-numeric
            $ca = (int)$a['chno']; $cb = (int)$b['chno'];
            if ($ca !== $cb) return $ca - $cb;
            return strcasecmp($a['name'], $b['name']);
        });
        $sb = array();
        foreach ($G['scoreboard'] as $team => $p) { $sb[] = array('team'=>$team,'points'=>$p); }
        usort($sb, function($a,$b){
            if ($a['points'] !== $b['points']) return $b['points'] - $a['points'];
            return strcasecmp($a['team'], $b['team']);
        });
        $G['scoreboard'] = $sb;
    } unset($G);

    uasort($groups, function($A,$B){
        if ($A['agorder'] !== $B['agorder']) return $A['agorder'] - $B['agorder'];
        if ($A['agegroup'] !== $B['agegroup']) return strcmp($A['agegroup'], $B['agegroup']);
        return strcmp($A['gender'], $B['gender']);
    });

    return array_values($groups);
}


function renderConsolidatedResults($groups, $eventTitle, $racename, $repdistrict = '') {
    // Helpers
    $mapGender = function($g) {
        $gl = strtolower(trim((string)$g));
        if (in_array($gl, array('f','female','girl','girls','women','woman'), true)) return 'Girls';
        if (in_array($gl, array('m','male','boy','boys','men','man'), true))       return 'Boys';
        return $g ?: '';
    };
    $rowClass = function($pos) {
        if ($pos==='1') return 'res-first';
        if ($pos==='2') return 'res-second';
        if ($pos==='3') return 'res-third';
        return 'res-none';
    };
    $medalIcon = function($pos) {
        if ($pos==='1') return '🥇';
        if ($pos==='2') return '🥈';
        if ($pos==='3') return '🥉';
        return '';
    };
    $initials = function($name){
        $n = trim($name);
        if ($n==='') return '';
        $parts = preg_split('/\s+/', $n);
        $first = strtoupper(mb_substr($parts[0],0,1,'UTF-8'));
        $last  = isset($parts[count($parts)-1]) ? strtoupper(mb_substr($parts[count($parts)-1],0,1,'UTF-8')) : '';
        return $first . $last;
    };
    $photoSrc = function($raw){
        $raw = trim((string)$raw);
        if ($raw==='') return '';
        if (strpos($raw, 'data:image/') === 0) return $raw; // already a data URL
        return 'data:image/png;base64,'. $raw;              // assume base64 PNG blob
    };

    // Build ONE overall team-points table by summing all group scoreboards
    $overallMap = array();
    foreach ($groups as $G) {
        if (empty($G['scoreboard'])) continue;
        foreach ($G['scoreboard'] as $row) {
            $t = (string)$row['team'];
            $p = (int)$row['points'];
            if (!isset($overallMap[$t])) $overallMap[$t] = 0;
            $overallMap[$t] += $p;
        }
    }
    $overall = array();
    foreach ($overallMap as $team=>$pts) $overall[] = array('team'=>$team,'points'=>$pts);
    usort($overall, function($a,$b){
        if ($a['points'] !== $b['points']) return $b['points'] - $a['points'];
        return strcasecmp($a['team'], $b['team']);
    });

    // Header/footer bits
    date_default_timezone_set('Asia/Kolkata');
    $printedOn = 'Printed On : ' . date('d-m-Y h:i:sa');
    $logoSafe = preg_replace('/[^A-Za-z0-9_-]/', '_', (string)$repdistrict);
    $logoHtml = $logoSafe !== ''
        ? "<div class='logo'><img src=\"districtlogos/".htmlspecialchars($logoSafe, ENT_QUOTES, 'UTF-8').".png\" alt=\"\" style=\"width:75%;height:auto;\" onerror=\"this.style.display='none'\" /></div>"
        : "";

    // CSS
    $css = <<<CSS
<style>
  body { font-family: Arial, sans-serif; font-size: 12pt; margin: 0.6cm; }
  h3, h4, h5 { margin: 4px 0; }
  table { border-collapse: collapse; width: 100%; margin: 6px 0 10px; table-layout: fixed; }
  th, td { border: 1px solid #444; padding: 6px 8px; text-align: left; vertical-align: middle; overflow: hidden; }
  th, td { white-space: nowrap; }

  .cell-name { white-space: normal; word-break: break-word; }
  .namewrap { display: inline-flex; align-items: center; gap: 8px; }
  .avatar { width: 28px; height: 28px; border-radius: 50%; object-fit: cover; display: inline-block; vertical-align: middle; }
  .avatar.initials {
    background: #ddd; color: #555; font-weight: bold; font-size: 11px;
    display: inline-flex; align-items: center; justify-content: center;
  }
  .cell-team { text-overflow: ellipsis; }

  /* Results table column widths (no Timing) */
  .r-col-app{width:14%}.r-col-chno{width:12%}.r-col-name{width:42%}.r-col-team{width:22%}.r-col-pos{width:10%;text-align:center}

  .header  { text-align: center; margin-bottom: 6px; }
  .header .logo { display: none; }  /* hide logo on screen */
  @media print { .header .logo { display: block; margin: 0 auto 6px; } }

  .group { margin: 10px 0 12px; break-inside: avoid; page-break-inside: avoid; }
  .group h4 { margin: 2px 0 6px; }

  .footer { display: flex; flex-direction: column; color: #000; font-size: 11pt; margin-top: 10px; }
  .sigrow { display: flex; justify-content: space-between; }
  .printed { margin-top: 4px; font-size: 9pt; }

  /* Row colors for positions */
  tr.res-first{background:#fff3c4}
  tr.res-second{background:#eceff4}
  tr.res-third{background:#f6e0d5}
  tr.res-none{background:#fff}
  tr.res-first td:first-child{border-left:4px solid #ffd700}
  tr.res-second td:first-child{border-left:4px solid #c0c0c0}
  tr.res-third td:first-child{border-left:4px solid #cd7f32}

  .medal{font-size:12pt}

  /* Overall scoreboard */
  .scoreboard { width: 60%; margin: 12px auto 6px; }
  .scoreboard th, .scoreboard td { text-align: left; }
  .scoreboard th.rank, .scoreboard td.rank { width: 12%; text-align: center; }
  .scoreboard th.points, .scoreboard td.points { width: 20%; text-align: right; }

  @media print {
    table, .group { break-inside: avoid; page-break-inside: avoid; }
  }
</style>
CSS;

    $out = $css;

    // One header
    $out .= "<div class='header'>"
          .   $logoHtml
          .   "<center><h3>".htmlspecialchars($eventTitle, ENT_QUOTES, 'UTF-8')."</h3></center>"
          .   "<center><h5>".htmlspecialchars(strtoupper($racename), ENT_QUOTES, 'UTF-8')." RESULTS</h5></center>"
          . "</div>";

    // All age-group results
    if (empty($groups)) {
        $out .= "<p>No medal results found.</p>";
    } else {
        foreach ($groups as $G) {
            $ag   = $G['agegroup'];
            $gLbl = $mapGender($G['gender']);

            $out .= "<div class='group'>\n";
            $out .= "  <h4>Age Group : ".htmlspecialchars($ag, ENT_QUOTES, 'UTF-8')
                  .  " - ".htmlspecialchars($gLbl, ENT_QUOTES, 'UTF-8')."</h4>\n";
            $out .= "  <table>\n";
            $out .= "    <colgroup><col class='r-col-app'><col class='r-col-chno'><col class='r-col-name'><col class='r-col-team'><col class='r-col-pos'></colgroup>\n";
            $out .= "    <thead><tr><th>Appno</th><th>Race No</th><th>Name</th><th>Team</th><th>Position</th></tr></thead>\n";
            $out .= "    <tbody>\n";

            foreach ($G['items'] as $r) {
                $cls   = $rowClass($r['pos']);
                $icon  = $medalIcon($r['pos']);
                $src   = $photoSrc($r['photo']);
                if ($src !== '') {
                    $avatar = '<img class="avatar" src="'.htmlspecialchars($src, ENT_QUOTES, 'UTF-8').'" alt="Photo of '.htmlspecialchars($r['name'], ENT_QUOTES, 'UTF-8').'" onerror="this.style.display=\'none\'">';
                } else {
                    $avatar = '<span class="avatar initials">'.htmlspecialchars($initials($r['name']), ENT_QUOTES, 'UTF-8').'</span>';
                }

                $out .= "      <tr class='{$cls}'>"
                      . "        <td>".htmlspecialchars($r['appno'], ENT_QUOTES, 'UTF-8')."</td>"
                      . "        <td>".htmlspecialchars($r['chno'], ENT_QUOTES, 'UTF-8')."</td>"
                      . "        <td class='cell-name'><span class='namewrap'>{$avatar}<span class='medal'>{$icon}</span><span>".htmlspecialchars($r['name'], ENT_QUOTES, 'UTF-8')."</span></span></td>"
                      . "        <td class='cell-team' title=\"".htmlspecialchars($r['team'], ENT_QUOTES, 'UTF-8')."\">".htmlspecialchars($r['team'], ENT_QUOTES, 'UTF-8')."</td>"
                      . "        <td class='r-col-pos'>".htmlspecialchars($r['pos'], ENT_QUOTES, 'UTF-8')."</td>"
                      . "      </tr>\n";
            }

            $out .= "    </tbody>\n";
            $out .= "  </table>\n";
            $out .= "</div>\n";
        }
    }

    // Overall Team Points (moved BELOW results)
    if (!empty($overall)) {
        $out .= "<h4 style='text-align:center;margin-top:8px;'>Team Points (Overall) &nbsp; <small>(5/3/1)</small></h4>";
        $out .= "<table class='scoreboard'>"
              .   "<thead><tr><th class='rank'>Rank</th><th>Team</th><th class='points'>Points</th></tr></thead><tbody>";
        $rank = 1;
        foreach ($overall as $row) {
            $out .= "<tr>"
                  .   "<td class='rank'>".$rank++."</td>"
                  .   "<td>".htmlspecialchars($row['team'], ENT_QUOTES, 'UTF-8')."</td>"
                  .   "<td class='points'>".(int)$row['points']."</td>"
                  . "</tr>";
        }
        $out .= "</tbody></table>";
    } else {
        $out .= "<p style='text-align:center;margin:8px 0;'>No medal results found for team points.</p>";
    }

    // Footer
    $out .= "<div class='footer'>"
          .   "<div class='sigrow'><span>Sign.</span><span>Chief.</span></div>"
          .   "<div class='printed'>".htmlspecialchars($printedOn, ENT_QUOTES, 'UTF-8')."</div>"
          . "</div>";

    return $out;
}
function scoresheet($db, $event, $maxPerHeat, $repdistrict = null) {
    // allowed event columns
    $allowed = [
        'u8race1q','u8race2q','u8race1i','u8race2i',
        'rink1','rink2','rink3','road1','road2','rink4','rink5','rink6','rink7',
        'p2p','elim','relay','mixedrelay','road3','road4','road5','p2prd','elimrd','marathon',
        'figure','free','pair','solodance','pairdance','inlinefree','quartet','precisionskating','showgroup',
        'quadhockey','inlinehockey','mixedrollerhockey',
        'speedslalom','pairslalom','classicslalom','alpine','downhill','rollerderby','rollerfreestylepark','skateboardingpark','scooterpark','rollerfreestylestreet','skateboardingstreet','scooterstreet'
    ];
    if (!in_array($event, $allowed, true)) {
        throw new InvalidArgumentException("Invalid event column: ".$event);
    }
    $W = (int)$maxPerHeat;
    if ($W <= 0) throw new InvalidArgumentException("maxPerHeat must be > 0");

    // events that REQUIRE chest number
    $requiresChnoSet = [
        'u8race1q','u8race2q','u8race1i','u8race2i',
        'rink1','rink2','rink3','rink4','rink5','rink6','rink7',
        'road1','road2','road3','road4','road5',
        'p2p','elim','relay','mixedrelay','p2prd','elimrd','marathon'
    ];
    $requiresChno = in_array($event, $requiresChnoSet, true);

    // WHERE
    $where = "COALESCE($event, '') <> '' AND $event NOT IN ('0','No')";
    if ($requiresChno) {
        $where .= " AND COALESCE(chno, '') <> ''";
    }
    $where .= " AND order_status = 'Success'";

    $bindTypes = '';
    $bindVals  = [];
    // if ($repdistrict !== null && $repdistrict !== '') {
    //     $where     .= " AND repstate = ?";
    //     $bindTypes .= 's';
    //     $bindVals[] = $repdistrict;
    // }

    // Fetch rows (include event column as result_code)
    $sql = "
        SELECT
            appno, chno, sname, club, clubname, repdistrict,
            skaterid, dob, age, agegroup, gender,
            IFNULL(agorder, 999999) AS agorder,
            `$event` AS result_code
        FROM applications
        WHERE $where
        ORDER BY
            IFNULL(agorder, 999999),
            agegroup, gender,
            CAST(chno AS UNSIGNED), chno
    ";
    $stmt = mysqli_prepare($db, $sql);
    if (!$stmt) throw new RuntimeException('Prepare failed: '.mysqli_error($db));
    if ($bindTypes !== '') {
        $refs = [ &$bindTypes ];
        foreach ($bindVals as $i => $v) { $refs[] = &$bindVals[$i]; }
        call_user_func_array('mysqli_stmt_bind_param', array_merge([$stmt], $refs));
    }
    if (!mysqli_stmt_execute($stmt)) {
        throw new RuntimeException('Execute failed: '.mysqli_stmt_error($stmt));
    }

    $base = [];
    if (function_exists('mysqli_stmt_get_result')) {
        $res = mysqli_stmt_get_result($stmt);
        while ($row = mysqli_fetch_assoc($res)) $base[] = $row;
        if ($res) mysqli_free_result($res);
    } else {
        mysqli_stmt_store_result($stmt);
        mysqli_stmt_bind_result(
            $stmt, $appno, $chno, $sname, $club, $clubname, $repdistrictOut,
            $skaterid, $dob, $age, $agegroup, $gender, $agorder, $result_code
        );
        while (mysqli_stmt_fetch($stmt)) {
            $base[] = compact(
                'appno','chno','sname','club','clubname','repdistrictOut',
                'skaterid','dob','age','agegroup','gender','agorder','result_code'
            );
        }
    }
    mysqli_stmt_close($stmt);

    // ---------- Apply discipline-specific age-group overrides BEFORE grouping ----------
    // Hockey: quadhockey/inlinehockey
    //   <9  => "6 to 9 - Cadet Tiny Tots", agorder_print=1
    //   9–<12 => "9 to 12 - Cadet",        agorder_print=2
    // Roller Derby: rollerderby
    //   12–<18 => "12 to 18 Junior",       agorder_print=1
    $transformed = [];
    $isHockey = in_array($event, ['quadhockey','inlinehockey'], true);
    $isDerby  = ($event === 'rollerderby');

    foreach ($base as $r) {
        $displayAg  = $r['agegroup'];
        $displayOrd = (int)$r['agorder'];
        $ageInt     = (int)$r['age'];

        if ($isHockey) {
            if ($ageInt < 9) {
                $displayAg  = '6 to 9 - Cadet Tiny Tots';
                $displayOrd = 1;
            } elseif ($ageInt >= 9 && $ageInt < 12) {
                $displayAg  = '9 to 12 - Cadet';
                $displayOrd = 2;
            }
        } elseif ($isDerby) {
            if ($ageInt >= 12 && $ageInt < 18) {
                $displayAg  = '12 to 18 Junior';
                $displayOrd = 1;
            }
        }

        // carry through overridden values for grouping & print
        $r['agegroup_print'] = $displayAg;
        $r['agorder_print']  = $displayOrd;
        $transformed[] = $r;
    }

    // Group and serpentine assign using OVERRIDDEN agegroup/agorder
    $out = [];
    $currKey = null; $group = [];

    $flushGroup = function() use (&$out, &$group, $W) {
        $n = count($group); if ($n === 0) return;
        $H = (int)ceil($n / $W);
        $assigned = [];
        for ($i = 0; $i < $n; $i++) {
            $col  = intdiv($i, $H);
            $row  = $i % $H;
            $heat = ($col % 2 === 0) ? ($row + 1) : ($H - $row);
            $lane = $col + 1;
            $r = $group[$i];

            $assigned[] = [
                'agegroup'     => isset($r['agegroup_print']) ? $r['agegroup_print'] : $r['agegroup'],
                'gender'       => $r['gender'],
                'heat_no'      => $heat,
                'lane_no'      => $lane,
                'appno'        => $r['appno'],
                'chno'         => $r['chno'],
                'sname'        => $r['sname'],
                'club'         => $r['club'],
                'clubname'     => $r['clubname'],
                'repdistrict'  => isset($r['repdistrictOut']) ? $r['repdistrictOut'] : $r['repdistrict'],
                'skaterid'     => $r['skaterid'],
                'dob'          => $r['dob'],
                'age'          => $r['age'],
                'result_code'  => isset($r['result_code']) ? $r['result_code'] : '',
            ];
        }
        usort($assigned, function($a, $b){
            if ($a['heat_no'] === $b['heat_no']) return $a['lane_no'] <=> $b['lane_no'];
            return $a['heat_no'] <=> $b['heat_no'];
        });
        foreach ($assigned as $row) $out[] = $row;
        $group = [];
    };

    // sort first by overridden agorder/agegroup/gender/chno, then walk & flush
    usort($transformed, function($a,$b){
        $ao = (int)$a['agorder_print']; $bo = (int)$b['agorder_print'];
        if ($ao !== $bo) return $ao <=> $bo;
        $agc = strcmp($a['agegroup_print'], $b['agegroup_print']);
        if ($agc !== 0) return $agc;
        $gd = strcmp($b['gender'], $a['gender']); // DESC
        if ($gd !== 0) return $gd;
        // then by ch.no
        $ac = (int)$a['chno']; $bc = (int)$b['chno'];
        if ($ac !== $bc) return $ac <=> $bc;
        return strcmp($a['chno'], $b['chno']);
    });

    foreach ($transformed as $row) {
        $key = $row['agegroup_print'].'|'.$row['gender'].'|'.$row['agorder_print'];
        if ($currKey !== null && $key !== $currKey) { $flushGroup(); }
        $group[] = $row; $currKey = $key;
    }
    $flushGroup();

    return $out;
}



function renderScoresheet( array $rows, mysqli $con, $raceTitle = 'Start List', $racename = '', $repdistrict = '', $eventTitle='' ) {

    if (!$rows) return "<p>No entries.</p>";

    $eventCol     = (string)$racename;
    $safeEventCol = htmlspecialchars($eventCol, ENT_QUOTES, 'UTF-8');

    // events that REQUIRE chest number (used to decide whether to show the column)
    $requiresChnoSet = array_flip([
        'rink1','rink2','rink3','rink4','rink5','rink6','rink7',
        'road1','road2','road3','road4','road5',
        'p2p','elim','relay','mixedrelay','p2prd','elimrd','marathon'
    ]);
    $requiresChno = isset($requiresChnoSet[$eventCol]);

    // Gender label
    $mapGender = function($g) {
        $gl = strtolower(trim((string)$g));
        if (in_array($gl, ['f','female','girl','girls','women','woman'], true)) return 'Girls';
        if (in_array($gl, ['m','male','boy','boys','men','man'], true))       return 'Boys';
        return $g ?: '';
    };

    // Position text (now includes S & F)
    $mapPos = function($code) {
        $c = strtoupper(trim((string)$code));
        if ($c === '1') return 'First';
        if ($c === '2') return 'Second';
        if ($c === '3') return 'Third';
        if ($c === 'S') return 'Selected';
        if ($c === 'F') return 'Forward';
        if ($c === 'P') return 'Participated';
        if ($c === 'A') return 'Absent';
        return 'Not Reported';
    };

    // Row CSS class
    $mapRowClass = function($code) {
        $c = strtoupper(trim((string)$code));
        if ($c === '1') return 'res-first';
        if ($c === '2') return 'res-second';
        if ($c === '3') return 'res-third';
        if ($c === 'S') return 'res-selected';
        if ($c === 'F') return 'res-forward';
        if ($c === 'P') return 'res-participated';
        if ($c === 'A') return 'res-absent';
        return 'res-none';
    };

    // IST timestamp
    date_default_timezone_set('Asia/Kolkata');
    $printedOn = 'Printed On : ' . date('d-m-Y h:i:sa');

    // Print-only header logo
    $logoSafe = preg_replace('/[^A-Za-z0-9_-]/', '_', (string)$repdistrict);
    $logoHtml = $logoSafe !== ''
        ? "<div class='logo'><img src=\"districtlogos/".htmlspecialchars($logoSafe, ENT_QUOTES, 'UTF-8').".png\" alt=\"\" style=\"width:75%;height:auto;\" onerror=\"this.style.display='none'\" /></div>"
        : "";

    $css = <<<CSS
<style>
  body { font-family: Arial, sans-serif; font-size: 12pt; }
  h2, h3, h4, h5 { margin: 6px 0; }
  table { border-collapse: collapse; width: 100%; margin: 8px 0 14px; table-layout: fixed; }
  th, td { border: 1px solid #444; padding: 6px 8px; text-align: left; vertical-align: top; overflow: hidden; }
  th, td { white-space: nowrap; }
  .cell-name, .cell-remarks { white-space: normal; word-break: break-word; }
  .cell-club { text-overflow: ellipsis; }
  .cell-chno { font-weight: bold; }
  th.th-chno { font-weight: bold; }

  /* Column widths when Ch.No. is present */
  .col-lane    { width: 8%;  }
  .col-chno    { width: 12%; }
  .col-name    { width: 30%; }
  .col-club    { width: 22%; }
  .col-remarks { width: 12%; }
  .col-pos     { width: 10%; }
  .col-result  { width: 16%; } /* screen only */

  /* Alternate widths when Ch.No. is hidden */
  .no-chno .col-lane   { width: 9%; }
  .no-chno .col-name   { width: 36%; }
  .no-chno .col-club   { width: 27%; }
  .no-chno .col-remarks{ width: 13%; }
  .no-chno .col-pos    { width: 15%; }
  .no-chno .col-result { width: 18%; }

  .page { page-break-after: always; min-height: 96vh; display: flex; flex-direction: column; margin-bottom: 16px; }
  @media print { .page { page-break-after: always; } }

  .header  { text-align: center; margin-bottom: 6px; }
  .header .logo { display: none; }
  @media print { .header .logo { display: block; margin: 0 auto 6px; } }

  .content { flex: 1 1 auto; }
  .heatTitle { margin: 4px 0; font-size: 11.5pt; }

  .footer { display: flex; flex-direction: column; color: #000; font-size: 11pt; margin-top: 12px; }
  .sigrow { display: flex; justify-content: space-between; }
  .printed { margin-top: 4px; font-size: 9pt; }

  .btns { display: flex; gap: 4px; flex-wrap: wrap; }
  .res-btn { font-size: 10pt; padding: 2px 6px; cursor: pointer; border: 1px solid #666; background: #f6f6f6; }
  .res-btn.gold   { background: #ffd700; }
  .res-btn.silver { background: #c0c0c0; }
  .res-btn.bronze { background: #cd7f32; color: #fff; border-color: #a15b23; }
  .res-btn.sel    { background: #e3f2fd; }     /* Selected */
  .res-btn.fwd    { background: #ede7f6; }     /* Forward  */
  .res-btn.chosen { box-shadow: inset 0 0 0 2px #000; }

  @media print {
    /* Hide live controls; keep Position column structure */
    .td-pos { color: transparent; }
    .col-result, td.col-result, th.col-result, .btns, .res-btn { display: none !important; }
  }

  /* Row colors */
  tr.res-first         { background-color: #fff3c4; }
  tr.res-second        { background-color: #eceff4; }
  tr.res-third         { background-color: #f6e0d5; }
  tr.res-selected      { background-color: #e8f3ff; } /* light blue */
  tr.res-forward       { background-color: #f0eaff; } /* light purple */
  tr.res-participated  { background-color: #fff; }
  tr.res-absent        { background-color: #fdecea; }
  tr.res-none          { background-color: #ffffff; }

  tr.res-first td:first-child        { border-left: 4px solid #ffd700; }
  tr.res-second td:first-child       { border-left: 4px solid #c0c0c0; }
  tr.res-third td:first-child        { border-left: 4px solid #cd7f32; }
  tr.res-selected td:first-child     { border-left: 4px solid #1976d2; }
  tr.res-forward td:first-child      { border-left: 4px solid #7e57c2; }
  tr.res-participated td:first-child { border-left: 4px solid #2e7d32; }
  tr.res-absent td:first-child       { border-left: 4px solid #c62828; }
</style>
CSS;

    $out = $css;

    $currKey  = null;
    $currHeat = null;
    $openTable = false;
    $openPage  = false;

    foreach ($rows as $r) {
        $ag   = $r['agegroup'];
        $gRaw = $r['gender'];
        $gLbl = $mapGender($gRaw);
        $heat = (int)$r['heat_no'];
        $key  = $ag . '|' . $gRaw;

        $codeRaw = isset($r['result_code']) ? $r['result_code'] : (isset($r[$eventCol]) ? $r[$eventCol] : '');
        $ucCode  = strtoupper(trim((string)$codeRaw));
        $posText = $mapPos($ucCode);
        $rowCls  = $mapRowClass($ucCode);

        // New page (agegroup, gender)
        if ($currKey !== $key) {
            if ($openTable) { $out .= "</tbody></table>\n"; $openTable = false; }
            if ($openPage)  {
                $out .= "</div><!-- .content -->\n";
                $out .= "<div class='footer'>"
                      .   "<div class='sigrow'><span>Sign.</span><span>Chief.</span></div>"
                      .   "<div class='printed'>".htmlspecialchars($printedOn, ENT_QUOTES, 'UTF-8')."</div>"
                      . "</div>\n";
                $out .= "</div><!-- .page -->\n";
                $openPage = false;
            }

            $currKey  = $key;
            $currHeat = null;

            $pageCls = $requiresChno ? '' : ' no-chno';
            $out .= "<div class='page{$pageCls}' data-event=\"{$safeEventCol}\">\n";
            $out .= "<div class='header'>"
                  . $logoHtml
                  . "<center><h3>".htmlspecialchars($eventTitle, ENT_QUOTES, 'UTF-8')."</h3></center>"
                  . "<center><h5>".htmlspecialchars($raceTitle, ENT_QUOTES, 'UTF-8')." - RACE CHART</h5></center>"
                  . "</div>\n";
            $out .= "<div class='content'>\n";
            $out .= "<h3>".htmlspecialchars($ag, ENT_QUOTES, 'UTF-8')." - ".htmlspecialchars($gLbl, ENT_QUOTES, 'UTF-8')."</h3>\n";
            $openPage = true;
        }

        // Heat table
        if ($currHeat !== $heat) {
            if ($openTable) { $out .= "</tbody></table>\n"; }
            $currHeat = $heat;

            // Build header with/without Ch.No.
            if ($requiresChno) {
                $out .= "<div class='heatTitle'>Heat {$heat}</div>\n";
                $out .= "<table>"
                      . "<colgroup>"
                      . "<col class='col-lane'><col class='col-chno'><col class='col-name'>"
                      . "<col class='col-club'><col class='col-remarks'><col class='col-pos'><col class='col-result'>"
                      . "</colgroup>"
                      . "<thead><tr>"
                      . "<th>Lane</th><th class='th-chno'>Ch.No.</th><th>Name</th>"
                      . "<th>Team</th><th>Timing/Remarks</th><th class='th-pos'>Position</th><th class='col-result'>Result</th>"
                      . "</tr></thead><tbody>\n";
            } else {
                $out .= "<div class='heatTitle'>Heat {$heat}</div>\n";
                $out .= "<table>"
                      . "<colgroup>"
                      . "<col class='col-lane'><col class='col-name'><col class='col-club'>"
                      . "<col class='col-remarks'><col class='col-pos'><col class='col-result'>"
                      . "</colgroup>"
                      . "<thead><tr>"
                      . "<th>Lane</th><th>Name</th><th>Team</th>"
                      . "<th>Timing/Remarks</th><th class='th-pos'>Position</th><th class='col-result'>Result</th>"
                      . "</tr></thead><tbody>\n";
            }
            $openTable = true;
        }

        $team = ($r['clubname'] !== '' ? $r['clubname'] : $r['club']);
        $appnoAttr = (int)$r['appno'];

        // Preselect buttons
        $sel1 = ($ucCode === '1') ? ' chosen' : '';
        $sel2 = ($ucCode === '2') ? ' chosen' : '';
        $sel3 = ($ucCode === '3') ? ' chosen' : '';
        $selS = ($ucCode === 'S') ? ' chosen' : '';
        $selF = ($ucCode === 'F') ? ' chosen' : '';
        $selP = ($ucCode === 'P') ? ' chosen' : '';
        $selA = ($ucCode === 'A') ? ' chosen' : '';

        $out .= "<tr class=\"{$rowCls}\" data-appno=\"{$appnoAttr}\">"
              . "<td>".(int)$r['lane_no']."</td>";
        if ($requiresChno) {
            $out .= "<td class='cell-chno'>".htmlspecialchars($r['chno'], ENT_QUOTES, 'UTF-8')."</td>";
        }
        $out .= "<td class='cell-name'>".htmlspecialchars($r['sname'], ENT_QUOTES, 'UTF-8')."</td>"
              . "<td class='cell-club' title=\"".htmlspecialchars($team, ENT_QUOTES, 'UTF-8')."\">".htmlspecialchars($team, ENT_QUOTES, 'UTF-8')."</td>"
              . "<td class='cell-remarks'></td>"
              . "<td class='td-pos'>".htmlspecialchars($posText, ENT_QUOTES, 'UTF-8')."</td>"
              . "<td class='col-result'>"
              .   "<div class='btns'>"
              .     "<button type='button' class='res-btn gold{$sel1}'   data-code='1' data-event='{$safeEventCol}'>Gold</button>"
              .     "<button type='button' class='res-btn silver{$sel2}' data-code='2' data-event='{$safeEventCol}'>Silver</button>"
              .     "<button type='button' class='res-btn bronze{$sel3}' data-code='3' data-event='{$safeEventCol}'>Bronze</button>"
              .     "<button type='button' class='res-btn sel{$selS}'    data-code='S' data-event='{$safeEventCol}'>Selected</button>"
              .     "<button type='button' class='res-btn fwd{$selF}'    data-code='F' data-event='{$safeEventCol}'>Forward</button>"
              .     "<button type='button' class='res-btn{$selP}'        data-code='P' data-event='{$safeEventCol}'>Participated</button>"
              .     "<button type='button' class='res-btn{$selA}'        data-code='A' data-event='{$safeEventCol}'>Absent</button>"
              .   "</div>"
              . "</td>"
              . "</tr>\n";
    }

    if ($openTable) { $out .= "</tbody></table>\n"; }
    if ($openPage)  {
        $out .= "</div><!-- .content -->\n";
        $out .= "<div class='footer'>"
              .   "<div class='sigrow'><span>Sign.</span><span>Chief.</span></div>"
              .   "<div class='printed'>".htmlspecialchars($printedOn, ENT_QUOTES, 'UTF-8')."</div>"
              . "</div>\n";
        $out .= "</div><!-- .page -->\n";
    }

    // JS: update Position + row color + selection state
    $out .= <<<JS
<script>
(function(){
  function labelFor(code){
    switch(String(code).toUpperCase()){
      case '1': return 'First';
      case '2': return 'Second';
      case '3': return 'Third';
      case 'S': return 'Selected';
      case 'F': return 'Forward';
      case 'P': return 'Participated';
      case 'A': return 'Absent';
      default:  return 'Not Reported';
    }
  }
  function classFor(code){
    switch(String(code).toUpperCase()){
      case '1': return 'res-first';
      case '2': return 'res-second';
      case '3': return 'res-third';
      case 'S': return 'res-selected';
      case 'F': return 'res-forward';
      case 'P': return 'res-participated';
      case 'A': return 'res-absent';
      default:  return 'res-none';
    }
  }
  function clearResClasses(tr){
    ['res-first','res-second','res-third','res-selected','res-forward','res-participated','res-absent','res-none']
      .forEach(function(c){ tr.classList.remove(c); });
  }

  document.addEventListener('click', function(e){
    var t = e.target;
    if(!t.classList.contains('res-btn')) return;
    var tr = t.closest('tr');
    if(!tr) return;
    var appno = tr.getAttribute('data-appno');
    var code  = t.getAttribute('data-code');
    var page = t.closest('.page');
    var eventCol = (t.getAttribute('data-event') || (page && page.getAttribute('data-event')) || '');
    if(!eventCol){ alert('Missing event column.'); return; }

    var cell = t.closest('td');
    cell.querySelectorAll('button').forEach(function(b){ b.disabled = true; });

    var body = 'appno=' + encodeURIComponent(appno) +
               '&event=' + encodeURIComponent(eventCol) +
               '&code='  + encodeURIComponent(code);

    fetch('update_result.php', {
      method: 'POST',
      headers: {'Content-Type':'application/x-www-form-urlencoded; charset=UTF-8'},
      body: body,
      cache: 'no-store'
    }).then(function(r){ return r.json(); })
      .then(function(j){
        cell.querySelectorAll('button').forEach(function(b){ b.disabled = false; b.classList.remove('chosen'); });
        if(j && j.ok){
          t.classList.add('chosen');
          var posCell = tr.querySelector('.td-pos');
          if (posCell) posCell.textContent = labelFor(code);
          clearResClasses(tr);
          tr.classList.add(classFor(code));
        }else{
          alert('Update failed' + (j && j.error ? ': ' + j.error : '.'));
        }
      }).catch(function(){
        cell.querySelectorAll('button').forEach(function(b){ b.disabled = false; });
        alert('Network error. Please retry.');
      });
  });
})();
</script>
JS;

    return $out;
}

function assignchestnoKL(mysqli $con, $district, $seq)
{
    if($district=="")
{
    $district=$_SESSION['teamf'];
}

    // $sjrnos = trim(file_get_contents('sjrchno.txt'));

    // Kerala District Prefix Mapping
    $prefixMap = [
        "Alappuzha"        => "AL",
        "Ernakulam"        => "ER",
        "Idukki"           => "ID",
        "Kannur"           => "KN",
        "Kasaragod"        => "KS",
        "Kollam"           => "KM",
        "Kottayam"         => "KT",
        "Kozhikode"        => "KZ",
        "Malappuram"       => "MP",
        "Palakkad"         => "PK",
        "Pathanamthitta"   => "PT",
        "Thiruvananthapuram"=> "TV",
        "Thrissur"         => "TR",
        "Wayanad"          => "WY"
    ];

     if (!array_key_exists($district, $prefixMap)) {
        echo "1District Not Found".$district;
        exit();
    }

    $prefixx = $prefixMap[$district];

    // Validate sequence
    if ($seq === "" || $seq === null) {
        echo "Seq Wrong";
        exit();
    }

    $sql = 'SELECT appno, club, skatertype
            FROM applications
            WHERE status != "Delete"
              AND (skatertype LIKE "Speed%%")
              AND (chno = "" OR chno IS NULL)
              AND (club = ?)
            ORDER BY club, skatertype DESC,
                     CONVERT(agorder, UNSIGNED INTEGER),
                     gender DESC,
                     CONVERT(appno, UNSIGNED INTEGER)';

    $stmt = mysqli_prepare($con, $sql);
    mysqli_stmt_bind_param($stmt, "s", $district);
    mysqli_stmt_execute($stmt);
    mysqli_stmt_store_result($stmt);

    mysqli_stmt_bind_result($stmt, $appno, $club, $skatertype);

    $teamchno = (int)$seq;

    while (mysqli_stmt_fetch($stmt)) {
        $teamchno++;
        $chno = str_pad($teamchno, 2, '0', STR_PAD_LEFT);
        $finalChno = $prefixx . $chno;

        $updateq = 'UPDATE applications 
                    SET chno = ? 
                    WHERE appno = ? 
                      AND (chno = "" OR chno IS NULL)';
        $stmt2 = mysqli_prepare($con, $updateq);
        mysqli_stmt_bind_param($stmt2, "si", $finalChno, $appno);
        mysqli_stmt_execute($stmt2);

        echo $finalChno . " " . $appno . " " . mysqli_stmt_affected_rows($stmt2) . "<br/>";
    }

    mysqli_stmt_close($stmt);
    // $myfile1 = fopen("sjrchno.txt", "w") or die("Unable to open file!");
    // fwrite($myfile1, $sjrnos);
    // fclose($myfile1);
}


function assignchestnoTN(mysqli $con, $district, $seq)
{
    // $sjrnos = trim(file_get_contents('sjrchno.txt'));
    if($district=="")
{
    $district=$_SESSION['teamf'];
}
    // Tamil Nadu District Prefix Mapping
    $prefixMap = [
        "Ariyalur"        => "AR",
        "Chennai"         => "CH",
        "Coimbatore"      => "CB",
        "Cuddalore"       => "CU",
        "Dharmapuri"      => "DP",
        "Dindigul"        => "DG",
        "Erode"           => "ER",
        "Kanchipuram"     => "KC",
        "Kanniyakumari"   => "KK",
        "Karur"           => "KR",
        "Krishnagiri"     => "KG",
        "Madurai"         => "MD",
        "Nagapattinam"    => "NG",
        "Namakkal"        => "NM",
        "Perambalur"      => "PB",
        "Pudukkottai"     => "PK",
        "Ramanathapuram"  => "RP",
        "Salem"           => "SL",
        "Sivaganga"       => "SV",
        "Thanjavur"       => "TJ",
        "The Nilgiris"    => "NI",
        "Theni"           => "TI",
        "Thiruvallur"     => "TR",
        "Thiruvarur"      => "TV",
        "Tiruchirappalli" => "TP",
        "Tirunelveli"     => "TL",
        "Tiruppur"        => "TU",
        "Tiruvannamalai"  => "TA",
        "Tuticorin"       => "TT",
        "Vellore"         => "VE",
        "Villupuram"      => "VI",
        "Virudhunagar"    => "VN"
    ];

    if (!array_key_exists($district, $prefixMap)) {
        echo "District Not Found";
        exit();
    }

    $prefixx = $prefixMap[$district];

    // Validate sequence
    if ($seq === "" || $seq === null) {
        echo "Seq Wrong";
        exit();
    }

    $sql = 'SELECT appno, club, skatertype
            FROM applications
            WHERE status != "Delete"
              AND (skatertype LIKE "Speed%%")
              AND (chno = "" OR chno IS NULL)
              AND (club = ?)
            ORDER BY club, skatertype DESC,
                     CONVERT(agorder, UNSIGNED INTEGER),
                     gender DESC,
                     CONVERT(appno, UNSIGNED INTEGER)';

    $stmt = mysqli_prepare($con, $sql);
    mysqli_stmt_bind_param($stmt, "s", $district);
    mysqli_stmt_execute($stmt);
    mysqli_stmt_store_result($stmt);

    mysqli_stmt_bind_result($stmt, $appno, $club, $skatertype);

    $teamchno = (int)$seq;

    while (mysqli_stmt_fetch($stmt)) {
        $teamchno++;
        $chno = str_pad($teamchno, 2, '0', STR_PAD_LEFT);
        $finalChno = $prefixx . $chno;

        $updateq = 'UPDATE applications 
                    SET chno = ? 
                    WHERE appno = ? 
                      AND (chno = "" OR chno IS NULL)';
        $stmt2 = mysqli_prepare($con, $updateq);
        mysqli_stmt_bind_param($stmt2, "si", $finalChno, $appno);
        mysqli_stmt_execute($stmt2);

        echo $finalChno . " " . $appno . " " . mysqli_stmt_affected_rows($stmt2) . "<br/>";
    }

    mysqli_stmt_close($stmt);

    // // update file
    // file_put_contents("sjrchno.txt", $sjrnos);
}


function assignchestno()
{
include('dbconnect.php');
set_time_limit (1200);
	/*$databaseQuery = 'UPDATE applications AS t
JOIN
(
    SELECT @rownum:=@rownum+1 rownum,appno,club,skatertype,CONVERT(agorder,UNSIGNED INTEGER),gender,CONVERT(appno,UNSIGNED INTEGER) 
    FROM applications
    CROSS JOIN (select @rownum := 0) rn
  where status != "delete" AND skatertype LIKE "Speed%%" order by club,skatertype,CONVERT(agorder,UNSIGNED INTEGER),gender desc,CONVERT(appno,UNSIGNED INTEGER) 
) AS r ON t.appno = r.appno
SET t.skaterid =r.rownum';*/
$dt=$_SESSION['teamf'];

$dbqs='SELECT @rownum:=@rownum+1 rownum,appno,club,skatertype,CONVERT(agorder,UNSIGNED INTEGER),gender,CONVERT(appno,UNSIGNED INTEGER) 
    FROM applications
    CROSS JOIN (select @rownum := 100) rn
  where repdistrict="'.$dt.'" AND status != "Delete" AND status != "Rejected" AND (ordeQuadus="Success") AND ((skatertype LIKE "Speed%%") OR (skatertype LIKE "Tenacity")) order by club,skatertype desc,CONVERT(agorder,UNSIGNED INTEGER),gender desc,CONVERT(appno,UNSIGNED INTEGER) ';
  
  $selectresult = mysqli_query($con,$dbqs) or die('Query failed: ' . mysqli_error());
 // echo $dbqs;
  while($row = mysqli_fetch_array($selectresult))
  {
	  $chno=$row['rownum'];
	  $appno=$row['appno'];
	  
	  $updateq ='update applications set chno='.$chno.' where appno='.$appno.' and (chno="" or chno is NULL)';

	$updateresult = mysqli_query($con,$updateq) or die('Query failed: ' . mysqli_error());
	echo $chno." ".$appno." ".$con -> affected_rows."<br/>";
	  
  }


echo mysqli_num_rows($selectresult);

	

}

function sendform($appno)
{


    include('dbconnect.php');

    $databaseQuery = 'SELECT appno, sname, email, hashcode FROM applications WHERE appno = "' . mysqli_real_escape_string($con, $appno) . '"';
    $result = mysqli_query($con, $databaseQuery) or die('Query failed - Send Form: ' . mysqli_error($con));

    if ($result && $row = mysqli_fetch_array($result)) {
        $appno = $row["appno"];
        $sname = $row["sname"];
        $email = $row["email"];
        $key   = $row["hashcode"];

        $content = '<html><body><b>Dear Skater '.$sname.',<br/><br/></b><br/>
Your registration is complete.<br/><br/>

You can download your <b>TAMILNADU DISTRICT CHAMPIONSHIPS – 2025 - Entry Form </b> in the following link.<br/>

<a href="https://tamilnaduskate.com/tndistricts2025/application.php?appno='.$appno.'&k='.$key.'">Click Here to Print / Download Application Form</a>
<br/></b><br/>
Please contact your District / State Unit for further details and approval.
Thanks & Regards<br/><br/>
TNRSA<br/>
tamilnaduskate.com
</body></html>';

        $mail = new PHPMailer(true);
        try {
            // SMTP settings
            $mail->isSMTP();
            $mail->Host       = 'mail.tamilnaduskate.com';
            $mail->SMTPAuth   = true;
            $mail->Username   = 'office@tamilnaduskate.com';
            $mail->Password   = 'priority1@1';
            $mail->SMTPSecure = ''; // no encryption
            $mail->Port       = 25;

            // $mail->SMTPDebug = 2; // optional debug
            // $mail->Debugoutput = 'html';

            // Recipients
            $mail->setFrom('office@tamilnaduskate.com', 'TNRSA');
            $mail->addAddress($email, $sname);
         //   $mail->addBCC('jeganonly@gmail.com');

            // Content
            $mail->isHTML(true);
            $mail->Subject = $sname." |Entry Form ".$appno." | TAMILNADU DISTRICT CHAMPIONSHIPS - 2025";
            $mail->Body    = $content;

            $mail->send();
            $mailres = "Success";
        } catch (Exception $e) {
            $mailres = "Mailer Error: " . $mail->ErrorInfo;
        }

        $qtext = 'UPDATE applications SET emailstatus="' . mysqli_real_escape_string($con, $mailres) . '" WHERE appno = "' . $appno . '"';
        mysqli_query($con, $qtext);
    }
}

function sendformold($appno)
{
include('dbconnect.php');
$databaseQuery = 'SELECT appno,sname,email,hashcode FROM applications where (appno= "'.$appno.'")';
$result = mysqli_query($con,$databaseQuery) or die('Query failed: ' . mysqli_error());
if($result)
{

	$row = mysqli_fetch_array($result);

$appno=$row["appno"];
$sname=$row["sname"];
$email=$row["email"];
$key=$row["hashcode"];

$content='<html><body><b>Dear Skater '.$sname.',<br/><br/></b><br/>
Your registration is complete.<br/><br/>

You can download your <b>TAMILNADU DISTRICT CHAMPIONSHIPS – 2025 - Entry Form </b> in the following link.<br/>

<a href="https://tamilnaduskate.com/tndistricts2025/application.php?appno='.$appno.'&k='.$key.'">Click Here to Print / Download Application Form</a>
<br/></b><br/>
Please contact your District / State Unit for further details and approval.
Thanks & Regards<br/><br/>
TNRSA<br/>
tamilnaduskate.com
</body></html>';


//$to = "jeganonly@gmail.com,krishnamani_k@yahoo.com,vishnuamalraj@yahoo.com";
$to =$email;
//$to =$email.",jeganonly@gmail.com";
//$to ="jeganonly@gmail.com";
$subject = $sname." |Entry Form ".$appno." | TAMILNADU DISTRICT CHAMPIONSHIPS – 2025";

$headers = "MIME-Version: 1.0" . "\r\n";
$headers .= "Content-type:text/html;charset=UTF-8" . "\r\n";
$headers .= "From: office@tamilnaduskate.com" . "\r\n" ;
//$headers .= "Bcc: jeganonly@gmail.com"; //disable later

$mailres=mail($to,$subject,$content,$headers);


$qtext='UPDATE applications SET emailstatus="'.$mailres.'" WHERE appno = "'.$appno.'"';
	//	echo $qtext;
		 mysqli_query($con,$qtext) or mysqli_error();
			

			

}



}


function listskaterbase()
{

	include('dbconnect.php');
	
	$dt=$_SESSION['username'];
	if($dt=="secretary")
	{
		$dt=$_SESSION['teamf'];
	//	$dt="Chennai";
	}
	//$qtext='SELECT appno, sname, dob, agegroup, gender, club from skaterbase_'.strtolower($_SESSION['username']).' where status != "delete"';

	$qtext='SELECT appno, sname, dob, agegroup, gender, clubname as club from tdrsc2021 where status != "delete"';

	//where clubname="'.strtolower($_SESSION['username']).'" AND

//	echo $qtext;
$result3 = mysqli_query($con,$qtext) or die('Query failed: ' . mysqli_error());
				while($row = mysqli_fetch_array($result3))
  {
	  
	    $appno=trim($row["appno"]);
 $sname=trim($row["sname"]);
$dob=trim($row["dob"]);
$ag=trim($row["agegroup"])." ".trim($row["gender"]);
$club=trim($row["club"]);
//$photo="http://".$_SERVER[HTTP_HOST]."/oldpics/".trim($row["Photo"]);
$gender=trim($row["gender"]);
echo '<li><a href="#" onclick="loadprof(\''.$appno.'\');">'.$sname." | ".$dob." | ".$club.' </a></li>';

  }
}

function listentries($stypesel,$teamfilter=NULL,$del=NULL)
{
    include('dbconnect.php');

    $delstatus = "";
    if ($del=="hidedelete") {
        $delstatus='AND status != "delete" ';
    }

    $stype = $stypesel;
    $dt = "";
    $club = $_SESSION["username"];

    if ($club=="secretary") {
        $team = 
        $dt = "%";
        $team=$teamfilter;
    } else {
        if ($club=="") { loginbox(); return; }
        $team = $club;
    }

    $usertype = $_SESSION["usertype"];
    if ($usertype=="District") {
        $team=$teamfilter;
        if($team=="All Entries"){ $team = "%"; }
        $dt   = $_SESSION["currentdistrict"];
        if($dt==""){
            $_SESSION["currentdistrict"]=$dt;
            $dt=$_SESSION["username"];
        }
    } else if ($usertype=="Club") {
        $team = $_SESSION["username"];
        $dt   = $_SESSION["currentdistrict"];
    }
    if($team=="All Entries"){ $team = "%"; }

    if ($stype!="Other") {
        $databaseQuery = 'SELECT * FROM applications
                          WHERE (skatertype like "%'.$stype.'%")
                            and (club like "%'.$con->real_escape_string($team).'%")
                            and (repstate like "%'.$con->real_escape_string($dt).'%")
                            '.$delstatus.' AND (order_status="Success")
                          ORDER BY agorder+0,gender desc,skatertype,club,CONVERT(appno,UNSIGNED INTEGER)';
    } else {
        $databaseQuery = 'SELECT * FROM applications
                          WHERE (otherdiscipline <> "")
                            and (club like "%'.$con->real_escape_string($team).'%")
                            and (repstate like "%'.$con->real_escape_string($dt).'%")
                            '.$delstatus.' AND (order_status="Success")
                          ORDER BY skatertype,agorder+0,gender desc,club,CONVERT(appno,UNSIGNED INTEGER)';
    }

    $result3 = mysqli_query($con,$databaseQuery) or die('Query failed: ' . mysqli_error($con));
    date_default_timezone_set('Asia/Kolkata');

    echo '<p class="font2"> ' .mysqli_num_rows($result3) . ' Results found for "'.$dt."-".$team.'-'.$stype.'" as on '.date("d-m-Y h:i:sa").' </p>';
    echo '<title>'.$team.'-'.$stype.'</title>';

    if ($_SESSION['usertype']=="Club") {
        echo '<a href="print.php?stype='.$stype.'" target="_blank" class="noprint ui-btn ui-btn-raised  ui-btn ui-btn-inline waves-effect waves-button waves-effect waves-button" ><i class="zmdi zmdi-print zmd-2x"></i> Print Entry Form</a>';
    } else if($_SESSION['username']=="secretary" || $_SESSION['usertype']=="District") {
        echo '<a href="print-list.php?stype='.$stype.'" target="_blank" class="noprint ui-btn ui-btn-raised  ui-btn ui-btn-inline waves-effect waves-button waves-effect waves-button" ><i class="zmdi zmdi-print zmd-2x"></i> Print List</a>';
    }

    echo '<table id="listtable" data-role="table" data-mode="columntoggle" style="overflow-x: auto; width:90%;"    class="ui-responsive table-stroke">';
    echo '<thead>';

    if ($stype=="all") {
        echo '<tr class="th-groups" >
            <th colspan="4" data-priority="1" style="height:auto !important; text-align:center;">Skater Details</th>
            <th colspan="2" data-priority="5" style="height:auto !important; text-align:center;" >DOB & Age</th>
            <th colspan="2" data-priority="2" style="height:auto !important; text-align:center;">Age Group</th>
            <th colspan="1" data-priority="6" style="height:auto !important; text-align:center;">Representing Team</th>
            <th colspan="2" data-priority="1" style="height:auto !important; text-align:center;">Tenacity</th>
            <th colspan="2" data-priority="1" style="height:auto !important; text-align:center;">Under 5 Quad</th>
            <th colspan="2" data-priority="1" style="height:auto !important; text-align:center;">Under 5 Inline</th>
            <th colspan="4" data-priority="1" style="height:auto !important; text-align:center;">Quad Events</th>
            <th colspan="10" data-priority="1" style="height:auto !important; text-align:center;">Inline Events</th>
            <th colspan="1" data-priority="4" style="height:auto !important; text-align:center;">Comments</th>
        </tr>';
    }

    echo '<tr>
        <th><div class="verticalText">Sl.No.</div></th>';

    if ($stype=="Speed-Quad"|| $stype=="Speed-Inline" || $stype=="Tenacity" || $stype=="Beginner-Quad" || $stype=="Beginner-Inline") {
        echo '<th><div>Race No.</div></th>';
    }

    echo '<th><div class="verticalText">AppNo</div></th>
        <th><div>Status</div></th>
        <th><div>RSFI App.no.</div></th>
        <th ><div style=" width:120px;">Skater Name</div></th>
        <th><div>Date_of_Birth</div></th>
        <th><div>Age</div></th>
        <th><div>AgeGroup</div></th>
        <th><div>Gender</div></th>
        <th><div>Representing Team</div></th>';

    if ($_SESSION['username']=="secretary" || $_SESSION['usertype']=="District" || $_SESSION['usertype']=="Club") {
        echo '<th class="noprint"><div class="noprint">Edit</div></th>';
    }
    echo '<th class="noprint"><div class="noprint">Delete</div></th>';

    if ($stype=="Tenacity" || $stype=="all") {
        echo '<th><div class="verticalText">Race 1</div></th>
              <th><div class="verticalText">Race 2</div></th>';
    }
    if ($stype=="Beginner-Quad" || $stype=="all") {
        echo '<th><div class="verticalText">Under 5- Quad Race 1</div></th>
              <th><div class="verticalText">Under 5-Quad Race 2</div></th>';
    }
    if ($stype=="Beginner-Inline" || $stype=="all") {
        echo '<th><div class="verticalText">Under 5- Inline Race 1</div></th>
              <th><div class="verticalText">Under 5- Inline Race 2</div></th>';
    }
    if ($stype=="Speed-Quad"|| $stype=="all") {
        echo '<th><div class="verticalText">Rink - I<br/>(1 Lap  [200M])</div></th>
              <th><div class="verticalText">Rink - II<br/>(2 Lap / 500+D)</div></th>
              <th><div class="verticalText">Rink - III<br/>(3 Lap / 4 Lap / 1000 M)</div></th>
              <th><div class="verticalText">Road - I<br/>(1 Lap)</div></th>
              <th><div class="verticalText">Road - II<br/>(1500 / 3000 M)</div></th>';
    }
    if ($stype=="Speed-Inline"|| $stype=="all") {
        echo '<th><div class="verticalText">Rink - IV<br/>(1 Lap [200M])</div></th>
              <th><div class="verticalText">Rink - V<br/>(500+D)</div></th>
              <th><div class="verticalText">Rink - VI<br/>(1000 M)</div></th>
              <th><div class="verticalText">Rink - VII<br/>DUAL TT(200 M)</div></th>
              <th><div class="verticalText">Points Track (5000 M)</div></th>
              <th><div class="verticalText">Elimination - Rink (10000 M)</div></th>
              <th><div class="verticalText">Road - III (100 M)</div></th>
              <th><div class="verticalText">Road - IV (1 Lap)</div></th>
              <th><div class="verticalText">Road - V (3000 M)</div></th>
              <th><div class="verticalText">Point to Point - Road (10000 M)</div></th>
              <th><div class="verticalText">Elimination - Road (15000 M)</div></th>
              <th><div class="verticalText">Relay (3000M)</div></th>
              <th><div class="verticalText">Mixed Relay (4000M)</div></th>';
    }
    if ($stype=="Artistic") {
        echo '<th><div class="verticalText">Figure</div></th>
              <th><div class="verticalText">Free</div></th>
              <th><div class="verticalText">Pair</div></th>
              <th><div class="verticalText">Partner Name</div></th>
              <th><div class="verticalText">Solodance</div></th>
              <th><div class="verticalText">Coupledance</div></th>
              <th><div class="verticalText">Partner Name</div></th>
              <th><div class="verticalText">Inlinefree</div></th>
              <th><div class="verticalText">Quartet</div></th>
              <th><div class="verticalText">ShowGroup</div></th>
              <th><div class="verticalText">Precision</div></th>';
    }
    if ($stype=="Roller-Hockey") {
        echo '<th><div class="verticalText">Roller Hockey</div></th>
              <th><div class="verticalText">Roller Hockey - Mixed</div></th>
              <th><div class="verticalText">Role</div></th>
              <th><div class="verticalText">Jersey No.</div></th>';
    }
    if ($stype=="Inline-Hockey") {
        echo '<th><div class="verticalText">Inline Hockey</div></th>
              <th><div class="verticalText">Role</div></th>
              <th><div class="verticalText">Jersey No.</div></th>';
    }
    if ($stype=="Inline-Freestyle") {
        echo '<th><div class="verticalText">Classic Slalom</div></th>
              <th><div class="verticalText">Speed Slalom</div></th>
              <th><div class="verticalText">Pair Slalom</div></th>';
    }
    if ($stype=="Other") {
        echo '<th><div class="verticalText">Main Discipline</div></th>
              <th><div class="verticalText">Other Discipline</div></th>
              <th><div class="verticalText">Alpine</div></th>
              <th><div class="verticalText">Downhill</div></th>
              <th><div class="verticalText">Roller Derby</div></th>
              <th><div class="verticalText">Roller Freestyle - Park</div></th>
              <th><div class="verticalText">Roller Freestyle - Street</div></th>
              <th><div class="verticalText">Skateboarding - Park</div></th>
                <th><div class="verticalText">Skateboarding - Street</div></th>
              <th><div class="verticalText">Scooter - Park</div></th>
              <th><div class="verticalText">Scooter - Street</div></th>
              ';
    }
    echo '<th><div class="verticalText">Comments</div></th>';
    echo '</tr></thead>';

    // ---------- Collect rows, then apply hockey overrides and sort ----------
    $rows = [];
    while($row = mysqli_fetch_assoc($result3)) { $rows[] = $row; }

    // apply override (agegroup + agorder) for Roller/Inline Hockey BEFORE sorting/grouping
    foreach ($rows as &$r) {
        $r['agegroup_print'] = $r['agegroup'];
        $r['agorder_print']  = (int)$r['agorder'];
        if ($r['skatertype'] === 'Roller-Hockey' || $r['skatertype'] === 'Inline-Hockey') {
            $a = (int)$r['age'];
            if ($a < 9)               { $r['agegroup_print'] = '6 to 9 - Cadet Tiny Tots'; $r['agorder_print'] = 1; }
            elseif ($a >=9 && $a<12 ) { $r['agegroup_print'] = '9 to 12 - Cadet';         $r['agorder_print'] = 2; }
        }
    }
    unset($r);

    // sort by NEW agorder/agegroup, then gender desc, skatertype, club, appno
    usort($rows, function($a,$b){
        $ao = (int)$a['agorder_print']; $bo = (int)$b['agorder_print'];
        if ($ao !== $bo) return $ao <=> $bo;
        $agc = strcmp($a['agegroup_print'], $b['agegroup_print']);
        if ($agc !== 0) return $agc;
        // gender desc
        $gd = strcmp($b['gender'], $a['gender']);
        if ($gd !== 0) return $gd;
        $st = strcmp($a['skatertype'],$b['skatertype']);
        if ($st !== 0) return $st;
        $cl = strcmp($a['club'],$b['club']);
        if ($cl !== 0) return $cl;
        $ai = (int)$a['appno']; $bi = (int)$b['appno'];
        if ($ai !== $bi) return $ai <=> $bi;
        return strcmp($a['appno'],$b['appno']);
    });

    // ---------- Render ----------
    $twocol=0;  $itcount=0;
    $curag=""; $curgender=""; $curteam="";

    $rink1cnt=0; $rink2cnt=0; $road1cnt=0; $road2cnt=0; $quadskaterscnt=0;
    $rink3cnt=0; $rink4cnt=0; $rink5cnt=0; $rink6cnt=0; $rink7cnt=0;
    $road3cnt=0; $road4cnt=0; $road5cnt=0; $p2pcnt=0; $rinkelimcnt=0; $p2prdcnt=0;
    $roadelimcnt=0; $relaycnt=0; $mixedrelaycnt=0; $inlineskaterscnt=0;
    $rollerhockeycnt=0; $inlinehockeycnt=0;

    echo '<tbody>';
    $slno=0;

    // helper: normalize event result to 1/2/3/P/A/S/F/-
    $normalize = function($v){
        $c = strtoupper(trim((string)$v));
        return in_array($c, ['1','2','3','P','A','S','F']) ? $c : '-';
    };

    foreach ($rows as $row) {
        $status = trim($row["status"]);
        $slno++;

        $appno   = trim($row["appno"]);
        $sname   = trim($row["sname"]);
        $hashcode= trim($row["hashcode"]);
        $discipline = trim($row["skatertype"]);
        $otherdiscipline = trim($row["otherdiscipline"]);
        if ($otherdiscipline=='on') { $otherdiscipline="Yes"; }

        if ($discipline=="Speed-Quad")  { $quadskaterscnt++; }
        if ($discipline=="Speed-Inline"){ $inlineskaterscnt++; }

        $skaterid= trim($row["skaterid"]);
        $chno    = trim($row["chno"]);
        $dob     = trim($row["dob"]);
        $age     = trim($row["age"]);

        // use overridden group for header/grouping
        $ag      = $row['agegroup_print'];

        if ($discipline=="Roller-Hockey") { $rollerhockeycnt++; }
        if ($discipline=="Inline-Hockey"){ $inlinehockeycnt++; }

        $gender   = trim($row["gender"]);
        $club     = trim($row["club"]);
        $clubname = trim($row["clubname"]);
        $school   = trim($row["school"]);

        $residingstate   = trim($row["residingstate"]);
        $residingdistrict= trim($row["residingdistrict"]);
        $repstate        = trim($row["repstate"]);
        $repdistrict     = trim($row["repdistrict"]);
        $fathername      = trim($row["fathername"]);
        $address         = trim($row["address"]);
        $address2        = trim($row["address2"]);
        $city            = trim($row["city"]);
        $pin             = trim($row["pin"]);
        $phone           = trim($row["phone"]);
        $email           = trim($row["email"]);
        $blood           = trim($row["bloodgroup"]);
        $comments        = trim($row["comments"]);
        $payref          = trim($row["payref"]);
        $paystatus       = trim($row["paystatus"]);

        $nodob = "";
        $doburl= trim($row["doburl"]);
        if ($doburl=='NA') { $nodob="true"; }
        $pwd = trim($row["aadhaarpass"]);

        $position = trim($row["hockeyplayertype"]);
        $jerseyno = trim($row["jerseyno"]);

        // ---- RESULT-CODE aware mapping + counters (1/2/3/P/S/F/A/-)
        $setAndCount = function($raw, &$cnt) use ($normalize, $status){
            $code = $normalize($raw);
            if ($status!="Delete" && in_array($code, ['1','2','3','P','S','F'])) { $cnt++; }
            return $code;
        };

        $adjrink1 = $normalize($row["adjrink1"]);
        $adjrink2 = $normalize($row["adjrink2"]);
        $adjrink3 = $normalize($row["adjrink3"]);

        $u8race1q = $normalize($row["u8race1q"]);
        $u8race2q = $normalize($row["u8race2q"]);
        $u8race1i = $normalize($row["u8race1i"]);
        $u8race2i = $normalize($row["u8race2i"]);

        $rink1 = $setAndCount($row["rink1"], $rink1cnt);
        $rink2 = $setAndCount($row["rink2"], $rink2cnt);
        $rink3 = $setAndCount($row["rink3"], $rink3cnt);
        $road1 = $setAndCount($row["road1"], $road1cnt);

        $rink4 = $setAndCount($row["rink4"], $rink4cnt);
        $rink5 = $setAndCount($row["rink5"], $rink5cnt);
        $rink6 = $setAndCount($row["rink6"], $rink6cnt);
        $rink7 = $normalize($row["rink7"]);

        $road2 = $setAndCount($row["road2"], $road2cnt);
        $road3 = $setAndCount($row["road3"], $road3cnt);
        $road4 = $setAndCount($row["road4"], $road4cnt);
        $road5 = $setAndCount($row["road5"], $road5cnt);

        $p2p   = $setAndCount($row["p2p"], $p2pcnt);
        $elim  = $setAndCount($row["elim"], $rinkelimcnt);
        $p2prd = $setAndCount($row["p2prd"], $p2prdcnt);
        $elimrd= $setAndCount($row["elimrd"], $roadelimcnt);

        $relay      = $setAndCount($row["relay"], $relaycnt);
        $mixedrelay = $setAndCount($row["mixedrelay"], $mixedrelaycnt);

        $figure     = $normalize($row["figure"]);
        $free       = $normalize($row["free"]);
        $combined   = $normalize($row["combined"]);
        $pair       = $normalize($row["pair"]);
        $pairpartnername = trim($row["pairpartnername"]);
        $pairpartnerag   = trim($row["pairpartnerag"]);
        $inlinefree = $normalize($row["inlinefree"]);
        $solodance  = $normalize($row["solodance"]);
        $pairdance  = $normalize($row["pairdance"]);
        $quartet    = $normalize($row["quartet"]);
        $coupledancepartnername = trim($row["coupledancepartnername"]);
        $coupledancepartnerag   = trim($row["coupledancepartnerag"]);
        $quadhockey = $normalize($row["quadhockey"]);
        $mixedhockey = $normalize($row["mixedrollerhockey"]);
        $inlinehockey = $normalize($row["inlinehockey"]);

        $classicslalom = $normalize($row["classicslalom"]);
        $speedslalom   = $normalize($row["speedslalom"]);
        $pairslalom    = $normalize($row["pairslalom"]);

        $alpine        = $normalize($row["alpine"]);
        $downhill      = $normalize($row["downhill"]);
        $rollerderby   = $normalize($row["rollerderby"]);
 
        $precision     = $normalize($row["precisionskating"]);
        $showgroup     = $normalize($row["showgroup"]);

        $rollerfreestylepark = $normalize($row["rollerfreestylepark"]);
        $skateboardingpark = $normalize($row["skateboardingpark"]);
        $scooterpark       = $normalize($row["scooterpark"]);
        $rollerfreestylestreet = $normalize($row["rollerfreestylestreet"]);
        $skateboardingstreet = $normalize($row["skateboardingstreet"]);
        $scooterstreet       = $normalize($row["scooterstreet"]);

        // row background by status
        $bgc="";
        if ($status=="Approved by state") { $bgc="Lime"; }
        if ($status=="Rejected")          { $bgc="grey"; }
        if ($status=="Verified By Dt")    { $bgc="LightGreen"; }
        if ($status=="Pending")           { $bgc="Red"; }
        if ($status=="Held")              { $bgc="Yellow"; }
        if ($status=="Delete")            { $bgc="LightGrey"; }

        // group header when agegroup/gender changes (using OVERRIDDEN group)
        if ($curag!=$ag || $curgender!=$gender) {
            if ($rollerhockeycnt>10) {
                echo '<tr style="background-color:red; color:white;"><td colspan=8>Error! More than 10 skaters in a '.$curag.' '.$curgender.' Team. </td></tr>';
            }
            if ($inlinehockeycnt>12) {
                echo '<tr style="background-color:red; color:white;"><td colspan=8>Error! More than 12 skaters in a '.$curag.' '.$curgender.' Team. </td></tr>';
            }
            $rollerhockeycnt=0;
            $inlinehockeycnt=0;

            echo '<tr style="background-color:#e6ffe6;"><td colspan=8><h5 style="-webkit-margin-after:0.5em !important; -webkit-margin-before:0.67em !important;"><b>'.$ag.' '.$gender.'</b></h5></td></tr>';   
            $curag=trim($ag);
            $curgender=trim($gender);
            $curteam=trim($club);
        }

        echo '<tr style="background-color:'.$bgc.'"><td>'.$slno.'</td>';
        if ($stype=="Speed-Quad"|| $stype=="Speed-Inline" || $stype=="Tenacity" || $stype=="Beginner-Quad" || $stype=="Beginner-Inline") {
            echo '<td><b>'.$chno.'</b></td>';
        }

        echo '<td>'.$appno.'</td>
              <td id="status'.$appno.'">'.$status.'</td>
              <td>'.$skaterid.'</td>
              <td style=" text-align:left;">'.$sname.'<br/>'.$phone.'</td>
              <td>'.$dob.'</td>
              <td>'.$age.'</td>
              <td>'.$ag.'</td>
              <td>'.$gender.'</td>
              <td style="white-space: nowrap; text-overflow:ellipsis; overflow: hidden; max-width:100px; width:80%;">'.$club.'</td>';

        if ($_SESSION['username']=="secretary" || $_SESSION['usertype']=="District" || $_SESSION['usertype']=="Club") {
            echo '<td class="noprint"><a href="#" onclick="editapp('.$appno.');"  data-rel="popup" data-position-to="window" data-role="button" class="ui-btn ui-btn-inline ui-mini ui-btn-raised">Edit</a></td>';
        }

        echo '<td class="noprint"><a href="#" onclick="deleteapp('.$appno.');"  data-rel="popup" data-position-to="window" data-role="button" class="ui-btn ui-btn-inline ui-mini ui-btn-raised color-red">Delete</a></td>';

        if ($stype=="Tenacity" || $stype=="all") {
            echo '<td>'.$adjrink1.'</td><td>'.$adjrink2.'</td>';
        }
        if ($stype=="Beginner-Quad" || $stype=="all") {
            echo '<td>'.$u8race1q.'</td><td>'.$u8race2q.'</td>';
        }
        if ($stype=="Beginner-Inline" || $stype=="all") {
            echo '<td>'.$u8race1i.'</td><td>'.$u8race2i.'</td>';
        }
        if ($stype=="Speed-Quad" || $stype=="all") {
            echo '<td>'.$rink1.'</td><td>'.$rink2.'</td><td>'.$rink3.'</td><td>'.$road1.'</td><td>'.$road2.'</td>';
        }
        if ($stype=="Speed-Inline" || $stype=="all") {
            echo '<td style="border-left:1px solid black !important;">'.$rink4.'</td><td>'.$rink5.'</td><td>'.$rink6.'</td><td>'.$rink7.'</td><td>'.$p2p.'</td><td>'.$elim.'</td><td>'.$road3.'</td><td>'.$road4.'</td><td>'.$road5.'</td><td>'.$p2prd.'</td><td>'.$elimrd.'</td><td>'.$relay.'</td><td>'.$mixedrelay.'</td>';
        }
        if ($stype=="Artistic") {
            echo '<td>'.$figure.'</td><td>'.$free.'</td><td>'.$pair.'</td><td>'.$pairpartnername.'<br/>'.$pairpartnerag.'</td><td>'.$solodance.'</td><td>'.$pairdance.'</td><td>'.$coupledancepartnername.'<br/>'.$coupledancepartnerag.'</td><td>'.$inlinefree.'</td><td>'.$quartet.'</td><td>'.$showgroup.'</td><td>'.$precision.'</td>';
        }
        if ($stype=="Roller-Hockey") {
            echo '<td>'.$quadhockey.'</td><td>'.$mixedhockey.'</td>';
            echo '<td>'.$position.'</td><td>'.$jerseyno.'</td>';
        }
        if ($stype=="Inline-Hockey") {
            echo '<td>'.$inlinehockey.'</td>';
            echo '<td>'.$position.'</td><td>'.$jerseyno.'</td>';
        }
        if ($stype=="Inline-Freestyle") {
            echo '<td>'.$classicslalom.'</td><td>'.$speedslalom.'</td><td>'.$pairslalom.'</td>';
        }
        if ($stype=="Other") {
            echo '<td>'.$discipline.'</td>';
            echo '<td>'.$otherdiscipline.'</td>';
            echo '<td>'.$alpine.'</td>';
            echo '<td>'.$downhill.'</td>';
            echo '<td>'.$rollerderby.'</td>';
            echo '<td>'.$rollerfreestylepark.'</td>';
            echo '<td>'.$rollerfreestylestreet.'</td>';
            echo '<td>'.$skateboardingpark.'</td>';
            echo '<td>'.$skateboardingstreet.'</td>';
            echo '<td>'.$scooterpark.'</td>';
            echo '<td>'.$scooterstreet.'</td>';
        }

        echo '<td> '.$comments.' </td></tr>';
    }

    // reset counters
    $rink1cnt=0; $rink2cnt=0; $road1cnt=0; $road2cnt=0; $quadskaterscnt=0;
    $rink3cnt=0; $rink4cnt=0; $road3cnt=0; $road4cnt=0; $road5cnt=0; $p2pcnt=0; $rinkelimcnt=0; $p2prdcnt=0;
    $roadelimcnt=0; $relaycnt=0; $mixedrelaycnt=0; $inlineskaterscnt=0; $rollerhockeycnt=0; $inlinehockeycnt=0;

    echo '</tbody>';  
    echo "</table>";
}

 ?>