403Webshell
Server IP : 193.86.120.172  /  Your IP : 216.73.216.67
Web Server : Apache/2.4.63 (Unix)
System : Linux JServices 3.10.108 #86003 SMP Wed Oct 22 13:20:46 CST 2025 x86_64
User : kubec ( 1026)
PHP Version : 8.2.28
Disable Function : NONE
MySQL : OFF  |  cURL : ON  |  WGET : ON  |  Perl : ON  |  Python : OFF  |  Sudo : ON  |  Pkexec : OFF
Directory :  /volume1/web/hotel_jservices_cz/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : /volume1/web/hotel_jservices_cz/admin.html
<!DOCTYPE html>
<html lang="cs">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Administrace — Hotel DEMO</title>
<style>
/* ============================================================
   RESET & PROMĚNNÉ
   ============================================================ */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
:root {
  --blue-700:#1d4ed8; --blue-600:#2563eb; --blue-500:#3b82f6;
  --blue-100:#dbeafe; --blue-50:#eff6ff;
  --gray-900:#0f172a; --gray-800:#1e293b; --gray-700:#334155;
  --gray-600:#475569; --gray-500:#64748b; --gray-400:#94a3b8;
  --gray-300:#cbd5e1; --gray-200:#e2e8f0; --gray-100:#f1f5f9; --gray-50:#f8fafc;
  --white:#ffffff;
  --green-600:#16a34a; --green-100:#dcfce7; --green-50:#f0fdf4;
  --red-600:#dc2626;   --red-100:#fee2e2;   --red-50:#fef2f2;
  --amber-600:#d97706; --amber-100:#fef9c3;
  --sidebar-w: 220px;
  --topbar-h:  52px;
  --radius: 10px;
  --shadow: 0 1px 3px rgba(0,0,0,.08);
  --shadow-md: 0 4px 12px rgba(0,0,0,.1);
}
html, body { height: 100%; font-family: Arial, sans-serif; font-size: 14px;
  color: var(--gray-800); background: var(--gray-50); overflow: hidden; }

/* ============================================================
   PŘIHLAŠOVACÍ OBRAZOVKA
   ============================================================ */
#loginScreen {
  position: fixed; inset: 0; background: var(--gray-50);
  display: flex; align-items: center; justify-content: center; z-index: 999;
}
.login-card {
  background: var(--white); border: 1px solid var(--gray-200);
  border-radius: 14px; padding: 36px 32px; width: 100%; max-width: 380px;
  box-shadow: var(--shadow-md);
}
.login-logo { font-size: 16px; font-weight: 600; color: var(--blue-600); margin-bottom: 6px; }
.login-sub  { font-size: 13px; color: var(--gray-500); margin-bottom: 28px; }
.login-field { margin-bottom: 14px; }
.login-field label { display: block; font-size: 12px; font-weight: 500; color: var(--gray-700); margin-bottom: 5px; }
.login-field input {
  width: 100%; border: 1px solid var(--gray-200); border-radius: 8px;
  padding: 10px 12px; font-size: 14px; color: var(--gray-900); font-family: inherit;
  transition: border-color .15s;
}
.login-field input:focus { outline: none; border-color: var(--blue-500); box-shadow: 0 0 0 3px var(--blue-50); }
.login-zapamatovat { display: flex; align-items: center; gap: 8px; margin-bottom: 20px; font-size: 13px; color: var(--gray-600); }
.login-zapamatovat input[type=checkbox] { accent-color: var(--blue-600); width: 15px; height: 15px; }
.login-error { background: var(--red-100); color: var(--red-600); border-radius: 8px; padding: 10px 12px; font-size: 13px; margin-bottom: 14px; display: none; }
.btn-login {
  width: 100%; padding: 11px; border: none; border-radius: 8px;
  background: var(--blue-600); color: var(--white); font-size: 14px;
  font-weight: 500; cursor: pointer; font-family: inherit;
}
.btn-login:hover { background: var(--blue-700); }
.btn-login:disabled { opacity: .6; cursor: not-allowed; }

/* ============================================================
   SHELL — SIDEBAR + TOPBAR + OBSAH
   ============================================================ */
#appShell { display: none; height: 100vh; overflow: hidden; }

/* Sidebar */
.sidebar {
  position: fixed; left: 0; top: 0; bottom: 0; width: var(--sidebar-w);
  background: var(--gray-900); display: flex; flex-direction: column; z-index: 50;
}
.sb-logo {
  padding: 0 16px; height: var(--topbar-h);
  display: flex; align-items: center;
  border-bottom: 1px solid rgba(255,255,255,.08);
  font-size: 14px; font-weight: 600; color: var(--white); letter-spacing: .3px;
}
.sb-logo span { color: var(--blue-400, #60a5fa); }
.sb-nav { flex: 1; padding: 10px 8px; overflow-y: auto; }
.sb-section { font-size: 10px; font-weight: 600; letter-spacing: 1px;
  color: rgba(255,255,255,.3); padding: 14px 8px 6px; text-transform: uppercase; }
.sb-item {
  display: flex; align-items: center; gap: 9px;
  padding: 9px 10px; border-radius: 8px; cursor: pointer;
  font-size: 13px; color: rgba(255,255,255,.6);
  transition: background .15s, color .15s; margin-bottom: 1px;
  user-select: none; position: relative;
}
.sb-item:hover { background: rgba(255,255,255,.07); color: rgba(255,255,255,.9); }
.sb-item.active { background: var(--blue-600); color: var(--white); }
.sb-item .icon { font-size: 16px; flex-shrink: 0; }
.sb-badge {
  position: absolute; right: 8px; top: 50%; transform: translateY(-50%);
  background: var(--red-600); color: var(--white); font-size: 10px;
  font-weight: 600; min-width: 18px; height: 18px; border-radius: 9px;
  display: flex; align-items: center; justify-content: center; padding: 0 4px;
}
.sb-bottom {
  padding: 10px 8px 12px;
  border-top: 1px solid rgba(255,255,255,.08);
}
.sb-user {
  display: flex; align-items: center; gap: 9px;
  padding: 8px 10px; border-radius: 8px;
  cursor: pointer; transition: background .15s;
}
.sb-user:hover { background: rgba(255,255,255,.07); }
.sb-avatar {
  width: 30px; height: 30px; border-radius: 50%;
  background: var(--blue-600); color: var(--white);
  display: flex; align-items: center; justify-content: center;
  font-size: 11px; font-weight: 600; flex-shrink: 0;
}
.sb-user-info { min-width: 0; }
.sb-user-name { font-size: 12px; font-weight: 500; color: var(--white);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.sb-user-role { font-size: 11px; color: rgba(255,255,255,.4); }
.sb-logout {
  display: flex; align-items: center; gap: 9px;
  padding: 7px 10px; border-radius: 8px; cursor: pointer;
  font-size: 12px; color: rgba(255,255,255,.4);
  transition: color .15s, background .15s; margin-top: 2px;
}
.sb-logout:hover { color: var(--red-600); background: rgba(255,255,255,.05); }

/* Topbar */
.topbar {
  position: fixed; left: var(--sidebar-w); right: 0; top: 0; height: var(--topbar-h);
  background: var(--white); border-bottom: 1px solid var(--gray-200);
  display: flex; align-items: center; justify-content: space-between;
  padding: 0 24px; z-index: 40;
}
.topbar-title { font-size: 15px; font-weight: 600; color: var(--gray-900); }
.topbar-right  { display: flex; align-items: center; gap: 10px; }

/* Obsah */
.content {
  position: fixed;
  left: var(--sidebar-w); right: 0;
  top: var(--topbar-h); bottom: 0;
  overflow-y: auto; padding: 24px;
}

/* ============================================================
   SPOLEČNÉ KOMPONENTY
   ============================================================ */
.card {
  background: var(--white); border: 1px solid var(--gray-200);
  border-radius: var(--radius); box-shadow: var(--shadow);
}
.card-header {
  padding: 14px 18px; border-bottom: 1px solid var(--gray-100);
  display: flex; align-items: center; justify-content: space-between;
}
.card-title { font-size: 13px; font-weight: 600; color: var(--gray-900); }
.card-body  { padding: 18px; }

/* Tlačítka */
.btn {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 8px 14px; border-radius: 8px; font-size: 13px; font-weight: 500;
  border: none; cursor: pointer; font-family: inherit; transition: opacity .15s;
  text-decoration: none; white-space: nowrap;
}
.btn:active { opacity: .8; }
.btn-primary   { background: var(--blue-600); color: var(--white); }
.btn-primary:hover { background: var(--blue-700); }
.btn-secondary { background: var(--white); color: var(--gray-700); border: 1px solid var(--gray-200); }
.btn-secondary:hover { background: var(--gray-50); }
.btn-danger    { background: var(--red-100); color: var(--red-600); }
.btn-danger:hover { background: #fecaca; }
.btn-success   { background: var(--green-100); color: var(--green-600); }
.btn-sm { padding: 5px 10px; font-size: 12px; border-radius: 6px; }
.btn:disabled  { opacity: .45; cursor: not-allowed; }

/* Formulářové prvky */
.field { margin-bottom: 14px; }
.field label { display: block; font-size: 12px; font-weight: 500; color: var(--gray-700); margin-bottom: 5px; }
.field input, .field select, .field textarea {
  width: 100%; border: 1px solid var(--gray-200); border-radius: 8px;
  padding: 9px 11px; font-size: 13px; color: var(--gray-900);
  background: var(--white); font-family: inherit; transition: border-color .15s;
}
.field input:focus, .field select:focus, .field textarea:focus {
  outline: none; border-color: var(--blue-500); box-shadow: 0 0 0 3px var(--blue-50);
}
.field textarea { resize: vertical; min-height: 72px; }
.field-row { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.field-row-3 { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 12px; }
.field-hint { font-size: 11px; color: var(--gray-400); margin-top: 4px; }

/* Toggle switch */
.toggle-wrap { display: flex; align-items: center; gap: 10px; }
.toggle {
  width: 40px; height: 22px; border-radius: 11px; background: var(--gray-200);
  position: relative; cursor: pointer; flex-shrink: 0;
  transition: background .2s; border: none;
}
.toggle.on { background: var(--blue-600); }
.toggle::after {
  content: ''; position: absolute;
  width: 18px; height: 18px; background: var(--white);
  border-radius: 50%; top: 2px; left: 2px;
  transition: left .2s; box-shadow: 0 1px 3px rgba(0,0,0,.2);
}
.toggle.on::after { left: 20px; }
.toggle-label { font-size: 13px; color: var(--gray-700); }

/* Badges */
.badge {
  display: inline-flex; align-items: center; padding: 2px 8px;
  border-radius: 20px; font-size: 11px; font-weight: 500; white-space: nowrap;
}
.badge-blue   { background: var(--blue-100); color: var(--blue-700); }
.badge-green  { background: var(--green-100); color: var(--green-600); }
.badge-amber  { background: var(--amber-100); color: var(--amber-600); }
.badge-red    { background: var(--red-100); color: var(--red-600); }
.badge-gray   { background: var(--gray-100); color: var(--gray-500); }

/* Tabulka */
.table-wrap { overflow-x: auto; }
table { width: 100%; border-collapse: collapse; font-size: 13px; }
th { text-align: left; font-size: 11px; font-weight: 600; letter-spacing: .5px;
  color: var(--gray-500); padding: 10px 12px; border-bottom: 1px solid var(--gray-200);
  background: var(--gray-50); white-space: nowrap; }
td { padding: 11px 12px; border-bottom: 1px solid var(--gray-100); vertical-align: middle; }
tr:last-child td { border-bottom: none; }
tr:hover td { background: var(--gray-50); }
.td-akce { display: flex; gap: 6px; }

/* Statistické karty */
.stat-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 14px; margin-bottom: 20px; }
.stat-card { background: var(--white); border: 1px solid var(--gray-200); border-radius: var(--radius); padding: 16px 18px; }
.stat-label { font-size: 11px; font-weight: 600; letter-spacing: .5px; color: var(--gray-400); text-transform: uppercase; margin-bottom: 6px; }
.stat-val   { font-size: 24px; font-weight: 600; color: var(--gray-900); line-height: 1; margin-bottom: 4px; }
.stat-val.blue  { color: var(--blue-600); }
.stat-val.green { color: var(--green-600); }
.stat-val.amber { color: var(--amber-600); }
.stat-sub   { font-size: 12px; color: var(--gray-400); }
.stat-sub.up   { color: var(--green-600); }
.stat-sub.down { color: var(--red-600); }

/* Alert */
.alert { padding: 11px 14px; border-radius: 8px; font-size: 13px; margin-bottom: 14px; }
.alert-error { background: var(--red-100); color: #991b1b; }
.alert-info  { background: var(--blue-50); color: var(--blue-700); }
.alert-ok    { background: var(--green-100); color: #166534; }
.alert-warn  { background: var(--amber-100); color: #92400e; }

/* Spinner */
.spinner { width: 18px; height: 18px; border: 2px solid var(--gray-200);
  border-top-color: var(--blue-600); border-radius: 50%;
  animation: spin .7s linear infinite; display: inline-block; }
@keyframes spin { to { transform: rotate(360deg); } }
.loading-row { text-align: center; padding: 32px; color: var(--gray-400); font-size: 13px; }

/* Modal */
.modal-overlay {
  position: fixed; inset: 0; background: rgba(0,0,0,.4);
  display: flex; align-items: center; justify-content: center;
  z-index: 200; padding: 16px;
}
.modal {
  background: var(--white); border-radius: 14px; width: 100%;
  max-width: 520px; max-height: 90vh; overflow-y: auto;
  box-shadow: var(--shadow-md);
}
.modal-header {
  padding: 18px 22px; border-bottom: 1px solid var(--gray-200);
  display: flex; align-items: center; justify-content: space-between;
}
.modal-title { font-size: 15px; font-weight: 600; color: var(--gray-900); }
.modal-close { background: none; border: none; font-size: 20px; cursor: pointer;
  color: var(--gray-400); line-height: 1; padding: 2px 6px; border-radius: 4px; }
.modal-close:hover { background: var(--gray-100); color: var(--gray-700); }
.modal-body   { padding: 22px; }
.modal-footer { padding: 14px 22px; border-top: 1px solid var(--gray-200);
  display: flex; justify-content: flex-end; gap: 8px; }

/* Stránkování */
.pagination { display: flex; align-items: center; gap: 6px; padding: 12px 16px; border-top: 1px solid var(--gray-100); }
.page-btn { background: none; border: 1px solid var(--gray-200); border-radius: 6px;
  padding: 5px 10px; font-size: 12px; cursor: pointer; color: var(--gray-600); }
.page-btn:hover { background: var(--gray-50); }
.page-btn.active { background: var(--blue-600); color: var(--white); border-color: var(--blue-600); }
.page-btn:disabled { opacity: .4; cursor: not-allowed; }
.page-info { font-size: 12px; color: var(--gray-400); margin-left: auto; }

/* Filtrační lišta */
.filter-bar { display: flex; gap: 8px; padding: 14px 18px; border-bottom: 1px solid var(--gray-100); flex-wrap: wrap; }
.filter-bar input, .filter-bar select {
  border: 1px solid var(--gray-200); border-radius: 8px;
  padding: 7px 11px; font-size: 13px; color: var(--gray-900);
  background: var(--white); font-family: inherit;
}
.filter-bar input:focus, .filter-bar select:focus {
  outline: none; border-color: var(--blue-500);
}
.filter-bar input[type=search] { flex: 1; min-width: 160px; }

/* Responsivita */
@media (max-width: 900px) {
  .sidebar { transform: translateX(-100%); transition: transform .25s; }
  .sidebar.open { transform: translateX(0); }
  .topbar { left: 0; }
  .content { left: 0; }
  .stat-grid { grid-template-columns: repeat(2,1fr); }
}
@media (max-width: 600px) {
  .stat-grid { grid-template-columns: 1fr 1fr; }
  .field-row, .field-row-3 { grid-template-columns: 1fr; }
  .content { padding: 16px; }
}

/* ============================================================
   GANTT KALENDÁŘ
   ============================================================ */
.gantt-wrap { overflow-x: auto; }
.gantt-table { border-collapse: collapse; font-size: 12px; min-width: 100%; }
.gantt-room-col { width: 130px; min-width: 130px; }
.gantt-th-room {
  position: sticky; left: 0; z-index: 3;
  background: var(--gray-50); border-right: 1px solid var(--gray-200);
  border-bottom: 1px solid var(--gray-200);
  padding: 8px 12px; font-size: 10px; font-weight: 600;
  letter-spacing: .5px; color: var(--gray-400); text-transform: uppercase;
}
.gantt-th-day {
  min-width: 44px; width: 44px; text-align: center;
  padding: 6px 0; border-right: 1px solid var(--gray-100);
  border-bottom: 1px solid var(--gray-200); background: var(--gray-50);
}
.gantt-th-day .day-name { font-size: 9px; color: var(--gray-400); display: block; margin-bottom: 2px; }
.gantt-th-day .day-num  { font-size: 12px; color: var(--gray-700); font-weight: 500; }
.gantt-th-day.today .day-num {
  background: var(--blue-600); color: var(--white);
  border-radius: 50%; width: 22px; height: 22px;
  display: inline-flex; align-items: center; justify-content: center;
}
.gantt-th-day.weekend { background: #fafbff; }
.gantt-td-room {
  position: sticky; left: 0; z-index: 2;
  background: var(--white); border-right: 1px solid var(--gray-200);
  border-bottom: 1px solid var(--gray-100);
  padding: 8px 12px; white-space: nowrap;
}
.gantt-td-room:hover { background: var(--gray-50); }
.gantt-room-cislo { font-size: 13px; font-weight: 500; color: var(--gray-900); }
.gantt-room-typ   { font-size: 11px; color: var(--gray-400); }
.gantt-td-day {
  border-right: 1px solid var(--gray-100);
  border-bottom: 1px solid var(--gray-100);
  position: relative; height: 60px;
  min-width: 44px; width: 44px;
}
.gantt-td-day.weekend { background: #fafbff; }
.gantt-bar {
  position: absolute; top: 4px; height: 52px;
  border-radius: 6px; display: flex; align-items: center;
  padding: 0 6px; font-size: 11px; font-weight: 500;
  white-space: nowrap; overflow: hidden; cursor: pointer;
  z-index: 1; left: 2px;
  transition: opacity .15s;
  flex-direction: column; justify-content: center;
}
.gantt-bar:hover { opacity: .85; }
.gantt-bar.dragging { opacity: .6; cursor: grabbing; z-index: 10; }
.gantt-bar.drag-invalid { background: var(--red-100) !important; color: var(--red-600) !important; border-color: #fca5a5 !important; }
.gantt-bar .resize-handle {
  position: absolute; top: 0; width: 8px; height: 100%;
  cursor: col-resize; z-index: 2; opacity: 0;
  transition: opacity .15s;
}
.gantt-bar:hover .resize-handle { opacity: 1; }
.gantt-bar .resize-handle-l { left: 0; border-radius: 4px 0 0 4px; background: rgba(0,0,0,.15); }
.gantt-bar .resize-handle-r { right: 0; border-radius: 0 4px 4px 0; background: rgba(0,0,0,.15); }
.gantt-td-day.drop-target { background: var(--blue-50); outline: 2px dashed var(--blue-400); }
.gantt-td-day.drop-invalid { background: var(--red-100) !important; }
.gantt-bar.potvrzena { background: var(--green-100); color: #166534; border: 1px solid #bbf7d0; }
.gantt-bar.ceka      { background: var(--amber-100); color: var(--amber-600); border: 1px solid #fde68a; }
.gantt-bar.blokovano { background: var(--gray-100); color: var(--gray-500); border: 1px solid var(--gray-200); }
.gantt-bar.ceka-schvaleni { background: #ede9fe; color: #6d28d9; border: 1px solid #d8b4fe; }

/* Nav přes měsíce */
.gantt-nav { display: flex; align-items: center; gap: 10px; }
.gantt-nav-btn {
  background: none; border: 1px solid var(--gray-200); border-radius: 7px;
  width: 30px; height: 30px; cursor: pointer; font-size: 15px;
  color: var(--gray-500); display: flex; align-items: center; justify-content: center;
}
.gantt-nav-btn:hover { background: var(--gray-100); }
.gantt-period { font-size: 14px; font-weight: 500; color: var(--gray-900); min-width: 180px; text-align: center; }

/* Legenda */
.gantt-legenda { display: flex; gap: 16px; padding: 10px 18px; border-top: 1px solid var(--gray-100); flex-wrap: wrap; }
.gantt-leg-item { display: flex; align-items: center; gap: 6px; font-size: 12px; color: var(--gray-500); }
.gantt-leg-dot  { width: 12px; height: 12px; border-radius: 3px; }

/* ============================================================
   SEKCE — PŘEHLED (dashboard)
   ============================================================ */
.dnes-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; margin-top: 20px; }
.dnes-list { display: flex; flex-direction: column; gap: 8px; }
.dnes-item {
  display: flex; align-items: center; gap: 10px;
  background: var(--white); border: 1px solid var(--gray-200);
  border-radius: 8px; padding: 10px 12px;
}
.dnes-pokoj { font-weight: 600; color: var(--blue-600); font-size: 13px; min-width: 36px; }
.dnes-host  { flex: 1; font-size: 13px; color: var(--gray-900); }
.dnes-cas   { font-size: 12px; color: var(--gray-500); }

/* ============================================================
   HESLO — MODAL
   ============================================================ */
.heslo-strength { height: 4px; border-radius: 2px; background: var(--gray-200);
  margin-top: 6px; overflow: hidden; }
.heslo-strength-bar { height: 100%; border-radius: 2px; transition: width .3s, background .3s; width: 0; }
.notif-item { display:flex; align-items:flex-start; gap:10px; padding:10px 16px; cursor:pointer; border-bottom:0.5px solid var(--gray-50); transition:background .1s; }
.notif-item:hover { background:var(--gray-50); }
.notif-item.nova { background:#eff6ff; }
.notif-item.nova:hover { background:#dbeafe; }
.notif-ikona { font-size:18px; flex-shrink:0; margin-top:1px; }
.notif-text { font-size:13px; color:var(--gray-700); line-height:1.4; }
.notif-cas { font-size:11px; color:var(--gray-400); margin-top:2px; }
</style>
</head>
<body>

<!-- ============================================================
     PŘIHLÁŠENÍ
     ============================================================ -->
<div id="loginScreen">
  <div class="login-card">
    <div class="login-logo" id="loginLogo">Hotel DEMO</div>
    <div class="login-sub">Administrace — přihlaste se</div>
    <div class="login-error" id="loginError"></div>
    <div class="login-field">
      <label for="loginJmeno">Přihlašovací jméno</label>
      <input type="text" id="loginJmeno" autocomplete="username" placeholder="Přihlašovací jméno">
    </div>
    <div class="login-field">
      <label for="loginHeslo">Heslo</label>
      <input type="password" id="loginHeslo" autocomplete="current-password">
    </div>
    <div class="login-zapamatovat">
      <input type="checkbox" id="loginZapamatovat">
      <label for="loginZapamatovat">Zapamatovat mě na 30 dní</label>
    </div>
    <button class="btn-login" id="btnLogin" onclick="prihlasit()">Přihlásit se</button>
  </div>
</div>

<!-- ============================================================
     APP SHELL
     ============================================================ -->
<div id="appShell">

  <!-- SIDEBAR -->
  <aside class="sidebar" id="sidebar">
    <div class="sb-logo" id="sbLogo">Hotel <span>DEMO</span></div>
    <nav class="sb-nav">
      <div class="sb-section">Přehled</div>
      <div class="sb-item active" onclick="naSecci('prehled')" id="nav-prehled">
        <span class="icon">📊</span> Přehled
      </div>
      <div class="sb-item" onclick="naSecci('kalendar')" id="nav-kalendar">
        <span class="icon">📅</span> Kalendář
      </div>

      <div class="sb-section" data-sekce="rezervace" id="sbSekceRezervace">Rezervace</div>
      <div class="sb-item" onclick="naSecci('rezervace')" id="nav-rezervace">
        <span class="icon">📋</span> Rezervace
        <span class="sb-badge" id="badgeCekajici" style="display:none"></span>
      </div>
      <div class="sb-item" onclick="naSecci('zakaznici')" id="nav-zakaznici">
        <span class="icon">👥</span> Zákazníci
      </div>
      <div class="sb-item" onclick="naSecci('hodnoceni')" id="nav-hodnoceni">
        <span class="icon">⭐</span> Hodnocení
      </div>
      <div class="sb-item" onclick="naSecci('statistiky')" id="nav-statistiky">
        <span class="icon">📊</span> Statistiky
      </div>

      <div class="sb-section" id="sbSekceHotel" data-sekce="hotel">Hotel</div>
      <div class="sb-item" onclick="naSecci('pokoje')" id="nav-pokoje">
        <span class="icon">🚪</span> Pokoje
      </div>
      <div class="sb-item" onclick="naSecci('doplnky')" id="nav-doplnky">
        <span class="icon">➕</span> Doplňky
      </div>

      <div class="sb-section" id="sbSekceSystem">Systém</div>
      <div class="sb-item" onclick="naSecci('uzivatele')" id="nav-uzivatele">
        <span class="icon">🔐</span> Uživatelé
      </div>
      <div class="sb-item" onclick="naSecci('nastaveni')" id="nav-nastaveni">
        <span class="icon">⚙️</span> Nastavení
      </div>
    </nav>
    <div class="sb-bottom">
      <div class="sb-user" onclick="otevritHesloModal()">
        <div class="sb-avatar" id="sbAvatar">?</div>
        <div class="sb-user-info">
          <div class="sb-user-name" id="sbUserName">—</div>
          <div class="sb-user-role" id="sbUserRole">—</div>
        </div>
      </div>
      <div class="sb-logout" onclick="odhlasit()">↩ Odhlásit se</div>
    </div>
  </aside>

  <!-- TOPBAR -->
  <header class="topbar">
    <div style="display:flex;align-items:center;gap:12px">
      <button onclick="toggleSidebar()" style="display:none;background:none;border:none;cursor:pointer;font-size:20px;color:var(--gray-500)" id="btnMenu">☰</button>
      <div class="topbar-title" id="topbarTitle">Přehled</div>
    </div>
    <div style="display:flex;align-items:center;gap:12px">
      <div style="position:relative" id="notifWrap">
        <button onclick="notifToggle()" id="notifBtn" style="background:none;border:none;cursor:pointer;font-size:20px;color:var(--gray-500);position:relative;width:36px;height:36px;display:flex;align-items:center;justify-content:center;border-radius:8px" title="Notifikace">
          🔔
          <span id="notifBadge" style="display:none;position:absolute;top:2px;right:2px;background:#dc2626;color:#fff;font-size:10px;font-weight:700;border-radius:10px;min-width:16px;height:16px;line-height:16px;text-align:center;padding:0 4px"></span>
        </button>
        <div id="notifDropdown" style="display:none;position:absolute;right:0;top:44px;width:340px;background:#fff;border-radius:10px;box-shadow:0 8px 32px rgba(0,0,0,.15);border:0.5px solid var(--gray-200);z-index:1000;max-height:420px;overflow-y:auto">
          <div style="display:flex;align-items:center;justify-content:space-between;padding:12px 16px;border-bottom:1px solid var(--gray-100)">
            <span style="font-size:13px;font-weight:600">Nevyřízené položky</span>
          </div>
          <div id="notifSeznam" style="padding:8px 0"><div style="padding:16px;text-align:center;color:var(--gray-400);font-size:13px">Načítám…</div></div>
        </div>
      </div>
      <div class="topbar-right" id="topbarRight"></div>
    </div>
  </header>

  <!-- OBSAH -->
  <main class="content" id="mainContent">
    <div class="loading-row"><div class="spinner"></div></div>
  </main>

</div>

<!-- ============================================================
     MODAL — ZMĚNA HESLA
     ============================================================ -->
<div class="modal-overlay" id="hesloModal" style="display:none" onclick="if(event.target===this)zavritModal('hesloModal')">
  <div class="modal">
    <div class="modal-header">
      <div class="modal-title">Změna hesla</div>
      <button class="modal-close" onclick="zavritModal('hesloModal')">×</button>
    </div>
    <div class="modal-body">
      <div id="hesloAlert"></div>
      <div class="field">
        <label>Současné heslo</label>
        <input type="password" id="hesloStare" autocomplete="current-password">
      </div>
      <div class="field">
        <label>Nové heslo</label>
        <input type="password" id="hesloNove" oninput="hesloSila(this.value)" autocomplete="new-password">
        <div class="heslo-strength"><div class="heslo-strength-bar" id="hesloBar"></div></div>
      </div>
      <div class="field">
        <label>Nové heslo znovu</label>
        <input type="password" id="hesloZnovu" autocomplete="new-password">
      </div>
    </div>
    <div class="modal-footer">
      <button class="btn btn-secondary" onclick="zavritModal('hesloModal')">Zrušit</button>
      <button class="btn btn-primary" onclick="ulozitHeslo()">Uložit heslo</button>
    </div>
  </div>
</div>

<script>
// ============================================================
//  KONFIGURACE
// ============================================================
const API  = '/api/index.php';
let APP = {
  user:      null,
  token:     null,
  sekce:     'prehled',
  nastaveni: {},
  // Data pro Gantt
  ganttOd:   null,
  ganttDo:   null,
};

// Pomocné zkratky
const $  = id => document.getElementById(id);
const esc = s => String(s||'').replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/"/g,'&quot;');

// ============================================================
//  PŘIHLÁŠENÍ / SESSION
// ============================================================
async function init() {
  // Zjistit zda máme uloženou session
  const token = localStorage.getItem('hd_token') || sessionStorage.getItem('hd_token');
  if (token) {
    APP.token = token;
    try {
      const r = await apiFetch('auth', 'check');
      if (r.ok) {
        APP.user      = r.data.user;
        APP.opravneni = r.data.opravneni || {};
        await spustitApp();
        return;
      }
    } catch(e) {}
  }
  $('loginScreen').style.display = 'flex';
}

async function prihlasit() {
  const login      = $('loginJmeno').value.trim();
  const heslo      = $('loginHeslo').value;
  const zapamatovat= $('loginZapamatovat').checked;
  const errEl      = $('loginError');
  const btn        = $('btnLogin');

  errEl.style.display = 'none';
  if (!login || !heslo) {
    errEl.textContent = 'Vyplňte přihlašovací jméno a heslo.';
    errEl.style.display = 'block';
    return;
  }

  btn.disabled = true;
  btn.textContent = 'Přihlašuji…';

  try {
    const r = await fetch(API + '/auth/login', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      credentials: 'include',
      body: JSON.stringify({ login, heslo, zapamatovat }),
    });
    const d = await r.json();

    if (!d.ok) {
      errEl.textContent = d.error || 'Chyba přihlášení.';
      errEl.style.display = 'block';
      btn.disabled = false;
      btn.textContent = 'Přihlásit se';
      return;
    }

    APP.token     = d.data.token;
    APP.user      = d.data.user;
    APP.opravneni = d.data.opravneni || {};
    const store = zapamatovat ? localStorage : sessionStorage;
    store.setItem('hd_token', APP.token);

    await spustitApp();
  } catch(e) {
    errEl.textContent = 'Nepodařilo se připojit k serveru.';
    errEl.style.display = 'block';
    btn.disabled = false;
    btn.textContent = 'Přihlásit se';
  }
}

$('loginHeslo').addEventListener('keydown', e => { if (e.key === 'Enter') prihlasit(); });

async function odhlasit() {
  await apiFetch('auth', 'logout');
  localStorage.removeItem('hd_token');
  sessionStorage.removeItem('hd_token');
  APP.token = null;
  APP.user  = null;
  $('appShell').style.display = 'none';
  $('loginScreen').style.display = 'flex';
  $('loginJmeno').value = '';
  $('loginHeslo').value = '';
  $('loginError').style.display = 'none';
  $('btnLogin').disabled = false;
  $('btnLogin').textContent = 'Přihlásit se';
}

async function spustitApp() {
  $('loginScreen').style.display = 'none';
  $('appShell').style.display = 'block';

  // Nastavit UI dle uživatele
  const u = APP.user;
  $('sbUserName').textContent = u.jmeno + ' ' + u.prijmeni;
  $('sbUserRole').textContent = { admin: 'Administrátor', manazer: 'Manažer', zamestnanec: 'Zaměstnanec' }[u.role] || u.role;
  $('sbAvatar').textContent = (u.jmeno[0] + u.prijmeni[0]).toUpperCase();

  // Načíst nastavení
  try {
    const r = await apiFetch('nastaveni', 'verejne');
    if (r.ok) {
      APP.nastaveni = r.data;
      const nazev = r.data.hotel_nazev || 'Hotel DEMO';
      $('sbLogo').innerHTML = nazev.split(' ').length > 1
        ? nazev.split(' ').slice(0,-1).join(' ') + ' <span>' + nazev.split(' ').slice(-1) + '</span>'
        : '<span>' + nazev + '</span>';
      $('loginLogo').textContent = nazev;
      document.title = 'Admin — ' + nazev;
    }
  } catch(e) {}

  // Skrýt sekce dle role a oprávnění
  if (u.role === 'zamestnanec') {
    const op = APP.opravneni || {};
    // Vždy skryté pro zaměstnance
    ['nav-pokoje','nav-doplnky','nav-uzivatele','nav-nastaveni',
     'sbSekceHotel','sbSekceSystem'].forEach(id => {
      const el = $(id); if(el) el.style.display = 'none';
    });
    // Podmíněně dle oprávnění
    if (!op.zmena_rezervace && !op.storno_rezervace && !op.potvrzeni_rezervace && !op.zmena_terminu) {
      const el = $('nav-rezervace'); if(el) el.style.display = 'none';
    }
    if (!op.kartoteka) {
      const el = $('nav-zakaznici'); if(el) el.style.display = 'none';
    }
    if (!op.hodnoceni) {
      const el = $('nav-hodnoceni'); if(el) el.style.display = 'none';
    }
    if (!op.statistiky_modul) {
      const el = $('nav-statistiky'); if(el) el.style.display = 'none';
    }
    // Skrýt sekci Rezervace v menu pokud jsou všechny pod ní skryté
    const rezViditelna = $('nav-rezervace') && $('nav-rezervace').style.display !== 'none';
    const zakViditelna = $('nav-zakaznici') && $('nav-zakaznici').style.display !== 'none';
    const hodViditelna = $('nav-hodnoceni') && $('nav-hodnoceni').style.display !== 'none';
    if (!rezViditelna && !zakViditelna && !hodViditelna) {
      const sbRez = $('sbSekceRezervace');
      if (sbRez) sbRez.style.display = 'none';
    }
  }

  // Obsluha přímého odkazu z e-mailu (#rezervace/123)
  const hash = window.location.hash;
  if (hash.startsWith('#rezervace/')) {
    const rid = parseInt(hash.split('/')[1]);
    if (rid) {
      naSecci('rezervace');
      setTimeout(() => otevritRezervaci(rid), 600);
      nactiStatsBadge();
      return;
    }
  }
  // Načíst dashboard
  naSecci('prehled');
  nactiStatsBadge();
  startNotifPolling();
}

// ============================================================
//  NAVIGACE MEZI SEKCEMI
// ============================================================
function naSecci(sekce) {
  // Kontrola přístupu pro zaměstnance
  if (APP.user?.role === 'zamestnanec') {
    const op = APP.opravneni || {};
    const zakazane = ['pokoje','doplnky','uzivatele','nastaveni'];
    if (zakazane.includes(sekce)) { naSecci('prehled'); return; }
    if (sekce === 'rezervace' && !op.zmena_rezervace && !op.storno_rezervace && !op.potvrzeni_rezervace && !op.zmena_terminu) { naSecci('prehled'); return; }
    if (sekce === 'zakaznici' && !op.kartoteka) { naSecci('prehled'); return; }
    if (sekce === 'hodnoceni' && !op.hodnoceni) { naSecci('prehled'); return; }
    if (sekce === 'statistiky' && !op.statistiky_modul) { naSecci('prehled'); return; }
  }
  APP.sekce = sekce;
  document.querySelectorAll('.sb-item').forEach(el => el.classList.remove('active'));
  const navEl = $('nav-' + sekce);
  if (navEl) navEl.classList.add('active');

  const titulky = {
    prehled:'Přehled', kalendar:'Kalendář obsazenosti',
    rezervace:'Rezervace', zakaznici:'Zákazníci', hodnoceni:'Hodnocení',
    pokoje:'Pokoje', doplnky:'Doplňkové služby',
    uzivatele:'Uživatelé', nastaveni:'Nastavení',
  };
  $('topbarTitle').textContent = titulky[sekce] || sekce;
  $('topbarRight').innerHTML = '';

  const mc = $('mainContent');
  mc.innerHTML = '<div class="loading-row"><div class="spinner"></div></div>';

  switch(sekce) {
    case 'prehled':   renderPrehled();   break;
    case 'kalendar':  renderKalendar();  break;
    case 'rezervace': renderRezervace(); break;
    case 'zakaznici': renderZakaznici(); break;
    case 'hodnoceni': renderHodnoceni(); break;
    case 'statistiky': renderStatistiky(); break;
    case 'pokoje':    renderPokoje();    break;
    case 'doplnky':   renderDoplnky();   break;
    case 'uzivatele': renderUzivatele(); break;
    case 'nastaveni': renderNastaveni(); break;
  }
}

// ============================================================
//  PŘEHLED (DASHBOARD)
// ============================================================
function prepnoutObsazenost(perioda) {
  const d = APP.obsazenostData;
  if (!d) return;
  const mapa = {
    tyden:        d.obsazenost_tyden,
    pristy_tyden: d.obsazenost_pristy_tyden,
    mesic:        d.obsazenost_mesic,
    kvartal: d.obsazenost_kvartal,
    pulrok:  d.obsazenost_pulrok,
    rok:     d.obsazenost_rok,
  };
  const el = document.getElementById('obsazenostHodnota');
  if (el) el.textContent = (mapa[perioda] ?? '—') + ' %';
}

const KAP = { datumOd: null, pocetDni: 7 };

function kapFormatDen(datum) {
  const dt = new Date(datum + 'T00:00:00');
  const dnazvy = ['Ne','Po','Út','St','Čt','Pá','So'];
  return `${dnazvy[dt.getDay()]} ${dt.getDate()}.${dt.getMonth()+1}.`;
}

function kapNastavRozsah(pocetDni) {
  KAP.pocetDni = pocetDni;
  nactiKapacituDnes();
}

function kapPosunOkno(smer) {
  const dt = new Date(KAP.datumOd + 'T00:00:00');
  dt.setDate(dt.getDate() + smer * KAP.pocetDni);
  KAP.datumOd = dt.toISOString().split('T')[0];
  nactiKapacituDnes();
}

async function nactiKapacituDnes() {
  try {
    if (!KAP.datumOd) KAP.datumOd = new Date().toISOString().split('T')[0];
    const r = await apiFetch('dostupnost', 'kapacity_tyden', { datum_od: KAP.datumOd, pocet_dni: KAP.pocetDni });
    if (!r.ok) return;
    const dny = r.data.dny;
    APP._kapDny = dny;

    const dnesStr = new Date().toISOString().split('T')[0];
    const dtOd = new Date(KAP.datumOd + 'T00:00:00');
    const dtDo = new Date(dtOd); dtDo.setDate(dtDo.getDate() + KAP.pocetDni - 1);
    const obdobiLabel = `${dtOd.getDate()}. – ${dtDo.getDate()}. ${['ledna','února','března','dubna','května','června','července','srpna','září','října','listopadu','prosince'][dtDo.getMonth()]} ${dtDo.getFullYear()}`;

    const radek = (ikon, label, klic, getVal, getMax) => `
      <div style="display:grid;grid-template-columns:90px repeat(${dny.length},1fr);gap:2px;margin-bottom:4px">
        <div style="font-size:12px;color:var(--gray-500);display:flex;align-items:center;gap:4px">${ikon}${label}</div>
        ${dny.map(d => {
          const val = getVal(d), max = getMax ? getMax(d) : null;
          const plno = max !== null && val >= max;
          const prazdno = val === 0;
          const bg = plno ? 'var(--amber-100)' : prazdno ? 'var(--gray-50)' : 'var(--gray-100)';
          const color = plno ? 'var(--amber-600)' : 'var(--gray-700)';
          const label2 = max !== null ? `${val}/${max}` : `${val}`;
          return `<div onclick="kapOtevritDen('${d.datum}','${klic}')" style="cursor:pointer;text-align:center;font-size:12px;font-weight:600;padding:6px 2px;background:${bg};border-radius:6px;color:${color}">${label2}</div>`;
        }).join('')}
      </div>`;

    const el = document.getElementById('widgetKapacita');
    if (!el) return;
    el.innerHTML = `
      <div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:12px;flex-wrap:wrap;gap:8px">
        <div style="display:flex;align-items:center;gap:6px">
          <button onclick="kapPosunOkno(-1)" class="btn btn-secondary btn-sm" style="padding:3px 8px">‹</button>
          <span style="font-size:13px;font-weight:500">${obdobiLabel}</span>
          <button onclick="kapPosunOkno(1)" class="btn btn-secondary btn-sm" style="padding:3px 8px">›</button>
        </div>
        <div style="display:flex;gap:4px">
          <button onclick="kapNastavRozsah(7)" class="btn btn-sm ${KAP.pocetDni===7?'btn-primary':'btn-secondary'}" style="padding:3px 10px;font-size:11px">Týden</button>
          <button onclick="kapNastavRozsah(14)" class="btn btn-sm ${KAP.pocetDni===14?'btn-primary':'btn-secondary'}" style="padding:3px 10px;font-size:11px">14 dní</button>
        </div>
      </div>
      <div style="display:grid;grid-template-columns:90px repeat(${dny.length},1fr);gap:2px;margin-bottom:6px">
        <div></div>
        ${dny.map(d => `<div style="text-align:center;font-size:11px;padding:3px 0;border-radius:6px;${d.datum===dnesStr?'background:var(--blue-50);color:var(--blue-600);font-weight:600':'color:var(--gray-400)'}">${kapFormatDen(d.datum)}</div>`).join('')}
      </div>
      ${radek('🚗', 'Parkování', 'parkovani', d => d.parkovani.obsazeno, d => d.parkovani.kapacita)}
      ${radek('⚡', 'Dobíjení', 'dobijeni', d => d.dobijeni.obsazeno, d => d.dobijeni.kapacita)}
      ${radek('☕', 'Snídaně', 'snidane', d => d.snidane.porci, null)}
      <p style="font-size:11px;color:var(--gray-400);margin-top:10px;text-align:center">Kliknutím na den zobrazíte jmenný seznam hostů</p>
    `;
  } catch(e) { console.error(e); }
}

function kapOtevritDen(datum, klic) {
  const den = (APP._kapDny || []).find(d => d.datum === datum);
  if (!den) return;
  const dt = new Date(datum + 'T00:00:00');
  const dnazvyDlouhe = ['neděle','pondělí','úterý','středa','čtvrtek','pátek','sobota'];
  const datumLabel = `${dnazvyDlouhe[dt.getDay()]} ${dt.getDate()}.${dt.getMonth()+1}.${dt.getFullYear()}`;

  const sekce = (ikon, nazev, info, hoste) => `
    <div style="margin-bottom:14px">
      <div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:6px">
        <div style="font-size:13px;font-weight:600">${ikon} ${nazev}</div>
        <div style="font-size:12px;color:var(--gray-500)">${info}</div>
      </div>
      ${hoste.length
        ? hoste.map(h => `<div style="font-size:13px;color:var(--gray-700);padding:4px 0;border-bottom:1px solid var(--gray-50)">${h}</div>`).join('')
        : '<div style="font-size:12px;color:var(--gray-400)">Žádní hosté</div>'}
    </div>`;

  const obsahy = {
    parkovani: sekce('🚗', 'Parkování', `${den.parkovani.obsazeno} / ${den.parkovani.kapacita} míst`, den.parkovani.hoste),
    dobijeni: sekce('⚡', 'Dobíjení', `${den.dobijeni.obsazeno} / ${den.dobijeni.kapacita} míst`, den.dobijeni.hoste),
    snidane: sekce('☕', 'Snídaně', `${den.snidane.porci} porcí`, den.snidane.hoste.map(h => `${h.jmeno} <span style="color:var(--gray-400)">(${h.pocet} ${h.pocet===1?'osoba':h.pocet<5?'osoby':'osob'})</span>`)),
  };

  const modal = document.createElement('div');
  modal.className = 'modal-overlay';
  modal.id = 'kapDenModal';
  modal.onclick = e => { if (e.target === modal) modal.remove(); };
  modal.innerHTML = `<div class="modal" style="max-width:380px">
    <div class="modal-header">
      <div class="modal-title">${datumLabel}</div>
      <button class="modal-close" onclick="document.getElementById('kapDenModal').remove()">×</button>
    </div>
    <div class="modal-body">
      ${obsahy.parkovani}
      ${obsahy.dobijeni}
      ${obsahy.snidane}
    </div>
  </div>`;
  document.body.appendChild(modal);
}

async function renderPrehled() {
  const mc = $('mainContent');
  try {
    const r = await apiFetch('statistiky', 'prehled');
    if (!r.ok) throw new Error(r.error);
    const d = r.data;

    APP.obsazenostData = d;
    const zmenaStr = d.trzby_zmena_proc !== null
      ? (d.trzby_zmena_proc >= 0 ? '+' : '') + d.trzby_zmena_proc + ' % vs. minulý měsíc'
      : '';
    const zmenaCls = d.trzby_zmena_proc >= 0 ? 'up' : 'down';

    mc.innerHTML = `
      <div class="stat-grid">
        <div class="stat-card">
          <div class="stat-label">Příjezdy dnes</div>
          <div class="stat-val blue">${d.prijezdy_dnes}</div>
          <div class="stat-sub">check-in od ${APP.nastaveni.checkin_cas||'14:00'}</div>
        </div>
        <div class="stat-card">
          <div class="stat-label">Odjezdy dnes</div>
          <div class="stat-val">${d.odjezdy_dnes}</div>
          <div class="stat-sub">check-out do ${APP.nastaveni.checkout_cas||'10:00'}</div>
        </div>
        <div class="stat-card" style="cursor:default">
          <div class="stat-label" style="display:flex;align-items:center;justify-content:space-between">
            <span>Obsazenost</span>
            <select id="obsazenostPerioda" onchange="prepnoutObsazenost(this.value)"
              style="font-size:10px;padding:2px 4px;border:1px solid var(--gray-200);border-radius:4px;background:var(--white);color:var(--gray-600)">
              <option value="tyden">Týden</option>
              <option value="pristy_tyden">Příští týden</option>
              <option value="mesic">Měsíc</option>
              <option value="kvartal">Kvartál</option>
              <option value="pulrok">Půlrok</option>
              <option value="rok">Rok</option>
            </select>
          </div>
          <div class="stat-val blue" id="obsazenostHodnota">${d.obsazenost_tyden} %</div>
          <div class="stat-sub">${d.ubytovani} hostů aktuálně</div>
        </div>
        ${['admin','manazer'].includes(APP.user.role) ? `
        <div class="stat-card">
          <div class="stat-label">Tržby tento měsíc</div>
          <div class="stat-val green">${formatCena(d.trzby_mesic)}</div>
          <div class="stat-sub ${zmenaCls}">${zmenaStr}</div>
        </div>` : ''}
      </div>

      ${d.cekajici_slevy > 0 ? `
        <div class="alert alert-warn" style="margin-bottom:16px">
          ⚠️ Čekají <strong>${d.cekajici_slevy}</strong> návrh(y) slevy ke schválení.
          <a href="#" onclick="naSecci('rezervace');return false" style="color:inherit;font-weight:600;margin-left:8px">Zobrazit →</a>
        </div>` : ''}

      ${d.hodnoceni_prumer ? `
        <div class="alert alert-info" style="margin-bottom:16px">
          ⭐ Průměrné hodnocení: <strong>${d.hodnoceni_prumer} / 5</strong>
          (${d.hodnoceni_pocet} hodnocení)
        </div>` : ''}

      <div class="card" style="margin-bottom:16px">
        <div class="card-header"><div class="card-title">🅿️ Kapacity doplňků</div></div>
        <div class="card-body" id="widgetKapacita"><div class="loading-row"><div class="spinner"></div></div></div>
      </div>
      <div class="dnes-grid">
        <div class="card">
          <div class="card-header"><div class="card-title">📥 Dnešní příjezdy</div></div>
          <div class="card-body" id="dnesPrijezdy"><div class="loading-row"><div class="spinner"></div></div></div>
        </div>
        <div class="card">
          <div class="card-header"><div class="card-title">📤 Dnešní odjezdy</div></div>
          <div class="card-body" id="dnesOdjezdy"><div class="loading-row"><div class="spinner"></div></div></div>
        </div>
      </div>`;

    // Načíst příjezdy/odjezdy
    const rez = await apiFetch('guest', 'today');
    if (rez.ok) {
      renderDnesniSeznam('dnesPrijezdy', rez.data.prijezdy, 'prijezd');
      renderDnesniSeznam('dnesOdjezdy',  rez.data.odjezdy,  'odjezd');
    }
    nactiKapacituDnes();

  } catch(e) {
    console.error('renderPrehled chyba:', e);
    mc.innerHTML = `<div class="alert alert-error">Nepodařilo se načíst přehled: ${esc(e.message)}</div>`;
  }
}

function renderDnesniSeznam(containerId, seznam, typ) {
  const el = $(containerId);
  if (!seznam.length) {
    el.innerHTML = '<div style="color:var(--gray-400);font-size:13px">Žádné ' + (typ==='prijezd'?'příjezdy':'odjezdy') + ' dnes</div>';
    return;
  }
  // Widget kapacity parkovišť


  el.innerHTML = '<div class="dnes-list">' +
    seznam.map(r => `
      <div class="dnes-item" onclick="otevritRezervaci(${r.id})" style="cursor:pointer">
        <div class="dnes-pokoj">${esc(r.pokoj_cislo)}</div>
        <div class="dnes-host">${esc(r.jmeno + ' ' + r.prijmeni)}</div>
        <div class="dnes-cas">${r[typ==='prijezd'?'checkin_cas':'checkout_cas'] || (typ==='prijezd'?APP.nastaveni.checkin_cas:'10:00') || ''}</div>
      </div>`).join('') +
  '</div>';
}

// ============================================================
//  GANTT KALENDÁŘ
// ============================================================
async function renderKalendar() {
  const mc = $('mainContent');
  const dnes = new Date();

  if (!APP.ganttOd) {
    APP.ganttOd = new Date(dnes.getFullYear(), dnes.getMonth(), 1);
    APP.ganttDo = new Date(dnes.getFullYear(), dnes.getMonth() + 1, 0);
  }

  // Topbar tlačítko
  $('topbarRight').innerHTML = `
    <button class="btn btn-primary" onclick="otevritNovouRezervaci()">+ Nová rezervace</button>`;

  mc.innerHTML = `
    <div class="card">
      <div class="card-header">
        <div class="gantt-nav">
          <button class="gantt-nav-btn" onclick="ganttPrev()">‹</button>
          <div class="gantt-period" id="ganttPeriod"></div>
          <button class="gantt-nav-btn" onclick="ganttNext()">›</button>
        </div>
        <div style="display:flex;gap:8px">
          <button class="btn btn-secondary btn-sm" onclick="nactiKalendar()" title="Obnovit kalendář">↻</button>
          <button class="btn btn-secondary btn-sm" onclick="ganttDnes()">Dnes</button>
        </div>
      </div>
      <div class="gantt-wrap">
        <div id="ganttTable"><div class="loading-row"><div class="spinner"></div></div></div>
      </div>
      <div class="gantt-legenda">
        <div class="gantt-leg-item"><div class="gantt-leg-dot" style="background:var(--green-100);border:1px solid #bbf7d0"></div>Potvrzená</div>
        <div class="gantt-leg-item"><div class="gantt-leg-dot" style="background:var(--amber-100);border:1px solid #fde68a"></div>Čeká</div>
        <div class="gantt-leg-item"><div class="gantt-leg-dot" style="background:#ede9fe;border:1px solid #d8b4fe"></div>Čeká na schválení</div>
        <div class="gantt-leg-item"><div class="gantt-leg-dot" style="background:var(--gray-100);border:1px solid var(--gray-200)"></div>Blokováno</div>
      </div>
    </div>`;

  await nactiGanttData();
}

async function nactiGanttData() {
  const od = formatDatum(APP.ganttOd);
  const doDate = APP.ganttDo;
  const do_ = formatDatum(doDate);

  const mesice = ['Leden','Únor','Březen','Duben','Květen','Červen',
                  'Červenec','Srpen','Září','Říjen','Listopad','Prosinec'];
  const period = mesice[APP.ganttOd.getMonth()] + ' ' + APP.ganttOd.getFullYear();
  const el = $('ganttPeriod');
  if (el) el.textContent = period;

  try {
    const r = await apiFetch('dostupnost', 'kalendar', { datum_od: od, datum_do: do_ });
    if (!r.ok) throw new Error(r.error);
    renderGanttTable(r.data, od, do_);
  } catch(e) {
    const gt = $('ganttTable');
    if (gt) gt.innerHTML = '<div class="alert alert-error" style="margin:16px">Nepodařilo se načíst kalendář.</div>';
  }
}

function nactiKalendar() {
  if (APP.ganttOd && APP.ganttDo) {
    nactiGanttData();
  } else {
    renderKalendar();
  }
}

function renderGanttTable(data, od, do_) {
  const gt = $('ganttTable');
  if (!gt) return;

  const CELL_W = 44;
  const ROW_H  = 60;
  const dnes   = formatDatum(new Date());
  const dny    = [];
  const dnazvy = ['Ne','Po','Út','St','Čt','Pá','So'];
  const op = APP.opravneni || {};
  const mozeEditTermin = APP.user.role === 'admin' || APP.user.role === 'manazer' ||
    !!(op.zmena_terminu === true || op.zmena_terminu === 1);

  let d = new Date(od);
  const konec = new Date(do_);
  konec.setDate(konec.getDate() + 1);
  while (d < konec) { dny.push(formatDatum(d)); d.setDate(d.getDate() + 1); }

  // === HEADER ===
  let html = `<table class="gantt-table"><thead><tr><th class="gantt-th-room">POKOJ</th>`;
  dny.forEach(datum => {
    const dt   = new Date(datum + 'T00:00:00');
    const isWE = dt.getDay() === 0 || dt.getDay() === 6;
    const today = datum === dnes;
    html += `<th class="gantt-th-day${isWE?' weekend':''}${today?' today':''}">
      <span class="day-name">${dnazvy[dt.getDay()]}</span>
      <span class="day-num">${dt.getDate()}</span>
    </th>`;
  });
  html += '</tr></thead><tbody>';

  // === ŘÁDKY — jen mřížka, bez barů ===
  const pokoje = data.pokoje;
  pokoje.forEach((pokoj, ri) => {
    const nazev = pokoj.nazev ? pokoj.cislo + ' — ' + pokoj.nazev : pokoj.cislo;
    html += `<tr>
      <td class="gantt-td-room" onclick="naSecci('pokoje')">
        <div class="gantt-room-cislo">${esc(nazev)}</div>
        <div class="gantt-room-typ">${esc(pokoj.typ_nazev)}</div>
      </td>`;
    dny.forEach(datum => {
      const dt   = new Date(datum + 'T00:00:00');
      const isWE = dt.getDay() === 0 || dt.getDay() === 6;
      html += `<td class="gantt-td-day${isWE?' weekend':''}" data-datum="${datum}" data-pokoj="${pokoj.id}"></td>`;
    });
    html += '</tr>';
  });
  html += '</tbody></table>';

  gt.innerHTML = html;

  // === OVERLAY BARY — absolutně přes celou tabulku ===
  const table  = gt.querySelector('table');
  const tbody  = table.querySelector('tbody');
  const thead  = table.querySelector('thead');

  // Wrapper pro overlay
  const wrap = document.createElement('div');
  wrap.style.cssText = 'position:relative;';
  gt.insertBefore(wrap, null);
  wrap.appendChild(table);

  const overlay = document.createElement('div');
  overlay.id = 'ganttOverlay';
  overlay.style.cssText = 'position:absolute;top:0;left:0;width:100%;height:100%;pointer-events:none;z-index:5;';
  wrap.appendChild(overlay);

  // Zjistit pozici hlavičky (výška thead)
  const headerH = thead.offsetHeight || 44;
  const roomW   = tbody.rows[0]?.cells[0]?.offsetWidth || 120;

  // Přidat bary
  pokoje.forEach((pokoj, ri) => {
    const top = headerH + ri * ROW_H;

    // Rezervace
    data.rezervace.filter(r => r.pokoj_id === pokoj.id).forEach(rez => {
      const diOd = dny.indexOf(rez.datum_prijezdu);
      const diDo = dny.indexOf(rez.datum_odjezdu);
      const diStart = diOd >= 0 ? diOd : (new Date(rez.datum_prijezdu) < new Date(od) ? 0 : -1);
      if (diStart < 0) return;

      const diEnd = diDo >= 0 ? diDo : dny.length;
      const pocetDni = diEnd - diStart;
      if (pocetDni <= 0) return;

      const left = roomW + diStart * CELL_W + 2;
      const w    = pocetDni * CELL_W - 4;

      const ikonky = (rez.doplnky_typy||[]).map(t => ({
        parking:'🚗', charging:'⚡', breakfast:'☕', late_checkout:'🕑', other:'•'
      }[t]||'')).join('');

      const bar = document.createElement('div');
      const maZadost = rez.pokoj_zadost_stav === 'ceka' || rez.cas_zadost_stav === 'ceka' || rez.sleva_stav === 'navrzena';
      bar.className = `gantt-bar ${maZadost ? 'ceka-schvaleni' : rez.stav}`;
      bar.style.cssText = `position:absolute;top:${top+4}px;left:${left}px;width:${w}px;height:${ROW_H-8}px;pointer-events:all;cursor:${mozeEditTermin?'grab':'pointer'};display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;overflow:hidden;`;
      bar.dataset.rezId    = rez.id;
      bar.dataset.datumOd  = rez.datum_prijezdu;
      bar.dataset.datumDo  = rez.datum_odjezdu;
      bar.dataset.pokojId  = pokoj.id;
      bar.dataset.diStart  = diStart;
      bar.dataset.origLeft = left;
      bar.dataset.cellW    = CELL_W;
      bar.dataset.roomW    = roomW;
      bar.dataset.rowTop   = top;
      bar.title = `${rez.jmeno} ${rez.prijmeni} (${rez.datum_prijezdu} – ${rez.datum_odjezdu})`;
      bar.innerHTML = `
        ${mozeEditTermin ? `<div class="resize-handle resize-handle-l" onmousedown="ganttResizeStart(event,'l',${rez.id})"></div>` : ''}
        <span style="line-height:1.2;font-size:11px;font-weight:500">${esc(rez.jmeno)}</span>
        <span style="line-height:1.2;font-size:11px">${esc(rez.prijmeni)}</span>
        ${ikonky ? `<span style="font-size:10px;opacity:.8">${ikonky}</span>` : ''}
        ${mozeEditTermin ? `<div class="resize-handle resize-handle-r" onmousedown="ganttResizeStart(event,'r',${rez.id})"></div>` : ''}
      `;
      bar.addEventListener('mousedown', ev => {
        if (!ev.target.classList.contains('resize-handle')) ganttMoveStart(ev, bar);
      });
      bar.addEventListener('click', ev => ganttBarClick(ev, rez.id));
      overlay.appendChild(bar);
    });

    // Blokace
    data.blokovane.filter(b => b.pokoj_id === pokoj.id).forEach(bl => {
      const diOd = dny.indexOf(bl.datum_od);
      if (diOd < 0) return;
      const diDo = dny.indexOf(bl.datum_do);
      const diEnd = diDo >= 0 ? diDo : dny.length;
      const pocetDni = diEnd - diOd;
      if (pocetDni <= 0) return;
      const left = roomW + diOd * CELL_W + 2;
      const w    = pocetDni * CELL_W - 4;
      const bar = document.createElement('div');
      bar.className = 'gantt-bar blokovano';
      bar.style.cssText = `position:absolute;top:${top+4}px;left:${left}px;width:${w}px;height:${ROW_H-8}px;pointer-events:all;cursor:default;display:flex;align-items:center;justify-content:center;overflow:hidden;font-size:11px;`;
      bar.title = `Blokováno: ${bl.duvod||'—'}`;
      bar.textContent = '🔒 ' + (bl.duvod || 'Blokováno');
      overlay.appendChild(bar);
    });
  });

  // Uložit data pro DnD
  GANTT_DND.dny    = dny;
  GANTT_DND.roomW  = roomW;
  GANTT_DND.CELL_W = CELL_W;
  GANTT_DND.ROW_H  = ROW_H;
  GANTT_DND.headerH = headerH;
}

function ganttPrev() {
  APP.ganttOd = new Date(APP.ganttOd.getFullYear(), APP.ganttOd.getMonth() - 1, 1);
  APP.ganttDo = new Date(APP.ganttOd.getFullYear(), APP.ganttOd.getMonth() + 1, 0);
  nactiGanttData();
}
function ganttNext() {
  APP.ganttOd = new Date(APP.ganttOd.getFullYear(), APP.ganttOd.getMonth() + 1, 1);
  APP.ganttDo = new Date(APP.ganttOd.getFullYear(), APP.ganttOd.getMonth() + 1, 0);
  nactiGanttData();
}
function ganttDnes() {
  const d = new Date();
  APP.ganttOd = new Date(d.getFullYear(), d.getMonth(), 1);
  APP.ganttDo = new Date(d.getFullYear(), d.getMonth() + 1, 0);
  nactiGanttData();
}

// ============================================================
//  SEZNAM REZERVACÍ
// ============================================================
let rezState = { offset: 0, limit: 25, search: '', stav: '', celkem: 0 };

async function renderRezervace() {
  const mc = $('mainContent');
  $('topbarRight').innerHTML = `<button class="btn btn-primary" onclick="otevritNovouRezervaci()">+ Nová rezervace</button>`;

  mc.innerHTML = `
    <div class="card">
      <div class="filter-bar">
        <input type="search" id="rezSearch" placeholder="Jméno, e-mail, telefon…"
          oninput="rezFilter()" style="max-width:260px">
        <select id="rezStav" onchange="rezFilter()">
          <option value="">Všechny stavy</option>
          <option value="potvrzena">Potvrzená</option>
          <option value="ceka">Čeká</option>
          <option value="zrusena">Zrušená</option>
        </select>
        <input type="date" id="rezOd" onchange="rezFilter()" title="Příjezd od">
        <input type="date" id="rezDo" onchange="rezFilter()" title="Příjezd do">
      </div>
      <div class="table-wrap">
        <table>
          <thead><tr>
            <th>#</th><th>Host</th><th>Pokoj</th>
            <th>Příjezd</th><th>Odjezd</th><th>Nocí</th>
            <th>Cena</th><th>Stav</th><th></th>
          </tr></thead>
          <tbody id="rezTbody"><tr><td colspan="9" class="loading-row"><div class="spinner"></div></td></tr></tbody>
        </table>
      </div>
      <div class="pagination" id="rezPagination"></div>
    </div>`;

  await nactiRezervace();
}

let rezFilterTimeout;
function rezFilter() {
  clearTimeout(rezFilterTimeout);
  rezFilterTimeout = setTimeout(() => {
    rezState.offset = 0;
    nactiRezervace();
  }, 350);
}

async function nactiRezervace() {
  const params = new URLSearchParams({
    search:   $('rezSearch')?.value || '',
    stav:     $('rezStav')?.value   || '',
    datum_od: $('rezOd')?.value     || '',
    datum_do: $('rezDo')?.value     || '',
    limit:    rezState.limit,
    offset:   rezState.offset,
  });

  const tbody = $('rezTbody');
  if (!tbody) return; // Uživatel není v sekci Rezervace — není co obnovovat
  const r = await apiFetch('guest', 'seznam', Object.fromEntries(params));

  if (!r.ok) {
    tbody.innerHTML = `<tr><td colspan="9"><div class="alert alert-error">${esc(r.error)}</div></td></tr>`;
    return;
  }

  rezState.celkem = r.data.celkem;
  const rezervace = r.data.rezervace;

  if (!rezervace.length) {
    tbody.innerHTML = '<tr><td colspan="9" class="loading-row" style="color:var(--gray-400)">Žádné rezervace</td></tr>';
    renderRezPaginaci();
    return;
  }

  tbody.innerHTML = rezervace.map(rez => {
    const stavBadge = {
      potvrzena: '<span class="badge badge-blue">Potvrzená</span>',
      ceka:      '<span class="badge badge-amber">Čeká</span>',
      zrusena:   '<span class="badge badge-gray">Zrušená</span>',
    }[rez.stav] || rez.stav;

    const cena = rez.cena_upravena !== null
      ? formatCena(rez.cena_upravena)
      : formatCena(rez.cena_zaklad);

    const slevaIco = rez.sleva_stav === 'navrzena'
      ? '<span title="Čeká sleva ke schválení" style="color:var(--amber-600)">💰</span> ' : '';

    return `<tr>
      <td style="color:var(--gray-400)">#${rez.id}</td>
      <td><strong>${esc(rez.jmeno + ' ' + rez.prijmeni)}</strong> ${({cs:'🇨🇿',en:'🇬🇧',de:'🇩🇪'})[rez.jazyk] || '🇨🇿'}<br>
        <span style="font-size:11px;color:var(--gray-400)">${esc(rez.email)}</span></td>
      <td>${esc(rez.pokoj_cislo)} <span style="color:var(--gray-400);font-size:11px">${esc(rez.typ_nazev)}</span></td>
      <td>${formatDatumCS(rez.datum_prijezdu)}</td>
      <td>${formatDatumCS(rez.datum_odjezdu)}</td>
      <td>${rez.pocet_noci}</td>
      <td>${slevaIco}${cena}</td>
      <td>${stavBadge}</td>
      <td>
        <div class="td-akce">
          <button class="btn btn-secondary btn-sm" onclick="otevritRezervaci(${rez.id})">Detail</button>
        </div>
      </td>
    </tr>`;
  }).join('');

  renderRezPaginaci();
  nactiStatsBadge();
}

function renderRezPaginaci() {
  const el = $('rezPagination');
  if (!el) return;
  const stranky = Math.ceil(rezState.celkem / rezState.limit);
  const aktualni = Math.floor(rezState.offset / rezState.limit);

  let html = `<button class="page-btn" onclick="rezStrana(${aktualni-1})" ${aktualni===0?'disabled':''}>‹</button>`;
  for (let i = 0; i < Math.min(stranky, 7); i++) {
    html += `<button class="page-btn ${i===aktualni?'active':''}" onclick="rezStrana(${i})">${i+1}</button>`;
  }
  html += `<button class="page-btn" onclick="rezStrana(${aktualni+1})" ${aktualni>=stranky-1?'disabled':''}>›</button>`;
  html += `<span class="page-info">Celkem: ${rezState.celkem}</span>`;
  el.innerHTML = html;
}

function rezStrana(n) {
  rezState.offset = n * rezState.limit;
  nactiRezervace();
}

// ============================================================
//  DETAIL REZERVACE (modal)
// ============================================================
async function otevritRezervaci(id) {
  const r = await apiFetch('guest', 'detail', { id });
  if (!r.ok) { alert(r.error); return; }

  const { rezervace: rez, doplnky, hodnoceni } = r.data;
  window._rezDetail = {
    typ_id: rez.typ_id, jmeno: rez.jmeno, prijmeni: rez.prijmeni,
    email: rez.email, telefon: rez.telefon, pocet_hostu: rez.pocet_hostu,
    poznamka: rez.poznamka, na_firmu: rez.na_firmu, firma: rez.firma,
    ico: rez.ico, dic: rez.dic, faktura_ulice: rez.faktura_ulice,
    faktura_psc: rez.faktura_psc, faktura_mesto: rez.faktura_mesto,
  };
  const checkin  = rez.checkin_cas  || APP.nastaveni.checkin_cas  || '14:00';
  // Zkontrolovat pozdní check-out v doplňcích
  let checkout = rez.checkout_cas || APP.nastaveni.checkout_cas || '10:00';
  doplnky.forEach(d => {
    const n = d.nazev.toLowerCase();
    if (n.includes('check-out') || n.includes('checkout') || n.includes('pozdní')) {
      const m = d.nazev.match(/(\d{1,2}:\d{2})/);
      if (m) checkout = m[1];
    }
  });

  const cenaZaklad  = parseFloat(rez.cena_zaklad);
  const cenaDoplnky = doplnky.reduce((s,d) => s + parseFloat(d.cena_celkem), 0);
  const cenaUpravena= rez.cena_upravena !== null ? parseFloat(rez.cena_upravena) : null;
  const slevaSchval = rez.sleva_stav === 'schvalena' ? parseFloat(rez.sleva_castka||0) : 0;
  const cenaCelkem  = cenaUpravena !== null ? cenaUpravena : cenaZaklad + cenaDoplnky - slevaSchval;

  const stavBadge = {
    potvrzena: '<span class="badge badge-blue">Potvrzená</span>',
    ceka:      '<span class="badge badge-amber">Čeká</span>',
    zrusena:   '<span class="badge badge-gray">Zrušená</span>',
  }[rez.stav] || rez.stav;

  let slevaHtml = '';
  if (rez.sleva_stav === 'navrzena') {
    slevaHtml = `<div class="alert alert-warn" style="margin:0 22px 14px">
      💰 Čeká sleva ${formatCena(rez.sleva_castka)} — důvod: ${esc(rez.sleva_poznamka)}
      ${['admin','manazer'].includes(APP.user.role) ? `
        <div style="margin-top:8px;display:flex;gap:6px">
          <button class="btn btn-success btn-sm" onclick="rozhodnoutSlevu(${id},true)">✓ Schválit</button>
          <button class="btn btn-danger btn-sm"  onclick="rozhodnoutSlevu(${id},false)">✗ Zamítnout</button>
        </div>` : ''}
    </div>`;
  } else if (rez.sleva_stav === 'schvalena') {
    slevaHtml = `<div class="alert alert-ok" style="margin:0 22px 14px">
      Sleva ${formatCena(rez.sleva_castka)} schválena. Důvod: ${esc(rez.sleva_poznamka)}
    </div>`;
  } else if (rez.sleva_stav === 'zamitnuta') {
    slevaHtml = `<div class="alert" style="margin:0 22px 14px;background:var(--gray-100);color:var(--gray-600)">
      <div><strong>Sleva ${formatCena(rez.sleva_castka)} zamítnuta.</strong></div>
      <div style="margin-top:4px">Důvod žádosti (zaměstnanec): "${esc(rez.sleva_poznamka || '—')}"</div>
      ${rez.sleva_manazer_poznamka ? `<div style="margin-top:4px;font-style:italic">Poznámka manažera: "${esc(rez.sleva_manazer_poznamka)}"</div>` : ''}
    </div>`;
  }

  const mozeEditovat       = APP.user.role !== 'zamestnanec' ||
    !!(APP.opravneni?.zmena_rezervace);
  const mozeRusit          = APP.user.role !== 'zamestnanec' ||
    !!(APP.opravneni?.storno_rezervace);
  const mozeEditovatTermin = APP.user.role === 'admin' || APP.user.role === 'manazer' ||
    !!(APP.opravneni?.zmena_terminu);

  const doplnkyHtml = `<div id="doplnkyDetail_${rez.id}">
    ${doplnky.length
      ? doplnky.map(d => `
        <div style="display:flex;align-items:center;justify-content:space-between;padding:8px 10px;margin-bottom:4px;background:var(--green-100);border-radius:6px;border:0.5px solid #bbf7d0">
          <div style="display:flex;align-items:center;gap:6px">
            <span style="font-size:13px">${
              d.nazev.toLowerCase().includes('park') ? '🚗' :
              d.nazev.toLowerCase().includes('dobíj') || d.nazev.toLowerCase().includes('elektro') ? '⚡' :
              d.nazev.toLowerCase().includes('snídaně') || d.nazev.toLowerCase().includes('snidane') ? '☕' :
              d.nazev.toLowerCase().includes('check-out') || d.nazev.toLowerCase().includes('pozdní') ? '🕑' : '•'
            }</span>
            <div>
              <div style="font-size:13px;font-weight:500;color:var(--gray-900)">${esc(d.nazev)}</div>
              <div style="font-size:11px;color:var(--gray-500)">${formatCena(d.cena_celkem)}</div>
            </div>
          </div>
          ${mozeEditovat ? `<button class="btn btn-sm" style="color:var(--red-600);font-size:11px" onclick="odebratrDoplnek(${rez.id}, ${d.id||0}, '${esc(d.nazev)}')">✕ odebrat</button>` : ''}
        </div>`).join('')
      : '<div style="font-size:12px;color:var(--gray-400);margin-bottom:8px">Žádné doplňky</div>'}
    ${mozeEditovat ? `<button class="btn btn-sm btn-secondary" style="width:100%;margin-top:4px" onclick="pridatDoplnek(${rez.id}, '${rez.datum_prijezdu}', '${rez.datum_odjezdu}')">+ Přidat doplněk</button>` : ''}
  </div>`;

  const hodnoceniHtml = hodnoceni
    ? '<span style="color:#f59e0b">' + '★'.repeat(hodnoceni.hvezdicky) + '☆'.repeat(5-hodnoceni.hvezdicky) + '</span>'
    : '<span style="color:var(--gray-400)">Nezhodnoceno</span>';



  const html = `
    <div class="modal-overlay" id="rezModal" onclick="if(event.target===this)zavritModal('rezModal')">
      <div class="modal" style="max-width:600px">
        <div class="modal-header">
          <div class="modal-title">Rezervace #${rez.id} ${stavBadge}</div>
          <button class="modal-close" onclick="zavritModal('rezModal')">×</button>
        </div>
        ${slevaHtml}
        ${rez.cas_zadost_stav === 'ceka' ? `
        <div class="alert alert-warn" style="margin:0 22px 14px">
          🕑 Zaměstnanec žádá o změnu <strong>${rez.cas_zadost_typ === 'checkin' ? 'check-in' : 'check-out'}</strong>
          na <strong>${rez.cas_zadost_hodnota}</strong> zdarma.
          ${['admin','manazer'].includes(APP.user.role) ? `
          <div style="margin-top:8px;display:flex;gap:6px">
            <button class="btn btn-success btn-sm" onclick="schvalitCas(${id})">✓ Schválit</button>
            <button class="btn btn-danger btn-sm" onclick="zamitnoutCas(${id})">✗ Zamítnout</button>
          </div>` : '<div style="margin-top:6px;font-size:12px;color:#92400e">Čeká na schválení manažerem.</div>'}
        </div>` : ''}
        ${rez.cas_zadost_stav === 'zamitnuto' ? `
        <div class="alert" style="margin:0 22px 14px;background:var(--gray-100);color:var(--gray-600)">
          <div><strong>Žádost o změnu ${rez.cas_zadost_typ === 'checkin' ? 'check-in' : 'check-out'} na ${rez.cas_zadost_hodnota} zdarma — zamítnuta.</strong></div>
          ${rez.cas_zadost_poznamka ? `<div style="margin-top:4px;font-style:italic">Poznámka manažera: "${esc(rez.cas_zadost_poznamka)}"</div>` : ''}
        </div>` : ''}
        ${rez.pokoj_zadost_stav === 'ceka' ? `
        <div class="alert alert-warn" style="margin:0 22px 14px">
          🔁 Zaměstnanec žádá o přiřazení dražšího pokoje za <strong>${formatCena(rez.cena_upravena !== null ? rez.cena_upravena : rez.cena_zaklad)}</strong>
          (odpovídající cena nového typu: <strong>${formatCena(rez.pokoj_zadost_cena_typu)}</strong>).
          ${['admin','manazer'].includes(APP.user.role) ? `
          <div style="margin-top:8px;display:flex;gap:6px">
            <button class="btn btn-success btn-sm" onclick="schvalitZmenuPokoje(${id})">✓ Schválit</button>
            <button class="btn btn-danger btn-sm" onclick="zamitnoutZmenuPokoje(${id})">✗ Zamítnout</button>
          </div>` : '<div style="margin-top:6px;font-size:12px;color:#92400e">Čeká na schválení manažerem.</div>'}
        </div>` : ''}
        ${rez.pokoj_zadost_stav === 'zamitnuto' ? `
        <div class="alert" style="margin:0 22px 14px;background:var(--gray-100);color:var(--gray-600)">
          <div><strong>Žádost o přiřazení dražšího pokoje za ${formatCena(rez.cena_upravena !== null ? rez.cena_upravena : rez.cena_zaklad)} (cena nového typu: ${formatCena(rez.pokoj_zadost_cena_typu)}) — zamítnuta.</strong></div>
          ${rez.pokoj_zadost_poznamka ? `<div style="margin-top:4px;font-style:italic">Poznámka manažera: "${esc(rez.pokoj_zadost_poznamka)}"</div>` : ''}
        </div>` : ''}
        <div class="modal-body" style="display:grid;grid-template-columns:1fr 1fr;gap:20px">
          <div>
            <div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:10px">
              <div style="font-size:11px;font-weight:600;letter-spacing:.5px;color:var(--gray-400)">HOST</div>
              ${mozeEditovat ? `<button class="btn btn-sm btn-secondary" style="font-size:11px;padding:3px 8px" onclick="toggleEditHost(${id})">✏️ Upravit</button>` : ''}
            </div>
            <div id="hostView_${id}">
              <div style="font-size:14px;font-weight:700;margin-bottom:4px;display:flex;align-items:center;gap:6px">
                <span>${esc(rez.jmeno + ' ' + rez.prijmeni)}</span>
                <span title="Vyplněno v jazyce ${({cs:'CZ',en:'EN',de:'DE'})[rez.jazyk] || 'CZ'}" style="font-size:15px">${({cs:'🇨🇿',en:'🇬🇧',de:'🇩🇪'})[rez.jazyk] || '🇨🇿'}</span>
              </div>
              <div style="font-size:13px;color:var(--gray-600);">${esc(rez.email)}</div>
              <div style="font-size:13px;color:var(--gray-600);">${esc(rez.telefon||'—')}</div>
              <div style="font-size:13px;color:var(--gray-400);margin-top:6px">${rez.pocet_hostu} host(é)</div>
              ${rez.poznamka ? `<div style="font-size:12px;color:var(--gray-500);margin-top:6px;font-style:italic">"${esc(rez.poznamka)}"</div>` : ''}
              ${rez.faktura_ulice || rez.na_firmu ? `
              <div style="margin-top:10px;padding-top:10px;border-top:1px solid var(--gray-100)">
                ${rez.na_firmu ? `
                  <div style="font-size:11px;font-weight:600;letter-spacing:.5px;color:var(--gray-400);margin-bottom:6px">FIREMNÍ FAKTURACE</div>
                  ${rez.firma ? `<div style="font-size:13px;font-weight:500">${esc(rez.firma)}</div>` : ''}
                  <div style="font-size:12px;color:var(--gray-500);margin-top:3px">
                    ${rez.ico ? `IČO: ${esc(rez.ico)}` : ''}
                    ${rez.ico && rez.dic ? ' &nbsp;·&nbsp; ' : ''}
                    ${rez.dic ? `DIČ: ${esc(rez.dic)}` : ''}
                  </div>
                ` : `<div style="font-size:11px;font-weight:600;letter-spacing:.5px;color:var(--gray-400);margin-bottom:6px">ADRESA</div>`}
                ${rez.faktura_ulice ? `<div style="font-size:12px;color:var(--gray-500);margin-top:2px">${esc(rez.faktura_ulice)}, ${esc(rez.faktura_psc||'')} ${esc(rez.faktura_mesto||'')}</div>` : ''}
              </div>` : ''}
            </div>
            <div id="hostEdit_${id}" style="display:none">
              <div id="hostEditAlert" style="font-size:12px;margin-bottom:6px"></div>
              <div style="display:grid;grid-template-columns:1fr 1fr;gap:6px;margin-bottom:6px">
                <div>
                  <div style="font-size:10px;color:var(--gray-400);margin-bottom:2px">JMÉNO</div>
                  <input type="text" id="heJmeno" value="${esc(rez.jmeno)}" style="width:100%;border:1px solid var(--gray-200);border-radius:6px;padding:5px 8px;font-size:13px">
                </div>
                <div>
                  <div style="font-size:10px;color:var(--gray-400);margin-bottom:2px">PŘÍJMENÍ</div>
                  <input type="text" id="hePrijmeni" value="${esc(rez.prijmeni)}" style="width:100%;border:1px solid var(--gray-200);border-radius:6px;padding:5px 8px;font-size:13px">
                </div>
              </div>
              <div style="margin-bottom:6px">
                <div style="font-size:10px;color:var(--gray-400);margin-bottom:2px">E-MAIL</div>
                <input type="email" id="heEmail" value="${esc(rez.email)}" style="width:100%;border:1px solid var(--gray-200);border-radius:6px;padding:5px 8px;font-size:13px">
              </div>
              <div style="margin-bottom:6px">
                <div style="font-size:10px;color:var(--gray-400);margin-bottom:2px">TELEFON</div>
                <input type="tel" id="heTelefon" value="${esc(rez.telefon||'')}" style="width:100%;border:1px solid var(--gray-200);border-radius:6px;padding:5px 8px;font-size:13px">
              </div>
              <div style="margin-bottom:6px">
                <div style="font-size:10px;color:var(--gray-400);margin-bottom:2px">ULICE</div>
                <input type="text" id="heUlice" value="${esc(rez.faktura_ulice||'')}" style="width:100%;border:1px solid var(--gray-200);border-radius:6px;padding:5px 8px;font-size:13px">
              </div>
              <div style="display:grid;grid-template-columns:1fr 2fr;gap:6px;margin-bottom:6px">
                <div>
                  <div style="font-size:10px;color:var(--gray-400);margin-bottom:2px">PSČ</div>
                  <input type="text" id="hePsc" value="${esc(rez.faktura_psc||'')}" maxlength="6" oninput="formatPsc(this)" style="width:100%;border:1px solid var(--gray-200);border-radius:6px;padding:5px 8px;font-size:13px">
                </div>
                <div>
                  <div style="font-size:10px;color:var(--gray-400);margin-bottom:2px">MĚSTO</div>
                  <input type="text" id="heMesto" value="${esc(rez.faktura_mesto||'')}" style="width:100%;border:1px solid var(--gray-200);border-radius:6px;padding:5px 8px;font-size:13px">
                </div>
              </div>
              <div style="margin-bottom:8px">
                <div style="font-size:10px;color:var(--gray-400);margin-bottom:2px">POZNÁMKA</div>
                <textarea id="hePoznamka" rows="2" style="width:100%;border:1px solid var(--gray-200);border-radius:6px;padding:5px 8px;font-size:13px;resize:vertical">${esc(rez.poznamka||'')}</textarea>
              </div>
              <div style="margin-bottom:10px;padding-top:10px;border-top:1px solid var(--gray-100)">
                <label style="display:flex;align-items:center;gap:8px;cursor:pointer;font-size:13px;margin-bottom:8px">
                  <input type="checkbox" id="heNaFirmu" ${rez.na_firmu ? 'checked' : ''}
                    onchange="toggleHeFirma(this.checked)"
                    style="width:16px;height:16px;cursor:pointer">
                  <span>Fakturace na firmu</span>
                </label>
                <div id="heFirmaFields" style="display:${rez.na_firmu ? '' : 'none'}">
                  <div style="margin-bottom:6px">
                    <div style="font-size:10px;color:var(--gray-400);margin-bottom:2px">NÁZEV FIRMY</div>
                    <input type="text" id="heFirma" value="${esc(rez.firma||'')}" style="width:100%;border:1px solid var(--gray-200);border-radius:6px;padding:5px 8px;font-size:13px">
                  </div>
                  <div style="display:grid;grid-template-columns:1fr 1fr;gap:6px;margin-bottom:6px">
                    <div>
                      <div style="font-size:10px;color:var(--gray-400);margin-bottom:2px">IČO</div>
                      <div style="display:flex;gap:4px">
                        <input type="text" id="heIco" value="${esc(rez.ico||'')}" maxlength="8"
                          onblur="nacistAres()"
                          style="flex:1;border:1px solid var(--gray-200);border-radius:6px;padding:5px 8px;font-size:13px">
                      </div>
                      <div id="aresAlert" style="font-size:11px;margin-top:3px"></div>
                    </div>
                    <div>
                      <div style="font-size:10px;color:var(--gray-400);margin-bottom:2px">DIČ</div>
                      <input type="text" id="heDic" value="${esc(rez.dic||'')}" style="width:100%;border:1px solid var(--gray-200);border-radius:6px;padding:5px 8px;font-size:13px">
                    </div>
                  </div>
                </div>
              </div>
              <div style="display:flex;gap:6px">
                <button class="btn btn-primary btn-sm" onclick="ulozitHosta(${id})">Uložit</button>
                <button class="btn btn-secondary btn-sm" onclick="toggleEditHost(${id})">Zrušit</button>
              </div>
            </div>
          </div>
          <div>
            <div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:10px">
              <div style="font-size:11px;font-weight:600;letter-spacing:.5px;color:var(--gray-400)">POBYT</div>
              ${mozeEditovatTermin && rez.stav !== 'zrusena' ? `<button class="btn btn-sm btn-secondary" style="font-size:11px;padding:3px 8px" onclick="zmenitPokoj(${id})">🔁 Změnit pokoj</button>` : ''}
            </div>
            <div style="font-size:14px;font-weight:700;margin-bottom:4px">${esc(rez.pokoj_nazev)} <span style="color:var(--gray-400);font-size:12px;font-weight:400">${esc(rez.typ_nazev)}</span></div>
            ${mozeEditovatTermin ? `
            <div style="display:grid;grid-template-columns:1fr 1fr;gap:8px;margin-bottom:6px">
              <div>
                <div style="font-size:10px;color:var(--gray-400);margin-bottom:3px">PŘÍJEZD</div>
                <input type="date" id="editOd" value="${rez.datum_prijezdu}"
                  style="border:1px solid var(--gray-200);border-radius:6px;padding:5px 8px;font-size:13px;width:100%">
              </div>
              <div>
                <div style="font-size:10px;color:var(--gray-400);margin-bottom:3px">ODJEZD</div>
                <input type="date" id="editDo" value="${rez.datum_odjezdu}"
                  style="border:1px solid var(--gray-200);border-radius:6px;padding:5px 8px;font-size:13px;width:100%">
              </div>
            </div>
            <button class="btn btn-secondary btn-sm" style="margin-bottom:8px" onclick="ulozitTermin(${id})">
              Uložit termín
            </button>
            <div id="terminAlert" style="font-size:12px"></div>
            ` : `
            <div style="font-size:13px;color:var(--gray-600)">
              📅 ${formatDatumCS(rez.datum_prijezdu)} → ${formatDatumCS(rez.datum_odjezdu)}
            </div>
            `}
            <div style="font-size:13px;color:var(--gray-600)">${rez.pocet_noci} nocí</div>
            ${mozeEditovatTermin ? `
            <div style="display:flex;gap:10px;margin-top:8px">
              <div>
                <div style="font-size:10px;color:var(--gray-400)">CHECK-IN</div>
                <input type="time" value="${checkin}" id="ciCas"
                  style="border:1px solid var(--gray-200);border-radius:6px;padding:5px 8px;font-size:13px;width:90px"
                  onchange="ulozitCheckinOut(${id},'checkin',this.value)">
              </div>
              <div>
                <div style="font-size:10px;color:var(--gray-400)">CHECK-OUT</div>
                <input type="time" value="${checkout}" id="coCas"
                  style="border:1px solid var(--gray-200);border-radius:6px;padding:5px 8px;font-size:13px;width:90px"
                  onchange="ulozitCheckinOut(${id},'checkout',this.value)">
              </div>
            </div>` : `
            <div style="display:flex;gap:10px;margin-top:8px">
              <div>
                <div style="font-size:10px;color:var(--gray-400)">CHECK-IN</div>
                <div style="font-size:13px;color:var(--gray-700);padding:5px 0">${checkin}</div>
              </div>
              <div>
                <div style="font-size:10px;color:var(--gray-400)">CHECK-OUT</div>
                <div style="font-size:13px;color:var(--gray-700);padding:5px 0">${checkout}</div>
              </div>
            </div>`}
          </div>
        </div>
        <div style="padding:0 22px 14px">
          <div style="font-size:11px;font-weight:600;letter-spacing:.5px;color:var(--gray-400);margin-bottom:8px">CENA</div>
          <div style="display:flex;justify-content:space-between;font-size:13px;color:var(--gray-600);padding:3px 0">
            <span>Pokoj (${rez.pocet_noci} nocí)</span><span>${formatCena(cenaZaklad)}</span>
          </div>
          ${doplnkyHtml}
          <div style="display:flex;justify-content:space-between;font-size:15px;font-weight:600;padding:10px 0 0;border-top:1px solid var(--gray-200);margin-top:8px">
            <span>Celkem</span><span style="color:var(--blue-600)">${formatCena(cenaCelkem)}</span>
          </div>
          ${(['admin','manazer'].includes(APP.user.role) || APP.opravneni?.hodnoceni) ? `<div style="margin-top:8px">Hodnocení: ${hodnoceniHtml}</div>` : ''}
        </div>
        <div class="modal-footer" style="flex-wrap:wrap;gap:8px">
          ${rez.stav !== 'zrusena' && mozeRusit ? `
            <button class="btn btn-danger btn-sm" onclick="zrusitRezervaci(${id})">Zrušit rezervaci</button>` : ''}
          ${rez.stav !== 'zrusena' ? `
            <button class="btn btn-secondary btn-sm" onclick="navrhnoutSlevu(${id})">Navrhnout slevu</button>` : ''}
          <div style="flex:1"></div>
          <button class="btn btn-secondary btn-sm" onclick="zobrazitQR(${id}, ${cenaCelkem}, '${esc(rez.jmeno + ' ' + rez.prijmeni)}')">QR platba</button>
          ${rez.stav === 'ceka' && (APP.user.role === 'admin' || APP.user.role === 'manazer' || APP.opravneni?.potvrzeni_rezervace) ? `
            <button class="btn btn-success" onclick="potvrditRezervaci(${id})">✓ Potvrdit</button>` : ''}
          <button class="btn btn-secondary" onclick="zavritModal('rezModal')">Zavřít</button>
        </div>
      </div>
    </div>`;

  document.body.insertAdjacentHTML('beforeend', html);
}

async function ulozitTermin(id) {
  const od  = $('editOd')?.value;
  const do_ = $('editDo')?.value;
  const alertEl = $('terminAlert');
  if (!od || !do_) return;
  if (od >= do_) {
    if (alertEl) alertEl.innerHTML = '<span style="color:var(--red-600)">Datum odjezdu musí být po příjezdu.</span>';
    return;
  }
  const r = await apiFetch('guest', 'upravit', { id }, {
    datum_prijezdu: od, datum_odjezdu: do_,
    // Zachovat ostatní údaje — načteme z aktuální rezervace
    ...window._rezDetail,
  });
  if (r.ok) {
    if (alertEl) alertEl.innerHTML = '<span style="color:var(--green-600)">✓ Termín uložen.</span>';
    setTimeout(() => nactiRezervace?.(), 1000);
  } else {
    if (alertEl) alertEl.innerHTML = `<span style="color:var(--red-600)">${esc(r.error)}</span>`;
  }
}

async function ulozitCheckinOut(id, typ, cas) {
  const akce = typ === 'checkin' ? 'checkin-cas' : 'checkout-cas';

  // Admin/manažer — uložit rovnou
  if (APP.user.role !== 'zamestnanec') {
    const r = await apiFetch('guest', akce, { id }, { cas });
    if (!r.ok) alert(r.error);
    return;
  }

  // Zaměstnanec — nejdřív zjistit zda je čas nestandardní
  const r = await apiFetch('guest', akce, { id }, { cas });
  if (!r.ok) { alert(r.error); return; }

  if (r.data?.nestandardni) {
    // Zobrazit dialog s možnostmi
    const vychozi = r.data.vychozi;
    const typStr  = typ === 'checkin' ? 'check-in' : 'check-out';
    const smer    = typ === 'checkin' ? 'dřívějšího příjezdu' : 'pozdějšího odjezdu';

    const modal = document.createElement('div');
    modal.className = 'modal-overlay';
    modal.id = 'casZadostModal';
    modal.innerHTML = `<div class="modal" style="max-width:400px">
      <div class="modal-header">
        <div class="modal-title">Nestandardní čas ${typStr}</div>
        <button class="modal-close" onclick="document.getElementById('casZadostModal').remove();nactiCheckinOut(${id})">×</button>
      </div>
      <div class="modal-body">
        <p style="font-size:13px;color:var(--gray-600);margin-bottom:16px">
          Standardní čas ${typStr} je <strong>${vychozi}</strong>. Změna na <strong>${cas}</strong> vyžaduje jednu z akcí:
        </p>
        <div style="display:flex;flex-direction:column;gap:8px">
          <button class="btn btn-primary" onclick="casZadostPridat(${id},'${typ}','${cas}')">
            ➕ Přidat placenou položku (pozdní ${typStr})
          </button>
          <button class="btn btn-secondary" onclick="casZadostSchvaleni(${id},'${typ}','${cas}')">
            📋 Požádat manažera o schválení zdarma
          </button>
          <button class="btn btn-secondary" style="color:var(--gray-400)" onclick="document.getElementById('casZadostModal').remove();nactiCheckinOut(${id})">
            Zrušit (ponechat ${vychozi})
          </button>
        </div>
      </div>
    </div>`;
    document.body.appendChild(modal);
  }
}

async function casZadostPridat(id, typ, cas) {
  document.getElementById('casZadostModal')?.remove();
  // Otevřít výběr doplňků
  const det = await apiFetch('guest', 'detail', { id });
  if (det.ok) {
    const rez = det.data.rezervace;
    pridatDoplnek(id, rez.datum_prijezdu, rez.datum_odjezdu);
  }
}

async function casZadostSchvaleni(id, typ, cas) {
  document.getElementById('casZadostModal')?.remove();
  const akce = typ === 'checkin' ? 'checkin-cas' : 'checkout-cas';
  const r = await apiFetch('guest', akce, { id }, { cas, zadost: 1 });
  if (r.ok && r.data?.zadost) {
    alert('Žádost odeslána. Manažer obdrží e-mail a může ji schválit nebo zamítnout.');
    otevritRezervaci(id);
  } else if (!r.ok) {
    alert(r.error);
  }
}

function nactiCheckinOut(id) {
  // Obnovit hodnoty v polích
  otevritRezervaci(id);
}


async function schvalitCas(id) {
  if (!confirm('Schválit změnu času? Zákazník obdrží e-mail s informací.')) return;
  const r = await apiFetch('guest', 'schvalit-cas', { id });
  if (r.ok) { zavritModal('rezModal'); otevritRezervaci(id); }
  else alert(r.error);
}

async function zamitnoutCas(id) {
  if (!confirm('Zamítnout žádost?')) return;
  const poznamka = prompt('Poznámka pro zaměstnance (nepovinné):', '') || '';
  const r = await apiFetch('guest', 'zamitnout-cas', { id }, { poznamka });
  if (r.ok) { zavritModal('rezModal'); otevritRezervaci(id); }
  else alert(r.error);
}

async function schvalitZmenuPokoje(id) {
  if (!confirm('Schválit přiřazení dražšího pokoje za původní cenu?')) return;
  const r = await apiFetch('guest', 'schvalit-pokoj', { id });
  if (r.ok) { zavritModal('rezModal'); otevritRezervaci(id); nactiRezervace?.(); renderKalendar?.(); }
  else alert(r.error);
}

async function zamitnoutZmenuPokoje(id) {
  if (!confirm('Zamítnout žádost? Pokoj zůstane nezměněn.')) return;
  const poznamka = prompt('Poznámka pro zaměstnance (nepovinné):', '') || '';
  const r = await apiFetch('guest', 'zamitnout-pokoj', { id }, { poznamka });
  if (r.ok) { zavritModal('rezModal'); otevritRezervaci(id); }
  else alert(r.error);
}

// ============================================================
//  QR PLATBA (SPD formát)
// ============================================================
async function zobrazitQR(rezervace_id, castka, jmeno_hosta) {
  const nas = APP.nastaveni || {};
  const iban = (nas.hotel_iban || '').replace(/\s/g, '').toUpperCase();
  if (!iban) {
    alert('IBAN účtu není nastaven. Vyplňte ho v Nastavení → Hotel.');
    return;
  }
  if (!/^[A-Z]{2}[0-9A-Z]{4,32}$/.test(iban)) {
    alert('IBAN účtu má neplatný formát. Zkontrolujte ho v Nastavení → Hotel.');
    return;
  }

  const castkaFormatovana = parseFloat(castka || 0).toFixed(2);
  let vs = ((nas.hotel_vs_prefix || '') + String(rezervace_id).padStart(6, '0')).replace(/[^0-9]/g, '');
  if (vs.length > 10) vs = vs.slice(-10); // VS max 10 číslic — ponechat posledních 10
  // Zpráva pro příjemce nesmí obsahovat diakritiku ani hvězdičku — SPD ji nepodporuje spolehlivě
  const zprava = ('Rezervace ' + rezervace_id)
    .normalize('NFD').replace(/[\u0300-\u036f]/g, '') // odstranit diakritiku
    .replace(/\*/g, '');

  // SPD QR string
  const spd = `SPD*1.0*ACC:${iban}*AM:${castkaFormatovana}*CC:CZK*X-VS:${vs}*MSG:${zprava}`;
  const qrUrl = `https://api.qrserver.com/v1/create-qr-code/?size=220x220&data=${encodeURIComponent(spd)}`;

  const modal = document.createElement('div');
  modal.className = 'modal-overlay';
  modal.id = 'qrModal';
  modal.onclick = e => { if (e.target === modal) modal.remove(); };
  modal.innerHTML = `
    <div class="modal" style="max-width:340px">
      <div class="modal-header">
        <div class="modal-title">QR platba — Rezervace #${rezervace_id}</div>
        <button class="modal-close" onclick="document.getElementById('qrModal').remove()">×</button>
      </div>
      <div class="modal-body" style="text-align:center">
        <img src="${qrUrl}" alt="QR kód platby" style="width:220px;height:220px;margin:8px auto;display:block;border-radius:8px">
        <div style="margin-top:16px;font-size:13px;color:var(--gray-600);line-height:1.8">
          <div><strong>Účet:</strong> ${iban.replace(/(.{4})/g,'$1 ').trim()}</div>
          <div><strong>Částka:</strong> ${Number(castka).toLocaleString('cs-CZ')} Kč</div>
          <div><strong>VS:</strong> ${vs}</div>
          <div><strong>Host:</strong> ${jmeno_hosta}</div>
        </div>
        <p style="font-size:11px;color:var(--gray-400);margin-top:12px">Naskenujte QR kód v bankovní aplikaci</p>
      </div>
    </div>`;
  document.body.appendChild(modal);
}

// ============================================================
//  ÚPRAVA DOPLŇKŮ V REZERVACI
// ============================================================
async function odebratrDoplnek(rezervace_id, doplnek_id, nazev) {
  if (!confirm(`Odebrat "${nazev}" z rezervace?
Cena bude přepočítána.`)) return;
  const r = await apiFetch('guest', 'odebrat-doplnek', { id: rezervace_id }, { doplnek_id, nazev });
  if (r.ok) {
    zavritModal('rezModal');
    otevritRezervaci(rezervace_id);
    nactiRezervace?.();
  } else alert(r.error);
}

async function pridatDoplnek(rezervace_id, datum_od, datum_do) {
  const det = await apiFetch('guest', 'detail', { id: rezervace_id });
  const pocet_hostu = det.ok ? det.data.rezervace.pocet_hostu : 1;

  const r = await apiFetch('dostupnost', 'doplnky', { datum_od, datum_do, rezervace_id, pocet_hostu });
  if (!r.ok) { alert(r.error); return; }
  const dostupne = r.data.doplnky.filter(d => d.dostupny);
  if (!dostupne.length) { alert('Žádné dostupné doplňky pro tento termín.'); return; }

  const volby = dostupne.map(d =>
    `<div style="display:flex;align-items:center;justify-content:space-between;padding:10px 12px;margin-bottom:6px;background:var(--gray-50);border-radius:8px;border:0.5px solid var(--gray-200)">
      <div>
        <div style="font-size:13px;font-weight:500">${esc(d.nazev)}</div>
        <div style="font-size:12px;color:var(--gray-500)">${formatCena(d.cena_celkem)}</div>
      </div>
      <button class="btn btn-sm btn-primary" onclick="potvrditPridatDoplnek(${rezervace_id}, ${d.id}, '${esc(d.nazev)}', ${d.cena}, '${d.typ_uctovani}', ${d.cena_celkem})">Přidat</button>
    </div>`
  ).join('');

  const modal = document.createElement('div');
  modal.className = 'modal-overlay';
  modal.id = 'doplnekModal';
  modal.onclick = e => { if (e.target === modal) modal.remove(); };
  modal.innerHTML = `<div class="modal" style="max-width:400px">
    <div class="modal-header">
      <div class="modal-title">Přidat doplněk</div>
      <button class="modal-close" onclick="document.getElementById('doplnekModal').remove()">×</button>
    </div>
    <div class="modal-body">${volby}</div>
  </div>`;
  document.body.appendChild(modal);
}

async function potvrditPridatDoplnek(rezervace_id, doplnek_id, nazev, cena, typ, cena_celkem) {
  document.getElementById('doplnekModal')?.remove();
  const r = await apiFetch('guest', 'pridat-doplnek', { id: rezervace_id }, { doplnek_id, nazev, cena, typ_uctovani: typ, cena_celkem });
  if (r.ok) {
    zavritModal('rezModal');
    otevritRezervaci(rezervace_id);
    nactiRezervace?.();
  } else alert(r.error);
}

async function potvrditRezervaci(id) {
  // Nejdřív načíst detail rezervace pro datum a typ
  const det = await apiFetch('guest', 'detail', { id });
  if (!det.ok) { alert(det.error); return; }
  const rez = det.data.rezervace;

  // Načíst dostupné pokoje pro daný termín a typ
  const dos = await apiFetch('dostupnost', 'pokoje', {
    datum_od: rez.datum_prijezdu,
    datum_do: rez.datum_odjezdu,
    pocet_hostu: rez.pocet_hostu,
    typ_id: rez.typ_id,
    vyjmout_rezervaci: id,
    admin: 1,
  });

  const pokoje = dos.ok
    ? dos.data.pokoje.filter(p => p.dostupny && p.min_splnen && p.typ_id == rez.typ_id)
    : [];

  // Zobrazit modal s výběrem pokoje
  const modal = document.createElement('div');
  modal.className = 'modal-overlay';
  modal.id = 'potvrzeniModal';
  modal.onclick = e => { if (e.target === modal) modal.remove(); };

  const pokojVolby = pokoje.length
    ? pokoje.map(p => `
        <div style="display:flex;align-items:center;justify-content:space-between;padding:10px 12px;margin-bottom:6px;background:var(--gray-50);border-radius:8px;border:0.5px solid var(--gray-200)">
          <div>
            <div style="font-size:13px;font-weight:500">Pokoj ${esc(p.cislo)}${p.nazev ? ' — ' + esc(p.nazev) : ''}</div>
            <div style="font-size:11px;color:var(--gray-500)">${esc(p.typ_nazev)}</div>
          </div>
          <button class="btn btn-sm btn-success" onclick="dokonciPotvrzeni(${id}, ${p.id})">Přiřadit</button>
        </div>`).join('')
    : `<div class="alert alert-warn">Žádný volný pokoj tohoto typu pro daný termín.</div>`;

  modal.innerHTML = `<div class="modal" style="max-width:420px">
    <div class="modal-header">
      <div class="modal-title">Přiřadit pokoj — Rezervace #${id}</div>
      <button class="modal-close" onclick="document.getElementById('potvrzeniModal').remove()">×</button>
    </div>
    <div class="modal-body">
      <p style="font-size:13px;color:var(--gray-600);margin-bottom:14px">
        Host: <strong>${esc(rez.jmeno + ' ' + rez.prijmeni)}</strong><br>
        Typ: <strong>${esc(rez.typ_nazev || '')}</strong><br>
        Termín: ${esc(rez.datum_prijezdu)} → ${esc(rez.datum_odjezdu)}
      </p>
      ${pokojVolby}
    </div>
  </div>`;
  document.body.appendChild(modal);
}

// ============================================================
//  ZMĚNA POKOJE — krok 1: počet hostů
// ============================================================
async function zmenitPokoj(id) {
  const det = await apiFetch('guest', 'detail', { id });
  if (!det.ok) { alert(det.error); return; }
  const rez = det.data.rezervace;

  const modal = document.createElement('div');
  modal.className = 'modal-overlay';
  modal.id = 'zmenaPokojModal';
  modal.onclick = e => { if (e.target === modal) modal.remove(); };
  modal.innerHTML = `<div class="modal" style="max-width:380px">
    <div class="modal-header">
      <div class="modal-title">Změnit pokoj — Rezervace #${id}</div>
      <button class="modal-close" onclick="document.getElementById('zmenaPokojModal').remove()">×</button>
    </div>
    <div class="modal-body">
      <p style="font-size:13px;color:var(--gray-600);margin-bottom:14px">
        Aktuální pokoj: <strong>${esc(rez.pokoj_nazev)}</strong> (${esc(rez.typ_nazev)})
      </p>
      <div class="field">
        <label>Kolik hostů bude ve výsledku ubytováno?</label>
        <input type="number" id="zpPocetHostu" value="${rez.pocet_hostu}" min="1" max="20"
          style="width:100%;border:1px solid var(--gray-200);border-radius:6px;padding:8px 10px;font-size:14px">
      </div>
    </div>
    <div class="modal-footer">
      <button class="btn btn-secondary" onclick="document.getElementById('zmenaPokojModal').remove()">Zrušit</button>
      <button class="btn btn-primary" onclick="zmenitPokojKrok2(${id})">Pokračovat</button>
    </div>
  </div>`;
  document.body.appendChild(modal);
}

// ============================================================
//  ZMĚNA POKOJE — krok 2: výběr typu a konkrétního pokoje
// ============================================================
async function zmenitPokojKrok2(id) {
  const pocetHostu = parseInt($('zpPocetHostu')?.value || 1);
  document.getElementById('zmenaPokojModal')?.remove();

  const det = await apiFetch('guest', 'detail', { id });
  if (!det.ok) { alert(det.error); return; }
  const rez = det.data.rezervace;

  const dos = await apiFetch('dostupnost', 'pokoje', {
    datum_od: rez.datum_prijezdu,
    datum_do: rez.datum_odjezdu,
    pocet_hostu: pocetHostu,
    vyjmout_rezervaci: id,
    admin: 1,
  });

  const vsechnyPokoje = dos.ok ? dos.data.pokoje : [];
  const dostupne = vsechnyPokoje.filter(p => p.dostupny && p.min_splnen && p.id != rez.pokoj_id);

  // Seskupit podle typu
  const podleTypu = {};
  dostupne.forEach(p => {
    if (!podleTypu[p.typ_id]) podleTypu[p.typ_id] = { typ_nazev: p.typ_nazev, kapacita: p.kapacita, cena_za_noc: p.cena_za_noc, pokoje: [] };
    podleTypu[p.typ_id].pokoje.push(p);
  });

  const pocetNoci = rez.pocet_noci;
  const staraCena = rez.cena_upravena !== null ? rez.cena_upravena : rez.cena_zaklad;
  // Cena doplňků = staraCena - cena_zaklad (základ pokoje bez doplňků)
  const cenaDoplnky = Math.round(staraCena - rez.cena_zaklad);
  const aktualniTypId = String(rez.typ_id);

  const typySeznam = Object.entries(podleTypu).map(([typId, t]) => {
    const malaKapacita = t.kapacita < pocetHostu;
    const novaCenaZaklad = Math.round(t.cena_za_noc * pocetNoci);
    // Celková nová cena = základ nového pokoje + stávající doplňky (nemění se)
    const novaCena = novaCenaZaklad + cenaDoplnky;
    const stejnyTyp = typId === aktualniTypId;
    const rozdil = novaCena - staraCena;
    const rozdilStr = stejnyTyp || rozdil === 0
      ? 'stejná cena'
      : (rozdil > 0 ? `+${formatCena(rozdil)} dráž` : `${formatCena(Math.abs(rozdil))} levněji`);
    const rozdilBarva = (stejnyTyp || rozdil === 0) ? 'var(--gray-400)' : (rozdil > 0 ? 'var(--red-600)' : 'var(--green-600)');
    return `
      <div style="margin-bottom:10px;${malaKapacita ? 'opacity:0.6' : ''}">
        <div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:2px">
          <div style="font-size:13px;font-weight:600">${esc(t.typ_nazev)}</div>
          <div style="font-size:11px;color:var(--gray-500)">${formatCena(novaCena)}</div>
        </div>
        <div style="font-size:11px;color:${rozdilBarva};margin-bottom:4px;font-weight:500">${rozdilStr}</div>
        ${malaKapacita ? `<div style="font-size:11px;color:var(--amber-600);margin-bottom:4px">⚠️ Kapacita ${t.kapacita} os. — méně než zadaných ${pocetHostu} hostů</div>` : ''}
        ${t.pokoje.map(p => `
          <div style="display:flex;align-items:center;justify-content:space-between;padding:8px 10px;margin-bottom:4px;background:var(--gray-50);border-radius:6px;border:0.5px solid var(--gray-200)">
            <div style="font-size:12px">Pokoj ${esc(p.cislo)}${p.nazev ? ' — ' + esc(p.nazev) : ''}</div>
            <button class="btn btn-sm btn-success" onclick="zmenitPokojKrok3(${id}, ${p.id}, ${typId}, '${esc(t.typ_nazev)}', ${novaCenaZaklad}, '${esc(p.cislo)}', '${esc(p.nazev||'')}', ${stejnyTyp})">Vybrat</button>
          </div>`).join('')}
      </div>`;
  }).join('');

  const modal = document.createElement('div');
  modal.className = 'modal-overlay';
  modal.id = 'zmenaPokojModal2';
  modal.onclick = e => { if (e.target === modal) modal.remove(); };
  modal.innerHTML = `<div class="modal" style="max-width:460px">
    <div class="modal-header">
      <div class="modal-title">Vyberte pokoj — ${pocetHostu} ${pocetHostu === 1 ? 'host' : pocetHostu < 5 ? 'hosté' : 'hostů'}</div>
      <button class="modal-close" onclick="document.getElementById('zmenaPokojModal2').remove()">×</button>
    </div>
    <div class="modal-body">
      ${typySeznam || `<div class="alert alert-warn">Žádný volný pokoj pro daný termín.</div>`}
    </div>
  </div>`;
  document.body.appendChild(modal);
}

// ============================================================
//  ZMĚNA POKOJE — krok 3: potvrzení s porovnáním ceny
// ============================================================
async function zmenitPokojKrok3(id, novy_pokoj_id, novy_typ_id, novy_typ_nazev, nova_cena_zaklad, novy_pokoj_cislo, novy_pokoj_nazev, stejny_typ) {
  document.getElementById('zmenaPokojModal2')?.remove();

  const det = await apiFetch('guest', 'detail', { id });
  if (!det.ok) { alert(det.error); return; }
  const rez = det.data.rezervace;

  const stara_cena = rez.cena_upravena !== null ? rez.cena_upravena : rez.cena_zaklad;
  const novyPokojLabel = `Pokoj ${esc(novy_pokoj_cislo)}${novy_pokoj_nazev ? ' — ' + esc(novy_pokoj_nazev) : ''}`;

  // Pro stejný typ se cena nemění — základ pokoje je stejný, doplňky se nemění
  const novaCenaCelkem = nova_cena_zaklad + Math.round(stara_cena - rez.cena_zaklad);
  const rozdil = stejny_typ ? 0 : (novaCenaCelkem - stara_cena);
  const rozdilStr = rozdil === 0 ? 'Stejná cena' : (rozdil > 0 ? `+${formatCena(rozdil)}` : formatCena(Math.abs(rozdil)) + ' levněji');
  const rozdilBarva = rozdil === 0 ? 'var(--gray-500)' : (rozdil > 0 ? 'var(--red-600)' : 'var(--green-600)');

  const modal = document.createElement('div');
  modal.className = 'modal-overlay';
  modal.id = 'zmenaPokojModal3';
  modal.onclick = e => { if (e.target === modal) modal.remove(); };
  modal.innerHTML = `<div class="modal" style="max-width:380px">
    <div class="modal-header">
      <div class="modal-title">Potvrdit změnu pokoje</div>
      <button class="modal-close" onclick="document.getElementById('zmenaPokojModal3').remove()">×</button>
    </div>
    <div class="modal-body">
      <div style="background:var(--gray-50);border-radius:8px;padding:12px;font-size:13px">
        <div style="margin-bottom:8px">
          <div style="color:var(--gray-500);font-size:11px;margin-bottom:2px">PŮVODNÍ</div>
          <div>${esc(rez.typ_nazev)}, ${esc(rez.pokoj_nazev)} — ${formatCena(stara_cena)}</div>
        </div>
        <div>
          <div style="color:var(--gray-500);font-size:11px;margin-bottom:2px">NOVÝ POKOJ</div>
          <div style="font-weight:600;color:var(--blue-600)">${esc(novy_typ_nazev)}, ${novyPokojLabel} — ${formatCena(stejny_typ ? stara_cena : novaCenaCelkem)}</div>
        </div>
        <div style="border-top:1px solid var(--gray-200);margin-top:8px;padding-top:8px;display:flex;justify-content:space-between">
          <span style="color:var(--gray-500)">Rozdíl v ceně:</span>
          <span style="font-weight:600;color:${rozdilBarva}">${rozdilStr}</span>
        </div>
      </div>
      ${!stejny_typ ? `
      <div style="margin-top:12px">
        <label style="display:flex;align-items:center;gap:8px;cursor:pointer;font-size:13px">
          <input type="checkbox" id="zpPrepocitatCenu" checked onchange="zpToggleInfo(${rozdil !== 0}, ${novaCenaCelkem}, ${stara_cena})" style="width:16px;height:16px;cursor:pointer">
          <span>Přepočítat cenu dle nového typu</span>
        </label>
      </div>
      ${rozdil !== 0 ? `
      <div id="zpEmailInfo" class="alert alert-info" style="margin-top:10px;font-size:12px">
        ✉️ Zákazník dostane e-mail s informací o nové ceně.
      </div>` : ''}
      ${APP.user.role === 'zamestnanec' && novaCenaCelkem > stara_cena ? `
      <div id="zpSchvaleniInfo" class="alert alert-warn" style="margin-top:10px;font-size:12px;display:none">
        ⚠️ Ponecháváte nižší cenu u dražšího typu pokoje — změna bude čekat na schválení manažerem.
      </div>` : ''}` : `
      <div class="alert alert-ok" style="margin-top:12px;font-size:12px">
        ✓ Stejný typ pokoje — cena zůstane nezměněna, zákazníkovi nepůjde žádný e-mail.
      </div>`}
    </div>
    <div class="modal-footer">
      <button class="btn btn-secondary" onclick="document.getElementById('zmenaPokojModal3').remove()">Zrušit</button>
      <button class="btn btn-primary" onclick="dokoncitZmenuPokoje(${id}, ${novy_pokoj_id}, ${stejny_typ ? 'null' : novaCenaCelkem})">Potvrdit změnu</button>
    </div>
  </div>`;
  document.body.appendChild(modal);
}

function zpToggleInfo(rozdilExistuje, novaCena, staraCena) {
  const prepocitat = $('zpPrepocitatCenu')?.checked;
  const emailEl = document.getElementById('zpEmailInfo');
  if (emailEl) emailEl.style.display = (rozdilExistuje && prepocitat) ? '' : 'none';

  const schvEl = document.getElementById('zpSchvaleniInfo');
  if (schvEl) schvEl.style.display = (!prepocitat && novaCena > staraCena) ? '' : 'none';
}

async function dokoncitZmenuPokoje(rezervace_id, novy_pokoj_id, nova_cena) {
  const prepocitat = nova_cena !== null && $('zpPrepocitatCenu')?.checked;
  document.getElementById('zmenaPokojModal3')?.remove();
  const r = await apiFetch('guest', 'zmenit-pokoj', { id: rezervace_id }, {
    pokoj_id: novy_pokoj_id,
    nova_cena: prepocitat ? nova_cena : null,
  });
  if (r.ok) {
    if (r.data?.zadost) {
      alert('Žádost o změnu pokoje odeslána manažerovi ke schválení.');
    }
    zavritModal('rezModal');
    otevritRezervaci(rezervace_id);
    nactiRezervace?.();
    renderKalendar?.();
  } else {
    alert(r.error);
  }
}

async function dokonciPotvrzeni(rezervace_id, pokoj_id) {
  document.getElementById('potvrzeniModal')?.remove();
  const r = await apiFetch('guest', 'potvrdit', { id: rezervace_id }, { pokoj_id });
  if (r.ok) {
    zavritModal('rezModal');
    nactiRezervace?.();
    renderKalendar?.();
  } else {
    alert(r.error);
  }
}

async function zrusitRezervaci(id) {
  if (!confirm('Opravdu chcete zrušit tuto rezervaci?')) return;
  const r = await apiFetch('guest', 'zrusit', { id }, { duvod: 'Zrušeno administrátorem' });
  if (r.ok) { zavritModal('rezModal'); nactiRezervace(); }
  else alert(r.error);
}

async function rozhodnoutSlevu(id, schvalit) {
  let poznamka = '';
  if (!schvalit) {
    poznamka = prompt('Poznámka pro zaměstnance (nepovinné):', '') || '';
  }
  const r = await apiFetch('guest', schvalit ? 'schvalit-slevu' : 'zamitnout-slevu', { id }, { poznamka });
  if (r.ok) { zavritModal('rezModal'); otevritRezervaci(id); }
  else alert(r.error);
}

function navrhnoutSlevu(id) {
  const castka   = prompt('Výše slevy v Kč:');
  if (!castka) return;
  const poznamka = prompt('Důvod slevy:');
  if (!poznamka) return;
  apiFetch('guest', 'navrhnout-slevu', { id }, { castka: parseFloat(castka), poznamka })
    .then(r => { if(r.ok) { zavritModal('rezModal'); otevritRezervaci(id); } else alert(r.error); });
}

function otevritNovouRezervaci() {
  window.open('/', '_blank');
}

// ============================================================
//  ZÁKAZNÍCI
// ============================================================
async function renderZakaznici() {
  const mc = $('mainContent');
  mc.innerHTML = `
    <div class="card">
      <div class="filter-bar">
        <input type="search" id="zakSearch" placeholder="Jméno, e-mail, telefon…"
          oninput="zakFilter()" style="max-width:300px">
      </div>
      <div class="table-wrap">
        <table>
          <thead><tr>
            <th>Jméno</th><th>E-mail</th><th>Telefon</th>
            <th>Pobytů</th><th>Poslední pobyt</th><th>Průměr ⭐</th><th></th>
          </tr></thead>
          <tbody id="zakTbody"><tr><td colspan="7" class="loading-row"><div class="spinner"></div></td></tr></tbody>
        </table>
      </div>
      <div class="pagination" id="zakPagination"></div>
    </div>`;
  await nactiZakaznici();
}

let zakFilterTimeout;
function zakFilter() {
  clearTimeout(zakFilterTimeout);
  zakFilterTimeout = setTimeout(nactiZakaznici, 350);
}

async function nactiZakaznici() {
  const tbody = $('zakTbody');
  const r = await apiFetch('zakaznici', 'seznam', { search: $('zakSearch')?.value||'' });
  if (!r.ok) { tbody.innerHTML = `<tr><td colspan="7"><div class="alert alert-error">${esc(r.error)}</div></td></tr>`; return; }

  const zakaznici = r.data.zakaznici;
  if (!zakaznici.length) {
    tbody.innerHTML = '<tr><td colspan="7" class="loading-row" style="color:var(--gray-400)">Žádní zákazníci</td></tr>';
    return;
  }

  tbody.innerHTML = zakaznici.map(z => `<tr>
    <td><strong>${esc(z.jmeno + ' ' + z.prijmeni)}</strong></td>
    <td style="font-size:12px">${esc(z.email)}</td>
    <td style="font-size:12px">${esc(z.telefon||'—')}</td>
    <td>${z.pocet_pobytu||0}</td>
    <td style="font-size:12px">${z.posledni_pobyt ? formatDatumCS(z.posledni_pobyt) : '—'}</td>
    <td>${z.prumerne_hodnoceni ? '⭐ ' + z.prumerne_hodnoceni : '—'}</td>
    <td><button class="btn btn-secondary btn-sm" onclick="detailZakaznika(${z.id})">Detail</button></td>
  </tr>`).join('');
}

async function detailZakaznika(id) {
  const r = await apiFetch('zakaznici', 'detail', { id });
  if (!r.ok) { alert(r.error); return; }
  const { zakaznik: z, rezervace, stats } = r.data;

  const rezHtml = rezervace.map(rez => `
    <tr>
      <td>#${rez.id}</td>
      <td>${esc(rez.pokoj_cislo)}</td>
      <td>${formatDatumCS(rez.datum_prijezdu)}</td>
      <td>${rez.pocet_noci} nocí</td>
      <td>${{ potvrzena:'Potvrzená', ceka:'Čeká', zrusena:'Zrušená' }[rez.stav]||rez.stav}</td>
      <td>${rez.hvezdicky ? '⭐'.repeat(rez.hvezdicky) : '—'}</td>
    </tr>`).join('');

  const html = `
    <div class="modal-overlay" id="zakModal" onclick="if(event.target===this)zavritModal('zakModal')">
      <div class="modal" style="max-width:640px">
        <div class="modal-header">
          <div class="modal-title">${esc(z.jmeno + ' ' + z.prijmeni)}</div>
          <button class="modal-close" onclick="zavritModal('zakModal')">×</button>
        </div>
        <div class="modal-body">
          <div style="display:grid;grid-template-columns:1fr 1fr;gap:16px;margin-bottom:16px">
            <div>
              <div style="font-size:12px;color:var(--gray-400)">E-mail</div>
              <div>${esc(z.email)}</div>
            </div>
            <div>
              <div style="font-size:12px;color:var(--gray-400)">Telefon</div>
              <div>${esc(z.telefon||'—')}</div>
            </div>
            <div>
              <div style="font-size:12px;color:var(--gray-400)">Celkem pobytů</div>
              <div>${stats.pocet_pobytu||0}</div>
            </div>
            <div>
              <div style="font-size:12px;color:var(--gray-400)">Průměrné hodnocení</div>
              <div>${stats.prumerne_hodnoceni ? '⭐ ' + stats.prumerne_hodnoceni : '—'}</div>
            </div>
          </div>
          ${z.poznamka ? `<div class="alert alert-info" style="margin-bottom:14px">${esc(z.poznamka)}</div>` : ''}
          <div style="font-size:11px;font-weight:600;letter-spacing:.5px;color:var(--gray-400);margin-bottom:8px">HISTORIE POBYTŮ</div>
          <div class="table-wrap">
            <table>
              <thead><tr><th>#</th><th>Pokoj</th><th>Příjezd</th><th>Nocí</th><th>Stav</th><th>⭐</th></tr></thead>
              <tbody>${rezHtml}</tbody>
            </table>
          </div>
        </div>
        <div class="modal-footer">
          <button class="btn btn-secondary" onclick="zavritModal('zakModal')">Zavřít</button>
        </div>
      </div>
    </div>`;
  document.body.insertAdjacentHTML('beforeend', html);
}

// ============================================================
//  HODNOCENÍ
// ============================================================
async function renderHodnoceni() {
  const mc = $('mainContent');
  const r  = await apiFetch('hodnoceni', 'seznam');
  if (!r.ok) { mc.innerHTML = `<div class="alert alert-error">${esc(r.error)}</div>`; return; }

  const { hodnoceni, prumer, celkem } = r.data;

  mc.innerHTML = `
    <div class="stat-grid" style="grid-template-columns:repeat(2,1fr);max-width:400px;margin-bottom:20px">
      <div class="stat-card">
        <div class="stat-label">Průměr</div>
        <div class="stat-val blue">${prumer||'—'} <span style="font-size:16px">⭐</span></div>
      </div>
      <div class="stat-card">
        <div class="stat-label">Celkem hodnocení</div>
        <div class="stat-val">${celkem}</div>
      </div>
    </div>
    <div class="card">
      <div class="table-wrap">
        <table>
          <thead><tr><th>Host</th><th>Pokoj</th><th>Termín</th><th>Hodnocení</th><th>Datum</th>
            ${APP.user.role!=='zamestnanec'?'<th></th>':''}
          </tr></thead>
          <tbody>
            ${hodnoceni.length ? hodnoceni.map(h => `<tr>
              <td>${esc(h.jmeno + ' ' + h.prijmeni)}</td>
              <td>${esc(h.pokoj_cislo)}</td>
              <td style="font-size:12px">${formatDatumCS(h.datum_prijezdu)} – ${formatDatumCS(h.datum_odjezdu)}</td>
              <td><span style="color:#f59e0b">${'★'.repeat(h.hvezdicky)}${'☆'.repeat(5-h.hvezdicky)}</span></td>
              <td style="font-size:12px;color:var(--gray-400)">${formatDatumCS(h.vytvoreno.split(' ')[0])}</td>
              ${APP.user.role!=='zamestnanec'?`<td><button class="btn btn-danger btn-sm" onclick="smazatHodnoceni(${h.id})">Smazat</button></td>`:''}
            </tr>`).join('') : '<tr><td colspan="6" class="loading-row" style="color:var(--gray-400)">Žádná hodnocení</td></tr>'}
          </tbody>
        </table>
      </div>
    </div>`;
}

async function smazatHodnoceni(id) {
  if (!confirm('Smazat toto hodnocení?')) return;
  const r = await apiFetch('hodnoceni', 'smazat', { id });
  if (r.ok) renderHodnoceni();
  else alert(r.error);
}

// ============================================================
//  POKOJE
// ============================================================
async function renderPokoje() {
  const mc = $('mainContent');
  $('topbarRight').innerHTML = `
    <button class="btn btn-primary" onclick="otevritPokoj(null)">+ Přidat pokoj</button>`;

  const [rPok, rTyp] = await Promise.all([
    apiFetch('pokoje', 'seznam'),
    apiFetch('typy-pokoju', 'seznam'),
  ]);

  if (!rPok.ok) { mc.innerHTML = `<div class="alert alert-error">${esc(rPok.error)}</div>`; return; }

  const pokoje = rPok.data;
  const typy   = rTyp.ok ? rTyp.data : [];

  mc.innerHTML = `
    <div class="card" style="margin-bottom:16px">
      <div class="card-header">
        <div class="card-title">Typy pokojů</div>
        <button class="btn btn-secondary btn-sm" onclick="otevritTyp(null)">+ Nový typ</button>
      </div>
      <div class="table-wrap">
        <table>
          <thead><tr><th>Název</th><th>Kapacita</th><th>Cena/noc</th><th>Snídaně</th><th>Pokojů</th><th></th></tr></thead>
          <tbody>
            ${typy.map(t => `<tr>
              <td><strong>${esc(t.nazev)}</strong></td>
              <td>${t.kapacita} os.</td>
              <td>${formatCena(t.cena_za_noc)}</td>
              <td>${t.snidane_dostupne ? '✓' : '—'}</td>
              <td>${t.pocet_aktivnich||0} / ${t.pocet_pokoju||0}</td>
              <td class="td-akce">
                <button class="btn btn-secondary btn-sm" onclick="otevritTyp(${t.id})">Upravit</button>
                <button class="btn btn-danger btn-sm" onclick="smazatTyp(${t.id})">Smazat</button>
              </td>
            </tr>`).join('') || '<tr><td colspan="6" class="loading-row" style="color:var(--gray-400)">Žádné typy</td></tr>'}
          </tbody>
        </table>
      </div>
    </div>
    <div class="card">
      <div class="card-header"><div class="card-title">Fyzické pokoje</div></div>
      <div class="table-wrap">
        <table>
          <thead><tr><th>Číslo</th><th>Název</th><th>Typ</th><th>Stav</th><th></th></tr></thead>
          <tbody>
            ${pokoje.map(p => `<tr style="${!p.aktivni?'opacity:.5':''}">
              <td><strong>${esc(p.cislo)}</strong></td>
              <td>${esc(p.nazev||'—')}</td>
              <td>${esc(p.typ_nazev)}</td>
              <td>${p.aktivni ? '<span class="badge badge-green">Aktivní</span>' : '<span class="badge badge-gray">Neaktivní</span>'}</td>
              <td class="td-akce">
                <button class="btn btn-secondary btn-sm" onclick="otevritPokoj(${p.id})">Upravit</button>
                ${p.aktivni
                  ? `<button class="btn btn-danger btn-sm" onclick="aktivovatPokoj(${p.id},false)">Deaktivovat</button>`
                  : `<button class="btn btn-success btn-sm" onclick="aktivovatPokoj(${p.id},true)">Aktivovat</button>`}
              </td>
            </tr>`).join('') || '<tr><td colspan="5" class="loading-row" style="color:var(--gray-400)">Žádné pokoje</td></tr>'}
          </tbody>
        </table>
      </div>
    </div>`;
}

async function otevritPokoj(id) {
  const typy = (await apiFetch('typy-pokoju', 'seznam')).data || [];
  let pokoj = { cislo:'', nazev:'', typ_id:'', poradi:0 };
  if (id) {
    const r = await apiFetch('pokoje', 'detail', { id });
    if (r.ok) pokoj = r.data.pokoj;
  }

  const html = `
    <div class="modal-overlay" id="pokojModal" onclick="if(event.target===this)zavritModal('pokojModal')">
      <div class="modal">
        <div class="modal-header">
          <div class="modal-title">${id ? 'Upravit pokoj' : 'Nový pokoj'}</div>
          <button class="modal-close" onclick="zavritModal('pokojModal')">×</button>
        </div>
        <div class="modal-body">
          <div id="pokojAlert"></div>
          <div class="field-row">
            <div class="field">
              <label>Číslo pokoje *</label>
              <input type="text" id="pokojCislo" value="${esc(pokoj.cislo)}" placeholder="101">
            </div>
            <div class="field">
              <label>Název (volitelný)</label>
              <input type="text" id="pokojNazev" value="${esc(pokoj.nazev||'')}" placeholder="Zahradní pokoj">
            </div>
          </div>
          <div class="field">
            <label>Typ pokoje *</label>
            <select id="pokojTyp">
              ${typy.map(t => `<option value="${t.id}" ${t.id==pokoj.typ_id?'selected':''}>${esc(t.nazev)}</option>`).join('')}
            </select>
          </div>
          <div class="field">
            <label>Pořadí</label>
            <input type="number" id="pokojPoradi" value="${pokoj.poradi||0}" min="0">
          </div>
        </div>
        <div class="modal-footer">
          <button class="btn btn-secondary" onclick="zavritModal('pokojModal')">Zrušit</button>
          <button class="btn btn-primary" onclick="ulozitPokoj(${id||0})">Uložit</button>
        </div>
      </div>
    </div>`;
  document.body.insertAdjacentHTML('beforeend', html);
}

async function ulozitPokoj(id) {
  const data = {
    cislo:   $('pokojCislo').value.trim(),
    nazev:   $('pokojNazev').value.trim(),
    typ_id:  $('pokojTyp').value,
    poradi:  $('pokojPoradi').value,
  };
  const r = id
    ? await apiFetch('pokoje', 'upravit', { id }, data)
    : await apiFetch('pokoje', 'vytvorit', {}, data);
  if (r.ok) { zavritModal('pokojModal'); renderPokoje(); }
  else { $('pokojAlert').innerHTML = `<div class="alert alert-error">${esc(r.error)}</div>`; }
}

async function aktivovatPokoj(id, aktivni) {
  const r = await apiFetch('pokoje', aktivni ? 'aktivovat' : 'deaktivovat', { id });
  if (r.ok) renderPokoje();
  else alert(r.error);
}

async function otevritTyp(id) {
  let typ = { nazev:'', kapacita:2, cena_za_noc:'', min_pobyt_noci:1, snidane_dostupne:true, popis:'', poradi:0 };
  if (id) {
    const r = await apiFetch('typy-pokoju', 'detail', { id });
    if (r.ok) typ = r.data.typ;
  }

  const html = `
    <div class="modal-overlay" id="typModal" onclick="if(event.target===this)zavritModal('typModal')">
      <div class="modal">
        <div class="modal-header">
          <div class="modal-title">${id ? 'Upravit typ pokoje' : 'Nový typ pokoje'}</div>
          <button class="modal-close" onclick="zavritModal('typModal')">×</button>
        </div>
        <div class="modal-body">
          <div id="typAlert"></div>
          <div class="field">
            <label>Název (CS) *</label>
            <input type="text" id="typNazev" value="${esc(typ.nazev)}" placeholder="Dvoulůžkový Deluxe">
          </div>
          <div class="field-row">
            <div class="field">
              <label>Název (EN)</label>
              <input type="text" id="typNazevEn" value="${esc(typ.nazev_en||'')}" placeholder="Double room Deluxe">
            </div>
            <div class="field">
              <label>Název (DE)</label>
              <input type="text" id="typNazevDe" value="${esc(typ.nazev_de||'')}" placeholder="Doppelzimmer Deluxe">
            </div>
          </div>
          <div class="field-row">
            <div class="field">
              <label>Kapacita (os.) *</label>
              <input type="number" id="typKapacita" value="${typ.kapacita}" min="1" max="20">
            </div>
            <div class="field">
              <label>Cena / noc (Kč) *</label>
              <input type="number" id="typCena" value="${typ.cena_za_noc}" min="0" step="50">
            </div>
          </div>
          <div class="field-row">
            <div class="field">
              <label>Min. pobyt (nocí)</label>
              <input type="number" id="typMinNoci" value="${typ.min_pobyt_noci}" min="1">
            </div>
            <div class="field">
              <label>Pořadí</label>
              <input type="number" id="typPoradi" value="${typ.poradi||0}" min="0">
            </div>
          </div>
          <div class="field">
            <label>Popis (CS)</label>
            <textarea id="typPopis">${esc(typ.popis||'')}</textarea>
          </div>
          <div class="field">
            <label>Popis (EN)</label>
            <textarea id="typPopisEn">${esc(typ.popis_en||'')}</textarea>
          </div>
          <div class="field">
            <label>Popis (DE)</label>
            <textarea id="typPopisDe">${esc(typ.popis_de||'')}</textarea>
          </div>
          <div class="toggle-wrap">
            <button class="toggle ${typ.snidane_dostupne?'on':''}" id="typSnidane"
              onclick="this.classList.toggle('on')"></button>
            <span class="toggle-label">Nabízet snídaně</span>
          </div>
        </div>
        <div class="modal-footer">
          <button class="btn btn-secondary" onclick="zavritModal('typModal')">Zrušit</button>
          <button class="btn btn-primary" onclick="ulozitTyp(${id||0})">Uložit</button>
        </div>
      </div>
    </div>`;
  document.body.insertAdjacentHTML('beforeend', html);
}

async function ulozitTyp(id) {
  const data = {
    nazev:            $('typNazev').value.trim(),
    nazev_en:         $('typNazevEn').value.trim(),
    nazev_de:         $('typNazevDe').value.trim(),
    kapacita:         $('typKapacita').value,
    cena_za_noc:      $('typCena').value,
    min_pobyt_noci:   $('typMinNoci').value,
    popis:            $('typPopis').value.trim(),
    popis_en:         $('typPopisEn').value.trim(),
    popis_de:         $('typPopisDe').value.trim(),
    snidane_dostupne: $('typSnidane').classList.contains('on'),
    poradi:           $('typPoradi').value,
  };
  const r = id
    ? await apiFetch('typy-pokoju', 'upravit', { id }, data)
    : await apiFetch('typy-pokoju', 'vytvorit', {}, data);
  if (r.ok) { zavritModal('typModal'); renderPokoje(); }
  else { $('typAlert').innerHTML = `<div class="alert alert-error">${esc(r.error)}</div>`; }
}

async function smazatTyp(id) {
  if (!confirm('Smazat tento typ pokoje? Tuto akci nelze vrátit.')) return;
  const r = await apiFetch('typy-pokoju', 'smazat', { id });
  if (r.ok) renderPokoje();
  else alert(r.error);
}

// ============================================================
//  DOPLŇKY
// ============================================================
async function renderDoplnky() {
  const mc = $('mainContent');
  $('topbarRight').innerHTML = `<button class="btn btn-primary" onclick="otevritDoplnek(null)">+ Přidat doplněk</button>`;

  const r = await apiFetch('doplnky', 'seznam');
  if (!r.ok) { mc.innerHTML = `<div class="alert alert-error">${esc(r.error)}</div>`; return; }
  APP._doplnkySeznam = r.data;

  mc.innerHTML = `
    <div class="card">
      <div class="table-wrap">
        <table>
          <thead><tr><th>Název</th><th>Cena</th><th>Účtování</th><th>Skupina</th><th>Kapacita</th><th>Stav</th><th></th></tr></thead>
          <tbody>
            ${r.data.map(d => `<tr>
              <td><strong>${esc(d.nazev)}</strong></td>
              <td>${formatCena(d.cena)}</td>
              <td>${{'za_noc':'Za noc', 'za_osobu_noc':'Za osobu / noc', 'jednorazove':'Jednorázově'}[d.typ_uctovani] || 'Jednorázově'}</td>
              <td>${d.skupina ? `<span style="font-size:11px;background:var(--gray-100);padding:2px 8px;border-radius:10px;color:var(--gray-600)">${esc(d.skupina)}</span>` : '<span style="color:var(--gray-300)">—</span>'}</td>
              <td>${d.kapacita !== null ? d.kapacita + ' míst' : 'Neomezeno'}</td>
              <td>${d.aktivni ? '<span class="badge badge-green">Aktivní</span>' : '<span class="badge badge-gray">Neaktivní</span>'}</td>
              <td class="td-akce">
                <button class="btn btn-secondary btn-sm" onclick="otevritDoplnek(${d.id})">Upravit</button>
                ${d.aktivni
                  ? `<button class="btn btn-danger btn-sm" onclick="aktivovatDoplnek(${d.id},false)">Deaktivovat</button>`
                  : `<button class="btn btn-success btn-sm" onclick="aktivovatDoplnek(${d.id},true)">Aktivovat</button>`}
              </td>
            </tr>`).join('') || '<tr><td colspan="6" class="loading-row" style="color:var(--gray-400)">Žádné doplňky</td></tr>'}
          </tbody>
        </table>
      </div>
    </div>`;
}

async function otevritDoplnek(id) {
  let d = { nazev:'', cena:0, typ_uctovani:'jednorazove', kapacita:'', poradi:0 };
  if (id) {
    const r = await apiFetch('doplnky', 'detail', { id });
    if (r.ok) d = r.data.doplnek;
  }

  const html = `
    <div class="modal-overlay" id="doplnekModal" onclick="if(event.target===this)zavritModal('doplnekModal')">
      <div class="modal">
        <div class="modal-header">
          <div class="modal-title">${id ? 'Upravit doplněk' : 'Nový doplněk'}</div>
          <button class="modal-close" onclick="zavritModal('doplnekModal')">×</button>
        </div>
        <div class="modal-body">
          <div id="doplnekAlert"></div>
          <div class="field">
            <label>Název (CS) *</label>
            <input type="text" id="dpNazev" value="${esc(d.nazev)}" placeholder="Parkování">
          </div>
          <div class="field-row">
            <div class="field">
              <label>Název (EN)</label>
              <input type="text" id="dpNazevEn" value="${esc(d.nazev_en||'')}" placeholder="Parking">
            </div>
            <div class="field">
              <label>Název (DE)</label>
              <input type="text" id="dpNazevDe" value="${esc(d.nazev_de||'')}" placeholder="Parkplatz">
            </div>
          </div>
          <div class="field-row">
            <div class="field">
              <label>Cena (Kč) *</label>
              <input type="number" id="dpCena" value="${d.cena}" min="0" step="10">
            </div>
            <div class="field">
              <label>Typ účtování</label>
              <select id="dpTyp">
                <option value="jednorazove" ${d.typ_uctovani==='jednorazove'?'selected':''}>Jednorázově</option>
                <option value="za_noc"      ${d.typ_uctovani==='za_noc'?'selected':''}>Za každou noc</option>
                <option value="za_osobu_noc" ${d.typ_uctovani==='za_osobu_noc'?'selected':''}>Za osobu a noc</option>
              </select>
            </div>
          </div>
          <div class="field">
            <label>Kapacita (prázdné = neomezeno)</label>
            <input type="number" id="dpKapacita" value="${d.kapacita||''}" min="0" placeholder="Např. 5 pro parkování">
            <div class="field-hint">Zadejte číslo pro kapacitní doplňky (parkování, dobíjení). Prázdné = neomezeno.</div>
          </div>
          <div class="field">
            <label>Skupina (volitelné)</label>
            <input type="text" id="dpSkupina" value="${esc(d.skupina||'')}" placeholder="Např. stravovani" list="dpSkupinySeznam">
            <datalist id="dpSkupinySeznam">
              ${[...new Set((APP._doplnkySeznam||[]).map(x=>x.skupina).filter(Boolean))].map(s=>`<option value="${esc(s)}">`).join('')}
            </datalist>
            <div class="field-hint">Doplňky se stejnou skupinou se zákazníkovi zobrazí jako výběr jedné možnosti (např. Snídaně / Polopenze / All inclusive), ne jako nezávislé zaškrtávátko. Ponechte prázdné pro samostatný doplněk.</div>
          </div>
        </div>
        <div class="modal-footer">
          <button class="btn btn-secondary" onclick="zavritModal('doplnekModal')">Zrušit</button>
          <button class="btn btn-primary" onclick="ulozitDoplnek(${id||0})">Uložit</button>
        </div>
      </div>
    </div>`;
  document.body.insertAdjacentHTML('beforeend', html);
}

async function ulozitDoplnek(id) {
  const data = {
    nazev:         $('dpNazev').value.trim(),
    nazev_en:      $('dpNazevEn').value.trim(),
    nazev_de:      $('dpNazevDe').value.trim(),
    cena:          $('dpCena').value,
    typ_uctovani:  $('dpTyp').value,
    kapacita:      $('dpKapacita').value || '',
    skupina:       $('dpSkupina').value.trim(),
  };
  const r = id
    ? await apiFetch('doplnky', 'upravit', { id }, data)
    : await apiFetch('doplnky', 'vytvorit', {}, data);
  if (r.ok) { zavritModal('doplnekModal'); renderDoplnky(); }
  else { $('doplnekAlert').innerHTML = `<div class="alert alert-error">${esc(r.error)}</div>`; }
}

async function aktivovatDoplnek(id, aktivni) {
  const r = await apiFetch('doplnky', aktivni ? 'aktivovat' : 'deaktivovat', { id });
  if (r.ok) renderDoplnky();
  else alert(r.error);
}

// ============================================================
//  UŽIVATELÉ
// ============================================================
async function renderUzivatele() {
  const mc = $('mainContent');
  $('topbarRight').innerHTML = `<button class="btn btn-primary" onclick="otevritUzivatele(null)">+ Přidat uživatele</button>`;

  const r = await apiFetch('uzivatele', 'seznam');
  if (!r.ok) { mc.innerHTML = `<div class="alert alert-error">${esc(r.error)}</div>`; return; }

  const roleBadge = { admin:'<span class="badge badge-red">Admin</span>',
    manazer:'<span class="badge badge-blue">Manažer</span>',
    zamestnanec:'<span class="badge badge-gray">Zaměstnanec</span>' };

  mc.innerHTML = `
    <div class="card">
      <div class="table-wrap">
        <table>
          <thead><tr><th>Jméno</th><th>Login</th><th>Role</th><th>Stav</th><th>Přihlášení</th><th></th></tr></thead>
          <tbody>
            ${r.data.map(u => `<tr style="${!u.aktivni?'opacity:.5':''}">
              <td><strong>${esc(u.jmeno + ' ' + u.prijmeni)}</strong>${u.email?`<br><span style="font-size:11px;color:var(--gray-400)">${esc(u.email)}</span>`:''}</td>
              <td style="font-family:monospace;font-size:12px">${esc(u.login)}</td>
              <td>${roleBadge[u.role]||u.role}</td>
              <td>${u.aktivni?'<span class="badge badge-green">Aktivní</span>':'<span class="badge badge-gray">Blokován</span>'}</td>
              <td style="font-size:12px;color:var(--gray-400)">${u.posl_prihlaseni?formatDatumCS(u.posl_prihlaseni.split(' ')[0]):'nikdy'}</td>
              <td class="td-akce">
                <button class="btn btn-secondary btn-sm" onclick="otevritUzivatele(${u.id})">Upravit</button>
                ${u.role !== 'admin' ? `
                  ${u.aktivni
                    ? `<button class="btn btn-danger btn-sm" onclick="blokovatUzivatele(${u.id},false)">Blokovat</button>`
                    : `<button class="btn btn-success btn-sm" onclick="blokovatUzivatele(${u.id},true)">Odblokovat</button>`}
                ` : ''}
              </td>
            </tr>`).join('') || '<tr><td colspan="6" class="loading-row" style="color:var(--gray-400)">Žádní uživatelé</td></tr>'}
          </tbody>
        </table>
      </div>
    </div>`;
}

async function otevritUzivatele(id) {
  let u = { jmeno:'', prijmeni:'', email:'', role:'zamestnanec' };
  let opravneni = {};
  if (id) {
    const r = await apiFetch('uzivatele', 'detail', { id });
    if (r.ok) {
      u = r.data.uzivatel;
      opravneni = Object.fromEntries(r.data.opravneni.map(o => [o.opravneni, o.povoleno]));
    }
  }

  const jeZam = u.role === 'zamestnanec';
  const jeManazer = u.role === 'manazer' || u.role === 'admin';
  const opHtml = jeZam || !id ? `
    <div style="background:var(--gray-50);border-radius:8px;padding:14px;margin-top:4px" id="opravneniWrap">
      <div style="font-size:11px;font-weight:600;letter-spacing:.5px;color:var(--gray-400);margin-bottom:10px">OPRÁVNĚNÍ ZAMĚSTNANCE</div>
      ${[
        ['kartoteka','👥 Zákazníci'],
        ['hodnoceni','⭐ Hodnocení'],
        ['trzby','📋 Přehled'],
        ['statistiky_modul','📊 Statistiky'],
        ['zmena_rezervace','✏️ Editace hosta a adresy'],
        ['zmena_terminu','📅 Změna termínu'],
        ['potvrzeni_rezervace','✓ Potvrzení rezervace'],
        ['storno_rezervace','🗑️ Storno rezervace'],
      ].map(([k,l]) => `
        <div class="toggle-wrap" style="margin-bottom:8px">
          <button class="toggle ${opravneni[k]?'on':''}" id="op_${k}" onclick="this.classList.toggle('on')"></button>
          <span class="toggle-label">${l}</span>
        </div>`).join('')}
    </div>` : '';

  const notifHtml = jeManazer && id ? `
    <div style="background:var(--gray-50);border-radius:8px;padding:14px;margin-top:12px">
      <div style="font-size:11px;font-weight:600;letter-spacing:.5px;color:var(--gray-400);margin-bottom:10px">📬 E-MAILOVÉ NOTIFIKACE</div>
      ${[
        ['notif_nova_rezervace','📥 Nová rezervace'],
        ['notif_navrh_slevy','💰 Návrh slevy ke schválení'],
        ['notif_storno','🗑️ Storno rezervace'],
        ['notif_zadost_cas','🕑 Žádost o změnu check-in/out'],
      ].map(([k,l]) => `
        <div class="toggle-wrap" style="margin-bottom:8px">
          <button class="toggle ${u[k]?'on':''}" id="nf_${k}" onclick="this.classList.toggle('on')"></button>
          <span class="toggle-label">${l}</span>
        </div>`).join('')}
    </div>` : '';

  const html = `
    <div class="modal-overlay" id="uzModal" onclick="if(event.target===this)zavritModal('uzModal')">
      <div class="modal">
        <div class="modal-header">
          <div class="modal-title">${id ? 'Upravit uživatele' : 'Nový uživatel'}</div>
          <button class="modal-close" onclick="zavritModal('uzModal')">×</button>
        </div>
        <div class="modal-body">
          <div id="uzAlert"></div>
          <div class="field-row">
            <div class="field"><label>Jméno *</label><input type="text" id="uzJmeno" value="${esc(u.jmeno)}"></div>
            <div class="field"><label>Příjmení *</label><input type="text" id="uzPrijmeni" value="${esc(u.prijmeni)}"></div>
          </div>
          <div class="field" id="uzLoginPreview" style="${id?'display:none':''}">
            <div class="field-hint">Login bude automaticky vygenerován: <strong id="uzLoginText">—</strong></div>
          </div>
          <div class="field">
            <label>Role *</label>
            <select id="uzRole" onchange="uzRoleZmena(this.value)" ${u.role==='admin'?'disabled':''}>
              ${APP.user.role !== 'zamestnanec' ? `<option value="manazer" ${u.role==='manazer'?'selected':''}>Manažer</option>` : ''}
              <option value="zamestnanec" ${u.role==='zamestnanec'?'selected':''}>Zaměstnanec</option>
            </select>
          </div>
          <div class="field" id="uzEmailField">
            <label>E-mail ${u.role!=='zamestnanec'?'*':''}</label>
            <input type="email" id="uzEmail" value="${esc(u.email||'')}">
          </div>
          ${!id ? `
            <div class="field">
              <label>Heslo *</label>
              <input type="password" id="uzHeslo" autocomplete="new-password">
              <div class="field-hint">Minimálně 8 znaků.</div>
            </div>` : `
            <div class="field">
              <label>Nové heslo (prázdné = beze změny)</label>
              <input type="password" id="uzHeslo" autocomplete="new-password">
            </div>`}
          ${opHtml}
          ${notifHtml}
        </div>
        <div class="modal-footer">
          ${id && u.role !== 'admin' ? `<button class="btn btn-danger" onclick="smazatUzivatele(${id})">Smazat</button>` : ''}
          <div style="flex:1"></div>
          <button class="btn btn-secondary" onclick="zavritModal('uzModal')">Zrušit</button>
          <button class="btn btn-primary" onclick="ulozitUzivatele(${id||0})">Uložit</button>
        </div>
      </div>
    </div>`;
  document.body.insertAdjacentHTML('beforeend', html);

  // Live preview loginu
  if (!id) {
    const upd = () => {
      const j = ($('uzJmeno')?.value||'').trim().toLowerCase().normalize('NFD').replace(/[\u0300-\u036f]/g,'').replace(/[^a-z]/g,'');
      const p = ($('uzPrijmeni')?.value||'').trim().toLowerCase().normalize('NFD').replace(/[\u0300-\u036f]/g,'').replace(/[^a-z]/g,'');
      const el = $('uzLoginText');
      if (el) el.textContent = j && p ? j + '.' + p : '—';
    };
    $('uzJmeno')?.addEventListener('input', upd);
    $('uzPrijmeni')?.addEventListener('input', upd);
  }
}

function uzRoleZmena(role) {
  const label = document.querySelector('#uzEmailField label');
  if (label) label.textContent = 'E-mail' + (role !== 'zamestnanec' ? ' *' : '');
  const opWrap = $('opravneniWrap');
  if (opWrap) opWrap.style.display = role === 'zamestnanec' ? '' : 'none';
}

async function ulozitUzivatele(id) {
  const heslo    = $('uzHeslo').value;
  const role     = $('uzRole').value;

  const data = {
    jmeno:    $('uzJmeno').value.trim(),
    prijmeni: $('uzPrijmeni').value.trim(),
    email:    $('uzEmail').value.trim(),
    role,
  };

  let r;
  if (id) {
    // Pokud manažer/zaměstnanec upravuje sám sebe, použij vlastni-profil
    const jeVlastni = APP.user && APP.user.id === id;
    const akce = jeVlastni ? 'vlastni-profil' : 'upravit';
    r = await apiFetch('uzivatele', akce, jeVlastni ? {} : { id }, data);
    if (r.ok && heslo) {
      await apiFetch('uzivatele', 'heslo-reset', { id }, { heslo });
    }
    // Uložit oprávnění
    if (r.ok && role === 'zamestnanec') {
      const op = {};
      ['kartoteka','hodnoceni','trzby','statistiky_modul','zmena_rezervace','zmena_terminu','potvrzeni_rezervace','storno_rezervace'].forEach(k => {
        op[k] = $('op_' + k)?.classList.contains('on') || false;
      });
      await apiFetch('uzivatele', 'opravneni', { id }, op);
    }
    // Uložit notifikace pro manažera/admina
    if (r.ok && (role === 'manazer' || role === 'admin')) {
      const notif = {};
      ['notif_nova_rezervace','notif_navrh_slevy','notif_storno','notif_zadost_cas'].forEach(k => {
        notif[k] = $('nf_' + k)?.classList.contains('on') ? 1 : 0;
      });
      await apiFetch('uzivatele', 'notifikace', { id }, notif);
    }
  } else {
    r = await apiFetch('uzivatele', 'vytvorit', {}, { ...data, heslo });
    if (r.ok && role === 'zamestnanec') {
      const newId = r.data.id;
      const op = {};
      ['kartoteka','hodnoceni','trzby','statistiky_modul','zmena_rezervace','zmena_terminu','potvrzeni_rezervace','storno_rezervace'].forEach(k => {
        op[k] = $('op_' + k)?.classList.contains('on') || false;
      });
      await apiFetch('uzivatele', 'opravneni', { id: newId }, op);
    }
  }

  if (r.ok) {
    if (r.data?.login) alert('Uživatel vytvořen. Login: ' + r.data.login);
    zavritModal('uzModal');
    renderUzivatele();
  } else {
    $('uzAlert').innerHTML = `<div class="alert alert-error">${esc(r.error)}</div>`;
  }
}

async function blokovatUzivatele(id, aktivovat) {
  const r = await apiFetch('uzivatele', aktivovat ? 'aktivovat' : 'blokovat', { id });
  if (r.ok) renderUzivatele();
  else alert(r.error);
}

async function smazatUzivatele(id) {
  if (!confirm('Opravdu smazat tohoto uživatele?')) return;
  const r = await apiFetch('uzivatele', 'smazat', { id });
  if (r.ok) { zavritModal('uzModal'); renderUzivatele(); }
  else alert(r.error);
}

// ============================================================
//  NASTAVENÍ
// ============================================================
async function renderNastaveni() {
  const mc = $('mainContent');
  const r  = await apiFetch('nastaveni', 'seznam');
  if (!r.ok) { mc.innerHTML = `<div class="alert alert-error">${esc(r.error)}</div>`; return; }

  const nas = {};
  r.data.forEach(n => { nas[n.klic] = n.hodnota; });

  mc.innerHTML = `
    <div id="nasAlert" style="margin-bottom:14px"></div>
    <div style="display:grid;grid-template-columns:1fr 1fr;gap:16px">

      <div class="card">
        <div class="card-header"><div class="card-title">Hotel</div></div>
        <div class="card-body">
          <div class="field"><label>Název hotelu</label><input type="text" id="nas_hotel_nazev" value="${esc(nas.hotel_nazev||'')}"></div>
          <div class="field"><label>Telefon</label><input type="tel" id="nas_hotel_telefon" value="${esc(nas.hotel_telefon||'')}"></div>
          <div class="field"><label>E-mail</label><input type="email" id="nas_hotel_email" value="${esc(nas.hotel_email||'')}"></div>
          <div class="field"><label>Adresa</label><input type="text" id="nas_hotel_adresa" value="${esc(nas.hotel_adresa||'')}"></div>
          <div class="field"><label>Webová adresa</label><input type="url" id="nas_hotel_web" value="${esc(nas.hotel_web||'')}"></div>
          <div class="field">
            <label>IBAN (pro QR platbu)
              <span style="font-weight:400;color:var(--gray-400);font-size:11px;margin-left:6px">
                — <a href="https://www.penize.cz/kalkulacky/vypocet-iban" target="_blank" style="color:var(--blue-500);text-decoration:none">převést číslo účtu na IBAN</a>
              </span>
            </label>
            <input type="text" id="nas_hotel_iban" placeholder="CZ65 0800 0000 0012 3456 7890" value="${esc(nas.hotel_iban||'')}">
          </div>
          <div class="field"><label>Variabilní symbol — prefix</label><input type="text" id="nas_hotel_vs_prefix" placeholder="Např. 2026" value="${esc(nas.hotel_vs_prefix||'')}"></div>
          <div class="field"><label>Úvodní text (CS)</label><textarea id="nas_uvodni_text">${esc(nas.uvodni_text||'')}</textarea></div>
          <div class="field"><label>Úvodní text (EN)</label><textarea id="nas_uvodni_text_en">${esc(nas.uvodni_text_en||'')}</textarea></div>
          <div class="field"><label>Úvodní text (DE)</label><textarea id="nas_uvodni_text_de">${esc(nas.uvodni_text_de||'')}</textarea></div>

        </div>
      </div>

      <div>
        <div class="card" style="margin-bottom:16px">
          <div class="card-header"><div class="card-title">Check-in / Check-out</div></div>
          <div class="card-body">
            <div class="field-row">
              <div class="field"><label>Check-in čas</label><input type="time" id="nas_checkin_cas" value="${esc(nas.checkin_cas||'14:00')}"></div>
              <div class="field"><label>Check-out čas</label><input type="time" id="nas_checkout_cas" value="${esc(nas.checkout_cas||'10:00')}"></div>
            </div>
          </div>
        </div>

        <div class="card" style="margin-bottom:16px">
          <div class="card-header"><div class="card-title">Rezervace</div></div>
          <div class="card-body">
            <div class="field-row">
              <div class="field"><label>Min. dnů předem</label><input type="number" id="nas_rezervace_min_predem_dni" value="${esc(nas.rezervace_min_predem_dni||'1')}" min="0"></div>
              <div class="field"><label>Storno zdarma (dní)</label><input type="number" id="nas_rezervace_storno_dni" value="${esc(nas.rezervace_storno_dni||'3')}" min="0"></div>
            </div>
          </div>
        </div>

        <div class="card" style="margin-bottom:16px">
          <div class="card-header"><div class="card-title">Kapacity doplňků</div></div>
          <div class="card-body">
            <div class="field-row">
              <div class="field"><label>Parkovacích míst</label><input type="number" id="nas_parkovani_kapacita" value="${esc(nas.parkovani_kapacita||'5')}" min="0"></div>
              <div class="field"><label>Dobíjecích míst</label><input type="number" id="nas_dobijeni_kapacita" value="${esc(nas.dobijeni_kapacita||'2')}" min="0"></div>
            </div>
          </div>
        </div>

        <div class="card" style="margin-bottom:16px">
          <div class="card-header"><div class="card-title">Sleva — jednolůžkové obsazení</div></div>
          <div class="card-body">
            <div class="toggle-wrap" style="margin-bottom:12px">
              <button class="toggle ${nas.sleva_jednoluzko_zapnuta==='1'?'on':''}" id="nas_sleva_jednoluzko_zapnuta" onclick="this.classList.toggle('on')"></button>
              <span class="toggle-label">Automatická sleva pro 1 hosta ve vícelůžkovém pokoji</span>
            </div>
            <div class="field">
              <label>Výše slevy (%)</label>
              <input type="number" id="nas_sleva_jednoluzko_procent" value="${esc(nas.sleva_jednoluzko_procent||'20')}" min="0" max="100" style="width:100px">
            </div>
          </div>
        </div>

        <div class="card">
          <div class="card-header"><div class="card-title">E-maily</div></div>
          <div class="card-body">
            <div class="toggle-wrap" style="margin-bottom:12px">
              <button class="toggle ${nas.pripominka_zapnuta==='1'?'on':''}" id="nas_pripominka_zapnuta" onclick="this.classList.toggle('on')"></button>
              <span class="toggle-label">Připomínka před příjezdem</span>
            </div>
            <div class="field"><label>Hodin před příjezdem</label><input type="number" id="nas_pripominka_hodin" value="${esc(nas.pripominka_hodin||'48')}" min="1"></div>
            <div class="toggle-wrap" style="margin:12px 0">
              <button class="toggle ${nas.hodnoceni_zapnuto==='1'?'on':''}" id="nas_hodnoceni_zapnuto" onclick="this.classList.toggle('on')"></button>
              <span class="toggle-label">Žádost o hodnocení po odjezdu</span>
            </div>
            <div class="field"><label>Hodin po odjezdu</label><input type="number" id="nas_hodnoceni_hodin_po" value="${esc(nas.hodnoceni_hodin_po||'24')}" min="1"></div>
            <div class="toggle-wrap" style="margin-top:12px">
              <button class="toggle ${nas.hodnoceni_verejne==='1'?'on':''}" id="nas_hodnoceni_verejne" onclick="this.classList.toggle('on')"></button>
              <span class="toggle-label">Zobrazit hodnocení na rezervační stránce</span>
            </div>
          </div>
        </div>
      </div>
    </div>

    <div style="margin-top:16px;display:flex;justify-content:flex-end">
      <button class="btn btn-primary" onclick="ulozitNastaveni()">Uložit nastavení</button>
    </div>`;
}

async function ulozitNastaveni() {
  const klice = [
    'hotel_nazev','hotel_telefon','hotel_email','hotel_adresa','hotel_web',
    'uvodni_text','uvodni_text_en','uvodni_text_de','cislo_uctu','checkin_cas','checkout_cas',
    'rezervace_min_predem_dni','rezervace_storno_dni',
    'hotel_iban','hotel_vs_prefix',
    'parkovani_kapacita','dobijeni_kapacita',
    'sleva_jednoluzko_procent',
    'pripominka_hodin','hodnoceni_hodin_po',
  ];

  const data = {};
  klice.forEach(k => {
    const el = $('nas_' + k);
    if (el) data[k] = el.value;
  });

  // Toggles
  ['pripominka_zapnuta','hodnoceni_zapnuto','hodnoceni_verejne','sleva_jednoluzko_zapnuta'].forEach(k => {
    const el = $('nas_' + k);
    if (el) data[k] = el.classList.contains('on') ? '1' : '0';
  });

  const r = await apiFetch('nastaveni', 'ulozit', {}, data);
  const alert = $('nasAlert');
  if (r.ok) {
    alert.innerHTML = '<div class="alert alert-ok">Nastavení bylo uloženo.</div>';
    setTimeout(() => { alert.innerHTML = ''; }, 3000);
  } else {
    alert.innerHTML = `<div class="alert alert-error">${esc(r.error)}</div>`;
  }
}

// ============================================================
//  HESLO
// ============================================================
function otevritHesloModal() {
  if (APP.user?.zmena_hesla_zakaz) { alert('Tomuto účtu nelze měnit heslo.'); return; }
  $('hesloStare').value = '';
  $('hesloNove').value  = '';
  $('hesloZnovu').value = '';
  $('hesloAlert').innerHTML = '';
  $('hesloBar').style.width = '0';
  $('hesloModal').style.display = 'flex';
}

function hesloSila(heslo) {
  let sila = 0;
  if (heslo.length >= 8) sila++;
  if (/[A-Z]/.test(heslo)) sila++;
  if (/[0-9]/.test(heslo)) sila++;
  if (/[^A-Za-z0-9]/.test(heslo)) sila++;
  const barvy = ['','#ef4444','#f59e0b','#22c55e','#16a34a'];
  $('hesloBar').style.width  = (sila * 25) + '%';
  $('hesloBar').style.background = barvy[sila] || '#ef4444';
}

async function ulozitHeslo() {
  const stare = $('hesloStare').value;
  const nove  = $('hesloNove').value;
  const znovu = $('hesloZnovu').value;
  const alertEl = $('hesloAlert');

  if (!stare || !nove || !znovu) {
    alertEl.innerHTML = '<div class="alert alert-error">Vyplňte všechna pole.</div>';
    return;
  }
  if (nove !== znovu) {
    alertEl.innerHTML = '<div class="alert alert-error">Nová hesla se neshodují.</div>';
    return;
  }

  const r = await apiFetch('heslo', 'zmenit', {}, {
    heslo_stare: stare, heslo_nove: nove, heslo_znovu: znovu,
  });

  if (r.ok) {
    alertEl.innerHTML = '<div class="alert alert-ok">Heslo bylo změněno.</div>';
    setTimeout(() => zavritModal('hesloModal'), 1500);
  } else {
    alertEl.innerHTML = `<div class="alert alert-error">${esc(r.error)}</div>`;
  }
}

// ============================================================
//  SDÍLENÉ HELPERY
// ============================================================
async function apiFetch(resource, action, params = {}, body = null) {
  // PATH_INFO přístup - obejití WAF blokování query stringu
  let url = API + '/' + encodeURIComponent(resource) + '/' + encodeURIComponent(action);
  let qs = '';
  Object.entries(params).forEach(([k,v]) => {
    if (v !== undefined && v !== '') qs += (qs ? '&' : '?') + encodeURIComponent(k) + '=' + encodeURIComponent(v);
  });
  if (qs) url += qs;

  const opts = {
    credentials: 'include',
    headers: { 'X-Session-Token': APP.token || '' },
  };
  if (body) {
    opts.method  = 'POST';
    opts.headers['Content-Type'] = 'application/json';
    opts.body    = JSON.stringify(body);
  }

  const r = await fetch(url, opts);
  const text = await r.text();
  try {
    return JSON.parse(text);
  } catch(e) {
    console.error('apiFetch:', resource, action, text.substring(0, 200));
    return { ok: false, error: 'Chyba serveru. Viz konzole (F12).' };
  }
}

function zavritModal(id) {
  const el = $(id);
  if (el) el.remove();
}

function toggleSidebar() {
  $('sidebar').classList.toggle('open');
}

async function nactiStatsBadge() {
  try {
    const r = await apiFetch('statistiky', 'prehled');
    if (r.ok && r.data.cekajici_slevy > 0) {
      const badge = $('badgeCekajici');
      if (badge) { badge.textContent = r.data.cekajici_slevy; badge.style.display = ''; }
    }
  } catch(e) {}
}

function formatDatum(d) {
  return d.getFullYear() + '-' + String(d.getMonth()+1).padStart(2,'0') + '-' + String(d.getDate()).padStart(2,'0');
}

function formatDatumCS(str) {
  if (!str) return '—';
  const [r,m,d] = str.split('-');
  const mesice = ['','ledna','února','března','dubna','května','června',
                  'července','srpna','září','října','listopadu','prosince'];
  return parseInt(d) + '. ' + mesice[parseInt(m)] + ' ' + r;
}

function formatCena(c) {
  return Number(c||0).toLocaleString('cs-CZ') + ' Kč';
}

// Responzivní menu tlačítko
if (window.innerWidth <= 900) {
  $('btnMenu').style.display = 'block';
  document.addEventListener('click', e => {
    const sb = $('sidebar');
    if (sb.classList.contains('open') && !sb.contains(e.target) && !$('btnMenu').contains(e.target)) {
      sb.classList.remove('open');
    }
  });
}

// ============================================================
//  EDITACE HOSTA
// ============================================================
async function nacistAres() {
  const icoEl = document.getElementById('heIco');
  const alertEl = document.getElementById('aresAlert');
  const ico = (icoEl?.value || '').trim().replace(/[^0-9]/g, '');
  if (!ico || ico.length < 6) return; // Tiše ignorovat pokud IČO nevypadá validně

  if (alertEl) alertEl.innerHTML = '<span style="color:var(--gray-400)">Načítám z ARES…</span>';

  try {
    const r = await fetch(`https://ares.gov.cz/ekonomicke-subjekty-v-be/rest/ekonomicke-subjekty/${ico}`);
    const text = await r.text();
    let d;
    try { d = JSON.parse(text); } catch(pe) { throw new Error('Neplatná odpověď ARES'); }

    // API může vrátit chybu v poli 'popis' nebo nenajít ico
    if (!d || !d.ico) throw new Error('Nenalezen');

    // Název firmy
    const firma = d.obchodniJmeno || '';
    if (firma) { const el = document.getElementById('heFirma'); if (el) el.value = firma; }

    // DIČ
    const dic = d.dic || '';
    if (dic) { const el = document.getElementById('heDic'); if (el) el.value = dic; }

    // Adresa - ARES vrací sidlo
    const s = d.sidlo || {};
    // Ulice: nazevUlice + číslo, nebo nazevObce + číslo pokud ulice chybí
    const nazevUlice = s.nazevUlice || '';
    const cd = s.cisloDomovni ? String(s.cisloDomovni) : '';
    const co = s.cisloOrientacni ? String(s.cisloOrientacni) : '';
    const cislo = cd ? (co ? cd + '/' + co : cd) : '';
    const ulice = [nazevUlice, cislo].filter(Boolean).join(' ');
    if (ulice) { const el = document.getElementById('heUlice'); if (el) el.value = ulice; }

    // PSČ
    const psc = s.psc ? String(s.psc) : '';
    if (psc) {
      const el = document.getElementById('hePsc');
      if (el) { el.value = psc; if (typeof formatPsc === 'function') formatPsc(el); }
    }

    // Město - nazevObce je vždy přítomno
    const mesto = s.nazevObce || '';
    if (mesto) { const el = document.getElementById('heMesto'); if (el) el.value = mesto; }

    if (alertEl) alertEl.innerHTML = '<span style="color:var(--green-600)">✓ Načteno z ARES</span>';
    setTimeout(() => { if (alertEl) alertEl.innerHTML = ''; }, 3000);

  } catch(e) {
    // Zobrazit chybu jen pokud IČO vypadá kompletní (8 číslic)
    if (ico.length === 8) {
      if (alertEl) alertEl.innerHTML = `<span style="color:var(--red-600)">IČO ${ico} nebylo v ARES nalezeno.</span>`;
    } else {
      if (alertEl) alertEl.innerHTML = '';
    }
  }
}

function toggleHeFirma(checked) {
  const el = document.getElementById('heFirmaFields');
  if (el) el.style.display = checked ? '' : 'none';
}

function toggleEditHost(id) {
  const view = document.getElementById('hostView_' + id);
  const edit = document.getElementById('hostEdit_' + id);
  if (!view || !edit) return;
  const isEdit = edit.style.display !== 'none';
  view.style.display = isEdit ? '' : 'none';
  edit.style.display = isEdit ? 'none' : '';
}

async function ulozitHosta(id) {
  const jmeno    = document.getElementById('heJmeno')?.value.trim();
  const prijmeni = document.getElementById('hePrijmeni')?.value.trim();
  const email    = document.getElementById('heEmail')?.value.trim();
  const alertEl  = document.getElementById('hostEditAlert');

  if (!jmeno || !prijmeni || !email) {
    if (alertEl) alertEl.innerHTML = '<span style="color:var(--red-600)">Jméno, příjmení a e-mail jsou povinné.</span>';
    return;
  }

  const naFirmu = document.getElementById('heNaFirmu')?.checked ? 1 : 0;
  const r = await apiFetch('guest', 'upravit-hosta', { id }, {
    jmeno, prijmeni, email,
    telefon:       document.getElementById('heTelefon')?.value.trim() || '',
    poznamka:      document.getElementById('hePoznamka')?.value.trim() || '',
    faktura_ulice: document.getElementById('heUlice')?.value.trim() || '',
    faktura_psc:   document.getElementById('hePsc')?.value.trim() || '',
    faktura_mesto: document.getElementById('heMesto')?.value.trim() || '',
    na_firmu:      naFirmu,
    firma:         document.getElementById('heFirma')?.value.trim() || '',
    ico:           document.getElementById('heIco')?.value.trim() || '',
    dic:           document.getElementById('heDic')?.value.trim() || '',
  });

  if (r.ok) {
    zavritModal('rezModal');
    otevritRezervaci(id);
  } else {
    if (alertEl) alertEl.innerHTML = `<span style="color:var(--red-600)">${esc(r.error)}</span>`;
  }
}

// ============================================================
//  ESC — zavření modalu
// ============================================================
document.addEventListener('keydown', e => {
  if (e.key !== 'Escape') return;
  // Zavřít v pořadí: vnořené modaly první
  const modaly = ['doplnekModal','potvrzeniModal','qrModal','editRezModal','uzModal','rezModal'];
  for (const id of modaly) {
    const el = document.getElementById(id);
    if (el) { el.remove(); return; }
  }
  // Modaly zobrazené přes display:flex
  const viditelne = ['hesloModal'];
  for (const id of viditelne) {
    const el = document.getElementById(id);
    if (el && el.style.display !== 'none') { el.style.display = 'none'; return; }
  }
});

// ============================================================
//  START
// ============================================================
init();

// ============================================================
//  NOTIFIKACE — polling každých 30 sekund
//  Zobrazuje aktuální nevyřízené položky (žluté + fialové)
// ============================================================
let _notifOtevreno = false;
let _notifData = [];

async function nactiNotifikace() {
  try {
    const r = await apiFetch('notifikace', 'get');
    if (!r.ok) { console.error('Notifikace error:', r.error); return; }
    _notifData = r.data.notifikace || [];
    const pocet = r.data.pocet || 0;

    const badge = $('notifBadge');
    if (badge) {
      badge.style.display = pocet > 0 ? '' : 'none';
      badge.textContent = pocet > 9 ? '9+' : pocet;
    }

    const btn = $('notifBtn');
    if (btn) btn.style.color = pocet > 0 ? '#d97706' : 'var(--gray-500)';

    if (_notifOtevreno) renderNotifDropdown();
  } catch(e) { console.error('Notifikace výjimka:', e); }
}

function renderNotifDropdown() {
  const el = $('notifSeznam');
  if (!el) return;
  if (!_notifData.length) {
    el.innerHTML = '<div style="padding:20px;text-align:center;color:var(--gray-400);font-size:13px">Vše vyřízeno ✓</div>';
    return;
  }
  el.innerHTML = _notifData.map(n => `
    <div class="notif-item" onclick="notifKlik(${n.rezervace_id})" style="border-left:3px solid ${n.barva}">
      <div class="notif-ikona">${n.ikona}</div>
      <div>
        <div class="notif-text" style="font-weight:500">${esc(n.text)}</div>
        <div class="notif-cas" style="color:${n.barva}">${esc(n.popis)}</div>
      </div>
    </div>`).join('');
}

function notifToggle() {
  _notifOtevreno = !_notifOtevreno;
  const dd = $('notifDropdown');
  if (dd) dd.style.display = _notifOtevreno ? '' : 'none';
  if (_notifOtevreno) renderNotifDropdown();
}

function notifKlik(rezervaceId) {
  _notifOtevreno = false;
  const dd = $('notifDropdown');
  if (dd) dd.style.display = 'none';
  otevritRezervaci(rezervaceId);
}

// Zavřít dropdown při kliknutí mimo
document.addEventListener('click', e => {
  if (_notifOtevreno && !$('notifWrap')?.contains(e.target)) {
    _notifOtevreno = false;
    const dd = $('notifDropdown');
    if (dd) dd.style.display = 'none';
  }
});

// Spustit polling po přihlášení
function startNotifPolling() {
  nactiNotifikace();
  setInterval(nactiNotifikace, 30000);
}
</script>
</body>
</html>
<script>
// ============================================================
//  STATISTIKY — grafický přehled
// ============================================================
async function renderStatistiky() {
  const mc = $('mainContent');
  const rokAkt = new Date().getFullYear();

  mc.innerHTML = `
    <div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:20px;flex-wrap:wrap;gap:10px">
      <h2 style="font-size:18px;font-weight:600;color:var(--gray-900);margin:0">Statistiky</h2>
      <div style="display:flex;align-items:center;gap:8px">
        <label style="font-size:13px;color:var(--gray-600)">Rok:</label>
        <select id="statRok" onchange="nactiStatistiky()" style="border:1px solid var(--gray-200);border-radius:8px;padding:6px 10px;font-size:13px">
          ${[rokAkt-1, rokAkt, rokAkt+1].map(r => `<option value="${r}" ${r===rokAkt?'selected':''}>${r}</option>`).join('')}
        </select>
      </div>
    </div>

    <!-- Grafy -->
    <div style="display:grid;grid-template-columns:1fr 1fr;gap:16px;margin-bottom:16px">
      <div class="card">
        <div class="card-header"><div class="card-title">📈 Obsazenost po měsících (%)</div></div>
        <div class="card-body" id="grafObsazenost" style="padding:16px 8px">
          <div class="loading"><div class="spinner"></div></div>
        </div>
      </div>
      <div class="card">
        <div class="card-header"><div class="card-title">💰 Tržby po měsících (Kč)</div></div>
        <div class="card-body" id="grafTrzby" style="padding:16px 8px">
          <div class="loading"><div class="spinner"></div></div>
        </div>
      </div>
    </div>

    <!-- Tabulka -->
    <div class="card">
      <div class="card-header"><div class="card-title">📋 Přehled po měsících</div></div>
      <div class="card-body" id="statTabulka">
        <div class="loading"><div class="spinner"></div></div>
      </div>
    </div>`;

  nactiStatistiky();
}

async function nactiStatistiky() {
  const rok = parseInt($('statRok')?.value || new Date().getFullYear());
  const mesice = ['Led','Úno','Bře','Dub','Kvě','Čvn','Čvc','Srp','Zář','Říj','Lis','Pro'];

  // Načíst data paralelně
  const [rObs, rTrz] = await Promise.all([
    apiFetch('statistiky', 'mesicni', { rok }),
    apiFetch('statistiky', 'trzby', { rok }),
  ]);

  if (!rObs.ok || !rTrz.ok) {
    $('grafObsazenost').innerHTML = '<div class="alert alert-error">Chyba načtení dat</div>';
    return;
  }

  const obsData = rObs.data.mesice;
  const trzData = rTrz.data.mesice;

  // Graf obsazenosti
  $('grafObsazenost').innerHTML = renderBarChart(
    mesice,
    obsData.map(m => m.obsazenost),
    '#16a34a', '%', 100
  );

  // Graf tržeb
  const maxTrz = Math.max(...trzData.map(m => m.trzby), 1);
  $('grafTrzby').innerHTML = renderBarChart(
    mesice,
    trzData.map(m => m.trzby),
    '#2563eb', ' Kč', maxTrz, true
  );

  // Tabulka
  const tbody = mesice.map((m, i) => {
    const obs = obsData[i];
    const trz = trzData[i];
    const jeAktualniMesic = (i + 1) === new Date().getMonth() + 1 && rok === new Date().getFullYear();
    return `<tr style="${jeAktualniMesic ? 'background:var(--blue-50)' : ''}">
      <td style="padding:8px 12px;font-weight:${jeAktualniMesic?600:400};color:var(--gray-900)">${m} ${rok}</td>
      <td style="padding:8px 12px;text-align:center">
        <div style="display:flex;align-items:center;gap:8px;justify-content:center">
          <div style="width:60px;height:6px;background:var(--gray-100);border-radius:3px">
            <div style="width:${obs.obsazenost}%;height:100%;background:#16a34a;border-radius:3px"></div>
          </div>
          <span style="font-size:13px;color:var(--gray-700);min-width:40px">${obs.obsazenost} %</span>
        </div>
      </td>
      <td style="padding:8px 12px;text-align:right;font-size:13px;color:var(--gray-700)">${trz.pocet_rezervaci}</td>
      <td style="padding:8px 12px;text-align:right;font-size:13px;color:var(--gray-700)">${trz.celkem_noci || 0}</td>
      <td style="padding:8px 12px;text-align:right;font-size:13px;font-weight:500;color:var(--blue-600)">${Number(trz.trzby).toLocaleString('cs-CZ')} Kč</td>
    </tr>`;
  }).join('');

  const celkemTrz = trzData.reduce((s, m) => s + parseFloat(m.trzby || 0), 0);
  const celkemRez = trzData.reduce((s, m) => s + parseInt(m.pocet_rezervaci || 0), 0);
  const celkemNoci = trzData.reduce((s, m) => s + parseInt(m.celkem_noci || 0), 0);
  const prumObs = obsData.length ? (obsData.reduce((s, m) => s + m.obsazenost, 0) / 12).toFixed(1) : 0;

  $('statTabulka').innerHTML = `
    <table style="width:100%;border-collapse:collapse">
      <thead>
        <tr style="border-bottom:2px solid var(--gray-200)">
          <th style="padding:8px 12px;text-align:left;font-size:12px;color:var(--gray-500);font-weight:500">Měsíc</th>
          <th style="padding:8px 12px;text-align:center;font-size:12px;color:var(--gray-500);font-weight:500">Obsazenost</th>
          <th style="padding:8px 12px;text-align:right;font-size:12px;color:var(--gray-500);font-weight:500">Rezervace</th>
          <th style="padding:8px 12px;text-align:right;font-size:12px;color:var(--gray-500);font-weight:500">Nocí</th>
          <th style="padding:8px 12px;text-align:right;font-size:12px;color:var(--gray-500);font-weight:500">Tržby</th>
        </tr>
      </thead>
      <tbody>${tbody}</tbody>
      <tfoot>
        <tr style="border-top:2px solid var(--gray-200);background:var(--gray-50)">
          <td style="padding:10px 12px;font-weight:600;font-size:13px">Celkem / Průměr</td>
          <td style="padding:10px 12px;text-align:center;font-weight:600;font-size:13px">${prumObs} %</td>
          <td style="padding:10px 12px;text-align:right;font-weight:600;font-size:13px">${celkemRez}</td>
          <td style="padding:10px 12px;text-align:right;font-weight:600;font-size:13px">${celkemNoci}</td>
          <td style="padding:10px 12px;text-align:right;font-weight:600;font-size:13px;color:var(--blue-600)">${Number(celkemTrz).toLocaleString('cs-CZ')} Kč</td>
        </tr>
      </tfoot>
    </table>`;
}

function renderBarChart(labels, values, color, suffix, maxVal, formatKc = false) {
  const max = maxVal || Math.max(...values, 1);
  const w = 56; // šířka sloupce + mezera
  const h = 160; // výška grafu
  const pad = 8;
  const totalW = labels.length * w + pad * 2;

  const bars = labels.map((label, i) => {
    const val = values[i] || 0;
    const barH = Math.round((val / max) * h);
    const x = pad + i * w + 4;
    const y = h - barH;
    const displayVal = formatKc
      ? (val >= 1000 ? Math.round(val/1000) + 'k' : val)
      : val;

    return `
      <g>
        <rect x="${x}" y="${y}" width="${w-8}" height="${barH}"
          rx="4" fill="${color}" opacity="0.85"/>
        <text x="${x + (w-8)/2}" y="${y - 4}" text-anchor="middle"
          font-size="9" fill="var(--gray-600)">${val > 0 ? displayVal + (suffix === ' Kč' ? '' : suffix) : ''}</text>
        <text x="${x + (w-8)/2}" y="${h + 14}" text-anchor="middle"
          font-size="10" fill="var(--gray-400)">${label}</text>
      </g>`;
  }).join('');

  // Mřížka
  const gridLines = [0, 25, 50, 75, 100].filter(p => p <= (suffix === '%' ? 100 : 100)).map(p => {
    const y = h - Math.round((p / 100) * h);
    const val = suffix === '%' ? p + '%' : '';
    return `<line x1="${pad}" y1="${y}" x2="${totalW - pad}" y2="${y}"
      stroke="var(--gray-200)" stroke-width="1" stroke-dasharray="4,4"/>
      ${val ? `<text x="${pad-2}" y="${y+3}" text-anchor="end" font-size="9" fill="var(--gray-300)">${val}</text>` : ''}`;
  }).join('');

  return `<svg viewBox="0 0 ${totalW} ${h + 30}" style="width:100%;overflow:visible">
    ${gridLines}
    ${bars}
  </svg>`;
}
</script>
<script>
// ============================================================
//  GANTT DRAG & DROP + RESIZE — overlay architektura
// ============================================================

const GANTT_DND = {
  active: false,
  type: null,
  bar: null,
  rezId: null,
  startX: 0,
  origLeft: 0,
  origWidth: 0,
  origOd: null,
  origDo: null,
  CELL_W: 44,
  dny: [],
  roomW: 120,
  wasDragged: false,
};

function ganttBarClick(e, id) {
  if (GANTT_DND.wasDragged) { GANTT_DND.wasDragged = false; return; }
  otevritRezervaci(id);
}

function ganttMoveStart(e, bar) {
  const op = APP.opravneni || APP.user?.opravneni || {};
  const mozeEdit = APP.user?.role === 'admin' || APP.user?.role === 'manazer' ||
    !!(op.zmena_terminu === true || op.zmena_terminu === 1);
  if (!mozeEdit) return;
  e.preventDefault();
  e.stopPropagation();
  GANTT_DND.active    = true;
  GANTT_DND.type      = 'move';
  GANTT_DND.bar       = bar;
  GANTT_DND.rezId     = parseInt(bar.dataset.rezId);
  GANTT_DND.startX    = e.clientX;
  GANTT_DND.origLeft  = parseInt(bar.style.left);
  GANTT_DND.origWidth = parseInt(bar.style.width);
  GANTT_DND.origOd    = bar.dataset.datumOd;
  GANTT_DND.origDo    = bar.dataset.datumDo;
  GANTT_DND.wasDragged = false;
  bar.style.cursor    = 'grabbing';
  bar.style.zIndex    = '20';
  bar.style.opacity   = '0.8';
  document.body.style.userSelect = 'none';
}

function ganttResizeStart(e, smer, id) {
  e.preventDefault();
  e.stopPropagation();
  const bar = e.target.closest('.gantt-bar');
  if (!bar) return;
  GANTT_DND.active    = true;
  GANTT_DND.type      = smer === 'l' ? 'resize-l' : 'resize-r';
  GANTT_DND.bar       = bar;
  GANTT_DND.rezId     = parseInt(bar.dataset.rezId);
  GANTT_DND.startX    = e.clientX;
  GANTT_DND.origLeft  = parseInt(bar.style.left);
  GANTT_DND.origWidth = parseInt(bar.style.width);
  GANTT_DND.origOd    = bar.dataset.datumOd;
  GANTT_DND.origDo    = bar.dataset.datumDo;
  GANTT_DND.wasDragged = false;
  bar.style.cursor    = 'col-resize';
  bar.style.zIndex    = '20';
  document.body.style.userSelect = 'none';
}

document.addEventListener('mousemove', e => {
  if (!GANTT_DND.active) return;
  const dx    = e.clientX - GANTT_DND.startX;
  const CW    = GANTT_DND.CELL_W || 44;
  const delta = Math.round(dx / CW);
  if (Math.abs(dx) > 4) GANTT_DND.wasDragged = true;

  const bar = GANTT_DND.bar;
  if (!bar) return;

  if (GANTT_DND.type === 'move') {
    bar.style.left = (GANTT_DND.origLeft + delta * CW) + 'px';
  } else if (GANTT_DND.type === 'resize-r') {
    const newW = Math.max(CW - 4, GANTT_DND.origWidth + delta * CW);
    bar.style.width = newW + 'px';
  } else if (GANTT_DND.type === 'resize-l') {
    const newW = Math.max(CW - 4, GANTT_DND.origWidth - delta * CW);
    bar.style.width  = newW + 'px';
    bar.style.left   = (GANTT_DND.origLeft + (GANTT_DND.origWidth - newW)) + 'px';
  }
});

document.addEventListener('mouseup', async e => {
  if (!GANTT_DND.active) return;
  GANTT_DND.active = false;

  const bar  = GANTT_DND.bar;
  const CW   = GANTT_DND.CELL_W || 44;
  const RW   = GANTT_DND.roomW  || 120;
  const dny  = GANTT_DND.dny || [];

  document.body.style.userSelect = '';
  if (!bar) return;
  bar.style.cursor  = 'grab';
  bar.style.zIndex  = '5';
  bar.style.opacity = '1';

  if (!GANTT_DND.wasDragged) return;

  // Vypočítat nové datumy z pozice
  const newLeft  = parseInt(bar.style.left);
  const newWidth = parseInt(bar.style.width);
  const diStart  = Math.round((newLeft - RW) / CW);
  const diEnd    = Math.round((newLeft - RW + newWidth + 4) / CW);

  if (diStart < 0 || diStart >= dny.length || diEnd <= diStart) {
    // Vrátit na původní pozici
    bar.style.left  = GANTT_DND.origLeft + 'px';
    bar.style.width = GANTT_DND.origWidth + 'px';
    return;
  }

  const novaOd = dny[Math.max(0, diStart)];
  const novaDo = dny[Math.min(dny.length - 1, diEnd)] || dny[dny.length - 1];

  if (!novaOd || !novaDo || (novaOd === GANTT_DND.origOd && novaDo === GANTT_DND.origDo)) {
    bar.style.left  = GANTT_DND.origLeft + 'px';
    bar.style.width = GANTT_DND.origWidth + 'px';
    return;
  }

  // Potvrzovací dialog
  const origOdFmt = GANTT_DND.origOd ? GANTT_DND.origOd.split('-').reverse().join('.') : '';
  const origDoFmt = GANTT_DND.origDo ? GANTT_DND.origDo.split('-').reverse().join('.') : '';
  const novaOdFmt = novaOd.split('-').reverse().join('.');
  const novaDoFmt = novaDo.split('-').reverse().join('.');

  const dniPuvod = Math.round((new Date(GANTT_DND.origDo) - new Date(GANTT_DND.origOd)) / 86400000);
  const dniNove  = Math.round((new Date(novaDo) - new Date(novaOd)) / 86400000);
  let akce = 'změněn termín';
  if (dniNove > dniPuvod) akce = 'prodloužen pobyt';
  else if (dniNove < dniPuvod) akce = 'zkrácen pobyt';

  const potvrdit = await new Promise(resolve => {
    const modal = document.createElement('div');
    modal.className = 'modal-overlay';
    modal.id = 'dndConfirmModal';
    modal.innerHTML = `<div class="modal" style="max-width:380px">
      <div class="modal-header">
        <div class="modal-title">Potvrdit změnu termínu</div>
        <button class="modal-close" onclick="document.getElementById('dndConfirmModal').remove()">×</button>
      </div>
      <div class="modal-body">
        <p style="font-size:13px;color:var(--gray-600);margin-bottom:16px">
          Bude <strong>${akce}</strong> rezervace:
        </p>
        <div style="background:var(--gray-50);border-radius:8px;padding:12px;font-size:13px">
          <div style="display:flex;justify-content:space-between;margin-bottom:6px">
            <span style="color:var(--gray-500)">Původní termín:</span>
            <span>${origOdFmt} — ${origDoFmt} (${dniPuvod} nocí)</span>
          </div>
          <div style="display:flex;justify-content:space-between">
            <span style="color:var(--gray-500)">Nový termín:</span>
            <span style="font-weight:600;color:var(--blue-600)">${novaOdFmt} — ${novaDoFmt} (${dniNove} nocí)</span>
          </div>
        </div>
        <p style="font-size:12px;color:var(--gray-400);margin-top:12px">Zákazníkovi bude automaticky odeslán e-mail o změně termínu.</p>
      </div>
      <div class="modal-footer">
        <button class="btn btn-secondary" onclick="document.getElementById('dndConfirmModal').remove(); window._dndResolve(false)">Zrušit</button>
        <button class="btn btn-primary" onclick="document.getElementById('dndConfirmModal').remove(); window._dndResolve(true)">Potvrdit změnu</button>
      </div>
    </div>`;
    window._dndResolve = resolve;
    document.body.appendChild(modal);
  });

  if (!potvrdit) {
    bar.style.left    = GANTT_DND.origLeft + 'px';
    bar.style.width   = GANTT_DND.origWidth + 'px';
    bar.style.opacity = '1';
    return;
  }

  // Uložit
  bar.style.opacity = '0.5';
  try {
    const det = await apiFetch('guest', 'detail', { id: GANTT_DND.rezId });
    if (!det.ok) throw new Error(det.error);
    const rez = det.data.rezervace;
    const r = await apiFetch('guest', 'upravit', { id: GANTT_DND.rezId }, {
      typ_id: rez.typ_id, datum_prijezdu: novaOd, datum_odjezdu: novaDo,
      jmeno: rez.jmeno, prijmeni: rez.prijmeni, email: rez.email,
      telefon: rez.telefon, pocet_hostu: rez.pocet_hostu,
      poznamka: rez.poznamka, na_firmu: rez.na_firmu,
      firma: rez.firma, ico: rez.ico, dic: rez.dic,
      faktura_ulice: rez.faktura_ulice, faktura_psc: rez.faktura_psc,
      faktura_mesto: rez.faktura_mesto,
    });
    if (r.ok) {
      nactiKalendar();
    } else {
      alert('Nepodařilo se uložit: ' + r.error);
      bar.style.left    = GANTT_DND.origLeft + 'px';
      bar.style.width   = GANTT_DND.origWidth + 'px';
      bar.style.opacity = '1';
    }
  } catch(err) {
    alert('Chyba: ' + err.message);
    nactiKalendar();
  }
});

document.addEventListener('mouseleave', () => {
  if (!GANTT_DND.active) return;
  GANTT_DND.active = false;
  const bar = GANTT_DND.bar;
  if (bar) {
    bar.style.left    = GANTT_DND.origLeft + 'px';
    bar.style.width   = GANTT_DND.origWidth + 'px';
    bar.style.opacity = '1';
    bar.style.cursor  = 'grab';
    bar.style.zIndex  = '5';
  }
  document.body.style.userSelect = '';
});
</script>

Youez - 2016 - github.com/yon3zu
LinuXploit