/* eslint-disable */
// יפן 2026 — shared overlays folded into the real screens:
//  • PlaceDetailView — the one tap-to-open detail (bottom sheet; recommended)
//  • TaxiCard        — big-type Japanese address for the driver
//  • ChibiLightbox   — full-size chibi + download
//  • TapChibi        — makes a header/sticker chibi tappable
//  • CAT_TAG / hebTag — Hebrew presets for the fixed schedule categories
// Reuses design-system atoms from the compiled bundle. Load BEFORE each screen.
(function () {
  const DS = window.Ds2026DesignSystem_dc290c;
  const { Polaroid, Washi, VeganBadge, StatusChip } = DS;

  const CITY = {
    tokyo:  { color:'var(--city-tokyo)',  tint:'var(--city-tokyo-tint)',  deep:'var(--city-tokyo-deep)',  name:'טוקיו' },
    hakone: { color:'var(--city-hakone)', tint:'var(--city-hakone-tint)', deep:'var(--city-hakone-deep)', name:'האקונה' },
    kyoto:  { color:'var(--city-kyoto)',  tint:'var(--city-kyoto-tint)',  deep:'var(--city-kyoto-deep)',  name:'קיוטו' },
    osaka:  { color:'var(--city-osaka)',  tint:'var(--city-osaka-tint)',  deep:'var(--city-osaka-deep)',  name:'אוסקה' },
  };

  // Fixed schedule categories → Hebrew (proper place names stay Latin).
  const CAT_TAG = {
    transit:   { label:'מעבר',  icon:'🚃' },
    food:      { label:'אוכל',  icon:'🍜' },
    rest:      { label:'מנוחה', icon:'😴' },
    shopping:  { label:'קניות', icon:'🛍️' },
    temple:    { label:'מקדש',  icon:'⛩️' },
    viewpoint: { label:'תצפית', icon:'🌄' },
    nature:    { label:'טבע',   icon:'🌳' },
    workshop:  { label:'סדנה',  icon:'🎨' },
    theme_park:{ label:'פארק שעשועים', icon:'🎢' },
  };
  const hebTag = (cat) => CAT_TAG[cat] || null;

  /* ---------- Japanese address block: labelled, JP font, copyable, hides when empty ---------- */
  function JpAddress({ address, postal, onTaxi }) {
    if (!address) return null;
    const [copied, setCopied] = React.useState(false);
    const copy = () => {
      const text = (postal ? '〒' + postal + ' ' : '') + address;
      try { navigator.clipboard && navigator.clipboard.writeText(text); } catch (e) {}
      setCopied(true); setTimeout(() => setCopied(false), 1600);
    };
    return (
      <section style={{ background:'var(--surface-card-2)', border:'var(--border-card)', borderRadius:'var(--r-md)',
        padding:'var(--sp-4)', display:'flex', flexDirection:'column', gap:'var(--sp-3)' }}>
        <div style={{ display:'flex', justifyContent:'space-between', alignItems:'baseline' }}>
          <span style={{ fontFamily:'var(--font-ui)', fontSize:'var(--fs-sm)', color:'var(--ink-700)' }}>כתובת ביפנית</span>
          <span style={{ fontSize:'var(--fs-2xs)', color:'var(--ink-500)' }}>הראו לנהג המונית 🚕</span>
        </div>
        <div className="jp-address" style={{ fontFamily:"'Noto Sans JP','DM Mono',ui-monospace,monospace", fontSize:22,
          lineHeight:1.5, color:'var(--ink-900)', background:'var(--surface-white)', border:'1px solid var(--hairline)',
          borderRadius:'var(--r-sm)', padding:'var(--sp-3) var(--sp-4)', fontWeight:500 }}>
          {postal && <div style={{ fontSize:15, color:'var(--ink-500)', fontWeight:400 }}>〒{postal}</div>}
          {address}
        </div>
        <div style={{ display:'flex', gap:'var(--sp-2)' }}>
          <button type="button" onClick={copy} style={{ appearance:'none', border:'1px solid var(--hairline)',
            background:'var(--surface-card)', color:'var(--ink-700)', borderRadius:'var(--r-md)', padding:'12px',
            fontFamily:'var(--font-ui)', fontSize:'var(--fs-sm)', cursor:'pointer', flex:'0 0 auto', minWidth:96 }}>
            {copied ? 'הועתק ✓' : '📋 העתק'}
          </button>
          {onTaxi && (
            <button type="button" onClick={onTaxi} style={{ appearance:'none', border:'none', flex:1, padding:'12px',
              borderRadius:'var(--r-md)', background:'var(--ink-900)', color:'var(--paper-cream)', fontFamily:'var(--font-ui)',
              fontSize:'var(--fs-md)', cursor:'pointer', display:'flex', alignItems:'center', justifyContent:'center',
              gap:'var(--sp-2)', boxShadow:'var(--shadow-card)' }}>
              <span aria-hidden="true" style={{ fontSize:20 }}>🚕</span> הצג לנהג המונית
            </button>
          )}
        </div>
      </section>
    );
  }

  function MapThumb() {
    return (
      <div style={{ width:'100%', height:120, borderRadius:'var(--r-md)', overflow:'hidden', position:'relative',
        border:'var(--border-card)', background:'repeating-linear-gradient(135deg, var(--paper-cream-deep) 0 12px, var(--surface-card-2) 12px 24px)' }}>
        <span style={{ position:'absolute', inset:0, display:'grid', placeItems:'center', fontSize:30 }} aria-hidden="true">📍</span>
        <span style={{ position:'absolute', insetInline:0, bottom:0, background:'var(--surface-card)', borderTop:'1px solid var(--hairline)',
          fontFamily:'var(--font-ui)', fontSize:'var(--fs-xs)', color:'var(--ink-700)', padding:'6px 10px', textAlign:'center' }}>🗺️ פתח בגוגל מפות</span>
      </div>
    );
  }

  /* ---------- Detail body (shared by sheet + full) ---------- */
  function DetailBody({ item, onTaxi }) {
    const c = CITY[item.city] || CITY.tokyo;
    return (
      <div style={{ padding:'var(--sp-3) var(--sp-5) var(--sp-8)' }}>
        <div style={{ position:'relative', marginBottom:'var(--sp-4)' }}>
          <Washi color={c.color} width={90} height={24} rotate={-4} style={{ position:'absolute', top:-12, insetInlineStart:24, zIndex:4 }} />
          <Polaroid src={item.photo} variant="frame" aspect="16 / 10" />
        </div>
        <div style={{ display:'flex', alignItems:'flex-start', gap:'var(--sp-3)', marginBottom:'var(--sp-2)' }}>
          <div style={{ flex:1, minWidth:0 }}>
            <h2 style={{ fontFamily:'var(--font-display)', fontSize:'var(--fs-title)', lineHeight:0.95, color:'var(--ink-900)' }}>{item.name}</h2>
            {item.nameLatin && <div className="ltr" style={{ fontFamily:'var(--font-ui)', fontSize:'var(--fs-sm)', color:'var(--ink-500)' }}>{item.nameLatin}</div>}
          </div>
          {item.vegan && <VeganBadge status={item.vegan} size="lg" />}
        </div>
        <div style={{ display:'flex', alignItems:'center', gap:'var(--sp-3)', flexWrap:'wrap', marginBottom:'var(--sp-3)' }}>
          {item.rating != null && (
            <span className="rating" style={{ fontSize:'var(--fs-md)', color:'var(--ink-700)' }}>
              <span style={{ color:'var(--rating-star)' }}>★</span> {item.rating.toFixed(1)}
              {item.reviews != null && <span style={{ color:'var(--ink-500)' }}> ({item.reviews.toLocaleString('en-US')})</span>}
            </span>
          )}
          {item.category?.label && <span style={{ fontSize:'var(--fs-sm)', color:c.deep }}>{item.category.icon} {item.category.label}</span>}
          <span style={{ fontSize:'var(--fs-sm)', color:c.deep }}>📍 {c.name}</span>
          {item.price && <span style={{ fontSize:'var(--fs-sm)', color:'var(--ink-700)' }}>💴 <span className="ltr">{item.price}</span></span>}
        </div>
        <div style={{ display:'flex', gap:6, flexWrap:'wrap', marginBottom:'var(--sp-4)' }}>
          {item.hours && <StatusChip label={item.hours} icon="🕒" tone={c.deep} />}
          {item.open === false && <StatusChip preset="closed" />}
          {(item.chips || []).map((ch, i) => ch.preset ? <StatusChip key={i} preset={ch.preset} /> : <StatusChip key={i} label={ch.label} icon={ch.icon} tone={c.deep} />)}
        </div>
        {item.desc && <p style={{ fontFamily:'var(--font-ui)', fontSize:'var(--fs-md)', color:'var(--ink-700)', lineHeight:'var(--lh-body)', margin:'0 0 var(--sp-4)' }}>{item.desc}</p>}
        {item.note && <p style={{ fontFamily:'var(--font-ui)', fontSize:'var(--fs-md)', color:'var(--ink-700)', background:'var(--sun-tint)', borderRadius:'var(--r-md)', padding:'var(--sp-3) var(--sp-4)', margin:'0 0 var(--sp-4)', lineHeight:'var(--lh-body)' }}>✍️ {item.note}</p>}
        <div style={{ marginBottom:'var(--sp-4)' }}><MapThumb /></div>
        <JpAddress address={item.address} postal={item.postal} onTaxi={onTaxi} />
      </div>
    );
  }

  /* ---------- Bottom-sheet detail (RECOMMENDED default) ---------- */
  function PlaceDetailView({ item, onClose, onTaxi }) {
    if (!item) return null;
    return (
      <div className="jp-sheet-scrim" onClick={onClose} style={{ position:'absolute', inset:0, zIndex:100,
        background:'rgba(74,64,58,0.34)', display:'flex', alignItems:'flex-end' }}>
        <div className="jp-sheet-panel" onClick={(e) => e.stopPropagation()} style={{ position:'relative', width:'100%',
          maxHeight:'92%', overflowY:'auto', background:'var(--surface-card)', borderTopLeftRadius:'var(--r-xl)',
          borderTopRightRadius:'var(--r-xl)', boxShadow:'var(--shadow-sheet)' }}>
          <button type="button" onClick={onClose} aria-label="סגור" style={{ appearance:'none', border:'none',
            background:'transparent', display:'block', width:'100%', padding:'8px 0 4px', cursor:'pointer' }}>
            <span style={{ display:'block', width:44, height:5, borderRadius:999, background:'var(--ink-300)', margin:'0 auto' }} />
          </button>
          <DetailBody item={item} onTaxi={onTaxi} />
        </div>
      </div>
    );
  }

  /* ---------- Taxi big-type card ---------- */
  function TaxiCard({ item, onClose }) {
    if (!item) return null;
    return (
      <div onClick={onClose} style={{ position:'absolute', inset:0, zIndex:130, background:'var(--ink-900)',
        color:'var(--paper-cream)', display:'flex', flexDirection:'column' }}>
        <div style={{ padding:'var(--sp-4) var(--sp-5)' }}>
          <button type="button" onClick={onClose} style={{ appearance:'none', border:'none', background:'transparent',
            color:'var(--paper-cream)', fontFamily:'var(--font-ui)', fontSize:'var(--fs-md)', cursor:'pointer' }}>‹ חזרה</button>
        </div>
        <div style={{ flex:1, display:'flex', flexDirection:'column', justifyContent:'center', alignItems:'center', gap:'var(--sp-5)', padding:'var(--sp-5)', textAlign:'center' }}>
          <div style={{ fontFamily:'var(--font-ui)', fontSize:'var(--fs-md)', opacity:0.8 }}>הראו מסך זה לנהג המונית 🚕</div>
          <div style={{ fontFamily:"'Noto Sans JP','DM Mono',monospace", direction:'ltr', unicodeBidi:'isolate', fontSize:34, lineHeight:1.45, fontWeight:700 }}>
            {item.postal && <div style={{ fontSize:22, opacity:0.75, fontWeight:400 }}>〒{item.postal}</div>}
            {item.address}
          </div>
          <div style={{ fontFamily:'var(--font-display)', fontSize:34 }}>{item.name}</div>
        </div>
      </div>
    );
  }

  /* ---------- Chibi lightbox + tappable chibi ---------- */
  function ChibiLightbox({ src, onClose }) {
    if (!src) return null;
    const download = () => {
      const a = document.createElement('a');
      a.href = src; a.download = (src.split('/').pop() || 'chibi.png');
      document.body.appendChild(a); a.click(); a.remove();
    };
    return (
      <div className="jp-fade-in" onClick={onClose} style={{ position:'absolute', inset:0, zIndex:120,
        background:'rgba(74,64,58,0.62)', display:'flex', flexDirection:'column', alignItems:'center', justifyContent:'center', padding:'var(--sp-6)' }}>
        <button type="button" onClick={onClose} aria-label="סגור" style={{ position:'absolute', top:16, insetInlineEnd:16,
          appearance:'none', border:'none', width:40, height:40, borderRadius:'50%', background:'var(--surface-card)',
          color:'var(--ink-700)', fontSize:20, cursor:'pointer', boxShadow:'var(--shadow-card)' }}>✕</button>
        <div className="jp-launch-pop" onClick={(e) => e.stopPropagation()} style={{ position:'relative' }}>
          <Washi color="var(--city-tokyo)" width={110} height={28} rotate={-5} style={{ position:'absolute', top:-14, insetInlineStart:'50%', marginInlineStart:-55, zIndex:2 }} />
          <div style={{ background:'var(--surface-white)', borderRadius:'var(--r-md)', padding:'var(--sp-4)', boxShadow:'var(--shadow-lift)' }}>
            <img src={src} alt="משה וליעוז" style={{ width:220, height:'auto', display:'block' }} />
          </div>
        </div>
        <button type="button" onClick={download} style={{ marginTop:'var(--sp-5)', appearance:'none', border:'none',
          padding:'12px 22px', borderRadius:'var(--r-pill)', background:'var(--paper-cream)', color:'var(--ink-900)',
          fontFamily:'var(--font-ui)', fontSize:'var(--fs-md)', cursor:'pointer', display:'inline-flex', alignItems:'center', gap:'var(--sp-2)', boxShadow:'var(--shadow-card)' }}>
          <span aria-hidden="true" style={{ fontSize:18 }}>⬇️</span> הורדה
        </button>
      </div>
    );
  }

  // Wrap a header/sticker chibi image so tapping opens the lightbox.
  function TapChibi({ src, onOpen, style, alt='משה וליעוז' }) {
    return (
      <button type="button" onClick={() => onOpen(src)} aria-label="הגדל תמונה" style={{ appearance:'none', border:'none',
        background:'transparent', padding:0, cursor:'zoom-in', lineHeight:0, ...style }}>
        <img src={src} alt={alt} style={{ width:'100%', height:'100%', objectFit:'contain',
          filter:'drop-shadow(0 3px 6px rgba(74,64,58,0.20))', display:'block' }} />
      </button>
    );
  }

  /* ---------- Document attachment: placeholder art, thumb, attach row, viewer ---------- */
  // Placeholder document art (real upload drops in via `src`). kind: pass | qr | photo | pdf.
  // `contentType` (e.g. 'application/pdf') is a second signal for real uploaded docs, so a
  // caller doesn't have to get `kind` exactly right — pdf content always renders as pdf.
  function DocArt({ kind='pass', src, contentType, big=false, accent='var(--sky-blue)' }) {
    const isPdf = kind === 'pdf' || contentType === 'application/pdf';
    if (src && isPdf) {
      // iOS standalone-PWA PDF-in-iframe can be flaky (Safari sometimes refuses to render a
      // PDF inside an <iframe>/<object> in a home-screen web app) — DocViewer always pairs
      // this with a guaranteed download / open-in-browser fallback, so viewing never dead-ends.
      return (
        <object data={src} type="application/pdf" style={{ display:'block', width:'100%', height:'100%', border:'none' }}>
          <iframe src={src} title="PDF" style={{ display:'block', width:'100%', height:'100%', border:'none' }} />
        </object>
      );
    }
    if (src) return <img src={src} alt="" style={{ display:'block', width:'100%', height:'100%', objectFit:'contain' }} />;
    if (kind === 'qr') {
      return (
        <div style={{ width:'100%', height:'100%', display:'grid', placeItems:'center', background:'var(--surface-white)', padding: big?24:6 }}>
          <div style={{ width: big?220:'70%', aspectRatio:'1/1',
            background:'repeating-conic-gradient(var(--ink-900) 0 25%, var(--surface-white) 0 50%)',
            backgroundSize: big?'26px 26px':'7px 7px', border: big?'10px solid var(--surface-white)':'3px solid var(--surface-white)',
            outline:'1px solid var(--hairline)' }} />
          {big && <div className="ltr" style={{ fontFamily:'var(--font-mono)', fontSize:13, color:'var(--ink-500)', marginTop:14 }}>SCAN AT GATE</div>}
        </div>
      );
    }
    if (kind === 'photo') {
      return (
        <div style={{ width:'100%', height:'100%', display:'grid', placeItems:'center', background:'var(--paper-cream-deep)',
          color:'var(--ink-500)', fontFamily:'var(--font-ui)', fontSize: big?15:10 }}>📷 {big && 'צילום אישור'}</div>
      );
    }
    // boarding pass
    return (
      <div style={{ width:'100%', height:'100%', background:'var(--surface-white)', display:'flex', flexDirection:'column', overflow:'hidden' }}>
        <div style={{ height: big?10:4, background:accent, flex:'0 0 auto' }} />
        <div style={{ flex:1, padding: big?'18px 20px':'5px 6px', display:'flex', flexDirection:'column', gap: big?12:2 }}>
          {big && <div style={{ display:'flex', justifyContent:'space-between', fontFamily:'var(--font-mono)', fontSize:12, color:'var(--ink-500)' }}><span>BOARDING PASS</span><span className="ltr">EL AL · LY85</span></div>}
          <div style={{ display:'flex', alignItems:'center', justifyContent:'space-between', gap:8 }}>
            <span className="ltr" style={{ fontFamily:'var(--font-display)', fontSize: big?46:14, lineHeight:0.9, color:'var(--ink-900)' }}>TLV</span>
            <span aria-hidden="true" style={{ fontSize: big?20:9 }}>✈️</span>
            <span className="ltr" style={{ fontFamily:'var(--font-display)', fontSize: big?46:14, lineHeight:0.9, color:'var(--ink-900)' }}>NRT</span>
          </div>
          {big && <div className="ltr" style={{ display:'flex', justifyContent:'space-between', fontFamily:'var(--font-ui)', fontSize:13, color:'var(--ink-700)' }}><span>GATE 24 · SEAT 24A</span><span>21:40</span></div>}
          <div style={{ marginTop:'auto', height: big?52:10, background:'repeating-linear-gradient(90deg, var(--ink-900) 0 2px, transparent 2px 5px)' }} />
        </div>
      </div>
    );
  }

  // Resolve a real uploaded doc's viewable URL (cache-first, see store.js resolveDocUrl) and
  // revoke the object URL on unmount/doc-change so blob URLs never leak. No-op for placeholder
  // docs that already carry a plain `src`.
  function useResolvedDocUrl(doc) {
    const [url, setUrl] = React.useState((doc && doc.src) || null);
    React.useEffect(() => {
      let cancelled = false, created = null;
      const StoreApi = window.JP2026Store;
      if (doc && doc.path && StoreApi && StoreApi.resolveDocUrl) {
        StoreApi.resolveDocUrl(doc).then((u) => { if (!cancelled && u) { created = u; setUrl(u); } })
          .catch((e) => console.warn('[shared-detail] resolveDocUrl failed', e));
      } else {
        setUrl((doc && doc.src) || null);
      }
      return () => {
        cancelled = true;
        if (created && StoreApi && StoreApi.revokeDocUrl) StoreApi.revokeDocUrl(created);
      };
    }, [doc && doc.path, doc && doc.src]);
    return url;
  }

  // Small preview thumbnail of an attached doc.
  function DocThumb({ doc, size=44 }) {
    const src = useResolvedDocUrl(doc);
    return (
      <span style={{ flex:'0 0 auto', width:size, height:size*1.28, borderRadius:6, overflow:'hidden',
        border:'1px solid var(--hairline)', boxShadow:'var(--shadow-sm)', background:'var(--surface-white)', display:'block' }}>
        <DocArt kind={doc.kind} src={src} contentType={doc.contentType} accent={doc.accent} />
      </span>
    );
  }

  // Attach affordance on a card / in an edit sheet. Empty vs attached.
  function AttachRow({ doc, onOpen, onAttach }) {
    if (!doc) {
      return (
        <button type="button" onClick={onAttach} style={{ appearance:'none', cursor:'pointer', width:'100%',
          display:'flex', alignItems:'center', justifyContent:'center', gap:8, padding:'10px',
          borderRadius:'var(--r-md)', border:'2px dashed color-mix(in srgb, var(--sky-blue) 55%, var(--hairline))',
          background:'transparent', color:'var(--ink-700)', fontFamily:'var(--font-ui)', fontSize:'var(--fs-sm)' }}>
          <span aria-hidden="true" style={{ fontSize:16 }}>📎</span> צרף מסמך
        </button>
      );
    }
    return (
      <button type="button" onClick={onOpen} style={{ appearance:'none', cursor:'pointer', width:'100%',
        display:'flex', alignItems:'center', gap:'var(--sp-3)', padding:'8px 10px', borderRadius:'var(--r-md)',
        border:'var(--border-card)', background:'var(--surface-card-2)' }}>
        <DocThumb doc={doc} size={40} />
        <span style={{ flex:1, minWidth:0, textAlign:'start' }}>
          <span style={{ display:'block', fontFamily:'var(--font-ui)', fontSize:'var(--fs-sm)', color:'var(--ink-900)' }}>{doc.title}</span>
          <span style={{ display:'block', fontFamily:'var(--font-ui)', fontSize:'var(--fs-2xs)', color:'var(--ink-500)' }}>מסמך מצורף · הקישו להצגה</span>
        </span>
        <span aria-hidden="true" style={{ color:'var(--ink-300)', fontSize:18 }}>⤢</span>
      </button>
    );
  }

  // Full-screen document viewer — zoom + download/share + back. Resolves real uploaded docs
  // (doc.path) cache-first via Store.resolveDocUrl (offline-capable); placeholder docs keep
  // using doc.src directly. DL-016.
  function DocViewer({ doc, onClose, onDelete }) {
    if (!doc) return null;
    const [scale, setScale] = React.useState(1);
    const [confirming, setConfirming] = React.useState(false);
    const [deleting, setDeleting] = React.useState(false);
    const [delErr, setDelErr] = React.useState('');
    const resolvedSrc = useResolvedDocUrl(doc);
    const isPdf = doc.kind === 'pdf' || doc.contentType === 'application/pdf';
    const clamp = (v) => Math.min(3, Math.max(1, +v.toFixed(2)));
    const doDelete = async () => {
      if (!onDelete) return;
      setDeleting(true); setDelErr('');
      try { await onDelete(); }            // parent closes the viewer on success
      catch (e) { setDeleting(false); setDelErr((e && e.message) || 'מחיקה נכשלה'); }
    };
    // Guaranteed download. A blob-URL (cache hit) honours `download` directly; a cross-origin
    // signed URL (cache-miss fallback) would IGNORE `download` and just open — so fetch it to a
    // blob first and download that. On fetch failure (offline), fall back to opening the URL.
    const download = async () => {
      if (!resolvedSrc) return;
      let href = resolvedSrc, revoke = null;
      if (!resolvedSrc.startsWith('blob:')) {
        try {
          const blob = await (await fetch(resolvedSrc)).blob();
          href = URL.createObjectURL(blob); revoke = href;
        } catch (e) { href = resolvedSrc; }   // degraded path — open instead of download
      }
      const a = document.createElement('a'); a.href = href; a.download = doc.title || 'document';
      document.body.appendChild(a); a.click(); a.remove();
      if (revoke) setTimeout(() => URL.revokeObjectURL(revoke), 4000);
    };
    const ZBtn = ({ label, on }) => (
      <button type="button" onClick={on} aria-label={label} style={{ appearance:'none', border:'none', width:44, height:44,
        borderRadius:'50%', background:'var(--surface-card)', color:'var(--ink-900)', fontSize:22, cursor:'pointer', boxShadow:'var(--shadow-card)' }}>{label}</button>
    );
    return (
      <div style={{ position:'absolute', inset:0, zIndex:140, background:'var(--ink-900)', display:'flex', flexDirection:'column' }}>
        <div style={{ display:'flex', alignItems:'center', justifyContent:'space-between', padding:'14px 18px', color:'var(--paper-cream)' }}>
          <button type="button" onClick={onClose} style={{ appearance:'none', border:'none', background:'transparent',
            color:'var(--paper-cream)', fontFamily:'var(--font-ui)', fontSize:'var(--fs-md)', cursor:'pointer' }}>‹ חזרה</button>
          <span style={{ fontFamily:'var(--font-ui)', fontSize:'var(--fs-sm)', opacity:0.85 }}>{doc.title}</span>
          <span style={{ display:'flex', alignItems:'center', gap:16 }}>
            <button type="button" onClick={download} disabled={!resolvedSrc} aria-label="הורדה ושיתוף" style={{ appearance:'none', border:'none', background:'transparent',
              color:'var(--paper-cream)', fontSize:20, cursor: resolvedSrc ? 'pointer' : 'default', opacity: resolvedSrc ? 1 : 0.4 }}>⬇️</button>
            {onDelete && (
              <button type="button" onClick={()=>{ setDelErr(''); setConfirming(true); }} aria-label="מחיקת מסמך" style={{ appearance:'none', border:'none', background:'transparent',
                color:'var(--paper-cream)', fontSize:19, cursor:'pointer' }}>🗑️</button>
            )}
          </span>
        </div>
        {!resolvedSrc && doc.path && (
          <div style={{ textAlign:'center', color:'var(--paper-cream)', opacity:0.75, fontFamily:'var(--font-ui)', fontSize:'var(--fs-sm)', padding:'4px 18px' }}>
            {navigator.onLine ? 'טוען מסמך…' : 'לא זמין במצב לא מקוון — עדיין לא נשמר מקומית'}
          </div>
        )}
        <div style={{ flex:1, overflow:'auto', display:'grid', placeItems:'center', padding:'12px' }}>
          <div style={{ width: isPdf ? 'min(92vw, 480px)' : 300, aspectRatio: doc.kind==='qr' ? '1/1' : '3/4',
            transform:`scale(${scale})`, transformOrigin:'center',
            transition:'transform var(--dur-fast) var(--ease-soft)', borderRadius:'var(--r-md)', overflow:'hidden',
            boxShadow:'var(--shadow-lift)', background:'var(--surface-white)' }}>
            <DocArt kind={doc.kind} src={resolvedSrc} contentType={doc.contentType} accent={doc.accent} big />
          </div>
        </div>
        {/* iOS standalone-PWA PDF-in-iframe can refuse to render — guaranteed escape hatch. */}
        {isPdf && resolvedSrc && (
          <div style={{ textAlign:'center', padding:'0 18px 8px' }}>
            <a href={resolvedSrc} target="_blank" rel="noopener noreferrer" download={doc.title || 'document'}
              style={{ color:'var(--paper-cream)', opacity:0.85, fontFamily:'var(--font-ui)', fontSize:'var(--fs-sm)', textDecoration:'underline' }}>
              לא נטען? פתח/הורד בדפדפן
            </a>
          </div>
        )}
        <div style={{ display:'flex', alignItems:'center', justifyContent:'center', gap:'var(--sp-4)', padding:'14px 18px calc(18px + env(safe-area-inset-bottom))' }}>
          <ZBtn label="－" on={()=>setScale(s=>clamp(s-0.25))} />
          <span style={{ color:'var(--paper-cream)', fontFamily:'var(--font-mono)', fontSize:'var(--fs-sm)', minWidth:52, textAlign:'center' }}>{Math.round(scale*100)}%</span>
          <ZBtn label="＋" on={()=>setScale(s=>clamp(s+0.25))} />
        </div>
        {confirming && (
          <div style={{ position:'absolute', inset:0, zIndex:150, background:'rgba(0,0,0,0.55)', display:'grid', placeItems:'center', padding:24 }}>
            <div style={{ background:'var(--surface-card)', borderRadius:'var(--r-lg)', padding:'20px 22px', maxWidth:320, width:'100%', boxShadow:'var(--shadow-lift)', textAlign:'center' }}>
              <div style={{ fontFamily:'var(--font-ui)', fontSize:'var(--fs-md)', color:'var(--ink-900)', marginBottom:6 }}>למחוק את המסמך?</div>
              <div className="ltr" style={{ fontFamily:'var(--font-ui)', fontSize:'var(--fs-sm)', color:'var(--ink-500)', marginBottom:16, wordBreak:'break-word' }}>{doc.title}</div>
              {delErr && <div style={{ color:'#c0563b', fontFamily:'var(--font-ui)', fontSize:'var(--fs-2xs)', marginBottom:10 }}>{delErr}</div>}
              <div style={{ display:'flex', gap:10, justifyContent:'center' }}>
                <button type="button" disabled={deleting} onClick={()=>setConfirming(false)} style={{ appearance:'none', border:'var(--border-card)', background:'var(--surface-card-2)',
                  color:'var(--ink-900)', borderRadius:'var(--r-md)', padding:'9px 18px', fontFamily:'var(--font-ui)', fontSize:'var(--fs-sm)', cursor: deleting?'default':'pointer' }}>ביטול</button>
                <button type="button" disabled={deleting} onClick={doDelete} style={{ appearance:'none', border:'none', background:'#c0563b', color:'#fff',
                  borderRadius:'var(--r-md)', padding:'9px 18px', fontFamily:'var(--font-ui)', fontSize:'var(--fs-sm)', cursor: deleting?'default':'pointer', opacity: deleting?0.6:1 }}>{deleting ? 'מוחק…' : 'מחק'}</button>
              </div>
            </div>
          </div>
        )}
      </div>
    );
  }

  // Store `places` row → detail `item`. Single source of truth for the three screens that open
  // the detail sheet (discover / today / dayview). TITLE is the Latin `name` (locked rule — never
  // a niqqud'd Hebrew name); `address` is the verbatim Japanese address (taxi drivers read it).
  function fromPlace(p) {
    if (!p) return null;
    return {
      name: p.name, city: p.city, category: { label: p.cat, icon: p.icon },
      rating: p.rating, reviews: p.reviews, vegan: p.vegan, hours: p.hours, open: p.open,
      chips: (p.chips || []).map((v) => (typeof v === 'string' ? { preset: v } : v)),
      desc: p.what_to_order || '', note: p.note || '',
      address: p.address_japanese || '', postal: p.postal || '', photo: p.photo_url || '',
      price: p.price_range || '',
    };
  }

  window.JP2026Detail = { PlaceDetailView, DetailBody, TaxiCard, ChibiLightbox, TapChibi, JpAddress,
    DocArt, DocThumb, AttachRow, DocViewer, CAT_TAG, hebTag, fromPlace };
})();
