/* ============================================================
   mobile-apps.jsx
   Composants pour patterns d'app courants : avatar+menu,
   onboarding, chat, calendrier, maps, recherche+filtres,
   scanner QR, caméra, gestion fichiers.
   ============================================================ */

const { useState: uA, useRef: rA, useEffect: eA } = React;

/* ============================================================
   Avatar — bouton rond utilisateur (initiales ou icône)
   Nom système : Avatar
   ============================================================ */
function Avatar({ name = 'M', color = 'var(--accent)', size = 36, onClick, active }) {
  const initials = name.split(' ').map(w => w[0]).slice(0, 2).join('').toUpperCase();
  return (
    <button onClick={onClick} className="touch-press" style={{
      width: size, height: size, borderRadius: '50%',
      background: `linear-gradient(135deg, ${color}, color-mix(in oklch, ${color} 60%, black))`,
      color: 'var(--bg-1)',
      border: active ? '2px solid var(--accent)' : 'none',
      display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
      fontFamily: 'var(--font-ui)', fontSize: size * 0.4, fontWeight: 700,
      cursor: 'pointer',
      boxShadow: 'inset 0 1px 0 rgba(255,255,255,0.25), 0 2px 6px rgba(0,0,0,0.3)',
      WebkitTapHighlightColor: 'transparent',
    }}>{initials}</button>
  );
}

/* ============================================================
   AvatarMenu — popup descendant depuis l'avatar
   Nom système : AvatarMenu
   Items : [{icon, label, onClick, danger}]
   ============================================================ */
function AvatarMenu({ open, onClose, name, email, items = [] }) {
  if (!open) return null;
  return (
    <div onClick={onClose} style={{
      position: 'absolute', inset: 0, zIndex: 200,
      background: 'rgba(0,0,0,0.35)',
      animation: 'fade-in .15s',
    }}>
      <style>{`
        @keyframes fade-in { from { opacity: 0 } to { opacity: 1 } }
        @keyframes drop-in { from { opacity: 0; transform: translateY(-8px) scale(.95) } to { opacity: 1; transform: translateY(0) scale(1) } }
      `}</style>
      <div onClick={(e) => e.stopPropagation()} style={{
        position: 'absolute', top: 56, right: 12,
        width: 240,
        background: 'var(--bg-3)',
        border: '1px solid var(--border-2)',
        borderRadius: 14,
        overflow: 'hidden',
        boxShadow: '0 14px 32px rgba(0,0,0,0.5)',
        animation: 'drop-in .2s cubic-bezier(.3,.7,.3,1.2)',
        transformOrigin: 'top right',
      }}>
        <div style={{
          padding: '14px 14px 12px',
          display: 'flex', alignItems: 'center', gap: 10,
          borderBottom: '1px solid var(--border-1)',
          background: 'var(--bg-2)',
        }}>
          <Avatar name={name} size={36} />
          <div style={{ minWidth: 0, flex: 1 }}>
            <div style={{ fontSize: 14, fontWeight: 700 }}>{name}</div>
            {email && <div style={{ fontSize: 11, color: 'var(--ink-3)', fontFamily: 'var(--font-mono)' }}>{email}</div>}
          </div>
        </div>
        {items.map((it, i) => (
          <button key={i} onClick={() => { onClose(); it.onClick && it.onClick(); }}
            className="touch-press" style={{
              width: '100%', minHeight: 44,
              padding: '10px 14px',
              background: 'transparent', border: 'none',
              borderTop: i > 0 ? '1px solid var(--border-1)' : 'none',
              color: it.danger ? 'var(--err)' : 'var(--ink-1)',
              display: 'flex', alignItems: 'center', gap: 10,
              fontFamily: 'var(--font-ui)', fontSize: 14, fontWeight: 500,
              cursor: 'pointer', textAlign: 'left',
              WebkitTapHighlightColor: 'transparent',
            }}>
            <Icon name={it.icon} size={15} style={{ color: it.danger ? 'var(--err)' : 'var(--accent)' }} />
            <span style={{ flex: 1 }}>{it.label}</span>
            {!it.danger && <Icon name="chevR" size={12} style={{ color: 'var(--ink-3)' }} />}
          </button>
        ))}
      </div>
    </div>
  );
}

/* ============================================================
   OnboardingSlider — slides + dots + boutons suivant/passer
   Nom système : OnboardingSlider
   Cas : présentation d'une nouvelle app à l'utilisateur.
   slides : [{icon, color, title, desc}]
   ============================================================ */
function OnboardingSlider({ slides, onFinish }) {
  const [i, setI] = uA(0);
  const isLast = i === slides.length - 1;
  return (
    <div style={{ display: 'flex', flexDirection: 'column', height: '100%' }}>
      <div style={{
        padding: '14px 20px',
        display: 'flex', justifyContent: 'flex-end',
      }}>
        <button onClick={onFinish} style={{
          padding: '6px 12px', background: 'transparent', border: 'none',
          color: 'var(--ink-3)', fontFamily: 'var(--font-ui)',
          fontWeight: 600, fontSize: 14, cursor: 'pointer',
          WebkitTapHighlightColor: 'transparent',
        }}>Passer</button>
      </div>
      <div style={{
        flex: 1, padding: '0 32px',
        display: 'flex', flexDirection: 'column',
        alignItems: 'center', justifyContent: 'center',
        textAlign: 'center',
      }}>
        <div style={{
          width: 110, height: 110, borderRadius: 28,
          background: `linear-gradient(135deg, ${slides[i].color}, color-mix(in oklch, ${slides[i].color} 60%, black))`,
          color: 'var(--bg-1)',
          display: 'flex', alignItems: 'center', justifyContent: 'center',
          marginBottom: 28,
          boxShadow: `inset 0 2px 0 rgba(255,255,255,0.2), 0 12px 28px rgba(0,0,0,0.4)`,
          animation: 'pop-in .35s cubic-bezier(.3,.7,.3,1.3)',
        }}>
          <style>{`@keyframes pop-in { from { transform: scale(.7); opacity: 0 } }`}</style>
          <Icon name={slides[i].icon} size={56} />
        </div>
        <div style={{ fontSize: 26, fontWeight: 700, marginBottom: 12 }}>{slides[i].title}</div>
        <div style={{ fontSize: 15, color: 'var(--ink-3)', lineHeight: 1.5, maxWidth: 280 }}>{slides[i].desc}</div>
      </div>
      <div style={{ padding: '20px 24px 30px' }}>
        <div style={{ display: 'flex', justifyContent: 'center', gap: 8, marginBottom: 22 }}>
          {slides.map((_, j) => (
            <span key={j} onClick={() => setI(j)} style={{
              width: i === j ? 24 : 8, height: 8, borderRadius: 4,
              background: i === j ? 'var(--accent)' : 'var(--border-3)',
              transition: 'width .25s, background .2s',
              cursor: 'pointer',
            }} />
          ))}
        </div>
        <PrimaryButton icon={isLast ? 'play' : 'chevR'}
          onClick={() => isLast ? onFinish() : setI(i + 1)}>
          {isLast ? 'Commencer' : 'Suivant'}
        </PrimaryButton>
      </div>
    </div>
  );
}

/* ============================================================
   ChatBubble — bulle de message (envoyé/reçu)
   Nom système : ChatBubble
   ============================================================ */
function ChatBubble({ text, time, me, status }) {
  return (
    <div style={{
      display: 'flex',
      justifyContent: me ? 'flex-end' : 'flex-start',
      padding: '4px 14px',
    }}>
      <div style={{
        maxWidth: '78%',
        padding: '8px 12px',
        background: me ? 'var(--accent)' : 'var(--bg-3)',
        color: me ? 'var(--bg-1)' : 'var(--ink-1)',
        borderRadius: me ? '16px 16px 4px 16px' : '16px 16px 16px 4px',
        fontSize: 14, lineHeight: 1.4,
        boxShadow: me ? '0 2px 6px var(--accent-glow)' : 'var(--shadow-1)',
        border: me ? 'none' : '1px solid var(--border-2)',
      }}>
        <div>{text}</div>
        <div style={{
          fontSize: 10,
          color: me ? 'rgba(0,0,0,0.55)' : 'var(--ink-3)',
          marginTop: 4, textAlign: 'right',
          fontFamily: 'var(--font-mono)',
          display: 'inline-flex', alignItems: 'center', gap: 4,
          float: 'right',
        }}>
          {time}
          {me && status === 'sent' && <span>✓</span>}
          {me && status === 'read' && <span>✓✓</span>}
        </div>
      </div>
    </div>
  );
}

/* ============================================================
   ChatComposer — barre d'envoi en bas (input + + + send)
   Nom système : ChatComposer
   ============================================================ */
function ChatComposer({ onSend }) {
  const [v, setV] = uA('');
  return (
    <div style={{
      padding: '8px 10px 18px',
      display: 'flex', alignItems: 'flex-end', gap: 8,
      borderTop: '1px solid var(--border-2)',
      background: 'var(--surf-glass-strong)',
      backdropFilter: 'blur(14px)',
    }}>
      <IconButton icon="plus" label="Joindre" size={36} />
      <div style={{
        flex: 1, minHeight: 36,
        display: 'flex', alignItems: 'center', gap: 6,
        padding: '6px 12px',
        background: 'var(--bg-3)',
        border: '1px solid var(--border-2)',
        borderRadius: 18,
      }}>
        <input type="text" value={v} onChange={(e) => setV(e.target.value)}
          placeholder="Message…"
          style={{
            flex: 1, minWidth: 0,
            background: 'transparent', border: 'none', outline: 'none',
            color: 'var(--ink-1)', fontFamily: 'var(--font-ui)', fontSize: 14,
          }} />
      </div>
      {v ? (
        <button onClick={() => { onSend && onSend(v); setV(''); }}
          className="touch-press" style={{
            width: 36, height: 36, borderRadius: '50%',
            background: 'var(--accent)', color: 'var(--bg-1)',
            border: 'none', display: 'flex', alignItems: 'center', justifyContent: 'center',
            cursor: 'pointer', boxShadow: '0 2px 6px var(--accent-glow)',
            WebkitTapHighlightColor: 'transparent',
          }}><Icon name="chevR" size={16} /></button>
      ) : (
        <IconButton icon="terminal" label="Audio" size={36} />
      )}
    </div>
  );
}

/* ============================================================
   CalendarMonth — vue mois avec points sous les jours marqués
   Nom système : CalendarMonth
   Props : year, month (0-11), selected (Date), onSelect, events (Set de jours)
   ============================================================ */
function CalendarMonth({ year, month, selected, onSelect, events = new Set() }) {
  const today = new Date();
  const first = new Date(year, month, 1);
  const last = new Date(year, month + 1, 0);
  const startDay = (first.getDay() + 6) % 7; // lundi = 0
  const days = last.getDate();
  const cells = [];
  for (let i = 0; i < startDay; i++) cells.push(null);
  for (let d = 1; d <= days; d++) cells.push(d);
  const monthName = first.toLocaleDateString('fr-FR', { month: 'long', year: 'numeric' });
  return (
    <div>
      <div style={{
        display: 'flex', alignItems: 'center', justifyContent: 'space-between',
        padding: '0 14px 12px',
      }}>
        <IconButton icon="chevL" label="Mois précédent" size={32} />
        <div style={{ fontSize: 16, fontWeight: 700, textTransform: 'capitalize' }}>{monthName}</div>
        <IconButton icon="chevR" label="Mois suivant" size={32} />
      </div>
      <div style={{
        display: 'grid', gridTemplateColumns: 'repeat(7, 1fr)', gap: 4,
        padding: '0 8px',
      }}>
        {['L', 'M', 'M', 'J', 'V', 'S', 'D'].map((d, i) => (
          <div key={i} style={{
            textAlign: 'center', fontSize: 10,
            color: 'var(--ink-3)', fontFamily: 'var(--font-mono)',
            fontWeight: 700, padding: '4px 0',
            letterSpacing: '0.08em',
          }}>{d}</div>
        ))}
        {cells.map((d, i) => {
          const isToday  = d === today.getDate() && month === today.getMonth() && year === today.getFullYear();
          const isSel    = selected && d === selected.getDate() && month === selected.getMonth() && year === selected.getFullYear();
          const hasEvent = d && events.has(d);
          return (
            <button key={i} onClick={() => d && onSelect && onSelect(new Date(year, month, d))}
              disabled={!d}
              className="touch-press"
              style={{
                aspectRatio: '1',
                background: isSel ? 'var(--accent)' : isToday ? 'var(--accent-tint)' : 'transparent',
                color: isSel ? 'var(--bg-1)' : isToday ? 'var(--accent)' : (d ? 'var(--ink-1)' : 'transparent'),
                border: 'none', borderRadius: 8,
                fontFamily: 'var(--font-mono)', fontSize: 13,
                fontWeight: isSel || isToday ? 700 : 500,
                cursor: d ? 'pointer' : 'default',
                position: 'relative',
                WebkitTapHighlightColor: 'transparent',
              }}>
              {d}
              {hasEvent && (
                <span style={{
                  position: 'absolute', bottom: 4, left: '50%',
                  transform: 'translateX(-50%)',
                  width: 4, height: 4, borderRadius: '50%',
                  background: isSel ? 'var(--bg-1)' : 'var(--accent)',
                }}/>
              )}
            </button>
          );
        })}
      </div>
    </div>
  );
}

/* ============================================================
   MapView — placeholder visuel d'une carte avec pins
   Nom système : MapView
   ============================================================ */
function MapView({ pins = [] }) {
  return (
    <div style={{
      position: 'relative',
      height: '100%', width: '100%',
      background: 'var(--bg-2)',
      overflow: 'hidden',
    }}>
      {/* fond carte stylisé */}
      <svg width="100%" height="100%" viewBox="0 0 400 600" preserveAspectRatio="xMidYMid slice" style={{ position: 'absolute', inset: 0 }}>
        <defs>
          <pattern id="grid" width="40" height="40" patternUnits="userSpaceOnUse">
            <path d="M 40 0 L 0 0 0 40" fill="none" stroke="var(--border-1)" strokeWidth="0.5"/>
          </pattern>
        </defs>
        <rect width="100%" height="100%" fill="url(#grid)"/>
        {/* routes */}
        <path d="M 0 200 Q 200 150 400 250" stroke="var(--ink-4)" strokeWidth="6" fill="none" opacity="0.3"/>
        <path d="M 100 0 Q 150 200 200 400 T 250 600" stroke="var(--ink-4)" strokeWidth="6" fill="none" opacity="0.3"/>
        <path d="M 200 100 L 350 500" stroke="var(--ink-4)" strokeWidth="4" fill="none" opacity="0.25"/>
        {/* zones */}
        <path d="M 0 0 L 150 0 L 100 120 L 0 100 Z" fill="var(--bg-3)" opacity="0.5"/>
        <path d="M 280 350 L 400 380 L 400 550 L 320 600 L 250 500 Z" fill="var(--bg-3)" opacity="0.4"/>
        <circle cx="240" cy="380" r="60" fill="var(--ok)" opacity="0.12"/>
        {/* fleuve */}
        <path d="M 0 450 Q 100 420 200 460 T 400 440" stroke="var(--info)" strokeWidth="10" fill="none" opacity="0.4"/>
      </svg>
      {/* pins */}
      {pins.map((p, i) => (
        <div key={i} style={{
          position: 'absolute', left: `${p.x}%`, top: `${p.y}%`,
          transform: 'translate(-50%, -100%)',
          pointerEvents: 'none',
        }}>
          <div style={{
            width: 28, height: 28, borderRadius: '50% 50% 50% 0',
            background: p.color || 'var(--accent)',
            transform: 'rotate(-45deg)',
            border: '2px solid var(--bg-1)',
            display: 'flex', alignItems: 'center', justifyContent: 'center',
            boxShadow: '0 4px 10px rgba(0,0,0,0.5)',
          }}>
            <Icon name={p.icon || 'grid'} size={12} style={{ color: 'var(--bg-1)', transform: 'rotate(45deg)' }}/>
          </div>
          {p.label && (
            <div style={{
              position: 'absolute', top: -28, left: '50%',
              transform: 'translateX(-50%)',
              padding: '3px 8px',
              background: 'var(--bg-3)',
              border: '1px solid var(--border-2)',
              borderRadius: 6,
              fontFamily: 'var(--font-mono)', fontSize: 10,
              color: 'var(--ink-1)',
              whiteSpace: 'nowrap',
              boxShadow: 'var(--shadow-2)',
            }}>{p.label}</div>
          )}
        </div>
      ))}
    </div>
  );
}

/* ============================================================
   FilterChips — barre de chips de filtre
   Nom système : FilterChips
   ============================================================ */
function FilterChips({ value = [], onChange, options }) {
  const toggle = (v) => {
    if (value.includes(v)) onChange(value.filter((x) => x !== v));
    else onChange([...value, v]);
  };
  return (
    <div style={{ display: 'flex', gap: 6, overflowX: 'auto', padding: '4px 0', WebkitOverflowScrolling: 'touch' }}>
      {options.map((o) => {
        const v = typeof o === 'string' ? o : o.value;
        const l = typeof o === 'string' ? o : o.label;
        const ic = typeof o === 'object' ? o.icon : null;
        const active = value.includes(v);
        return (
          <button key={v} onClick={() => toggle(v)} className="touch-press" style={{
            flex: '0 0 auto',
            padding: '6px 12px',
            background: active ? 'var(--accent)' : 'var(--bg-3)',
            color: active ? 'var(--bg-1)' : 'var(--ink-2)',
            border: `1px solid ${active ? 'var(--accent)' : 'var(--border-2)'}`,
            borderRadius: 999,
            display: 'inline-flex', alignItems: 'center', gap: 6,
            cursor: 'pointer',
            fontFamily: 'var(--font-ui)', fontSize: 12, fontWeight: 600,
            WebkitTapHighlightColor: 'transparent',
          }}>
            {ic && <Icon name={ic} size={12} />}
            {l}
          </button>
        );
      })}
    </div>
  );
}

/* ============================================================
   QrScannerView — viseur scanner code-barres / QR
   Nom système : QrScannerView
   ============================================================ */
function QrScannerView({ onCapture }) {
  return (
    <div style={{
      position: 'relative', width: '100%', height: '100%',
      background: '#000',
      overflow: 'hidden',
    }}>
      {/* fake camera feed = grain animé */}
      <div style={{
        position: 'absolute', inset: 0,
        background: `
          radial-gradient(ellipse at 30% 40%, rgba(80,60,40,0.4), transparent 60%),
          radial-gradient(ellipse at 70% 60%, rgba(40,40,60,0.5), transparent 50%),
          #15110c
        `,
      }}/>
      {/* visée centrale */}
      <div style={{
        position: 'absolute', top: '50%', left: '50%',
        transform: 'translate(-50%, -50%)',
        width: 220, height: 220,
      }}>
        {/* 4 coins */}
        {[
          { top: 0, left: 0, br: '4px 0 0 0' },
          { top: 0, right: 0, br: '0 4px 0 0' },
          { bottom: 0, left: 0, br: '0 0 0 4px' },
          { bottom: 0, right: 0, br: '0 0 4px 0' },
        ].map((c, i) => (
          <div key={i} style={{
            position: 'absolute', ...c, width: 28, height: 28,
            borderTop: c.top !== undefined ? '3px solid var(--accent)' : 'none',
            borderBottom: c.bottom !== undefined ? '3px solid var(--accent)' : 'none',
            borderLeft: c.left !== undefined ? '3px solid var(--accent)' : 'none',
            borderRight: c.right !== undefined ? '3px solid var(--accent)' : 'none',
            borderRadius: c.br,
          }}/>
        ))}
        {/* ligne scan animée */}
        <div style={{
          position: 'absolute', left: 6, right: 6, height: 2,
          background: 'linear-gradient(90deg, transparent, var(--accent), transparent)',
          boxShadow: '0 0 12px var(--accent), 0 0 20px var(--accent)',
          animation: 'qr-scan 2.4s ease-in-out infinite',
        }}/>
        <style>{`@keyframes qr-scan {
          0%, 100% { top: 6px; opacity: 1 }
          50% { top: calc(100% - 8px); opacity: 0.7 }
        }`}</style>
      </div>
      {/* overlay assombri hors visée */}
      <div style={{
        position: 'absolute', inset: 0,
        boxShadow: '0 0 0 9999px rgba(0,0,0,0.55) inset',
        clipPath: 'polygon(0% 0%, 0% 100%, 100% 100%, 100% 0%, calc(50% + 110px) 0%, calc(50% + 110px) calc(50% + 110px), calc(50% - 110px) calc(50% + 110px), calc(50% - 110px) calc(50% - 110px), calc(50% + 110px) calc(50% - 110px), calc(50% + 110px) 0%)',
        pointerEvents: 'none',
      }}/>
      {/* texte */}
      <div style={{
        position: 'absolute', top: 'calc(50% + 140px)', left: 0, right: 0,
        textAlign: 'center', color: 'var(--ink-1)',
        fontFamily: 'var(--font-ui)', fontSize: 14, fontWeight: 600,
      }}>Pointe vers un QR code ou code-barres</div>
      {/* boutons bas */}
      <div style={{
        position: 'absolute', bottom: 28, left: 0, right: 0,
        display: 'flex', justifyContent: 'space-around', alignItems: 'center',
      }}>
        <IconButton icon="folder" label="Galerie" size={44} />
        <button onClick={() => onCapture && onCapture('demo')} className="touch-press" style={{
          width: 70, height: 70, borderRadius: '50%',
          background: 'var(--accent)', border: '4px solid #fff',
          color: 'var(--bg-1)', cursor: 'pointer',
          display: 'flex', alignItems: 'center', justifyContent: 'center',
          boxShadow: '0 4px 12px var(--accent-glow)',
          WebkitTapHighlightColor: 'transparent',
        }}><Icon name="grid" size={26} /></button>
        <IconButton icon="moon" label="Flash" size={44} />
      </div>
    </div>
  );
}

/* ============================================================
   CameraView — viseur appareil photo avec shutter rond
   Nom système : CameraView
   ============================================================ */
function CameraView({ onShoot }) {
  return (
    <div style={{
      position: 'relative', width: '100%', height: '100%',
      background: '#000', overflow: 'hidden',
    }}>
      {/* fake scene */}
      <div style={{
        position: 'absolute', inset: 0,
        background: `
          linear-gradient(180deg, #4a2e1a 0%, #6b4423 30%, #2a1f15 70%, #15110c 100%),
          radial-gradient(circle at 50% 30%, rgba(254,128,25,0.3), transparent 50%)
        `,
        backgroundBlendMode: 'overlay',
      }}/>
      {/* règle des tiers */}
      <div style={{ position: 'absolute', inset: 0, pointerEvents: 'none' }}>
        {[33.33, 66.66].map((p) => (
          <React.Fragment key={p}>
            <div style={{ position:'absolute', left:0, right:0, top:`${p}%`, height:1, background:'rgba(255,255,255,0.2)' }}/>
            <div style={{ position:'absolute', top:0, bottom:0, left:`${p}%`, width:1, background:'rgba(255,255,255,0.2)' }}/>
          </React.Fragment>
        ))}
      </div>
      {/* top bar */}
      <div style={{
        position: 'absolute', top: 20, left: 0, right: 0,
        display: 'flex', justifyContent: 'space-around',
        padding: '0 16px',
      }}>
        {[
          { icon: 'moon', label: 'Flash' },
          { icon: 'clock', label: 'Minuteur' },
          { icon: 'grid', label: 'Grille' },
        ].map((b) => (
          <IconButton key={b.label} icon={b.icon} label={b.label} size={36} />
        ))}
      </div>
      {/* mode chips */}
      <div style={{
        position: 'absolute', bottom: 130, left: 0, right: 0,
        display: 'flex', justifyContent: 'center', gap: 20,
        color: 'var(--ink-2)', fontFamily: 'var(--font-mono)', fontSize: 12,
        letterSpacing: '0.08em', textTransform: 'uppercase',
      }}>
        <span style={{ opacity: 0.5 }}>Vidéo</span>
        <span style={{ color: 'var(--accent)', fontWeight: 700 }}>Photo</span>
        <span style={{ opacity: 0.5 }}>Portrait</span>
      </div>
      {/* bottom controls */}
      <div style={{
        position: 'absolute', bottom: 28, left: 0, right: 0,
        display: 'flex', justifyContent: 'space-around', alignItems: 'center',
      }}>
        <div style={{
          width: 50, height: 50, borderRadius: 10,
          background: 'linear-gradient(135deg, #6b4423, #2a1f15)',
          border: '2px solid #fff',
        }}/>
        <button onClick={() => onShoot && onShoot()} className="touch-press" style={{
          width: 76, height: 76, borderRadius: '50%',
          background: '#fff', border: '4px solid rgba(255,255,255,0.4)',
          cursor: 'pointer',
          boxShadow: '0 0 0 4px rgba(0,0,0,0.4)',
          WebkitTapHighlightColor: 'transparent',
        }}/>
        <IconButton icon="refresh" label="Caméra avant" size={44} />
      </div>
    </div>
  );
}

/* ============================================================
   FileExplorer — liste fichiers/dossiers
   Nom système : FileExplorer
   ============================================================ */
function FileExplorer({ items, onOpen, onAction }) {
  const sizeFmt = (b) => {
    if (b == null) return '';
    if (b < 1024) return `${b} o`;
    if (b < 1024 * 1024) return `${(b / 1024).toFixed(1)} Ko`;
    if (b < 1024 ** 3) return `${(b / 1024 / 1024).toFixed(1)} Mo`;
    return `${(b / 1024 / 1024 / 1024).toFixed(1)} Go`;
  };
  const typeIcon = (t) => ({
    folder: 'folder', image: 'grid', video: 'play', audio: 'terminal',
    pdf: 'list', code: 'terminal', archive: 'download', file: 'list',
  })[t] || 'list';
  const typeColor = (t) => ({
    folder: 'var(--accent)', image: 'var(--blue)', video: 'var(--purple)',
    audio: 'var(--ok)', pdf: 'var(--err)', code: 'var(--info)', archive: 'var(--warn)',
  })[t] || 'var(--ink-3)';
  return (
    <div>
      {items.map((it) => (
        <SwipeableRow key={it.name}
          onTap={() => onOpen && onOpen(it)}
          leftActions={[
            { label: 'Suppr.', icon: 'close', color: 'var(--err)',
              onClick: () => onAction && onAction('delete', it) },
          ]}
          rightActions={[
            { label: 'Renom.', icon: 'cog', color: 'var(--info)',
              onClick: () => onAction && onAction('rename', it) },
            { label: 'Partag.', icon: 'download', color: 'var(--accent)',
              onClick: () => onAction && onAction('share', it) },
          ]}>
          <div style={{
            padding: '12px 14px',
            display: 'flex', alignItems: 'center', gap: 12,
            borderBottom: '1px solid var(--border-1)',
            background: 'var(--bg-3)',
          }}>
            <span style={{
              width: 38, height: 38, borderRadius: 8,
              background: 'var(--bg-1)',
              border: `1px solid ${typeColor(it.type)}`,
              color: typeColor(it.type),
              display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
            }}>
              <Icon name={typeIcon(it.type)} size={17} />
            </span>
            <div style={{ flex: 1, minWidth: 0 }}>
              <div style={{ fontSize: 14, fontWeight: 500, color: 'var(--ink-1)',
                            overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{it.name}</div>
              <div style={{ fontSize: 11, color: 'var(--ink-3)', fontFamily: 'var(--font-mono)', marginTop: 2 }}>
                {it.date || ''} {it.size != null && `· ${sizeFmt(it.size)}`}
              </div>
            </div>
            {it.type === 'folder' && <Icon name="chevR" size={13} style={{ color: 'var(--ink-3)' }}/>}
          </div>
        </SwipeableRow>
      ))}
    </div>
  );
}

Object.assign(window, {
  Avatar, AvatarMenu,
  OnboardingSlider,
  ChatBubble, ChatComposer,
  CalendarMonth,
  MapView,
  FilterChips,
  QrScannerView, CameraView,
  FileExplorer,
});
