// variant-b-mobile.jsx
// Mobile-optimized layout of Variant B for the iOS-frame prototype.
// Reuses BFormProvider/useBForm/calcQuote from variant-b-form.jsx so the form state,
// pricing, submit modal, and success state are shared with the desktop prototype.
//
// Mobile-specific decisions:
// • Single-column everything. Type ramp is tighter (~38px headings instead of 96px).
// • Hero leads with one big CTA + phone — form lives further down the page.
// • Bottom sheets replace the desktop popovers for Size / Date / Time.
// • Sticky bottom CTA bar sits inside the iOS frame, above the home indicator.
// • Submit modal renders as an absolute overlay scoped to the iOS device, not viewport-fixed.

const DEVICE_W = 402;
const DEVICE_H = 874;
const STATUS_BAR_H = 54;
const HOME_INDICATOR_H = 34;
const MOBILE_SITE_MODE = window.SEVEN_SITE_MODE === true;

// ── Small helpers ────────────────────────────────────────────────────────────

function MBadge({ children, light }) {
  return (
    <span style={{
      display: 'inline-flex', alignItems: 'center', gap: 6, fontFamily: bSans,
      fontSize: 10.5, fontWeight: 700, letterSpacing: 1.5, textTransform: 'uppercase',
      color: light ? B.brass : B.brassDeep,
    }}>
      <span style={{ width: 18, height: 1, background: light ? B.brass : B.brass }}/>
      {children}
    </span>
  );
}

function MPrimaryBtn({ children, onClick, style, icon = 'arrow-right' }) {
  return (
    <button
      type="button"
      onClick={onClick || (() => scrollToBookingForm())}
      {...rollover(
        { transform: 'translateY(-2px)', background: B.greenDark, boxShadow: '0 16px 28px -14px color-mix(in srgb, var(--p7-primary) 70%, transparent)' },
        { transform: 'translateY(0)', background: B.green, boxShadow: '0 12px 24px -12px color-mix(in srgb, var(--p7-primary) 60%, transparent)' }
      )}
      style={{
      width: '100%', padding: '17px 18px',
      background: B.green, color: '#fff', border: 'none', borderRadius: 12,
      fontFamily: bSans, fontWeight: 700, fontSize: 16, letterSpacing: 0.1,
      cursor: 'pointer', display: 'inline-flex', alignItems: 'center', justifyContent: 'center', gap: 10,
      boxShadow: '0 12px 24px -12px color-mix(in srgb, var(--p7-primary) 60%, transparent)',
      transition: ROLLOVER_TRANSITION,
      ...style,
    }}>
      {children}
      {icon && <Icon name={icon} size={18} sw={2.2}/>}
    </button>
  );
}

function MGhostBtn({ children, onClick, icon, style }) {
  return (
    <button
      type="button"
      onClick={onClick}
      {...rollover(
        { transform: 'translateY(-2px)', background: B.bg, borderColor: B.green, boxShadow: '0 12px 22px -18px rgba(26,46,38,0.3)' },
        { transform: 'translateY(0)', background: '#fff', borderColor: B.line, boxShadow: 'none' }
      )}
      style={{
      padding: '15px 18px',
      background: '#fff', color: B.ink, border: `1px solid ${B.line}`, borderRadius: 12,
      fontFamily: bSans, fontWeight: 600, fontSize: 15, letterSpacing: 0.1,
      cursor: 'pointer', display: 'inline-flex', alignItems: 'center', justifyContent: 'center', gap: 8,
      transition: ROLLOVER_TRANSITION,
      ...style,
    }}>
      {icon && <Icon name={icon} size={16} sw={2} stroke={B.green}/>}
      {children}
    </button>
  );
}

// ── Top bar (sticky inside scroll area, behind status bar) ──────────────────

function MTopBar() {
  return (
    <div style={{
      position: 'sticky', top: 0, zIndex: 20,
      paddingTop: MOBILE_SITE_MODE ? 0 : STATUS_BAR_H, background: B.bg,
      borderBottom: `1px solid ${B.line}`,
    }}>
      <div style={{
        display: 'flex', alignItems: 'center', justifyContent: 'space-between',
        padding: '10px 18px 12px',
      }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
          <img src={SEVEN.logo} alt={SEVEN.brand} style={{ width: 126, height: 32, objectFit: 'contain', display: 'block' }} />
        </div>
        <div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
          <a href={SEVEN.phoneHref} aria-label="Call us" style={{
            width: 40, height: 40, borderRadius: 12, border: `1px solid ${B.line}`,
            background: '#fff', color: B.green, textDecoration: 'none',
            display: 'grid', placeItems: 'center',
          }}>
            <Icon name="phone" size={16} sw={2}/>
          </a>
          <button type="button" onClick={scrollToBookingForm} style={{
            padding: '10px 14px', background: B.green, color: '#fff', border: 'none',
            borderRadius: 12, fontFamily: bSans, fontSize: 13, fontWeight: 700,
            cursor: 'pointer', transition: ROLLOVER_TRANSITION,
          }}
          {...rollover(
            { transform: 'translateY(-1px)', background: B.greenDark, boxShadow: '0 10px 20px -14px rgba(26,46,38,0.45)' },
            { transform: 'translateY(0)', background: B.green, boxShadow: 'none' }
          )}>Book</button>
        </div>
      </div>
    </div>
  );
}

// ── Hero ────────────────────────────────────────────────────────────────────

function MHero() {
  return (
    <section style={{ padding: '32px 20px 36px', background: B.bg }}>
      <MBadge>For Vancouver · Portland</MBadge>
      <h1 style={{
        fontFamily: bDisplay, fontSize: 44, lineHeight: 1, fontWeight: 800,
        letterSpacing: -1.8, color: B.ink, margin: '14px 0 18px',
      }}>
        Your home,<br/>
        <em style={{ color: B.green, fontStyle: 'normal', position: 'relative' }}>
          spotless
          <svg viewBox="0 0 180 14" preserveAspectRatio="none" style={{
            position: 'absolute', left: 0, right: 0, bottom: -4, width: '100%', height: 10,
          }}>
            <path d="M2 8 C 50 2, 130 2, 178 8" fill="none" stroke={B.brass} strokeWidth="3" strokeLinecap="round"/>
          </svg>
        </em>
        <br/>quietly done.
      </h1>
      <p style={{
        fontFamily: bSans, fontSize: 15.5, lineHeight: 1.55, color: B.ink2,
        margin: '0 0 22px',
      }}>
        Meticulous, eco-friendly cleaners — usually at your door within 48 hours. Flat-rate, fully insured.
      </p>

      <div style={{ display: 'grid', gap: 10, marginBottom: 24 }}>
        <MPrimaryBtn>Get my free quote</MPrimaryBtn>
        <a href={SEVEN.phoneHref} style={{
          padding: '15px 18px', background: '#fff', color: B.ink,
          border: `1px solid ${B.line}`, borderRadius: 12, textDecoration: 'none',
          fontFamily: bSans, fontSize: 15, fontWeight: 600,
          display: 'inline-flex', alignItems: 'center', justifyContent: 'center', gap: 10,
        }}>
          <Icon name="phone" size={16} sw={2} stroke={B.green}/> {SEVEN.phone}
        </a>
      </div>

      {/* Trust strip — compact */}
      <div style={{
        background: '#fff', border: `1px solid ${B.line}`, borderRadius: 12, padding: '14px 16px',
        display: 'grid', gridTemplateColumns: 'auto 1px auto 1px auto', alignItems: 'center', gap: 14,
      }}>
        <div>
          <div style={{ display: 'flex', alignItems: 'center', gap: 4 }}>
            <Stars n={5} size={11} color={B.brass}/>
            <span style={{ fontFamily: bDisplay, fontWeight: 800, color: B.ink, fontSize: 14, marginLeft: 2 }}>4.9</span>
          </div>
          <div style={{ fontSize: 10.5, color: B.muted, marginTop: 2 }}>312 reviews</div>
        </div>
        <span style={{ height: 22, background: B.line }}/>
        <div>
          <div style={{ fontFamily: bDisplay, fontWeight: 800, color: B.ink, fontSize: 14 }}>2,400+</div>
          <div style={{ fontSize: 10.5, color: B.muted, marginTop: 2 }}>Homes</div>
        </div>
        <span style={{ height: 22, background: B.line }}/>
        <div>
          <div style={{ fontFamily: bDisplay, fontWeight: 800, color: B.ink, fontSize: 14 }}>Insured</div>
          <div style={{ fontSize: 10.5, color: B.muted, marginTop: 2 }}>& bonded</div>
        </div>
      </div>
    </section>
  );
}

// ── Selling points ──────────────────────────────────────────────────────────

function MSelling() {
  return (
    <section style={{ background: B.green, color: '#fff', padding: '36px 20px 40px' }}>
      <MBadge light>Why Seven</MBadge>
      <h2 style={{ fontFamily: bDisplay, fontSize: 30, fontWeight: 800, letterSpacing: -1, lineHeight: 1.05, margin: '14px 0 22px' }}>
        Four reasons we're called first.
      </h2>
      <div style={{ display: 'grid', gap: 12 }}>
        {SEVEN.selling.map((s, i) => (
          <div key={i} style={{
            display: 'grid', gridTemplateColumns: '52px 1fr', gap: 16, alignItems: 'flex-start',
            paddingBottom: 16,
            borderBottom: i < SEVEN.selling.length - 1 ? '1px solid rgba(255,255,255,0.15)' : 'none',
          }}>
            <div style={{
              width: 52, height: 52, borderRadius: 12,
              background: 'rgba(255,255,255,0.12)', color: B.brass,
              display: 'grid', placeItems: 'center',
            }}>
              <Icon name={s.icon} size={22} sw={1.7} />
            </div>
            <div>
              <div style={{ fontFamily: bDisplay, fontSize: 17, fontWeight: 700, letterSpacing: -0.3, marginBottom: 4 }}>
                {s.title}
              </div>
              <div style={{ fontFamily: bSans, fontSize: 13.5, color: B.greenSoft, lineHeight: 1.55 }}>
                {s.body}
              </div>
            </div>
          </div>
        ))}
      </div>
    </section>
  );
}

// ── Bottom-sheet primitive (absolutely positioned within the iOS device wrap) ──

function MBottomSheet({ open, onClose, title, children }) {
  // Rendered inside an absolutely-positioned overlay that covers the device frame.
  // The sheet itself slides up from bottom with a CSS transition tracking `open`.
  const overlayStyle = MOBILE_SITE_MODE
    ? { position: 'fixed', inset: 0, zIndex: 80, overflow: 'hidden', pointerEvents: 'auto' }
    : { position: 'absolute', inset: 0, zIndex: 80, borderRadius: 48, overflow: 'hidden', pointerEvents: 'auto' };
  return (
    <>
      <style>{`@keyframes m-sheet-up { from { transform: translateY(100%) } to { transform: translateY(0) } }
                @keyframes m-fade-in  { from { opacity: 0 } to { opacity: 1 } }`}</style>
      {open && (
        <div style={overlayStyle}>
          <div onClick={onClose} style={{
            position: 'absolute', inset: 0, background: 'rgba(20,30,25,0.45)',
            backdropFilter: 'blur(2px)', animation: 'm-fade-in .2s ease-out',
          }}/>
          <div style={{
            position: 'absolute', bottom: 0, left: 0, right: 0,
            background: B.card, borderRadius: '20px 20px 0 0',
            paddingBottom: MOBILE_SITE_MODE ? 'calc(env(safe-area-inset-bottom, 0px) + 16px)' : HOME_INDICATOR_H + 8,
            maxHeight: '78%',
            display: 'flex', flexDirection: 'column',
            boxShadow: '0 -10px 40px -10px rgba(20,30,25,0.25)',
            animation: 'm-sheet-up .28s cubic-bezier(.2,.8,.2,1)',
          }}>
            {/* Grabber */}
            <div style={{
              width: 36, height: 4, borderRadius: 2, background: B.line,
              margin: '10px auto 4px',
            }}/>
            <div style={{
              display: 'flex', alignItems: 'center', justifyContent: 'space-between',
              padding: '8px 20px 14px', borderBottom: `1px solid ${B.line}`,
            }}>
              <div style={{ fontFamily: bDisplay, fontSize: 20, fontWeight: 700, color: B.ink, letterSpacing: -0.4 }}>
                {title}
              </div>
              <button type="button" onClick={onClose} aria-label="close" style={{
                width: 32, height: 32, borderRadius: '50%', border: `1px solid ${B.line}`,
                background: '#fff', color: B.muted, cursor: 'pointer',
                display: 'grid', placeItems: 'center', fontSize: 16, fontWeight: 600,
              }}>×</button>
            </div>
            <div style={{ padding: 20, overflowY: 'auto' }}>
              {children}
            </div>
          </div>
        </div>
      )}
    </>
  );
}

// ── Mobile booking form ─────────────────────────────────────────────────────

function MServiceTabs() {
  const { state, set } = useBForm();
  return (
    <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 8 }}>
      {Object.entries(SVC_LABELS).map(([k, t]) => {
        const on = state.service === k;
        return (
          <button key={k} type="button" onClick={() => set('service', k)} style={{
            display: 'flex', alignItems: 'center', gap: 10,
            padding: '14px 12px', borderRadius: 10,
            border: `1px solid ${on ? B.green : B.line}`,
            background: on ? 'color-mix(in srgb, var(--p7-primary) 14%, transparent)' : '#fff',
            color: on ? B.green : B.ink2,
            fontFamily: bSans, fontWeight: 600, fontSize: 13, letterSpacing: 0.1,
            cursor: 'pointer', transition: 'all .15s', textAlign: 'left',
          }}>
            <Icon name={t.icon} size={18} sw={1.7}/>
            {t.name}
          </button>
        );
      })}
    </div>
  );
}

function MFieldButton({ icon, label, value, onClick, disabled = false }) {
  return (
    <button type="button" onClick={onClick} disabled={disabled} style={{
      width: '100%', textAlign: 'left', background: '#fff',
      border: `1px solid ${B.line}`, borderRadius: 10, padding: '14px 16px',
      display: 'flex', alignItems: 'center', gap: 14, fontFamily: bSans,
      cursor: disabled ? 'not-allowed' : 'pointer', opacity: disabled ? 0.55 : 1,
    }}>
      <Icon name={icon} size={20} sw={1.7} stroke={disabled ? B.muted : B.green}/>
      <div style={{ flex: 1, minWidth: 0 }}>
        <div style={{ fontSize: 10.5, color: B.brassDeep, fontWeight: 700, letterSpacing: 1.4, textTransform: 'uppercase' }}>
          {label}
        </div>
        <div style={{ fontSize: 15, color: B.ink, fontWeight: 600, marginTop: 3, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>
          {value}
        </div>
      </div>
      {!disabled && <Icon name="chevron-down" size={16} sw={2} stroke={B.muted}/>}
    </button>
  );
}

function MBookingForm() {
  const { state, set, quote } = useBForm();
  const isOffice = state.service === 'office';
  const sizeValue = isOffice ? 'Not needed for office' : `${state.bedrooms} bed${state.bedrooms !== 1 ? 's' : ''} · ${state.bathrooms} bath${state.bathrooms !== 1 ? 's' : ''}`;
  const dateValue = formatDate(state.date);
  const timeValue = timeLabel(state.time);
  const zipOk = /^\d{5}$/.test(state.zip);

  const onSubmit = (e) => {
    e.preventDefault();
    if (!zipOk) {
      const zipEl = document.getElementById('m-booking-zip');
      if (zipEl) zipEl.focus();
      return;
    }
    set('modalOpen', true);
  };

  return (
    <section style={{ padding: '40px 20px', background: B.bg }}>
      <MBadge>Reservations</MBadge>
      <h2 style={{ fontFamily: bDisplay, fontSize: 30, fontWeight: 800, letterSpacing: -1, lineHeight: 1.05, margin: '14px 0 6px', color: B.ink }}>
        Get your free quote.
      </h2>
      <p style={{ fontFamily: bSans, fontSize: 14, color: B.muted, marginBottom: 20, lineHeight: 1.5 }}>
        ~60 seconds. We'll text you a flat-rate estimate.
      </p>

      <form id="booking-form" onSubmit={onSubmit} style={{
        background: B.card, border: `1px solid ${B.line}`, borderRadius: 14, padding: 20,
        boxShadow: '0 20px 40px -25px rgba(26,46,38,0.18)',
        position: 'relative',
        scrollMarginTop: STATUS_BAR_H + 20,
      }}>
        <div style={{
          position: 'absolute', top: -1, right: -1, width: 28, height: 28,
          borderTop: `2px solid ${B.brass}`, borderRight: `2px solid ${B.brass}`,
          borderTopRightRadius: 14, pointerEvents: 'none',
        }}/>

        <div style={{ display: 'grid', gap: 12 }}>
          <div>
            <div style={{ fontSize: 10.5, color: B.brassDeep, fontWeight: 700, letterSpacing: 1.4, textTransform: 'uppercase', marginBottom: 8 }}>
              Service
            </div>
            <MServiceTabs />
          </div>

          <MFieldButton icon="home"     label="Home size"      value={sizeValue}  onClick={() => !isOffice && set('openSheet', 'size')} disabled={isOffice} />
          <MFieldButton icon="calendar" label="Preferred date" value={dateValue}  onClick={() => set('openSheet', 'date')} />
          <MFieldButton icon="clock"    label="Time window"    value={timeValue}  onClick={() => set('openSheet', 'time')} />

          {/* ZIP */}
          <div style={{
            border: `1px solid ${zipOk ? B.green : (state.zip && !zipOk ? '#C04D2F' : B.line)}`,
            borderRadius: 10, padding: '10px 16px',
            background: '#fff', display: 'flex', alignItems: 'center', gap: 14,
          }}>
            <Icon name="pin" size={20} sw={1.7} stroke={B.green}/>
            <div style={{ flex: 1 }}>
              <label htmlFor="m-booking-zip" style={{
                display: 'block', fontSize: 10.5, color: B.brassDeep, fontWeight: 700,
                letterSpacing: 1.4, textTransform: 'uppercase',
              }}>ZIP code</label>
              <input
                id="m-booking-zip"
                inputMode="numeric"
                maxLength={5}
                placeholder=""
                value={state.zip}
                onChange={(e) => set('zip', e.target.value.replace(/[^\d]/g, '').slice(0, 5))}
                style={{
                  width: '100%', border: 'none', outline: 'none', background: 'transparent',
                  fontFamily: bSans, fontSize: 15, color: B.ink, fontWeight: 600,
                  padding: 0, marginTop: 3,
                }}
              />
            </div>
          </div>
        </div>

        {/* Estimate */}
        <div style={{
          marginTop: 16, padding: '14px 16px', background: B.bg, border: `1px solid ${B.line}`,
          borderRadius: 10, display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 12,
        }}>
          <div>
            <div style={{ fontSize: 10.5, color: B.brassDeep, fontWeight: 700, letterSpacing: 1.4, textTransform: 'uppercase' }}>
              Estimated total
            </div>
            <div style={{ fontFamily: bDisplay, fontSize: 24, fontWeight: 800, color: B.ink, letterSpacing: -0.5, lineHeight: 1.1, marginTop: 2 }}>
              ${quote.price}
              <span style={{ fontFamily: bSans, fontSize: 11.5, color: B.muted, fontWeight: 500, marginLeft: 6 }}>
                · {quote.hours}h · {quote.cleaners} cleaners
              </span>
            </div>
          </div>
          <span style={{
            fontSize: 9.5, letterSpacing: 1.3, textTransform: 'uppercase',
            color: B.brassDeep, fontWeight: 700,
            padding: '5px 9px', border: `1px solid ${B.brass}`, borderRadius: 999, whiteSpace: 'nowrap',
          }}>Flat rate</span>
        </div>

        <button type="submit" style={{
          width: '100%', marginTop: 14, padding: '17px 18px',
          background: B.green, color: '#fff', border: 'none', borderRadius: 12,
          fontFamily: bSans, fontSize: 16, fontWeight: 700, letterSpacing: 0.1,
          cursor: 'pointer', display: 'inline-flex', alignItems: 'center', justifyContent: 'center', gap: 10,
          boxShadow: '0 12px 24px -12px color-mix(in srgb, var(--p7-primary) 60%, transparent)',
        }}>
          See available times <Icon name="arrow-right" size={18} sw={2.2}/>
        </button>

        <div style={{
          marginTop: 12, display: 'flex', alignItems: 'center', justifyContent: 'center',
          gap: 14, fontFamily: bSans, fontSize: 11.5, color: B.muted,
        }}>
          <span style={{ display: 'inline-flex', alignItems: 'center', gap: 5 }}>
            <Icon name="shield" size={12} sw={1.8} stroke={B.muted}/>
            Free cancellation
          </span>
          <span style={{ width: 3, height: 3, borderRadius: '50%', background: B.line }}/>
          <span style={{ display: 'inline-flex', alignItems: 'center', gap: 5 }}>
            <Icon name="check" size={12} sw={2.2} stroke={B.green}/>
            24h re-clean
          </span>
        </div>
      </form>
    </section>
  );
}

// ── Success card (mobile version of BSuccessCard) ───────────────────────────

function MSuccessCard() {
  const { state, set, quote } = useBForm();
  const reset = () => set({ submitted: false, name: '', phone: '', email: '', confirmationId: null });

  return (
    <section style={{ padding: '40px 20px', background: B.bg }}>
      <div id="booking-form" style={{
        background: B.card, borderRadius: 14, padding: 24,
        border: `1px solid ${B.green}`,
        boxShadow: '0 20px 40px -20px rgba(126,193,56,0.30), 0 0 0 4px color-mix(in srgb, var(--p7-primary) 8%, transparent)',
        position: 'relative', scrollMarginTop: STATUS_BAR_H + 20,
      }}>
        <div style={{
          position: 'absolute', top: -1, right: -1, width: 28, height: 28,
          borderTop: `2px solid ${B.brass}`, borderRight: `2px solid ${B.brass}`,
          borderTopRightRadius: 14, pointerEvents: 'none',
        }}/>
        <div style={{
          width: 56, height: 56, borderRadius: '50%',
          background: 'color-mix(in srgb, var(--p7-primary) 18%, transparent)',
          color: B.green, display: 'grid', placeItems: 'center', marginBottom: 16,
        }}>
          <Icon name="check-circle" size={32} sw={1.8}/>
        </div>
        <div style={{ fontSize: 10.5, color: B.brassDeep, fontWeight: 700, letterSpacing: 1.4, textTransform: 'uppercase', marginBottom: 6 }}>
          Confirmation {state.confirmationId}
        </div>
        <div style={{ fontFamily: bDisplay, fontSize: 26, fontWeight: 800, color: B.ink, letterSpacing: -0.7, lineHeight: 1.1, marginBottom: 8 }}>
          Thanks, {state.name.split(' ')[0] || 'friend'} — we'll text you within an hour.
        </div>
        <div style={{ fontSize: 13.5, color: B.ink2, lineHeight: 1.55, marginBottom: 18 }}>
          Your quote of <strong style={{ color: B.ink }}>${quote.price}</strong> for a {SVC_LABELS[state.service].name.toLowerCase()} on <strong style={{ color: B.ink }}>{formatDate(state.date)}</strong> ({timeLabel(state.time)}) is on its way to <strong style={{ color: B.ink }}>{state.phone}</strong>.
        </div>

        <div style={{ display: 'grid', gap: 10 }}>
          <a href={SEVEN.phoneHref} style={{
            padding: '14px 16px', background: B.green, color: '#fff',
            borderRadius: 12, textDecoration: 'none', fontFamily: bSans,
            fontSize: 15, fontWeight: 700, textAlign: 'center',
            display: 'inline-flex', alignItems: 'center', justifyContent: 'center', gap: 8,
          }}>
            <Icon name="phone" size={14} sw={2}/> Call us now
          </a>
          <button type="button" onClick={reset} style={{
            padding: '14px 16px', background: 'transparent', color: B.ink,
            border: `1px solid ${B.line}`, borderRadius: 12, cursor: 'pointer',
            fontFamily: bSans, fontSize: 14, fontWeight: 600,
          }}>Book another quote</button>
        </div>
      </div>
    </section>
  );
}

// ── Services (stacked cards) ────────────────────────────────────────────────

function MServices() {
  return (
    <section style={{ background: B.bg, padding: '40px 20px' }}>
      <MBadge>Services</MBadge>
      <h2 style={{ fontFamily: bDisplay, fontSize: 32, fontWeight: 800, letterSpacing: -1.2, lineHeight: 1, margin: '14px 0 22px', color: B.ink }}>
        Choose your <em style={{ color: B.green, fontStyle: 'normal' }}>clean</em>.
      </h2>
      <div style={{ display: 'grid', gap: 12 }}>
        {SEVEN.services.map((sv, i) => (
          <div key={sv.key} style={{
            background: B.card, borderRadius: 14, overflow: 'hidden',
            border: `1px solid ${B.line}`,
          }}>
            <div style={{
              height: 140, background: `url(${sv.img}) center/cover`, position: 'relative',
            }}>
              <span style={{
                position: 'absolute', top: 10, left: 10, padding: '4px 10px',
                background: B.card, fontFamily: bSans, fontSize: 10, fontWeight: 700,
                letterSpacing: 1, textTransform: 'uppercase', color: B.ink, borderRadius: 999,
              }}>0{i + 1}</span>
              <span style={{
                position: 'absolute', top: 10, right: 10, padding: '4px 10px',
                background: 'rgba(255,255,255,0.95)', fontFamily: bSans, fontSize: 11.5, fontWeight: 700,
                color: B.ink, borderRadius: 999,
              }}>From ${sv.from}</span>
            </div>
            <div style={{ padding: 18 }}>
              <div style={{ fontFamily: bDisplay, fontSize: 22, fontWeight: 700, color: B.ink, letterSpacing: -0.5, lineHeight: 1.15 }}>
                {sv.name}
              </div>
              <div style={{ fontFamily: bSans, fontSize: 13, color: B.muted, marginTop: 4, marginBottom: 12 }}>
                {sv.tagline}
              </div>
              <ul style={{ listStyle: 'none', padding: 0, margin: '0 0 14px', display: 'grid', gap: 6 }}>
                {sv.bullets.map((b, j) => (
                  <li key={j} style={{ fontFamily: bSans, fontSize: 13, color: B.ink2, display: 'flex', alignItems: 'flex-start', gap: 8 }}>
                    <span style={{ color: B.brass, lineHeight: 1.4 }}>—</span>
                    {b}
                  </li>
                ))}
              </ul>
              <button type="button" onClick={scrollToBookingForm} style={{
                width: '100%', padding: '12px 14px', background: B.green, color: '#fff',
                border: 'none', borderRadius: 10, fontFamily: bSans, fontSize: 13, fontWeight: 700,
                cursor: 'pointer', display: 'inline-flex', alignItems: 'center', justifyContent: 'center', gap: 6,
              }}>
                Reserve this <Icon name="arrow-right" size={14} sw={2.4}/>
              </button>
            </div>
          </div>
        ))}
      </div>
    </section>
  );
}

// ── Process ─────────────────────────────────────────────────────────────────

function MProcess() {
  return (
    <section style={{ background: B.bgDeep, padding: '40px 20px' }}>
      <MBadge>The process</MBadge>
      <h2 style={{ fontFamily: bDisplay, fontSize: 32, fontWeight: 800, letterSpacing: -1.2, lineHeight: 1, margin: '14px 0 22px', color: B.ink }}>
        Three steps.<br/>That's <em style={{ color: B.green, fontStyle: 'normal' }}>it</em>.
      </h2>
      <div style={{ display: 'grid', gap: 12 }}>
        {SEVEN.steps.map((st) => (
          <div key={st.n} style={{
            background: B.card, padding: 20, borderRadius: 12, border: `1px solid ${B.line}`,
            display: 'grid', gridTemplateColumns: '52px 1fr', gap: 16, alignItems: 'flex-start',
          }}>
            <div style={{ fontFamily: bDisplay, fontSize: 44, color: B.brass, letterSpacing: -1.2, lineHeight: 0.9, fontWeight: 800 }}>
              0{st.n}
            </div>
            <div>
              <div style={{ fontFamily: bDisplay, fontSize: 19, fontWeight: 700, color: B.ink, letterSpacing: -0.4, lineHeight: 1.2, marginBottom: 6 }}>
                {st.title}
              </div>
              <div style={{ fontFamily: bSans, fontSize: 13.5, color: B.ink2, lineHeight: 1.55 }}>
                {st.body}
              </div>
            </div>
          </div>
        ))}
      </div>
    </section>
  );
}

// ── Reviews ─────────────────────────────────────────────────────────────────

function MReviews() {
  return (
    <section style={{ background: B.bg, padding: '40px 20px' }}>
      <MBadge>Stories from clients</MBadge>
      <h2 style={{ fontFamily: bDisplay, fontSize: 30, fontWeight: 800, letterSpacing: -1, lineHeight: 1.05, margin: '14px 0 6px', color: B.ink }}>
        They came back.
      </h2>
      <div style={{ fontFamily: bDisplay, fontSize: 30, fontWeight: 800, letterSpacing: -1, lineHeight: 1.05, color: B.green, fontStyle: 'normal', marginBottom: 18 }}>
        So did the shine.
      </div>
      <div style={{
        background: B.card, borderRadius: 14, padding: 22, border: `1px solid ${B.line}`,
        marginBottom: 12,
      }}>
        <Icon name="sparkles" size={24} sw={1.5} stroke={B.brass}/>
        <div style={{ fontFamily: bDisplay, fontSize: 19, lineHeight: 1.35, color: B.ink, letterSpacing: -0.3, margin: '14px 0 16px', fontWeight: 600 }}>
          "I'm kicking myself for not having called them sooner. They left me with a spotless, great-smelling home."
        </div>
        <div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
          <img src={SEVEN.reviews[1].avatar} style={{ width: 40, height: 40, borderRadius: '50%', objectFit: 'cover' }}/>
          <div>
            <div style={{ fontFamily: bSans, fontSize: 14, fontWeight: 700, color: B.ink }}>{SEVEN.reviews[1].name}</div>
            <div style={{ fontFamily: bSans, fontSize: 12, color: B.muted }}>{SEVEN.reviews[1].city} · Deep cleaning</div>
          </div>
          <Stars n={5} size={12} color={B.brass}/>
        </div>
      </div>
      <div style={{ display: 'grid', gap: 10 }}>
        {SEVEN.reviews.slice(2, 5).map((r, i) => (
          <div key={i} style={{
            background: B.card, padding: 18, borderRadius: 12, border: `1px solid ${B.line}`,
          }}>
            <Stars n={r.stars} size={12} color={B.brass}/>
            <div style={{ fontFamily: bSans, fontSize: 13.5, lineHeight: 1.55, color: B.ink, marginTop: 10, marginBottom: 14 }}>
              "{r.body.length > 120 ? r.body.slice(0, 120) + '…' : r.body}"
            </div>
            <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
              <img src={r.avatar} style={{ width: 32, height: 32, borderRadius: '50%', objectFit: 'cover' }}/>
              <div>
                <div style={{ fontFamily: bSans, fontSize: 13, fontWeight: 700, color: B.ink }}>{r.name}</div>
                <div style={{ fontFamily: bSans, fontSize: 11.5, color: B.muted }}>{r.city}</div>
              </div>
            </div>
          </div>
        ))}
      </div>
    </section>
  );
}

// ── FAQ ─────────────────────────────────────────────────────────────────────

function MFaq() {
  const [open, setOpen] = React.useState(0);
  return (
    <section style={{ background: B.bgDeep, padding: '40px 20px 30px' }}>
      <MBadge>FAQ</MBadge>
      <h2 style={{ fontFamily: bDisplay, fontSize: 30, fontWeight: 800, letterSpacing: -1, lineHeight: 1.05, margin: '14px 0 4px', color: B.ink }}>
        Questions, <em style={{ color: B.green, fontStyle: 'normal' }}>answered.</em>
      </h2>
      <p style={{ fontFamily: bSans, fontSize: 13.5, color: B.ink2, lineHeight: 1.5, marginBottom: 14 }}>
        Still unsure? Text us — we usually reply within minutes.
      </p>
      <div>
        {SEVEN.faqs.map((f, i) => {
          const isOpen = open === i;
          return (
            <div key={i} style={{ borderBottom: `1px solid ${B.line}` }}>
              <button onClick={() => setOpen(isOpen ? -1 : i)} type="button" style={{
                width: '100%', padding: '18px 0', background: 'none', border: 'none', cursor: 'pointer',
                display: 'flex', alignItems: 'flex-start', justifyContent: 'space-between', gap: 14, textAlign: 'left',
              }}>
                <span style={{ fontFamily: bDisplay, fontSize: 16, fontWeight: 700, color: B.ink, letterSpacing: -0.3, lineHeight: 1.25 }}>
                  {f.q}
                </span>
                <span style={{
                  width: 28, height: 28, borderRadius: '50%', border: `1px solid ${B.green}`,
                  color: B.green, display: 'grid', placeItems: 'center', flexShrink: 0,
                  transform: isOpen ? 'rotate(45deg)' : 'rotate(0)', transition: 'transform .25s',
                }}>
                  <Icon name="plus" size={12} sw={2}/>
                </span>
              </button>
              {isOpen && (
                <div style={{ paddingBottom: 18, fontFamily: bSans, fontSize: 13.5, color: B.ink2, lineHeight: 1.7 }}>
                  {f.a}
                </div>
              )}
            </div>
          );
        })}
      </div>
    </section>
  );
}

// ── Final CTA strip ─────────────────────────────────────────────────────────

function MFinalCTA() {
  return (
    <section style={{ padding: '36px 20px', background: B.bg }}>
      <div style={{
        background: `linear-gradient(180deg, ${B.green}, ${B.greenDark})`,
        borderRadius: 16, padding: 28, color: '#fff', position: 'relative', overflow: 'hidden',
      }}>
        <div style={{
          position: 'absolute', right: -30, top: -30, width: 140, height: 140, borderRadius: '50%',
          background: B.brass, opacity: 0.18, filter: 'blur(30px)', pointerEvents: 'none',
        }}/>
        <MBadge light>Reserve your time</MBadge>
        <h2 style={{ fontFamily: bDisplay, fontSize: 30, fontWeight: 800, letterSpacing: -1, lineHeight: 1.05, margin: '12px 0 14px' }}>
          Tomorrow morning, <em style={{ color: B.brass, fontStyle: 'normal' }}>spotless.</em>
        </h2>
        <p style={{ fontFamily: bSans, fontSize: 14, color: B.greenSoft, lineHeight: 1.55, marginBottom: 20 }}>
          Most jobs are scheduled within 48 hours. We respond to every quote within an hour.
        </p>
        <button type="button" onClick={scrollToBookingForm} style={{
          width: '100%', padding: '15px 18px', background: B.brass, color: B.ink, border: 'none',
          borderRadius: 12, fontFamily: bSans, fontSize: 15, fontWeight: 700, cursor: 'pointer',
          display: 'inline-flex', alignItems: 'center', justifyContent: 'center', gap: 8, marginBottom: 10,
          transition: ROLLOVER_TRANSITION,
        }}
        {...rollover(
          { transform: 'translateY(-2px)', background: B.accentDeep, boxShadow: '0 14px 26px -18px rgba(0,0,0,0.35)' },
          { transform: 'translateY(0)', background: B.brass, boxShadow: 'none' }
        )}>
          Get my quote <Icon name="arrow-right" size={16} sw={2.4}/>
        </button>
        <a href={SEVEN.phoneHref} style={{
          width: '100%', padding: '15px 18px', background: 'transparent', color: '#fff',
          border: '1px solid rgba(255,255,255,0.3)', borderRadius: 12, textDecoration: 'none',
          fontFamily: bSans, fontSize: 15, fontWeight: 600,
          display: 'inline-flex', alignItems: 'center', justifyContent: 'center', gap: 8, boxSizing: 'border-box',
        }}>
          <Icon name="phone" size={14} sw={2} stroke={B.brass}/> {SEVEN.phone}
        </a>
      </div>
    </section>
  );
}

// ── Footer ──────────────────────────────────────────────────────────────────

function MFooter() {
  return (
    <footer style={{ background: B.ink, color: 'rgba(255,255,255,0.7)', padding: MOBILE_SITE_MODE ? '28px 20px 112px' : '28px 20px 100px' }}>
      <div style={{ display: 'grid', gap: 16 }}>
        <img src={SEVEN.logo} alt={SEVEN.brand} style={{ width: 176, height: 44, objectFit: 'contain', display: 'block' }} />
        <p style={{ fontFamily: bSans, fontSize: 13, lineHeight: 1.6, margin: 0, color: 'rgba(255,255,255,0.6)' }}>
          Meticulous, eco-friendly cleaning for Vancouver, Portland, and nearby communities.
        </p>
        <a href={SEVEN.phoneHref} style={{ color: '#fff', textDecoration: 'none', fontWeight: 700, fontSize: 14 }}>
          {SEVEN.phone}
        </a>
      </div>
      <div style={{ borderTop: '1px solid rgba(255,255,255,0.1)', marginTop: 20, paddingTop: 16, display: 'flex', justifyContent: 'space-between', gap: 16, fontSize: 11, color: 'rgba(255,255,255,0.45)' }}>
        <div>© 2026 7 Seven Cleaning</div>
        <div>Vancouver, WA</div>
      </div>
      <a href="mailto:vitaliy.georgiev@gmail.com" style={{
        display: 'inline-block', marginTop: 10, color: 'rgba(255,255,255,0.48)',
        textDecoration: 'none', fontSize: 11, lineHeight: 1.45,
      }}>
        design & marketing by Vit
      </a>
    </footer>
  );
}

// ── Sticky bottom CTA bar (inside iOS device, above home indicator) ────────

function MStickyCTA() {
  const { state, quote } = useBForm();
  if (state.submitted) return null;
  const bottomPad = MOBILE_SITE_MODE ? 'calc(env(safe-area-inset-bottom, 0px) + 12px)' : `${HOME_INDICATOR_H + 8}px`;
  return (
    <div style={{
      position: 'sticky', bottom: 0, zIndex: 30,
      marginTop: MOBILE_SITE_MODE ? -72 : -(HOME_INDICATOR_H + 60), // pull up so the gradient overlaps neatly
      padding: `12px 16px ${bottomPad}`,
      background: 'linear-gradient(180deg, rgba(245,241,232,0) 0%, rgba(245,241,232,0.95) 30%, rgba(245,241,232,1) 100%)',
      pointerEvents: 'none',
    }}>
      <div style={{
        display: 'flex', alignItems: 'center', gap: 10,
        background: B.ink, color: '#fff', borderRadius: 14, padding: '10px 12px',
        boxShadow: '0 16px 32px -16px rgba(20,30,25,0.45)',
        pointerEvents: 'auto',
      }}>
        <div style={{ flex: 1, minWidth: 0 }}>
          <div style={{ fontSize: 9.5, color: B.brass, fontWeight: 700, letterSpacing: 1.2, textTransform: 'uppercase' }}>
            Your estimate
          </div>
          <div style={{ fontFamily: bDisplay, fontSize: 17, fontWeight: 800, letterSpacing: -0.3, lineHeight: 1.1 }}>
            ${quote.price}
            <span style={{ fontFamily: bSans, fontSize: 11, color: 'rgba(255,255,255,0.55)', fontWeight: 500, marginLeft: 6 }}>
              · {SVC_LABELS[state.service].name}
            </span>
          </div>
        </div>
        <a href={SEVEN.phoneHref} aria-label="Call" style={{
          width: 38, height: 38, borderRadius: 10, background: 'rgba(255,255,255,0.08)',
          color: B.brass, textDecoration: 'none', display: 'grid', placeItems: 'center', flexShrink: 0,
        }}>
          <Icon name="phone" size={15} sw={2}/>
        </a>
        <button type="button" onClick={scrollToBookingForm} style={{
          padding: '10px 16px', background: B.green, color: '#fff', border: 'none',
          borderRadius: 10, fontFamily: bSans, fontSize: 13, fontWeight: 700,
          cursor: 'pointer', display: 'inline-flex', alignItems: 'center', gap: 6, flexShrink: 0,
          transition: ROLLOVER_TRANSITION,
        }}
        {...rollover(
          { transform: 'translateY(-1px)', background: B.greenDark, boxShadow: '0 10px 20px -14px rgba(0,0,0,0.45)' },
          { transform: 'translateY(0)', background: B.green, boxShadow: 'none' }
        )}>
          Book <Icon name="arrow-right" size={13} sw={2.4}/>
        </button>
      </div>
    </div>
  );
}

// ── Submit modal scoped to device frame (replaces fixed BSubmitModal on mobile) ──

function MSubmitModal() {
  const { state, set, quote } = useBForm();
  if (!state.modalOpen) return null;

  const close = () => set('modalOpen', false);
  const phoneOk = /^\(?\d{3}\)?[\s.-]?\d{3}[\s.-]?\d{4}$/.test(state.phone.replace(/\s/g, ''));
  const nameOk  = state.name.trim().length >= 2;
  const canSubmit = phoneOk && nameOk && !state.submitting;

  const onSubmit = async (e) => {
    e.preventDefault();
    if (!canSubmit) return;
    set({ submitting: true, submitError: null });
    try {
      await submitLeadToWeb3Forms(state, quote, 'Mobile booking modal');
      trackLeadConversion(state, quote, 'Mobile booking modal');
      const id = 'SEV-' + Math.floor(Math.random() * 9000 + 1000);
      set({ submitted: true, modalOpen: false, confirmationId: id, submitting: false, submitError: null });
      setTimeout(() => scrollToBookingForm(), 80);
    } catch (err) {
      set({ submitting: false, submitError: err.message || 'Could not send your quote request. Please call us instead.' });
    }
  };

  return (
    <div onClick={close} style={{
      position: MOBILE_SITE_MODE ? 'fixed' : 'absolute', inset: 0, zIndex: 90, borderRadius: MOBILE_SITE_MODE ? 0 : 48, overflow: 'hidden',
      background: 'rgba(20,30,25,0.55)', backdropFilter: 'blur(6px)',
      display: 'flex', flexDirection: 'column', justifyContent: 'flex-end',
      animation: 'm-fade-in .2s ease-out',
    }}>
      <form onClick={(e) => e.stopPropagation()} onSubmit={onSubmit} style={{
        background: B.card, borderRadius: '20px 20px 0 0', padding: 24,
        paddingBottom: MOBILE_SITE_MODE ? 'calc(env(safe-area-inset-bottom, 0px) + 24px)' : HOME_INDICATOR_H + 16,
        animation: 'm-sheet-up .28s cubic-bezier(.2,.8,.2,1)',
      }}>
        <div style={{ width: 36, height: 4, borderRadius: 2, background: B.line, margin: '0 auto 14px' }}/>
        <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 14 }}>
          <MBadge>One last step</MBadge>
          <button type="button" onClick={close} aria-label="close" style={{
            width: 30, height: 30, borderRadius: '50%', border: `1px solid ${B.line}`,
            background: '#fff', cursor: 'pointer', color: B.muted,
            display: 'grid', placeItems: 'center', fontSize: 16, fontWeight: 600,
          }}>×</button>
        </div>
        <div style={{ fontFamily: bDisplay, fontSize: 24, fontWeight: 800, color: B.ink, letterSpacing: -0.6, lineHeight: 1.15, marginBottom: 6 }}>
          Where should we text your quote?
        </div>
        <div style={{ fontSize: 13, color: B.muted, marginBottom: 18, lineHeight: 1.5 }}>
          We'll send your <strong style={{ color: B.ink }}>${quote.price}</strong> estimate and times within an hour.
        </div>
        <div style={{ display: 'grid', gap: 10 }}>
          <input value={state.name} onChange={(e) => set('name', e.target.value)} placeholder="Your name" autoFocus
            style={{
              width: '100%', padding: '13px 14px', borderRadius: 10,
              border: `1px solid ${B.line}`, fontFamily: bSans, fontSize: 15,
              color: B.ink, background: '#fff', outline: 'none', boxSizing: 'border-box',
            }}
            onFocus={(e) => e.target.style.borderColor = B.green}
            onBlur={(e) => e.target.style.borderColor = B.line}
          />
          <input value={state.phone} onChange={(e) => set('phone', e.target.value)} placeholder="Mobile phone" inputMode="tel"
            style={{
              width: '100%', padding: '13px 14px', borderRadius: 10,
              border: `1px solid ${B.line}`, fontFamily: bSans, fontSize: 15,
              color: B.ink, background: '#fff', outline: 'none', boxSizing: 'border-box',
            }}
            onFocus={(e) => e.target.style.borderColor = B.green}
            onBlur={(e) => e.target.style.borderColor = B.line}
          />
        </div>
        {state.submitError && (
          <div style={{ marginTop: 12, color: '#C04D2F', fontSize: 12, lineHeight: 1.45 }}>
            {state.submitError}
          </div>
        )}

        <button type="submit" disabled={!canSubmit} style={{
          width: '100%', marginTop: 16, padding: '16px 18px',
          background: canSubmit ? B.green : B.line, color: '#fff',
          border: 'none', borderRadius: 12, cursor: canSubmit ? 'pointer' : 'not-allowed',
          fontFamily: bSans, fontSize: 15, fontWeight: 700,
          display: 'inline-flex', alignItems: 'center', justifyContent: 'center', gap: 8,
        }}>
          {state.submitting ? 'Sending...' : 'Send my quote'} <Icon name="arrow-right" size={16} sw={2.2}/>
        </button>
        <div style={{ marginTop: 12, textAlign: 'center', fontSize: 11, color: B.muted }}>
          By submitting you agree to receive a text. Reply STOP anytime.
        </div>
      </form>
    </div>
  );
}

// ── Sheets host (renders open sheets — Size / Date / Time) ──────────────────

function MSheets() {
  const { state, set } = useBForm();
  const close = () => set('openSheet', null);

  return (
    <>
      <MBottomSheet open={state.openSheet === 'size'} onClose={close} title="How big is your space?">
        <div style={{ display: 'grid', gap: 4 }}>
          <BStepper label="Bedrooms"  value={state.bedrooms}  onChange={(v) => set('bedrooms', v)}  min={0} max={8} />
          <BStepper label="Bathrooms" value={state.bathrooms} onChange={(v) => set('bathrooms', v)} min={1} max={6} />
          <button type="button" onClick={close} style={{
            marginTop: 12, padding: '14px 18px', background: B.green, color: '#fff',
            border: 'none', borderRadius: 12, fontFamily: bSans, fontSize: 15, fontWeight: 700, cursor: 'pointer',
          }}>Done</button>
        </div>
      </MBottomSheet>

      <MBottomSheet open={state.openSheet === 'date'} onClose={close} title="Pick a date">
        <BDatePicker value={state.date} onSelect={(d) => set('date', d)} close={close} />
      </MBottomSheet>

      <MBottomSheet open={state.openSheet === 'time'} onClose={close} title="Pick a time">
        <BTimePicker value={state.time} onSelect={(t) => set('time', t)} close={close} />
      </MBottomSheet>
    </>
  );
}

// ── Booking panel: form OR success card ─────────────────────────────────────

function MBookingPanel() {
  const { state } = useBForm();
  return state.submitted ? <MSuccessCard /> : <MBookingForm />;
}

// ── Root component (NO BFormProvider here — it's at the app level) ──────────

function VariantBMobile() {
  return (
    <div data-screen-label={MOBILE_SITE_MODE ? 'Mobile Site' : 'Mobile Prototype'} style={{
      ...brandVars(useBrand(), B_DEFAULTS),
      background: B.bg, fontFamily: bSans, color: B.ink,
      minHeight: '100%',
    }}>
      <MTopBar />
      <MHero />
      <MServices />
      <MSelling />
      <MBookingPanel />
      <MProcess />
      <MReviews />
      <MFinalCTA />
      <MFaq />
      <MFooter />
      <MStickyCTA />
    </div>
  );
}

Object.assign(window, {
  VariantBMobile, MSubmitModal, MSheets,
  DEVICE_W, DEVICE_H, STATUS_BAR_H, HOME_INDICATOR_H,
});
