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/kadernictvidenisa_cz/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : /volume1/web/kadernictvidenisa_cz//admin.html
<!DOCTYPE html>
<html lang="cs">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">
<title>Admin – Kadeřnictví Denisa</title>
<style>
*{box-sizing:border-box;margin:0;padding:0}
html,body{max-width:100%;overflow-x:hidden}
:root{
  --p50:#faf5ff;--p100:#f3e8ff;--p200:#e9d5ff;--p500:#a855f7;
  --p600:#9333ea;--p700:#7c3aed;--p800:#6b21a8;
  --g50:#f9fafb;--g100:#f3f4f6;--g200:#e5e7eb;--g300:#d1d5db;
  --g400:#9ca3af;--g500:#6b7280;--g700:#374151;--g900:#111827;
}
body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;background:var(--g50);color:var(--g900)}
.app{max-width:480px;margin:0 auto;padding-bottom:80px}

/* Login */
#loginView{min-height:100vh;display:flex;align-items:center;justify-content:center;padding:1rem}
.login-box{background:#fff;border:1px solid var(--g200);border-radius:20px;padding:2rem;width:100%;max-width:360px;text-align:center}
.login-logo{font-size:40px;margin-bottom:12px}
.login-title{font-size:20px;font-weight:700;margin-bottom:4px}
.login-sub{font-size:13px;color:var(--g400);margin-bottom:1.5rem}
input{width:100%;border:2px solid var(--p200);border-radius:8px;padding:11px 12px;font-size:14px;color:var(--g900);outline:none;margin-bottom:10px;font-family:inherit;background:#fff}
input:focus{border-color:var(--p500)}
.btn-login{width:100%;background:var(--p600);color:#fff;border:none;border-radius:999px;padding:13px;font-size:15px;font-weight:600;cursor:pointer}
.btn-login:hover{background:var(--p700)}
.alert{border-radius:10px;padding:10px 14px;font-size:13px;margin-bottom:12px;display:none}
.alert.error{background:#fee2e2;color:#991b1b;display:block}
.alert.success{background:#dcfce7;color:#166534;display:block}

/* Main */
#mainView{display:none}
.topbar{background:#fff;border-bottom:1px solid var(--g200);padding:14px 16px;display:flex;align-items:center;justify-content:space-between;position:sticky;top:0;z-index:10}
.topbar-title{font-size:16px;font-weight:700}
.topbar-sub{font-size:12px;color:var(--g400)}
.topbar-btn{background:none;border:1px solid var(--p200);border-radius:8px;width:34px;height:34px;cursor:pointer;color:var(--p600);font-size:16px}
.scroll{padding:14px 16px;display:flex;flex-direction:column;gap:14px}

/* Tabs */
.bottomnav{position:fixed;bottom:0;left:50%;transform:translateX(-50%);width:100%;max-width:480px;background:#fff;border-top:1px solid var(--g200);display:flex;z-index:20}
.nav-item{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;padding:10px 4px;cursor:pointer;border:none;background:none;color:var(--g400);font-size:10px;gap:3px}
.nav-item.active{color:var(--p700)}
.nav-icon{font-size:20px}

/* Tab views */
.tab-view{display:none}
.tab-view.active{display:flex;flex-direction:column;gap:14px}

/* Cards */
.card{background:#fff;border:1px solid var(--g200);border-radius:14px;padding:14px;overflow:hidden}
.card-title{font-size:14px;font-weight:600;margin-bottom:10px;display:flex;align-items:center;gap:6px}
.card-title span{font-size:16px}

/* Stats */
.stat-grid{display:grid;grid-template-columns:1fr 1fr;gap:8px}
.stat-card{background:var(--p50);border:1px solid var(--p200);border-radius:10px;padding:12px}
.stat-val{font-size:22px;font-weight:700;color:var(--p800)}
.stat-label{font-size:11px;color:var(--p600);margin-top:2px}

/* Rezervace */
.rez-item{display:flex;gap:10px;padding:10px 0;border-bottom:1px solid var(--g100)}
.rez-item:last-child{border-bottom:none;padding-bottom:0}
.rez-time{min-width:44px;background:var(--p100);border-radius:8px;padding:5px 4px;text-align:center}
.rez-time-h{font-size:13px;font-weight:700;color:var(--p800)}
.rez-time-d{font-size:10px;color:var(--p600)}
.rez-info{flex:1}
.rez-name{font-size:13px;font-weight:600}
.rez-service{font-size:12px;color:var(--g400);margin-top:1px}
.rez-actions{display:flex;gap:5px;margin-top:6px}
.btn-sm{border:none;border-radius:6px;padding:4px 10px;font-size:11px;font-weight:600;cursor:pointer}
.btn-confirm{background:#dcfce7;color:#166534}
.btn-cancel-sm{background:#fee2e2;color:#991b1b}
.btn-detail{background:var(--g100);color:var(--g700)}

/* Badge */
.badge{display:inline-flex;align-items:center;padding:2px 8px;border-radius:999px;font-size:11px;font-weight:600}
.badge-green{background:#dcfce7;color:#166534}
.badge-amber{background:#fef3c7;color:#92400e}
.badge-red{background:#fee2e2;color:#991b1b}
.badge-purple{background:var(--p100);color:var(--p800)}

/* Služby */
.svc-row{display:flex;align-items:center;justify-content:space-between;padding:10px 0;border-bottom:1px solid var(--g100)}
.svc-row:last-child{border-bottom:none}
.svc-icon{width:32px;height:32px;background:var(--p100);border-radius:8px;display:flex;align-items:center;justify-content:center;font-size:15px;flex-shrink:0}
.svc-name{font-size:13px;font-weight:600}
.svc-detail{font-size:11px;color:var(--g400)}
.svc-price{font-size:13px;font-weight:700;color:var(--p700)}
.btn-icon{width:30px;height:30px;border:1px solid var(--g200);border-radius:8px;background:none;cursor:pointer;font-size:14px}

/* Nastavení */
.set-row{display:flex;align-items:center;justify-content:space-between;padding:10px 0;border-bottom:1px solid var(--g100);gap:12px}
.set-row:last-child{border-bottom:none}
.set-label{font-size:13px;color:var(--g700);flex-shrink:1;min-width:0}
.set-sub{font-size:11px;color:var(--g400)}
.set-input{border:2px solid var(--p200);border-radius:8px;padding:6px 10px;font-size:13px;color:var(--g900);outline:none;width:130px;max-width:40vw;text-align:right;background:#fff;flex-shrink:0;min-width:0}
.set-input:focus{border-color:var(--p500)}
.days-wrap{display:flex;gap:5px;flex-wrap:wrap}
.day-pill{width:30px;height:30px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:11px;font-weight:600;cursor:pointer;border:2px solid var(--p200);color:var(--p700);background:#fff}
.day-pill.on{background:var(--p600);color:#fff;border-color:var(--p600)}
.btn-save{width:100%;background:var(--p600);color:#fff;border:none;border-radius:999px;padding:13px;font-size:15px;font-weight:600;cursor:pointer;margin-top:4px}
.btn-save:hover{background:var(--p700)}
.btn-add{display:inline-flex;align-items:center;gap:4px;background:var(--p100);color:var(--p800);border:none;border-radius:999px;padding:5px 12px;font-size:12px;font-weight:600;cursor:pointer}

/* Modal */
.modal-overlay{display:none;position:fixed;inset:0;background:rgba(0,0,0,.45);z-index:50;align-items:flex-end;justify-content:center}
.modal-overlay.active{display:flex}
.modal-sheet{background:#fff;border-radius:20px 20px 0 0;padding:16px;width:100%;max-width:480px;max-height:90vh;overflow-y:auto}
.modal-handle{width:36px;height:4px;background:var(--g200);border-radius:2px;margin:0 auto 14px}
.modal-title{font-size:16px;font-weight:700;margin-bottom:14px}
.modal-label{font-size:12px;color:var(--g500);display:block;margin-bottom:4px}
.modal-input{width:100%;border:2px solid var(--p200);border-radius:8px;padding:9px 12px;font-size:14px;color:var(--g900);outline:none;margin-bottom:10px;font-family:inherit;background:#fff}
.modal-input:focus{border-color:var(--p500)}
.btn-row{display:flex;gap:8px;margin-top:4px}
.btn-modal-save{flex:1;background:var(--p600);color:#fff;border:none;border-radius:999px;padding:11px;font-size:14px;font-weight:600;cursor:pointer}
.btn-modal-discard{flex:1;background:var(--g100);color:var(--g700);border:none;border-radius:999px;padding:11px;font-size:14px;cursor:pointer}
.loading{text-align:center;padding:1.5rem;color:var(--g400);font-size:14px}
.empty{text-align:center;padding:1.5rem;color:var(--g400);font-size:13px}

/* Blokace */
.blok-row{display:flex;align-items:center;justify-content:space-between;padding:9px 0;border-bottom:1px solid var(--g100)}
.blok-row:last-child{border-bottom:none}
.blok-date{font-size:13px;font-weight:600}
.blok-reason{font-size:11px;color:var(--g400);margin-top:1px}
.btn-del{background:none;border:none;cursor:pointer;font-size:16px;color:#9ca3af;padding:4px}
.btn-del:hover{color:#991b1b}
.drag-handle{cursor:grab;color:#d1d5db;font-size:18px;padding:0 4px;user-select:none;flex-shrink:0}
.drag-handle:active{cursor:grabbing}
.svc-row.sortable-ghost{opacity:.4;background:#faf5ff}
.svc-row.sortable-chosen{background:#faf5ff}
.zak-card{background:#fff;border:0.5px solid var(--g200);border-radius:12px;padding:12px 14px;cursor:pointer;transition:all .15s;margin-bottom:8px}
.zak-card:hover{border-color:#e9d5ff;background:#faf5ff}
.zak-avatar{width:38px;height:38px;border-radius:50%;background:#f3e8ff;display:flex;align-items:center;justify-content:center;font-size:14px;font-weight:700;color:#7c3aed;flex-shrink:0}
.zak-name{font-size:14px;font-weight:600;color:#111827}
.zak-sub{font-size:11px;color:#9ca3af;margin-top:1px}
.zak-stat{font-size:11px;color:#7c3aed;background:#f3e8ff;border-radius:6px;padding:2px 7px;white-space:nowrap}
.stitek{display:inline-flex;align-items:center;gap:3px;background:#f3e8ff;color:#6b21a8;font-size:11px;font-weight:500;padding:2px 8px;border-radius:999px;margin:2px}
.stitek-del{cursor:pointer;opacity:.6;font-size:10px}
.stitek-del:hover{opacity:1}
.rez-checkbox{width:16px;height:16px;accent-color:#9333ea;cursor:pointer;flex-shrink:0;margin-top:2px}
.rez-item.checked{background:#faf5ff;border-radius:8px}
.hromadne-bar{display:none;background:#f3e8ff;border:1.5px solid #e9d5ff;border-radius:10px;padding:10px 12px;margin-bottom:10px;align-items:center;justify-content:space-between;gap:10px}
.hromadne-bar.show{display:flex}
.hromadne-info{font-size:13px;color:#6b21a8;font-weight:500}
.btn-hromadne{background:#9333ea;color:#fff;border:none;border-radius:999px;padding:8px 16px;font-size:13px;font-weight:600;cursor:pointer}
.btn-hromadne:hover{background:#7c3aed}
.btn-hromadne-zrusit{background:none;border:1.5px solid #e9d5ff;border-radius:999px;padding:7px 14px;font-size:12px;color:#9333ea;cursor:pointer}

/* Výběr části dne */
.cal-strip{display:flex;gap:6px;overflow-x:auto;padding-bottom:4px}
.cal-strip::-webkit-scrollbar{display:none}
.view-btn{border:1.5px solid #e9d5ff;border-radius:8px;padding:5px 10px;font-size:12px;color:#7c3aed;background:#fff;cursor:pointer}
.view-btn.active{background:#9333ea;color:#fff;border-color:#9333ea}
.cal-nav-btn{width:28px;height:28px;border:1px solid #e9d5ff;border-radius:6px;background:none;cursor:pointer;color:#9333ea;font-size:16px}
.cal-nav-btn:hover{background:#faf5ff}
.mesic-den{border-radius:6px;padding:4px 2px;text-align:center;font-size:12px;cursor:pointer;min-height:36px;position:relative;border:1.5px solid transparent}
.mesic-den:hover:not(.mesic-disabled):not(.mesic-empty){background:#faf5ff;border-color:#e9d5ff}
.mesic-den.mesic-dnes{border-color:#d8b4fe;color:#7c3aed;font-weight:600}
.mesic-den.mesic-selected{background:#f3e8ff;border-color:#9333ea}
.mesic-den.mesic-disabled{color:#d1d5db;cursor:default}
.mesic-den-dots{display:flex;gap:2px;justify-content:center;margin-top:2px;flex-wrap:wrap}
.dot-ceka{width:6px;height:6px;border-radius:50%;background:#f59e0b;flex-shrink:0}
.dot-potvrzena{width:6px;height:6px;border-radius:50%;background:#22c55e;flex-shrink:0}
.dot-zrusena{width:6px;height:6px;border-radius:50%;background:#ef4444;flex-shrink:0}
.cal-pill{min-width:44px;padding:7px 4px;text-align:center;border-radius:8px;border:2px solid var(--p200);cursor:pointer;flex-shrink:0}
.cal-pill.active{background:var(--p600);border-color:var(--p600)}
.cal-pill .wd{font-size:10px;color:var(--p600)}
.cal-pill.active .wd{color:#e9d5ff}
.cal-pill .dn{font-size:15px;font-weight:700;color:var(--p800)}
.cal-pill.active .dn{color:#fff}
.cal-pill .dot{width:5px;height:5px;border-radius:50%;background:var(--p400);margin:3px auto 0}
.cal-pill.active .dot{background:#e9d5ff}
</style>
</head>
<body>

<!-- LOGIN -->
<div id="loginView">
  <div class="login-box">
    <div class="login-logo">✂️</div>
    <div class="login-title">Admin panel</div>
    <div class="login-sub" id="login-salon-nazev">načítám</div>
    <div id="login-alert" class="alert"></div>
    <input type="text" id="login-user" placeholder="Uživatelské jméno" onkeydown="if(event.key==='Enter')doLogin()">
    <input type="password" id="login-pass" placeholder="Heslo" onkeydown="if(event.key==='Enter')doLogin()">
    <div style="display:flex;align-items:center;gap:8px;margin:-4px 0 12px;text-align:left">
      <input type="checkbox" id="login-remember" style="width:16px;height:16px;accent-color:#9333ea;margin:0;flex-shrink:0">
      <label for="login-remember" style="font-size:13px;color:#6b7280;cursor:pointer">Zapamatovat mě na 90 dní</label>
    </div>
    <button class="btn-login" onclick="doLogin()">Přihlásit se</button>

  </div>
</div>

<!-- MAIN -->
<div id="mainView">
  <div class="topbar">
    <div>
      <div class="topbar-title" id="topbar-title">Dnešní přehled</div>
      <div class="topbar-sub" id="topbar-sub"></div>
    </div>
    <div style="display:flex;gap:6px"><button class="topbar-btn" onclick="openModal('modal-nova-rez')" title="Nová rezervace">➕</button><button class="topbar-btn" onclick="location.reload()" title="Obnovit stránku">🔄</button><button class="topbar-btn" onclick="openModal('modal-heslo')" title="Změnit heslo">🔑</button><button class="topbar-btn" onclick="doLogout()" title="Odhlásit">⎋</button></div>
  </div>

  <div class="app">
    <div class="scroll">

      <!-- TAB: DNES -->
      <div class="tab-view active" id="tab-dnes">
        <div class="stat-grid" id="stats-dnes">
          <div class="stat-card"><div class="stat-val">…</div><div class="stat-label">rezervací dnes</div></div>
          <div class="stat-card"><div class="stat-val">…</div><div class="stat-label">tržby dnes</div></div>
        </div>
        <div class="card">
          <div class="card-title"><span>🕐</span> Průběh dne</div>
          <div id="dnes-list"><div class="loading">Načítám…</div></div>
        </div>
      </div>

      <!-- TAB: KALENDÁŘ -->
      <div class="tab-view" id="tab-kalendar">
        <div class="card" style="padding:12px 14px">
          <div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:10px">
            <div style="display:flex;gap:6px">
              <button class="view-btn active" id="vbtn-mesic" onclick="setView('mesic')">📅 Měsíc</button>
              <button class="view-btn" id="vbtn-seznam" onclick="setView('seznam')">📋 Seznam</button>
            </div>
            <select id="kal-filtr" onchange="applyFilter()" style="border:1.5px solid #e9d5ff;border-radius:8px;padding:5px 8px;font-size:12px;color:#374151;background:#fff;outline:none">
              <option value="">Všechny</option>
              <option value="ceka">⏳ Čekající</option>
              <option value="potvrzena">✅ Potvrzené</option>
              <option value="zrusena">❌ Zrušené</option>
            </select>
          </div>

          <!-- Měsíční pohled -->
          <div id="view-mesic">
            <div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:8px">
              <button class="cal-nav-btn" onclick="mesicChange(-1)">&#8249;</button>
              <div style="font-size:14px;font-weight:600;color:#111827" id="mesic-label"></div>
              <button class="cal-nav-btn" onclick="mesicChange(1)">&#8250;</button>
            </div>
            <div style="display:grid;grid-template-columns:repeat(7,1fr);gap:2px;margin-bottom:4px" id="mesic-hlavicka"></div>
            <div style="display:grid;grid-template-columns:repeat(7,1fr);gap:2px" id="mesic-grid"></div>
            <div style="display:flex;gap:10px;margin-top:8px;flex-wrap:wrap">
              <span style="font-size:11px;color:#6b7280;display:flex;align-items:center;gap:4px"><span style="width:8px;height:8px;border-radius:50%;background:#f59e0b;display:inline-block"></span>Čeká</span>
              <span style="font-size:11px;color:#6b7280;display:flex;align-items:center;gap:4px"><span style="width:8px;height:8px;border-radius:50%;background:#22c55e;display:inline-block"></span>Potvrzeno</span>
              <span style="font-size:11px;color:#6b7280;display:flex;align-items:center;gap:4px"><span style="width:8px;height:8px;border-radius:50%;background:#ef4444;display:inline-block"></span>Zrušeno</span>
            </div>
          </div>

          <!-- Seznam pohled -->
          <div id="view-seznam" style="display:none">
            <div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:8px">
              <button class="cal-nav-btn" onclick="seznamChange(-1)">&#8249;</button>
              <div style="font-size:14px;font-weight:600;color:#111827" id="seznam-label"></div>
              <button class="cal-nav-btn" onclick="seznamChange(1)">&#8250;</button>
            </div>
          </div>
        </div>

        <!-- Detail dne / seznam výsledků -->
        <div class="hromadne-bar" id="hromadne-bar">
          <div class="hromadne-info" id="hromadne-info">0 vybraných</div>
          <div style="display:flex;gap:6px">
            <button class="btn-hromadne-zrusit" onclick="zrusitVyber()">Zrušit výběr</button>
            <button class="btn-hromadne" onclick="hromadnePotvrzeni()">✅ Potvrdit vybrané</button>
          </div>
        </div>
        <div class="card" id="kal-detail-card">
          <div class="card-title"><span>📋</span> <span id="kal-datum-label">Vyberte den</span></div>
          <div id="kal-list"><div class="empty">Vyberte den v kalendáři</div></div>
        </div>
      </div>

      <!-- TAB: SLUŽBY -->
      <div class="tab-view" id="tab-sluzby">
        <div class="card">
          <div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:10px">
            <div class="card-title" style="margin-bottom:0"><span>✂️</span> Aktivní služby</div>
            <button class="btn-add" onclick="openSvcModal(null)">+ Přidat</button>
          </div>
          <div id="sluzby-list"><div class="loading">Načítám…</div></div>
        </div>
        <div class="card">
          <div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:10px">
            <div class="card-title" style="margin-bottom:0"><span>🚫</span> Blokované termíny</div>
            <button class="btn-add" onclick="openBlokModal(null)">+ Přidat</button>
          </div>
          <div id="blok-list"><div class="loading">Načítám…</div></div>
        </div>
      </div>

      <!-- TAB: KARTOTÉKA -->
      <div class="tab-view" id="tab-kartoteka">
        <div style="display:flex;gap:8px;margin-bottom:4px">
          <input type="search" id="kartotek-search" placeholder="🔍 Hledat jméno, e-mail, telefon…" style="flex:1;border:1.5px solid #e9d5ff;border-radius:8px;padding:9px 12px;font-size:13px;outline:none;background:#fff;color:#111827" oninput="searchKartoteka(this.value)">
        </div>
        <div id="kartoteka-list"><div class="loading">Načítám…</div></div>
      </div>

      <!-- TAB: QR PLATBA -->
      <div class="tab-view" id="tab-qr">
        <div class="card">
          <div class="card-title"><span>💳</span> Generátor QR platby</div>
          <div style="font-size:12px;color:#9ca3af;margin-bottom:14px" id="qr-ucet-popis">Účet: načítám… · VS: dnešní datum (automaticky)</div>
          <div class="set-row" style="border:none;padding-top:0">
            <div><div class="set-label">Částka (Kč) *</div></div>
            <input class="set-input" type="number" id="qr-castka" placeholder="0" min="1" style="width:120px;max-width:30vw" oninput="generateQR()">
          </div>
          <div class="set-row" style="border:none">
            <div><div class="set-label">Poznámka / zpráva</div></div>
            <input class="set-input" type="text" id="qr-poznamka" placeholder="Střih…" maxlength="60" style="width:160px;max-width:42vw" oninput="generateQR()">
          </div>
          <div style="border-top:0.5px solid var(--g200);margin:10px 0;padding-top:14px;text-align:center" id="qr-wrap" style="display:none">
            <div id="qr-code" style="display:inline-block;background:#fff;padding:12px;border-radius:12px;border:1px solid #e9d5ff"></div>
            <div style="margin-top:10px;font-size:12px;color:#6b7280" id="qr-info"></div>
          </div>
          <div id="qr-placeholder" style="text-align:center;padding:1.5rem;color:#d1d5db;font-size:13px">Zadejte částku pro vygenerování QR kódu</div>
        </div>
      </div>

      <!-- TAB: NASTAVENÍ -->
      <div class="tab-view" id="tab-nastaveni">
        <div class="card">
          <div class="card-title"><span>🏪</span> Základní údaje</div>
          <div class="set-row"><div><div class="set-label">Název salónu</div></div><input class="set-input" id="set-salon_nazev" style="width:160px;max-width:42vw"></div>
          <div class="set-row"><div><div class="set-label">Telefon</div></div><input class="set-input" id="set-salon_telefon" style="width:160px;max-width:42vw"></div>
          <div class="set-row"><div><div class="set-label">Kontaktní e-mail</div></div><input class="set-input" id="set-salon_email" style="width:160px;max-width:42vw"></div>
          <div class="set-row"><div><div class="set-label">Adresa</div><div class="set-sub">Zobrazí se v patičce rezervací</div></div><input class="set-input" id="set-salon_adresa" placeholder="Ulice 1, 123 45 Město" style="width:160px;max-width:42vw"></div>
          <div class="set-row"><div><div class="set-label">Číslo účtu</div><div class="set-sub">Pro QR platbu</div></div><input class="set-input" id="set-cislo_uctu" placeholder="1234567890/5500" style="width:160px;max-width:42vw"></div>
        </div>
        <div class="card">
          <div class="card-title"><span>🕐</span> Pracovní doba</div>
          <div style="font-size:12px;color:#9ca3af;margin-bottom:12px">Zaškrtněte dny a nastavte časy pro každý den zvlášť</div>
          <div id="pracovni-doba-wrap"></div>
          <div class="set-row" style="border:none;padding-bottom:0">
            <div><div class="set-label">Délka slotu (min)</div></div>
            <input class="set-input" type="number" id="set-slot_minut" style="width:90px">
          </div>
        </div>
        <div class="card">
          <div class="card-title"><span>⚙️</span> Rezervační pravidla</div>
          <div class="set-row">
            <div><div class="set-label">Min. předstih (hod)</div></div>
            <input class="set-input" type="number" id="set-rezervace_min_predem" style="width:90px">
          </div>
          <div class="set-row">
            <div><div class="set-label">Storno do (hod)</div></div>
            <input class="set-input" type="number" id="set-rezervace_storno_hod" style="width:90px">
          </div>
        </div>
        <div class="card">
          <div class="card-title"><span>🔔</span> Připomenutí rezervace</div>
          <div class="set-row">
            <div><div class="set-label">Odesílat připomenutí</div><div class="set-sub">E-mail zákazníkovi před termínem</div></div>
            <label style="position:relative;display:inline-block;width:46px;height:26px;flex-shrink:0">
              <input type="checkbox" id="set-pripominka_zapnuta" style="opacity:0;width:0;height:0" onchange="togglePripominka(this)">
              <span id="pripominka-toggle" style="position:absolute;cursor:pointer;inset:0;background:#e5e7eb;border-radius:999px;transition:.2s"></span>
              <span id="pripominka-knob" style="position:absolute;height:20px;width:20px;left:3px;bottom:3px;background:#fff;border-radius:50%;transition:.2s;box-shadow:0 1px 3px rgba(0,0,0,.2)"></span>
            </label>
          </div>
          <div class="set-row" id="pripominka-hod-row" style="display:none">
            <div><div class="set-label">Kolik hodin předem</div><div class="set-sub">Např. 24 = den předem</div></div>
            <input class="set-input" type="number" id="set-pripominka_hodin" style="width:90px" min="1" max="168">
          </div>
        </div>
        <div class="card">
          <div class="card-title"><span>⭐</span> Hodnocení rezervací</div>
          <div class="set-row">
            <div><div class="set-label">Žádost o hodnocení</div><div class="set-sub">E-mail po termínu s odkazem na hvězdičky</div></div>
            <label style="position:relative;display:inline-block;width:46px;height:26px;flex-shrink:0">
              <input type="checkbox" id="set-hodnoceni_zadost_zapnuta" style="opacity:0;width:0;height:0" onchange="toggleSwitch(this,'hodnoceni-hod-row','hodnoceni-zadost-toggle','hodnoceni-zadost-knob')">
              <span id="hodnoceni-zadost-toggle" style="position:absolute;cursor:pointer;inset:0;background:#e5e7eb;border-radius:999px;transition:.2s"></span>
              <span id="hodnoceni-zadost-knob" style="position:absolute;height:20px;width:20px;left:3px;bottom:3px;background:#fff;border-radius:50%;transition:.2s;box-shadow:0 1px 3px rgba(0,0,0,.2)"></span>
            </label>
          </div>
          <div class="set-row" id="hodnoceni-hod-row" style="display:none">
            <div><div class="set-label">Kolik hodin po termínu</div><div class="set-sub">Např. 2 = dvě hodiny po skončení</div></div>
            <input class="set-input" type="number" id="set-hodnoceni_hodin_po" style="width:90px" min="1" max="168">
          </div>
          <div class="set-row">
            <div><div class="set-label">Zobrazit hodnocení na webu</div><div class="set-sub">Průměr a počet v rezervačním formuláři</div></div>
            <label style="position:relative;display:inline-block;width:46px;height:26px;flex-shrink:0">
              <input type="checkbox" id="set-hodnoceni_verejne_zapnuta" style="opacity:0;width:0;height:0" onchange="toggleSwitchSimple(this,'hodnoceni-verejne-toggle','hodnoceni-verejne-knob')">
              <span id="hodnoceni-verejne-toggle" style="position:absolute;cursor:pointer;inset:0;background:#e5e7eb;border-radius:999px;transition:.2s"></span>
              <span id="hodnoceni-verejne-knob" style="position:absolute;height:20px;width:20px;left:3px;bottom:3px;background:#fff;border-radius:50%;transition:.2s;box-shadow:0 1px 3px rgba(0,0,0,.2)"></span>
            </label>
          </div>
        </div>
        <div id="set-alert" class="alert" style="display:none"></div>
        <button class="btn-save" onclick="saveSettings()">Uložit nastavení</button>

        <!-- Správa uživatelů - viditelná jen pro admin -->
        <div class="card" id="card-uzivatele" style="display:none;margin-top:14px">
          <div class="card-title"><span>👤</span> Správa uživatelů</div>
          <div id="uzivatele-list"><div class="loading">Načítám…</div></div>
        </div>
      </div>

    </div>
  </div>

  <div class="bottomnav">
    <button class="nav-item active" id="nav-dnes" onclick="switchTab('dnes')"><span class="nav-icon">🏠</span>Dnes</button>
    <button class="nav-item" id="nav-kalendar" onclick="switchTab('kalendar')"><span class="nav-icon">📅</span>Kalendář</button>
    <button class="nav-item" id="nav-qr" onclick="switchTab('qr')"><span class="nav-icon">💳</span>QR platba</button>
    <button class="nav-item" id="nav-kartoteka" onclick="switchTab('kartoteka')"><span class="nav-icon">👥</span>Kartotéka</button>
    <button class="nav-item" id="nav-sluzby" onclick="switchTab('sluzby')"><span class="nav-icon">✂️</span>Služby</button>
    <button class="nav-item" id="nav-nastaveni" onclick="switchTab('nastaveni')"><span class="nav-icon">⚙️</span>Nastavení</button>
  </div>
</div>

<!-- MODAL: Rezervace detail -->
<div class="modal-overlay" id="modal-rez">
  <div class="modal-sheet">
    <div class="modal-handle"></div>
    <div class="modal-title">Detail rezervace</div>
    <div id="modal-rez-content"></div>
    <div class="btn-row" id="modal-rez-btns"></div>
  </div>
</div>

<!-- MODAL: Služba -->
<div class="modal-overlay" id="modal-svc">
  <div class="modal-sheet">
    <div class="modal-handle"></div>
    <div class="modal-title" id="modal-svc-title">Nová služba</div>
    <input type="hidden" id="svc-id">
    <label class="modal-label">Název</label>
    <input class="modal-input" id="svc-nazev" placeholder="Střih & styling">
    <label class="modal-label">Trvání (minuty)</label>
    <input class="modal-input" type="number" id="svc-trvani" placeholder="60">
    <label class="modal-label">Cena (Kč)</label>
    <input class="modal-input" type="text" inputmode="numeric" id="svc-cena" placeholder="Volitelné">
    <div class="btn-row">
      <button class="btn-modal-discard" onclick="closeModal('modal-svc')">Zrušit</button>
      <button class="btn-modal-save" onclick="saveSvc()">Uložit</button>
    </div>
  </div>
</div>

<!-- MODAL: Blokace -->
<div class="modal-overlay" id="modal-blok">
  <div class="modal-sheet">
    <div class="modal-handle"></div>
    <div class="modal-title">Blokovat termín</div>
    <label class="modal-label">Od</label>
    <input class="modal-input" type="date" id="blok-od">
    <label class="modal-label">Do (stejný den = jen tento den)</label>
    <input class="modal-input" type="date" id="blok-do">
    <label class="modal-label">Důvod</label>
    <input class="modal-input" id="blok-duvod" placeholder="Dovolená, školení…">
    <div class="btn-row">
      <button class="btn-modal-discard" onclick="closeModal('modal-blok')">Zrušit</button>
      <button class="btn-modal-save" onclick="saveBlok()">Uložit</button>
    </div>
  </div>
</div>

<script>
var API = '/api';

// Načti název salónu pro přihlašovací obrazovku
document.addEventListener('DOMContentLoaded', function() {
  var el = document.getElementById('login-salon-nazev');
  if (!el) return;
  fetch('/api/nastaveni/public')
    .then(function(r){ return r.json(); })
    .then(function(d){
      el.textContent = (d.ok && d.data && d.data.salon_nazev) ? d.data.salon_nazev : 'Rezervační systém';
      document.title = 'Admin – ' + el.textContent;
    })
    .catch(function(){
      el.textContent = 'Rezervační systém';
    });
});

// Úložiště tokenu — sessionStorage nebo localStorage podle "zapamatovat mě"
var _store = {
  getItem: function(k) {
    try { return localStorage.getItem(k) || sessionStorage.getItem(k); } catch(e) { return null; }
  },
  setItem: function(k, v, persistent) {
    try {
      // Zjisti zda je token persistentní (uložen v localStorage)
      var isPersistent = persistent !== undefined ? persistent : !!localStorage.getItem('admin_remember');
      if (isPersistent) { localStorage.setItem(k, v); sessionStorage.removeItem(k); }
      else { sessionStorage.setItem(k, v); localStorage.removeItem(k); }
    } catch(e) {}
  },
  removeItem: function(k) {
    try { localStorage.removeItem(k); sessionStorage.removeItem(k); } catch(e) {}
  }
};
var token = _store.getItem('admin_token') || '';
var MESICE = ['led','úno','bře','dub','kvě','čvn','čvc','srp','zář','říj','lis','pro'];
var DNY_SHORT = ['Ne','Po','Út','St','Čt','Pá','So'];
var activeDays = [1,2,3,4,5,6];

function authHeaders() {
  return { 'Content-Type':'application/json', 'Authorization':'Bearer ' + token };
}

async function doLogin() {
  var user = document.getElementById('login-user').value.trim();
  var pass = document.getElementById('login-pass').value;
  var remember = document.getElementById('login-remember').checked;
  var alertEl = document.getElementById('login-alert');
  alertEl.className = 'alert';
  if (!user || !pass) { alertEl.className='alert error'; alertEl.textContent='Vyplňte přihlašovací údaje.'; return; }
  try {
    var r = await fetch(API + '/auth/login', { method:'POST', headers:{'Content-Type':'application/json'}, body: JSON.stringify({uzivatelske_jmeno:user, heslo:pass, remember_me: remember}) });
    var d = await r.json();
    if (d.ok) {
      token = d.token;
      _store.setItem('admin_token', token, remember);
      _store.setItem('admin_uzivatel', d.uzivatel || '', remember);
      if (remember) localStorage.setItem('admin_remember', '1');
      else localStorage.removeItem('admin_remember');
      showMain();
    } else {
      alertEl.className='alert error'; alertEl.textContent = d.error || 'Nesprávné přihlašovací údaje.';
    }
  } catch(e) {
    alertEl.className='alert error'; alertEl.textContent='Chyba připojení.';
  }
}

function doLogout() {
  fetch(API + '/auth/logout', { method:'POST', headers: authHeaders() });
  _store.removeItem('admin_token');
  _store.removeItem('admin_uzivatel');
  localStorage.removeItem('admin_remember');
  // Úklid starých WebAuthn dat
  Object.keys(localStorage).forEach(function(k) {
    if (k.indexOf('webauthn_') === 0) localStorage.removeItem(k);
  });
  token = '';
  document.getElementById('mainView').style.display = 'none';
  document.getElementById('loginView').style.display = 'flex';
}

function showMain() {
  document.getElementById('loginView').style.display = 'none';
  document.getElementById('mainView').style.display = 'block';
  var now = new Date();
  var uzivatel = _store.getItem('admin_uzivatel') || '';
  document.getElementById('topbar-sub').textContent = now.toLocaleDateString('cs-CZ', {weekday:'long', day:'numeric', month:'long'})
    + (uzivatel ? '  ·  ' + uzivatel : '');
  loadDnes();
  buildCalStrip();
  loadSluzby();
  loadSluzbySel();
  loadKartoteka();
  loadBlokace();
  loadSettings();
  setTimeout(zpracujHash, 300);
}

// Při načtení zkus token z localStorage
if (token) showMain();

// Zpracuj hash po přihlášení nebo při načtení
function zpracujHash() {
  var hash = window.location.hash; // např. #kalendar/2026-06-24
  if (!hash) return;
  var parts = hash.replace('#', '').split('/');
  var tab   = parts[0];
  var datum = parts[1];
  if (tab === 'kalendar') {
    switchTab('kalendar');
    if (datum && datum.match(/^\d{4}-\d{2}-\d{2}$/)) {
      // Nastavit měsíc podle data a vybrat den
      var d = new Date(datum + 'T12:00:00');
      mesicDate = new Date(d.getFullYear(), d.getMonth(), 1);
      selectedMesicDay = datum;
      loadMesicData().then(function() {
        var rezy = allRezervace[datum] || [];
        showDenDetail(datum, rezy);
      });
    }
  }
  // Vymaž hash z URL bez reload
  history.replaceState(null, '', window.location.pathname);
}

function switchTab(tab) {
  ['dnes','kalendar','sluzby','kartoteka','qr','nastaveni'].forEach(function(t) {
    document.getElementById('tab-'+t).classList.toggle('active', t===tab);
    document.getElementById('nav-'+t).classList.toggle('active', t===tab);
  });
  var titles = {dnes:'Dnešní přehled', kalendar:'Kalendář', sluzby:'Služby & ceny', kartoteka:'Kartotéka', qr:'QR platba', nastaveni:'Nastavení'};
  document.getElementById('topbar-title').textContent = titles[tab];
  if (tab === 'nastaveni') loadUzivatele();
}

async function loadDnes() {
  var dnes = formatDate(new Date());
  try {
    var r = await fetch(API + '/rezervace?datum_od=' + dnes + '&datum_do=' + dnes, { headers: authHeaders() });
    var d = await r.json();
    if (!d.ok) { if(d.error && d.error.includes('Přístup')) { doLogout(); return; } }
    var list = d.data || [];
    var sg = document.getElementById('stats-dnes');
    var trzby = list.filter(function(r){ return r.stav !== 'zrusena'; }).reduce(function(s,r){
      if (r.cena_upravena !== null && r.cena_upravena !== undefined && r.cena_upravena !== '') {
        return s + (parseFloat(r.cena_upravena) || 0);
      }
      var zakladni = parseFloat(r.cena) || 0;
      var extra = (r.doplnky || []).reduce(function(ss,d){ return ss + parseFloat(d.cena||0); }, 0);
      return s + zakladni + extra;
    }, 0);
    sg.innerHTML = '<div class="stat-card"><div class="stat-val">' + list.filter(function(r){ return r.stav!=='zrusena'; }).length + '</div><div class="stat-label">rezervací dnes</div></div>'
      + '<div class="stat-card"><div class="stat-val">' + Math.round(trzby).toLocaleString('cs-CZ') + ' Kč</div><div class="stat-label">tržby dnes</div></div>';
    renderRezList('dnes-list', list);
  } catch(e) {}
}

var DNY_SEZNAM = ['Ne','Po','Út','St','Čt','Pá','So'];
var MESICE_SEZNAM = ['led','úno','bře','dub','kvě','čvn','čvc','srp','zář','říj','lis','pro'];

function formatDatumCZ(datum) {
  var d = new Date(datum + 'T12:00:00');
  return DNY_SEZNAM[d.getDay()] + ' ' + d.getDate() + '. ' + MESICE_SEZNAM[d.getMonth()] + '.';
}

function renderRezList(containerId, list) {
  var el = document.getElementById(containerId);
  if (!list.length) { el.innerHTML = '<div class="empty">Žádné rezervace</div>'; return; }
  var showDate = containerId === 'kal-list' && kalView === 'seznam';
  el.innerHTML = list.map(function(r) {
    var badgeCls = r.stav==='potvrzena'?'badge-green':r.stav==='zrusena'?'badge-red':'badge-amber';
    var badgeTxt = r.stav==='potvrzena'?'Potvrzeno':r.stav==='zrusena'?'Zrušeno':'Čeká';
    var btns = r.stav !== 'zrusena' ? '<button class="btn-sm btn-detail" onclick=\'openRezDetail(' + JSON.stringify(r).replace(/'/g,"&#39;") + ')\'>Detail</button>'
      + (r.stav==='ceka' ? '<button class="btn-sm btn-confirm" onclick="confirmRez(' + r.id + ',this)">Potvrdit</button>' : '')
      + '<button class="btn-sm btn-cancel-sm" onclick="cancelRez(' + r.id + ',this)">Zrušit</button>' : '';
    var datumBadge = showDate
      ? '<div style="font-size:11px;font-weight:600;color:#7c3aed;background:#f3e8ff;border-radius:6px;padding:2px 7px;display:inline-block;margin-bottom:4px">' + formatDatumCZ(r.datum) + ' · ' + r.cas_od + '</div><br>'
      : '';
    var checkbox = r.stav === 'ceka'
      ? '<input type="checkbox" class="rez-checkbox" id="chk-' + r.id + '" onchange="onCheckChange(' + r.id + ',this)">'
      : '<div style="width:16px;flex-shrink:0"></div>';
    return '<div class="rez-item" id="rez-' + r.id + '" style="align-items:flex-start">'
      + checkbox
      + (showDate ? '' : '<div class="rez-time"><div class="rez-time-h">' + r.cas_od + '</div><div class="rez-time-d">' + r.cas_do + '</div></div>')
      + '<div class="rez-info" style="flex:1">'
      + datumBadge
      + '<div style="display:flex;align-items:center;justify-content:space-between"><div class="rez-name">' + esc(r.jmeno) + ' ' + esc(r.prijmeni) + '</div><span class="badge ' + badgeCls + '">' + badgeTxt + '</span></div>'
      + '<div class="rez-service">' + esc(r.sluzba)
      + (function() {
          var doplnky = r.doplnky || [];
          var celkem;
          if (r.cena_upravena !== null && r.cena_upravena !== undefined && r.cena_upravena !== '') {
            celkem = parseFloat(r.cena_upravena) || 0;
          } else {
            var zakladni = r.cena && parseFloat(r.cena) > 0 ? parseFloat(r.cena) : 0;
            var extraCena = doplnky.reduce(function(s,d){ return s + parseFloat(d.cena||0); }, 0);
            celkem = zakladni + extraCena;
          }
          var cenaStr = celkem > 0 ? ' · ' + Math.round(celkem).toLocaleString('cs-CZ') + ' Kč' : ' · Individuální';
          var doplnkyStr = doplnky.length > 0 ? '<span style="color:#9333ea;font-size:11px"> + ' + doplnky.map(function(d){ return d.nazev; }).join(', ') + '</span>' : '';
          return cenaStr + doplnkyStr;
        })()
      + '</div>'
      + (r.hodnoceni ? '<div style="margin-top:2px">' + renderStars(r.hodnoceni, 12) + '</div>' : '')
      + (r.telefon ? '<div style="font-size:11px;color:#9ca3af;margin-top:2px">📞 ' + esc(r.telefon) + '</div>' : '')
      + '<div class="rez-actions">' + btns + '</div></div></div>';
  }).join('');
}
var vybrane = new Set();

function onCheckChange(id, el) {
  if (el.checked) {
    vybrane.add(id);
    document.getElementById('rez-' + id).classList.add('checked');
  } else {
    vybrane.delete(id);
    document.getElementById('rez-' + id).classList.remove('checked');
  }
  updateHromadneBar();
}

function updateHromadneBar() {
  var bar = document.getElementById('hromadne-bar');
  var info = document.getElementById('hromadne-info');
  if (vybrane.size > 0) {
    bar.classList.add('show');
    info.textContent = vybrane.size + ' ' + (vybrane.size === 1 ? 'vybraná rezervace' : vybrane.size < 5 ? 'vybrané rezervace' : 'vybraných rezervací');
  } else {
    bar.classList.remove('show');
  }
}

function zrusitVyber() {
  vybrane.forEach(function(id) {
    var chk = document.getElementById('chk-' + id);
    if (chk) chk.checked = false;
    var item = document.getElementById('rez-' + id);
    if (item) item.classList.remove('checked');
  });
  vybrane.clear();
  updateHromadneBar();
}

async function potvrditJednu(id) {
  var r = await fetch(API + '/rezervace/' + id, {
    method: 'PUT',
    headers: authHeaders(),
    body: JSON.stringify({stav: 'potvrzena'})
  });
  // HTTP 200/201 = úspěch, nehledě na tělo odpovědi
  return r.status >= 200 && r.status < 300;
}

async function hromadnePotvrzeni() {
  if (vybrane.size === 0) return;
  var btn = document.querySelector('.btn-hromadne');
  btn.disabled = true;
  var ids = Array.from(vybrane).map(Number);
  var celkem = ids.length;
  var uspesne = 0;

  for (var i = 0; i < ids.length; i++) {
    var id = ids[i];
    btn.textContent = 'Potvrzuji ' + (i+1) + ' / ' + celkem + '…';
    try {
      var ok = await potvrditJednu(id);
      if (ok) {
        uspesne++;
        var item = document.getElementById('rez-' + id);
        if (item) {
          var badge = item.querySelector('.badge');
          if (badge) { badge.className = 'badge badge-green'; badge.textContent = 'Potvrzeno'; }
          var chk = document.getElementById('chk-' + id);
          if (chk && chk.parentNode) chk.parentNode.removeChild(chk);
          var actions = item.querySelector('.rez-actions');
          if (actions) actions.innerHTML = '';
          item.classList.remove('checked');
        }
      }
    } catch(e) {
      console.error('Potvrzení selhalo pro id=' + id, e);
    }
    if (i < ids.length - 1) await new Promise(function(res){ setTimeout(res, 200); });
  }

  vybrane.clear();
  updateHromadneBar();
  btn.disabled = false;
  btn.textContent = '✅ Potvrdit vybrané';
  showToast(uspesne === celkem
    ? '✅ Potvrzeno všech ' + celkem + ' rezervací.'
    : '✅ Potvrzeno ' + uspesne + ' z ' + celkem + ' rezervací.');
  refreshKalendar();
}

async function confirmRez(id, btn) {
  btn.disabled = true;
  btn.textContent = '…';
  var item = document.getElementById('rez-' + id);
  if (item) {
    var badge = item.querySelector('.badge');
    if (badge) { badge.className = 'badge badge-green'; badge.textContent = 'Potvrzuji…'; }
  }

  var controller = new AbortController();
  var timeout = setTimeout(function() { controller.abort(); }, 10000);

  try {
    var r = await fetch(API + '/rezervace/' + id, {
      method: 'PUT', headers: authHeaders(),
      body: JSON.stringify({stav:'potvrzena'}),
      signal: controller.signal
    });
    clearTimeout(timeout);
    // Úspěch nebo timeout — v obou případech DB je aktualizovaná
    if (item) {
      var badge2 = item.querySelector('.badge');
      if (badge2) { badge2.className = 'badge badge-green'; badge2.textContent = 'Potvrzeno'; }
      var actions = item.querySelector('.rez-actions');
      if (actions) actions.innerHTML = '';
      var chk = document.getElementById('chk-' + id);
      if (chk && chk.parentNode) chk.parentNode.removeChild(chk);
    }
    showToast('✅ Rezervace potvrzena a zákazník byl informován e-mailem.');
    refreshKalendar();
  } catch(e) {
    clearTimeout(timeout);
    if (e.name === 'AbortError') {
      // Timeout — DB aktualizovaná, email se odesílá
      if (item) {
        var badge3 = item.querySelector('.badge');
        if (badge3) { badge3.className = 'badge badge-green'; badge3.textContent = 'Potvrzeno'; }
        var actions2 = item.querySelector('.rez-actions');
        if (actions2) actions2.innerHTML = '';
      }
      showToast('✅ Rezervace potvrzena. Email se odesílá na pozadí.');
      refreshKalendar();
    } else {
      if (item) {
        var badge4 = item.querySelector('.badge');
        if (badge4) { badge4.className = 'badge badge-amber'; badge4.textContent = 'Čeká'; }
      }
      btn.disabled = false;
      btn.textContent = 'Potvrdit';
      showToast('❌ Chyba připojení.', true);
    }
  }
}

function showToast(msg, isError) {
  var t = document.getElementById('toast-notif');
  if (!t) {
    t = document.createElement('div');
    t.id = 'toast-notif';
    t.style.cssText = 'position:fixed;bottom:90px;left:50%;transform:translateX(-50%);background:#166534;color:#fff;padding:11px 20px;border-radius:12px;font-size:14px;font-weight:500;z-index:999;max-width:320px;text-align:center;box-shadow:0 4px 12px rgba(0,0,0,.15);transition:opacity .3s';
    document.body.appendChild(t);
  }
  t.style.background = isError ? '#991b1b' : '#166534';
  t.textContent = msg;
  t.style.opacity = '1';
  clearTimeout(t._timer);
  t._timer = setTimeout(function(){ t.style.opacity = '0'; }, 3000);
}

function cancelRez(id, btn) {
  // Otevři modal pro zadání důvodu
  document.getElementById('zruseni-rez-id').value = id;
  document.getElementById('zruseni-duvod').value = '';
  document.getElementById('zruseni-alert').style.display = 'none';
  // Ulož referenci na tlačítko pro pozdější update
  window._cancelBtn = btn;
  closeModal('modal-rez');
  openModal('modal-zruseni');
}

async function provestZruseni() {
  var id = document.getElementById('zruseni-rez-id').value;
  var duvod = document.getElementById('zruseni-duvod').value.trim();
  var saveBtn = document.getElementById('zruseni-save-btn');
  saveBtn.disabled = true;
  saveBtn.textContent = 'Ruším…';

  var controller = new AbortController();
  // Po 10s vzdej čekání na odpověď — server stejně dokončí práci
  var timeout = setTimeout(function() { controller.abort(); }, 10000);

  try {
    var r = await fetch(API + '/rezervace/' + id, {
      method: 'PUT',
      headers: authHeaders(),
      body: JSON.stringify({stav: 'zrusena', duvod_zruseni: duvod}),
      signal: controller.signal
    });
    clearTimeout(timeout);
    // Jakýkoliv HTTP status = server přijal požadavek
    closeModal('modal-zruseni');
    var item = document.getElementById('rez-' + id);
    if (item) {
      item.style.opacity = '.4';
      item.querySelector('.badge').className = 'badge badge-red';
      item.querySelector('.badge').textContent = 'Zrušeno';
      item.querySelector('.rez-actions').innerHTML = '';
    }
    showToast('Rezervace byla zrušena a zákazník byl informován.');
    refreshKalendar();
  } catch(e) {
    clearTimeout(timeout);
    if (e.name === 'AbortError') {
      // Timeout — server stále pracuje (odesílá emaily), ale DB je již aktualizovaná
      closeModal('modal-zruseni');
      var item2 = document.getElementById('rez-' + id);
      if (item2) {
        item2.style.opacity = '.4';
        item2.querySelector('.badge').className = 'badge badge-red';
        item2.querySelector('.badge').textContent = 'Zrušeno';
        item2.querySelector('.rez-actions').innerHTML = '';
      }
      showToast('Rezervace zrušena. Email se odesílá na pozadí.');
      refreshKalendar();
    } else {
      var alertEl = document.getElementById('zruseni-alert');
      alertEl.textContent = 'Chyba: ' + e.message;
      alertEl.style.display = 'block';
      saveBtn.disabled = false;
      saveBtn.textContent = 'Zrušit rezervaci';
    }
  }
}

function openRezDetail(r) {
  var zakladniCena = r.sluzba_cena && parseFloat(r.sluzba_cena) > 0 ? parseFloat(r.sluzba_cena) : 0;
  var doplnkyCena  = (r.doplnky||[]).reduce(function(s,d){ return s + parseFloat(d.cena||0); }, 0);
  // Pokud existuje ručně upravená cena (cena_upravena), použij ji — jinak součet základní + doplňky
  var celkemCena = (r.cena_upravena !== null && r.cena_upravena !== undefined && r.cena_upravena !== '')
    ? parseFloat(r.cena_upravena)
    : (zakladniCena + doplnkyCena);

  var doplnkyRowsHtml = (r.doplnky||[]).map(function(d) {
    return '<div style="display:flex;justify-content:space-between;padding:7px 0;border-bottom:1px solid #f3e8ff;font-size:13px">'
      + '<span style="color:#6b7280">+ ' + d.nazev + '</span>'
      + '<span style="font-weight:600;color:#7c3aed">+ ' + Math.round(parseFloat(d.cena)).toLocaleString('cs-CZ') + ' Kč</span>'
      + '</div>';
  }).join('');

  document.getElementById('modal-rez-content').innerHTML =
    '<div style="display:flex;flex-direction:column;gap:0">'
    + detailRow('Jméno', r.jmeno + ' ' + r.prijmeni)
    + detailRow('E-mail', r.email)
    + (r.telefon ? detailRowHtml('Telefon', '<a href="tel:' + r.telefon.replace(/\s/g,'') + '" style="color:#7c3aed;text-decoration:none">' + esc(r.telefon) + '</a>') : '')
    + detailRow('Služba', r.sluzba + (zakladniCena > 0 ? ' (' + Math.round(zakladniCena).toLocaleString('cs-CZ') + ' Kč)' : ''))
    + detailRow('Datum', r.datum)
    + detailRow('Čas', r.cas_od + ' – ' + r.cas_do)
    + doplnkyRowsHtml
    + (r.hodnoceni ? detailRowHtml('Hodnocení', renderStars(r.hodnoceni, 16)) : '')
    + (r.poznamka ? detailRow('Poznámka', r.poznamka) : '')
    + '<div style="display:flex;justify-content:space-between;padding:10px 0;border-bottom:1px solid #f3e8ff;font-size:13px;align-items:center">'
    + '<span style="color:#6b7280;font-weight:600">Celkem</span>'
    + '<div style="display:flex;align-items:center;gap:8px">'
    + '<input type="number" id="rez-cena-input" value="' + Math.round(celkemCena) + '" min="0" style="width:90px;border:2px solid #e9d5ff;border-radius:8px;padding:4px 8px;font-size:13px;text-align:right;outline:none;font-weight:600">'
    + '<span style="font-size:13px;color:#6b7280">Kč</span>'
    + '</div></div>'
    + '</div>';

  document.getElementById('_rez_detail_data') && document.getElementById('_rez_detail_data').remove();
  var dataEl = document.createElement('input');
  dataEl.type = 'hidden'; dataEl.id = '_rez_detail_data';
  dataEl.value = JSON.stringify(r);
  document.getElementById('modal-rez-content').appendChild(dataEl);

  document.getElementById('modal-rez-btns').innerHTML =
    '<button class="btn-modal-discard" onclick="closeModal(\'modal-rez\')">Zavřít</button>'
    + (r.stav!=='zrusena' ? '<button class="btn-modal-discard" style="background:#f3e8ff;color:#6b21a8" onclick="openQrZRezervace()">💳 QR</button>' : '')
    + (r.stav!=='zrusena' ? '<button class="btn-modal-discard" style="background:#f3e8ff;color:#6b21a8" onclick="openUpravTermin(' + r.id + ');closeModal(\'modal-rez\')">✏️ Termín</button>' : '')
    + (r.stav!=='zrusena' ? '<button class="btn-modal-save" style="background:#166534;font-size:12px" onclick="ulozitCenuRezervace(' + r.id + ')">💾 Cenu</button>' : '')
    + (r.stav!=='zrusena' ? '<button class="btn-modal-save" style="background:#991b1b;font-size:12px" onclick="cancelRez('+r.id+',this);closeModal(\'modal-rez\')">Zrušit</button>' : '');
  openModal('modal-rez');
}

async function ulozitCenuRezervace(id) {
  var novaCena = parseFloat(document.getElementById('rez-cena-input').value) || 0;
  try {
    var r = await fetch(API + '/rezervace/' + id + '/cena', {
      method: 'PUT',
      headers: authHeaders(),
      body: JSON.stringify({ cena: novaCena })
    });
    if (r.status >= 200 && r.status < 300) {
      closeModal('modal-rez');
      showToast('✅ Cena uložena a zákazník byl informován.');
      refreshKalendar();
      loadDnes();
    } else {
      var d = await r.json().catch(function(){ return {}; });
      showToast('Chyba: ' + (d.error || 'Nepodařilo se uložit.'), true);
    }
  } catch(e) {
    showToast('Chyba připojení.', true);
  }
}

async function openQrZRezervace() {
  // Přečti hodnoty PŘED zavřením modalu
  var dataEl = document.getElementById('_rez_detail_data');
  var cenaEl = document.getElementById('rez-cena-input');
  if (!dataEl || !cenaEl) return;
  var r = JSON.parse(dataEl.value);
  var novaCena = parseFloat(cenaEl.value) || 0;
  var jmeno = r.jmeno + ' ' + r.prijmeni;
  closeModal('modal-rez');
  switchTab('qr');
  // Zajisti že cislo_uctu je načteno
  var ucetEl = document.getElementById('set-cislo_uctu');
  if (!ucetEl || !ucetEl.value) {
    try {
      var resp = await fetch(API + '/nastaveni', { headers: authHeaders() });
      var data = await resp.json();
      if (data.ok && data.data && data.data.cislo_uctu) {
        ucetEl.value = data.data.cislo_uctu.hodnota || '';
      }
    } catch(e) {}
  }
  // Nastav částku a poznámku a generuj QR přímo
  var castkaEl  = document.getElementById('qr-castka');
  var poznamkaEl = document.getElementById('qr-poznamka');
  castkaEl.value  = Math.round(novaCena);
  poznamkaEl.value = jmeno;
  generateQR();
}

// ---- Úprava termínu rezervace ----
var _upravRez = null;

async function openUpravTermin(id) {
  // Načti detail rezervace z API
  try {
    var resp = await fetch(API + '/rezervace/' + id, { headers: authHeaders() });
    var data = await resp.json();
    if (!data.ok) { showToast('Chyba načítání rezervace.', true); return; }
    var r = data.data;
    _upravRez = r;
    document.getElementById('ut-rez-id').value = r.id;
    document.getElementById('ut-sluzba-nazev').textContent = r.sluzba || r.sluzba_nazev || '';
    document.getElementById('ut-datum').value = r.datum;
    document.getElementById('ut-cas-manual').value = r.cas_od;
    document.getElementById('ut-times-wrap').style.display = 'none';
    document.getElementById('ut-times-grid').innerHTML = '';
    document.getElementById('ut-alert').style.display = 'none';
    utNactiCasy(r.datum, r.sluzba_id || '');
    openModal('modal-uprav-termin');
  } catch(e) {
    showToast('Chyba připojení.', true);
  }
}

function utDatumChange() {
  var datum = document.getElementById('ut-datum').value;
  document.getElementById('ut-cas-manual').value = '';
  if (datum) utNactiCasy(datum, _upravRez ? (_upravRez.sluzba_id || '') : '');
}

async function utNactiCasy(datum, sluzbaId) {
  var wrap = document.getElementById('ut-times-wrap');
  wrap.style.display = 'block';
  document.getElementById('ut-times-loading').style.display = 'block';
  document.getElementById('ut-times-grid').innerHTML = '';
  if (!sluzbaId) {
    document.getElementById('ut-times-loading').style.display = 'none';
    document.getElementById('ut-times-grid').innerHTML = '<p style="font-size:12px;color:#9ca3af;grid-column:1/-1">Zadejte čas ručně níže.</p>';
    return;
  }
  try {
    var r = await fetch(API + '/dostupnost?sluzba_id=' + sluzbaId + '&datum=' + datum, { headers: authHeaders() });
    var d = await r.json();
    document.getElementById('ut-times-loading').style.display = 'none';
    var tg = document.getElementById('ut-times-grid');
    if (d.blokovano) {
      tg.innerHTML = '<p style="font-size:12px;color:#f59e0b;grid-column:1/-1">⚠️ Den je blokován — přesto můžete zadat čas ručně.</p>';
    } else if (!d.volne_casy || !d.volne_casy.length) {
      tg.innerHTML = '<p style="font-size:12px;color:#9ca3af;grid-column:1/-1">Žádné volné časy — zadejte čas ručně níže.</p>';
    } else {
      d.volne_casy.forEach(function(t) {
        var el = document.createElement('div');
        el.style.cssText = 'border:1.5px solid #e9d5ff;border-radius:8px;padding:7px 4px;text-align:center;font-size:12px;cursor:pointer;transition:all .15s';
        el.textContent = t;
        el.onclick = function() {
          document.querySelectorAll('#ut-times-grid div').forEach(function(s){ s.style.background=''; s.style.color=''; s.style.borderColor='#e9d5ff'; });
          el.style.background = '#9333ea'; el.style.color = '#fff'; el.style.borderColor = '#9333ea';
          document.getElementById('ut-cas-manual').value = t;
        };
        tg.appendChild(el);
      });
    }
  } catch(e) {
    document.getElementById('ut-times-loading').style.display = 'none';
  }
}

async function ulozitUpravTermin() {
  var id    = document.getElementById('ut-rez-id').value;
  var datum = document.getElementById('ut-datum').value;
  var cas   = document.getElementById('ut-cas-manual').value;
  var alertEl = document.getElementById('ut-alert');
  alertEl.style.display = 'none';

  if (!datum || !cas) {
    alertEl.className = 'alert error'; alertEl.textContent = 'Vyplňte datum a čas.'; alertEl.style.display = 'block'; return;
  }

  var btn = document.getElementById('ut-btn-ulozit');
  btn.disabled = true; btn.textContent = 'Ukládám…';

  var controller = new AbortController();
  var timeout = setTimeout(function() { controller.abort(); }, 10000);

  try {
    var r = await fetch(API + '/rezervace/' + id + '/termin', {
      method: 'PUT',
      headers: authHeaders(),
      body: JSON.stringify({ datum: datum, cas: cas }),
      signal: controller.signal
    });
    clearTimeout(timeout);
    if (r.status >= 200 && r.status < 300) {
      closeModal('modal-uprav-termin');
      showToast('✅ Termín byl změněn a zákazník byl informován.');
      refreshKalendar();
      loadDnes();
    } else {
      var d = await r.json().catch(function(){ return {}; });
      alertEl.className = 'alert error'; alertEl.textContent = d.error || 'Chyba při ukládání.'; alertEl.style.display = 'block';
    }
  } catch(e) {
    clearTimeout(timeout);
    if (e.name === 'AbortError') {
      closeModal('modal-uprav-termin');
      showToast('✅ Termín byl změněn. Email se odesílá na pozadí.');
      refreshKalendar();
      loadDnes();
    } else {
      alertEl.className = 'alert error'; alertEl.textContent = 'Chyba připojení.'; alertEl.style.display = 'block';
    }
  }
  btn.disabled = false; btn.textContent = 'Uložit termín';
}

function detailRow(label, val) {
  return '<div style="display:flex;justify-content:space-between;padding:7px 0;border-bottom:1px solid #f3e8ff;font-size:13px">'
    + '<span style="color:#6b7280">' + label + '</span><span style="font-weight:600">' + esc(String(val)) + '</span></div>';
}

function detailRowHtml(label, html) {
  return '<div style="display:flex;justify-content:space-between;padding:7px 0;border-bottom:1px solid #f3e8ff;font-size:13px">'
    + '<span style="color:#6b7280">' + label + '</span><span style="font-weight:600">' + html + '</span></div>';
}

var kalView = 'mesic';
var mesicDate = new Date();
var seznamDate = new Date();
var allRezervace = {};
var kalFiltr = '';
var selectedMesicDay = null;

function setView(v) {
  kalView = v;
  document.getElementById('view-mesic').style.display = v === 'mesic' ? 'block' : 'none';
  document.getElementById('view-seznam').style.display = v === 'seznam' ? 'block' : 'none';
  document.getElementById('vbtn-mesic').classList.toggle('active', v === 'mesic');
  document.getElementById('vbtn-seznam').classList.toggle('active', v === 'seznam');
  if (v === 'mesic') renderMesic();
  else renderSeznam();
}

function applyFilter() {
  kalFiltr = document.getElementById('kal-filtr').value;
  if (kalView === 'mesic') renderMesic();
  else renderSeznam();
}

// ---- MĚSÍČNÍ POHLED ----
var MESICE_LONG = ['Leden','Únor','Březen','Duben','Květen','Červen','Červenec','Srpen','Září','Říjen','Listopad','Prosinec'];

async function loadMesicData() {
  var y = mesicDate.getFullYear(), m = mesicDate.getMonth();
  var od = y + '-' + String(m+1).padStart(2,'0') + '-01';
  var do_ = y + '-' + String(m+1).padStart(2,'0') + '-' + String(new Date(y,m+1,0).getDate()).padStart(2,'0');
  try {
    var r = await fetch(API + '/rezervace?datum_od=' + od + '&datum_do=' + do_, { headers: authHeaders() });
    var d = await r.json();
    allRezervace = {};
    (d.data || []).forEach(function(rez) {
      if (!allRezervace[rez.datum]) allRezervace[rez.datum] = [];
      allRezervace[rez.datum].push(rez);
    });
    renderMesic();
  } catch(e) {}
}

function renderMesic() {
  var y = mesicDate.getFullYear(), m = mesicDate.getMonth();
  document.getElementById('mesic-label').textContent = MESICE_LONG[m] + ' ' + y;
  var hl = document.getElementById('mesic-hlavicka');
  hl.innerHTML = '';
  ['Po','Út','St','Čt','Pá','So','Ne'].forEach(function(d){
    var el = document.createElement('div');
    el.style.cssText = 'text-align:center;font-size:10px;color:#9ca3af;padding:2px 0;font-weight:500';
    el.textContent = d; hl.appendChild(el);
  });
  var grid = document.getElementById('mesic-grid');
  grid.innerHTML = '';
  var prvni = new Date(y, m, 1).getDay();
  var offset = prvni === 0 ? 6 : prvni - 1;
  for (var i = 0; i < offset; i++) {
    var e = document.createElement('div'); e.className = 'mesic-den mesic-empty'; grid.appendChild(e);
  }
  var dniVM = new Date(y, m+1, 0).getDate();
  var dnes = formatDate(new Date());
  for (var d = 1; d <= dniVM; d++) {
    var datum = y + '-' + String(m+1).padStart(2,'0') + '-' + String(d).padStart(2,'0');
    var el = document.createElement('div');
    el.className = 'mesic-den';
    if (datum === dnes) el.classList.add('mesic-dnes');
    if (selectedMesicDay === datum) el.classList.add('mesic-selected');
    var rezy = allRezervace[datum] || [];
    var filtrovane = kalFiltr ? rezy.filter(function(r){ return r.stav === kalFiltr; }) : rezy;
    var dots = '';
    filtrovane.forEach(function(r){
      dots += '<div class="dot-' + r.stav + '"></div>';
    });
    el.innerHTML = '<div style="font-size:12px">' + d + '</div>' + (dots ? '<div class="mesic-den-dots">' + dots + '</div>' : '');
    (function(datum_copy, rezy_copy) {
      el.onclick = function() {
        selectedMesicDay = datum_copy;
        renderMesic();
        showDenDetail(datum_copy, rezy_copy);
      };
    })(datum, filtrovane);
    grid.appendChild(el);
  }
}

function showDenDetail(datum, rezy) {
  var czDny = ['Neděle','Pondělí','Úterý','Středa','Čtvrtek','Pátek','Sobota'];
  var d = new Date(datum + 'T12:00:00');
  document.getElementById('kal-datum-label').textContent = czDny[d.getDay()] + ' ' + d.getDate() + '. ' + (d.getMonth()+1) + '. ' + d.getFullYear();
  renderRezList('kal-list', rezy);
}

function mesicChange(dir) {
  mesicDate.setMonth(mesicDate.getMonth() + dir);
  selectedMesicDay = null;
  document.getElementById('kal-datum-label').textContent = 'Vyberte den';
  document.getElementById('kal-list').innerHTML = '<div class="empty">Vyberte den v kalendáři</div>';
  loadMesicData();
}

// ---- SEZNAM POHLED ----
var seznamOd = new Date();
var seznamTydny = 4;

async function renderSeznam() {
  var od = formatDate(seznamOd);
  var do_date = new Date(seznamOd);
  do_date.setDate(do_date.getDate() + 30);
  var do_ = formatDate(do_date);
  document.getElementById('seznam-label').textContent = 'Příštích 30 dní';
  document.getElementById('kal-datum-label').textContent = 'Rezervace';
  document.getElementById('kal-list').innerHTML = '<div class="loading">Načítám…</div>';
  var stav_param = kalFiltr ? '&stav=' + kalFiltr : '';
  try {
    var r = await fetch(API + '/rezervace?datum_od=' + od + '&datum_do=' + do_ + stav_param, { headers: authHeaders() });
    var d = await r.json();
    renderRezList('kal-list', d.data || []);
  } catch(e) {
    document.getElementById('kal-list').innerHTML = '<div class="empty">Chyba načítání</div>';
  }
}

function seznamChange(dir) {
  seznamOd.setDate(seznamOd.getDate() + dir * 30);
  renderSeznam();
}

// Refresh kalendáře po změně stavu
function refreshKalendar() {
  loadMesicData();
  // Pokud je vybraný den, aktualizuj i jeho detail
  if (selectedMesicDay) {
    var rezy = allRezervace[selectedMesicDay] || [];
    var filtr = kalFiltr;
    var filtrovane = filtr ? rezy.filter(function(r){ return r.stav === filtr; }) : rezy;
    // Nestačí, data ještě nejsou aktuální - loadMesicData to udělá async
    // Po načtení dat znovu zobrazíme detail
    setTimeout(function() {
      var rezy2 = allRezervace[selectedMesicDay] || [];
      var filtrovane2 = kalFiltr ? rezy2.filter(function(r){ return r.stav === kalFiltr; }) : rezy2;
      showDenDetail(selectedMesicDay, filtrovane2);
    }, 800);
  }
}

// Inicializace kalendáře
function buildCalStrip() {
  mesicDate = new Date();
  seznamOd = new Date();
  loadMesicData();
}

async function loadKalendarDen(date, el) {
  var datum = formatDate(date);
  selectedMesicDay = datum;
  renderMesic();
  var rezy = allRezervace[datum] || [];
  showDenDetail(datum, rezy);
}

// Služby
var ikony = {'Střih & styling':'✂️','Barvení':'🎨','Melír':'✨','Péče o vlasy':'💆','Dětský střih':'😊','Foukaná':'💨'};

async function loadSluzbySel() {
  var r = await fetch(API + '/sluzby');
  var d = await r.json();
  var sel = document.getElementById('nr-sluzba');
  sel.innerHTML = '<option value="">— vyberte —</option>';
  (d.data || []).forEach(function(s) {
    var o = document.createElement('option');
    o.value = s.id; o.textContent = s.nazev + ' · ' + s.trvani_min + ' min · ' + (s.cena && parseFloat(s.cena) > 0 ? Math.round(s.cena).toLocaleString('cs-CZ') + ' Kč' : 'Individuální');
    o.dataset.trvani = s.trvani_min;
    sel.appendChild(o);
  });
  var dnes = new Date(); dnes.setDate(dnes.getDate() + 1);
  document.getElementById('nr-datum').min = formatDate(new Date());
}

async function loadSluzby() {
  var r = await fetch(API + '/sluzby');
  var d = await r.json();
  var el = document.getElementById('sluzby-list');
  if (!d.data || !d.data.length) { el.innerHTML = '<div class="empty">Žádné služby</div>'; return; }
  el.innerHTML = d.data.map(function(s) {
    return '<div class="svc-row" data-id="' + s.id + '"><div style="display:flex;align-items:center;gap:8px">'
      + '<span class="drag-handle" title="Přetáhněte pro změnu pořadí">⠿</span>'
      + '<div class="svc-icon">' + (ikony[s.nazev]||'💇') + '</div>'
      + '<div><div class="svc-name">' + esc(s.nazev) + '</div><div class="svc-detail">' + s.trvani_min + ' min</div></div></div>'
      + '<div style="display:flex;align-items:center;gap:8px"><div class="svc-price">' + (s.cena && parseFloat(s.cena) > 0 ? Math.round(s.cena).toLocaleString('cs-CZ') + ' Kč' : 'Individuální') + '</div>'
      + '<button class="btn-icon" onclick=\'openSvcModal(' + JSON.stringify(s).replace(/'/g,"&#39;") + ')\'>✏️</button>'
      + '<button class="btn-icon" style="color:#991b1b" onclick="deleteSvc(' + s.id + ',this)" title="Odebrat">🗑️</button></div>'
      + '<div id="doplnky-wrap-' + s.id + '" style="margin-top:8px"></div>'
      + '</div>';
  }).join('');
  // Načti doplňky pro každou službu
  (d.data || []).forEach(function(s) { loadDoplnky(s.id); });
  if (window.Sortable) {
    new Sortable(el, {
      handle: '.drag-handle', animation: 150,
      ghostClass: 'sortable-ghost', chosenClass: 'sortable-chosen',
      onEnd: function() { ulozitPoradiSluzeb(); }
    });
  }
}

// ---- Správa doplňků ----
async function loadDoplnky(sluzbaId) {
  var wrap = document.getElementById('doplnky-wrap-' + sluzbaId);
  if (!wrap) return;
  try {
    var r = await fetch(API + '/doplnky?sluzba_id=' + sluzbaId, { headers: authHeaders() });
    var d = await r.json();
    var items = d.data || [];
    wrap.innerHTML = '<div style="background:#faf5ff;border-radius:8px;padding:8px 12px;">'
      + '<div style="font-size:11px;font-weight:600;color:#6b21a8;margin-bottom:6px;display:flex;justify-content:space-between;align-items:center">'
      + '<span>Doplňkové služby</span>'
      + '<button class="btn-add" style="font-size:10px;padding:3px 8px" onclick="openDoplnekModal(' + sluzbaId + ',null)">+ Přidat</button>'
      + '</div>'
      + (items.length ? items.map(function(dd) {
          return '<div style="display:flex;align-items:center;justify-content:space-between;padding:6px 0;border-bottom:0.5px solid #e9d5ff">'
            + '<div><div style="font-size:12px;color:#111827">' + esc(dd.nazev) + '</div>'
            + '<div style="font-size:11px;color:#9ca3af">+' + dd.trvani_min + ' min</div></div>'
            + '<div style="display:flex;align-items:center;gap:8px">'
            + '<span style="font-size:12px;font-weight:600;color:#7c3aed">+' + Math.round(dd.cena).toLocaleString('cs-CZ') + ' Kč</span>'
            + '<button class="btn-icon" style="width:24px;height:24px;font-size:11px" onclick="openDoplnekModal(' + sluzbaId + ',' + JSON.stringify(dd).replace(/"/g,'&quot;') + ')">✏️</button>'
            + '<button class="btn-del" onclick="deleteDoplnek(' + dd.id + ',' + sluzbaId + ')">🗑️</button>'
            + '</div></div>';
        }).join('') : '<div style="font-size:11px;color:#9ca3af;padding:4px 0">Žádné doplňky</div>')
      + '</div>';
  } catch(e) {}
}

function openDoplnekModal(sluzbaId, dd) {
  document.getElementById('doplnek-sluzba-id').value = sluzbaId;
  document.getElementById('doplnek-id').value = dd ? dd.id : '';
  document.getElementById('doplnek-nazev').value = dd ? dd.nazev : '';
  document.getElementById('doplnek-cena').value = dd ? dd.cena : '';
  document.getElementById('doplnek-min').value = dd ? dd.trvani_min : '';
  document.getElementById('modal-doplnek-title').textContent = dd ? 'Upravit doplněk' : 'Nový doplněk';
  document.getElementById('doplnek-alert').style.display = 'none';
  openModal('modal-doplnek');
}

async function saveDoplnek() {
  var sluzbaId = document.getElementById('doplnek-sluzba-id').value;
  var id       = document.getElementById('doplnek-id').value;
  var nazev    = document.getElementById('doplnek-nazev').value.trim();
  var cena     = parseFloat(document.getElementById('doplnek-cena').value) || 0;
  var min      = parseInt(document.getElementById('doplnek-min').value) || 0;
  var alertEl  = document.getElementById('doplnek-alert');
  alertEl.style.display = 'none';

  if (!nazev) { alertEl.className = 'alert error'; alertEl.textContent = 'Vyplňte název.'; alertEl.style.display = 'block'; return; }

  var url    = id ? API + '/doplnky/' + id : API + '/doplnky';
  var method = id ? 'PUT' : 'POST';
  var body   = { nazev: nazev, cena: cena, trvani_min: min };
  if (!id) body.sluzba_id = parseInt(sluzbaId);

  try {
    var r = await fetch(url, { method: method, headers: authHeaders(), body: JSON.stringify(body) });
    var d = await r.json();
    if (d.ok) {
      closeModal('modal-doplnek');
      loadDoplnky(parseInt(sluzbaId));
      showToast('Doplněk uložen.');
    } else {
      alertEl.className = 'alert error'; alertEl.textContent = d.error || 'Chyba.'; alertEl.style.display = 'block';
    }
  } catch(e) {
    alertEl.className = 'alert error'; alertEl.textContent = 'Chyba připojení.'; alertEl.style.display = 'block';
  }
}

async function deleteDoplnek(id, sluzbaId) {
  if (!confirm('Smazat doplněk?')) return;
  var r = await fetch(API + '/doplnky/' + id, { method: 'DELETE', headers: authHeaders() });
  var d = await r.json();
  if (d.ok) { loadDoplnky(sluzbaId); showToast('Doplněk smazán.'); }
}

async function loadBlokace() {
  var r = await fetch(API + '/admin/blokovane', { headers: authHeaders() });
  var d = await r.json();
  var el = document.getElementById('blok-list');
  if (!d.data || !d.data.length) { el.innerHTML = '<div class="empty">Žádné blokace</div>'; return; }
  el.innerHTML = d.data.map(function(b) {
    var range = b.datum_od === b.datum_do ? b.datum_od : b.datum_od + ' – ' + b.datum_do;
    return '<div class="blok-row"><div><div class="blok-date">' + range + '</div><div class="blok-reason">' + esc(b.duvod||'') + '</div></div>'
      + '<button class="btn-del" onclick="deleteBlok(' + b.id + ',this)">🗑️</button></div>';
  }).join('');
}

async function deleteBlok(id, btn) {
  if (!confirm('Smazat blokaci?')) return;
  btn.disabled = true;
  var r = await fetch(API + '/admin/blokovane/' + id, { method:'DELETE', headers: authHeaders() });
  var d = await r.json();
  if (d.ok) loadBlokace();
}

async function deleteSvc(id, btn) {
  if (!confirm('Opravdu odebrat tuto službu? Existující rezervace nebudou smazány.')) return;
  btn.disabled = true;
  var r = await fetch(API + '/sluzby/' + id, { method:'DELETE', headers: authHeaders() });
  var d = await r.json();
  if (d.ok) { loadSluzby(); showToast('Služba byla odebrána.'); }
  else { btn.disabled = false; showToast('Chyba: ' + (d.error || 'Nepodařilo se smazat.'), true); }
}

var kartotek_timeout;
var kpick_timeout;
var kpickData = [];
async function kpickSearch(q) {
  var res = document.getElementById('kpick-results');
  clearTimeout(kpick_timeout);
  if (!q || q.length < 1) { res.innerHTML = '<div class="empty">Začněte psát pro vyhledání</div>'; return; }
  kpick_timeout = setTimeout(async function() {
    try {
      var r = await fetch(API + '/zakaznici?q=' + encodeURIComponent(q), { headers: authHeaders() });
      var d = await r.json();
      var list = d.data || [];
      if (!list.length) { res.innerHTML = '<div class="empty">Žádné výsledky</div>'; return; }
      // Uložíme výsledky do globální proměnné a renderujeme s index
      kpickData = list;
      res.innerHTML = list.map(function(z, idx) {
        return '<div style="display:flex;align-items:center;gap:10px;padding:10px 12px;border-bottom:1px solid #f3e8ff;cursor:pointer" onclick="kpickVybrat(' + idx + ')">'
          + '<div class="zak-avatar" style="width:32px;height:32px;font-size:12px">' + esc(((z.jmeno||'')[0]+(z.prijmeni||'')[0]).toUpperCase()) + '</div>'
          + '<div><div style="font-size:13px;font-weight:600">' + esc(z.prijmeni) + ' ' + esc(z.jmeno) + '</div>'
          + '<div style="font-size:11px;color:#9ca3af">' + esc(z.email) + (z.telefon ? ' · ' + esc(z.telefon) : '') + '</div></div>'
          + '</div>';
      }).join('');
    } catch(e) { res.innerHTML = '<div class="empty">Chyba načítání</div>'; }
  }, 250);
}

function kpickVybrat(idx) {
  var z = kpickData[idx];
  if (!z) return;
  document.getElementById('nr-jmeno').value    = z.jmeno    || '';
  document.getElementById('nr-prijmeni').value = z.prijmeni || '';
  document.getElementById('nr-email').value    = z.email    || '';
  document.getElementById('nr-telefon').value  = z.telefon  || '';
  closeModal('modal-kartotek-pick');
  document.getElementById('kpick-search').value = '';
  document.getElementById('kpick-results').innerHTML = '<div class="empty">Začněte psát pro vyhledání</div>';
}

async function ulozitPoradiSluzeb() {
  var rows = document.querySelectorAll('#sluzby-list .svc-row[data-id]');
  var poradi = Array.from(rows).map(function(r, i) {
    return { id: parseInt(r.dataset.id), poradi: i + 1 };
  });
  try {
    await fetch(API + '/sluzby/poradi', {
      method: 'PUT',
      headers: authHeaders(),
      body: JSON.stringify({ poradi: poradi })
    });
  } catch(e) { console.error('Chyba uložení pořadí', e); }
}

function openSvcModal(s) {
  document.getElementById('modal-svc-title').textContent = s ? 'Upravit službu' : 'Nová služba';
  document.getElementById('svc-id').value = s ? s.id : '';
  document.getElementById('svc-nazev').value = s ? s.nazev : '';
  document.getElementById('svc-trvani').value = s ? s.trvani_min : '';
  document.getElementById('svc-cena').value = (s && s.cena && parseFloat(s.cena) > 0) ? Math.round(s.cena) : '';
  openModal('modal-svc');
}

async function saveSvc() {
  var id      = document.getElementById('svc-id').value;
  var nazev   = document.getElementById('svc-nazev').value.trim();
  var trvani  = parseInt(document.getElementById('svc-trvani').value);
  var cenaRaw = document.getElementById('svc-cena').value.trim();
  var cena    = cenaRaw !== '' ? parseFloat(cenaRaw) : null;

  if (!nazev) { alert('Vyplňte název služby.'); return; }
  if (!trvani || trvani < 1) { alert('Vyplňte trvání služby.'); return; }

  var payload = { nazev: nazev, trvani_min: trvani, cena: cena };
  var url    = id ? API + '/sluzby/' + id : API + '/sluzby';
  var method = id ? 'PUT' : 'POST';
  try {
    var r = await fetch(url, { method: method, headers: authHeaders(), body: JSON.stringify(payload) });
    var d = await r.json();
    if (d.ok) { closeModal('modal-svc'); loadSluzby(); showToast('Služba uložena.'); }
    else { alert(d.error || 'Chyba při ukládání: ' + JSON.stringify(d)); }
  } catch(e) { alert('Síťová chyba: ' + e.message); }
}

function openBlokModal() {
  var today = formatDate(new Date());
  document.getElementById('blok-od').value = today;
  document.getElementById('blok-do').value = today;
  document.getElementById('blok-duvod').value = '';
  openModal('modal-blok');
}

async function saveBlok() {
  var payload = { datum_od: document.getElementById('blok-od').value, datum_do: document.getElementById('blok-do').value, duvod: document.getElementById('blok-duvod').value };
  var r = await fetch(API + '/admin/blokovane', { method:'POST', headers: authHeaders(), body: JSON.stringify(payload) });
  var d = await r.json();
  if (d.ok) { closeModal('modal-blok'); loadBlokace(); }
  else alert(d.error || 'Chyba při ukládání.');
}

// Nastavení
var DAYS_DEF = [{l:'Po',v:1},{l:'Út',v:2},{l:'St',v:3},{l:'Čt',v:4},{l:'Pá',v:5},{l:'So',v:6},{l:'Ne',v:7}];

function buildDaysWrap(active) {
  activeDays = active;
  var wrap = document.getElementById('daysWrap');
  wrap.innerHTML = '';
  DAYS_DEF.forEach(function(d) {
    var el = document.createElement('div');
    el.className = 'day-pill' + (active.indexOf(d.v)>-1?' on':'');
    el.textContent = d.l;
    el.onclick = function() {
      var idx = activeDays.indexOf(d.v);
      if (idx>-1) { activeDays.splice(idx,1); el.classList.remove('on'); }
      else { activeDays.push(d.v); activeDays.sort(); el.classList.add('on'); }
      document.getElementById('set-pracovni_dny').value = activeDays.join(',');
    };
    wrap.appendChild(el);
  });
  document.getElementById('set-pracovni_dny').value = active.join(',');
}

var DNY_NASTAVENI = [{l:'Pondělí',v:1},{l:'Úterý',v:2},{l:'Středa',v:3},{l:'Čtvrtek',v:4},{l:'Pátek',v:5},{l:'Sobota',v:6},{l:'Neděle',v:7}];

async function loadSettings() {
  var r = await fetch(API + '/nastaveni', { headers: authHeaders() });
  var d = await r.json();
  if (!d.ok) return;
  var keys = ['salon_nazev','salon_telefon','salon_email','salon_adresa','cislo_uctu','slot_minut','rezervace_min_predem','rezervace_storno_hod','pripominka_hodin','hodnoceni_hodin_po'];
  keys.forEach(function(k) {
    var el = document.getElementById('set-' + k);
    if (el && d.data[k]) el.value = d.data[k].hodnota;
  });

  // Připomenutí - toggle switch
  var pripZapnuta = d.data['pripominka_zapnuta'] && d.data['pripominka_zapnuta'].hodnota === '1';
  document.getElementById('set-pripominka_zapnuta').checked = pripZapnuta;
  document.getElementById('pripominka-toggle').style.background = pripZapnuta ? '#9333ea' : '#e5e7eb';
  document.getElementById('pripominka-knob').style.left = pripZapnuta ? '23px' : '3px';
  document.getElementById('pripominka-hod-row').style.display = pripZapnuta ? 'flex' : 'none';
  if (!d.data['pripominka_hodin']) document.getElementById('set-pripominka_hodin').value = 24;

  // Hodnocení - žádost o hodnocení
  var hodZadost = d.data['hodnoceni_zadost_zapnuta'] && d.data['hodnoceni_zadost_zapnuta'].hodnota === '1';
  document.getElementById('set-hodnoceni_zadost_zapnuta').checked = hodZadost;
  document.getElementById('hodnoceni-zadost-toggle').style.background = hodZadost ? '#9333ea' : '#e5e7eb';
  document.getElementById('hodnoceni-zadost-knob').style.left = hodZadost ? '23px' : '3px';
  document.getElementById('hodnoceni-hod-row').style.display = hodZadost ? 'flex' : 'none';
  if (!d.data['hodnoceni_hodin_po']) document.getElementById('set-hodnoceni_hodin_po').value = 2;

  // Hodnocení - veřejné zobrazení
  var hodVerejne = d.data['hodnoceni_verejne_zapnuta'] && d.data['hodnoceni_verejne_zapnuta'].hodnota === '1';
  document.getElementById('set-hodnoceni_verejne_zapnuta').checked = hodVerejne;
  document.getElementById('hodnoceni-verejne-toggle').style.background = hodVerejne ? '#9333ea' : '#e5e7eb';
  document.getElementById('hodnoceni-verejne-knob').style.left = hodVerejne ? '23px' : '3px';

  // Aktualizuj popis účtu v QR záložce
  var ucetEl = document.getElementById('set-cislo_uctu');
  var popisEl = document.getElementById('qr-ucet-popis');
  if (ucetEl && popisEl) {
    var ucetVal = (d.data['cislo_uctu'] && d.data['cislo_uctu'].hodnota) ? d.data['cislo_uctu'].hodnota : '—';
    popisEl.textContent = 'Účet: ' + ucetVal + ' · VS: dnešní datum (automaticky)';
  }

  // Načti pracovní dobu per den
  try {
    var r2 = await fetch(API + '/pracovni-doba', { headers: authHeaders() });
    var d2 = await r2.json();
    buildPracovniDobaWrap(d2.ok ? d2.data : {});
  } catch(e) { buildPracovniDobaWrap({}); }
}

function buildPracovniDobaWrap(data) {
  var wrap = document.getElementById('pracovni-doba-wrap');
  if (!wrap) return;
  wrap.innerHTML = DNY_NASTAVENI.map(function(den) {
    var db = data[den.v] || {aktivni: den.v <= 6, od_min: 480, do_min: 1020};
    var checked = db.aktivni ? 'checked' : '';
    var od  = minNaCas(db.od_min || 480);
    var doCas = minNaCas(db.do_min || 1020);
    return '<div style="display:flex;align-items:center;gap:8px;padding:8px 0;border-bottom:0.5px solid var(--g200)">'
      + '<input type="checkbox" id="pd-aktivni-' + den.v + '" ' + checked + ' style="accent-color:#9333ea;width:16px;height:16px;flex-shrink:0" onchange="toggleDenDoba(' + den.v + ',this.checked)">'
      + '<span style="font-size:13px;color:#374151;min-width:72px">' + den.l + '</span>'
      + '<div id="pd-doba-' + den.v + '" style="display:' + (db.aktivni ? 'flex' : 'none') + ';align-items:center;gap:6px;flex:1">'
      + '<input type="time" id="pd-od-' + den.v + '" value="' + od + '" style="border:1.5px solid #e9d5ff;border-radius:6px;padding:4px 8px;font-size:13px;color:#111827;background:#fff">'
      + '<span style="font-size:12px;color:#9ca3af">–</span>'
      + '<input type="time" id="pd-do-' + den.v + '" value="' + doCas + '" style="border:1.5px solid #e9d5ff;border-radius:6px;padding:4px 8px;font-size:13px;color:#111827;background:#fff">'
      + '</div>'
      + '<span id="pd-zavreno-' + den.v + '" style="display:' + (db.aktivni ? 'none' : 'block') + ';font-size:12px;color:#9ca3af">Zavřeno</span>'
      + '</div>';
  }).join('');
}

function toggleDenDoba(den, aktivni) {
  document.getElementById('pd-doba-' + den).style.display = aktivni ? 'flex' : 'none';
  document.getElementById('pd-zavreno-' + den).style.display = aktivni ? 'none' : 'block';
}

async function saveSettings() {
  var keys = ['salon_nazev','salon_telefon','salon_email','salon_adresa','cislo_uctu','slot_minut','rezervace_min_predem','rezervace_storno_hod','pripominka_hodin','hodnoceni_hodin_po'];
  var payload = {};
  keys.forEach(function(k) {
    var el = document.getElementById('set-' + k);
    if (el) payload[k] = el.value;
  });
  payload['pripominka_zapnuta'] = document.getElementById('set-pripominka_zapnuta').checked ? '1' : '0';
  payload['hodnoceni_zadost_zapnuta'] = document.getElementById('set-hodnoceni_zadost_zapnuta').checked ? '1' : '0';
  payload['hodnoceni_verejne_zapnuta'] = document.getElementById('set-hodnoceni_verejne_zapnuta').checked ? '1' : '0';
  var alertEl = document.getElementById('set-alert');
  alertEl.style.display = 'none';

  // Uložit obecná nastavení
  var r1 = await fetch(API + '/nastaveni', { method:'PUT', headers: authHeaders(), body: JSON.stringify(payload) });
  var d1 = await r1.json();

  // Uložit pracovní dobu per den
  var dny = {};
  DNY_NASTAVENI.forEach(function(d) {
    var aktivni = document.getElementById('pd-aktivni-' + d.v);
    var od      = document.getElementById('pd-od-' + d.v);
    var doCas   = document.getElementById('pd-do-' + d.v);
    if (aktivni) {
      dny[d.v] = {
        aktivni: aktivni.checked ? 1 : 0,
        od_min:  casNaMin(od ? od.value : '08:00'),
        do_min:  casNaMin(doCas ? doCas.value : '17:00')
      };
    }
  });
  var r2 = await fetch(API + '/pracovni-doba', { method:'PUT', headers: authHeaders(), body: JSON.stringify({dny: dny}) });
  var d2 = await r2.json();

  alertEl.style.display = 'block';
  if (d1.ok && d2.ok) { alertEl.className='alert success'; alertEl.textContent='✅ Nastavení uloženo.'; }
  else { alertEl.className='alert error'; alertEl.textContent = (!d1.ok ? d1.error : d2.error) || 'Chyba při ukládání.'; }
  setTimeout(function(){ alertEl.style.display='none'; }, 3000);
}

function togglePripominka(el) {
  document.getElementById('pripominka-hod-row').style.display = el.checked ? 'flex' : 'none';
  document.getElementById('pripominka-toggle').style.background = el.checked ? '#9333ea' : '#e5e7eb';
  document.getElementById('pripominka-knob').style.left = el.checked ? '23px' : '3px';
}

function toggleSwitch(el, rowId, toggleId, knobId) {
  document.getElementById(rowId).style.display = el.checked ? 'flex' : 'none';
  document.getElementById(toggleId).style.background = el.checked ? '#9333ea' : '#e5e7eb';
  document.getElementById(knobId).style.left = el.checked ? '23px' : '3px';
}

function toggleSwitchSimple(el, toggleId, knobId) {
  document.getElementById(toggleId).style.background = el.checked ? '#9333ea' : '#e5e7eb';
  document.getElementById(knobId).style.left = el.checked ? '23px' : '3px';
}

function casNaMin(cas) {
  var parts = cas.split(':');
  return parseInt(parts[0]) * 60 + parseInt(parts[1] || 0);
}

function minNaCas(min) {
  return String(Math.floor(min/60)).padStart(2,'0') + ':' + String(min%60).padStart(2,'0');
}

function openModal(id) { document.getElementById(id).classList.add('active'); }
function closeModal(id) { document.getElementById(id).classList.remove('active'); }
function formatDate(d) { return d.getFullYear()+'-'+String(d.getMonth()+1).padStart(2,'0')+'-'+String(d.getDate()).padStart(2,'0'); }
function esc(s) { return String(s).replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;'); }

function renderStars(hodnoceni, size) {
  size = size || 13;
  var html = '<span style="font-size:' + size + 'px">';
  for (var i = 1; i <= 5; i++) {
    var color = i <= hodnoceni ? '#f59e0b' : '#d1d5db';
    html += '<span style="color:' + color + '">★</span>';
  }
  html += '</span>';
  return html;
}

async function changeHeslo() {
  var stare    = document.getElementById('heslo-stare').value;
  var nove     = document.getElementById('heslo-nove').value;
  var potvrzeni = document.getElementById('heslo-potvrzeni').value;
  var alertEl  = document.getElementById('heslo-alert');
  alertEl.style.display = 'none';

  if (!stare || !nove || !potvrzeni) {
    alertEl.className = 'alert error'; alertEl.textContent = 'Vyplňte všechna pole.'; alertEl.style.display = 'block'; return;
  }
  if (nove.length < 8) {
    alertEl.className = 'alert error'; alertEl.textContent = 'Nové heslo musí mít alespoň 8 znaků.'; alertEl.style.display = 'block'; return;
  }
  if (nove !== potvrzeni) {
    alertEl.className = 'alert error'; alertEl.textContent = 'Nové heslo a potvrzení se neshodují.'; alertEl.style.display = 'block'; return;
  }

  try {
    var r = await fetch(API + '/heslo', {
      method: 'POST',
      headers: authHeaders(),
      body: JSON.stringify({ stare_heslo: stare, nove_heslo: nove, potvrzeni: potvrzeni })
    });
    var d = await r.json();
    if (d.ok) {
      alertEl.className = 'alert success'; alertEl.textContent = '✅ Heslo bylo úspěšně změněno.'; alertEl.style.display = 'block';
      setTimeout(function() { closeModal('modal-heslo'); resetHesloForm(); }, 2000);
    } else {
      alertEl.className = 'alert error'; alertEl.textContent = d.error || 'Chyba při změně hesla.'; alertEl.style.display = 'block';
    }
  } catch(e) {
    alertEl.className = 'alert error'; alertEl.textContent = 'Chyba připojení.'; alertEl.style.display = 'block';
  }
}

// ---- KARTOTÉKA ----
var kartotekaData = [];

async function loadKartoteka(q) {
  var url = API + '/zakaznici' + (q ? '?q=' + encodeURIComponent(q) : '');
  var el = document.getElementById('kartoteka-list');
  try {
    var r = await fetch(url, { headers: authHeaders() });
    var d = await r.json();
    if (!d.ok) {
      // Tabulka neexistuje – sync
      await fetch(API + '/zakaznici/sync', { method:'POST', headers: authHeaders() });
      return loadKartoteka(q);
    }
    kartotekaData = d.data || [];
    renderKartoteka(kartotekaData);
  } catch(e) { el.innerHTML = '<div class="empty">Chyba načítání</div>'; }
}

function renderKartoteka(list) {
  var el = document.getElementById('kartoteka-list');
  if (!list.length) { el.innerHTML = '<div class="empty">Žádní zákazníci</div>'; return; }
  el.innerHTML = list.map(function(z) {
    var initials = (z.jmeno[0] || '') + (z.prijmeni[0] || '');
    var stitky = z.stitky ? z.stitky.split(',').filter(Boolean).map(function(s){
      return '<span class="stitek">' + esc(s.trim()) + '</span>';
    }).join('') : '';
    var posledni = z.posledni_navsteva ? '<span style="font-size:11px;color:#9ca3af">Naposledy: ' + z.posledni_navsteva + '</span>' : '';
    return '<div class="zak-card" id="zak-' + z.id + '">'
      + '<div style="display:flex;align-items:center;gap:10px" onclick="openZakaznik(' + z.id + ')">'
      + '<div class="zak-avatar">' + esc(initials.toUpperCase()) + '</div>'
      + '<div style="flex:1;min-width:0">'
      + '<div style="display:flex;align-items:center;justify-content:space-between;gap:6px">'
      + '<div class="zak-name">' + esc(z.prijmeni) + ' ' + esc(z.jmeno) + '</div>'
      + '<span class="zak-stat">' + (z.navstevy || z.pocet_rezervaci || 0) + ' návštěv</span>'
      + '</div>'
      + '<div class="zak-sub">' + esc(z.email) + (z.telefon ? ' · ' + esc(z.telefon) : '') + '</div>'
      + (stitky ? '<div style="margin-top:4px">' + stitky + '</div>' : '')
      + (posledni ? '<div style="margin-top:2px">' + posledni + '</div>' : '')
      + '</div></div>'
      + '<div style="display:flex;justify-content:flex-end;padding-top:6px;border-top:1px solid #f3e8ff;margin-top:6px">'
      + '<button class="btn-sm" style="background:#fee2e2;color:#991b1b" onclick="event.stopPropagation();smazatZakaznika(' + z.id + ',\'' + esc(z.jmeno) + ' ' + esc(z.prijmeni) + '\')">🗑 Smazat</button>'
      + '</div></div>';
  }).join('');
}

async function smazatZakaznika(id, jmeno) {
  if (!confirm('Smazat zákazníka ' + jmeno + ' z kartotéky?\nTato akce je nevratná.')) return;
  try {
    var r = await fetch(API + '/zakaznici/' + id, { method: 'DELETE', headers: authHeaders() });
    var d = await r.json();
    if (d.ok) {
      var el = document.getElementById('zak-' + id);
      if (el) el.remove();
      showToast('Zákazník ' + jmeno + ' byl smazán.');
    } else {
      showToast('Chyba: ' + (d.error || 'Nepodařilo se smazat.'), true);
    }
  } catch(e) {
    showToast('Chyba připojení.', true);
  }
}

var searchTimeout;
function searchKartoteka(q) {
  clearTimeout(searchTimeout);
  searchTimeout = setTimeout(function(){ loadKartoteka(q); }, 300);
}

async function openZakaznik(id) {
  var r = await fetch(API + '/zakaznici/' + id, { headers: authHeaders() });
  var d = await r.json();
  if (!d.ok) return;
  var z = d.zakaznik, stats = d.stats, rezervace = d.rezervace || [];

  var stitky = (z.stitky || '').split(',').filter(Boolean);
  var stitkyHtml = stitky.map(function(s,i){
    return '<span class="stitek">' + esc(s.trim()) + ' <span class="stitek-del" onclick="removeStitok(' + id + ',' + i + ')">✕</span></span>';
  }).join('');

  var rezHtml = rezervace.length ? rezervace.map(function(rez){
    var badgeCls = rez.stav==='potvrzena'?'badge-green':rez.stav==='zrusena'?'badge-red':'badge-amber';
    var badgeTxt = rez.stav==='potvrzena'?'Potvrzeno':rez.stav==='zrusena'?'Zrušeno':'Čeká';
    return '<div style="display:flex;align-items:center;gap:8px;padding:8px 0;border-bottom:1px solid #f3e8ff;font-size:12px">'
      + '<div style="min-width:80px;color:#6b7280">' + rez.datum + '</div>'
      + '<div style="flex:1">' + esc(rez.sluzba)
      + (function() {
          var doplnky = rez.doplnky || [];
          if (doplnky.length > 0) {
            return '<br><span style="color:#9333ea;font-size:11px">+ ' + doplnky.map(function(d){ return d.nazev; }).join(', ') + '</span>';
          }
          return '';
        })()
      + '<br><span style="color:#9ca3af">' + rez.cas_od + ' · '
      + (function() {
          var doplnky = rez.doplnky || [];
          var celkem;
          if (rez.cena_upravena !== null && rez.cena_upravena !== undefined && rez.cena_upravena !== '') {
            celkem = parseFloat(rez.cena_upravena) || 0;
          } else {
            var extra = doplnky.reduce(function(s,d){ return s + parseFloat(d.cena||0); }, 0);
            celkem = (parseFloat(rez.cena)||0) + extra;
          }
          return celkem > 0 ? Math.round(celkem).toLocaleString('cs-CZ') + ' Kč' : 'Individuální';
        })()
      + (rez.hodnoceni ? ' · ' + renderStars(rez.hodnoceni, 11) : '')
      + '</span></div>'
      + '<span class="badge ' + badgeCls + '" style="font-size:10px">' + badgeTxt + '</span>'
      + '</div>';
  }).join('') : '<div class="empty" style="padding:8px 0">Žádné rezervace</div>';

  document.getElementById('modal-zak-content').innerHTML =
    '<div style="display:flex;align-items:center;gap:12px;margin-bottom:14px">'
    + '<div class="zak-avatar" style="width:48px;height:48px;font-size:17px">' + esc((z.jmeno[0]||'')+(z.prijmeni[0]||'')).toUpperCase() + '</div>'
    + '<div><div style="font-size:16px;font-weight:700">' + esc(z.prijmeni) + ' ' + esc(z.jmeno) + '</div>'
    + '<div style="font-size:12px;color:#9ca3af">' + esc(z.email) + '</div>'
    + (stats.pocet_hodnoceni > 0 ? '<div style="margin-top:3px;display:flex;align-items:center;gap:5px">' + renderStars(Math.round(stats.prumer_hodnoceni), 13) + '<span style="font-size:11px;color:#9ca3af">' + stats.prumer_hodnoceni.toFixed(1) + ' (' + stats.pocet_hodnoceni + ')</span></div>' : '')
    + '</div></div>'
    + '<div style="display:grid;grid-template-columns:1fr 1fr 1fr;gap:8px;margin-bottom:14px">'
    + '<div class="stat-card"><div class="stat-val" style="font-size:18px">' + (stats.navstevy||0) + '</div><div class="stat-label">návštěv</div></div>'
    + '<div class="stat-card"><div class="stat-val" style="font-size:14px">' + Math.round(stats.celkem_utraceno||0).toLocaleString('cs-CZ') + ' Kč</div><div class="stat-label">celkem</div></div>'
    + '<div class="stat-card"><div class="stat-val" style="font-size:13px">' + (stats.posledni||'—') + '</div><div class="stat-label">naposledy</div></div>'
    + '</div>'
    + '<label class="modal-label">Telefon</label>'
    + '<input class="modal-input" id="zak-telefon" value="' + esc(z.telefon||'') + '" placeholder="+420...">'
    + '<label class="modal-label">Štítky</label>'
    + '<div style="margin-bottom:8px" id="zak-stitky-wrap">' + (stitkyHtml||'<span style="font-size:12px;color:#9ca3af">Žádné štítky</span>') + '</div>'
    + '<div style="display:flex;gap:6px;margin-bottom:10px">'
    + '<input class="modal-input" id="zak-novy-stitek" placeholder="Nový štítek (VIP, Alergie…)" style="margin:0;flex:1" onkeydown="if(event.key==&quot;Enter&quot;)addStitok(' + id + ')">'
    + '<button class="btn-modal-save" style="padding:0 12px;font-size:12px" onclick="addStitok(' + id + ')">+</button>'
    + '</div>'
    + '<label class="modal-label">Interní poznámka</label>'
    + '<textarea class="modal-input" id="zak-poznamka" style="height:60px;resize:none;line-height:1.5">' + esc(z.poznamka||'') + '</textarea>'
    + '<label class="modal-label" style="margin-top:10px">Historie rezervací</label>'
    + '<div style="max-height:200px;overflow-y:auto">' + rezHtml + '</div>';

  document.getElementById('modal-zak-id').value = id;
  document.getElementById('modal-zak-stitky').value = z.stitky || '';
  openModal('modal-zak');
}

function smazatZakModal() {
  var id = document.getElementById('modal-zak-id').value;
  var nazev = document.querySelector('#modal-zak-content .zak-jmeno')?.textContent || 'zákazníka';
  closeModal('modal-zak');
  smazatZakaznika(id, nazev);
}

async function saveZakaznik() {
  var id = document.getElementById('modal-zak-id').value;
  var payload = {
    poznamka: document.getElementById('zak-poznamka').value,
    stitky:   document.getElementById('modal-zak-stitky').value,
    telefon:  document.getElementById('zak-telefon').value,
  };
  var r = await fetch(API + '/zakaznici/' + id, { method:'PUT', headers: authHeaders(), body: JSON.stringify(payload) });
  var d = await r.json();
  if (d.ok) { closeModal('modal-zak'); loadKartoteka(document.getElementById('kartotek-search').value); }
}

function addStitok(id) {
  var inp = document.getElementById('zak-novy-stitek');
  var val = inp.value.trim();
  if (!val) return;
  var current = document.getElementById('modal-zak-stitky').value;
  var arr = current ? current.split(',').filter(Boolean) : [];
  if (arr.indexOf(val) === -1) arr.push(val);
  document.getElementById('modal-zak-stitky').value = arr.join(',');
  inp.value = '';
  // Aktualizuj zobrazení
  var wrap = document.getElementById('zak-stitky-wrap');
  wrap.innerHTML = arr.map(function(s,i){
    return '<span class="stitek">' + esc(s.trim()) + ' <span class="stitek-del" onclick="removeStitok(' + id + ',' + i + ')">✕</span></span>';
  }).join('');
}

function removeStitok(zakId, idx) {
  var current = document.getElementById('modal-zak-stitky').value;
  var arr = current.split(',').filter(Boolean);
  arr.splice(idx, 1);
  document.getElementById('modal-zak-stitky').value = arr.join(',');
  var wrap = document.getElementById('zak-stitky-wrap');
  wrap.innerHTML = arr.length ? arr.map(function(s,i){
    return '<span class="stitek">' + esc(s.trim()) + ' <span class="stitek-del" onclick="removeStitok(' + zakId + ',' + i + ')">✕</span></span>';
  }).join('') : '<span style="font-size:12px;color:#9ca3af">Žádné štítky</span>';
}

// ---- QR PLATBA ----
var qrInstance = null;

function getVS() {
  var d = new Date();
  return d.getFullYear().toString() +
    String(d.getMonth()+1).padStart(2,'0') +
    String(d.getDate()).padStart(2,'0');
}

function getIBAN() {
  var ucet = (document.getElementById('set-cislo_uctu') || {}).value || '';
  if (!ucet) return '';
  var parts = ucet.split('/');
  var kodBanky = (parts[1] || '0800').replace(/\s/g, '');
  var cisloParts = parts[0].replace(/\s/g, '').split('-');
  var predcisli = cisloParts.length > 1 ? cisloParts[0] : '0';
  var zakladni  = cisloParts.length > 1 ? cisloParts[1] : cisloParts[0];
  // CZ IBAN: kod(4) + predcisli(6) + zakladni(10)
  predcisli = predcisli.padStart(6, '0');
  zakladni  = zakladni.padStart(10, '0');
  var bban = kodBanky + predcisli + zakladni;
  // Přidej CZ00 na konec pro MOD97
  var raw = bban + '123500'; // CZ=1235, 00=placeholder
  // MOD97 přes BigInt pro přesnost
  var mod;
  try {
    mod = Number(BigInt(raw) % BigInt(97));
  } catch(e) {
    // Fallback pro starší prohlížeče
    mod = 0;
    for (var i = 0; i < raw.length; i++) { mod = (mod * 10 + parseInt(raw[i])) % 97; }
  }
  var check = String(98 - mod).padStart(2, '0');
  return 'CZ' + check + bban;
}

function removeDiacritics(str) {
  return str.normalize('NFD').replace(/[\u0300-\u036f]/g, '').replace(/[^a-zA-Z0-9 ]/g, '');
}

function buildSPD(castka, poznamka) {
  var iban = getIBAN();
  if (!iban) return '';
  var vs = getVS();
  // Minimální validní SPD*1.0 formát dle české normy
  var str = 'SPD*1.0*ACC:' + iban + '*AM:' + parseFloat(castka).toFixed(2) + '*CC:CZK';
  str += '*X-VS:' + vs;
  if (poznamka) str += '*MSG:' + removeDiacritics(poznamka).substring(0, 60);
  return str;
}

function generateQR() {
  var castka  = document.getElementById('qr-castka').value;
  var poznamka = document.getElementById('qr-poznamka').value.trim();
  var wrap    = document.getElementById('qr-wrap');
  var placeholder = document.getElementById('qr-placeholder');

  if (!castka || parseFloat(castka) <= 0) {
    wrap.style.display = 'none';
    placeholder.style.display = 'block';
    return;
  }

  var spd = buildSPD(castka, poznamka);
  var container = document.getElementById('qr-code');
  container.innerHTML = '';

  console.log('SPD:', spd);
  if (typeof QRCode !== 'undefined') {
    new QRCode(container, {
      text: spd,
      width: 200,
      height: 200,
      colorDark: '#111827',
      colorLight: '#ffffff',
      correctLevel: QRCode.CorrectLevel.L
    });
  }

  var vs = getVS();
  var ucet_display = (document.getElementById('set-cislo_uctu') || {}).value || '—';
  var info = ucet_display + ' · ' + parseFloat(castka).toLocaleString('cs-CZ') + ' Kč · VS: ' + vs;
  if (poznamka) info += ' · ' + poznamka;
  document.getElementById('qr-info').textContent = info;
  wrap.style.display = 'block';
  placeholder.style.display = 'none';
}

function downloadQR() {
  var canvas = document.querySelector('#qr-code canvas');
  if (!canvas) return;
  var castka = document.getElementById('qr-castka').value;
  var link = document.createElement('a');
  link.download = 'qr-platba-' + castka + 'kc-' + getVS() + '.png';
  link.href = canvas.toDataURL('image/png');
  link.click();
}

var nrSluzbaTrvani = 0;
var nrVybranyCas = '';

function nrSluzbaChange() {
  var sel = document.getElementById('nr-sluzba');
  var opt = sel.options[sel.selectedIndex];
  nrSluzbaTrvani = opt ? parseInt(opt.dataset.trvani || 0) : 0;
  nrVybranyCas = '';
  document.getElementById('nr-times-wrap').style.display = 'none';
  document.getElementById('nr-cas-manual').value = '';
  var sluzbaId = sel.value;
  // Načti doplňky
  if (sluzbaId) {
    nrNactiDoplnky(sluzbaId);
  } else {
    document.getElementById('nr-doplnky-wrap').style.display = 'none';
  }
  var datum = document.getElementById('nr-datum').value;
  if (datum && nrSluzbaTrvani) nrNactiCasy(datum);
}

async function nrNactiDoplnky(sluzbaId) {
  var wrap = document.getElementById('nr-doplnky-wrap');
  var grid = document.getElementById('nr-doplnky-grid');
  try {
    var r = await fetch(API + '/doplnky?sluzba_id=' + sluzbaId, { headers: authHeaders() });
    var d = await r.json();
    if (!d.ok || !d.data || d.data.length === 0) {
      wrap.style.display = 'none';
      return;
    }
    wrap.style.display = 'block';
    grid.innerHTML = d.data.map(function(dd) {
      return '<div style="display:flex;align-items:center;justify-content:space-between;padding:6px 0;border-bottom:0.5px solid #e9d5ff">'
        + '<div style="display:flex;align-items:center;gap:8px">'
        + '<input type="checkbox" class="nr-doplnek-check" id="nr-doplnek-' + dd.id + '" data-id="' + dd.id + '" data-nazev="' + esc(dd.nazev) + '" data-cena="' + dd.cena + '" data-min="' + dd.trvani_min + '" style="width:16px;height:16px;accent-color:#9333ea;cursor:pointer" onchange="nrDoplnekChange()">'
        + '<div><div style="font-size:12px;color:#111827">' + esc(dd.nazev) + '</div>'
        + (dd.trvani_min > 0 ? '<div style="font-size:11px;color:#9ca3af">+' + dd.trvani_min + ' min</div>' : '')
        + '</div></div>'
        + '<div style="font-size:12px;font-weight:600;color:#7c3aed">+' + Math.round(dd.cena).toLocaleString('cs-CZ') + ' Kč</div>'
        + '</div>';
    }).join('') + '<div style="border-top:none"></div>';
  } catch(e) {
    wrap.style.display = 'none';
  }
}

var nrDoplnkyExtraMin = 0;

function nrDoplnekChange() {
  var checkboxes = document.querySelectorAll('.nr-doplnek-check:checked');
  nrDoplnkyExtraMin = Array.from(checkboxes).reduce(function(s, ch) {
    return s + parseInt(ch.dataset.min || 0);
  }, 0);
  // Znovu načti časy s novým extra_min
  var datum = document.getElementById('nr-datum').value;
  if (datum && nrSluzbaTrvani) {
    nrVybranyCas = '';
    document.getElementById('nr-cas-manual').value = '';
    nrNactiCasy(datum);
  }
}

function nrDatumChange() {
  var datum = document.getElementById('nr-datum').value;
  nrVybranyCas = '';
  document.getElementById('nr-cas-manual').value = '';
  if (datum && nrSluzbaTrvani) nrNactiCasy(datum);
}

async function nrNactiCasy(datum) {
  var sluzbaId = document.getElementById('nr-sluzba').value;
  if (!sluzbaId) return;
  var wrap = document.getElementById('nr-times-wrap');
  wrap.style.display = 'block';
  document.getElementById('nr-times-loading').style.display = 'block';
  document.getElementById('nr-times-grid').innerHTML = '';
  try {
    var extraMin = nrDoplnkyExtraMin || 0;
    var r = await fetch(API + '/dostupnost?sluzba_id=' + sluzbaId + '&datum=' + datum + (extraMin > 0 ? '&extra_min=' + extraMin : ''), { headers: authHeaders() });
    var d = await r.json();
    document.getElementById('nr-times-loading').style.display = 'none';
    var tg = document.getElementById('nr-times-grid');
    if (d.blokovano) {
      tg.innerHTML = '<p style="font-size:12px;color:#f59e0b;grid-column:1/-1">⚠️ Den je blokován — admin může přesto rezervovat.</p>';
    } else if (!d.volne_casy || !d.volne_casy.length) {
      tg.innerHTML = '<p style="font-size:12px;color:#9ca3af;grid-column:1/-1">Žádné volné časy — zadejte vlastní čas níže.</p>';
    } else {
      d.volne_casy.forEach(function(t) {
        var el = document.createElement('div');
        el.style.cssText = 'border:1.5px solid #e9d5ff;border-radius:8px;padding:7px 4px;text-align:center;font-size:12px;cursor:pointer;transition:all .15s';
        el.textContent = t;
        el.onclick = function() {
          document.querySelectorAll('#nr-times-grid div').forEach(function(s){ s.style.background=''; s.style.color=''; s.style.borderColor='#e9d5ff'; });
          el.style.background = '#9333ea'; el.style.color = '#fff'; el.style.borderColor = '#9333ea';
          nrVybranyCas = t;
          document.getElementById('nr-cas-manual').value = t;
        };
        tg.appendChild(el);
      });
    }
  } catch(e) {
    document.getElementById('nr-times-loading').style.display = 'none';
  }
}

function nrManualCas() {
  nrVybranyCas = document.getElementById('nr-cas-manual').value;
  document.querySelectorAll('#nr-times-grid div').forEach(function(s){ s.style.background=''; s.style.color=''; s.style.borderColor='#e9d5ff'; });
}

async function ulozitNovuRez() {
  var alertEl = document.getElementById('nova-rez-alert');
  alertEl.style.display = 'none';
  var sluzbaId = document.getElementById('nr-sluzba').value;
  var datum    = document.getElementById('nr-datum').value;
  var cas      = nrVybranyCas || document.getElementById('nr-cas-manual').value;
  var jmeno    = document.getElementById('nr-jmeno').value.trim();
  var prijmeni = document.getElementById('nr-prijmeni').value.trim();
  var email    = document.getElementById('nr-email').value.trim();

  if (!sluzbaId || !datum || !cas || !jmeno || !prijmeni || !email) {
    alertEl.className = 'alert error'; alertEl.textContent = 'Vyplňte všechna povinná pole.'; alertEl.style.display = 'block'; return;
  }

  var btn = document.getElementById('nr-btn-ulozit');
  btn.disabled = true; btn.textContent = 'Ukládám…';

  try {
    var r = await fetch(API + '/rezervace/admin', {
      method: 'POST',
      headers: authHeaders(),
      body: JSON.stringify({
        sluzba_id: sluzbaId, datum: datum, cas: cas,
        jmeno: jmeno, prijmeni: prijmeni, email: email,
        telefon: document.getElementById('nr-telefon').value.trim(),
        poznamka: document.getElementById('nr-poznamka').value.trim(),
        admin_override: true,
        doplnky: Array.from(document.querySelectorAll('.nr-doplnek-check:checked')).map(function(ch){ return parseInt(ch.dataset.id); })
      })
    });
    var d = await r.json();
    if (d.ok) {
      alertEl.className = 'alert success'; alertEl.textContent = '✅ Rezervace vytvořena!'; alertEl.style.display = 'block';
      setTimeout(function(){ closeModal('modal-nova-rez'); resetNovaRez(); loadDnes(); loadMesicData(); }, 1500);
    } else {
      alertEl.className = 'alert error'; alertEl.textContent = d.error || 'Chyba při ukládání.'; alertEl.style.display = 'block';
    }
  } catch(e) {
    alertEl.className = 'alert error'; alertEl.textContent = 'Chyba připojení.'; alertEl.style.display = 'block';
  }
  btn.disabled = false; btn.textContent = 'Uložit';
}

function resetNovaRez() {
  ['nr-sluzba','nr-datum','nr-jmeno','nr-prijmeni','nr-email','nr-telefon','nr-poznamka','nr-cas-manual'].forEach(function(id){
    var el = document.getElementById(id); if (el) el.value = '';
  });
  document.getElementById('nr-times-wrap').style.display = 'none';
  document.getElementById('nr-times-grid').innerHTML = '';
  document.getElementById('nr-doplnky-wrap').style.display = 'none';
  document.getElementById('nr-doplnky-grid').innerHTML = '';
  document.getElementById('nova-rez-alert').style.display = 'none';
  nrVybranyCas = ''; nrSluzbaTrvani = 0; nrDoplnkyExtraMin = 0;
}

function resetHesloForm() {
  ['heslo-stare','heslo-nove','heslo-potvrzeni'].forEach(function(id){ document.getElementById(id).value = ''; });
  document.getElementById('heslo-alert').style.display = 'none';
}

// --- Správa uživatelů ---
var _prihlasenyUzivatel = '';

async function loadUzivatele() {
  try {
    var r = await fetch(API + '/uzivatele', { headers: authHeaders() });
    if (r.status === 403) return; // Demo účet - nezobrazovat
    var d = await r.json();
    if (!d.ok) return;
    // Zobraz kartu pouze pro admin
    document.getElementById('card-uzivatele').style.display = 'block';
    var el = document.getElementById('uzivatele-list');
    el.innerHTML = d.data.map(function(u) {
      return '<div class="set-row" id="uzivatel-row-' + u.id + '">'
        + '<div><div class="set-label">' + esc(u.uzivatelske_jmeno) + '</div>'
        + '<div class="set-sub">' + (u.zmena_hesla_zakaz ? '🔒 Změna hesla zakázána' : '🔓 Může měnit heslo') + '</div></div>'
        + '<button class="btn-sm btn-detail" onclick="openZmenaHeslaUzivatele(' + u.id + ',&quot;' + esc(u.uzivatelske_jmeno) + '&quot;)">Změnit heslo</button>'
        + '</div>';
    }).join('');
  } catch(e) {}
}

function openZmenaHeslaUzivatele(id, jmeno) {
  document.getElementById('uzivatel-heslo-id').value = id;
  document.getElementById('uzivatel-heslo-jmeno').textContent = jmeno;
  document.getElementById('uzivatel-heslo-input').value = '';
  document.getElementById('uzivatel-heslo-alert').style.display = 'none';
  openModal('modal-uzivatel-heslo');
}

async function ulozitHesloUzivatele() {
  var id    = document.getElementById('uzivatel-heslo-id').value;
  var heslo = document.getElementById('uzivatel-heslo-input').value;
  var alertEl = document.getElementById('uzivatel-heslo-alert');
  alertEl.style.display = 'none';
  if (heslo.length < 8) {
    alertEl.className = 'alert error'; alertEl.textContent = 'Heslo musí mít alespoň 8 znaků.'; alertEl.style.display = 'block'; return;
  }
  try {
    var r = await fetch(API + '/uzivatele/' + id, {
      method: 'PUT', headers: authHeaders(),
      body: JSON.stringify({ nove_heslo: heslo })
    });
    var d = await r.json();
    if (d.ok) {
      closeModal('modal-uzivatel-heslo');
      showToast('✅ Heslo bylo změněno.');
    } else {
      alertEl.className = 'alert error'; alertEl.textContent = d.error || 'Chyba.'; alertEl.style.display = 'block';
    }
  } catch(e) {
    alertEl.className = 'alert error'; alertEl.textContent = 'Chyba připojení.'; alertEl.style.display = 'block';
  }
}
</script>
<!-- MODAL: Výběr zákazníka z kartotéky -->
<div class="modal-overlay" id="modal-kartotek-pick" style="z-index:200">
  <div class="modal-sheet" style="max-height:80vh">
    <div class="modal-handle"></div>
    <div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:14px">
      <div class="modal-title" style="margin-bottom:0">Vybrat z kartotéky</div>
      <button class="btn-modal-discard" style="padding:6px 14px;font-size:13px" onclick="closeModal('modal-kartotek-pick')">Zavřít</button>
    </div>
    <input class="modal-input" type="search" id="kpick-search" placeholder="🔍 Hledat jméno nebo e-mail…" oninput="kpickSearch(this.value)" style="margin-bottom:8px">
    <div id="kpick-results" style="max-height:50vh;overflow-y:auto">
      <div class="empty">Začněte psát pro vyhledání</div>
    </div>
  </div>
</div>

<!-- MODAL: Detail zákazníka -->
<div class="modal-overlay" id="modal-zak">
  <div class="modal-sheet" style="max-height:92vh">
    <div class="modal-handle"></div>
    <div class="modal-title">Karta zákazníka</div>
    <input type="hidden" id="modal-zak-id">
    <input type="hidden" id="modal-zak-stitky">
    <div id="modal-zak-content"></div>
    <div class="btn-row" style="margin-top:12px">
      <button class="btn-modal-discard" onclick="closeModal('modal-zak')">Zavřít</button>
      <button class="btn-modal-discard" style="background:#fee2e2;color:#991b1b" onclick="smazatZakModal()">🗑 Smazat</button>
      <button class="btn-modal-save" onclick="saveZakaznik()">Uložit</button>
    </div>
  </div>
</div>

<!-- MODAL: Nová rezervace (admin) -->
<div class="modal-overlay" id="modal-nova-rez">
  <div class="modal-sheet" style="max-height:92vh">
    <div class="modal-handle"></div>
    <div class="modal-title">Nová rezervace</div>
    <div id="nova-rez-alert" class="alert" style="display:none"></div>
    <label class="modal-label">Služba *</label>
    <select class="modal-input" id="nr-sluzba" onchange="nrSluzbaChange()" style="margin-bottom:10px">
      <option value="">— vyberte —</option>
    </select>
    <div id="nr-doplnky-wrap" style="display:none;margin-bottom:10px">
      <label class="modal-label">Doplňkové služby</label>
      <div id="nr-doplnky-grid" style="background:#faf5ff;border-radius:8px;padding:8px 10px"></div>
    </div>
    <label class="modal-label">Datum *</label>
    <input class="modal-input" type="date" id="nr-datum" min="" onchange="nrDatumChange()">
    <div id="nr-times-wrap" style="display:none;margin-bottom:10px">
      <label class="modal-label">Čas *</label>
      <div id="nr-times-loading" style="font-size:13px;color:#9ca3af;padding:6px 0">Načítám časy…</div>
    <div style="font-size:11px;color:#9ca3af;margin-bottom:6px">Zobrazeny jsou volné časy zákazníků. Jako admin můžete zadat libovolný čas níže.</div>
      <div style="display:grid;grid-template-columns:repeat(4,1fr);gap:6px" id="nr-times-grid"></div>
      <div style="margin-top:6px">
        <label class="modal-label">Nebo zadat vlastní čas</label>
        <input class="modal-input" type="time" id="nr-cas-manual" style="margin-bottom:0" oninput="nrManualCas()">
      </div>
    </div>
    <button type="button" class="btn-add" style="margin-bottom:10px;width:100%;justify-content:center;padding:9px" onclick="openModal('modal-kartotek-pick')">👥 Vybrat z kartotéky</button>
    <label class="modal-label">Jméno *</label>
    <input class="modal-input" type="text" id="nr-jmeno" placeholder="Jana">
    <label class="modal-label">Příjmení *</label>
    <input class="modal-input" type="text" id="nr-prijmeni" placeholder="Nováková">
    <label class="modal-label">E-mail *</label>
    <input class="modal-input" type="email" id="nr-email" placeholder="jana@email.cz">
    <label class="modal-label">Telefon</label>
    <input class="modal-input" type="tel" id="nr-telefon" placeholder="+420 123 456 789">
    <label class="modal-label">Poznámka</label>
    <input class="modal-input" type="text" id="nr-poznamka" placeholder="Volitelná poznámka">
    <div class="btn-row">
      <button class="btn-modal-discard" onclick="closeModal('modal-nova-rez');resetNovaRez()">Zrušit</button>
      <button class="btn-modal-save" id="nr-btn-ulozit" onclick="ulozitNovuRez()">Uložit</button>
    </div>
  </div>
</div>

<!-- MODAL: Změna hesla -->
<div class="modal-overlay" id="modal-heslo">
  <div class="modal-sheet">
    <div class="modal-handle"></div>
    <div class="modal-title">Změna hesla</div>
    <div id="heslo-alert" class="alert" style="display:none"></div>
    <label class="modal-label">Stávající heslo</label>
    <input class="modal-input" type="password" id="heslo-stare" placeholder="••••••••">
    <label class="modal-label">Nové heslo (min. 8 znaků)</label>
    <input class="modal-input" type="password" id="heslo-nove" placeholder="••••••••">
    <label class="modal-label">Potvrzení nového hesla</label>
    <input class="modal-input" type="password" id="heslo-potvrzeni" placeholder="••••••••">
    <div class="btn-row">
      <button class="btn-modal-discard" onclick="closeModal('modal-heslo');resetHesloForm()">Zrušit</button>
      <button class="btn-modal-save" onclick="changeHeslo()">Uložit heslo</button>
    </div>
  </div>
</div>

<script src="https://cdn.jsdelivr.net/npm/sortablejs@1.15.2/Sortable.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/qrcodejs@1.0.0/qrcode.min.js"></script>
<!-- MODAL: Zrušení rezervace s důvodem -->
<div class="modal-overlay" id="modal-zruseni">
  <div class="modal-sheet">
    <div class="modal-handle"></div>
    <div class="modal-title">Zrušit rezervaci</div>
    <div id="zruseni-alert" class="alert error" style="display:none"></div>
    <input type="hidden" id="zruseni-rez-id">
    <label class="modal-label">Důvod zrušení (volitelné)</label>
    <textarea class="modal-input" id="zruseni-duvod" placeholder="Např. kapacitní důvody, nemoc, technická závada…" style="height:90px;resize:none;line-height:1.5"></textarea>
    <div style="font-size:12px;color:#9ca3af;margin-bottom:12px">Důvod bude uveden v e-mailu zákazníkovi. Pokud nevyplníte, zákazník dostane pouze oznámení o zrušení.</div>
    <div class="btn-row">
      <button class="btn-modal-discard" onclick="closeModal('modal-zruseni')">Zpět</button>
      <button class="btn-modal-save" id="zruseni-save-btn" style="background:#991b1b" onclick="provestZruseni()">Zrušit rezervaci</button>
    </div>
  </div>
</div>

<!-- MODAL: Změna hesla uživatele (admin) -->
<div class="modal-overlay" id="modal-uzivatel-heslo">
  <div class="modal-sheet">
    <div class="modal-handle"></div>
    <div class="modal-title">Změna hesla — <span id="uzivatel-heslo-jmeno"></span></div>
    <input type="hidden" id="uzivatel-heslo-id">
    <div id="uzivatel-heslo-alert" class="alert" style="display:none"></div>
    <label class="modal-label">Nové heslo (min. 8 znaků)</label>
    <input class="modal-input" type="password" id="uzivatel-heslo-input" placeholder="••••••••">
    <div class="btn-row">
      <button class="btn-modal-discard" onclick="closeModal('modal-uzivatel-heslo')">Zrušit</button>
      <button class="btn-modal-save" onclick="ulozitHesloUzivatele()">Uložit heslo</button>
    </div>
  </div>
</div>

<!-- MODAL: Doplněk služby -->
<div class="modal-overlay" id="modal-doplnek">
  <div class="modal-sheet">
    <div class="modal-handle"></div>
    <div class="modal-title" id="modal-doplnek-title">Nový doplněk</div>
    <input type="hidden" id="doplnek-sluzba-id">
    <input type="hidden" id="doplnek-id">
    <div id="doplnek-alert" class="alert" style="display:none"></div>
    <label class="modal-label">Název doplňku *</label>
    <input class="modal-input" id="doplnek-nazev" placeholder="Mytí vlasů">
    <div style="display:grid;grid-template-columns:1fr 1fr;gap:10px">
      <div>
        <label class="modal-label">Cena (Kč)</label>
        <input class="modal-input" type="number" id="doplnek-cena" placeholder="40" min="0">
      </div>
      <div>
        <label class="modal-label">Čas navíc (min)</label>
        <input class="modal-input" type="number" id="doplnek-min" placeholder="10" min="0">
      </div>
    </div>
    <div class="btn-row">
      <button class="btn-modal-discard" onclick="closeModal('modal-doplnek')">Zrušit</button>
      <button class="btn-modal-save" onclick="saveDoplnek()">Uložit</button>
    </div>
  </div>
</div>

<!-- MODAL: Úprava termínu rezervace -->
<div class="modal-overlay" id="modal-uprav-termin">
  <div class="modal-sheet">
    <div class="modal-handle"></div>
    <div class="modal-title">Upravit termín</div>
    <input type="hidden" id="ut-rez-id">
    <div style="font-size:13px;color:#6b7280;margin-bottom:12px">Služba: <strong id="ut-sluzba-nazev"></strong></div>
    <div id="ut-alert" class="alert" style="display:none"></div>
    <label class="modal-label">Nové datum *</label>
    <input class="modal-input" type="date" id="ut-datum" onchange="utDatumChange()">
    <div id="ut-times-wrap" style="display:none;margin-bottom:10px">
      <label class="modal-label">Volné časy</label>
      <div id="ut-times-loading" style="font-size:13px;color:#9ca3af;padding:6px 0">Načítám časy…</div>
      <div style="font-size:11px;color:#9ca3af;margin-bottom:6px">Jako admin můžete zadat libovolný čas ručně.</div>
      <div style="display:grid;grid-template-columns:repeat(4,1fr);gap:6px" id="ut-times-grid"></div>
    </div>
    <label class="modal-label">Čas *</label>
    <input class="modal-input" type="time" id="ut-cas-manual">
    <div style="font-size:11px;color:#9ca3af;margin-bottom:12px">Zákazník dostane e-mail s novým termínem.</div>
    <div class="btn-row">
      <button class="btn-modal-discard" onclick="closeModal('modal-uprav-termin')">Zrušit</button>
      <button class="btn-modal-save" id="ut-btn-ulozit" onclick="ulozitUpravTermin()">Uložit termín</button>
    </div>
  </div>
</div>

</body>
</html>

Youez - 2016 - github.com/yon3zu
LinuXploit