// СУ 47 — Interactive tools: combobox, validation, volume helper, quote flow.
// One merged estimate→order flow (QuoteFlow). The volume-from-dimensions helper
// is folded in as an optional collapsible inside the flow's volume step.

const { useState, useMemo, useEffect, useRef, useId } = React;

/* =====================================================
   Combobox — searchable, keyboard-accessible select.
   Replaces native <select> for long lists (districts).
   options: [{ value, label, hint? }]
   ===================================================== */
function Combobox({ value, onChange, options, placeholder = 'Выберите…', searchPlaceholder = 'Поиск…', theme = 'light' }) {
  const [open, setOpen] = useState(false);
  const [query, setQuery] = useState('');
  const [active, setActive] = useState(0);
  const rootRef = useRef(null);
  const inputRef = useRef(null);
  const listRef = useRef(null);
  const baseId = useId();

  const selected = options.find(o => o.value === value) || null;

  const filtered = useMemo(() => {
    const q = query.trim().toLowerCase();
    if (!q) return options;
    return options.filter(o => o.label.toLowerCase().includes(q) || (o.hint || '').toLowerCase().includes(q));
  }, [query, options]);

  // Close on outside click.
  useEffect(() => {
    if (!open) return;
    const onDoc = (e) => { if (rootRef.current && !rootRef.current.contains(e.target)) close(); };
    document.addEventListener('mousedown', onDoc);
    return () => document.removeEventListener('mousedown', onDoc);
  }, [open]);

  // Focus search when opening; reset active to selected.
  useEffect(() => {
    if (open) {
      setQuery('');
      const idx = Math.max(0, options.findIndex(o => o.value === value));
      setActive(idx);
      requestAnimationFrame(() => inputRef.current?.focus());
    }
  }, [open]);

  // Keep active option scrolled into view.
  useEffect(() => {
    if (!open || !listRef.current) return;
    const el = listRef.current.querySelector(`[data-idx="${active}"]`);
    el?.scrollIntoView({ block: 'nearest' });
  }, [active, open]);

  const close = () => { setOpen(false); setQuery(''); };
  const choose = (opt) => { if (!opt) return; onChange(opt.value); close(); };

  const onKeyDown = (e) => {
    if (!open && (e.key === 'ArrowDown' || e.key === 'Enter' || e.key === ' ')) { e.preventDefault(); setOpen(true); return; }
    if (!open) return;
    if (e.key === 'ArrowDown') { e.preventDefault(); setActive(a => Math.min(a + 1, filtered.length - 1)); }
    else if (e.key === 'ArrowUp') { e.preventDefault(); setActive(a => Math.max(a - 1, 0)); }
    else if (e.key === 'Enter') { e.preventDefault(); choose(filtered[active]); }
    else if (e.key === 'Escape') { e.preventDefault(); close(); }
    else if (e.key === 'Home') { e.preventDefault(); setActive(0); }
    else if (e.key === 'End') { e.preventDefault(); setActive(filtered.length - 1); }
  };

  return (
    <div className={`combo combo--${theme} ${open ? 'combo--open' : ''}`} ref={rootRef}>
      <button
        type="button"
        className={`combo__trigger ${selected ? '' : 'combo__trigger--empty'}`}
        aria-haspopup="listbox"
        aria-expanded={open}
        onClick={() => setOpen(o => !o)}
        onKeyDown={onKeyDown}
      >
        <span className="combo__value">
          {selected ? selected.label : placeholder}
          {selected?.hint && <span className="combo__value-hint">{selected.hint}</span>}
        </span>
        <span className="combo__chevron" aria-hidden="true">▾</span>
      </button>

      {open && (
        <div className="combo__panel" role="dialog">
          <div className="combo__search">
            <input
              ref={inputRef}
              className="combo__search-input"
              type="text"
              role="combobox"
              aria-controls={`${baseId}-list`}
              aria-expanded="true"
              aria-autocomplete="list"
              aria-activedescendant={filtered.length ? `${baseId}-opt-${active}` : undefined}
              value={query}
              placeholder={searchPlaceholder}
              onChange={e => { setQuery(e.target.value); setActive(0); }}
              onKeyDown={onKeyDown}
            />
          </div>
          <ul className="combo__list" id={`${baseId}-list`} role="listbox" ref={listRef}>
            {filtered.length === 0 && <li className="combo__empty">Ничего не найдено</li>}
            {filtered.map((o, i) => (
              <li
                key={o.value}
                id={`${baseId}-opt-${i}`}
                data-idx={i}
                role="option"
                aria-selected={o.value === value}
                className={`combo__option ${i === active ? 'combo__option--active' : ''} ${o.value === value ? 'combo__option--selected' : ''}`}
                onMouseEnter={() => setActive(i)}
                onMouseDown={(e) => { e.preventDefault(); choose(o); }}
              >
                <span className="combo__option-label">{o.label}</span>
                {o.hint && <span className="combo__option-hint">{o.hint}</span>}
              </li>
            ))}
          </ul>
        </div>
      )}
    </div>
  );
}

/* =====================================================
   Validation + submission helpers
   ===================================================== */
function phoneDigits(raw) {
  let d = (raw || '').replace(/\D/g, '');
  if (d.startsWith('8')) d = '7' + d.slice(1);
  if (d && !d.startsWith('7')) d = '7' + d;
  return d.slice(0, 11);
}
function formatRuPhone(raw) {
  const p = phoneDigits(raw).slice(1); // 10 digits after country code
  let out = '+7';
  if (p.length > 0) out += ' (' + p.slice(0, 3);
  if (p.length >= 3) out += ') ' + p.slice(3, 6);
  if (p.length >= 6) out += '-' + p.slice(6, 8);
  if (p.length >= 8) out += '-' + p.slice(8, 10);
  return out;
}
const isValidPhone = (raw) => phoneDigits(raw).length === 11;
const isValidEmail = (e) => /^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/.test((e || '').trim());
const isValidName = (n) => (n || '').trim().length >= 2;

// Abstracted submission seam — POSTs to /api/quote. The lead-delivery mechanism
// (Telegram / email / store) lives behind that endpoint and is intentionally
// left open; the UI only needs an { ok } result.
async function submitQuote(payload) {
  try {
    const res = await fetch('/api/quote', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(payload),
    });
    if (!res.ok) return { ok: false };
    return await res.json();
  } catch {
    return { ok: false };
  }
}

/* =====================================================
   Volume-from-dimensions helper.
   Used inline (collapsible) inside the quote's volume step;
   onApply(volume) fills the order's volume field.
   ===================================================== */
function VolumeHelper({ onApply }) {
  const [type, setType] = useState('strip'); // strip | slab | column
  const [vals, setVals] = useState({
    length: 10, width: 8, stripWidth: 0.4, height: 0.8,
    slabL: 10, slabW: 8, slabH: 0.2,
    colD: 0.4, colH: 3, colN: 6
  });

  const volume = useMemo(() => {
    if (type === 'strip') {
      const perimeter = 2 * (Number(vals.length) + Number(vals.width));
      return perimeter * Number(vals.stripWidth) * Number(vals.height);
    }
    if (type === 'slab') {
      return Number(vals.slabL) * Number(vals.slabW) * Number(vals.slabH);
    }
    if (type === 'column') {
      return Math.PI * Math.pow(Number(vals.colD) / 2, 2) * Number(vals.colH) * Number(vals.colN);
    }
    return 0;
  }, [type, vals]);

  const withReserve = Math.max(1, Math.ceil(volume * 1.07));
  const upd = (k, v) => setVals(s => ({ ...s, [k]: v }));

  return (
    <div className="vhelp__body">
      <div className="vhelp__types" role="group" aria-label="Тип конструкции">
        <button type="button" className={`vhelp__type ${type === 'strip' ? 'vhelp__type--active' : ''}`} onClick={() => setType('strip')}>Ленточный фундамент</button>
        <button type="button" className={`vhelp__type ${type === 'slab' ? 'vhelp__type--active' : ''}`} onClick={() => setType('slab')}>Монолитная плита</button>
        <button type="button" className={`vhelp__type ${type === 'column' ? 'vhelp__type--active' : ''}`} onClick={() => setType('column')}>Столбы / сваи</button>
      </div>

      {type === 'strip' && (
        <div className="vhelp__fields">
          <div><label className="label">Длина, м</label><input className="input" type="number" inputMode="decimal" value={vals.length} onChange={e => upd('length', e.target.value)} /></div>
          <div><label className="label">Ширина, м</label><input className="input" type="number" inputMode="decimal" value={vals.width} onChange={e => upd('width', e.target.value)} /></div>
          <div><label className="label">Ширина ленты, м</label><input className="input" type="number" inputMode="decimal" step="0.05" value={vals.stripWidth} onChange={e => upd('stripWidth', e.target.value)} /></div>
          <div><label className="label">Высота, м</label><input className="input" type="number" inputMode="decimal" step="0.1" value={vals.height} onChange={e => upd('height', e.target.value)} /></div>
        </div>
      )}
      {type === 'slab' && (
        <div className="vhelp__fields">
          <div><label className="label">Длина, м</label><input className="input" type="number" inputMode="decimal" value={vals.slabL} onChange={e => upd('slabL', e.target.value)} /></div>
          <div><label className="label">Ширина, м</label><input className="input" type="number" inputMode="decimal" value={vals.slabW} onChange={e => upd('slabW', e.target.value)} /></div>
          <div><label className="label">Толщина, м</label><input className="input" type="number" inputMode="decimal" step="0.05" value={vals.slabH} onChange={e => upd('slabH', e.target.value)} /></div>
        </div>
      )}
      {type === 'column' && (
        <div className="vhelp__fields">
          <div><label className="label">Диаметр, м</label><input className="input" type="number" inputMode="decimal" step="0.05" value={vals.colD} onChange={e => upd('colD', e.target.value)} /></div>
          <div><label className="label">Высота, м</label><input className="input" type="number" inputMode="decimal" step="0.1" value={vals.colH} onChange={e => upd('colH', e.target.value)} /></div>
          <div><label className="label">Количество, шт</label><input className="input" type="number" inputMode="numeric" value={vals.colN} onChange={e => upd('colN', e.target.value)} /></div>
        </div>
      )}

      <div className="vhelp__result">
        <div className="vhelp__result-main">
          <span className="vhelp__result-label">К&nbsp;заказу с&nbsp;запасом 7%</span>
          <span className="vhelp__result-v">{withReserve}<small>м³</small></span>
          <p className="vhelp__note">Чистый объём {volume.toFixed(1)}&nbsp;м³&nbsp;· {Math.max(1, Math.ceil(withReserve / 7))} миксер(ов) по&nbsp;7&nbsp;м³</p>
        </div>
        <button type="button" className="btn btn--rust btn--sm" onClick={() => onApply(withReserve)}>
          Подставить {withReserve}&nbsp;м³
        </button>
      </div>
    </div>
  );
}

/* =====================================================
   Quote / order flow — the single merged estimate→order spine.
   purpose → grade → volume+date → district → contacts → success.
   Live running total; volume step folds in the dimension helper.
   ===================================================== */
function QuoteFlow() {
  const [step, setStep] = useState(0);
  const [data, setData] = useState({
    purpose: null,      // 0
    grade: null,        // 1
    volume: 10,         // 2
    district: null,     // 3
    date: '',           // 2
    pump: false,
    name: '',
    phone: '',
    email: '',
    comment: '',
    website: ''        // honeypot — must stay empty; only bots fill it
  });
  const [touched, setTouched] = useState({});
  const [submitting, setSubmitting] = useState(false);
  const [submitError, setSubmitError] = useState(null);
  const [helperOpen, setHelperOpen] = useState(false);
  const bodyRef = useRef(null);
  const firstRender = useRef(true);
  // When the form first mounted — lets the server tell a human (seconds to fill)
  // from a bot that posts instantly. Reset on a new estimate.
  const openedAt = useRef(Date.now());
  const today = new Date().toISOString().slice(0, 10);

  // Deep-link from the price table: a grade click pre-selects it and jumps
  // straight to the volume step — no re-picking purpose + grade by hand.
  useEffect(() => {
    const onSelectGrade = (e) => {
      const g = e.detail?.grade;
      if (!g || !SU47_DATA.gradeInfo[g]) return;
      setData(d => ({ ...d, grade: g }));
      setStep(2);
    };
    window.addEventListener('su47:selectGrade', onSelectGrade);
    return () => window.removeEventListener('su47:selectGrade', onSelectGrade);
  }, []);

  // Each step has a different height; after a step change bring the form's top
  // just under the nav so Back/Next/option-picks always land in a sane place.
  useEffect(() => {
    if (firstRender.current) { firstRender.current = false; return; }
    const el = bodyRef.current;
    if (!el) return;
    // Only re-anchor when the form top isn't already sitting just under the nav
    // (skips a needless jump on desktop where the whole flow is usually visible).
    const top = el.getBoundingClientRect().top;
    if (top >= 64 && top <= 160) return;
    const reduce = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
    const y = top + window.scrollY - 76;
    window.scrollTo({ top: y, behavior: reduce ? 'auto' : 'smooth' });
  }, [step]);

  const errors = {
    name: isValidName(data.name) ? null : 'Укажите имя (минимум 2 символа)',
    phone: isValidPhone(data.phone) ? null : 'Введите номер полностью: +7 (___) ___-__-__',
    email: !data.email.trim() || isValidEmail(data.email) ? null : 'Проверьте адрес — например, name@mail.ru',
  };

  const steps = [
    { key: 'purpose', title: 'Что заливаете' },
    { key: 'grade', title: 'Марка бетона' },
    { key: 'volume', title: 'Объём и дата' },
    { key: 'district', title: 'Доставка' },
    { key: 'contact', title: 'Контакты' },
  ];

  const upd = (k, v) => setData(s => ({ ...s, [k]: v }));
  const next = () => setStep(s => Math.min(s + 1, steps.length));
  const prev = () => { setSubmitError(null); setStep(s => Math.max(s - 1, 0)); };
  const touch = (k) => setTouched(t => ({ ...t, [k]: true }));

  const gradePrice = data.grade ? SU47_DATA.gradeInfo[data.grade].price : 0;
  const deliveryPer = data.district ? SU47_DATA.districts.find(d => d.name === data.district)?.price || 0 : 0;
  const total = (gradePrice * data.volume) + (deliveryPer * data.volume) + (data.pump ? 35000 : 0);

  const contactValid = !errors.name && !errors.phone && !errors.email;
  const canNext = () => {
    if (step === 0) return !!data.purpose;
    if (step === 1) return !!data.grade;
    if (step === 2) return data.volume > 0;
    if (step === 3) return !!data.district;
    if (step === 4) return contactValid;
    return true;
  };

  const handleSubmit = async () => {
    setTouched({ name: true, phone: true, email: true });
    if (!contactValid) return;
    setSubmitting(true);
    setSubmitError(null);
    const res = await submitQuote({
      ...data,
      phone: '+' + phoneDigits(data.phone),
      total,
      createdAt: new Date().toISOString(),
      _elapsed: Date.now() - openedAt.current,   // ms the form was open (bot check)
    });
    setSubmitting(false);
    if (res.ok) setStep(5);
    else setSubmitError('Не удалось отправить заявку. Попробуйте ещё раз или позвоните нам напрямую.');
  };

  const reset = () => {
    setStep(0); setTouched({}); setSubmitError(null); setHelperOpen(false);
    openedAt.current = Date.now();
    setData({ purpose: null, grade: null, volume: 10, district: null, date: '', pump: false, name: '', phone: '', email: '', comment: '', website: '' });
  };

  return (
    <div className="quote" data-scroll="quote">
      <aside className="quote__aside">
        <span className="quote__aside-eyebrow">Расчёт&nbsp;и&nbsp;заявка</span>
        <h2 className="quote__aside-title">Рассчитать и&nbsp;заказать</h2>
        <p className="quote__aside-sub">Посчитайте точную стоимость с&nbsp;доставкой и&nbsp;оставьте заявку — в&nbsp;одном потоке. Пять шагов до&nbsp;точной цены; менеджер перезвонит и&nbsp;подтвердит заказ.</p>
        <ol className="quote__steps">
          {steps.map((s, i) => (
            <li key={i} className={`quote__step ${i === step ? 'quote__step--active' : ''} ${i < step || step === 5 ? 'quote__step--done' : ''}`}>
              <span className="quote__step-num">{String(i + 1).padStart(2, '0')}</span>
              <span className="quote__step-title">{s.title}</span>
              {(i < step || step === 5) && <span className="quote__step-check" aria-hidden="true">✓</span>}
            </li>
          ))}
        </ol>
      </aside>

      <div className="quote__body" ref={bodyRef}>
        <div className="quote__view" key={step}>
        {step === 0 && (
          <>
            <div>
              <div className="quote__q-title">Что вы&nbsp;заливаете?</div>
              <div className="quote__q-sub">Подскажем подходящую марку под&nbsp;задачу</div>
            </div>
            <div className="quote__options">
              {[
                { k: 'foundation', t: 'Фундамент', s: 'лента · плита · сваи' },
                { k: 'floor', t: 'Пол / стяжка', s: 'внутри / снаружи' },
                { k: 'slab', t: 'Перекрытие', s: 'монолитные плиты' },
                { k: 'industrial', t: 'Промышленный', s: 'цех · склад · площадка' },
                { k: 'prep', t: 'Подготовка', s: 'подбетонка · бордюры' },
                { k: 'other', t: 'Другое', s: 'уточнить с менеджером' },
              ].map(o => (
                <button key={o.k} type="button" className={`quote__option ${data.purpose === o.k ? 'quote__option--active' : ''}`} onClick={() => { upd('purpose', o.k); setTimeout(next, 180); }}>
                  <span className="quote__option-title">{o.t}</span>
                  <span className="quote__option-sub">{o.s}</span>
                </button>
              ))}
            </div>
          </>
        )}

        {step === 1 && (
          <>
            <div>
              <div className="quote__q-title">Какая марка?</div>
              <div className="quote__q-sub">Не&nbsp;уверены в&nbsp;марке? М300 подходит для большинства задач.</div>
            </div>
            <div className="quote__options">
              {Object.keys(SU47_DATA.gradeInfo).map(g => (
                <button key={g} type="button" className={`quote__option ${data.grade === g ? 'quote__option--active' : ''}`} onClick={() => { upd('grade', g); setTimeout(next, 180); }}>
                  <span className="quote__option-title">{g}</span>
                  <span className="quote__option-sub">{SU47_DATA.gradeInfo[g].price.toLocaleString('ru')}&nbsp;₽/м³</span>
                </button>
              ))}
            </div>
          </>
        )}

        {step === 2 && (
          <>
            <div>
              <div className="quote__q-title">Сколько и&nbsp;когда?</div>
              <div className="quote__q-sub">Объём в&nbsp;м³ и&nbsp;желаемая дата поставки</div>
            </div>
            <div className="quote__grid2">
              <div>
                <label className="label" htmlFor="q-volume">Объём, м³</label>
                <input id="q-volume" className="input" type="number" inputMode="decimal" min="1" value={data.volume} onChange={e => upd('volume', Number(e.target.value))} />
              </div>
              <div>
                <label className="label" htmlFor="q-date">Желаемая дата</label>
                <input id="q-date" className="input input--date" type="date" min={today} value={data.date} onChange={e => upd('date', e.target.value)} />
              </div>
            </div>

            <div className={`vhelp ${helperOpen ? 'vhelp--open' : ''}`}>
              <button type="button" className="vhelp__toggle" aria-expanded={helperOpen} onClick={() => setHelperOpen(o => !o)}>
                Не знаете объём? Посчитайте по размерам
                <span className="vhelp__chev" aria-hidden="true">▾</span>
              </button>
              {helperOpen && <VolumeHelper onApply={(v) => { upd('volume', v); setHelperOpen(false); }} />}
            </div>

            <label className="quote__check">
              <input type="checkbox" checked={data.pump} onChange={e => upd('pump', e.target.checked)} />
              <span>Нужен бетононасос <small>· +7&nbsp;000&nbsp;₽/час, минимум 5&nbsp;часов</small></span>
            </label>
          </>
        )}

        {step === 3 && (
          <>
            <div>
              <div className="quote__q-title">Куда доставить?</div>
              <div className="quote__q-sub">Начните вводить название — список отфильтруется</div>
            </div>
            <div>
              <label className="label">Населённый пункт или&nbsp;район</label>
              <Combobox
                theme="dark"
                value={data.district || ''}
                onChange={v => upd('district', v)}
                options={SU47_DATA.districts.map(d => ({ value: d.name, label: d.name, hint: `+${d.price} ₽/м³` }))}
                placeholder="Выберите место доставки"
                searchPlaceholder="Район, посёлок, город…"
              />
            </div>
          </>
        )}

        {step === 4 && (
          <>
            <div>
              <div className="quote__q-title">Почти готово</div>
              <div className="quote__q-sub">Оставьте контакты — менеджер перезвонит в&nbsp;течение 15&nbsp;минут</div>
            </div>
            <div className="quote__grid2">
              <div className="field">
                <label className="label" htmlFor="q-name">Имя <span className="field__req">*</span></label>
                <input
                  id="q-name"
                  className={`input ${touched.name && errors.name ? 'input--error' : ''}`}
                  value={data.name}
                  maxLength={80}
                  onChange={e => upd('name', e.target.value)}
                  onBlur={() => touch('name')}
                  aria-invalid={!!(touched.name && errors.name)}
                  placeholder="Как к вам обращаться"
                />
                {touched.name && errors.name && <span className="field__error">{errors.name}</span>}
              </div>
              <div className="field">
                <label className="label" htmlFor="q-phone">Телефон <span className="field__req">*</span></label>
                <input
                  id="q-phone"
                  className={`input ${touched.phone && errors.phone ? 'input--error' : ''}`}
                  type="tel"
                  inputMode="tel"
                  value={data.phone}
                  onChange={e => upd('phone', formatRuPhone(e.target.value))}
                  onBlur={() => touch('phone')}
                  aria-invalid={!!(touched.phone && errors.phone)}
                  placeholder="+7 (___) ___-__-__"
                />
                {touched.phone && errors.phone && <span className="field__error">{errors.phone}</span>}
              </div>
            </div>
            <div className="field">
              <label className="label" htmlFor="q-email">E-mail <span className="field__opt">— по&nbsp;желанию, пришлём расчёт</span></label>
              <input
                id="q-email"
                className={`input ${touched.email && errors.email ? 'input--error' : ''}`}
                type="email"
                inputMode="email"
                value={data.email}
                onChange={e => upd('email', e.target.value)}
                onBlur={() => touch('email')}
                aria-invalid={!!(touched.email && errors.email)}
                placeholder="name@mail.ru"
              />
              {touched.email && errors.email && <span className="field__error">{errors.email}</span>}
            </div>
            <div className="field">
              <label className="label" htmlFor="q-comment">Комментарий</label>
              <textarea id="q-comment" className="textarea" rows="3" maxLength={1000} value={data.comment} onChange={e => upd('comment', e.target.value)} placeholder="Особенности объекта, подъезд, пожелания" />
            </div>

            {/* Honeypot: hidden from people, but bots fill every field they see.
                A non-empty value makes the server silently drop the submission.
                Off-screen (not display:none) + aria-hidden + tabIndex -1 so screen
                readers and keyboard users skip it entirely. */}
            <input
              type="text"
              name="website"
              tabIndex={-1}
              autoComplete="off"
              aria-hidden="true"
              value={data.website}
              onChange={e => upd('website', e.target.value)}
              style={{ position: 'absolute', left: '-9999px', width: 1, height: 1, opacity: 0 }}
            />

            <div className="quote__summary">
              <div className="quote__summary-line"><span className="quote__summary-k">Марка</span><span className="quote__summary-v">{data.grade || '—'}</span></div>
              <div className="quote__summary-line"><span className="quote__summary-k">Объём</span><span className="quote__summary-v">{data.volume}&nbsp;м³</span></div>
              <div className="quote__summary-line"><span className="quote__summary-k">Куда</span><span className="quote__summary-v">{data.district || '—'}</span></div>
              <div className="quote__summary-line"><span className="quote__summary-k">Дата</span><span className="quote__summary-v">{data.date || 'по согласованию'}</span></div>
            </div>
            <p className="quote__consent">Нажимая «Отправить заявку», вы&nbsp;соглашаетесь с&nbsp;политикой обработки персональных данных.</p>
          </>
        )}

        {step === 5 && (
          <div className="quote__success">
            <span className="quote__success-badge"><span aria-hidden="true">✓</span> Заявка принята</span>
            <p>
              Получили ваш расчёт на&nbsp;<strong>{total.toLocaleString('ru')}&nbsp;₽</strong>. Менеджер перезвонит на&nbsp;{data.phone || 'указанный номер'} в&nbsp;течение 15&nbsp;минут — подтвердит детали и&nbsp;согласует время доставки.
            </p>
            <button type="button" className="btn btn--ghost-dark" onClick={reset}>Новый расчёт</button>
          </div>
        )}
        </div>

        {step > 0 && step < 5 && (
          <div className="quote__total" aria-live="polite">
            <span className="quote__total-k">Предварительно</span>
            <span className="quote__total-v">{total.toLocaleString('ru')} ₽</span>
          </div>
        )}

        {step < 5 && (
          <div className="quote__navwrap">
            {submitError && <div className="quote__submit-error" role="alert">{submitError}</div>}
            {step === 4 && !contactValid && Object.values(touched).some(Boolean) && (
              <div className="quote__hint">Заполните имя и&nbsp;телефон, чтобы отправить заявку.</div>
            )}
            <div className="quote__nav">
              <button type="button" className="btn btn--ghost-dark" onClick={prev} disabled={step === 0 || submitting}>← Назад</button>
              {step === 4 ? (
                <button type="button" className="btn btn--rust" disabled={submitting} onClick={handleSubmit}>
                  {submitting ? 'Отправляем…' : 'Отправить заявку'}
                </button>
              ) : (
                <button type="button" className="btn btn--rust" disabled={!canNext()} onClick={next}>
                  Далее →
                </button>
              )}
            </div>
          </div>
        )}
      </div>
    </div>
  );
}

Object.assign(window, { Combobox, VolumeHelper, QuoteFlow, submitQuote, phoneDigits, formatRuPhone });
