<?php
require_once __DIR__ . '/../config/helpers.php';
require_once __DIR__ . '/../config/db.php';
$cfg = require __DIR__ . '/../config/config.php';
$pdo = db();
/* ================== AJAX NEWS & COMMENTS (with reply) ================== */
// tambahkan kolom parent_id jika belum ada
try{
  $pdo->exec("
    CREATE TABLE IF NOT EXISTS news_comments (
      id INT AUTO_INCREMENT PRIMARY KEY,
      news_id INT NOT NULL,
      parent_id INT NULL DEFAULT 0,
      name VARCHAR(120) NOT NULL,
      email VARCHAR(160) DEFAULT NULL,
      comment TEXT NOT NULL,
      created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
      is_approved TINYINT(1) NOT NULL DEFAULT 1,
      is_spam TINYINT(1) NOT NULL DEFAULT 0,
      INDEX(news_id), INDEX(parent_id), INDEX(is_approved), INDEX(is_spam), INDEX(created_at)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
  ");
  // jika tabel lama belum ada parent_id, coba tambah
  $pdo->exec("ALTER TABLE news_comments ADD COLUMN parent_id INT NULL DEFAULT 0 AFTER news_id");
} catch(Throwable $e){ /* ignore */ }

/** helper response JSON */
function jresp($ok, $data=[], $code=200){
  http_response_code($code);
  header('Content-Type: application/json; charset=utf-8');
  echo json_encode(['ok'=>$ok] + $data);
  exit;
}

if (isset($_GET['ajax']) || isset($_POST['ajax'])) {
  $act = $_GET['ajax'] ?? $_POST['ajax'];

  if ($act === 'news') { // GET detail berita + komentar
    $id = (int)($_GET['id'] ?? 0);
    if ($id<=0) jresp(false,['msg'=>'ID tidak valid'],400);

    $st = $pdo->prepare("
      SELECT id,title,content,photo_path,author,category,source,
             COALESCE(publish_date,created_at) AS published_at
      FROM news WHERE id=? LIMIT 1
    ");
    $st->execute([$id]);
    $news = $st->fetch();
    if (!$news) jresp(false,['msg'=>'Berita tidak ditemukan'],404);

    // ambil komentar (kembalikan id & parent_id untuk dibentuk tree di frontend)
    $sc = $pdo->prepare("
      SELECT id, parent_id, name, email, comment, created_at
      FROM news_comments
      WHERE news_id=? AND is_spam=0 AND is_approved=1
      ORDER BY created_at ASC, id ASC
    ");
    $sc->execute([$id]);
    $comments = $sc->fetchAll();

    jresp(true, ['news'=>$news, 'comments'=>$comments]);
  }

  if ($act === 'comment') { // POST komentar / balasan
    try{
      csrf_check();
      if (!empty($_POST['hp'] ?? '')) throw new RuntimeException('Spam terdeteksi.');

      $newsId   = (int)($_POST['news_id'] ?? 0);
      $parentId = (int)($_POST['parent_id'] ?? 0);  // 0 = komentar root
      $name     = trim($_POST['name'] ?? '');
      $email    = trim($_POST['email'] ?? '');
      $comm     = trim($_POST['comment'] ?? '');

      if ($newsId<=0) throw new RuntimeException('Berita tidak valid.');
      if ($name==='' || $comm==='') throw new RuntimeException('Nama dan komentar wajib diisi.');

      // pastikan berita ada
      $cek = $pdo->prepare("SELECT 1 FROM news WHERE id=?");
      $cek->execute([$newsId]);
      if (!$cek->fetch()) throw new RuntimeException('Berita tidak ditemukan.');

      // jika balasan, pastikan parent berada di berita yang sama
      if ($parentId>0){
        $cekp = $pdo->prepare("SELECT 1 FROM news_comments WHERE id=? AND news_id=?");
        $cekp->execute([$parentId,$newsId]);
        if(!$cekp->fetch()) throw new RuntimeException('Komentar induk tidak ditemukan.');
      }

      if (mb_strlen($name)>120)  $name  = mb_substr($name,0,120);
      if (mb_strlen($email)>160) $email = mb_substr($email,0,160);
      if (mb_strlen($comm)>4000) $comm  = mb_substr($comm,0,4000);

      $ins = $pdo->prepare("
        INSERT INTO news_comments (news_id,parent_id,name,email,comment,is_approved,is_spam)
        VALUES (?,?,?,?,?,1,0)
      ");
      $ins->execute([$newsId, $parentId ?: 0, $name, $email ?: null, $comm]);

      // ambil ulang komentar terbaru (kirim lengkap utk dirender bertingkat)
      $sc = $pdo->prepare("
        SELECT id, parent_id, name, email, comment, created_at
        FROM news_comments
        WHERE news_id=? AND is_spam=0 AND is_approved=1
        ORDER BY created_at ASC, id ASC
      ");
      $sc->execute([$newsId]);
      $comments = $sc->fetchAll();

      jresp(true, ['msg'=>'Komentar tersimpan.','comments'=>$comments]);
    }catch(Throwable $ex){
      jresp(false, ['msg'=>$ex->getMessage()], 400);
    }
  }

  jresp(false,['msg'=>'Aksi tidak dikenal'],400);
}
/* --------- Data dasar --------- */
$profile = $pdo->query("SELECT * FROM profile ORDER BY id DESC LIMIT 1")->fetch()
          ?: ['full_name'=>'Nama Anda','headline'=>'Headline','bio'=>'Tuliskan bio singkat Anda.','photo'=>null];

$about = $pdo->query("SELECT * FROM about ORDER BY id DESC LIMIT 1")->fetch() ?: [];
$studies = $pdo->query("SELECT * FROM studies ORDER BY end_year DESC, start_year DESC")->fetchAll();

try { $projects = $pdo->query("SELECT * FROM projects ORDER BY created_at DESC")->fetchAll(); }
catch (Throwable $e) { $projects = []; }

/* Galeri proyek (opsional) */
$projectGalleries = (isset($projectGalleries) && is_array($projectGalleries)) ? $projectGalleries : [];

/* --------- Skills (kategori + warna) --------- */
try { $skills = $pdo->query("SELECT name, level, category FROM skills ORDER BY category ASC, name ASC")->fetchAll(); }
catch (Throwable $e) { $skills = []; }

$catColors = [];
$palette = ['#0d6efd','#198754','#0dcaf0','#ffc107','#dc3545','#6610f2','#20c997','#fd7e14','#6f42c1','#e83e8c','#17a2b8','#6c757d'];
foreach ($skills as $s) {
  $cat = trim($s['category'] ?? 'General') ?: 'General';
  if (!isset($catColors[$cat])) $catColors[$cat] = $palette[count($catColors) % count($palette)];
}
function textColorByBg($hex){
  $hex = ltrim($hex,'#'); if (strlen($hex)===3) $hex="{$hex[0]}{$hex[0]}{$hex[1]}{$hex[1]}{$hex[2]}{$hex[2]}";
  $r=hexdec(substr($hex,0,2)); $g=hexdec(substr($hex,2,2)); $b=hexdec(substr($hex,4,2));
  $lum = 0.2126*$r + 0.7152*$g + 0.0722*$b; return ($lum>180)?'#111827':'#ffffff';
}

/* --------- Experiences --------- */
try {
  $experiences = $pdo->query("
    SELECT id, company, position, start_year, end_year, achievements
    FROM experiences
    ORDER BY (CASE WHEN end_year IS NULL THEN 1 ELSE 0 END) DESC, end_year DESC, start_year DESC, id DESC
  ")->fetchAll();
} catch (Throwable $e) { $experiences = []; }

/* --------- Certification --------- */
try {
  $certs = $pdo->query("
    SELECT org_name, issue_year, expire_year, cert_name, cert_url, cert_no, cert_photo
    FROM sertification
    ORDER BY issue_year DESC, expire_year DESC, cert_name ASC
  ")->fetchAll();
} catch (Throwable $e) { $certs = []; }

$ok = flash('ok');
?>
<!doctype html>
<html lang="id">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title><?php echo e($cfg['APP_NAME']) ?> — Fortopolio</title>
  <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-sRIl4kxILFvY47J16cr9ZwB07vP4J8+LH7qKQnuqkuIAvNWLzeN8tE5YBujZqJLB" crossorigin="anonymous">
  <link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.13.1/font/bootstrap-icons.css" rel="stylesheet">
  <link href="<?php echo e(base_url('assets/css/style.css')) ?>" rel="stylesheet">
  <style>
    
  </style>
  <style>
    /* ==== PANEL PENGALAMAN — Elegant Soft Effect ==== */

/* Card utama */
.panel-fx {
  background: rgba(255,255,255,.95);
  border-radius: 1rem;
  border: 1px solid rgba(0,0,0,.05);
  box-shadow: 0 8px 22px rgba(13,110,253,.08);
  transition: all .4s cubic-bezier(.2,.8,.2,1);
  position: relative;
  overflow: hidden;
}

[data-bs-theme="dark"] .panel-fx {
  background: rgba(17,23,39,.85);
  border-color: rgba(255,255,255,.06);
  box-shadow: 0 8px 22px rgba(0,0,0,.3);
}

/* Hover lembut */
.panel-fx:hover {
  transform: translateY(-4px);
  box-shadow: 0 14px 30px rgba(13,110,253,.12);
}

/* Fade raise animasi (aktif saat scroll reveal) */
.fade-raise {
  opacity: 0;
  transform: translateY(24px);
  transition: opacity .8s ease, transform .8s cubic-bezier(.2,.8,.2,1);
}
.fade-raise.reveal-in {
  opacity: 1;
  transform: none;
}

/* Judul panel */
.panel-fx h5 {
  font-weight: 700;
  letter-spacing: .3px;
  color: #0d6efd;
  border-bottom: 1px solid rgba(0,0,0,.05);
  padding-bottom: .4rem;
}
[data-bs-theme="dark"] .panel-fx h5 {
  color: #9ec5fe;
  border-color: rgba(255,255,255,.08);
}

/* Timeline container */
.timeline {
  position: relative;
  margin-left: 1.4rem;
  padding-left: 1rem;
  border-left: 2px solid rgba(13,110,253,.2);
}
[data-bs-theme="dark"] .timeline {
  border-color: rgba(13,110,253,.25);
}

/* Timeline item */
.timeline-item {
  position: relative;
  margin-bottom: 1.25rem;
  padding-left: .75rem;
  animation: fadeSlideUp .8s ease both;
}
@keyframes fadeSlideUp {
  0% { opacity: 0; transform: translateY(20px); }
  100% { opacity: 1; transform: none; }
}

/* Titik timeline */
.timeline-dot {
  position: absolute;
  left: -1.3rem;
  top: .4rem;
  width: 12px; height: 12px;
  background: linear-gradient(90deg, #0d6efd, #20c997);
  border-radius: 50%;
  box-shadow: 0 0 0 4px rgba(13,110,253,.12);
  transition: transform .3s ease;
}
.timeline-item:hover .timeline-dot {
  transform: scale(1.15);
}

/* Konten timeline */
.timeline-content {
  background: rgba(255,255,255,.5);
  border-radius: .65rem;
  padding: .65rem .9rem;
  transition: background .35s ease;
}
[data-bs-theme="dark"] .timeline-content {
  background: rgba(17,23,39,.5);
}
.timeline-item:hover .timeline-content {
  background: rgba(13,110,253,.05);
}

/* Detail teks */
.timeline-content .fw-semibold {
  font-weight: 600;
  color: #0b132b;
}
[data-bs-theme="dark"] .timeline-content .fw-semibold {
  color: #e2e8f0;
}
.timeline-content .text-muted {
  color: #6c757d !important;
}
.timeline-content .text-secondary {
  color: #495057 !important;
}
[data-bs-theme="dark"] .timeline-content .text-secondary {
  color: #a3b1c6 !important;
}

/* Achievement icon */
.timeline-content i.bi-trophy-fill {
  color: #ffc107;
}

/* Efek garis cahaya halus di kiri */
.panel-fx::before {
  content:"";
  position:absolute; left:0; top:0; bottom:0; width:4px;
  background: linear-gradient(180deg, #0d6efd, #20c997);
  opacity:.1;
  transition: opacity .5s ease;
}
.panel-fx:hover::before { opacity:.4; }

/* Responsif */
@media (max-width:576px){
  .timeline{ margin-left:.9rem; padding-left:.8rem; }
  .timeline-dot{ left:-1rem; }
}

  </style>
  <style>
    <style>
/* Panel & efek lembut */
.news-panel{ border-radius: 1rem; overflow: hidden; }
.news-panel .card-header{ border-bottom:1px solid rgba(0,0,0,.05); }
.news-panel .card-footer{ border-top:1px solid rgba(0,0,0,.05); }

/* Hover halus per item */
.news-item{ transition: background .25s ease, transform .25s ease, box-shadow .25s ease; border:0; border-bottom:1px solid rgba(0,0,0,.06); }
.news-item:last-child{ border-bottom:0; }
.news-item:hover{
  background: rgba(13,110,253,.03);
  transform: translateY(-2px);
  box-shadow: 0 8px 22px rgba(13,110,253,.06);
}

/* Tombol kecil efek ringkas */
.fx-btn{ position: relative; overflow:hidden; }
.fx-btn::after{
  content:""; position:absolute; inset:-1px;
  background: radial-gradient(120px 60px at var(--x,50%) var(--y,50%), rgba(255,255,255,.3), transparent 55%);
  opacity:0; transition: opacity .2s ease;
}
.fx-btn:active::after{ opacity:1; transition: opacity .06s ease; }

/* Shimmer gambar kecil */
.cover{ position:relative; border-radius:.5rem; overflow:hidden; }
.cover.shimmer::after{
  content:""; position:absolute; inset:0; pointer-events:none;
  background: linear-gradient(120deg, transparent 0%, rgba(255,255,255,.45) 22%, transparent 40%);
  transform: translateX(-120%); animation: newsShimmer 1.8s infinite;
}
@keyframes newsShimmer{ to{ transform: translateX(120%); } }

</style>
  </style>
  <style>
    html{scroll-behavior:smooth;}
    /* spacing hero */
    #hero{padding-bottom:24px;} @media (max-width:991.98px){#hero{padding-bottom:18px;}}

   /* ==== SIDEBAR NAV (Enhanced, warna dipertahankan) ==== */
#sideNav{
  position: relative;
  display: block;
  overflow: auto;               /* biar bisa scroll */
  max-height: calc(100vh - 2rem);
  padding-right: .25rem;        /* ruang untuk scrollbar */
  /* Scroll fade (mask) agar lebih premium di browser modern */
  -webkit-mask-image: linear-gradient(to bottom, transparent 0, #000 16px, #000 calc(100% - 16px), transparent 100%);
          mask-image: linear-gradient(to bottom, transparent 0, #000 16px, #000 calc(100% - 16px), transparent 100%);
}

/* Scrollbar tipis */
#sideNav::-webkit-scrollbar{ width: 8px; }
#sideNav::-webkit-scrollbar-thumb{ background: rgba(255,255,255,.12); border-radius: 6px; }
#sideNav::-webkit-scrollbar-track{ background: transparent; }

/* Link dasar (tetap warna & nuansa asli) */
#sideNav .nav-link{
  position: relative;
  display: flex; align-items: center; gap: .55rem;
  padding: .55rem 1rem;
  color: #ced4da;
  border-radius: .5rem;
  margin: .15rem .5rem;
  transition: color .25s, background .25s, transform .25s;
  text-decoration: none;
  outline: none;
}

/* Ikon bootstrap (bi) tersusun rapi */
#sideNav .nav-link .bi{
  font-size: 1.05rem;
  width: 1.25rem; min-width: 1.25rem; text-align: center;
  opacity: .9;
}

/* Label & badge count di kanan */
#sideNav .nav-link .label{ flex: 1 1 auto; }
#sideNav .nav-link .count{
  font-size: .72rem; font-weight: 600;
  padding: .15rem .45rem; border-radius: .85rem;
  background: rgba(13,110,253,.12); color: #e7f1ff;
  border: 1px solid rgba(13,110,253,.25);
}

/* Dot penanda item baru */
#sideNav .nav-link .dot{
  width: 8px; height: 8px; border-radius: 50%;
  background: #20c997; box-shadow: 0 0 0 0 rgba(32,201,151,.5);
  margin-left: .25rem;
  animation: navDotPulse 1.8s ease-out infinite;
}
@keyframes navDotPulse{
  0%{ box-shadow: 0 0 0 0 rgba(32,201,151,.45); }
  100%{ box-shadow: 0 0 0 10px rgba(32,201,151,0); }
}

/* Hover & underline anim (warna tetap) */
#sideNav .nav-link:hover{
  background: rgba(255,255,255,.06);
  color: #fff;
  transform: translateX(2px);
}
#sideNav .nav-link::after{
  content:"";
  position:absolute; left:1rem; bottom:.35rem; height:2px; width:0;
  background: linear-gradient(90deg,#0d6efd,#20c997);
  border-radius:2px;
  transition: width .28s cubic-bezier(.2,.8,.2,1);
}
#sideNav .nav-link:hover::after{ width: 28px; }

/* Active state (kelas lama + aksesibel via aria-current) */
#sideNav .nav-link.is-active,
#sideNav .nav-link[aria-current="page"]{
  color:#fff; background: rgba(255,255,255,.08);
}
#sideNav .nav-link.is-active::after,
#sideNav .nav-link[aria-current="page"]::after{ width:28px; }
#sideNav .nav-link.is-active::before,
#sideNav .nav-link[aria-current="page"]::before{
  content:""; position:absolute; left:-4px; top:8px; bottom:8px; width:3px;
  background: linear-gradient(180deg,#20c997,#0d6efd);
  border-radius:3px; box-shadow:0 0 .6rem rgba(13,110,253,.35);
}

/* Focus ring yang jelas (keyboard accessibility) */
#sideNav .nav-link:focus-visible{
  box-shadow: 0 0 0 3px rgba(13,110,253,.35), 0 0 0 6px rgba(13,110,253,.18);
  outline: none;
}

/* Chevron untuk submenu + rotasi saat expanded */
#sideNav .nav-link .chev{
  margin-left: auto; transition: transform .25s ease;
}
#sideNav .nav-link[aria-expanded="true"] .chev,
#sideNav .nav-link.is-active .chev{
  transform: rotate(90deg);
}

/* Ripple klik (pure CSS, ringan) */
#sideNav .nav-link::before{
  content:""; position:absolute; inset:0; border-radius: inherit;
  background: radial-gradient(80px circle at var(--x,50%) var(--y,50%), rgba(13,110,253,.18), transparent 40%);
  opacity: 0; transition: opacity .35s ease;
  pointer-events: none;
}
#sideNav .nav-link:active::before{ opacity: 1; transition: opacity .05s ease; }

/* Judul grup navigasi */
#sideNav .nav-title{
  font-size:.78rem; letter-spacing:.06em; text-transform: uppercase;
  color:#94a3b8; margin: .9rem .75rem .35rem;
  padding-left:.35rem;
}

/* Divider halus antar grup */
#sideNav .nav-sep{
  height:1px; margin:.6rem .75rem;
  background: linear-gradient(90deg, transparent, rgba(255,255,255,.12), transparent);
  border:0;
}

/* Tooltip sederhana via data-tip */
#sideNav [data-tip]{ position:relative; }
#sideNav [data-tip]:hover::after{
  content: attr(data-tip);
  position:absolute; top:50%; left: calc(100% + 10px); transform: translateY(-50%);
  white-space: nowrap; font-size:.78rem; color:#e2e8f0;
  background:#111827; border:1px solid rgba(255,255,255,.08);
  padding:.28rem .45rem; border-radius:.4rem; z-index: 5;
  box-shadow: 0 8px 22px rgba(0,0,0,.22);
}

/* Mode compact (opsional): tambahkan class .is-compact ke #sideNav parent */
.is-compact #sideNav .nav-link{
  justify-content: center; gap: 0; padding: .55rem .6rem;
}
.is-compact #sideNav .nav-link .label,
.is-compact #sideNav .nav-link .count{ display: none; }
.is-compact #sideNav .nav-link .bi{ margin: 0; }

/* Responsif: rapikan spacing di layar kecil */
@media (max-width: 991.98px){
  #sideNav{ max-height: none; -webkit-mask-image: none; mask-image: none; }
  #sideNav .nav-link{ margin: .15rem .25rem; }
}

/* ====== (Opsional) JS mini utk ripple posisi ======
Tambahkan JS kecil ini agar ripple mengikuti titik klik:
document.querySelectorAll('#sideNav .nav-link').forEach(el=>{
  el.addEventListener('pointerdown',e=>{
    const r=el.getBoundingClientRect();
    el.style.setProperty('--x', (e.clientX - r.left)+'px');
    el.style.setProperty('--y', (e.clientY - r.top)+'px');
  });
});
==================================================== */


    /* ==== ABOUT cards lift ==== */
    #about .card{transition:transform .35s cubic-bezier(.2,.8,.2,1), box-shadow .35s cubic-bezier(.2,.8,.2,1); box-shadow:0 .25rem .9rem rgba(0,0,0,.06);}
    #about:hover .card, #about.near .card{transform:translateY(-8px); box-shadow:0 .85rem 1.6rem rgba(0,0,0,.10);}
    #about .card:hover{transform:translateY(-12px); box-shadow:0 1.1rem 2rem rgba(0,0,0,.12);}

    /* ==== REVEAL generic ==== */
    .fade-raise{opacity:0; transform:translateY(26px) scale(.995); border-radius:.95rem;
      transition:opacity .85s cubic-bezier(.25,.8,.25,1), transform .85s cubic-bezier(.25,.8,.25,1), box-shadow .5s ease;}
    .fade-raise.appear{opacity:1;transform:none;}
    .fade-slide-up{opacity:0; transform:translateY(12px); transition:opacity .6s, transform .6s;}
    .fade-slide-up.appear{opacity:1; transform:none;}

/* ==== HERO REVEAL — Soft Effects, No Shadow ==== */

/* Basis arah gerak */
.reveal-left, .reveal-right, .reveal-up, .reveal-down, .reveal-soft, .reveal-fade {
  opacity: 0;
  will-change: transform, opacity, filter;
  transition:
    transform .8s cubic-bezier(.2,.8,.2,1),
    opacity .8s cubic-bezier(.2,.8,.2,1),
    filter .8s cubic-bezier(.2,.8,.2,1);
  backface-visibility: hidden;
}

/* Arah default (lebih lembut dari versi lama) */
.reveal-left  { transform: translateX(-40px) scale(.985); }
.reveal-right { transform: translateX( 40px) scale(.985); }
.reveal-up    { transform: translateY( 28px) scale(.985); }
.reveal-down  { transform: translateY(-28px) scale(.985); }

/* Variasi super halus: blur-to-clear */
.reveal-soft  { transform: translateY(18px) scale(.985); filter: blur(8px) saturate(.9); }

/* Fade saja, tanpa translasi */
.reveal-fade  { transform: none; }

/* State terlihat */
.reveal-in{
  opacity: 1 !important;
  transform: none !important;
  filter: none !important;
}

/* ===== Underline & Glow Lembut (tanpa shadow) ===== */

/* Garis bawah tumbuh untuk judul/link */
.reveal-underline{
  position: relative;
}
.reveal-underline::after{
  content:"";
  position:absolute; left:0; bottom:-6px; height:2px; width:0%;
  background: linear-gradient(90deg, #0d6efd, #20c997);
  border-radius: 2px;
  transition: width .6s cubic-bezier(.2,.8,.2,1);
}
.reveal-underline.reveal-in::after{ width: 72px; }

/* Halo gradien super tipis (bukan shadow) */
.reveal-glow{
  position: relative;
}
.reveal-glow::before{
  content:"";
  position:absolute; inset:-4px;
  border-radius: 10px;
  opacity: 0;
  background:
    radial-gradient(40% 60% at 50% 100%, rgba(13,110,253,.18), transparent 70%),
    radial-gradient(30% 50% at 0% 30%,   rgba(32,201,151,.14), transparent 70%);
  transition: opacity .8s ease;
  pointer-events: none;
}
.reveal-glow.reveal-in::before{ opacity: .7; }
.reveal-glow:hover::before{ opacity: .9; }

/* ===== Stagger (muncul berurutan) ===== */
.reveal-stagger > *{
  opacity:0; transform: translateY(20px) scale(.985);
  transition: transform .7s cubic-bezier(.2,.8,.2,1), opacity .7s cubic-bezier(.2,.8,.2,1), filter .7s;
  filter: blur(6px);
}
.reveal-stagger.reveal-in > *{
  opacity:1; transform:none; filter:none;
}
.reveal-stagger.reveal-in > *:nth-child(1){ transition-delay: .06s; }
.reveal-stagger.reveal-in > *:nth-child(2){ transition-delay: .12s; }
.reveal-stagger.reveal-in > *:nth-child(3){ transition-delay: .18s; }
.reveal-stagger.reveal-in > *:nth-child(4){ transition-delay: .24s; }
.reveal-stagger.reveal-in > *:nth-child(5){ transition-delay: .30s; }
.reveal-stagger.reveal-in > *:nth-child(6){ transition-delay: .36s; }

/* ===== Util delay & durasi (opsional) ===== */
.reveal-delay-1{ transition-delay: .08s !important; }
.reveal-delay-2{ transition-delay: .16s !important; }
.reveal-delay-3{ transition-delay: .24s !important; }
.reveal-fast   { transition-duration: .55s !important; }
.reveal-slow   { transition-duration: 1s !important; }

/* ===== Hover micro-move (tanpa shadow) ===== */
.hover-float{
  transition: transform .35s cubic-bezier(.2,.8,.2,1), filter .35s;
}
.hover-float:hover{
  transform: translateY(-3px) scale(1.005);
  filter: saturate(1.05);
}

/* ===== Respect reduced-motion ===== */
@media (prefers-reduced-motion: reduce){
  .reveal-left, .reveal-right, .reveal-up, .reveal-down, .reveal-soft, .reveal-fade,
  .reveal-stagger > *, .hover-float,
  .reveal-underline::after, .reveal-glow::before{
    transition-duration: .001ms !important;
    transform: none !important;
    filter: none !important;
  }
}


    /* ==== Timeline ==== */
  
    /* ==== Portfolio cards ==== */
    .card-cover{height:220px;object-fit:cover;width:100%;display:block;} @media (max-width:768px){.card-cover{height:190px;}}
    .fx-raise{opacity:0; transform:translateY(14px); border-radius:.9rem;
      transition:opacity .6s, transform .6s, box-shadow .28s, filter .28s; box-shadow:0 .35rem 1.1rem rgba(0,0,0,.06); position:relative; overflow:hidden;}
    .fx-raise.appear{opacity:1; transform:none; box-shadow:0 .65rem 1.6rem rgba(0,0,0,.08);}
    .fx-raise::before{content:""; position:absolute; inset:0; border-radius:inherit; padding:1px;
      background:linear-gradient(135deg, rgba(13,110,253,.18), rgba(25,135,84,.18));
      -webkit-mask:linear-gradient(#fff 0 0) content-box,linear-gradient(#fff 0 0);
      -webkit-mask-composite:xor; mask-composite:exclude; pointer-events:none; opacity:0; transition:opacity .25s;}
    .fx-raise:hover::before{opacity:.7;}

    .portfolio-card{will-change:transform,box-shadow;}
    .portfolio-card:hover{transform:translateY(-6px); box-shadow:0 1.1rem 2.1rem rgba(0,0,0,.12);}
    .cover-wrap{position:relative; overflow:hidden; border-top-left-radius:.9rem;border-top-right-radius:.9rem;}
    .cover-wrap img{transform:scale(1); transition:transform .6s cubic-bezier(.2,.8,.2,1), filter .6s;}
    .portfolio-card:hover .cover-wrap img{transform:scale(1.06); filter:saturate(1.04);}

    /* penting: overlay aman tidak menutupi klik */
    .cover-overlay{position:absolute; left:0; right:0; top:.5rem; display:flex; gap:.5rem; align-items:center; padding:0 .5rem;
      opacity:0; transform:translateY(-6px); transition:opacity .3s, transform .3s; pointer-events:none; z-index:2;}
    .portfolio-card:hover .cover-overlay{opacity:1; transform:none;}
    .cover-overlay .overlay-actions, .cover-overlay a, .cover-overlay button{pointer-events:auto;}

    .btn-light-soft{backdrop-filter:blur(4px); background:rgba(255,255,255,.75); border:1px solid rgba(0,0,0,.08);}
    .soft-border{border:1px solid rgba(0,0,0,.08);}

    .glare{position:absolute; inset:0; pointer-events:none; z-index:1;
      background: radial-gradient(600px 120px at 10% -20%, rgba(255,255,255,.35), transparent 60%),
                  linear-gradient(120deg, rgba(255,255,255,.10), transparent 40% 60%, rgba(255,255,255,.10));
      opacity:0; transition:opacity .35s;}
    .portfolio-card:hover .glare{opacity:.9;}

    .shimmer::after{content:""; position:absolute; inset:0; pointer-events:none; z-index:1;
      background:linear-gradient(90deg, rgba(255,255,255,0) 0%, rgba(255,255,255,.55) 45%, rgba(255,255,255,0) 60%);
      transform:translateX(-100%); animation:shimmer 1.2s infinite; opacity:.25;}
    @keyframes shimmer{to{transform:translateX(100%);}}
    /* ===== Portfolio — Soft & Pretty Effects ===== */

/* Kartu: lift halus */
.portfolio-card{
  border-radius: 14px;
  transition: transform .35s cubic-bezier(.2,.8,.2,1), box-shadow .35s, filter .35s;
  will-change: transform;
}
.portfolio-card.fx-raise{ transform: translateY(10px); opacity:.0; transition-property: transform,opacity,box-shadow,filter; }
.portfolio-card.fx-raise.is-in{ transform:none; opacity:1; }

/* Hover: sedikit terangkat + fokus sampul */
.portfolio-card:hover{ transform: translateY(-6px); }

/* Sampul + overlay */
.cover-wrap{ position: relative; overflow: hidden; border-top-left-radius: 14px; border-top-right-radius: 14px; }
.card-cover{ height: 220px; object-fit: cover; display:block; }

.cover-overlay{
  position:absolute; inset:0; display:flex; align-items:start; gap:.5rem;
  padding:.6rem; opacity:0; transition: opacity .3s ease, backdrop-filter .3s ease, background .3s ease;
  background: linear-gradient(180deg, rgba(0,0,0,.15), rgba(0,0,0,.00) 35%, rgba(0,0,0,.35) 100%);
  backdrop-filter: blur(1px);
}
.portfolio-card:hover .cover-overlay{ opacity:1; backdrop-filter: blur(2px); }

/* Badge tanggal dan tombol aksi */
.soft-border{ border:1px solid rgba(255,255,255,.35); backdrop-filter: blur(2px); }
.btn-light-soft{
  --btn-bg: rgba(255,255,255,.85);
  --btn-bd: rgba(0,0,0,.08);
  background: var(--btn-bg); border:1px solid var(--btn-bd);
  color:#0b132b; border-radius: .6rem; padding:.35rem .5rem;
  transition: transform .2s ease, background .2s ease, border-color .2s ease;
}
.btn-light-soft:hover{ transform: translateY(-1px); background:#fff; }
.btn-light-soft:active{ transform: translateY(0); }

/* Glare (kilau lembut di pojok) */
.glare{
  position:absolute; right:-30%; top:-30%;
  width:70%; height:70%; pointer-events:none; opacity:.0;
  background: radial-gradient(closest-side, rgba(255,255,255,.55), transparent 70%);
  transform: rotate(15deg);
  transition: opacity .35s ease, transform .35s ease;
}
.portfolio-card:hover .glare{ opacity:.7; transform: rotate(0deg); }

/* Shimmer saat loading gambar (sudah dipakai di HTML) */
.shimmer{ position: relative; }
.shimmer::after{
  content:""; position:absolute; inset:0; pointer-events:none;
  background: linear-gradient(120deg, transparent 0%, rgba(255,255,255,.35) 18%, transparent 33%);
  transform: translateX(-120%); animation: pfShimmer 2.2s ease-in-out infinite;
}
@keyframes pfShimmer{
  0%{ transform: translateX(-120%); }
  60%,100%{ transform: translateX(120%); }
}
.cover-wrap.shimmer img{ opacity:.85; filter: saturate(.9); }

/* Judul & teks */
#portfolio .card-title{ font-weight:700; letter-spacing:.2px; }
#portfolio .card-text{ line-height: 1.45; }

/* Tilt ringan pakai data-tilt (tanpa lib) */
[data-tilt]{ transform-style: preserve-3d; }
.portfolio-card[data-tilt]:hover .card-img-top{ transform: translateZ(8px); transition: transform .35s ease; }

/* Dark theme penyesuaian */
[data-bs-theme="dark"] .btn-light-soft{
  --btn-bg: rgba(17,23,39,.85);
  --btn-bd: rgba(255,255,255,.12);
  color:#e2e8f0;
}
[data-bs-theme="dark"] .soft-border{ border-color: rgba(255,255,255,.25); }

/* Grid spacing responsif rapi */
@media (min-width: 992px){
  #portfolio .row.g-3 > [class*="col-"]{ display:flex; }
  #portfolio .portfolio-card{ width:100%; }
}







   /* ==== Certification slider — Soft & Pretty Upgrade ==== */
/* Track & item */
.cert-track{
  display: flex; gap: .85rem;
  scroll-snap-type: x mandatory;
  scroll-behavior: smooth;
  overflow-x: auto; overflow-y: hidden;
  scroll-padding: 1rem;
  padding-bottom: .25rem;
  -webkit-overflow-scrolling: touch;
}
.cert-track::-webkit-scrollbar{ height: 8px; }
.cert-track::-webkit-scrollbar-thumb{
  background: rgba(0,0,0,.15);
  border-radius: 6px;
}
[data-bs-theme="dark"] .cert-track::-webkit-scrollbar-thumb{
  background: rgba(255,255,255,.18);
}

.cert-item{
  scroll-snap-align: start;
  scroll-snap-stop: always; /* lebih mantap berhenti */
  width: 88vw; max-width: 520px; flex: 0 0 auto;
  transition: transform .45s cubic-bezier(.2,.8,.2,1), opacity .45s cubic-bezier(.2,.8,.2,1);
  opacity: .96;
}
@media (min-width:576px){ .cert-item{ width: calc(50% - .75rem); } }
@media (min-width:992px){ .cert-item{ width: calc(33.333% - .85rem); } }

/* Card: lembut & modern (tanpa shadow berlebihan) */
.cert-card{
  border-radius: .75rem;
  border: 1px solid rgba(0,0,0,.06);
  background: rgba(255,255,255,.9);
  transition: transform .35s cubic-bezier(.2,.8,.2,1), border-color .35s, filter .35s;
  overflow: hidden; position: relative;
}
[data-bs-theme="dark"] .cert-card{
  background: rgba(17,23,39,.85);
  border-color: rgba(255,255,255,.08);
}

/* Hover: gerak halus + glare tipis */
.cert-card:hover{ transform: translateY(-3px) scale(1.01); }
.cert-card::before{
  /* glare lembut */
  content:""; position:absolute; inset:0; pointer-events:none;
  background: radial-gradient(120% 50% at 10% 0%, rgba(13,110,253,.12), transparent 60%),
              radial-gradient(120% 60% at 100% 20%, rgba(32,201,151,.10), transparent 65%);
  opacity: .0; transition: opacity .5s ease;
}
.cert-card:hover::before{ opacity: .9; }

/* Foto dengan shimmer halus (class .shimmer opsional di img) */
.cert-photo{
  height: 190px; width: 100%; object-fit: cover;
  border-top-left-radius: .75rem; border-top-right-radius: .75rem;
  display: block; position: relative;
}
.shimmer{ position: relative; overflow: hidden; }
.shimmer::after{
  content:""; position:absolute; inset:0; pointer-events:none;
  background: linear-gradient(120deg, transparent 0%, rgba(255,255,255,.25) 18%, transparent 33%);
  transform: translateX(-120%);
  animation: certShimmer 2.2s ease-in-out infinite;
}
@keyframes certShimmer{
  0%{ transform: translateX(-120%); }
  60%{ transform: translateX(120%); }
  100%{ transform: translateX(120%); }
}

/* Mask pinggir agar konten fade-out di kiri/kanan */
.cert-slider-outer{ position: relative; }
.cert-mask{
  position: absolute; top:0; bottom:0; width:56px; z-index: 2; pointer-events:none;
  background: linear-gradient(to right, rgba(255,255,255,1), rgba(255,255,255,0));
}
.cert-mask-left{ left:-2px; }
.cert-mask-right{ right:-2px; transform: rotate(180deg); }
[data-bs-theme="dark"] .cert-mask{
  background: linear-gradient(to right, rgba(33,37,41,1), rgba(33,37,41,0));
}

/* State aktif (tambahkan .is-active via JS saat item berada di tengah) */
.cert-item.is-active{
  transform: translateY(-2px) scale(1.015);
  opacity: 1;
}


/* Fokus aksesibel (keyboard) */
.cert-card:focus-within,
.cert-card:focus-visible{
  outline: none;
  box-shadow: 0 0 0 0; /* tanpa shadow */
  border-color: rgba(13,110,253,.45);
}

/* Tombol prev/next minimalis */
.cert-btn{
  position: absolute; top: 50%; transform: translateY(-50%);
  width: 40px; height: 40px; border-radius: 999px;
  display: grid; place-items: center;
  background: rgba(255,255,255,.7);
  border: 1px solid rgba(0,0,0,.08);
  cursor: pointer; z-index: 3;
  transition: transform .25s ease, background .25s ease, border-color .25s ease;
}
.cert-btn:hover{ transform: translateY(-50%) scale(1.06); }
.cert-btn:active{ transform: translateY(-50%) scale(.98); }
.cert-btn.prev{ left: .25rem; }
.cert-btn.next{ right: .25rem; }
[data-bs-theme="dark"] .cert-btn{
  background: rgba(17,23,39,.85); border-color: rgba(255,255,255,.12);
}

/* Dots indikator */
.cert-dots{
  display:flex; gap:.4rem; justify-content:center; margin-top:.6rem;
}
.cert-dots .dot{
  width:8px; height:8px; border-radius:50%;
  background: rgba(0,0,0,.2);
  transition: transform .25s ease, background .25s ease;
}
.cert-dots .dot.is-active{
  transform: scale(1.25);
  background: linear-gradient(90deg, #0d6efd, #20c997);
}
[data-bs-theme="dark"] .cert-dots .dot{ background: rgba(255,255,255,.25); }

/* Micro-interaksi saat drag/scroll (tanpa JS) */
.cert-track:active .cert-item{ transition-duration: .2s; }

/* Reduce motion */
@media (prefers-reduced-motion: reduce){
  .cert-item, .cert-card, .cert-card::before, .shimmer::after,
  .cert-dots .dot { transition: none !important; animation: none !important; transform: none !important; }
}
  </style>
<style>
/* ===== Komentar — compact & pretty ===== */
.cmt-list { margin: 0; padding: 0; }
.cmt-item { list-style: none; margin: .5rem 0; }
.cmt-card {
  border: 1px solid rgba(0,0,0,.06);
  border-radius: .75rem;
  padding: .75rem .9rem;
  background: rgba(255,255,255,.9);
  transition: box-shadow .25s ease, transform .25s ease, border-color .25s ease;
}
.cmt-card:hover{
  box-shadow: 0 8px 20px rgba(13,110,253,.06);
  transform: translateY(-1px);
  border-color: rgba(13,110,253,.18);
}
[data-bs-theme="dark"] .cmt-card{
  background: rgba(17,23,39,.85);
  border-color: rgba(255,255,255,.08);
}

.cmt-head{ display:flex; align-items:flex-start; gap:.65rem; }
.cmt-avatar{
  width:34px;height:34px; border-radius:999px; display:grid; place-items:center;
  font-weight:700; font-size:.85rem; user-select:none;
  background: linear-gradient(135deg, #0d6efd22, #20c99722);
  color:#0b132b;
}
[data-bs-theme="dark"] .cmt-avatar{ color:#e2e8f0; }

.cmt-meta{ display:flex; align-items:center; gap:.5rem; }
.cmt-name{ font-weight:600; }
.cmt-date{ font-size:.8rem; color:#6c757d; }
.cmt-email{ font-size:.8rem; color:#6c757d; }

.cmt-body{ margin-top:.4rem; font-size:.95rem; color:#495057; white-space:pre-wrap; }
[data-bs-theme="dark"] .cmt-body{ color:#cbd5e1; }

/* clamp 4 baris */
.cmt-body.clamped{
  display:-webkit-box; -webkit-line-clamp:4; -webkit-box-orient:vertical; overflow:hidden;
}
.cmt-expand{
  display:inline-block; font-size:.85rem; margin-top:.25rem;
  color: var(--bs-primary); cursor:pointer; user-select:none;
}

.cmt-actions{ margin-top:.5rem; display:flex; gap:.5rem; align-items:center; flex-wrap:wrap; }
.cmt-chip{
  font-size:.72rem; font-weight:600; padding:.15rem .45rem; border-radius:.85rem;
  background: rgba(13,110,253,.08);
  border:1px solid rgba(13,110,253,.18);
  color:#0d6efd;
}

/* nesting garis kiri */
.cmt-branch{
  position:relative;
  margin-left: 0;
  padding-left: .75rem;
}
.cmt-branch::before{
  content:"";
  position:absolute; left: 0; top: .3rem; bottom: .3rem; width:2px;
  background: linear-gradient(180deg, rgba(13,110,253,.2), rgba(32,201,151,.2));
  border-radius:2px;
}
/* kedalaman pad */
.cmt-depth-1{ margin-left: 12px; }
.cmt-depth-2{ margin-left: 24px; }
.cmt-depth-3{ margin-left: 36px; }
.cmt-depth-4{ margin-left: 48px; }
.cmt-depth-5{ margin-left: 60px; }

/* replies slide container */
.cmt-replies{
  overflow:hidden;
  transition: height .25s ease;
}
.cmt-replies.is-collapsed{ height: 0 !important; }

/* reply form mini */
.reply-form.card{ border-radius:.65rem; }
.reply-form .form-control{ font-size:.9rem; }

/* dot notif baru (opsional) */
.cmt-dot{
  width:8px;height:8px;border-radius:999px;background:#20c997;margin-left:.25rem;
  box-shadow:0 0 0 0 rgba(32,201,151,.5); animation:cmtDot 1.8s ease-out infinite;
}
@keyframes cmtDot{ 0%{ box-shadow:0 0 0 0 rgba(32,201,151,.45);} 100%{ box-shadow:0 0 0 10px rgba(32,201,151,0);} }
</style>
</head>
<body>
<!-- DESKTOP SIDEBAR -->
<aside id="sidebar" class="d-lg-flex flex-column align-items-center d-none d-lg-flex">
  <img class="avatar" src="<?php echo e($profile['photo'] ?: 'https://picsum.photos/400/400') ?>" alt="Avatar">
  <div class="name text-center"><?php echo e($profile['full_name']) ?></div>
  <div class="headline text-center mb-3"><?php echo e($profile['headline'] ?: '') ?></div>
  <nav id="sideNav" class="nav flex-column w-100">
    <a class="nav-link" href="#hero" data-section="#hero"><i class="bi bi-house me-2"></i>Home</a>
    <a class="nav-link" href="#about" data-section="#about"><i class="bi bi-person me-2"></i>About</a>
    <a class="nav-link" href="#sertification" data-section="#sertification"><i class="bi bi-award me-2"></i>Sertification</a>
    <a class="nav-link" href="#portfolio" data-section="#portfolio"><i class="bi bi-kanban me-2"></i>Projects</a>
    <a class="nav-link" href="#berita" data-section="#berita"><i class="bi bi-newspaper me-2"></i>Berita</a>

    <a class="nav-link" href="#contact" data-section="#contact"><i class="bi bi-envelope me-2"></i>Contact</a>
  </nav>
  <div class="mt-4 small text-secondary">© <?php echo date('Y'); ?> <?php echo e($cfg['APP_NAME']) ?></div>
  <div class="mt-2"><a class="btn btn-sm btn-outline-light" href="<?php echo e(base_url('../admin/login.php')) ?>">Admin</a></div>
</aside>

<!-- MOBILE NAVBAR + OFFCANVAS -->
<nav class="navbar navbar-dark bg-dark d-lg-none sticky-top">
  <div class="container-fluid">
    <a class="navbar-brand fw-bold" href="#hero"><?php echo e($cfg['APP_NAME']) ?></a>
    <button class="navbar-toggler" type="button" data-bs-toggle="offcanvas" data-bs-target="#offcanvasNav" aria-controls="offcanvasNav" aria-label="Menu">
      <span class="navbar-toggler-icon"></span>
    </button>
  </div>
</nav>
<div class="offcanvas offcanvas-end bg-dark text-light" tabindex="-1" id="offcanvasNav" data-bs-scroll="true" data-bs-backdrop="true" aria-labelledby="offcanvasNavLabel">
  <div class="offcanvas-header">
    <h5 class="offcanvas-title" id="offcanvasNavLabel">Navigasi</h5>
    <button class="btn-close btn-close-white" type="button" data-bs-dismiss="offcanvas" aria-label="Tutup"></button>
  </div>
  <div class="offcanvas-body">
    <nav id="mobileNav" class="nav flex-column">

      <a class="nav-link" href="#hero" data-section="#hero"><i class="bi bi-house me-2"></i>Home</a>
      <a class="nav-link" href="#about" data-section="#about"><i class="bi bi-person me-2"></i>About</a>
      <a class="nav-link" href="#sertification" data-section="#sertification"><i class="bi bi-award me-2"></i>Sertification</a>
      <a class="nav-link" href="#portfolio" data-section="#portfolio"><i class="bi bi-kanban me-2"></i>Projects</a>
      <a class="nav-link" href="#berita" data-section="#berita"><i class="bi bi-newspaper me-2"></i>Berita</a>

      <a class="nav-link" href="#contact" data-section="#contact"><i class="bi bi-envelope me-2"></i>Contact</a>
      <hr class="border-secondary opacity-50">
      <a class="nav-link text-warning" href="<?php echo e(base_url('../admin/login.php')) ?>">Admin</a>
    </nav>
  </div>
</div>

<main id="content">
  <!-- HERO -->
  <section id="hero" class="section">
    <div class="container">
      <div class="row align-items-center g-4">
        <div class="col-lg-6 reveal-left">
          <h1 id="typed-text" class="fw-bold text-dark" style="min-height:60px"></h1>
          <p class="lead text-muted"><?php echo e($profile['headline'] ?: 'Profesional / Pekerjaan'); ?></p>
          <p class="fs-5" style="text-align:justify;"><?php echo nl2br(e($profile['bio'] ?? '')); ?></p>
          <a href="#portfolio" class="btn btn-primary btn-lg me-2"><i class="bi bi-kanban me-1"></i>Lihat Proyek</a>
          <a href="#contact" class="btn btn-outline-secondary btn-lg"><i class="bi bi-envelope me-1"></i>Kontak</a>
<a href="#" class="btn btn-outline-success btn-lg" data-bs-toggle="modal" data-bs-target="#whatsappModal"><i class="bi bi-whatsapp me-1"></i>WhatsApp</a>





        </div>
        <div class="col-lg-6 text-center reveal-right">
          <img class="img-fluid rounded-4 shadow" style="max-height:420px;object-fit:cover"
               src="<?php echo e($profile['photo'] ?: 'https://picsum.photos/900/900') ?>" alt="Foto">
        </div>
      </div>
    </div>
    <!-- ===== Modal Form WhatsApp ===== -->
    <?php
  // Ambil dari DB
  $wa_raw   = trim($profile['whatsapp'] ?? '');
  // Hanya angka
  $wa_digits = preg_replace('~\D+~', '', $wa_raw);

  // (Opsional) Normalisasi sederhana: jika diawali 0 dan kamu pakai kode negara tertentu,
  // isi $default_cc = '62'; // ID
  // if ($wa_digits !== '' && $wa_digits[0] === '0') {
  //   $wa_digits = $default_cc . substr($wa_digits, 1);
  // }
?>

<!-- ===== Modal Form WhatsApp ===== -->
<div class="modal fade" id="whatsappModal" tabindex="-1" aria-hidden="true"
     data-phone="<?php echo e($wa_digits); ?>">
  <div class="modal-dialog modal-dialog-centered">
    <div class="modal-content border-0 shadow-lg">
      <div class="modal-header bg-success text-white">
        <h5 class="modal-title"><i class="bi bi-whatsapp me-2"></i>Hubungi via WhatsApp</h5>
        <button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Tutup"></button>
      </div>
      <div class="modal-body">
        <form id="waForm">
          <div class="mb-3">
            <label for="waName" class="form-label">Nama Anda</label>
            <input type="text" id="waName" class="form-control" placeholder="Masukkan nama" required>
          </div>
          <div class="mb-3">
            <label for="waMessage" class="form-label">Pesan</label>
            <textarea id="waMessage" class="form-control" rows="3" placeholder="Tulis pesan Anda..." required></textarea>
          </div>
          <div class="d-flex justify-content-between align-items-center">
            <small class="text-muted">
              Nomor tujuan: <span id="waTargetPreview"><?php echo e($wa_digits ?: '—'); ?></span>
            </small>
            <button type="submit" class="btn btn-success">
              <i class="bi bi-send me-1"></i>Kirim ke WhatsApp
            </button>
          </div>
        </form>
        <?php if(empty($wa_digits)): ?>
          <div class="alert alert-warning mt-3 mb-0">
            Nomor WhatsApp belum diisi pada profil. Silakan isi di Admin &raquo; Profile.
          </div>
        <?php endif; ?>
      </div>
    </div>
  </div>
</div>


  </section>

  <!-- ABOUT -->
<section id="about" class="section bg-light">
  <div class="container">
    <h2 class="section-title mb-4"><i class="bi bi-person-circle me-2 text-success"></i>About Me</h2>

    <div class="row g-4 align-items-start">

      <div class="col-lg-8">
        <!-- ABOUT TEXT -->
        <div class="card border-0 shadow-sm mb-4 panel-fx fade-raise" data-panel="about-text">
          <div class="card-body fs-5" style="text-align:justify;">
            <?php echo nl2br(e($about['content'] ?? 'Belum ada konten.')); ?>
          </div>
        </div>

        <!-- PENGALAMAN -->
        <div class="card border-0 shadow-sm mb-4 panel-fx fade-raise" data-panel="about-exp">
          <div class="card-body">
            <h5 class="mb-3"><i class="bi bi-briefcase me-2"></i>Pengalaman</h5>
            <?php if (!empty($experiences)): ?>
              <div class="timeline">
                <?php foreach ($experiences as $ex):
                  $sy=$ex['start_year']??null; $ey=$ex['end_year']??null;
                  $pos=trim($ex['position']??''); $co=trim($ex['company']??''); $ach=trim($ex['achievements']??'');
                ?>
                  <div class="timeline-item fade-slide-up">
                    <div class="timeline-dot"></div>
                    <div class="timeline-content">
                      <div class="fw-semibold">
                        <?php echo e($pos ?: '—'); ?> <span class="text-muted">•</span> <?php echo e($co ?: '—'); ?>
                      </div>
                      <div class="text-muted small">
                        <i class="bi bi-calendar2-week me-1"></i><?php echo e($sy ?: '—'); ?> – <?php echo e($ey ?: 'Sekarang'); ?>
                      </div>
                      <?php if($ach!==''): ?>
                        <div class="mt-2 text-secondary" style="white-space:pre-line">
                          <i class="bi bi-trophy-fill me-1"></i><?php echo e($ach); ?>
                        </div>
                      <?php endif; ?>
                    </div>
                  </div>
                <?php endforeach; ?>
              </div>
            <?php else: ?>
              <div class="alert alert-info mb-0">Belum ada pengalaman yang ditampilkan.</div>
            <?php endif; ?>
          </div>
        </div>

        <!-- RIWAYAT STUDI (BARU) -->
        <?php
          // opsi kecil untuk badge warna hasil studi
          function study_result_badge(?string $status): string {
            $s = strtolower(trim((string)$status));
            if ($s === 'cumlaude')   return 'bg-warning-subtle text-warning-emphasis border border-warning-subtle';
            if ($s === 'memuaskan')  return 'bg-info-subtle text-info-emphasis border border-info-subtle';
            if ($s === 'lulus')      return 'bg-success-subtle text-success-emphasis border border-success-subtle';
            return 'bg-secondary-subtle text-secondary-emphasis border border-secondary-subtle';
          }
        ?>
        <div class="card border-0 shadow-sm panel-fx fade-raise" data-panel="about-studies">
          <div class="card-body">
            <h5 class="mb-3"><i class="bi bi-mortarboard-fill me-2"></i>Riwayat Studi</h5>

            <?php if (!empty($studies)): ?>
              <div class="timeline">
                <?php foreach ($studies as $st):
                  $inst = trim($st['institution'] ?? '');
                  $prog = trim($st['program'] ?? '');
                  $sy   = $st['start_year'] ?? null;
                  $ey   = $st['end_year']   ?? null;
                  $gr   = trim($st['grade'] ?? '');
                  $rs   = trim($st['result_status'] ?? '');
                  $badgeCls = study_result_badge($rs);
                ?>
                  <div class="timeline-item fade-slide-up">
                    <div class="timeline-dot"></div>
                    <div class="timeline-content">
                      <div class="fw-semibold d-flex flex-wrap align-items-center gap-2">
                        <span><?php echo e($inst ?: '—'); ?></span>
                        <?php if($rs!==''): ?>
                          <span class="badge rounded-pill px-2 py-1 <?php echo $badgeCls; ?>" title="Hasil studi">
                            <i class="bi bi-stars me-1"></i><?php echo e($rs); ?>
                          </span>
                        <?php endif; ?>
                      </div>
                      <div class="text-muted small mb-1">
                        <i class="bi bi-calendar2-week me-1"></i><?php echo e($sy ?: '—'); ?> – <?php echo e($ey ?: 'Sekarang'); ?>
                        <?php if($prog!==''): ?><span class="ms-2">• <?php echo e($prog); ?></span><?php endif; ?>
                      </div>
                      <?php if($gr!==''): ?>
                        <div class="text-secondary small">
                          <i class="bi bi-123 me-1"></i>Nilai / IPK: <span class="fw-semibold"><?php echo e($gr); ?></span>
                        </div>
                      <?php endif; ?>
                    </div>
                  </div>
                <?php endforeach; ?>
              </div>
            <?php else: ?>
              <div class="alert alert-info mb-0">Belum ada data studi yang ditampilkan.</div>
            <?php endif; ?>
          </div>
        </div>
        <!-- /RIWAYAT STUDI -->
      </div>

      <div class="col-lg-4">
        <?php
          $pf_photo = trim($profile['photo'] ?? '') ?: base_url('assets/img/avatar-default.png');
          $pf_name  = trim($profile['full_name'] ?? 'Nama Lengkap');
          $pf_head  = trim($profile['headline'] ?? 'Posisi / Keahlian Utama');
          $pf_loc   = trim($profile['address'] ?? '');
          $pf_email = trim($profile['email'] ?? '');
          $pf_wa    = trim($profile['whatsapp'] ?? '');
          $pf_addr  = trim($profile['address'] ?? '');
          $pf_link  = trim($profile['linkedin_url'] ?? '');
          $pf_cv    = trim($profile['cv_url'] ?? '');
          $pf_soc   = $profile['socials'] ?? [];
          $pf_wa_link = preg_replace('~\D~','',$pf_wa);
        ?>
        <div id="profile-card" class="card border-0 shadow-lg mb-4 panel-fx fade-raise" data-panel="about-profile">
          <div class="card-body text-center p-4 position-relative overflow-hidden">
            <div class="ribbon-gradient" style="position:absolute;inset:0;pointer-events:none;"></div>
            <div class="position-relative d-inline-block mb-3 avatar-wrap">
              <img src="<?php echo e($pf_photo); ?>" alt="Foto Profil"
                   class="rounded-circle border border-3 border-success-subtle"
                   style="width:140px;height:140px;object-fit:cover;"
                   onerror="this.src='<?php echo e(base_url('assets/img/avatar-default.png')); ?>'">
              <span class="ring-gradient" style="position:absolute;inset:0;pointer-events:none;"></span>
              <span class="position-absolute bottom-0 end-0 translate-middle p-1 bg-success rounded-circle border border-2 border-white"
                    title="Tersedia untuk peluang" data-bs-toggle="tooltip"><span class="visually-hidden">Status</span></span>
            </div>
            <h5 class="mb-1"><?php echo e($pf_name); ?></h5>
            <?php if($pf_head!==''): ?><div class="text-muted small mb-2"><?php echo e($pf_head); ?></div><?php endif; ?>
            <?php if($pf_loc!==''): ?><div class="text-muted small mb-3"><i class="bi bi-geo-alt me-1"></i><?php echo e($pf_loc); ?></div><?php endif; ?>

            <div class="d-flex justify-content-center gap-2 flex-wrap mb-3">
              <?php if($pf_email!==''): ?>
                <a class="btn btn-sm btn-outline-secondary" href="mailto:<?php echo e($pf_email); ?>"><i class="bi bi-envelope me-1"></i>Email</a>
              <?php endif; if($pf_wa_link!==''): ?>
                <a class="btn btn-sm btn-outline-secondary" href="https://wa.me/<?php echo e($pf_wa_link); ?>" target="_blank" rel="noopener"><i class="bi bi-whatsapp me-1"></i>WhatsApp</a>
              <?php endif; if($pf_link!==''): ?>
                <a class="btn btn-sm btn-outline-primary" href="<?php echo e($pf_link); ?>" target="_blank" rel="noopener"><i class="bi bi-linkedin me-1"></i>LinkedIn</a>
              <?php endif; if($pf_cv!==''): ?>
                <a class="btn btn-sm btn-success" href="<?php echo e($pf_cv); ?>" target="_blank" rel="noopener"><i class="bi bi-download me-1"></i>Download CV</a>
              <?php endif; ?>
            </div>

            <div class="text-start small mx-auto" style="max-width:440px;">
              <?php if($pf_addr!==''): ?>
                <div class="d-flex align-items-start mb-2">
                  <i class="bi bi-geo me-2 mt-1 text-secondary"></i>
                  <div class="flex-grow-1">
                    <div class="text-uppercase text-muted fw-semibold mb-0" style="letter-spacing:.4px;">Alamat</div>
                    <div class="text-body-secondary" style="white-space:pre-line;"><?php echo e($pf_addr); ?></div>
                  </div>
                </div>
              <?php endif; if($pf_email!==''): ?>
                <div class="d-flex align-items-center justify-content-between mb-2">
                  <div class="d-flex align-items-start">
                    <i class="bi bi-at me-2 mt-1 text-secondary"></i>
                    <div>
                      <div class="text-uppercase text-muted fw-semibold mb-0" style="letter-spacing:.4px;">Email</div>
                      <a href="mailto:<?php echo e($pf_email); ?>" class="text-decoration-none"><?php echo e($pf_email); ?></a>
                    </div>
                  </div>
                  <button class="btn btn-light btn-sm copy-btn" data-copy="<?php echo e($pf_email); ?>" title="Salin email"><i class="bi bi-clipboard"></i></button>
                </div>
              <?php endif; if($pf_wa_link!==''): ?>
                <div class="d-flex align-items-center justify-content-between mb-2">
                  <div class="d-flex align-items-start">
                    <i class="bi bi-telephone me-2 mt-1 text-secondary"></i>
                    <div>
                      <div class="text-uppercase text-muted fw-semibold mb-0" style="letter-spacing:.4px;">WhatsApp</div>
                      <a href="https://wa.me/<?php echo e($pf_wa_link); ?>" target="_blank" rel="noopener" class="text-decoration-none"><?php echo e($pf_wa); ?></a>
                    </div>
                  </div>
                  <button class="btn btn-light btn-sm copy-btn" data-copy="<?php echo e($pf_wa_link); ?>" title="Salin nomor"><i class="bi bi-clipboard"></i></button>
                </div>
              <?php endif; if($pf_link!==''): ?>
                <div class="d-flex align-items-start mb-1">
                  <i class="bi bi-linkedin me-2 mt-1 text-secondary"></i>
                  <div>
                    <div class="text-uppercase text-muted fw-semibold mb-0" style="letter-spacing:.4px;">LinkedIn</div>
                    <a href="<?php echo e($pf_link); ?>" target="_blank" rel="noopener" class="text-decoration-none"><?php echo e($pf_link); ?></a>
                  </div>
                </div>
              <?php endif; ?>
            </div>

            <?php if(!empty($pf_soc)): ?>
              <hr class="my-3">
              <div class="d-flex justify-content-center gap-2 flex-wrap">
                <?php foreach($pf_soc as $k=>$url){ if(!$url) continue; ?>
                  <a class="btn btn-sm btn-outline-secondary" href="<?php echo e($url); ?>" target="_blank" rel="noopener" title="<?php echo e(ucfirst($k)); ?>">
                    <i class="bi bi-<?php echo e($k); ?>"></i>
                  </a>
                <?php } ?>
              </div>
            <?php endif; ?>
          </div>
        </div>

        <!-- SKILLS -->
        <div class="card border-0 shadow-sm h-100 panel-fx fade-raise sticky-lg-top top-3" data-panel="about-skills">
          <div class="card-body">
            <div class="d-flex align-items-center justify-content-between mb-3">
              <h5 class="mb-0"><i class="bi bi-gear me-2"></i>Keahlian Utama</h5>
              <?php
                $cats=[]; foreach($skills as $s){ $c=trim($s['category']??'General')?:'General'; $cats[$c]=true; }
                $cats=array_keys($cats); sort($cats);
              ?>
              <?php if(!empty($cats)): ?>
                <div class="ms-2">
                  <select id="skill-filter" class="form-select form-select-sm">
                    <option value="__ALL__">Semua Kategori</option>
                    <?php foreach($cats as $c): ?><option value="<?php echo e($c); ?>"><?php echo e($c); ?></option><?php endforeach; ?>
                  </select>
                </div>
              <?php endif; ?>
            </div>

            <?php if(!empty($skills)): ?>
              <div id="skills-list" class="d-grid gap-3">
                <?php foreach($skills as $s):
                  $nm=e($s['name']??''); $lv=(int)($s['level']??0); $lv=max(0,min(100,$lv));
                  $cat=trim($s['category']??'General')?:'General'; $hex=$catColors[$cat]??'#6c757d'; $txt=textColorByBg($hex);
                ?>
                  <div class="skill-item fade-slide-up" data-cat="<?php echo e($cat); ?>">
                    <div class="d-flex justify-content-between align-items-center mb-1">
                      <div class="d-flex align-items-center">
                        <span class="badge me-2" style="background-color:<?php echo $hex ?>;color:<?php echo $txt ?>;font-weight:600;letter-spacing:.2px;"><?php echo e($cat) ?></span>
                        <span class="fw-medium"><?php echo $nm; ?></span>
                      </div>
                      <span class="text-muted small" title="Kemahiran"><span class="skill-val"><?php echo $lv; ?></span>%</span>
                    </div>
                    <div class="progress" style="height:10px;">
                      <div class="progress-bar skill-bar" role="progressbar" aria-label="<?php echo $nm; ?>"
                           data-target="<?php echo $lv; ?>" style="width:0%; background-color:<?php echo $hex ?>;"
                           aria-valuemin="0" aria-valuemax="100"></div>
                    </div>
                  </div>
                <?php endforeach; ?>
              </div>
            <?php else: ?>
              <div class="alert alert-info mb-0">Belum ada keahlian. Silakan tambah dari Admin &raquo; Keahlian.</div>
            <?php endif; ?>
          </div>
        </div>
      </div>
    </div> <!-- /row -->
  </div>
</section>


  <!-- CERTIFICATION -->
  <section id="sertification" class="section">
    <div class="container position-relative">
      <div class="d-flex align-items-center justify-content-between mb-3">
        <h2 class="section-title mb-0"><i class="bi bi-award me-2"></i>Sertification</h2>
        <?php if(!empty($certs)): ?>
          <div class="d-none d-md-flex gap-2">
            <button class="btn btn-outline-secondary btn-sm rounded-circle cert-prev" type="button" aria-label="Sebelumnya"><i class="bi bi-chevron-left"></i></button>
            <button class="btn btn-outline-secondary btn-sm rounded-circle cert-next" type="button" aria-label="Berikutnya"><i class="bi bi-chevron-right"></i></button>
          </div>
        <?php endif; ?>
      </div>

      <?php if(!empty($certs)): ?>
        <div class="cert-slider-outer">
          <div class="cert-mask cert-mask-left d-none d-md-block"></div>
          <div class="cert-mask cert-mask-right d-none d-md-block"></div>

          <div id="certTrack" class="cert-track d-flex gap-3 overflow-auto pb-2">
            <?php foreach ($certs as $c):
              $org=trim($c['org_name']??''); $nm=trim($c['cert_name']??''); $url=trim($c['cert_url']??''); $no=trim($c['cert_no']??'');
              $iy=(int)($c['issue_year']??0); $ey=(int)($c['expire_year']??0);
              $img=trim($c['cert_photo']??'') ?: 'https://picsum.photos/800/500';
            ?>
              <div class="cert-item flex-shrink-0 fade-slide-up">
                <div class="card border-0 shadow-sm h-100 cert-card">
                  <img class="cert-photo" src="<?php echo e($img) ?>" alt="certificate image" loading="lazy">
                  <div class="card-body d-flex flex-column">
                    <div class="d-flex flex-wrap align-items-center gap-2 mb-2">
                      <span class="badge bg-primary-subtle text-primary-emphasis border"><?php echo e($iy ?: '—'); ?> – <?php echo e($ey ?: '—'); ?></span>
                      <?php if ($no!==''): ?><span class="badge bg-secondary-subtle text-secondary-emphasis border"><i class="bi bi-hash me-1"></i><?php echo e($no); ?></span><?php endif; ?>
                    </div>
                    <h5 class="card-title mb-1"><?php echo e($nm !== '' ? $nm : 'Nama Sertifikat'); ?></h5>
                    <div class="text-muted mb-3"><i class="bi bi-building me-1"></i><?php echo e($org !== '' ? $org : 'Organisasi'); ?></div>
                    <?php if ($url!==''): ?>
                      <a href="<?php echo e($url) ?>" target="_blank" rel="noopener" class="btn btn-outline-primary btn-sm mt-auto">
                        <i class="bi bi-box-arrow-up-right me-1"></i>Lihat Sertifikat
                      </a>
                    <?php else: ?>
                      <div class="mt-auto small text-muted">Tidak ada tautan sertifikat.</div>
                    <?php endif; ?>
                  </div>
                </div>
              </div>
            <?php endforeach; ?>
          </div>

          <div class="d-flex d-md-none justify-content-center gap-2 mt-3">
            <button class="btn btn-outline-secondary btn-sm rounded-circle cert-prev" type="button" aria-label="Sebelumnya"><i class="bi bi-chevron-left"></i></button>
            <button class="btn btn-outline-secondary btn-sm rounded-circle cert-next" type="button" aria-label="Berikutnya"><i class="bi bi-chevron-right"></i></button>
          </div>
        </div>
      <?php else: ?>
        <div class="alert alert-info mb-0">Belum ada sertifikasi. Tambahkan dari halaman admin.</div>
      <?php endif; ?>
    </div>
  </section>

  <!-- PROJECTS -->
  <section id="portfolio" class="section">
    <div class="container">
      <h2 class="section-title mb-4"><i class="bi bi-lightbulb-fill me-2 text-info"></i>Projects</h2>

      <?php if(!empty($projects)): ?>
        <div class="row g-3">
          <?php foreach($projects as $p):
            $pid=(int)($p['id']??0);
            $title=trim($p['title']??'Untitled Project');
            $img=trim($p['image']??'') ?: 'https://picsum.photos/600/400';
            $desc=trim($p['description']??'');
            $link=trim($p['link']??'');
            $when=trim($p['created_at']??'');
            $gallery=$projectGalleries[$pid] ?? [];
            $galleryUrls=array_values(array_map(fn($it)=>$it['url'],$gallery));
            if(!in_array($img,$galleryUrls,true)) array_unshift($galleryUrls,$img);
            $dataImages=htmlspecialchars(json_encode($galleryUrls), ENT_QUOTES, 'UTF-8');
          ?>
            <div class="col-md-6 col-lg-4">
              <div class="card h-100 border-0 portfolio-card fx-raise" data-tilt>
                <div class="cover-wrap shimmer">
                  <img class="card-img-top card-cover" src="<?php echo e($img) ?>" alt="<?php echo e($title) ?>" loading="lazy"
                       onload="this.closest('.cover-wrap')?.classList.remove('shimmer')">
                  <div class="cover-overlay">
                    <?php if($when!==''): ?>
                      <span class="badge bg-dark-subtle text-dark-emphasis soft-border"><i class="bi bi-calendar-event me-1"></i><?php echo e($when) ?></span>
                    <?php endif; ?>
                    <div class="overlay-actions ms-auto d-flex gap-1">
                      <?php if($link!==''): ?>
                        <a class="btn btn-sm btn-light-soft" href="<?php echo e($link) ?>" target="_blank" title="Buka Proyek" rel="noopener"><i class="bi bi-box-arrow-up-right"></i></a>
                      <?php endif; ?>
                      <button type="button" class="btn btn-sm btn-light-soft btn-detail" title="Detail / Galeri"
                              data-bs-toggle="modal" data-bs-target="#projectDetailModal"
                              data-title="<?php echo e($title) ?>" data-image="<?php echo e($img) ?>"
                              data-desc="<?php echo e($desc) ?>" data-link="<?php echo e($link) ?>"
                              data-when="<?php echo e($when) ?>" data-images="<?php echo $dataImages ?>">
                        <i class="bi bi-images"></i>
                      </button>
                    </div>
                  </div>
                  <span class="glare"></span>
                </div>
                <div class="card-body d-flex flex-column">
                  <h5 class="card-title mb-1 text-truncate" title="<?php echo e($title) ?>"><?php echo e($title) ?></h5>
                  <p class="card-text small text-muted flex-grow-1"><?php echo nl2br(e(mb_strimwidth($desc,0,180,'…'))); ?></p>
                  <div class="d-flex gap-2 mt-auto">
                    <?php if($link!==''): ?>
                      <a href="<?php echo e($link) ?>" target="_blank" class="btn btn-outline-primary"><i class="bi bi-box-arrow-up-right me-1"></i>Buka</a>
                    <?php endif; ?>
                    <button type="button" class="btn btn-primary btn-detail" data-bs-toggle="modal" data-bs-target="#projectDetailModal"
                            data-title="<?php echo e($title) ?>" data-image="<?php echo e($img) ?>" data-desc="<?php echo e($desc) ?>"
                            data-link="<?php echo e($link) ?>" data-when="<?php echo e($when) ?>" data-images="<?php echo $dataImages ?>">
                      <i class="bi bi-images me-1"></i>Detail
                    </button>
                  </div>
                </div>
              </div>
            </div>
          <?php endforeach; ?>
        </div>
      <?php else: ?>
        <div class="alert alert-info">Belum ada proyek. Tambahkan dari halaman admin.</div>
      <?php endif; ?>
    </div>
  </section>

  <!-- MODAL DETAIL PROJEK -->
  <div class="modal fade" id="projectDetailModal" tabindex="-1" aria-hidden="true">
    <div class="modal-dialog modal-xl modal-dialog-centered modal-dialog-scrollable">
      <div class="modal-content">
        <div class="modal-header">
          <div>
            <h5 class="modal-title" id="projTitle">Judul Proyek</h5>
            <div class="small text-muted" id="projDate"></div>
          </div>
          <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Tutup"></button>
        </div>
        <div class="modal-body">
          <div id="projGallery"></div>
          <div id="projDesc" class="text-secondary mt-3" style="white-space:pre-line"></div>
        </div>
        <div class="modal-footer">
          <a id="projLink" href="#" target="_blank" class="btn btn-outline-primary d-none"><i class="bi bi-box-arrow-up-right me-1"></i>Buka Proyek</a>
          <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Tutup</button>
        </div>
      </div>
    </div>
  </div>

<?php
try{
  $newsList = $pdo->query("
    SELECT
      n.id,
      n.title,
      n.photo_path,
      n.category,
      COALESCE(n.publish_date, n.created_at) AS published_at,
      COALESCE(n.content,'') AS content,
      (
        SELECT COUNT(*)
        FROM news_comments nc
        WHERE nc.news_id = n.id
          AND nc.is_spam = 0
          AND nc.is_approved = 1
      ) AS comment_count
    FROM news n
    ORDER BY COALESCE(n.publish_date, n.created_at) DESC, n.id DESC
    LIMIT 8
  ")->fetchAll();
}catch(Throwable $e){ $newsList=[]; }

?>

<section id="berita" class="section bg-light">
 <?php
// ==== Siapkan palet warna untuk kategori (deterministik per nama kategori) ====
$__cat_palette = [
  '#0d6efd','#198754','#0dcaf0','#ffc107','#dc3545',
  '#6610f2','#20c997','#fd7e14','#6f42c1','#e83e8c','#17a2b8','#6c757d'
];
function catColor(string $cat) {
  global $__cat_palette;
  $c = trim(mb_strtolower($cat));
  if ($c === '') return ['#6c757d', '#ffffff'];
  // hash sederhana agar warna konsisten per kategori
  $h = 0;
  for ($i=0; $i<mb_strlen($c); $i++) $h = (31*$h + ord($c[$i])) & 0x7fffffff;
  $hex = $__cat_palette[$h % count($__cat_palette)];
  // teks putih/gelap berdasarkan luminance
  $hex1 = ltrim($hex,'#'); if(strlen($hex1)===3){$hex1="{$hex1[0]}{$hex1[0]}{$hex1[1]}{$hex1[1]}{$hex1[2]}{$hex1[2]}";}
  $r=hexdec(substr($hex1,0,2)); $g=hexdec(substr($hex1,2,2)); $b=hexdec(substr($hex1,4,2));
  $lum = 0.2126*$r + 0.7152*$g + 0.0722*$b;
  return [$hex, $lum>180 ? '#111827' : '#ffffff'];
}
?>
<section id="berita" class="section bg-light">
  <div class="container">

    <!-- Panel news -->
    <div class="card border-0 shadow-sm news-panel">
      <div class="card-header d-flex align-items-center justify-content-between bg-white">
        <div class="d-flex align-items-center gap-2">
          <span class="badge rounded-circle p-2 bg-primary-subtle" style="line-height:0">
            <i class="bi bi-newspaper text-primary"></i>
          </span>
          <h2 class="section-title mb-0">Berita</h2>
        </div>
        <div class="d-flex align-items-center gap-2">
          <div class="input-group input-group-sm" style="width:240px">
            <span class="input-group-text bg-transparent"><i class="bi bi-search"></i></span>
            <input id="newsFilter" type="search" class="form-control" placeholder="Cari judul/kategori…">
          </div>
        </div>
      </div>

      <div class="card-body">
        <?php if(!empty($newsList)): ?>
          <div class="list-group list-group-flush">
            <?php foreach($newsList as $n):
              $nid   = (int)($n['id'] ?? 0);
              $title = trim($n['title'] ?? 'Tanpa Judul');
              $img   = trim($n['photo_path'] ?? '') ?: 'https://picsum.photos/900/600';
              $date  = trim($n['published_at'] ?? ($n['publish_date'] ?? $n['created_at'] ?? ''));
              $cat   = trim($n['category'] ?? '');
              $exRaw = strip_tags($n['content'] ?? '');
              $ex    = trim(mb_strimwidth($exRaw, 0, 140, '…'));
              // warna kategori
              [$catBg, $catFg] = catColor($cat);
              // data content untuk modal (aman tanpa HTML)
              $modalContent = htmlspecialchars($exRaw, ENT_QUOTES, 'UTF-8');
            ?>
            <div class="list-group-item py-3 news-item"
     data-title="<?php echo e(mb_strtolower($title)); ?>"
     data-cat="<?php echo e(mb_strtolower($cat)); ?>"
     data-comments="<?php echo (int)($n['comment_count'] ?? 0); ?>">
  <div class="d-flex w-100 align-items-start">
    <div class="cover shimmer me-3">
      <img src="<?php echo e($img); ?>" alt="" class="rounded"
           style="width:112px;height:72px;object-fit:cover;"
           onload="this.closest('.cover')?.classList.remove('shimmer')">
    </div>

    <div class="flex-grow-1">
      <div class="d-flex justify-content-between flex-wrap gap-2">
        <h6 class="mb-0 text-truncate" style="max-width:70%" title="<?php echo e($title); ?>">
          <?php echo e($title); ?>
        </h6>
        <div class="d-flex align-items-center gap-2">
          <span class="badge bg-primary-subtle text-primary-emphasis border">
            <i class="bi bi-chat-dots me-1"></i><?php echo (int)($n['comment_count'] ?? 0); ?>
          </span>
          <small class="text-muted">
            <i class="bi bi-clock me-1"></i><?php echo e($date ?: '—'); ?>
          </small>
        </div>
      </div>

      <div class="mt-1">
        <?php if($cat!==''): ?>
          <span class="badge border"
                style="background:<?php echo $catBg ?>; color:<?php echo $catFg ?>; border-color:rgba(0,0,0,.08)">
            <i class="bi bi-tag me-1"></i><?php echo e($cat); ?>
          </span>
        <?php endif; ?>
      </div>

      <div class="text-muted small mt-2"><?php echo e($ex ?: '—'); ?></div>

      <div class="d-flex gap-2 mt-3">
        <a class="btn btn-sm btn-outline-secondary"
           href="<?php echo e(base_url('index.php?news='.$nid.'#berita')); ?>">
          <i class="bi bi-link-45deg me-1"></i>Buka Halaman
        </a>

        <!-- Tombol modal -->
        <button type="button"
          class="btn btn-sm btn-primary btn-news-modal fx-btn"
          data-news-id="<?php echo $nid; ?>"
          data-title="<?php echo e($title); ?>"
          data-date="<?php echo e($date ?: '—'); ?>"
          data-cat="<?php echo e($cat); ?>"
          data-img="<?php echo e($img); ?>"
          data-content="<?php echo $modalContent; ?>">
          <i class="bi bi-eye me-1"></i>Lihat (Berita)
        </button>
      </div>
    </div>
  </div>
</div>





            
            <?php endforeach; ?>
          </div>
        <?php else: ?>
          <div class="alert alert-info mb-0">Belum ada berita.</div>
        <?php endif; ?>
      </div>

      <div class="card-footer bg-white text-muted small d-flex justify-content-between align-items-center">
        <span>Panel Berita dengan efek lembut & badge kategori berwarna.</span>
        <span class="d-none d-sm-inline">Klik <em>Lihat (Berita)</em> untuk pratinjau cepat.</span>
      </div>
    </div>

  </div>
<!-- MODAL BERITA + KOMENTAR -->
<div class="modal fade" id="newsModal" tabindex="-1" aria-hidden="true">
  <div class="modal-dialog modal-xl modal-dialog-centered modal-dialog-scrollable">
    <div class="modal-content">
      <div class="modal-header">
        <div>
          <h5 class="modal-title" id="nmTitle">Berita</h5>
          <div class="small text-muted" id="nmMeta"></div>
        </div>
        <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Tutup"></button>
      </div>
      <div class="modal-body">
        <div id="nmCoverWrap" class="mb-3 d-none">
          <img id="nmCover" src="" class="img-fluid rounded" style="max-height:420px;object-fit:cover;width:100%;" alt="cover">
        </div>
        <div id="nmContent" class="text-secondary" style="text-align:justify;"></div>
        <div id="nmSource" class="mt-3 d-none">
          <a id="nmSourceLink" class="btn btn-outline-secondary btn-sm" href="#" target="_blank" rel="noopener">
            <i class="bi bi-box-arrow-up-right me-1"></i>Sumber Asli
          </a>
        </div>

        <hr class="my-4">

        <!-- HEADER KOMENTAR -->
<div class="d-flex align-items-center justify-content-between mb-3 comment-header">
  <div class="d-flex align-items-center gap-2">
    <span class="icon-wrap"><i class="bi bi-chat-dots"></i></span>
    <h6 class="mb-0 title-underline">Komentar</h6>
    <span class="badge rounded-pill bg-primary-subtle text-primary-emphasis border comment-count" id="nmCommentCount">0</span>
    <span class="notif-dot" id="nmCommentDot" hidden title="Komentar baru"></span>
  </div>
  <div class="d-flex gap-2">
    <button class="btn btn-sm btn-outline-secondary" id="nmRefreshBtn">
      <i class="bi bi-arrow-clockwise me-1"></i>Segarkan
    </button>
  </div>
</div>

<!-- LIST KOMENTAR -->
<div id="nmComments" class="comment-list"></div>

        <div class="card p-3 mt-3">
          <h6 class="mb-2">Tinggalkan Komentar</h6>
          <form id="nmForm">
            <input type="hidden" name="csrf" value="<?php echo e(csrf_token()); ?>">
            <input type="hidden" name="ajax" value="comment">
            <input type="hidden" name="news_id" id="nmNewsId" value="">
            <!-- honeypot -->
            <input type="text" name="hp" value="" style="display:none !important" tabindex="-1" autocomplete="off">

            <div class="row g-2">
              <div class="col-md-6">
                <label class="form-label">Nama *</label>
                <input class="form-control" name="name" required>
              </div>
              <div class="col-md-6">
                <label class="form-label">Email (opsional)</label>
                <input type="email" class="form-control" name="email">
              </div>
            </div>
            <div class="mt-2">
              <label class="form-label">Komentar *</label>
              <textarea class="form-control" name="comment" rows="4" required></textarea>
            </div>
            <div class="d-flex align-items-center gap-2 mt-3">
              <button class="btn btn-success" type="submit">
                <i class="bi bi-send"></i> Kirim
              </button>
              <div id="nmFormMsg" class="small"></div>
            </div>
          </form>
          <div class="form-text mt-2">Komentar tampil setelah disetujui (jika moderasi aktif).</div>
        </div>
      </div>
      <div class="modal-footer">
        <a id="nmOpenPage" href="#" target="_blank" class="btn btn-outline-primary d-none">
          <i class="bi bi-box-arrow-up-right me-1"></i>Buka Halaman
        </a>
        <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Tutup</button>
      </div>
    </div>
  </div>
</div>
</section>





  <!-- CONTACT -->
  <section id="contact" class="section bg-light">
    <div class="container">
     <h2 class="section-title mb-4"><i class="bi bi-send-fill me-2 text-info"></i>Contact</h2>
      <?php if(!empty($ok)): ?><div class="alert alert-success"><?php echo e($ok) ?></div><?php endif; ?>
      <div class="row g-4">
        <div class="col-lg-6">
          <form method="post" action="<?php echo e(base_url('contact_submit.php')) ?>" class="card p-3 border-0 shadow-sm">
            <input type="hidden" name="csrf" value="<?php echo e(csrf_token()); ?>">
            <div class="row g-3">
              <div class="col-md-6"><label class="form-label">Nama</label><input class="form-control" name="name" required></div>
              <div class="col-md-6"><label class="form-label">Email</label><input type="email" class="form-control" name="email" required></div>
              <div class="col-12"><label class="form-label">Subjek</label><input class="form-control" name="subject"></div>
              <div class="col-12"><label class="form-label">Pesan</label><textarea class="form-control" name="message" rows="5" required></textarea></div>
              <div class="col-12"><button class="btn btn-primary btn-lg"><i class="bi bi-send me-1"></i>Kirim</button></div>
            </div>
          </form>
        </div>
        <div class="col-lg-6">
          <div class="card border-0 shadow-sm h-100">
            <div class="card-body">
              <h5 class="mb-3"><i class="bi bi-geo-alt me-2"></i>Alamat</h5>
              <p class="mb-4 text-muted">Masukkan alamat atau kota Anda di sini.</p>
              <h5 class="mb-3"><i class="bi bi-share me-2"></i>Sosial</h5>
              <div class="d-flex gap-2">
                <a class="btn btn-outline-secondary btn-sm" href="#"><i class="bi bi-github"></i></a>
                <a class="btn btn-outline-secondary btn-sm" href="#"><i class="bi bi-linkedin"></i></a>
                <a class="btn btn-outline-secondary btn-sm" href="#"><i class="bi bi-facebook"></i></a>
              </div>
            </div>
          </div>
        </div>
      </div>
      <div class="footer-min text-center text-muted mt-4">© <?php echo date('Y'); ?> <?php echo e($cfg['APP_NAME']) ?> — Dibuat dengan Bootstrap 5</div>
    </div>
  </section>


</main>

<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>

<script>
/* ============== Typing effect (hero) ============== */
document.addEventListener("DOMContentLoaded", function(){
  const el = document.getElementById("typed-text");
  if(!el) return;
  const text = "Halo, saya <?php echo addslashes($profile['full_name']); ?>.";
  let i = 0;
  (function type(){
    if(i < text.length){ el.textContent += text.charAt(i++); setTimeout(type, 100); }
    else{ el.classList.add("text-primary"); }
  })();
});

/* ============== Hero reveal once ============== */
(function () {
  const left=document.querySelector('#hero .reveal-left'), right=document.querySelector('#hero .reveal-right');
  if(!left||!right) return;
  const already=sessionStorage.getItem('heroAnimated');
  function show(){ left.classList.add('reveal-in'); right.classList.add('reveal-in'); }
  if (already){ show(); return; }
  setTimeout(()=>left.classList.add('reveal-in'),100);
  setTimeout(()=>right.classList.add('reveal-in'),250);
  sessionStorage.setItem('heroAnimated','1');
})();

/* ============== Skills progress + generic appear ============== */
(function(){
  const skillsWrap=document.getElementById('skills-list');
  const bars=skillsWrap?skillsWrap.querySelectorAll('.skill-bar'):[];
  const fadables=document.querySelectorAll('.fade-slide-up, .fade-raise');

  if('IntersectionObserver' in window){
    const io=new IntersectionObserver(entries=>{
      entries.forEach(e=>{
        if(e.isIntersecting){
          if(e.target.classList.contains('skill-bar')){
            const t=parseInt(e.target.getAttribute('data-target')||'0',10);
            e.target.style.width=Math.max(0,Math.min(100,t))+'%';
          }
          e.target.classList.add('appear');
          io.unobserve(e.target);
        }
      });
    },{threshold:.2, rootMargin:'0px 0px -10% 0px'});
    fadables.forEach(f=>io.observe(f)); bars.forEach(b=>io.observe(b));
  } else {
    fadables.forEach(f=>f.classList.add('appear'));
    bars.forEach(b=>{const t=parseInt(b.getAttribute('data-target')||'0',10); b.style.width=Math.max(0,Math.min(100,t))+'%';});
  }
})();

/* ============== About near + gentle parallax (desktop only) ============== */
(function(){
  const about=document.getElementById('about'); if(!about) return;
  const cards=about.querySelectorAll('.card');
  function updateNear(){
    const r=about.getBoundingClientRect();
    const near=r.top<window.innerHeight*0.65 && r.bottom>window.innerHeight*0.25;
    about.classList.toggle('near',!!near);
  }
  let raf;
  function onMouseMove(e){
    const r=about.getBoundingClientRect();
    const nx=(e.clientX-r.left)/Math.max(1,r.width)-.5, ny=(e.clientY-r.top)/Math.max(1,r.height)-.5;
    cancelAnimationFrame(raf);
    raf=requestAnimationFrame(()=>{
      cards.forEach((c,i)=>{
        const strength=3+(i%3);
        c.style.transform=`translateY(${-8 - ny*strength}px)`;
        c.style.boxShadow=`0 ${14+Math.abs(ny)*8}px ${28+Math.abs(nx)*14}px rgba(0,0,0,.12)`;
      });
    });
  }
  function onMouseLeave(){ cancelAnimationFrame(raf); cards.forEach(c=>{c.style.transform=''; c.style.boxShadow='';}); }
  window.addEventListener('scroll',updateNear,{passive:true}); window.addEventListener('resize',updateNear); updateNear();
  if(window.matchMedia('(pointer:fine)').matches){ about.addEventListener('mousemove',onMouseMove); about.addEventListener('mouseleave',onMouseLeave); }
})();

/* ============== Portfolio reveal + tilt + glare follow ============== */
(function(){
  const cards=document.querySelectorAll('#portfolio .fx-raise');
  if('IntersectionObserver' in window){
    const io=new IntersectionObserver(ents=>{
      ents.forEach(ent=>{ if(ent.isIntersecting){ ent.target.classList.add('appear'); io.unobserve(ent.target);} });
    },{threshold:.15, rootMargin:'0px 0px -8% 0px'});
    cards.forEach(c=>io.observe(c));
  } else { cards.forEach(c=>c.classList.add('appear')); }

  const allowTilt=window.matchMedia ? !window.matchMedia('(prefers-reduced-motion: reduce)').matches : true;
  if(allowTilt){
    document.querySelectorAll('#portfolio [data-tilt]').forEach(card=>{
      let raf,rect; const glare=card.querySelector('.glare');
      function onMove(e){
        rect = rect || card.getBoundingClientRect();
        const x=(e.clientX-rect.left)/rect.width-.5, y=(e.clientY-rect.top)/rect.height-.5;
        cancelAnimationFrame(raf);
        raf=requestAnimationFrame(()=>{ card.style.transform=`translateY(-6px) rotateX(${(-y*4).toFixed(2)}deg) rotateY(${(x*5).toFixed(2)}deg)`; });
        if(glare){
          const gx=((e.clientX-rect.left)/rect.width)*100, gy=((e.clientY-rect.top)/rect.height)*100;
          glare.style.background=`radial-gradient(600px 140px at ${gx}% ${gy-20}% , rgba(255,255,255,.35), transparent 60%), linear-gradient(120deg, rgba(255,255,255,.10), transparent 40% 60%, rgba(255,255,255,.10))`;
        }
      }
      function reset(){ cancelAnimationFrame(raf); card.style.transform=''; rect=null; }
      card.addEventListener('mousemove',onMove); card.addEventListener('mouseleave',reset);
    });
  }
})();

/* ============== Portfolio modal build ============== */
(function(){
  const titleEl=document.getElementById('projTitle'), dateEl=document.getElementById('projDate'),
        descEl=document.getElementById('projDesc'), linkEl=document.getElementById('projLink'),
        galEl=document.getElementById('projGallery');

  function buildCarousel(images){
    if(!images||!images.length) return '';
    const id='projCarousel';
    const inds=images.map((_,i)=>`<button type="button" data-bs-target="#${id}" data-bs-slide-to="${i}" ${i===0?'class="active" aria-current="true"':''} aria-label="Slide ${i+1}"></button>`).join('');
    const items=images.map((url,i)=>`<div class="carousel-item ${i===0?'active':''}"><img src="${url.replace(/"/g,'&quot;')}" alt="Slide ${i+1}" style="max-height:460px;object-fit:cover;width:100%;border-radius:.5rem;"></div>`).join('');
    const ctrls=(images.length>1)?`
      <button class="carousel-control-prev" type="button" data-bs-target="#${id}" data-bs-slide="prev"><span class="carousel-control-prev-icon" aria-hidden="true"></span><span class="visually-hidden">Sebelumnya</span></button>
      <button class="carousel-control-next" type="button" data-bs-target="#${id}" data-bs-slide="next"><span class="carousel-control-next-icon" aria-hidden="true"></span><span class="visually-hidden">Berikutnya</span></button>`:'';
    return `<div id="${id}" class="carousel slide proj-carousel" data-bs-ride="false">
      <div class="carousel-indicators">${inds}</div>
      <div class="carousel-inner">${items}</div>${ctrls}</div>`;
  }

  document.addEventListener('click', function(e){
    const btn=e.target.closest('.btn-detail'); if(!btn) return;
    const title=btn.getAttribute('data-title')||'Detail Proyek';
    const when =btn.getAttribute('data-when')||'';
    const desc =btn.getAttribute('data-desc')||'';
    const link =btn.getAttribute('data-link')||'';
    let images=[]; try{images=JSON.parse(btn.getAttribute('data-images')||'[]');}catch(_){}
    titleEl.textContent=title; dateEl.textContent=when?('Diterbitkan: '+when):''; descEl.textContent=desc;
    galEl.innerHTML=images.length?buildCarousel(images):'<img src="https://picsum.photos/900/600" class="img-fluid rounded" alt="Preview">';
    if(link){ linkEl.href=link; linkEl.classList.remove('d-none'); } else { linkEl.classList.add('d-none'); }
  });
})();

/* ============== Certification slider controls ============== */
(function(){
  const track=document.getElementById('certTrack'); if(!track) return;
  const prevBtns=document.querySelectorAll('.cert-prev'); const nextBtns=document.querySelectorAll('.cert-next');
  function pageWidth(){ const item=track.querySelector('.cert-item'); return item?(item.getBoundingClientRect().width+12):(track.clientWidth*.9); }
  function scrollByDir(dir){ track.scrollBy({left:dir*pageWidth(),behavior:'smooth'}); }
  prevBtns.forEach(b=>b.addEventListener('click',()=>scrollByDir(-1)));
  nextBtns.forEach(b=>b.addEventListener('click',()=>scrollByDir(1)));

  const appearEls=track.querySelectorAll('.fade-slide-up');
  if('IntersectionObserver' in window){
    const io=new IntersectionObserver(entries=>{
      entries.forEach(ent=>{ if(ent.isIntersecting){ ent.target.classList.add('appear'); io.unobserve(ent.target);} });
    },{threshold:.2});
    appearEls.forEach(el=>io.observe(el));
  } else { appearEls.forEach(el=>el.classList.add('appear')); }
})();

/* ============== Sidebar highlighter + autoclose (desktop & mobile) ============== */
(function(){
  const sections=['#hero','#about','#sertification','#portfolio','#contact'];
  const sideLinks=[...document.querySelectorAll('#sideNav .nav-link')];
  function setActive(hash){ sideLinks.forEach(a=>a.classList.toggle('is-active', a.getAttribute('data-section')===hash)); }
  if('IntersectionObserver' in window){
    const obs=new IntersectionObserver(entries=>{
      entries.forEach(ent=>{ if(ent.isIntersecting){ setActive('#'+ent.target.id); } });
    },{rootMargin:'-35% 0px -55% 0px', threshold:0.02});
    sections.forEach(id=>{ const el=document.querySelector(id); if(el) obs.observe(el); });
  } else { setActive(location.hash||'#hero'); }

  document.addEventListener('click', function(e){
    const a=e.target.closest('a.nav-link[href^="#"]'); if(!a) return;
    setActive(a.getAttribute('data-section'));
    const off=document.querySelector('.offcanvas.show');
    if(off && window.bootstrap){ (bootstrap.Offcanvas.getInstance(off)||new bootstrap.Offcanvas(off)).hide(); }
  });
})();
</script>
<script>
document.querySelectorAll('#sideNav .nav-link').forEach(el=>{
  el.addEventListener('pointerdown',e=>{
    const r=el.getBoundingClientRect();
    el.style.setProperty('--x', (e.clientX - r.left)+'px');
    el.style.setProperty('--y', (e.clientY - r.top)+'px');
  });
});
</script>
<script>
/* ===== Portfolio Enhancements ===== */
document.addEventListener('DOMContentLoaded', () => {
  // 1) Reveal: .fx-raise -> .is-in saat masuk viewport
  const io = new IntersectionObserver(es=>{
    es.forEach(e=>{
      if(e.isIntersecting){ e.target.classList.add('is-in'); }
    });
  },{threshold:.12});
  document.querySelectorAll('.portfolio-card.fx-raise').forEach(el=>io.observe(el));

  // 2) Tilt ringan (tanpa lib) untuk [data-tilt]
  const clamp = (n,min,max)=>Math.max(min,Math.min(max,n));
  document.querySelectorAll('.portfolio-card[data-tilt]').forEach(card=>{
    let rAF=null;
    const onMove = (e)=>{
      const r = card.getBoundingClientRect();
      const x = (e.clientX - r.left)/r.width;  // 0..1
      const y = (e.clientY - r.top)/r.height; // 0..1
      const rx = clamp((.5 - y)*6, -6, 6);
      const ry = clamp((x - .5)*8, -8, 8);
      if(rAF) cancelAnimationFrame(rAF);
      rAF = requestAnimationFrame(()=>{ card.style.transform = `rotateX(${rx}deg) rotateY(${ry}deg)`; });
    };
    const reset = ()=>{ card.style.transform = ''; };
    card.addEventListener('mouseenter', ()=>card.style.willChange='transform');
    card.addEventListener('mousemove', onMove);
    card.addEventListener('mouseleave', ()=>{ reset(); card.style.willChange='auto'; });
    card.addEventListener('touchend', reset, {passive:true});
  });

  // 3) Modal detail proyek: isi dari data-* (gambar utama + galeri)
  const modal = document.getElementById('projectDetailModal');
  const detailBtns = document.querySelectorAll('.btn-detail');
  const makeSlides = (arr)=>arr.map((src,i)=>`
      <div class="carousel-item ${i===0?'active':''}">
        <img src="${src}" class="d-block w-100" alt="Project image ${i+1}">
      </div>`).join('');

  detailBtns.forEach(btn=>{
    btn.addEventListener('click', ()=>{
      if(!modal) return;
      const t = btn.getAttribute('data-title') || 'Detail Project';
      const d = btn.getAttribute('data-desc')  || '';
      const l = btn.getAttribute('data-link')  || '';
      const w = btn.getAttribute('data-when')  || '';
      let imgs = [];
      try{ imgs = JSON.parse(btn.getAttribute('data-images')||'[]'); }catch(_){}
      // isi modal (sesuaikan id/selector internal modal-mu)
      const titleEl = modal.querySelector('.modal-title');
      const whenEl  = modal.querySelector('.modal-when');
      const descEl  = modal.querySelector('.modal-desc');
      const linkEl  = modal.querySelector('.modal-link');
      const carIn   = modal.querySelector('.modal-carousel .carousel-inner');

      if(titleEl) titleEl.textContent = t;
      if(whenEl)  whenEl.textContent  = w;
      if(descEl)  descEl.textContent  = d;
      if(linkEl){
        if(l){ linkEl.href = l; linkEl.classList.remove('d-none'); }
        else { linkEl.classList.add('d-none'); }
      }
      if(carIn)  carIn.innerHTML = makeSlides(imgs);
    });
  });
});
</script>
<script>
document.addEventListener("DOMContentLoaded", ()=>{
  const form  = document.getElementById("waForm");
  const modalEl = document.getElementById("whatsappModal");

  form.addEventListener("submit", e=>{
    e.preventDefault();

    const phone = (modalEl.dataset.phone || "").trim();
    if(!phone){
      alert("Nomor WhatsApp belum tersedia. Harap lengkapi di Admin » Profile.");
      return;
    }

    const name = encodeURIComponent((document.getElementById("waName").value || "").trim());
    const msg  = encodeURIComponent((document.getElementById("waMessage").value || "").trim());
    if(!msg){
      document.getElementById("waMessage").focus();
      return;
    }

    const text = `Halo, saya *${name || 'Pengunjung'}* ingin menghubungi Anda.%0A%0A${msg}`;
    const url  = `https://wa.me/${phone}?text=${text}`;
    window.open(url, "_blank");

    // Tutup modal & reset form
    const bsModal = bootstrap.Modal.getInstance(modalEl);
    if(bsModal) bsModal.hide();
    form.reset();
  });
});
</script>
<script>
(function(){
  const base = "<?php echo addslashes(base_url('index.php')); ?>";
  const modalEl = document.getElementById('newsModal');
  const titleEl = document.getElementById('nmTitle');
  const metaEl  = document.getElementById('nmMeta');
  const coverWrap = document.getElementById('nmCoverWrap');
  const coverImg  = document.getElementById('nmCover');
  const contentEl = document.getElementById('nmContent');
  const sourceWrap= document.getElementById('nmSource');
  const sourceA   = document.getElementById('nmSourceLink');
  const commentsEl= document.getElementById('nmComments');
  const formEl    = document.getElementById('nmForm');
  const formMsg   = document.getElementById('nmFormMsg');
  const newsIdEl  = document.getElementById('nmNewsId');
  const openPageA = document.getElementById('nmOpenPage');
  const refreshBtn= document.getElementById('nmRefreshBtn');
  const countEl   = document.getElementById('nmCommentCount');

  const MAX_PREVIEW_CHARS = 380;   // auto clamp jika > ini
  const MAX_DEPTH = 5;             // batas padding kedalaman

  function esc(str){ const d=document.createElement('div'); d.textContent=str??''; return d.innerHTML; }
  const clampText = (txt)=> (txt||'').length > MAX_PREVIEW_CHARS;

  // ===== util slide (animasi buka/tutup) =====
  function slideToggle(el, show){
    if(!el) return;
    const cur = !el.classList.contains('is-collapsed');
    const willShow = (typeof show==='boolean') ? show : cur;
    // jika ingin show: ukur tinggi lalu set
    if(willShow){
      el.classList.add('is-collapsed'); // pastikan height 0 dulu
      el.style.height = '0px';
      requestAnimationFrame(()=>{
        el.classList.remove('is-collapsed');
        const h = el.scrollHeight;
        el.style.height = h+'px';
        el.addEventListener('transitionend', ()=> el.style.height='', {once:true});
      });
    }else{
      el.style.height = el.scrollHeight+'px';
      requestAnimationFrame(()=>{
        el.style.height = '0px';
        el.addEventListener('transitionend', ()=>{
          el.classList.add('is-collapsed');
          el.style.height='';
        }, {once:true});
      });
    }
  }

  // ===== RENDER KOMENTAR (bertier + toggle + clamp + anim) =====
  function renderComments(list){
    const data = Array.isArray(list) ? list.map(x => ({
      id: Number(x.id ?? 0),
      parent_id: Number(x.parent_id ?? 0),
      name: x.name ?? 'Anonim',
      email: x.email ?? '',
      comment: x.comment ?? '',
      created_at: x.created_at ?? ''
    })) : [];

    (countEl||{}).textContent = data.length || 0;

    if(!data.length){
      commentsEl.innerHTML = '<div class="alert alert-secondary mb-0">Belum ada komentar.</div>';
      return;
    }

    // group by parent
    const byParent = {};
    data.forEach(c => { (byParent[c.parent_id||0] ||= []).push(c); });
    Object.values(byParent).forEach(arr => arr.sort((a,b)=> a.id - b.id)); // urut lama->baru

    const replyBtn = (id) => `
      <button type="button" class="btn btn-sm btn-outline-primary btn-reply" data-parent-id="${id}">
        <i class="bi bi-reply me-1"></i>Balas
      </button>`;

    function buildReplyForm(pid){
      const newsId = newsIdEl ? (newsIdEl.value||'') : '';
      return `
        <form class="card card-body border-0 shadow-sm p-3 reply-form" data-parent-id="${pid}">
          <input type="hidden" name="csrf" value="<?php echo e(csrf_token()); ?>">
          <input type="hidden" name="ajax" value="comment">
          <input type="hidden" name="news_id" value="${esc(newsId)}">
          <input type="hidden" name="parent_id" value="${Number(pid)}">
          <input type="text" name="hp" value="" style="display:none !important" tabindex="-1" autocomplete="off">
          <div class="row g-2">
            <div class="col-md-4"><input class="form-control" name="name" placeholder="Nama *" required></div>
            <div class="col-md-4"><input type="email" class="form-control" name="email" placeholder="Email (opsional)"></div>
          </div>
          <div class="mt-2"><textarea class="form-control" name="comment" rows="3" placeholder="Tulis balasan…" required></textarea></div>
          <div class="d-flex align-items-center gap-2 mt-2">
            <button class="btn btn-primary btn-sm" type="submit"><i class="bi bi-send"></i> Kirim Balasan</button>
            <button class="btn btn-light btn-sm btn-reply-cancel" type="button">Batal</button>
            <div class="small ms-2 reply-msg text-muted"></div>
          </div>
        </form>`;
    }

    // avatar inisial
    function avatarLetter(name){
      const n = (name||'').trim();
      return esc((n[0]||'?').toUpperCase());
    }

    function renderItem(c, depth){
      const d = Math.max(0, Math.min(MAX_DEPTH, depth));
      const childs = byParent[c.id] || [];
      const hasChild = childs.length > 0;
      const clamped = clampText(c.comment);

      return `
        <li class="cmt-item cmt-depth-${d}">
          <div class="cmt-card ${d>0?'cmt-branch':''}">
            <div class="cmt-head">
              <div class="cmt-avatar" aria-hidden="true">${avatarLetter(c.name)}</div>
              <div class="flex-grow-1">
                <div class="cmt-meta">
                  <span class="cmt-name">${esc(c.name)}</span>
                  ${c.email ? `<span class="cmt-email">• ${esc(c.email)}</span>` : ''}
                  <span class="cmt-date ms-auto">${esc(c.created_at)}</span>
                </div>

                <div class="cmt-body ${clamped?'clamped':''}" data-full="${clamped ? esc(c.comment) : ''}">
                  ${esc(c.comment)}
                </div>
                ${clamped ? `<span class="cmt-expand" data-expand-for="${c.id}">Lihat selengkapnya</span>` : ''}

                <div class="cmt-actions">
                  ${replyBtn(c.id)}
                  ${hasChild ? `<span class="cmt-chip">
                    <i class="bi bi-chat-left-text me-1"></i>${childs.length} balasan
                  </span>
                  <button type="button" class="btn btn-sm btn-outline-secondary btn-toggle-replies" data-target="${c.id}">
                    Tampilkan balasan
                  </button>` : ''}
                </div>

                <div class="reply-wrap mt-2 d-none" data-parent-id="${c.id}"></div>

                <div class="cmt-replies mt-2 is-collapsed" data-replies-of="${c.id}">
                  <ul class="cmt-list">
                    ${childs.map(ch => renderItem(ch, depth+1)).join('')}
                  </ul>
                </div>
              </div>
            </div>
          </div>
        </li>`;
    }

    const roots = (byParent[0] || byParent[null] || []).slice();
    commentsEl.innerHTML = `<ul class="cmt-list">${roots.map(c => renderItem(c, 0)).join('')}</ul>`;
    commentsEl._buildReplyForm = buildReplyForm;
  }

  async function loadNews(id){
    titleEl.textContent='Memuat…';
    metaEl.textContent=''; contentEl.innerHTML='';
    coverWrap.classList.add('d-none'); sourceWrap.classList.add('d-none');
    openPageA.classList.add('d-none');
    commentsEl.innerHTML = '<div class="text-muted">Memuat komentar…</div>';
    newsIdEl.value = id;

    const url = `${base}?ajax=news&id=${encodeURIComponent(id)}`;
    const res = await fetch(url, {headers:{'Accept':'application/json'}});
    const js  = await res.json().catch(()=>({ok:false,msg:'Gagal membaca data.'}));
    if(!js.ok){
      titleEl.textContent='Gagal memuat';
      commentsEl.innerHTML='<div class="alert alert-danger">'+esc(js.msg||'Terjadi kesalahan')+'</div>';
      return;
    }

    const n = js.news;
    titleEl.textContent = n.title || 'Berita';
    metaEl.textContent  = (n.published_at || '') + (n.category ? ` • ${n.category}` : '') + (n.author ? ` • Penulis: ${n.author}` : '');

    if (n.photo_path){ coverImg.src = n.photo_path; coverWrap.classList.remove('d-none'); }
    contentEl.innerHTML = n.content || '';

    if (n.source){ sourceA.href = n.source; sourceWrap.classList.remove('d-none'); }

    openPageA.href = `${base}?news=${encodeURIComponent(id)}#berita`;
    openPageA.classList.remove('d-none');

    renderComments(js.comments || []);
  }

  // buka modal saat klik tombol
  document.addEventListener('click', (e)=>{
    const btn = e.target.closest('.btn-news-modal');
    if(!btn) return;
    const id = parseInt(btn.getAttribute('data-news-id')||'0',10);
    if(!id) return;
    loadNews(id).then(()=>{
      const mdl = bootstrap.Modal.getOrCreateInstance(modalEl);
      mdl.show();
    });
  });

  // segarkan komentar
  refreshBtn?.addEventListener('click', ()=>{
    const id = parseInt(newsIdEl.value||'0',10);
    if(id) loadNews(id);
  });

  // submit komentar root
  formEl.addEventListener('submit', async (e)=>{
    e.preventDefault();
    formMsg.className='small text-muted';
    formMsg.textContent='Mengirim…';

    const fd = new FormData(formEl);
    fd.set('ajax','comment');
    fd.set('parent_id','0');

    try{
      const res = await fetch(base, {method:'POST', body:fd});
      const js  = await res.json();
      if(!js.ok) throw new Error(js.msg || 'Gagal menyimpan komentar.');
      formMsg.className='small text-success';
      formMsg.textContent = js.msg || 'Komentar tersimpan.';
      formEl.reset();
      renderComments(js.comments || []);
    }catch(err){
      formMsg.className='small text-danger';
      formMsg.textContent = err.message || 'Terjadi kesalahan jaringan.';
    }
  });

  // toggle form balasan
  commentsEl.addEventListener('click', (e)=>{
    const btn = e.target.closest('.btn-reply');
    if(!btn) return;
    const pid = Number(btn.getAttribute('data-parent-id')||0);
    const wrap = commentsEl.querySelector(`.reply-wrap[data-parent-id="${pid}"]`);
    if(!wrap) return;
    if(!wrap.dataset.filled){
      wrap.innerHTML = commentsEl._buildReplyForm ? commentsEl._buildReplyForm(pid) : '';
      wrap.dataset.filled = '1';
    }
    wrap.classList.toggle('d-none');
  });

  // batal balas
  commentsEl.addEventListener('click', (e)=>{
    const cancel = e.target.closest('.btn-reply-cancel');
    if(!cancel) return;
    const form = cancel.closest('.reply-form');
    if(form){
      const wrap = form.closest('.reply-wrap');
      if(wrap) wrap.classList.add('d-none');
    }
  });

  // submit balasan
  commentsEl.addEventListener('submit', async (e)=>{
    const rform = e.target.closest('.reply-form');
    if(!rform) return;
    e.preventDefault();

    const msg = rform.querySelector('.reply-msg');
    msg.className='small ms-2 reply-msg text-muted';
    msg.textContent='Mengirim…';

    const fd = new FormData(rform);
    fd.set('ajax','comment');

    try{
      const res = await fetch(base, { method:'POST', body: fd });
      const js  = await res.json();
      if(!js.ok) throw new Error(js.msg || 'Gagal mengirim balasan.');

      msg.className='small ms-2 reply-msg text-success';
      msg.textContent = js.msg || 'Balasan terkirim.';

      rform.reset();
      const wrap = rform.closest('.reply-wrap');
      if(wrap) wrap.classList.add('d-none');

      renderComments(js.comments || []);
    }catch(err){
      msg.className='small ms-2 reply-msg text-danger';
      msg.textContent = err.message;
    }
  });

  // toggle tampilkan balasan (slide)
  commentsEl.addEventListener('click', (e)=>{
    const tgl = e.target.closest('.btn-toggle-replies');
    if(!tgl) return;
    const id = tgl.getAttribute('data-target');
    const box = commentsEl.querySelector(`.cmt-replies[data-replies-of="${id}"]`);
    if(!box) return;

    const collapsed = box.classList.contains('is-collapsed');
    slideToggle(box, collapsed); // true=show, false=hide
    tgl.textContent = collapsed ? 'Sembunyikan balasan' : 'Tampilkan balasan';
  });

  // expand/collapse isi komentar panjang
  commentsEl.addEventListener('click', (e)=>{
    const ex = e.target.closest('.cmt-expand');
    if(!ex) return;
    const card = ex.previousElementSibling; // cmt-body
    if(!card) return;
    const expanded = !card.classList.contains('clamped');
    if(expanded){
      // collapse kembali ke clamp
      const full = card.getAttribute('data-full') || card.textContent;
      card.textContent = full;
      card.classList.add('clamped');
      ex.textContent = 'Lihat selengkapnya';
    } else {
      // expand penuh
      const full = card.getAttribute('data-full');
      if(full){ card.textContent = full; }
      card.classList.remove('clamped');
      ex.textContent = 'Sembunyikan';
    }
  });

})();
</script>


<script>
// Filter sederhana judul/kategori
document.addEventListener('DOMContentLoaded', function(){
  const f = document.getElementById('newsFilter');
  const items = document.querySelectorAll('.news-item');
  if(!f) return;
  f.addEventListener('input', () => {
    const q = f.value.trim().toLowerCase();
    items.forEach(it => {
      const hit = it.dataset.title.includes(q) || it.dataset.cat.includes(q);
      it.style.display = hit ? '' : 'none';
    });
  });
});

// Modal filler
document.addEventListener('click', function(e){
  const btn = e.target.closest('.btn-news-modal');
  if(!btn) return;

  const id   = btn.getAttribute('data-news-id');
  const ttl  = btn.getAttribute('data-title') || 'Berita';
  const dt   = btn.getAttribute('data-date')  || '—';
  const cat  = btn.getAttribute('data-cat')   || '';
  const img  = btn.getAttribute('data-img')   || '';
  const body = btn.getAttribute('data-content') || '';

  const mTitle = document.getElementById('newsModalTitle');
  const mMeta  = document.getElementById('newsModalMeta');
  const mImg   = document.getElementById('newsModalImg');
  const mBody  = document.getElementById('newsModalContent');
  const mLink  = document.getElementById('newsModalLink');

  mTitle.textContent = ttl;
  mMeta.textContent  = (dt ? dt : '—') + (cat ? ' • ' + cat : '');
  mBody.textContent  = body || '—';
  if(img){
    mImg.src = img; mImg.classList.remove('d-none');
  } else {
    mImg.classList.add('d-none'); mImg.removeAttribute('src');
  }
  mLink.href = "<?php echo e(base_url('index.php?news=')); ?>" + encodeURIComponent(id) + "#berita";

  const modal = new bootstrap.Modal(document.getElementById('newsModal'));
  modal.show();

  // efek ripple posisi pada tombol
  const r = btn.getBoundingClientRect();
  btn.style.setProperty('--x', (e.clientX - r.left)+'px');
  btn.style.setProperty('--y', (e.clientY - r.top)+'px');
});
</script>


</body>
</html>
