PageSourceSearch

https://indmart.ru/jobs

html indmart.ru collected 2026-09-24 15:10:48 UTC 61,488 bytes, 1,234 lines download raw bytes

1<!doctype html>
2<html lang="ru">
3<head>
4<meta charset="utf-8">
5<meta name="viewport" content="width=device-width, initial-scale=1">
6<title>Работа в пищевой промышленности — IndMart</title>
7<meta name="description" content="Вакансии и резюме в пищевой промышленности России. Пекари, технологи, механики, руководители пекарен и кондитерских.">
8<link rel="canonical" href="https://indmart.ru/jobs">
9<link rel="preconnect" href="https://fonts.googleapis.com">
10<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
11<link href="https://fonts.googleapis.com/css2?family=Montserrat:wght@700;800&family=Inter:wght@400;500;600&display=swap" rel="stylesheet">
12<style>
13:root {
14  --navy: #1B3A6B;
15  --navy-light: #254d8f;
16  --orange: #FF6B35;
17  --orange-dark: #e55a25;
18  --bg: #f8f9fc;
19  --card: #ffffff;
20  --border: #e0e4ef;
21  --text: #1a2236;
22  --muted: #8892a4;
23  --green: #059669;
24  --radius: 12px;
25}
26
27* { box-sizing: border-box; margin: 0; padding: 0; }
28body { font-family: 'Inter', sans-serif; background: var(--bg); color: var(--text); -webkit-font-smoothing: antialiased; }
29
30/* NAV */
31nav {
32  background: white;
33  border-bottom: 1px solid #eee;
34  height: 56px;
35  display: flex;
36  align-items: center;
37  justify-content: space-between;
38  padding: 0 24px;
39  position: sticky;
40  top: 0;
41  z-index: 200;
42}
43.nav-logo { font-family: 'Montserrat', sans-serif; font-weight: 800; font-size: 20px; color: var(--navy); text-decoration: none; }
44.nav-logo span { color: var(--orange); }
45.nav-links { display: flex; gap: 4px; }
46.nav-link { color: #555; text-decoration: none; font-size: 14px; padding: 6px 12px; border-radius: 6px; transition: all 0.15s; }
47.nav-link:hover, .nav-link.active { color: var(--navy); background: #f5f7ff; }
48.nav-right { display: flex; gap: 8px; align-items: center; }
49.btn-post { background: var(--orange); color: white; border: none; border-radius: 8px; padding: 8px 16px; font-size: 13px; font-weight: 600; cursor: pointer; font-family: inherit; transition: background 0.15s; }
50.btn-post:hover { background: var(--orange-dark); }
51.btn-login { background: white; color: var(--navy); border: 1px solid var(--border); border-radius: 8px; padding: 6px 14px; font-size: 13px; cursor: pointer; font-family: inherit; }
52
53/* HERO */
54.hero {
55  background: white;
56  padding: 40px 24px 0;
57  border-bottom: 1px solid var(--border);
58}
59.hero-inner { max-width: 1100px; margin: 0 auto; }
60.hero-top {
61  display: flex;
62  align-items: center;
63  justify-content: space-between;
64  margin-bottom: 24px;
65}
66.hero h1 {
67  font-family: 'Montserrat', sans-serif;
68  font-weight: 800;
69  font-size: clamp(22px, 3vw, 32px);
70  color: var(--navy);
71}
72.hero h1 span { color: var(--orange); }
73.hero-sub { font-size: 15px; color: var(--muted); margin-top: 4px; }
74
75/* FILTERS */
76.filters {
77  max-width: 1100px;
78  margin: 0 auto;
79  padding: 16px 0;
80  display: flex;
81  gap: 10px;
82  align-items: end;
83  flex-wrap: wrap;
84}
85.f-field { display: flex; flex-direction: column; gap: 4px; }
86.f-label { font-size: 11px; font-weight: 600; color: var(--muted); text-transform: uppercase; letter-spacing: 0.5px; }
87.f-input, .f-select {
88  height: 38px;
89  border: 1.5px solid var(--border);
90  border-radius: 8px;
91  padding: 0 12px;
92  font-size: 14px;
93  font-family: inherit;
94  color: var(--text);
95  background: white;
96  outline: none;
97  transition: border-color 0.15s;
98}
99.f-input:focus, .f-select:focus { border-color: var(--navy); }
100.f-field-search { flex: 1; min-width: 200px; }
101.f-field-industry { flex: 0 0 180px; }
102.f-field-city { flex: 0 0 140px; }
103.f-field-type { flex: 0 0 140px; }
104.btn-search {
105  height: 38px;
106  background: white;
107  color: var(--navy);
108  border: 2px solid var(--navy);
109  border-radius: 8px;
110  padding: 0 20px;
111  font-size: 14px;
112  font-weight: 600;
113  cursor: pointer;
114  font-family: inherit;
115  transition: all 0.15s;
116  white-space: nowrap;
117}
118.btn-search:hover { background: var(--navy); color: white; }
119
120/* GEO AUTOCOMPLETE */
121.geo-wrap { position: relative; }
122.geo-dropdown {
123  position: absolute;
124  top: 100%;
125  left: 0;
126  right: 0;
127  background: white;
128  border: 1.5px solid var(--border);
129  border-top: none;
130  border-radius: 0 0 8px 8px;
131  box-shadow: 0 8px 24px rgba(27,58,107,0.10);
132  z-index: 500;
133  max-height: 200px;
134  overflow-y: auto;
135  display: none;
136}
137.geo-dropdown.open { display: block; }
138.geo-option {
139  padding: 8px 12px;
140  font-size: 13px;
141  cursor: pointer;
142  color: var(--text);
143  border-bottom: 1px solid var(--bg);
144}
145.geo-option:hover, .geo-option.active { background: #f5f7ff; color: var(--navy); }
146
147/* TABS */
148.tabs-wrap {
149  max-width: 1100px;
150  margin: 0 auto;
151  padding: 0 0 0;
152  display: flex;
153  gap: 0;
154  border-top: 1px solid var(--border);
155}
156.tab-btn {
157  padding: 12px 20px;
158  font-size: 14px;
159  font-weight: 600;
160  cursor: pointer;
161  border: none;
162  background: none;
163  color: var(--muted);
164  font-family: inherit;
165  border-bottom: 2px solid transparent;
166  transition: all 0.15s;
167}
168.tab-btn.active { color: var(--navy); border-bottom-color: var(--navy); }
169.tab-btn:hover { color: var(--navy); }
170
171/* MAIN */
172.main { max-width: 1100px; margin: 0 auto; padding: 24px; }
173
174/* STATS */
175.stats-row {
176  display: flex;
177  gap: 24px;
178  margin-bottom: 20px;
179  font-size: 14px;
180  color: var(--muted);
181}
182.stats-row strong { color: var(--text); }
183
184/* JOB CARD */
185.jobs-list { display: flex; flex-direction: column; gap: 12px; }
186.job-card {
187  background: white;
188  border: 1.5px solid var(--border);
189  border-radius: var(--radius);
190  padding: 20px 24px;
191  cursor: pointer;
192  transition: all 0.2s;
193  display: flex;
194  gap: 20px;
195  align-items: flex-start;
196}
197.job-card:hover { border-color: var(--navy); box-shadow: 0 4px 16px rgba(27,58,107,0.08); transform: translateY(-1px); }
198.job-card.urgent { border-left: 3px solid var(--orange); }
199.job-logo {
200  width: 48px;
201  height: 48px;
202  border-radius: 10px;
203  background: var(--bg);
204  border: 1.5px solid var(--border);
205  display: flex;
206  align-items: center;
207  justify-content: center;
208  flex-shrink: 0;
209  font-family: 'Montserrat', sans-serif;
210  font-weight: 800;
211  font-size: 16px;
212  color: var(--navy);
213}
214.job-body { flex: 1; min-width: 0; }
215.job-title { font-weight: 700; font-size: 16px; color: var(--navy); margin-bottom: 4px; }
216.job-company { font-size: 14px; color: var(--text); margin-bottom: 8px; }
217.job-meta { display: flex; gap: 12px; flex-wrap: wrap; }
218.job-badge {
219  display: inline-flex;
220  align-items: center;
221  gap: 4px;
222  padding: 3px 8px;
223  border-radius: 6px;
224  font-size: 12px;
225  font-weight: 500;
226}
227.badge-city { background: var(--bg); color: var(--muted); }
228.badge-salary { background: #f0fdf4; color: var(--green); font-weight: 600; }
229.badge-type { background: #eff6ff; color: #1d4ed8; }
230.badge-urgent { background: #fff3ee; color: var(--orange); }
231.badge-industry { background: #f5f7ff; color: var(--navy); }
232.job-right { text-align: right; flex-shrink: 0; }
233.job-salary { font-family: 'Montserrat', sans-serif; font-weight: 800; font-size: 16px; color: var(--navy); }
234.job-date { font-size: 12px; color: var(--muted); margin-top: 4px; }
235
236/* EMPTY */
237.empty { text-align: center; padding: 80px 24px; color: var(--muted); }
238.empty h3 { font-size: 18px; color: var(--text); margin-bottom: 8px; }
239
240/* NEW JOB FORM */
241.form-wrap { max-width: 680px; margin: 0 auto; }
242.form-card {
243  background: white;
244  border: 1.5px solid var(--border);
245  border-radius: 16px;
246  padding: 32px;
247}
248.form-title { font-family: 'Montserrat', sans-serif; font-weight: 800; font-size: 20px; color: var(--navy); margin-bottom: 24px; }
249.field { margin-bottom: 18px; }
250.field label { display: block; font-size: 12px; font-weight: 600; color: var(--muted); text-transform: uppercase; letter-spacing: 0.5px; margin-bottom: 6px; }
251.ctl {
252  width: 100%;
253  height: 42px;
254  border: 1.5px solid var(--border);
255  border-radius: 8px;
256  padding: 0 14px;
257  font-size: 14px;
258  font-family: inherit;
259  color: var(--text);
260  background: white;
261  outline: none;
262  transition: border-color 0.15s;
263}
264.ctl:focus { border-color: var(--navy); }
265textarea.ctl { height: auto; min-height: 100px; padding: 12px 14px; resize: vertical; line-height: 1.6; }
266.form-row { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
267.btn-submit {
268  width: 100%;
269  height: 48px;
270  background: var(--orange);
271  color: white;
272  border: none;
273  border-radius: 10px;
274  font-size: 16px;
275  font-weight: 700;
276  cursor: pointer;
277  font-family: inherit;
278  transition: background 0.15s;
279  margin-top: 8px;
280}
281.btn-submit:hover { background: var(--orange-dark); }
282.form-error { color: #dc2626; font-size: 13px; margin-bottom: 12px; display: none; }
283
284/* INDUSTRY CHIPS */
285.industry-chips { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 20px; }
286.chip {
287  padding: 6px 14px;
288  border-radius: 20px;
289  border: 1.5px solid var(--border);
290  font-size: 13px;
291  font-weight: 500;
292  cursor: pointer;
293  background: white;
294  color: var(--muted);
295  transition: all 0.15s;
296}
297.chip:hover { border-color: var(--navy); color: var(--navy); }
298.chip.active { background: var(--navy); color: white; border-color: var(--navy); }
299
300/* FOOTER */
301footer {
302  background: white;
303  border-top: 1px solid #eee;
304  padding: 28px 24px;
305  text-align: center;
306  color: var(--muted);
307  font-size: 13px;
308  margin-top: 60px;
309}
310.footer-logo { font-family: 'Montserrat', sans-serif; font-weight: 800; font-size: 16px; color: var(--navy); margin-bottom: 6px; }
311.footer-logo span { color: var(--orange); }
312
313/* MODAL */
314.modal-overlay {
315  display: none;
316  position: fixed;
317  inset: 0;
318  background: rgba(0,0,0,0.55);
319  z-index: 1000;
320  align-items: center;
321  justify-content: center;
322  backdrop-filter: blur(4px);
323}
324.modal-overlay.open { display: flex; }
325.modal {
326  background: white;
327  border-radius: 16px;
328  padding: 32px;
329  width: 100%;
330  max-width: 560px;
331  margin: 16px;
332  position: relative;
333  max-height: 90vh;
334  overflow-y: auto;
335}
336.modal-close { position: absolute; top: 14px; right: 14px; background: none; border: none; font-size: 20px; cursor: pointer; color: var(--muted); }
337.modal h2 { font-family: 'Montserrat', sans-serif; font-weight: 800; font-size: 20px; color: var(--navy); margin-bottom: 16px; }
338.detail-row { display: flex; justify-content: space-between; padding: 10px 0; border-bottom: 1px solid var(--bg); font-size: 14px; }
339.detail-row:last-child { border-bottom: none; }
340.detail-key { color: var(--muted); }
341.detail-val { font-weight: 500; max-width: 60%; text-align: right; }
342.detail-desc { font-size: 14px; line-height: 1.7; color: var(--text); margin-top: 16px; white-space: pre-wrap; }
343.btn-contact {
344  display: block;
345  width: 100%;
346  margin-top: 20px;
347  padding: 13px;
348  background: var(--navy);
349  color: white;
350  border: none;
351  border-radius: 10px;
352  font-size: 15px;
353  font-weight: 700;
354  cursor: pointer;
355  font-family: inherit;
356  text-align: center;
357  text-decoration: none;
358  transition: background 0.15s;
359}
360.btn-contact:hover { background: var(--navy-light); }
361
362@media (max-width: 768px) {
363  .nav-links { display: none; }
364  .filters { flex-wrap: wrap; }
365  .f-field-industry, .f-field-city, .f-field-type { flex: 1 1 140px; }
366  .form-row { grid-template-columns: 1fr; }
367  .job-card { flex-direction: column; gap: 12px; }
368  .job-right { text-align: left; }
369}
370</style>
371<!-- Yandex.Metrika counter -->
372<script type="text/javascript">
373(function(m,e,t,r,i,k,a){m[i]=m[i]||function(){(m[i].a=m[i].a||[]).push(arguments)};m[i].l=1*new Date();for(var j=0;j<document.scripts.length;j++){if(document.scripts[j].src===r){return;}}k=e.createElement(t),a=e.getElementsByTagName(t)[0],k.async=1,k.src=r,a.parentNode.insertBefore(k,a)})(window,document,"script","https://mc.yandex.ru/metrika/tag.js?id=110152856","ym");
374ym(110152856,"init",{ssr:true,webvisor:true,clickmap:true,accurateTrackBounce:true,trackLinks:true});
375</script>
375
376<noscript><div><img src="https://mc.yandex.ru/watch/110152856" style="position:absolute;left:-9999px;" alt=""/></div></noscript>
377<!-- /Yandex.Metrika counter -->
378<link rel="icon" type="image/svg+xml" href="/favicon.svg">
379</head>
380<body>
381<script src="/js/ui.js?v=20260722"></script>
381
382
383<nav>
384  <a href="/" class="nav-logo">Ind<span>Mart</span></a>
385  <div class="nav-links">
386    <a href="/listings" class="nav-link">Объявления</a>
387    <a href="/wanted" class="nav-link">Ищу</a>
388    <a href="/jobs" class="nav-link active">Работа</a>
389    <a href="/baza" class="nav-link">База знаний</a>
390  </div>
391  <div class="nav-right">
392    <button class="btn-post" onclick="showTab('new')">+ Разместить вакансию</button>
393    <div id="navUser" style="display:none;position:relative;align-items:center;">
394      <div style="display:flex;align-items:center;gap:8px;cursor:pointer;" onclick="toggleUserMenu()">
395        <div id="navAvatar" style="width:32px;height:32px;border-radius:50%;background:#FF6B35;display:flex;align-items:center;justify-content:center;font-size:14px;font-weight:700;color:white;">A</div>
396        <span id="navName" style="font-size:13px;color:var(--navy);font-weight:600;"></span>
397        <span style="font-size:10px;color:var(--muted);">▼</span>
398      </div>
399      <div id="userDropdown" style="display:none;position:absolute;right:0;top:44px;background:white;border:1.5px solid #e0e4ef;border-radius:12px;box-shadow:0 8px 32px rgba(0,0,0,0.12);
399min-width:200px;z-index:9999;overflow:hidden;">
400        <a href="/cabinet" style="display:flex;align-items:center;gap:10px;padding:11px 16px;font-size:14px;color:#1a2236;text-decoration:none;" onmouseover="this.style.background='#f5f7ff'" onmouseout="this.style.background=''">👤 Личный кабинет</a>
401        <a href="/messages" style="display:flex;align-items:center;gap:10px;padding:11px 16px;font-size:14px;color:#1a2236;text-decoration:none;" onmouseover="this.style.background='#f5f7ff'" onmouseout="this.style.background=''">💬 Сообщения</a>
402        <a href="/consultant" style="display:flex;align-items:center;gap:10px;padding:11px 16px;font-size:14px;color:#1a2236;text-decoration:none;" onmouseover="this.style.background='#f5f7ff'" onmouseout="this.style.background=''">🤖 AI Консультант</a>
403        <a href="/model-search.html" style="display:flex;align-items:center;gap:10px;padding:11px 16px;font-size:14px;color:#1a2236;text-decoration:none;" onmouseover="this.style.background='#f5f7ff'" onmouseout="this.style.background=''">📊 Аналитика цен</a>
404        <div style="height:1px;background:#e0e4ef;margin:4px 0;"></div>
405        <button onclick="logout()" style="display:flex;align-items:center;gap:10px;padding:11px 16px;font-size:14px;color:#dc2626;background:none;border:none;width:100%;cursor:pointer;font-family:inherit;" onmouseover="this.style.background='#fff0f0'" onmouseout="this.style.background=''">🚪 Выйти</button>
406      </div>
407    </div>
408    <button class="btn-login" id="navLoginBtn" onclick="window.openLoginModal()">Войти</button>
409  </div>
410</nav>
411
412<div class="hero">
413  <div class="hero-inner">
414    <div class="hero-top">
415      <div>
416        <h1>Работа в <span>пищевой промышленности</span></h1>
417        <div class="hero-sub">Вакансии для пекарей, технологов, механиков и руководителей</div>
418      </div>
419      <div id="heroCount" style="font-family:'Montserrat',sans-serif;font-weight:800;font-size:32px;color:var(--navy);"></div>
420    </div>
421
422    <!-- Фильтры -->
423    <div class="filters">
424      <div class="f-field f-field-search">
425        <div class="f-label">Поиск</div>
426        <input id="fSearch" class="f-input" placeholder="Должность, компания…" onkeydown="if(event.key==='Enter') doSearch()">
427      </div>
428      <div class="f-field f-field-industry">
429        <div class="f-label">Отрасль</div>
430        <select id="fIndustry" class="f-select">
431          <option value="">Все отрасли</option>
432          <option value="hlebopekarnoe">Пекарни и кондитерские</option>
433          <option value="myasopererabotka">Мясопереработка</option>
434          <option value="molochnoe">Молочное производство</option>
435          <option value="horeca">Общественное питание</option>
436        </select>
437      </div>
438      <div class="f-field f-field-city">
439        <div class="f-label">Город</div>
440        <div class="geo-wrap">
441          <input id="fCity" class="f-input" placeholder="Город" autocomplete="off" oninput="geoSuggest(this,'fCityDrop')" onkeydown="geoKeydown(event,this,'fCityDrop')">
442          <div class="geo-dropdown" id="fCityDrop"></div>
443        </div>
444      </div>
445      <div class="f-field f-field-type">
446        <div class="f-label">Тип занятости</div>
447        <select id="fType" class="f-select">
448          <option value="">Любой</option>
449          <option value="full">Полная</option>
450          <option value="part">Частичная</option>
451          <option value="contract">Договор</option>
452          <option value="remote">Удалённо</option>
453        </select>
454      </div>
455      <div class="f-field">
456        <div class="f-label">&nbsp;</div>
457        <button class="btn-search" onclick="doSearch()">Найти</button>
458      </div>
459    </div>
460
461    <!-- Отраслевые чипы -->
462    <div class="industry-chips" id="industryChips">
463      <div class="chip active" onclick="setIndustry('',this)">Все</div>
464      <div class="chip" onclick="setIndustry('hlebopekarnoe',this)">Пекарни и кондитерские</div>
465      <div class="chip" onclick="setIndustry('myasopererabotka',this)">Мясопереработка</div>
466      <div class="chip" onclick="setIndustry('molochnoe',this)">Молочное</div>
467      <div class="chip" onclick="setIndustry('horeca',this)">HoReCa</div>
468    </div>
469
470    <!-- Табы -->
471    <div class="tabs-wrap">
472      <button class="tab-btn active" id="tabVacancies" onclick="showTab('vacancies')">
472Вакансии</button>
473      <button class="tab-btn" id="tabResumes" onclick="showTab('resumes')">Резюме</button>
474      <button class="tab-btn" id="tabNew" onclick="showTab('new')">+ Разместить</button>
475    </div>
476  </div>
477</div>
478
479<!-- MAIN CONTENT -->
480<div class="main">
481
482  <!-- Вакансии -->
483  <div id="pageVacancies">
484    <div class="stats-row">
485      <span id="statsText">Загрузка...</span>
486    </div>
487    <div id="jobsList" class="jobs-list"></div>
488    <div id="emptyJobs" class="empty" style="display:none">
489      <h3>Вакансий пока нет</h3>
490      <p>Станьте первым — разместите вакансию бесплатно</p>
491      <button onclick="showTab('new')" style="margin-top:16px;padding:10px 24px;background:var(--orange);color:white;border:none;border-radius:8px;font-size:14px;font-weight:600;cursor:pointer;font-family:inherit;">Разместить вакансию</button>
492    </div>
493  </div>
494
495  <!-- Резюме -->
496  <div id="pageResumes" style="display:none">
497    <div class="empty">
498      <h3>Раздел резюме скоро откроется</h3>
499      <p>Пока вы можете разместить вакансию и найти сотрудника</p>
500      <button onclick="showTab('new')" style="margin-top:16px;padding:10px 24px;background:var(--orange);color:white;border:none;border-radius:8px;font-size:14px;font-weight:600;cursor:pointer;font-family:inherit;">Разместить вакансию</button>
501    </div>
502  </div>
503
504  <!-- Форма размещения -->
505  <div id="pageNew" style="display:none">
506    <div class="form-wrap">
507
508      <!-- Шаг 0: Выбор типа -->
509      <div id="stepChoose" class="form-card" style="text-align:center;">
510        <div class="form-title">Что хотите разместить?</div>
511        <div style="display:grid;grid-template-columns:1fr 1fr;gap:16px;margin-top:8px;">
512          <div onclick="chooseType('vacancy')" style="border:2px solid var(--border);border-radius:12px;padding:28px 16px;cursor:pointer;transition:all 0.2s;" id="choiceVacancy">
513            <div style="font-size:36px;margin-bottom:12px;">👔</div>
514            <div style="font-family:'Montserrat',sans-serif;font-weight:700;font-size:16px;color:var(--navy);">Вакансию</div>
515            <div style="font-size:13px;color:var(--muted);margin-top:6px;">Ищу сотрудника в компанию</div>
516          </div>
517          <div onclick="chooseType('resume')" style="border:2px solid var(--border);border-radius:12px;padding:28px 16px;cursor:pointer;transition:all 0.2s;" id="choiceResume">
518            <div style="font-size:36px;margin-bottom:12px;">📄</div>
519            <div style="font-family:'Montserrat',sans-serif;font-weight:700;font-size:16px;color:var(--navy);">Резюме</div>
520            <div style="font-size:13px;color:var(--muted);margin-top:6px;">Ищу работу в отрасли</div>
521          </div>
522        </div>
523      </div>
524
525      <!-- Форма вакансии -->
526      <div id="formVacancy" style="display:none;">
527        <div class="form-card">
528          <button onclick="backToChoose()" style="background:none;border:none;color:var(--navy);cursor:pointer;font-size:13px;margin-bottom:16px;font-family:inherit;">← Назад</button>
529          <div class="form-title">Разместить вакансию</div>
530
531          <!-- Блок о компании -->
532          <div style="background:#f5f7ff;border-radius:10px;padding:16px;margin-bottom:20px;">
533            <div style="font-size:12px;font-weight:700;color:var(--navy);text-transform:uppercase;letter-spacing:0.5px;margin-bottom:12px;">О компании</div>
534            <div class="field">
535              <label>Название компании *</label>
536              <input id="vCompany" class="ctl" placeholder="Пекарня 'Хлеб да Соль', ООО Хлебозавод…">
537            </div>
538            <div class="form-row">
539              <div class="field">
540                <label>Отрасль *</label>
541                <select id="vIndustry" class="ctl">
542                  <option value="">Выберите отрасль</option>
543                  <option value="hlebopekarnoe">Пекарни и кондитерские</option>
544                  <option value="myasopererabotka">Мясопереработка</option>
545                  <option value="molochnoe">Молочное производство</option>
546                  <option value="ovoshchi-frukty">Переработка овощей и фруктов</option>
547                  <option value="horeca">Общественное питание (HoReCa)</option>
548                  <option value="rybnoe">Рыбопереработка</option>
549                  <option value="zernovoe">Зернопереработка</option>
550                  <option value="korma">Производство кормов</option>
551                </select>
552              </div>
553              <div class="field">
554                <label>Город *</label>
555                <div class="geo-wrap">
556                  <input id="vCity" class="ctl" placeholder="Москва" autocomplete="off" oninput="geoSuggest(this,'vCityDrop')" onkeydown="geoKeydown(event,this,'vCityDrop')">
557                  <div class="geo-dropdown" id="vCityDrop"></div>
558                </div>
559              </div>
560            </div>
561            <div class="field" style="margin-bottom:0">
562              <label>О компании</label>
563              <textarea id="vCompanyDesc" class="ctl" style="min-height:70px;" placeholder="Кратко о вашей компании, чем занимаетесь, сколько лет на рынке…"></textarea>
564            </div>
565          </div>
566
567          <!-- Блок о вакансии -->
568          <div style="background:#fff;border-radius:10px;padding:16px;margin-bottom:20px;border:1.5px solid var(--border);">
569            <div style="font-size:12px;font-weight:700;color:var(--navy);text-transform:uppercase;letter-spacing:0.5px;margin-bottom:12px;">
569О вакансии</div>
570            <div class="field">
571              <label>Должность *</label>
572              <input id="vTitle" class="ctl" placeholder="Пекарь, технолог производства, механик…">
573            </div>
574            <div class="form-row">
575              <div class="field">
576                <label>Зарплата от, ₽</label>
577                <input id="vSalaryFrom" class="ctl" type="number" placeholder="50000">
578              </div>
579              <div class="field">
580                <label>Зарплата до, ₽</label>
581                <input id="vSalaryTo" class="ctl" type="number" placeholder="80000">
582              </div>
583            </div>
584            <div class="field">
585              <label>Тип занятости</label>
586              <select id="vType" class="ctl">
587                <option value="full">Полная занятость</option>
588                <option value="part">Частичная</option>
589                <option value="contract">Договор/проект</option>
590                <option value="remote">Удалённо</option>
591              </select>
592            </div>
593            <div class="field" style="margin-bottom:0">
594              <label>Обязанности и требования</label>
595              <textarea id="vDesc" class="ctl" placeholder="Что нужно делать, какой опыт нужен, условия работы…"></textarea>
596            </div>
597          </div>
598
599          <!-- Контакты -->
600          <div class="form-row">
601            <div class="field">
602              <label>Телефон</label>
603              <input id="vPhone" class="ctl" placeholder="+7 900 000-00-00">
604            </div>
605            <div class="field">
606              <label>Telegram</label>
607              <input id="vTg" class="ctl" placeholder="username">
608            </div>
609          </div>
610          <div style="font-size:12px;color:var(--muted);margin-bottom:12px;">Укажите хотя бы один способ связи</div>
611          <div class="form-error" id="vacancyError"></div>
612          <button class="btn-submit" onclick="submitVacancy()">Опубликовать вакансию бесплатно</button>
613        </div>
614      </div>
615
616      <!-- Форма резюме -->
617      <div id="formResume" style="display:none;">
618        <div class="form-card">
619          <button onclick="backToChoose()" style="background:none;border:none;color:var(--navy);cursor:pointer;font-size:13px;margin-bottom:16px;font-family:inherit;">← Назад</button>
620          <div class="form-title">Разместить резюме</div>
621
622          <!-- Блок о себе -->
623          <div style="background:#f5f7ff;border-radius:10px;padding:16px;margin-bottom:20px;">
624            <div style="font-size:12px;font-weight:700;color:var(--navy);text-transform:uppercase;letter-spacing:0.5px;margin-bottom:12px;">О себе</div>
625            <div class="form-row">
626              <div class="field">
627                <label>Имя *</label>
628                <input id="rName" class="ctl" placeholder="Иван Иванов">
629              </div>
630              <div class="field">
631                <label>Город *</label>
632                <div class="geo-wrap">
633                  <input id="rCity" class="ctl" placeholder="Москва" autocomplete="off" oninput="geoSuggest(this,'rCityDrop')" onkeydown="geoKeydown(event,this,'rCityDrop')">
634                  <div class="geo-dropdown" id="rCityDrop"></div>
635                </div>
636              </div>
637            </div>
638            <div class="form-row">
639              <div class="field">
640                <label>Опыт работы</label>
641                <select id="rExp" class="ctl">
642                  <option value="no_exp">Без опыта</option>
643                  <option value="1-3">1-3 года</option>
644                  <option value="3-6">3-6 лет</option>
645                  <option value="6+">Более 6 лет</option>
646                </select>
647              </div>
648              <div class="field">
649                <label>Отрасль</label>
650                <select id="rIndustry" class="ctl">
651                  <option value="">Любая</option>
652                  <option value="hlebopekarnoe">Пекарни и кондитерские</option>
653                  <option value="myasopererabotka">Мясопереработка</option>
654                  <option value="molochnoe">Молочное производство</option>
655                  <option value="horeca">Общественное питание</option>
656                  <option value="rybnoe">Рыбопереработка</option>
657                  <option value="zernovoe">Зернопереработка</option>
658                </select>
659              </div>
660            </div>
661            <div class="field" style="margin-bottom:0">
662              <label>О себе</label>
663              <textarea id="rAbout" class="ctl" style="min-height:70px;" placeholder="Кратко о вашем опыте, специализации, достижениях…"></textarea>
664            </div>
665          </div>
666
667          <!-- Блок резюме -->
668          <div style="background:#fff;border-radius:10px;padding:16px;margin-bottom:20px;border:1.5px solid var(--border);">
669            <div style="font-size:12px;font-weight:700;color:var(--navy);text-transform:uppercase;letter-spacing:0.5px;margin-bottom:12px;">Желаемая работа</div>
670            <div class="field">
671              <label>Желаемая должность *</label>
672              <input id="rTitle" class="ctl" placeholder="Пекарь, технолог, механик оборудования…">
673            </div>
674            <div class="form-row">
675              <div class="field">
676                <label>Желаемая зарплата от, ₽</label>
677                <input id="rSalary" class="ctl" type="number" placeholder="60000">
678              </div>
679              <div class="field">
680                <label>Тип занятости</label>
681                <select id="rType" class="ctl">
682                  <option value="full">Полная занятость</option>
683                  <option value="part">Частичная</option>
684                  <option value="contract">Договор/проект</option>
685                  <option value="remote">Удалённо</option>
686                </select>
687              </div>
688            </div>
689            <div class="field" style="margin-bottom:0">
690              <label>Опыт и навыки</label>
691              <textarea id="rDesc" class="ctl" placeholder="Где работали, на каком оборудовании, что умеете…"></textarea>
692            </div>
693          </div>
694
695          <!-- Контакты -->
696          <div class="form-row">
697            <div class="field">
698              <label>Телефон</label>
699              <input id="rPhone" class="ctl" placeholder="+7 900 000-00-00">
700            </div>
701            <div class="field">
702              <label>Telegram</label>
703              <input id="rTg" class="ctl" placeholder="username">
704            </div>
705          </div>
706          <div style="font-size:12px;color:var(--muted);margin-bottom:12px;">Укажите хотя бы один способ связи</div>
707          <div class="form-error" id="resumeError"></div>
708          <button class="btn-submit" onclick="submitResume()">Опубликовать резюме бесплатно</button>
709        </div>
710      </div>
711
712    </div>
713  </div>
714
715</div>
716
717<!-- JOB DETAIL MODAL -->
718<div class="modal-overlay" id="jobModal" onclick="if(event.target===this)closeModal()">
719  <div class="modal">
720    <button class="modal-close" onclick="closeModal()">✕</button>
721    <div id="modalContent"></div>
722  </div>
723</div>
724
725<footer>
726  <div class="footer-logo">Ind<span>Mart</span></div>
727  <div style="display:flex;justify-content:center;gap:20px;margin:8px 0;">
728    <a href="/" style="color:var(--muted);text-decoration:none;">Главная</a>
729    <a href="/listings" style="color:var(--muted);text-decoration:none;">Объявления</a>
730    <a href="/baza" style="color:var(--muted);text-decoration:none;">База знаний</a>
731    <a href="/upgrade" style="color:var(--muted);text-decoration:none;">Тарифы</a>
732  </div>
733  <div>© 2026 IndMart · Работа в пищевой промышленности</div>
734</footer>
735
736<script>
737const API = '/api';
738let currentTab = 'vacancies';
739let filters = {};
740let jobs = [];
741let geoTimer = null;
742
743// ── Auth ──────────────────────────────────────────────────────────────────────
744const token = localStorage.getItem('indmart_token');
745const userStr = localStorage.getItem('indmart_user');
746let currentUser = null;
747if (userStr) try { currentUser = JSON.parse(userStr); } catch(e) {}
748
749function authHeaders() {
750  return token ? { 'Authorization': 'Bearer ' + token } : {};
751}
752
753// Инициализация навбара
754(function() {
755  var u = localStorage.getItem('indmart_user');
756  var t = localStorage.getItem('indmart_token');
757  if (u && t) {
758    try {
759      var user = JSON.parse(u);
760      var name = user.username || user.email || 'User';
761      document.getElementById('navUser').style.display = 'flex';
762      document.getElementById('navLoginBtn').style.display = 'none';
763      document.getElementById('navAvatar').textContent = name[0].toUpperCase();
764      document.getElementById('navName').textContent = '@' + name;
765      // Аватар фото
766      if (user.photo_url) {
767        var img = document.createElement('img');
768        img.src = user.photo_url;
769        img.style.cssText = 'width:100%;height:100%;object-fit:cover;border-radius:50%;';
770        document.getElementById('navAvatar').textContent = '';
771        document.getElementById('navAvatar').appendChild(img);
772      }
773    } catch(e) {}
774  }
775})();
776function logout() {
777  localStorage.removeItem('indmart_token');
778  localStorage.removeItem('indmart_user');
779  location.reload();
780}
781function toggleUserMenu() {
782  var m = document.getElementById('userDropdown');
783  m.style.display = m.style.display === 'none' ? 'block' : 'none';
784}
785document.addEventListener('click', function(e) {
786  var m = document.getElementById('userDropdown');
787  if (m && !e.target.closest('#navUser')) m.style.display = 'none';
788});
789
790// ── Tabs ──────────────────────────────────────────────────────────────────────
791function showTab(tab) {
792  currentTab = tab;
793  document.getElementById('pageVacancies').style.display = tab === 'vacancies' ? 'block' : 'none';
794  document.getElementById('pageResumes').style.display = tab === 'resumes' ? 'block' : 'none';
795  document.getElementById('pageNew').style.display = tab === 'new' ? 'block' : 'none';
796  document.getElementById('tabVacancies').classList.toggle('active', tab === 'vacancies');
797  document.getElementById('tabResumes').classList.toggle('active', tab === 'resumes');
798  document.getElementById('tabNew').classList.toggle('active', tab === 'new');
799  if (tab === 'vacancies') loadJobs();
800  if (tab === 'resumes') loadResumes();
801  if (tab === 'new') backToChoose(); // Всегда сбрасываем к выбору типа
802}
803
804// ── Industry chips ────────────────────────────────────────────────────────────
805function setIndustry(val, el) {
806  document.querySelectorAll('.chip').forEach(c => c.classList.remove('active'));
807  el.classList.add('active');
808  document.getElementById('fIndustry').value = val;
809  filters.industry = val;
810  loadJobs();
811}
812
813// ── Load resumes ──────────────────────────────────────────────────────────────
814async function loadResumes() {
815  const page = document.getElementById('pageResumes');
816  page.innerHTML = '<div style="text-align:center;padding:40px;color:var(--muted);">Загрузка...</div>';
817  try {
818    const params = new URLSearchParams({ limit: 20 });
819    if (filters.search) params.set('search', filters.search);
820    if (filters.industry) params.set('category_slug', filters.industry);
821    if (filters.city) params.set('city', filters.city);
822    if (filters.type) params.set('employment_type', filters.type);
823
824    const res = await fetch(API + '/resumes?' + params);
825    const data = await res.json();
826    const resumes = data.resumes || [];
827    const total = data.total || resumes.length;
828
829    if (!resumes.length) {
830      page.innerHTML = `
831        <div class="empty">
832          <h3>Резюме пока нет</h3>
833          <p>Станьте первым — разместите резюме бесплатно</p>
834          <button onclick="showTab('new')" style="margin-top:16px;padding:10px 24px;background:var(--orange);color:white;border:none;border-radius:8px;font-size:14px;font-weight:600;cursor:pointer;font-family:inherit;">Разместить резюме</button>
835        </div>`;
836      return;
837    }
838
839    const expMap = { no_exp: 'Без опыта', '1-3': '1-3 года', '3-6': '3-6 лет', '6+': 'Более 6 лет' };
840    const typeMap = { full: 'Полная', part: 'Частичная', contract: 'Договор', remote: 'Удалённо' };
841
842    page.innerHTML = `
843      <div class="stats-row"><span>Найдено: <strong>${total}</strong> резюме</span></div>
844      <div class="jobs-list">
845        ${resumes.map(r => `
846          <div class="job-card" onclick="window.location='/resumes/${r.id}'">
847            <div class="job-logo">${(r.name||'?')[0].toUpperCase()}</div>
848            <div class="job-body">
849              <div class="job-title">${esc(r.title)}</div>
850              <div class="job-company">${esc(r.name)}</div>
851              <div class="job-meta">
852                ${r.city ? `<span class="job-badge badge-city">📍 ${esc(r.city)}</span>` : ''}
853                ${r.experience ? `<span class="job-badge badge-type">${expMap[r.experience] || r.experience}</span>` : ''}
854                ${r.employment_type ? `<span class="job-badge badge-industry">${typeMap[r.employment_type] || r.employment_type}</span>` : ''}
855              </div>
856            </div>
857            <div class="job-right">
858              ${r.salary_from ? `<div class="job-salary">от ${Number(r.salary_from).toLocaleString('ru-RU')} ₽</div>` : '<div class="job-salary" style="font-size:13px;color:var(--muted);">По договорённости</div>'}
859              <div class="job-date">${timeAgo(r.created_at)}</div>
860            </div>
861          </div>`).join('')}
862      </div>`;
863  } catch(e) {
864    page.innerHTML = `<div class="empty"><h3>Резюме пока нет</h3><p>Разместите первое резюме</p><button onclick="showTab('new')" style="margin-top:16px;padding:10px 24px;background:var(--orange);color:white;border:none;border-radius:8px;font-size:14px;font-weight:600;cursor:pointer;font-family:inherit;">Разместить резюме</button></div>`;
865  }
866}
867
868function openResume(r) {
869  const expMap = { no_exp: 'Без опыта', '1-3': '1-3 года', '3-6': '3-6 лет', '6+': 'Более 6 лет' };
870  const typeMap = { full: 'Полная занятость', part: 'Частичная', contract: 'Договор', remote: 'Удалённо' };
871
872  let contactBlock = '';
873  if (!currentUser) {
874    contactBlock = `
875      <div style="background:#f8f9fc;border:1.5px solid var(--border);border-radius:10px;padding:20px;text-align:center;margin-top:16px;">
876        <div style="font-size:14px;color:var(--muted);margin-bottom:12px;">Войдите чтобы увидеть контакты соискателя.<br><strong style="color:var(--orange)">7 дней Pro бесплатно</strong> после регистрации.</div>
877        <a href="/listings" style="display:inline-block;padding:10px 24px;background:var(--navy);color:white;border-radius:8px;font-size:14px;font-weight:600;text-decoration:none;">Войти / Зарегистрироваться</a>
878      </div>`;
879  } else if (r.phone || r.telegram_username) {
880    contactBlock = `<div style="margin-top:16px;display:flex;flex-direction:column;gap:10px;">`;
881    if (r.phone) contactBlock += `<a href="tel:${esc(r.phone)}" class="btn-contact">📞 Позвонить: ${esc(r.phone)}</a>`;
882    if (r.telegram_username) contactBlock += `<a href="https://t.me/${esc(r.telegram_username.replace('@',''))}" target="_blank" class="btn-contact" style="background:var(--navy);">✈️ Telegram: @${esc(r.telegram_username.replace('@',''))}</a>`;
883    contactBlock += `</div>`;
884  }
885
886  document.getElementById('modalContent').innerHTML = `
887    <h2>${esc(r.title)}</h2>
888    <div class="detail-row"><span class="detail-key">Соискатель</span><span class="detail-val">${esc(r.name)}</span></div>
889    <div class="detail-row"><span class="detail-key">Город</span><span class="detail-val">${esc(r.city || '—')}</span></div>
890    <div class="detail-row"><span class="detail-key">Опыт</span><span class="detail-val">${expMap[r.experience] || '—'}</span></div>
891    <div class="detail-row"><span class="detail-key">Занятость</span><span class="detail-val">${typeMap[r.employment_type] || '—'}</span></div>
892    ${r.salary_from ? `<div class="detail-row"><span class="detail-key">Ожидания</span><span class="detail-val">от ${Number(r.salary_from).toLocaleString('ru-RU')} ₽</span></div>` : ''}
893    ${r.about ? `<div class="detail-desc">${esc(r.about)}</div>` : ''}
894    ${r.description ? `<div class="detail-desc" style="margin-top:8px;">${esc(r.description)}</div>` : ''}
895    ${contactBlock}
896    <div style="margin-top:12px;text-align:center;">
897      <button onclick="reportObject('resume',${r.id})" style="background:none;border:none;color:var(--muted);font-size:12px;cursor:pointer;font-family:inherit;text-decoration:underline;">Пожаловаться</button>
898    </div>`;
899  document.getElementById('jobModal').classList.add('open');
900}
901
902// ── Load jobs ─────────────────────────────────────────────────────────────────
903async function loadJobs() {
904  const list = document.getElementById('jobsList');
905  const empty = document.getElementById('emptyJobs');
906  list.innerHTML = '<div style="text-align:center;padding:40px;color:var(--muted);">Загрузка...</div>';
907
908  try {
909    const params = new URLSearchParams({ limit: 20 });
910    if (filters.search) params.set('search', filters.search);
911    if (filters.industry) params.set('category_slug', filters.industry);
912    if (filters.city) params.set('city', filters.city);
913    if (filters.type) params.set('employment_type', filters.type);
914
915    const res = await fetch(API + '/jobs?' + params);
916    const data = await res.json();
917    jobs = data.jobs || data || [];
918    const total = data.total || jobs.length;
919
920    document.getElementById('statsText').innerHTML = `Найдено: <strong>${total}</strong> вакансий`;
921    if (total) document.getElementById('heroCount').textContent = total + ' вакансий';
922
923    if (!jobs.length) {
924      list.innerHTML = '';
925      empty.style.display = 'block';
926      return;
927    }
928    empty.style.display = 'none';
929    list.innerHTML = '';
930    jobs.forEach(j => list.appendChild(makeJobCard(j)));
931  } catch(e) {
932    // Показываем демо-вакансии если API не готов
933    showDemoJobs();
934  }
935}
936
937function makeJobCard(j) {
938  const div = document.createElement('div');
939  div.className = 'job-card' + (j.is_urgent ? ' urgent' : '');
940  div.onclick = () => window.location = '/jobs/' + j.id;
941  div.style.cursor = 'pointer';
942
943  const salary = j.salary_from || j.salary_to
944    ? (j.salary_from ? 'от ' + Number(j.salary_from).toLocaleString('ru-RU') : '') +
945      (j.salary_to ? ' до ' + Number(j.salary_to).toLocaleString('ru-RU') + ' ₽' : ' ₽')
946    : 'По договорённости';
947
948  const typeMap = { full: 'Полная', part: 'Частичная', contract: 'Договор', remote: 'Удалённо' };
949  const initial = (j.company || j.title || 'И')[0].toUpperCase();
950
951  div.innerHTML = `
952    <div class="job-logo">${initial}</div>
953    <div class="job-body">
954      <div class="job-title">${esc(j.title)}</div>
955      <div class="job-company">${esc(j.company || 'Компания не указана')}</div>
956      <div class="job-meta">
957        ${j.city ? `<span class="job-badge badge-city">📍 ${esc(j.city)}</span>` : ''}
958        ${j.employment_type ? `<span class="job-badge badge-type">${typeMap[j.employment_type] || j.employment_type}</span>` : ''}
959        ${j.is_urgent ? '<span class="job-badge badge-urgent">Срочно</span>' : ''}
960      </div>
961    </div>
962    <div class="job-right">
963      <div class="job-salary">${salary}</div>
964      <div class="job-date">${timeAgo(j.created_at)}</div>
965    </div>`;
966  return div;
967}
968
969function openJob(j) {
970  const typeMap = { full: 'Полная занятость', part: 'Частичная', contract: 'Договор', remote: 'Удалённо' };
971  const salary = j.salary_from || j.salary_to
972    ? (j.salary_from ? 'от ' + Number(j.salary_from).toLocaleString('ru-RU') : '') +
973      (j.salary_to ? ' до ' + Number(j.salary_to).toLocaleString('ru-RU') + ' ₽' : ' ₽')
974    : 'По договорённости';
975
976  let contactBlock = '';
977  if (!currentUser) {
978    contactBlock = `
979      <div style="background:#f8f9fc;border:1.5px solid var(--border);border-radius:10px;padding:20px;text-align:center;margin-top:16px;">
980        <div style="font-size:14px;color:var(--muted);margin-bottom:12px;">Войдите чтобы увидеть контакты работодателя.<br><strong style="color:var(--orange)">7 дней Pro бесплатно</strong> после регистрации.</div>
981        <a href="/listings" style="display:inline-block;padding:10px 24px;background:var(--navy);color:white;border-radius:8px;font-size:14px;font-weight:600;text-decoration:none;">Войти / Зарегистрироваться</a>
982      </div>`;
983  } else if (j.phone || j.telegram_username) {
984    contactBlock = `<div style="margin-top:16px;display:flex;flex-direction:column;gap:10px;">`;
985    if (j.phone) contactBlock += `<a href="tel:${esc(j.phone)}" class="btn-contact">📞 Позвонить: ${esc(j.phone)}</a>`;
986    if (j.telegram_username) contactBlock += `<a href="https://t.me/${esc(j.telegram_username.replace('@',''))}" target="_blank" class="btn-contact" style="background:var(--navy);">✈️ Написать в Telegram: @${esc(j.telegram_username.replace('@',''))}</a>`;
987    contactBlock += `</div>`;
988  } else {
989    contactBlock = `<div style="margin-top:16px;color:var(--muted);font-size:14px;text-align:center;">Контакты не указаны</div>`;
990  }
991
992  document.getElementById('modalContent').innerHTML = `
993    <h2>${esc(j.title)}</h2>
994    <div class="detail-row"><span class="detail-key">Компания</span><span class="detail-val">${esc(j.company || 'Не указана')}</span></div>
995    <div class="detail-row"><span class="detail-key">Город</span><span class="detail-val">${esc(j.city || 'Не указан')}</span></div>
996    <div class="detail-row"><span class="detail-key">Зарплата</span><span class="detail-val">${salary}</span></div>
997    <div class="detail-row"><span class="detail-key">Занятость</span><span class="detail-val">${typeMap[j.employment_type] || '—'}</span></div>
998    ${j.description ? `<div class="detail-desc">${esc(j.description)}</div>` : ''}
999    ${contactBlock}
1000    <div style="margin-top:12px;text-align:center;">
1001      <button onclick="reportObject('job',${j.id})" style="background:none;border:none;color:var(--muted);font-size:12px;cursor:pointer;font-family:inherit;text-decoration:underline;">Пожаловаться</button>
1002    </div>`;
1003
1004  document.getElementById('jobModal').classList.add('open');
1005}
1006
1007function closeModal() {
1008  document.getElementById('jobModal').classList.remove('open');
1009}
1010
1011async function reportObject(type, id) {
1012  const reason = await uiPrompt('Причина жалобы:\n- Спам\n- Фейк\n- Нецензурное\n- Другое\n\nВведите причину:');
1013  if (!reason) return;
1014  try {
1015    const res = await fetch(API + '/report', {
1016      method: 'POST',
1017      headers: { 'Content-Type': 'application/json', ...authHeaders() },
1018      body: JSON.stringify({ type, object_id: id, reason })
1019    });
1020    const data = await res.json();
1021    if (data.status === 'already_reported') {
1022      uiToast('Вы уже жаловались на это объявление.');
1023    } else {
1024      uiToast('Жалоба отправлена. Мы рассмотрим её в ближайшее время.');
1025    }
1026  } catch(e) {
1027    uiToast('Ошибка отправки жалобы. Попробуйте позже.');
1028  }
1029}
1030
1031// ── Demo jobs (пока нет данных) ───────────────────────────────────────────────
1032function showDemoJobs() {
1033  const demoJobs = [
1034    { id: 1, title: 'Пекарь', company: 'Пекарня "Хлеб да Соль"', city: 'Москва', salary_from: 60000, salary_to: 80000, employment_type: 'full', is_urgent: true, created_at: new Date().toISOString() },
1035    { id: 2, title: 'Технолог хлебопекарного производства', company: 'ООО Хлебозавод №3', city: 'Санкт-Петербург', salary_from: 80000, salary_to: 120000, employment_type: 'full', created_at: new Date(Date.now()-86400000).toISOString() },
1036    { id: 3, title: 'Механик по ремонту пекарного оборудования', company: 'Частная пекарня', city: 'Краснодар', salary_from: 70000, salary_to: 100000, employment_type: 'full', created_at: new Date(Date.now()-172800000).toISOString() },
1037    { id: 4, title: 'Кондитер', company: 'Кондитерская "Сладкий мир"', city: 'Екатеринбург', salary_from: 55000, salary_to: 75000, employment_type: 'full', created_at: new Date(Date.now()-259200000).toISOString() },
1038  ];
1039  jobs = demoJobs;
1040  document.getElementById('statsText').innerHTML = `Найдено: <strong>${demoJobs.length}</strong> вакансии`;
1041  document.getElementById('heroCount').textContent = demoJobs.length + ' вакансии';
1042  document.getElementById('emptyJobs').style.display = 'none';
1043  const list = document.getElementById('jobsList');
1044  list.innerHTML = '';
1045  demoJobs.forEach(j => list.appendChild(makeJobCard(j)));
1046}
1047
1048// ── Type chooser ──────────────────────────────────────────────────────────────
1049function chooseType(type) {
1050  document.getElementById('stepChoose').style.display = 'none';
1051  document.getElementById('formVacancy').style.display = type === 'vacancy' ? 'block' : 'none';
1052  document.getElementById('formResume').style.display = type === 'resume' ? 'block' : 'none';
1053}
1054
1055function backToChoose() {
1056  document.getElementById('stepChoose').style.display = 'block';
1057  document.getElementById('formVacancy').style.display = 'none';
1058  document.getElementById('formResume').style.display = 'none';
1059}
1060
1061// ── Submit vacancy ────────────────────────────────────────────────────────────
1062async function submitVacancy() {
1063  const company = document.getElementById('vCompany').value.trim();
1064  const title = document.getElementById('vTitle').value.trim();
1065  const industry = document.getElementById('vIndustry').value;
1066  const city = document.getElementById('vCity').value.trim();
1067  const phone = document.getElementById('vPhone').value.trim();
1068  const tg = document.getElementById('vTg').value.trim();
1069  const errEl = document.getElementById('vacancyError');
1070
1071  if (!company) { errEl.textContent = 'Введите название компании'; errEl.style.display = 'block'; return; }
1072  if (!title) { errEl.textContent = 'Введите должность'; errEl.style.display = 'block'; return; }
1073  if (!industry) { errEl.textContent = 'Выберите отрасль'; errEl.style.display = 'block'; return; }
1074  if (!city) { errEl.textContent = 'Укажите город'; errEl.style.display = 'block'; return; }
1075  if (!phone && !tg) { errEl.textContent = 'Укажите способ связи'; errEl.style.display = 'block'; return; }
1076
1077  errEl.style.display = 'none';
1078  const btn = document.querySelector('#formVacancy .btn-submit');
1079  btn.disabled = true; btn.textContent = 'Публикуем…';
1080
1081  try {
1082    const res = await fetch(API + '/jobs', {
1083      method: 'POST',
1084      headers: { 'Content-Type': 'application/json', ...authHeaders() },
1085      body: JSON.stringify({
1086        title, company,
1087        company_description: document.getElementById('vCompanyDesc').value.trim() || null,
1088        category_slug: industry, city,
1089        employment_type: document.getElementById('vType').value,
1090        salary_from: parseInt(document.getElementById('vSalaryFrom').value) || null,
1091        salary_to: parseInt(document.getElementById('vSalaryTo').value) || null,
1092        description: document.getElementById('vDesc').value.trim() || null,
1093        phone: phone || null,
1094        telegram_username: tg || null,
1095      })
1096    });
1097    if (!res.ok) throw new Error((await res.json().catch(()=>({}))).detail || 'Ошибка');
1098    showSuccess('formVacancy', 'Вакансия опубликована!');
1099  } catch(e) {
1100    errEl.textContent = e.message; errEl.style.display = 'block';
1101    btn.disabled = false; btn.textContent = 'Опубликовать вакансию бесплатно';
1102  }
1103}
1104
1105// ── Submit resume ─────────────────────────────────────────────────────────────
1106async function submitResume() {
1107  const name = document.getElementById('rName').value.trim();
1108  const title = document.getElementById('rTitle').value.trim();
1109  const city = document.getElementById('rCity').value.trim();
1110  const phone = document.getElementById('rPhone').value.trim();
1111  const tg = document.getElementById('rTg').value.trim();
1112  const errEl = document.getElementById('resumeError');
1113
1114  if (!name) { errEl.textContent = 'Введите имя'; errEl.style.display = 'block'; return; }
1115  if (!title) { errEl.textContent = 'Введите желаемую должность'; errEl.style.display = 'block'; return; }
1116  if (!city) { errEl.textContent = 'Укажите город'; errEl.style.display = 'block'; return; }
1117  if (!phone && !tg) { errEl.textContent = 'Укажите способ связи'; errEl.style.display = 'block'; return; }
1118
1119  errEl.style.display = 'none';
1120  const btn = document.querySelector('#formResume .btn-submit');
1121  btn.disabled = true; btn.textContent = 'Публикуем…';
1122
1123  try {
1124    const res = await fetch(API + '/resumes', {
1125      method: 'POST',
1126      headers: { 'Content-Type': 'application/json', ...authHeaders() },
1127      body: JSON.stringify({
1128        name, title, city,
1129        category_slug: document.getElementById('rIndustry').value || null,
1130        experience: document.getElementById('rExp').value,
1131        employment_type: document.getElementById('rType').value,
1132        salary_from: parseInt(document.getElementById('rSalary').value) || null,
1133        about: document.getElementById('rAbout').value.trim() || null,
1134        description: document.getElementById('rDesc').value.trim() || null,
1135        phone: phone || null,
1136        telegram_username: tg || null,
1137      })
1138    });
1139    if (!res.ok) throw new Error((await res.json().catch(()=>({}))).detail || 'Ошибка');
1140    showSuccess('formResume', 'Резюме опубликовано!');
1141  } catch(e) {
1142    errEl.textContent = e.message; errEl.style.display = 'block';
1143    btn.disabled = false; btn.textContent = 'Опубликовать резюме бесплатно';
1144  }
1145}
1146
1147function showSuccess(formId, msg) {
1148  document.querySelector(`#${formId} .form-card`).innerHTML = `
1149    <div style="text-align:center;padding:40px;">
1150      <svg width="52" height="52" viewBox="0 0 24 24" fill="none" stroke="#059669" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" style="margin-bottom:16px;"><circle cx="12" cy="12" r="10"/><polyline points="8 12 11 15 16 9"/></svg>
1151      <h2 style="font-family:'Montserrat',sans-serif;font-weight:800;font-size:22px;color:var(--navy);margin-bottom:12px;">${msg}</h2>
1152      <p style="color:var(--muted);margin-bottom:24px;">Ваше объявление уже видно соискателям.</p>
1153      <button onclick="showTab('vacancies')" style="padding:12px 28px;background:var(--orange);color:white;border:none;border-radius:8px;font-size:14px;font-weight:600;cursor:pointer;font-family:inherit;">Смотреть вакансии →</button>
1154    </div>`;
1155}
1156
1157// ── Search ────────────────────────────────────────────────────────────────────
1158function doSearch() {
1159  filters = {
1160    search: document.getElementById('fSearch').value.trim(),
1161    industry: document.getElementById('fIndustry').value,
1162    city: document.getElementById('fCity').value.trim(),
1163    type: document.getElementById('fType').value,
1164  };
1165  loadJobs();
1166}
1167
1168// ── Geo Autocomplete ──────────────────────────────────────────────────────────
1169async function geoSuggest(input, dropId) {
1170  const q = input.value.trim();
1171  const drop = document.getElementById(dropId);
1172  if (!drop) return;
1173  if (q.length < 2) { drop.classList.remove('open'); return; }
1174  clearTimeout(geoTimer);
1175  geoTimer = setTimeout(async () => {
1176    try {
1177      const res = await fetch(API + '/geo/suggest?q=' + encodeURIComponent(q));
1178      const data = await res.json();
1179      const items = data.suggestions || [];
1180      if (!items.length) { drop.classList.remove('open'); return; }
1181      drop.innerHTML = items.map(s =>
1182        `<div class="geo-option" onclick="geoSelect('${esc(s.name)}','${input.id}','${dropId}')">${esc(s.name)}</div>`
1183      ).join('');
1184      drop.classList.add('open');
1185    } catch(e) {}
1186  }, 200);
1187}
1188
1189function geoSelect(val, inputId, dropId) {
1190  const input = document.getElementById(inputId);
1191  const drop = document.getElementById(dropId);
1192  if (input) input.value = val;
1193  if (drop) { drop.classList.remove('open'); }
1194}
1195
1196function geoKeydown(e, input, dropId) {
1197  const drop = document.getElementById(dropId);
1198  if (!drop || !drop.classList.contains('open')) return;
1199  const items = drop.querySelectorAll('.geo-option');
1200  const active = drop.querySelector('.geo-option.active');
1201  let idx = Array.from(items).indexOf(active);
1202  if (e.key === 'ArrowDown') { e.preventDefault(); if (active) active.classList.remove('active'); items[Math.min(idx+1,items.length-1)]?.classList.add('active'); }
1203  else if (e.key === 'ArrowUp') { e.preventDefault(); if (active) active.classList.remove('active'); items[Math.max(idx-1,0)]?.classList.add('active'); }
1204  else if (e.key === 'Enter' && active) { e.preventDefault(); geoSelect(active.textContent, input.id, dropId); }
1205  else if (e.key === 'Escape') drop.classList.remove('open');
1206}
1207
1208document.addEventListener('click', e => {
1209  document.querySelectorAll('.geo-dropdown.open').forEach(d => {
1210    if (!d.previousElementSibling?.contains(e.target)) d.classList.remove('open');
1211  });
1212});
1213
1214// ── Utils ─────────────────────────────────────────────────────────────────────
1215function esc(s) {
1216  return String(s||'').replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/"/g,'&quot;');
1217}
1218function timeAgo(iso) {
1219  if (!iso) return '';
1220  const diff = (Date.now() - new Date(iso)) / 1000;
1221  if (diff < 3600) return Math.floor(diff/60) + ' мин назад';
1222  if (diff < 86400) return Math.floor(diff/3600) + ' ч назад';
1223  if (diff < 604800) return Math.floor(diff/86400) + ' дн назад';
1224  return new Date(iso).toLocaleDateString('ru-RU');
1225}
1226
1227// Init
1228const _newParam = new URLSearchParams(window.location.search).get('new');
1229if (_newParam === 'vacancy') { showTab('new'); chooseType('vacancy'); }
1230else if (_newParam === 'resume') { showTab('new'); chooseType('resume'); }
1231else loadJobs();
1232</script>
1232
1233</body>
1234</html>

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.