C:\TripServer\TripForm\index.html
<!DOCTYPE html>
<html lang="he" dir="rtl">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<meta name="theme-color" content="#0f172a">
<title>טופס קליטת טיול חדש — סוכן הטיולים של איתן v4</title>
<style>
:root{
--ink:#0f172a;--muted:#475569;--bg:#f4f7fb;--card:#fff;--line:rgba(15,23,42,.13);
--teal:#0f766e;--blue:#2563eb;--purple:#7c3aed;--orange:#f97316;--green:#166534;--red:#dc2626;--gold:#f59e0b;
--shadow:0 14px 36px rgba(15,23,42,.08);
--radius:24px;
}
*{box-sizing:border-box}
html{scroll-behavior:smooth;-webkit-text-size-adjust:100%;text-size-adjust:100%;overflow-x:hidden}
body{
margin:0;direction:rtl;color:var(--ink);font-family:Arial,"Noto Sans Hebrew","Segoe UI",sans-serif;
font-size:16px;line-height:1.65;background:
radial-gradient(circle at 92% 0%,rgba(20,184,166,.14),transparent 30rem),
radial-gradient(circle at 0% 0%,rgba(124,58,237,.12),transparent 28rem),
linear-gradient(180deg,#f8fafc 0%,#eef6f8 55%,#f8fafc 100%);
}
a{color:var(--teal);font-weight:900}
.wrap{width:100%;max-width:1180px;margin:0 auto;padding:22px 14px 90px}
header{
position:relative;overflow:hidden;color:#fff;border-radius:34px;padding:30px 22px;margin:10px 0 16px;
background:linear-gradient(135deg,#020617 0%,#0f172a 42%,#0f766e 100%);
box-shadow:0 24px 56px rgba(15,23,42,.25)
}
header:before{content:"";position:absolute;inset:0;background:radial-gradient(circle at top right,rgba(56,189,248,.25),transparent 24rem),radial-gradient(circle at bottom left,rgba(249,115,22,.18),transparent 22rem);pointer-events:none}
header>*{position:relative;z-index:1}
.badge{display:inline-flex;gap:7px;align-items:center;justify-content:center;min-height:34px;padding:7px 12px;border-radius:999px;background:#dcfce7;color:#166534;font-weight:950;font-size:13px;margin-bottom:12px}
h1{margin:0 0 10px;font-size:clamp(30px,7vw,52px);line-height:1.12;letter-spacing:-.4px}
.subtitle{font-size:clamp(16px,3.8vw,22px);font-weight:850;opacity:.95;max-width:920px}
.hero-grid,.score-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:12px;margin-top:20px}
.hero-card,.score-card{
background:rgba(255,255,255,.12);border:1px solid rgba(255,255,255,.18);border-radius:20px;padding:14px;backdrop-filter:blur(8px);font-weight:900
}
.hero-card .label,.score-card .label{font-size:12px;opacity:.78;margin-bottom:4px}
.hero-card .value,.score-card .value{font-size:clamp(18px,4vw,24px);font-weight:950}
.card,.section-nav,.summary-panel{
background:linear-gradient(180deg,#ffffff,#f8fafc);border:1px solid var(--line);border-radius:var(--radius);
padding:20px 16px;margin:18px 0;box-shadow:var(--shadow);overflow:hidden
}
.section-nav{position:sticky;top:0;z-index:10;background:linear-gradient(145deg,#020617,#0f172a);padding:12px;border-radius:0 0 22px 22px;margin:0 -14px 18px}
.nav-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(136px,1fr));gap:8px}
.nav-grid a,.action-btn,.mini-btn{
display:inline-flex;align-items:center;justify-content:center;text-align:center;min-height:42px;padding:9px 12px;border:0;border-radius:16px;
color:#fff;text-decoration:none;font-family:inherit;font-weight:950;line-height:1.22;cursor:pointer;background:linear-gradient(135deg,#0f766e,#2563eb);
box-shadow:0 7px 16px rgba(15,23,42,.16)
}
.nav-grid a:nth-child(3n+1){background:linear-gradient(135deg,#7c3aed,#2563eb)}
.nav-grid a:nth-child(3n+2){background:linear-gradient(135deg,#14b8a6,#0f766e)}
.nav-grid a:nth-child(3n+3){background:linear-gradient(135deg,#fb923c,#ea580c)}
h2{font-size:clamp(24px,5.8vw,34px);line-height:1.25;margin:0 0 12px;color:#0f4f57}
h2:after{content:"";display:block;width:112px;height:5px;border-radius:999px;margin-top:8px;background:linear-gradient(90deg,#0f766e,#38bdf8,#f59e0b)}
h3{font-size:clamp(19px,4.6vw,24px);color:var(--teal);margin:20px 0 8px}
.note,.warn,.ok,.gold{
border-radius:16px;padding:12px 14px;margin:12px 0;font-weight:850;line-height:1.55
}
.note{background:#eff6ff;border:1px solid #bfdbfe;color:#1e3a8a}
.warn{background:#fff7ed;border:1px solid #fed7aa;color:#7c2d12}
.ok{background:#ecfdf5;border:1px solid #a7f3d0;color:#14532d}
.gold{background:#fef3c7;border:1px solid #facc15;color:#78350f}
.form-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px}
.field{display:flex;flex-direction:column;gap:5px;min-width:0}
.field.full{grid-column:1/-1}
label{font-weight:950;color:#0f172a}
small{color:var(--muted);font-weight:750;line-height:1.4}
input,select,textarea{
width:100%;min-height:44px;border:1px solid rgba(15,23,42,.18);border-radius:14px;padding:10px 12px;
font:inherit;font-size:15px;background:#fff;color:var(--ink);outline:none
}
textarea{min-height:92px;resize:vertical}
input:focus,select:focus,textarea:focus{border-color:#38bdf8;box-shadow:0 0 0 4px rgba(56,189,248,.18)}
.check-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(210px,1fr));gap:8px;margin-top:8px}
.check-item{display:flex;gap:8px;align-items:flex-start;background:#f8fafc;border:1px solid rgba(15,23,42,.10);border-radius:14px;padding:10px;font-weight:850}
.check-item input{width:22px;min-height:22px;height:22px;margin-top:2px}
.repeater{border:1px solid rgba(15,23,42,.12);border-radius:18px;background:#fff;margin:14px 0;padding:12px}
.repeater-head{display:flex;justify-content:space-between;align-items:center;gap:10px;margin-bottom:10px}
.repeater-title{font-size:18px;font-weight:950;color:#0f172a}
.rows{display:grid;gap:10px}
.row{
position:relative;display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:8px;border:1px solid #dbeafe;border-radius:16px;background:#f8fafc;padding:12px
}
.row .wide{grid-column:span 2}
.row .full{grid-column:1/-1}
.remove-btn{position:absolute;top:8px;left:8px;background:linear-gradient(135deg,#ef4444,#b91c1c);min-height:34px;padding:6px 10px;border-radius:999px}
.action-bar{display:flex;flex-wrap:wrap;gap:10px;margin-top:14px}
.action-btn.secondary{background:linear-gradient(135deg,#64748b,#334155)}
.action-btn.danger{background:linear-gradient(135deg,#ef4444,#b91c1c)}
.action-btn.gold-btn{background:linear-gradient(135deg,#f59e0b,#ea580c)}
.progress-wrap{background:#e2e8f0;border-radius:999px;overflow:hidden;height:14px;margin:10px 0}
.progress-bar{height:100%;width:0%;background:linear-gradient(90deg,#ef4444,#f59e0b,#22c55e);transition:width .25s ease}
#missingList{padding-right:20px;margin:8px 0}
#missingList li{margin:6px 0}
.preview{white-space:pre-wrap;background:#020617;color:#e5e7eb;border-radius:18px;padding:14px;direction:rtl;text-align:right;max-height:420px;overflow:auto;font-family:Consolas,Menlo,monospace;font-size:13px}
.pill{display:inline-flex;align-items:center;justify-content:center;padding:5px 10px;border-radius:999px;background:#eef2ff;color:#312e81;font-weight:950;font-size:12px;margin:3px}
.footer-floating{
position:fixed;right:10px;left:10px;bottom:calc(8px + env(safe-area-inset-bottom,0px));z-index:999;
display:grid;grid-template-columns:repeat(4,1fr);gap:8px;max-width:880px;margin:auto;padding:8px;border-radius:22px;
background:rgba(2,6,23,.92);backdrop-filter:blur(10px);box-shadow:0 18px 44px rgba(0,0,0,.35)
}
.footer-floating button{min-height:42px;border-radius:16px;font-size:13px;padding:8px}
.reference-list{display:grid;grid-template-columns:repeat(auto-fit,minmax(230px,1fr));gap:10px}
.reference-card{background:#fff;border:1px solid rgba(15,23,42,.11);border-radius:18px;padding:13px;box-shadow:0 5px 18px rgba(15,23,42,.05)}
.reference-card b{display:block;color:#0f4f57;margin-bottom:5px}
@media(max-width:760px){
.wrap{padding:14px 10px 110px} header{border-radius:26px;padding:24px 16px}
.section-nav{position:static;margin:0 0 14px;border-radius:22px}
.nav-grid{grid-template-columns:1fr 1fr}
.form-grid{grid-template-columns:1fr}
.row{grid-template-columns:1fr}
.row .wide,.row .full{grid-column:1/-1}
.card{padding:16px 12px;border-radius:20px}
.footer-floating{grid-template-columns:1fr 1fr}
}
@media(max-width:390px){.nav-grid{grid-template-columns:1fr}.footer-floating{grid-template-columns:1fr}.footer-floating button{min-height:38px}}
@media print{.section-nav,.footer-floating,.action-bar,.mini-btn,.remove-btn{display:none!important}body{background:#fff}.card,header{box-shadow:none;break-inside:avoid}}
</style>
</head>
<body>
<div class="wrap" id="top">
<header>
<div class="badge">🧭 סוכן הטיולים של איתן · v3 Gold Reference</div>
<h1>טופס קליטת טיול חדש</h1>
<div class="subtitle">ממלאים פעם אחת את נתוני הפתיחה — והסוכן מקבל מקור אמת שמספיק לבניית קובץ HTML ברמת יפן/ארה״ב ומעלה: לוגיקה, תקציב, ימים, מובייל, מצב הסתר, נספחים, קישורים וגרסאות סופיות.</div>
<div class="hero-grid">
<div class="hero-card"><div class="label">סטנדרט ייחוס</div><div class="value">יפן 2026 + ארה״ב 2027</div></div>
<div class="hero-card"><div class="label">תוצר יעד</div><div class="value">HTML פרימיום + בדיקות איתן</div></div>
<div class="hero-card"><div class="label">ייצוא</div><div class="value">JSON / TXT / HTML ממולא</div></div>
<div class="hero-card"><div class="label">שמירה</div><div class="value">שמירה מקומית בדפדפן</div></div>
</div>
</header>
<section class="section-nav">
<div class="nav-grid">
<a href="#readiness">מוכנות</a>
<a href="#gold">סטנדרט זהב</a>
<a href="#basics">בסיס הטיול</a>
<a href="#people">משתתפים</a>
<a href="#route">מסלול ולינות</a>
<a href="#flights">טיסות ותחבורה</a>
<a href="#content">חובה / לא לשלב</a>
<a href="#parks">פארקים וכרטיסים</a>
<a href="#budget">תקציב</a>
<a href="#food">אוכל</a>
<a href="#design">עיצוב וקובץ</a>
<a href="#deliver">בדיקות וייצוא</a>
</div>
</section>
<section class="summary-panel" id="readiness">
<h2>מד מוכנות לסוכן</h2>
<div class="score-grid">
<div class="score-card" style="background:linear-gradient(135deg,#312e81,#2563eb);color:#fff"><div class="label">ציון מוכנות</div><div class="value" id="scoreText">0%</div></div>
<div class="score-card"><div class="label">ימים / לילות</div><div class="value" id="durationText">—</div></div>
<div class="score-card"><div class="label">רמת קובץ</div><div class="value" id="levelText">—</div></div>
<div class="score-card"><div class="label">מצב מקור אמת</div><div class="value" id="sourceTruthText">חסר</div></div>
</div>
<div class="progress-wrap"><div class="progress-bar" id="progressBar"></div></div>
<div class="note">המטרה אינה רק “למלא טופס”, אלא לתת לסוכן מספיק מידע כדי לא לנחש: מה קשיח, מה גמיש, מה כבר שולם, מה חובה, מה אסור, איזה עיצוב לשמר, ואילו בדיקות חייבות לעבור.</div>
<h3>מה עדיין חסר</h3>
<ul id="missingList"></ul>
</section>
<section class="card" id="gold">
<h2>סטנדרט זהב מקבצי יפן וארה״ב</h2>
<div class="reference-list">
<div class="reference-card"><b>מבנה חובה</b>Hero פתיחה, נתוני טיול, תוכן עניינים, חלקי מסלול, כרטיסי יום, תקציב, נספחים תפעוליים.</div>
<div class="reference-card"><b>יום טיול</b>כותרת, תאריך, סיכום, לוז, תקציב יום, קישורי ניווט, נקודות מרכזיות, אוכל, טיפים, תוכנית גיבוי.</div>
<div class="reference-card"><b>מובייל</b>RTL מלא, בלי גלילה אופקית, כפתורים גדולים, מצב הסתר/מובייל, פתיחה תקינה באייפון.</div>
<div class="reference-card"><b>תקציב</b>מנוע דינמי, עריכה, prepaid, מטבעות, שער עדכני, הפרדה בין קניות/לוז/שולם מראש.</div>
<div class="reference-card"><b>תפעול</b>מזוודות, דד־ליינים, תוכניות גיבוי, חירום, מזג אוויר, עומסים, החלטות משפחתיות.</div>
<div class="reference-card"><b>מסירה סופית</b>שתי גרסאות בלבד: Netlify ושרת פרטי, בלי גרסאות מיותרות ובלי שכבות Legacy.</div>
</div>
<div class="warn">חשוב: קובץ ייחוס לא אומר להעתיק עיוור. המטרה היא לשמר את הרמה, המבנה, המנגנונים והעיצוב — אבל לבנות נקי יותר, עם מקור אמת מרכזי יותר ופחות כפילויות.</div>
<div class="form-grid">
<div class="field">
<label>איזה קובץ ייחוס מתאים יותר לטיול החדש?</label>
<select data-path="reference.primaryStyle">
<option value="">בחר</option>
<option>יפן — טיול עירוני/תחבורה ציבורית/רב־עירוני</option>
<option>ארה״ב — Road Trip/פארקים/קרוז/רכב</option>
<option>שילוב יפן + ארה״ב</option>
<option>לבנות וריאציה חדשה, אבל לפי אותו סטנדרט</option>
</select>
</div>
<div class="field">
<label>רמת נאמנות לעיצוב הקיים</label>
<select data-path="reference.designFaithfulness">
<option value="">בחר</option>
<option>גבוהה מאוד — לשמר כמעט הכול</option>
<option>גבוהה — לשמר מבנה ושפה, לשפר ניקיון</option>
<option>בינונית — לקחת השראה, לבנות חדש</option>
</select>
</div>
<div class="field full">
<label>מה חייבים לשמר מקבצי יפן/ארה״ב?</label>
<textarea data-path="reference.keep" placeholder="לדוגמה: מצב הסתר, מסך טעינה, תוכן עניינים צבעוני, טבלאות תקציב, כפתורי ניווט, כרטיסי יום, נספחים..."></textarea>
</div>
<div class="field full">
<label>מה לשפר ביחס לקבצים הישנים?</label>
<textarea data-path="reference.improve" placeholder="לדוגמה: פחות כפילויות, מקור אמת אחד, קובץ קל יותר, תמונות דחוסות, פחות שכבות CSS ישנות, תקציב אחיד יותר..."></textarea>
</div>
</div>
</section>
<section class="card" id="basics">
<h2>1. בסיס הטיול</h2>
<div class="form-grid">
<div class="field"><label>יעד / מדינה / אזור</label><input data-path="basics.destination" placeholder="לדוגמה: הולנד / איטליה / תאילנד"></div>
<div class="field"><label>שם פנימי לטיול</label><input data-path="basics.tripName" placeholder="לדוגמה: הולנד 2027 משפחתי"></div>
<div class="field"><label>תאריך התחלה</label><input type="date" data-path="basics.startDate"></div>
<div class="field"><label>תאריך סיום</label><input type="date" data-path="basics.endDate"></div>
<div class="field"><label>סטטוס</label><select data-path="basics.status"><option value="">בחר</option><option>רעיון ראשוני</option><option>בודק כדאיות</option><option>תאריכים סגורים</option><option>טיסות הוזמנו</option><option>חלק מהדברים הוזמנו</option></select></div>
<div class="field"><label>מטרת העבודה</label><select data-path="basics.goal"><option value="">בחר</option><option>תכנון ראשוני בלבד</option><option>שלד מסלול</option><option>השוואת חלופות</option><option>קובץ HTML מלא</option><option>קובץ סופי עם בדיקות איתן</option></select></div>
<div class="field full"><label>רקע חופשי</label><textarea data-path="basics.freeNotes" placeholder="כל דבר שחשוב לדעת לפני שמתחילים: למה היעד, מה החלום, מה הרגישויות, מה הסגנון..."></textarea></div>
</div>
</section>
<section class="card" id="people">
<h2>2. משתתפים וקצב משפחתי</h2>
<div class="repeater" data-repeater="participants">
<div class="repeater-head"><div class="repeater-title">משתתפים</div><button class="mini-btn" type="button" data-add="participants">+ הוסף משתתף</button></div>
<div class="rows"></div>
</div>
<div class="form-grid">
<div class="field"><label>קצב טיול רצוי</label><select data-path="people.pace"><option value="">בחר</option><option>רגוע מאוד</option><option>מאוזן</option><option>עמוס אבל הגיוני</option><option>מקסימום הספק</option></select></div>
<div class="field"><label>שעת יציאה מועדפת בבוקר</label><input data-path="people.startTimePreference" placeholder="לדוגמה: 09:30–10:00"></div>
<div class="field"><label>שעת חזרה מועדפת למלון</label><input data-path="people.returnTimePreference" placeholder="לדוגמה: עד 22:30"></div>
<div class="field"><label>כמה מסעדות/עצירות אוכל כבדות ביום?</label><select data-path="people.foodLoad"><option value="">בחר</option><option>עד אחת</option><option>עד שתיים</option><option>לא משנה</option></select></div>
<div class="field full"><label>מגבלות / רגישויות / עומס / הליכה</label><textarea data-path="people.constraints" placeholder="לדוגמה: לא יותר מדי הליכה רצופה, רגישות לחום, ילדים אוהבים מתקנים, לא אוהבים מוזיאונים כבדים..."></textarea></div>
</div>
</section>
<section class="card" id="route">
<h2>3. מסלול, אזורים ולינות</h2>
<div class="form-grid">
<div class="field"><label>סגנון מסלול</label><select data-path="route.routeType"><option value="">בחר</option><option>עיר אחת כבסיס</option><option>שתי ערים</option><option>רב־עירוני</option><option>Road Trip</option><option>קרוז + יבשה</option><option>פתוח להמלצה</option></select></div>
<div class="field"><label>כמה מעברי מלון מקסימום?</label><input data-path="route.maxHotelMoves" placeholder="לדוגמה: עד 3"></div>
<div class="field"><label>רמת מלונות</label><select data-path="route.hotelLevel"><option value="">בחר</option><option>חסכוני טוב</option><option>ביניים איכותי</option><option>פרימיום</option><option>מלון עם יתרון תפעולי חשוב</option></select></div>
<div class="field"><label>חדרים</label><input data-path="route.rooms" placeholder="לדוגמה: חדר משפחתי / 2 חדרים / סוויטה"></div>
<div class="field full"><label>העדפות לינה</label><textarea data-path="route.hotelPreferences" placeholder="מיקום, חניה, כביסה, מטבחון, קרבה לרכבת/פארק, נוף, Premier/Express, שליחת מזוודות וכו׳"></textarea></div>
</div>
<div class="repeater" data-repeater="stays">
<div class="repeater-head"><div class="repeater-title">אזורים / לינות מתוכננות</div><button class="mini-btn" type="button" data-add="stays">+ הוסף אזור/לינה</button></div>
<div class="rows"></div>
</div>
</section>
<section class="card" id="flights">
<h2>4. טיסות, רכב ותחבורה</h2>
<div class="form-grid">
<div class="field"><label>טיסות</label><select data-path="transport.flightStatus"><option value="">בחר</option><option>אין עדיין</option><option>יש אופציות</option><option>הוזמן</option><option>צריך המלצה</option></select></div>
<div class="field"><label>תחבורה מרכזית</label><select data-path="transport.mainMode"><option value="">בחר</option><option>תחבורה ציבורית</option><option>רכב שכור</option><option>שילוב</option><option>קרוז</option><option>פתוח להמלצה</option></select></div>
<div class="field"><label>מגבלת נהיגה יומית</label><input data-path="transport.maxDrivePerDay" placeholder="לדוגמה: עד 4 שעות, חריגים עד 6"></div>
<div class="field"><label>מזוודות</label><input data-path="transport.luggage" placeholder="לדוגמה: 4 טרולי + 2 מזוודות גדולות"></div>
<div class="field full"><label>כללי תחבורה חשובים</label><textarea data-path="transport.rules" placeholder="רכב חובה/אסור, חניה, כבישי אגרה, רכבות, שינוע מזוודות, החזרת רכב, שאטלים, מעבורות..."></textarea></div>
</div>
<div class="repeater" data-repeater="flights">
<div class="repeater-head"><div class="repeater-title">טיסות / מקטעים</div><button class="mini-btn" type="button" data-add="flights">+ הוסף טיסה/מקטע</button></div>
<div class="rows"></div>
</div>
<div class="repeater" data-repeater="transportSegments">
<div class="repeater-head"><div class="repeater-title">מקטעי תחבורה יבשתיים חשובים</div><button class="mini-btn" type="button" data-add="transportSegments">+ הוסף מקטע</button></div>
<div class="rows"></div>
</div>
</section>
<section class="card" id="content">
<h2>5. תוכן חובה, לא לשלב ואילוצי ימים</h2>
<div class="repeater" data-repeater="mustPlaces">
<div class="repeater-head"><div class="repeater-title">אטרקציות / מקומות חובה</div><button class="mini-btn" type="button" data-add="mustPlaces">+ הוסף מקום</button></div>
<div class="rows"></div>
</div>
<div class="repeater" data-repeater="hardConstraints">
<div class="repeater-head"><div class="repeater-title">אילוצי ימים קשיחים</div><button class="mini-btn" type="button" data-add="hardConstraints">+ הוסף אילוץ</button></div>
<div class="rows"></div>
</div>
<div class="form-grid">
<div class="field full"><label>לא לשלב / לא מעניין / להימנע</label><textarea data-path="content.noGo" placeholder="לדוגמה: לא מוזיאונים כבדים, לא ימי קניות ארוכים, לא נסיעות לילה, לא פארקים מסוימים..."></textarea></div>
<div class="field full"><label>חלומות / העדפות פתוחות</label><textarea data-path="content.wishlist" placeholder="דברים שכיף לשלב אם מסתדר, אבל לא חובה."></textarea></div>
</div>
</section>
<section class="card" id="parks">
<h2>6. פארקים, כרטיסים, Priority / Express</h2>
<div class="form-grid">
<div class="field"><label>האם הטיול כולל פארקי שעשועים/מים?</label><select data-path="parks.hasParks"><option value="">בחר</option><option>כן</option><option>לא</option><option>אולי</option></select></div>
<div class="field"><label>גישה לכרטיסי דילוג/Express</label><select data-path="parks.expressApproach"><option value="">בחר</option><option>חובה כשאפשר</option><option>רק למתקנים מרכזיים</option><option>לפי מחיר</option><option>לא רלוונטי</option></select></div>
<div class="field full"><label>אסטרטגיית פארקים כללית</label><textarea data-path="parks.strategyNotes" placeholder="מתקנים חובה, מתקני אקסטרים, סימולטורים, ילדים, מים, הפסקות, פארק ביום גשם, שעות פתיחה, Priority וכו׳"></textarea></div>
</div>
<div class="repeater" data-repeater="parksList">
<div class="repeater-head"><div class="repeater-title">פארקים / ימים מיוחדים</div><button class="mini-btn" type="button" data-add="parksList">+ הוסף פארק</button></div>
<div class="rows"></div>
</div>
</section>
<section class="card" id="budget">
<h2>7. תקציב, prepaid, מטבעות ושערים</h2>
<div class="form-grid">
<div class="field"><label>תקציב כולל</label><input type="number" data-path="budget.total" placeholder="לדוגמה: 45000"></div>
<div class="field"><label>מטבע תקציב ראשי</label><select data-path="budget.primaryCurrency"><option value="">בחר</option><option>ILS</option><option>USD</option><option>EUR</option><option>JPY</option><option>GBP</option></select></div>
<div class="field"><label>תקציב קניות נפרד</label><input type="number" data-path="budget.shopping" placeholder="לדוגמה: 10000"></div>
<div class="field"><label>תקציב אוכל יומי</label><input data-path="budget.dailyFood" placeholder="לדוגמה: 260$ למשפחה / 800₪"></div>
<div class="field"><label>רזרבה / בלת״ם</label><input data-path="budget.reserve" placeholder="לדוגמה: 10% / 5000₪"></div>
<div class="field"><label>שער תכנון</label><input data-path="budget.planningRate" placeholder="לדוגמה: 1$=3.75₪"></div>
<div class="field full"><label>מה התקציב כולל ומה לא?</label><textarea data-path="budget.scope" placeholder="טיסות, מלונות, רכב, ביטוח, קרוז, אוכל, קניות, אטרקציות, שולם מראש, לא נספר פעמיים..."></textarea></div>
</div>
<div class="repeater" data-repeater="prepaid">
<div class="repeater-head"><div class="repeater-title">שולם מראש / הוזמן / חייב לא להיספר פעמיים</div><button class="mini-btn" type="button" data-add="prepaid">+ הוסף שורה</button></div>
<div class="rows"></div>
</div>
</section>
<section class="card" id="food">
<h2>8. אוכל, מסעדות והעדפות</h2>
<div class="form-grid">
<div class="field"><label>סגנון אוכל</label><input data-path="food.style" placeholder="לדוגמה: משפחתי, סושי, בשר, מסעדות קלילות, שווקים"></div>
<div class="field"><label>הגבלות מזון</label><input data-path="food.restrictions" placeholder="כשרות/אלרגיות/לא אוכלים..."></div>
<div class="field full"><label>כללי אוכל יומיים</label><textarea data-path="food.rules" placeholder="לא יותר משתי מסעדות כבדות, איפה חייבים להזמין, אוכל ליד פארקים, ארוחות בוקר במלון וכו׳"></textarea></div>
</div>
<div class="repeater" data-repeater="restaurants">
<div class="repeater-head"><div class="repeater-title">מסעדות / אוכל חובה / אופציות</div><button class="mini-btn" type="button" data-add="restaurants">+ הוסף מסעדה</button></div>
<div class="rows"></div>
</div>
</section>
<section class="card" id="design">
<h2>9. עיצוב, מנגנונים וקובץ HTML</h2>
<div class="check-grid">
<label class="check-item"><input type="checkbox" data-path="design.hero">Hero פתיחה פרימיום</label>
<label class="check-item"><input type="checkbox" data-path="design.loader">מסך טעינה מלא + דילוג מקומי</label>
<label class="check-item"><input type="checkbox" data-path="design.toc">תוכן עניינים יומי צבעוני</label>
<label class="check-item"><input type="checkbox" data-path="design.currentDay">כפתור קפיצה ליום נוכחי</label>
<label class="check-item"><input type="checkbox" data-path="design.hideMode">מצב הסתר/מובייל</label>
<label class="check-item"><input type="checkbox" data-path="design.editMode">מצב עריכת תקציב</label>
<label class="check-item"><input type="checkbox" data-path="design.smartSearch">חיפוש חכם בתוך הקובץ</label>
<label class="check-item"><input type="checkbox" data-path="design.liveFx">שער מטבע עדכני מהרשת</label>
<label class="check-item"><input type="checkbox" data-path="design.maps">מפות/תמונות/קישורי ניווט</label>
<label class="check-item"><input type="checkbox" data-path="design.presentationButton">כפתור מצגת בראש הקובץ</label>
<label class="check-item"><input type="checkbox" data-path="design.appendices">נספחי תפעול בסוף</label>
</div>
<div class="form-grid">
<div class="field"><label>קישור אפליקציית תקציב — Netlify</label><input data-path="design.budgetNetlifyUrl" placeholder="https://..."></div>
<div class="field"><label>קישור אפליקציית תקציב — שרת פרטי</label><input data-path="design.budgetPrivateServerUrl" placeholder="http://... / https://..."></div>
<div class="field"><label>רמת קובץ מבוקשת</label><select data-path="design.outputLevel"><option value="">בחר</option><option>טיוטה נוחה לקריאה</option><option>קובץ מלא</option><option>קובץ סופי ברמת יפן/ארה״ב</option><option>יותר טוב מיפן/ארה״ב — מקור אמת אחד וניקוי כפילויות</option></select></div>
<div class="field"><label>משקל קובץ רצוי</label><select data-path="design.fileWeight"><option value="">בחר</option><option>לא חשוב</option><option>חשוב שיהיה קל ככל האפשר</option><option>עדיף איכות על משקל</option><option>לא לעבור גודל סביר לאייפון</option></select></div>
<div class="field full"><label>הערות עיצוב / UX</label><textarea data-path="design.notes" placeholder="צבעים, מבנה, אילו חלקים מהקבצים הישנים אהבת, מה הפריע, מה להבליט במובייל..."></textarea></div>
</div>
</section>
<section class="card" id="presentation">
<h2>10. מצגת טיול מסונכרנת</h2>
<div class="check-grid">
<label class="check-item"><input type="checkbox" data-path="presentation.enabled"> להפיק מצגת HTML תואמת לקובץ הטיול</label>
<label class="check-item"><input type="checkbox" data-path="presentation.linkFromTripHero"> כפתור מצגת בראש ההירו, גלוי בלי גלילה</label>
<label class="check-item"><input type="checkbox" data-path="presentation.dailySlides"> שקף לכל יום/תחנת טיול לפי הלו״ז</label>
<label class="check-item"><input type="checkbox" data-path="presentation.imagesMatchItinerary"> תמונות/קישורי תמונות חייבים להתאים ליום וללוז</label>
<label class="check-item"><input type="checkbox" data-path="presentation.summaryTextPerDay"> מלל קצר ומסכם לכל יום, לא עומס טקסט</label>
<label class="check-item"><input type="checkbox" data-path="presentation.musicEnabled"> לכלול שיר/מוזיקה למצגת</label>
<label class="check-item"><input type="checkbox" data-path="presentation.audioSync"> סנכרון משך המצגת למשך השיר</label>
<label class="check-item"><input type="checkbox" data-path="presentation.localFirstImages"> תמונות Local First עם fallback לרשת</label>
<label class="check-item"><input type="checkbox" data-path="presentation.adminPanelSupport"> הפאנל החכם חייב לכלול העלאת מצגת/תמונות/שיר</label>
<label class="check-item"><input type="checkbox" data-path="presentation.cleanFinalNoWorkNotes"> מצגת וקובץ טיול ללא הסברי תיקונים/עדכונים</label>
</div>
<div class="form-grid">
<div class="field"><label>קוד תיקייה/Route בשרת</label><input data-path="presentation.tripCode" placeholder="לדוגמה: USA / JAPAN / EUROPE_2028"></div>
<div class="field"><label>שם קובץ מצגת בשרת</label><input data-path="presentation.presentationFilename" placeholder="לדוגמה: trip-presentation.html / usa2027-presentation.html"></div>
<div class="field"><label>נתיב תמונות למצגת</label><input data-path="presentation.imagesFolder" placeholder="media/trip-presentation/images"></div>
<div class="field"><label>שם קובץ שיר</label><input data-path="presentation.musicFilename" placeholder="לדוגמה: trip-theme.mp3"></div>
<div class="field"><label>סגנון מוזיקה</label><input data-path="presentation.musicStyle" placeholder="מרגש / משפחתי / כביש אמריקאי / יפן / טבע / קצבי"></div>
<div class="field"><label>מקור השיר</label><select data-path="presentation.musicSource"><option value="">בחר</option><option>המשתמש יעלה MP3</option><option>לבקש המלצת שיר/מקור חופשי</option><option>בלי שיר כרגע, להשאיר מנגנון מוכן</option></select></div>
<div class="field"><label>מבנה שקפים רצוי</label><select data-path="presentation.slideStructure"><option value="">בחר</option><option>Intro + תקציב + שקף לכל יום + סיכום</option><option>רק ימי טיול מרכזיים</option><option>שקפים לפי אזורים ולא לפי ימים</option><option>להחליט לפי הלוז והאופי של הטיול</option></select></div>
<div class="field"><label>יחס תצוגה</label><select data-path="presentation.aspectRatio"><option value="">בחר</option><option>16:9 פרימיום</option><option>מותאם מובייל קודם</option><option>גם 16:9 וגם מובייל</option></select></div>
<div class="field full"><label>הוראות למצגת</label><textarea data-path="presentation.notes" placeholder="אווירה רצויה, מה להבליט, מה לא להראות, טון כתיבה, תמונות חובה, סיום, כפתור חזרה לקובץ הטיול וכו׳"></textarea></div>
</div>
</section>
<section class="card" id="deliver">
<h2>11. בדיקות איתן, מסירה וסיכום</h2>
<div class="check-grid">
<label class="check-item"><input type="checkbox" data-path="tests.level1">בדיקות רמה 1 — קוד/מבנה</label>
<label class="check-item"><input type="checkbox" data-path="tests.level2">בדיקות רמה 2 — DOM/לוגיקה/תקציב</label>
<label class="check-item"><input type="checkbox" data-path="tests.level3">בדיקות רמה 3 — Chromium/Playwright מובייל</label>
<label class="check-item"><input type="checkbox" data-path="tests.noHorizontalScroll">בדיקת אין גלילה אופקית</label>
<label class="check-item"><input type="checkbox" data-path="tests.links">בדיקת קישורים/עוגנים/onClick</label>
<label class="check-item"><input type="checkbox" data-path="tests.budget">בדיקת תקציב/prepaid/מטבעות</label>
<label class="check-item"><input type="checkbox" data-path="tests.contentDup">בדיקת כפילויות תוכן</label>
<label class="check-item"><input type="checkbox" data-path="tests.iphone">בדיקת מובייל 390×844</label>
</div>
<div class="form-grid">
<div class="field"><label>סוג מסירה</label><select data-path="deliver.mode"><option value="">בחר</option><option>תכנון בצ׳אט בלבד</option><option>מקור אמת JSON בלבד</option><option>HTML אחד לבדיקה</option><option>שתי גרסאות סופיות בלבד — Netlify ושרת פרטי</option></select></div>
<div class="field"><label>האם להפיק דוח בדיקות נפרד?</label><select data-path="deliver.testReport"><option value="">בחר</option><option>לא, פירוט בצ׳אט בלבד</option><option>כן, לצרף דוח נפרד</option></select></div>
<div class="field full"><label>הערות אחרונות לסוכן לפני התחלה</label><textarea data-path="deliver.finalInstructions" placeholder="הוראות קשיחות, דברים לא לשנות, מה לבדוק במיוחד, מה נחשב הצלחה..."></textarea></div>
</div>
<div class="action-bar">
<button class="action-btn" type="button" id="saveBtn">💾 שמירה מקומית</button>
<button class="action-btn gold-btn" type="button" id="exportJsonBtn">📦 יצוא JSON להעלאה</button>
<button class="action-btn" type="button" id="exportTxtBtn">📝 יצוא TXT מסודר</button>
<button class="action-btn" type="button" id="exportHtmlBtn">🌐 יצוא HTML ממולא</button>
<button class="action-btn secondary" type="button" id="copySummaryBtn">📋 העתק סיכום לצ׳אט</button>
<button class="action-btn danger" type="button" id="clearBtn">🧹 ניקוי הטופס</button>
</div>
<div class="field full" style="margin-top:14px">
<label>ייבוא JSON קודם</label>
<input type="file" id="importJsonInput" accept="application/json,.json">
<small>מאפשר לפתוח מחדש טיול שכבר מילאת ולעדכן אותו.</small>
</div>
<h3>תצוגת סיכום לסוכן</h3>
<div class="preview" id="summaryPreview"></div>
</section>
</div>
<div class="footer-floating" aria-label="פעולות מהירות">
<button class="action-btn" type="button" onclick="document.getElementById('saveBtn').click()">💾 שמור</button>
<button class="action-btn gold-btn" type="button" onclick="document.getElementById('exportJsonBtn').click()">📦 JSON</button>
<button class="action-btn secondary" type="button" onclick="location.hash='readiness'">📊 מוכנות</button>
<button class="action-btn danger" type="button" onclick="location.hash='top'">⬆️ למעלה</button>
</div>
<script>
(function(){
'use strict';
const STORAGE_KEY = 'eitan_trip_intake_v4_trip_and_presentation';
function lsGet(key){ try{return window.localStorage.getItem(key);}catch(e){return null;} }
function lsSet(key,value){ try{window.localStorage.setItem(key,value);return true;}catch(e){return false;} }
function lsRemove(key){ try{window.localStorage.removeItem(key);return true;}catch(e){return false;} }
const GENERATED_AT = '2026-06-27';
const referenceProfile = {
gold_files_used:[
'טיול יפן 2026 מחשב.html',
'טיול ארצות הברית 2027 מחשב.html'
],
extracted_standard:{
rtl:true,
mobile_first:true,
premium_hero:true,
daily_toc:true,
day_cards:true,
dynamic_budget:true,
edit_mode:true,
hide_mode:true,
loader:true,
local_skip_loader:true,
live_fx:true,
budget_app_links:true,
route_maps:true,
operational_appendices:true,
linked_trip_presentation:true,
presentation_images_music:true,
smart_admin_panel_media:true,
eitan_tests:true,
final_versions:['Netlify','שרת פרטי']
}
};
const repeaters = {
participants:{
empty:{name:'',role:'',age:'',interests:'',constraints:''},
fields:[
['name','שם','לדוגמה: איתן'],
['role','תפקיד/קרבה','מבוגר / ילד / בן זוג'],
['age','גיל בזמן הטיול',''],
['interests','תחומי עניין','מתקנים, שופינג, אוכל, טבע...'],
['constraints','מגבלות/רגישויות','הליכה, אוכל, פחד גבהים...','full']
]
},
stays:{
empty:{area:'',nights:'',hotelStatus:'',hotelName:'',mustReasons:'',notes:''},
fields:[
['area','אזור/עיר','אמסטרדם / אורלנדו / טוקיו'],
['nights','לילות','3'],
['hotelStatus','סטטוס מלון','אין / יש אופציות / הוזמן'],
['hotelName','שם מלון אם ידוע',''],
['mustReasons','למה האזור/מלון חשוב','קרוב לפארק / רכבת / חניה','wide'],
['notes','הערות','חדרים, חניה, מזוודות, כביסה...','full']
]
},
flights:{
empty:{direction:'',date:'',from:'',to:'',time:'',airline:'',status:'',notes:''},
fields:[
['direction','כיוון','הלוך / חזור / פנימי'],
['date','תאריך',''],
['from','מוצא','TLV'],
['to','יעד','AMS'],
['time','שעה',''],
['airline','חברה/מספר טיסה',''],
['status','סטטוס','נבדק / הוזמן / פתוח'],
['notes','הערות','כבודה, מושבים, נחיתה מאוחרת...','full']
]
},
transportSegments:{
empty:{from:'',to:'',dateOrDay:'',mode:'',durationLimit:'',bookingStatus:'',notes:''},
fields:[
['from','מ־',''],
['to','אל',''],
['dateOrDay','תאריך/יום',''],
['mode','אמצעי','רכב / רכבת / טיסה / שאטל'],
['durationLimit','מגבלה','עד 4 שעות נהיגה'],
['bookingStatus','סטטוס','פתוח / הוזמן'],
['notes','הערות','חניה, אגרה, מזוודות, כבישים...','full']
]
},
mustPlaces:{
empty:{name:'',city:'',type:'',priority:'',fixedDate:'',prepaid:'',links:'',notes:''},
fields:[
['name','שם מקום/אטרקציה',''],
['city','אזור/עיר',''],
['type','סוג','פארק / מוזיאון / שוק / טבע'],
['priority','עדיפות','חובה / חשוב / אופציה'],
['fixedDate','תאריך קשיח אם יש',''],
['prepaid','שולם/צריך להזמין','שולם / להזמין / לא'],
['links','קישורים','אתר/מפות/כרטיסים','wide'],
['notes','הערות לסוכן','שעות, עומסים, מי רוצה, למה חשוב','full']
]
},
hardConstraints:{
empty:{dateOrDay:'',constraint:'',reason:'',flexibility:''},
fields:[
['dateOrDay','תאריך/יום',''],
['constraint','האילוץ','USJ ביום 10 / קרוז בשבת'],
['reason','סיבה','הזמנה / מחיר / לוגיסטיקה'],
['flexibility','גמישות','קשיח / אפשר להזיז / לבדיקה']
]
},
parksList:{
empty:{name:'',date:'',tickets:'',express:'',mustRides:'',avoid:'',notes:''},
fields:[
['name','שם פארק',''],
['date','תאריך/יום',''],
['tickets','כרטיסים','אין / הוזמן / צריך המלצה'],
['express','Express/Priority','חובה / אולי / לא'],
['mustRides','מתקנים חובה','רשימה','wide'],
['avoid','לא מעניין','מתקנים/אזורים לוותר','wide'],
['notes','אסטרטגיה','פתיחה, עומסים, גשם, הפסקות','full']
]
},
prepaid:{
empty:{item:'',category:'',amount:'',currency:'',paid:'',date:'',proof:'',notes:''},
fields:[
['item','פריט','טיסות / מלון / כרטיסים'],
['category','קטגוריה','טיסות / מלונות / אטרקציות'],
['amount','סכום',''],
['currency','מטבע','ILS/USD/EUR/JPY'],
['paid','סטטוס','שולם / הוזמן / פיקדון'],
['date','תאריך תשלום',''],
['proof','אסמכתא/קישור',''],
['notes','הערות','לא לספור פעמיים / כלול בתקציב','full']
]
},
restaurants:{
empty:{name:'',city:'',type:'',priority:'',reservation:'',link:'',notes:''},
fields:[
['name','שם',''],
['city','עיר/אזור',''],
['type','סוג','בשר / סושי / שוק / מתוק'],
['priority','עדיפות','חובה / אופציה'],
['reservation','הזמנה','צריך / לא / הוזמן'],
['link','קישור',''],
['notes','הערות','מתי לשלב, רמת עומס, מחיר','full']
]
}
};
function emptyData(){
return {
meta:{schema:'EitanTripIntakeV4TripAndPresentation', generatedAt:GENERATED_AT, referenceProfile},
reference:{primaryStyle:'',designFaithfulness:'',keep:'',improve:''},
basics:{destination:'',tripName:'',startDate:'',endDate:'',status:'',goal:'',freeNotes:''},
people:{pace:'',startTimePreference:'',returnTimePreference:'',foodLoad:'',constraints:''},
route:{routeType:'',maxHotelMoves:'',hotelLevel:'',rooms:'',hotelPreferences:''},
transport:{flightStatus:'',mainMode:'',maxDrivePerDay:'',luggage:'',rules:''},
content:{noGo:'',wishlist:''},
parks:{hasParks:'',expressApproach:'',strategyNotes:''},
budget:{total:'',primaryCurrency:'',shopping:'',dailyFood:'',reserve:'',planningRate:'',scope:''},
food:{style:'',restrictions:'',rules:''},
design:{hero:true,loader:true,toc:true,currentDay:true,hideMode:true,editMode:true,smartSearch:true,liveFx:true,maps:true,presentationButton:true,appendices:true,budgetNetlifyUrl:'',budgetPrivateServerUrl:'',outputLevel:'',fileWeight:'',notes:''},
presentation:{enabled:true,linkFromTripHero:true,dailySlides:true,imagesMatchItinerary:true,summaryTextPerDay:true,musicEnabled:true,audioSync:true,localFirstImages:true,adminPanelSupport:true,cleanFinalNoWorkNotes:true,tripCode:'',presentationFilename:'trip-presentation.html',imagesFolder:'media/trip-presentation/images',musicFilename:'trip-theme.mp3',musicStyle:'',musicSource:'',slideStructure:'Intro + תקציב + שקף לכל יום + סיכום',aspectRatio:'גם 16:9 וגם מובייל',notes:''},
tests:{level1:true,level2:true,level3:true,noHorizontalScroll:true,links:true,budget:true,contentDup:true,iphone:true},
deliver:{mode:'',testReport:'לא, פירוט בצ׳אט בלבד',finalInstructions:''},
participants:[
{name:'איתן',role:'מבוגר',age:'',interests:'תכנון, תקציב, לוגיקה, איכות קובץ',constraints:''},
{name:'קרין',role:'מבוגרת',age:'',interests:'',constraints:''},
{name:'עידו',role:'ילד/נער',age:'',interests:'',constraints:''},
{name:'מיכאל',role:'ילד',age:'',interests:'',constraints:''}
],
stays:[], flights:[], transportSegments:[], mustPlaces:[], hardConstraints:[], parksList:[], prepaid:[], restaurants:[]
};
}
let data = emptyData();
function getPath(obj,path){
return path.split('.').reduce((o,k)=>o && o[k], obj);
}
function setPath(obj,path,value){
const parts=path.split('.');
let cur=obj;
for(let i=0;i<parts.length-1;i++){
if(!cur[parts[i]] || typeof cur[parts[i]]!=='object') cur[parts[i]]={};
cur=cur[parts[i]];
}
cur[parts[parts.length-1]]=value;
}
function rowField(field,rowIndex,listName,value){
const [key,label,placeholder,cls]=field;
const wrap=document.createElement('div');
wrap.className='field '+(cls||'');
const id=`${listName}_${rowIndex}_${key}`;
wrap.innerHTML=`<label for="${id}">${label}</label><input id="${id}" data-list="${listName}" data-row="${rowIndex}" data-key="${key}" placeholder="${placeholder||''}">`;
wrap.querySelector('input').value=value||'';
return wrap;
}
function renderRepeater(listName){
const cfg=repeaters[listName];
const root=document.querySelector(`[data-repeater="${listName}"] .rows`);
if(!root) return;
root.innerHTML='';
const arr=Array.isArray(data[listName])?data[listName]:[];
arr.forEach((row,idx)=>{
const div=document.createElement('div');
div.className='row';
div.dataset.list=listName;
div.dataset.row=idx;
const remove=document.createElement('button');
remove.type='button';
remove.className='mini-btn remove-btn';
remove.textContent='מחק';
remove.addEventListener('click',()=>{
data[listName].splice(idx,1);
renderRepeater(listName);
syncInputsFromData();
updateAll();
});
div.appendChild(remove);
cfg.fields.forEach(f=>div.appendChild(rowField(f,idx,listName,row[f[0]])));
root.appendChild(div);
});
}
function renderAllRepeaters(){ Object.keys(repeaters).forEach(renderRepeater); }
function syncInputsFromData(){
document.querySelectorAll('[data-path]').forEach(el=>{
const val=getPath(data,el.dataset.path);
if(el.type==='checkbox') el.checked=!!val;
else el.value=val ?? '';
});
}
function collectFromDom(){
document.querySelectorAll('[data-path]').forEach(el=>{
setPath(data,el.dataset.path, el.type==='checkbox' ? el.checked : el.value);
});
Object.keys(repeaters).forEach(list=>{
const rows=[];
const rowEls=[...document.querySelectorAll(`.row[data-list="${list}"]`)];
rowEls.forEach(rowEl=>{
const obj={};
rowEl.querySelectorAll('[data-key]').forEach(inp=>obj[inp.dataset.key]=inp.value);
rows.push(obj);
});
data[list]=rows;
});
data.meta.updatedAt=new Date().toISOString();
data.meta.referenceProfile=referenceProfile;
return data;
}
function save(){
collectFromDom();
lsSet(STORAGE_KEY, JSON.stringify(data));
updateAll();
}
function load(){
const raw=lsGet(STORAGE_KEY);
if(raw){
try{ data = Object.assign(emptyData(), JSON.parse(raw)); }
catch(e){ data=emptyData(); }
} else data=emptyData();
// deep defaults for missing objects
const def=emptyData();
data={...def,...data};
['meta','reference','basics','people','route','transport','content','parks','budget','food','design','presentation','tests','deliver'].forEach(k=>data[k]={...def[k],...(data[k]||{})});
Object.keys(repeaters).forEach(k=>{ if(!Array.isArray(data[k])) data[k]=def[k]||[]; });
renderAllRepeaters();
syncInputsFromData();
updateAll();
}
function duration(){
const s=data.basics.startDate, e=data.basics.endDate;
if(!s || !e) return null;
const sd=new Date(s+'T00:00:00'), ed=new Date(e+'T00:00:00');
if(isNaN(sd)||isNaN(ed)||ed<sd) return null;
const days=Math.round((ed-sd)/(1000*60*60*24))+1;
return {days,nights:Math.max(0,days-1)};
}
function missingChecks(){
collectFromDom();
const m=[];
function need(condition,text){ if(!condition) m.push(text); }
need(data.basics.destination,'יעד הטיול');
need(data.basics.startDate && data.basics.endDate,'תאריכי התחלה וסיום');
need(data.basics.goal,'מטרת העבודה / רמת התוצר');
need(data.reference.primaryStyle,'בחירת קובץ/סגנון ייחוס');
need(data.reference.designFaithfulness,'רמת נאמנות לעיצוב הישן');
need((data.participants||[]).some(p=>p.name),'לפחות משתתף אחד');
need(data.people.pace,'קצב טיול רצוי');
need(data.route.routeType,'סוג מסלול/אופי חלוקת אזורים');
need(data.transport.mainMode,'תחבורה מרכזית');
need(data.budget.total && data.budget.primaryCurrency,'תקציב כולל ומטבע');
need(data.budget.scope,'מה התקציב כולל ומה לא');
need((data.mustPlaces||[]).some(x=>x.name) || data.content.wishlist,'מקומות חובה או לפחות Wishlist');
need(data.content.noGo,'מה לא לשלב / ממה להימנע');
need(data.design.outputLevel,'רמת קובץ HTML מבוקשת');
need(data.presentation.enabled,'החלטה/אישור להפקת מצגת טיול מסונכרנת');
if(data.presentation.enabled){
need(data.presentation.presentationFilename,'שם קובץ מצגת בשרת');
need(data.presentation.imagesFolder,'נתיב תמונות למצגת');
need(data.presentation.musicFilename || data.presentation.musicSource,'שיר/מוזיקה למצגת או החלטה להשאיר מנגנון מוכן');
need(data.presentation.adminPanelSupport,'אישור שהפאנל החכם יכלול מצגת/תמונות/שיר');
}
need(data.deliver.mode,'סוג מסירה סופית');
need(data.design.budgetNetlifyUrl || data.design.budgetPrivateServerUrl,'קישור לאפליקציית תקציב או החלטה שאין עדיין');
need(data.tests.level1 && data.tests.level2,'אישור בדיקות איתן רמה 1+2');
return m;
}
function score(){
const total=22;
const miss=missingChecks().length;
return Math.max(0,Math.round((total-miss)/total*100));
}
function summaryText(){
collectFromDom();
const dur=duration();
const lines=[];
lines.push('פתח טיול חדש לפי סוכן הטיולים של איתן — v4 Trip + Presentation Reference');
lines.push('');
lines.push('מקור ייחוס: '+(data.reference.primaryStyle||'לא צוין'));
lines.push('רמת נאמנות לעיצוב: '+(data.reference.designFaithfulness||'לא צוין'));
lines.push('יעד: '+(data.basics.destination||''));
lines.push('שם טיול: '+(data.basics.tripName||''));
lines.push('תאריכים: '+(data.basics.startDate||'')+' עד '+(data.basics.endDate||'')+(dur?` (${dur.days} ימים / ${dur.nights} לילות)`:''));
lines.push('מטרה: '+(data.basics.goal||''));
lines.push('סטטוס: '+(data.basics.status||''));
lines.push('');
lines.push('משתתפים:');
(data.participants||[]).filter(p=>p.name).forEach(p=>lines.push(`- ${p.name} | ${p.role||''} | גיל: ${p.age||''} | עניין: ${p.interests||''} | מגבלות: ${p.constraints||''}`));
lines.push('');
lines.push('קצב וכללים:');
lines.push('- קצב: '+(data.people.pace||''));
lines.push('- יציאה בבוקר: '+(data.people.startTimePreference||''));
lines.push('- חזרה למלון: '+(data.people.returnTimePreference||''));
lines.push('- מגבלות: '+(data.people.constraints||''));
lines.push('');
lines.push('מסלול ולינות:');
lines.push('- סוג מסלול: '+(data.route.routeType||''));
lines.push('- מעברי מלון מקסימום: '+(data.route.maxHotelMoves||''));
lines.push('- רמת מלונות: '+(data.route.hotelLevel||''));
lines.push('- חדרים: '+(data.route.rooms||''));
(data.stays||[]).filter(x=>x.area||x.hotelName).forEach(x=>lines.push(`- ${x.area||''}: ${x.nights||''} לילות | ${x.hotelStatus||''} | ${x.hotelName||''} | ${x.notes||''}`));
lines.push('');
lines.push('תחבורה:');
lines.push('- טיסות: '+(data.transport.flightStatus||''));
lines.push('- אמצעי מרכזי: '+(data.transport.mainMode||''));
lines.push('- מגבלת נהיגה: '+(data.transport.maxDrivePerDay||''));
lines.push('- מזוודות: '+(data.transport.luggage||''));
lines.push('');
lines.push('חובה לשלב:');
(data.mustPlaces||[]).filter(x=>x.name).forEach(x=>lines.push(`- ${x.name} | ${x.city||''} | ${x.priority||''} | תאריך: ${x.fixedDate||''} | ${x.notes||''}`));
lines.push('');
lines.push('לא לשלב: '+(data.content.noGo||''));
lines.push('Wishlist: '+(data.content.wishlist||''));
lines.push('');
lines.push('תקציב:');
lines.push(`- כולל: ${data.budget.total||''} ${data.budget.primaryCurrency||''}`);
lines.push('- קניות: '+(data.budget.shopping||''));
lines.push('- אוכל יומי: '+(data.budget.dailyFood||''));
lines.push('- רזרבה: '+(data.budget.reserve||''));
lines.push('- שער תכנון: '+(data.budget.planningRate||''));
lines.push('- כולל/לא כולל: '+(data.budget.scope||''));
lines.push('');
lines.push('Prepaid / הוזמן:');
(data.prepaid||[]).filter(x=>x.item).forEach(x=>lines.push(`- ${x.item} | ${x.category||''} | ${x.amount||''} ${x.currency||''} | ${x.paid||''} | ${x.notes||''}`));
lines.push('');
lines.push('אוכל:');
lines.push('- סגנון: '+(data.food.style||''));
lines.push('- הגבלות: '+(data.food.restrictions||''));
lines.push('- כללים: '+(data.food.rules||''));
lines.push('');
lines.push('מצגת טיול:');
lines.push('- להפיק מצגת: '+(data.presentation.enabled?'כן':'לא'));
lines.push('- כפתור מצגת בראש ההירו: '+(data.presentation.linkFromTripHero?'כן':'לא'));
lines.push('- מבנה שקפים: '+(data.presentation.slideStructure||''));
lines.push('- קוד תיקייה/Route: '+(data.presentation.tripCode||''));
lines.push('- קובץ מצגת: '+(data.presentation.presentationFilename||''));
lines.push('- נתיב תמונות: '+(data.presentation.imagesFolder||''));
lines.push('- שיר/קובץ מוזיקה: '+(data.presentation.musicFilename||''));
lines.push('- סגנון מוזיקה: '+(data.presentation.musicStyle||''));
lines.push('- מקור השיר: '+(data.presentation.musicSource||''));
lines.push('- תמונות תואמות לוז: '+(data.presentation.imagesMatchItinerary?'כן':'לא'));
lines.push('- סנכרון לשיר: '+(data.presentation.audioSync?'כן':'לא'));
lines.push('- תמיכה בפאנל חכם: '+(data.presentation.adminPanelSupport?'כן':'לא'));
lines.push('- הערות מצגת: '+(data.presentation.notes||''));
lines.push('');
lines.push('דרישות קובץ:');
lines.push('- רמת פלט: '+(data.design.outputLevel||''));
lines.push('- Netlify budget URL: '+(data.design.budgetNetlifyUrl||''));
lines.push('- Private budget URL: '+(data.design.budgetPrivateServerUrl||''));
lines.push('- מצב הסתר: '+(data.design.hideMode?'כן':'לא'));
lines.push('- עריכת תקציב: '+(data.design.editMode?'כן':'לא'));
lines.push('- שער חי: '+(data.design.liveFx?'כן':'לא'));
lines.push('- כפתור מצגת: '+(data.design.presentationButton?'כן':'לא'));
lines.push('- בדיקות איתן: '+Object.keys(data.tests).filter(k=>data.tests[k]).join(', '));
lines.push('- מסירה: '+(data.deliver.mode||''));
lines.push('');
lines.push('מה לשמר מהקבצים הישנים: '+(data.reference.keep||''));
lines.push('מה לשפר: '+(data.reference.improve||''));
lines.push('הוראות אחרונות: '+(data.deliver.finalInstructions||''));
return lines.join('\n');
}
function updateAll(){
collectFromDom();
const sc=score();
document.getElementById('scoreText').textContent=sc+'%';
document.getElementById('progressBar').style.width=sc+'%';
const dur=duration();
document.getElementById('durationText').textContent=dur?`${dur.days} ימים / ${dur.nights} לילות`:'—';
document.getElementById('levelText').textContent=data.design.outputLevel||data.basics.goal||'—';
document.getElementById('sourceTruthText').textContent=sc>=85?'מספיק להתחלה חזקה':(sc>=55?'בסיסי, חסרים פרטים':'חסר');
const ul=document.getElementById('missingList');
const miss=missingChecks();
ul.innerHTML=miss.length?miss.map(x=>`<li>${x}</li>`).join(''):'<li>אין חוסרים קריטיים. אפשר להעלות JSON ולהתחיל עבודה.</li>';
document.getElementById('summaryPreview').textContent=summaryText();
}
function download(filename,content,mime){
const blob=new Blob([content],{type:mime||'text/plain;charset=utf-8'});
const a=document.createElement('a');
a.href=URL.createObjectURL(blob); a.download=filename; document.body.appendChild(a); a.click();
setTimeout(()=>{URL.revokeObjectURL(a.href);a.remove();},200);
}
function safeName(){
const dest=(data.basics.destination||'trip').replace(/[^\u0590-\u05FFA-Za-z0-9_-]+/g,'_').replace(/^_+|_+$/g,'');
return dest || 'trip';
}
document.addEventListener('input', e=>{
if(e.target.matches('[data-path],[data-key]')){ collectFromDom(); updateAll(); lsSet(STORAGE_KEY, JSON.stringify(data)); }
});
document.addEventListener('change', e=>{
if(e.target.matches('[data-path],[data-key]')){ collectFromDom(); updateAll(); lsSet(STORAGE_KEY, JSON.stringify(data)); }
});
document.querySelectorAll('[data-add]').forEach(btn=>{
btn.addEventListener('click',()=>{
const list=btn.dataset.add;
collectFromDom();
data[list]=Array.isArray(data[list])?data[list]:[];
data[list].push({...repeaters[list].empty});
renderRepeater(list);
syncInputsFromData();
updateAll();
});
});
document.getElementById('saveBtn').addEventListener('click',()=>{save(); alert('נשמר מקומית בדפדפן.');});
document.getElementById('exportJsonBtn').addEventListener('click',()=>{
collectFromDom();
download(`Eitan_Trip_Intake_${safeName()}_v4.json`, JSON.stringify(data,null,2), 'application/json;charset=utf-8');
});
document.getElementById('exportTxtBtn').addEventListener('click',()=>{
download(`Eitan_Trip_Intake_${safeName()}_summary.txt`, summaryText(), 'text/plain;charset=utf-8');
});
document.getElementById('exportHtmlBtn').addEventListener('click',()=>{
save();
const html='<!DOCTYPE html>\n'+document.documentElement.outerHTML;
download(`Eitan_Trip_Intake_${safeName()}_filled.html`, html, 'text/html;charset=utf-8');
});
document.getElementById('copySummaryBtn').addEventListener('click',async()=>{
try{ await navigator.clipboard.writeText(summaryText()); alert('הסיכום הועתק.'); }
catch(e){ alert('לא הצלחתי להעתיק אוטומטית. אפשר לסמן ולהעתיק מהתצוגה למטה.'); }
});
document.getElementById('clearBtn').addEventListener('click',()=>{
if(confirm('למחוק את כל הנתונים שנשמרו בטופס הזה?')){
lsRemove(STORAGE_KEY); data=emptyData(); renderAllRepeaters(); syncInputsFromData(); updateAll();
}
});
document.getElementById('importJsonInput').addEventListener('change', async e=>{
const file=e.target.files && e.target.files[0];
if(!file) return;
try{
const txt=await file.text();
const imported=JSON.parse(txt);
data={...emptyData(),...imported};
renderAllRepeaters(); syncInputsFromData(); save(); updateAll();
alert('ה־JSON נטען לטופס.');
}catch(err){ alert('הקובץ לא נראה כמו JSON תקין.'); }
});
load();
})();
</script>
</body>
</html>