// マドリスキャン — Scanning screen
// LiDAR room scan in progress

const widthCandidates = [
  window.visualViewport?.width,
  window.parent && window.parent !== window ? window.parent.visualViewport?.width : undefined,
  window.screen?.width,
  window.frameElement?.clientWidth,
  window.innerWidth,
].filter((value) => value && value >= 360 && value <= 440);
const heightCandidates = [
  window.visualViewport?.height,
  window.parent && window.parent !== window ? window.parent.visualViewport?.height : undefined,
  window.screen?.height,
  window.frameElement?.clientHeight,
  window.innerHeight,
].filter((value) => value && value >= 720 && value <= 960);
const W = Math.round(widthCandidates[0] || 390);
const H = Math.round(heightCandidates[0] || 844);

function CameraPreview({ captureTick, completed }) {
  const videoRef = React.useRef(null);
  const canvasRef = React.useRef(null);
  const [state, setState] = React.useState("requesting");
  const [snapshot, setSnapshot] = React.useState(null);

  React.useEffect(() => {
    let stream;
    let cancelled = false;

    async function boot() {
      if (!navigator.mediaDevices?.getUserMedia) {
        if (!cancelled) setState("unsupported");
        return;
      }

      try {
        stream = await navigator.mediaDevices.getUserMedia({
          video: {
            facingMode: { ideal: "environment" },
            width: { ideal: 1280 },
            height: { ideal: 720 },
          },
          audio: false,
        });

        if (cancelled) {
          stream.getTracks().forEach((track) => track.stop());
          return;
        }

        const video = videoRef.current;
        if (video) {
          video.srcObject = stream;
          video.playsInline = true;
          video.muted = true;
          await video.play().catch(() => {});
        }

        setState("ready");
      } catch (error) {
        console.error("camera preview failed", error);
        if (!cancelled) setState("denied");
      }
    }

    boot();

    return () => {
      cancelled = true;
      if (stream) stream.getTracks().forEach((track) => track.stop());
    };
  }, []);

  React.useEffect(() => {
    if (!captureTick) return;
    const video = videoRef.current;
    const canvas = canvasRef.current;
    if (!video || !canvas || video.readyState < 2) return;

    const width = video.videoWidth || 1280;
    const height = video.videoHeight || 720;
    canvas.width = width;
    canvas.height = height;
    const ctx = canvas.getContext("2d");
    if (!ctx) return;
    ctx.drawImage(video, 0, 0, width, height);
    setSnapshot(canvas.toDataURL("image/jpeg", 0.92));
  }, [captureTick]);

  return (
    <>
      <canvas ref={canvasRef} style={{ display: "none" }} />

      {completed && snapshot ? (
        <img
          src={snapshot}
          alt="scan snapshot"
          style={{
            position: "absolute",
            inset: 0,
            width: "100%",
            height: "100%",
            objectFit: "cover",
            background: "#0b1220",
            filter: "saturate(0.9) contrast(1.01) brightness(0.9)",
          }}
        />
      ) : (
        <video
          ref={videoRef}
          autoPlay
          muted
          playsInline
          style={{
            position: "absolute",
            inset: 0,
            width: "100%",
            height: "100%",
            objectFit: "cover",
            background: "#0b1220",
            filter: "saturate(0.92) contrast(1.01) brightness(0.9)",
          }}
        />
      )}

      <div style={{
        position: "absolute",
        inset: 0,
        background:
          "radial-gradient(ellipse at 24% 16%, rgba(255,255,255,.58), transparent 38%)," +
          "radial-gradient(ellipse at 78% 14%, rgba(255,255,255,.26), transparent 28%)," +
          "linear-gradient(180deg, rgba(255,255,255,.54) 0%, rgba(255,255,255,.18) 34%, rgba(255,255,255,.08) 100%)",
        pointerEvents: "none",
      }} />

      {state !== "ready" && !completed && (
        <div style={{
          position: "absolute",
          left: 18,
          right: 18,
          bottom: 170,
          padding: "14px 16px",
          borderRadius: 18,
          background: "rgba(255,255,255,0.88)",
          border: "1px solid rgba(148,163,184,0.18)",
          backdropFilter: "blur(18px) saturate(180%)",
          WebkitBackdropFilter: "blur(18px) saturate(180%)",
          boxShadow: "0 14px 28px rgba(15,23,42,0.12)",
          zIndex: 18,
        }}>
          <div style={{ fontSize: 13, fontWeight: 700, color: "#1f2937", marginBottom: 6 }}>
            {state === "requesting" && "カメラを起動しています"}
            {state === "denied" && "カメラ許可が必要です"}
            {state === "unsupported" && "この環境ではカメラを使えません"}
          </div>
          <div style={{ fontSize: 12, lineHeight: 1.6, color: "#64748b" }}>
            {state === "requesting" && "ブラウザの許可ダイアログで カメラ を許可してください。"}
            {state === "denied" && "アドレスバー付近の権限設定からカメラを許可すると、実写プレビューに切り替わります。"}
            {state === "unsupported" && "HTTPS または localhost 環境の対応ブラウザで開く必要があります。"}
          </div>
        </div>
      )}
    </>
  );
}

function RecognitionOverlay({ phase, metrics }) {
  const lines = [
    { x1: 56, y1: 260, x2: 164, y2: 186, kind: "ceiling", phase: 2 },
    { x1: 164, y1: 186, x2: 284, y2: 178, kind: "ceiling", phase: 2 },
    { x1: 284, y1: 178, x2: 384, y2: 236, kind: "ceiling", phase: 2 },
    { x1: 56, y1: 260, x2: 64, y2: 580, kind: "wall", phase: 1 },
    { x1: 384, y1: 236, x2: 388, y2: 592, kind: "wall", phase: 1 },
    { x1: 64, y1: 580, x2: 216, y2: 642, kind: "floor", phase: 1 },
    { x1: 216, y1: 642, x2: 388, y2: 592, kind: "floor", phase: 1 },
    { x1: 216, y1: 642, x2: 214, y2: 368, kind: "corner", phase: 1 },
    { x1: 264, y1: 304, x2: 326, y2: 300, kind: "opening", phase: 3 },
    { x1: 326, y1: 300, x2: 332, y2: 420, kind: "opening", phase: 3 },
  ];

  const badges = [
    { x: 88, y: 306, label: "壁ライン", tint: "#38bdf8", phase: 1 },
    { x: 232, y: 148, label: "天井ライン", tint: "#f0b674", phase: 2 },
    { x: 298, y: 448, label: "開口候補", tint: "#a78bfa", phase: 3 },
  ];

  const dimensions = [
    { x: 132, y: 668, label: "幅 3,640 mm", phase: 1 },
    { x: 22, y: 430, label: "奥行 2,730 mm", rotate: -90, phase: 2 },
    { x: 262, y: 520, label: "開口 1,650 mm", phase: 3 },
  ];

  const steps = [
    { key: "frame", label: "フレーム固定", detail: "現在フレームを解析用に固定" },
    { key: "surface", label: "壁面抽出", detail: "壁・床・天井ラインを推定" },
    { key: "opening", label: "開口抽出", detail: "窓・出入口候補を分類" },
    { key: "done", label: "平面化準備", detail: "部屋外形と寸法候補を確定" },
  ];

  const statusTitle =
    phase === 0 ? "フレームを固定しました" :
    phase === 1 ? "壁面を推定しています" :
    phase === 2 ? "開口部を解析しています" :
    "認識完了";

  return (
    <>
      <svg
        width={W}
        height={H}
        viewBox={`0 0 ${W} ${H}`}
        style={{ position: "absolute", inset: 0, zIndex: 14, pointerEvents: "none" }}
      >
        <defs>
          <filter id="recognitionGlow" x="-20%" y="-20%" width="140%" height="140%">
            <feGaussianBlur stdDeviation="1.2" result="g" />
            <feMerge>
              <feMergeNode in="g" />
              <feMergeNode in="SourceGraphic" />
            </feMerge>
          </filter>
        </defs>
        {lines.filter((line) => phase >= line.phase).map((line, index) => (
          <line
            key={index}
            x1={line.x1}
            y1={line.y1}
            x2={line.x2}
            y2={line.y2}
            stroke={
              line.kind === "ceiling"
                ? "#f0b674"
                : line.kind === "opening"
                  ? "#a78bfa"
                : line.kind === "floor"
                  ? "#7dd3fc"
                  : line.kind === "corner"
                    ? "#e2e8f0"
                    : "#38bdf8"
            }
            strokeWidth={line.kind === "corner" ? 1.6 : line.kind === "opening" ? 2.2 : 2}
            strokeDasharray={line.kind === "ceiling" ? "0" : line.kind === "opening" ? "10 6" : "8 7"}
            strokeLinecap="round"
            opacity={0.88}
            filter="url(#recognitionGlow)"
          />
        ))}
      </svg>

      <div style={{
        position: "absolute",
        inset: 0,
        background:
          "radial-gradient(ellipse at 50% 45%, rgba(255,255,255,.28), transparent 42%)," +
          "linear-gradient(180deg, rgba(255,255,255,.12) 0%, rgba(255,255,255,.04) 45%, rgba(255,255,255,.18) 100%)",
        zIndex: 13,
        pointerEvents: "none",
      }} />

      {badges.filter((badge) => phase >= badge.phase).map((badge) => (
        <div
          key={badge.label}
          style={{
            position: "absolute",
            left: badge.x,
            top: badge.y,
            padding: "7px 10px",
            borderRadius: 999,
            background: "rgba(255,255,255,0.86)",
            border: `1px solid ${badge.tint}33`,
            boxShadow: "0 10px 24px rgba(15,23,42,0.08)",
            color: "#1f2937",
            fontSize: 11,
            fontWeight: 700,
            zIndex: 19,
            backdropFilter: "blur(12px)",
          }}
        >
          <span style={{ color: badge.tint, marginRight: 6 }}>●</span>
          {badge.label}
        </div>
      ))}

      {dimensions.filter((item) => phase >= item.phase).map((item) => (
        <div
          key={item.label}
          style={{
            position: "absolute",
            left: item.x,
            top: item.y,
            transform: item.rotate ? `rotate(${item.rotate}deg)` : "none",
            transformOrigin: "left center",
            padding: "6px 9px",
            borderRadius: 8,
            background: "rgba(15,23,42,0.72)",
            color: "#ffffff",
            fontSize: 10.5,
            fontWeight: 800,
            letterSpacing: 0.2,
            zIndex: 22,
            boxShadow: "0 10px 22px rgba(15,23,42,0.18)",
          }}
        >
          {item.label}
        </div>
      ))}

      <div style={{
        position: "absolute",
      right: 16,
        top: 122,
        width: 174,
        padding: "14px 14px 12px",
        borderRadius: 18,
        background: "rgba(255,255,255,0.9)",
        border: "1px solid rgba(148,163,184,0.16)",
        boxShadow: "0 16px 34px rgba(15,23,42,0.12)",
        backdropFilter: "blur(18px) saturate(180%)",
        WebkitBackdropFilter: "blur(18px) saturate(180%)",
        zIndex: 21,
      }}>
        <div style={{ fontSize: 12, fontWeight: 800, color: "#0f172a", marginBottom: 8 }}>
          {statusTitle}
        </div>
        <div style={{ display: "grid", gap: 6, fontSize: 11, color: "#475569" }}>
          <div>壁 {metrics.walls}本</div>
          <div>天井 {metrics.ceilings}本</div>
          <div>開口 {metrics.openings}箇所</div>
          <div>推定面積 {metrics.area}㎡</div>
          <div>信頼度 {metrics.confidence}%</div>
        </div>
      </div>

      <div style={{
        position: "absolute",
        left: 16,
        right: 118,
        bottom: 156,
        padding: "12px 14px",
        borderRadius: 18,
        background: "rgba(255,255,255,0.84)",
        border: "1px solid rgba(148,163,184,0.14)",
        boxShadow: "0 12px 28px rgba(15,23,42,0.09)",
        backdropFilter: "blur(18px) saturate(180%)",
        WebkitBackdropFilter: "blur(18px) saturate(180%)",
        zIndex: 18,
      }}>
        <div style={{ fontSize: 11, fontWeight: 800, color: "#64748b", letterSpacing: 1.1, marginBottom: 10 }}>
          認識ステップ
        </div>
        <div style={{ display: "grid", gap: 8 }}>
          {steps.map((step, index) => {
            const active = phase >= index;
            const current = phase === index && phase < steps.length - 1;
            return (
              <div key={step.key} style={{ display: "grid", gridTemplateColumns: "18px 1fr", gap: 10, alignItems: "start" }}>
                <div style={{
                  width: 18,
                  height: 18,
                  borderRadius: 999,
                  background: active ? (current ? "#f0b674" : "#38bdf8") : "rgba(203,213,225,0.9)",
                  boxShadow: active ? "0 0 8px rgba(56,189,248,0.18)" : "none",
                  marginTop: 1,
                }} />
                <div>
                  <div style={{ fontSize: 11, fontWeight: 700, color: active ? "#0f172a" : "#94a3b8" }}>
                    {step.label}
                  </div>
                  <div style={{ fontSize: 10, lineHeight: 1.5, color: active ? "#64748b" : "#cbd5e1" }}>
                    {step.detail}
                  </div>
                </div>
              </div>
            );
          })}
        </div>
      </div>
    </>
  );
}

// ─────────────────────────────────────────────────────────────
// LiDAR wireframe room — SVG, cyan glow + dashed ghost segments
// ─────────────────────────────────────────────────────────────
function LidarRoom() {
  // 7-8 wall segments forming a perspective room (one corner cut open)
  // Coordinate system: 440×520 viewBox, room floats centered
  const cx = 220, cy = 290; // visual center
  // Front-facing isometric-ish room: 3-quarter view
  // Define corners (a..h)
  const a = { x: 70,  y: 470, scanned: true  }; // front-left-floor
  const b = { x: 370, y: 470, scanned: true  }; // front-right-floor
  const c = { x: 320, y: 380, scanned: true  }; // back-right-floor
  const d = { x: 120, y: 380, scanned: false }; // back-left-floor  (ghost)
  const e = { x: 70,  y: 220, scanned: true  }; // front-left-top
  const f = { x: 370, y: 220, scanned: true  }; // front-right-top
  const g = { x: 320, y: 130, scanned: false }; // back-right-top (ghost partial)
  const h = { x: 120, y: 130, scanned: false }; // back-left-top  (ghost)

  // Edges: { from, to, scanned }
  const edges = [
    // floor
    [a, b, true],
    [b, c, true],
    [c, d, false],   // ghost
    [d, a, false],   // ghost
    // walls (verticals)
    [a, e, true],
    [b, f, true],
    [c, g, false],   // ghost (back-right vertical)
    [d, h, false],   // ghost
    // ceiling (mostly ghost — we haven't looked up)
    [e, f, true],
    [f, g, false],
    [g, h, false],
    [h, e, false],
  ];

  const pts = [a, b, c, d, e, f, g, h];
  // Floor diagonal scan lines (depth feel)
  const floorScan = [
    [{x: 130, y: 470}, {x: 155, y: 380}],
    [{x: 200, y: 470}, {x: 200, y: 380}],
    [{x: 270, y: 470}, {x: 250, y: 380}],
    [{x: 330, y: 470}, {x: 295, y: 380}],
  ];

  return (
    <svg
      width={W} height={520}
      viewBox={`0 0 ${W} 520`}
      style={{ position: 'absolute', left: 0, top: 220, pointerEvents: 'none' }}
    >
      <defs>
        <filter id="cyanGlow" x="-30%" y="-30%" width="160%" height="160%">
          <feGaussianBlur stdDeviation="1.5" result="b1"/>
          <feMerge>
            <feMergeNode in="b1"/>
            <feMergeNode in="SourceGraphic"/>
          </feMerge>
        </filter>
        <filter id="cyanGlowSoft" x="-50%" y="-50%" width="200%" height="200%">
          <feGaussianBlur stdDeviation="3.2"/>
        </filter>
        <radialGradient id="floorFade" cx="50%" cy="50%" r="50%">
          <stop offset="0%"   stopColor="#38bdf8" stopOpacity="0.06"/>
          <stop offset="100%" stopColor="#38bdf8" stopOpacity="0"/>
        </radialGradient>
      </defs>

      {/* soft floor glow */}
      <ellipse cx={220} cy={425} rx={170} ry={50} fill="url(#floorFade)" />

      {/* edges */}
      <g>
        {edges.map(([p, q, scanned], i) => (
          <g key={i}>
            {/* outer glow halo for scanned */}
            {scanned && (
              <line
                x1={p.x} y1={p.y} x2={q.x} y2={q.y}
                stroke="#38bdf8" strokeOpacity="0.18"
                strokeWidth="4.2" strokeLinecap="round"
                filter="url(#cyanGlowSoft)"
              />
            )}
            <line
              x1={p.x} y1={p.y} x2={q.x} y2={q.y}
              stroke="#38bdf8"
              strokeOpacity={scanned ? 0.92 : 0.28}
              strokeWidth={scanned ? 1.4 : 1.05}
              strokeLinecap="round"
              strokeDasharray={scanned ? undefined : "5 6"}
              filter={scanned ? "url(#cyanGlow)" : undefined}
            />
          </g>
        ))}
      </g>

      {/* floor depth lines */}
      <g opacity="0.55">
        {floorScan.map(([p, q], i) => (
          <line key={i}
            x1={p.x} y1={p.y} x2={q.x} y2={q.y}
            stroke="#38bdf8" strokeOpacity="0.4"
        strokeWidth="0.7" strokeDasharray="2 4"
          />
        ))}
      </g>

      {/* joint dots */}
      <g>
        {pts.map((p, i) => (
          <g key={i}>
            {p.scanned && (
              <circle cx={p.x} cy={p.y} r={6.5}
                fill="#38bdf8" fillOpacity="0.1"
                filter="url(#cyanGlowSoft)" />
            )}
            <circle
              cx={p.x} cy={p.y} r={p.scanned ? 3.2 : 2.4}
              fill={p.scanned ? "#7dd3fc" : "rgba(56,189,248,0.45)"}
              stroke={p.scanned ? "#bae6fd" : "rgba(56,189,248,0.6)"}
              strokeWidth={p.scanned ? 0.5 : 0.35}
              filter={p.scanned ? "url(#cyanGlow)" : undefined}
            />
          </g>
        ))}
      </g>

      {/* point cloud sprinkle — gives depth */}
      <g opacity="0.5">
        {Array.from({ length: 38 }).map((_, i) => {
          // deterministic pseudo-random
          const r = (Math.sin(i * 12.9898) * 43758.5453) % 1;
          const r2 = (Math.sin(i * 78.233) * 12345.678) % 1;
          const x = 80 + Math.abs(r) * 280;
          const y = 230 + Math.abs(r2) * 230;
          const sz = 0.6 + (Math.abs(r) * 1.2);
          return (
            <circle key={i} cx={x} cy={y} r={sz}
              fill="#7dd3fc" opacity={0.3 + Math.abs(r2) * 0.5}/>
          );
        })}
      </g>
    </svg>
  );
}

// ─────────────────────────────────────────────────────────────
// Sweeping horizontal scan line — animated via CSS keyframes
// ─────────────────────────────────────────────────────────────
function ScanLine() {
  return (
    <div style={{
      position: 'absolute', left: 0, right: 0, top: 0, bottom: 0,
      overflow: 'hidden', pointerEvents: 'none',
    }}>
      <div className="scan-sweep" style={{
        position: 'absolute', left: 0, right: 0, height: 220,
        background: 'linear-gradient(to bottom, rgba(56,189,248,0) 0%, rgba(56,189,248,0.08) 40%, rgba(125,211,252,0.42) 80%, rgba(186,230,253,0.85) 96%, rgba(125,211,252,0.3) 100%)',
        mixBlendMode: 'screen',
        filter: 'blur(0.4px)',
      }} />
      <div className="scan-sweep" style={{
        position: 'absolute', left: 0, right: 0, height: 2,
        marginTop: 218,
        background: 'linear-gradient(to right, transparent 0%, rgba(125,211,252,0.0) 8%, rgba(186,230,253,0.9) 50%, rgba(125,211,252,0) 92%, transparent 100%)',
        boxShadow: '0 0 18px rgba(125,211,252,0.7), 0 0 36px rgba(56,189,248,0.5)',
      }} />
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// Glass button — small round X close
// ─────────────────────────────────────────────────────────────
function CloseButton() {
  return (
    <button
      onClick={() => {}}
      className="tap"
      style={{
        width: 38, height: 38, borderRadius: 19,
      background: 'rgba(255,255,255,0.88)',
        backdropFilter: 'blur(18px) saturate(180%)',
        WebkitBackdropFilter: 'blur(18px) saturate(180%)',
        border: '1px solid rgba(255,255,255,0.42)',
        display: 'flex', alignItems: 'center', justifyContent: 'center',
        padding: 0, cursor: 'pointer',
        boxShadow: '0 8px 20px rgba(15,23,42,0.12), inset 0 1px 0 rgba(255,255,255,0.42)',
      }}
      aria-label="閉じる"
    >
      <svg width="14" height="14" viewBox="0 0 14 14">
        <path d="M2 2L12 12 M12 2L2 12"
          stroke="rgba(51,65,85,0.92)" strokeWidth="1.8"
          strokeLinecap="round" />
      </svg>
    </button>
  );
}

// ─────────────────────────────────────────────────────────────
// Guidance bubble (top right)
// ─────────────────────────────────────────────────────────────
function GuidanceBubble() {
  return (
    <div style={{
      position: 'relative',
      maxWidth: 188,
      background: '#fff',
      borderRadius: 14,
      padding: '10px 14px',
      boxShadow: '0 14px 28px rgba(15,23,42,0.12), 0 2px 6px rgba(15,23,42,0.06)',
      fontFamily: 'var(--font-jp)',
      fontSize: 13,
      lineHeight: 1.45,
      color: '#0F172A',
      fontWeight: 500,
      letterSpacing: 0.1,
    }}>
      <svg width="15" height="15" viewBox="0 0 15 15" style={{ marginRight: 6, verticalAlign: -2 }}>
        <rect x="3.3" y="1.4" width="8.4" height="12.2" rx="2" fill="none" stroke="#334155" strokeWidth="1.3"/>
        <path d="M6.2 11.6h2.6" stroke="#334155" strokeWidth="1.3" strokeLinecap="round"/>
      </svg>
      部屋の周りを<br/>ゆっくり歩く
      {/* tail (down-pointing triangle) */}
      <div style={{
        position: 'absolute',
        bottom: -7, right: 28,
        width: 0, height: 0,
        borderLeft: '7px solid transparent',
        borderRight: '7px solid transparent',
        borderTop: '8px solid #fff',
        filter: 'drop-shadow(0 2px 1px rgba(0,0,0,0.1))',
      }} />
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// Progress card (blur, glass)
// ─────────────────────────────────────────────────────────────
function ProgressCard({ pct = 75, completed, phase, metrics }) {
  const title =
    !completed ? "読み取り中..." :
    phase === 0 ? "フレーム固定中..." :
    phase === 1 ? "壁面を解析中..." :
    phase === 2 ? "開口部を抽出中..." :
    "平面化の準備ができました";
  const eta =
    !completed ? "約30" :
    phase === 0 ? "約8" :
    phase === 1 ? "約5" :
    phase === 2 ? "約2" :
    "0";
  const tone = completed && phase >= 3 ? "#38bdf8" : "#f0b674";
  const fillWidth = completed ? Math.max(82, metrics.confidence) : pct;

  return (
    <div style={{
      margin: '0 16px',
      borderRadius: 18,
      padding: '14px 16px 16px',
      position: 'relative',
      overflow: 'hidden',
      background: 'rgba(255,255,255,0.9)',
      backdropFilter: 'blur(22px) saturate(180%)',
      WebkitBackdropFilter: 'blur(22px) saturate(180%)',
      border: '1px solid rgba(148,163,184,0.16)',
      boxShadow: '0 18px 34px rgba(15,23,42,0.12), inset 0 1px 0 rgba(255,255,255,0.4)',
    }}>
      <div style={{
        display: 'flex', alignItems: 'baseline', justifyContent: 'space-between',
        marginBottom: 10,
      }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
          {/* pulsing dot */}
          <span className="pulse-dot" style={{
            width: 8, height: 8, borderRadius: 4,
            background: tone,
            boxShadow: `0 0 10px ${tone}`,
          }} />
          <span style={{
            fontFamily: 'var(--font-jp)',
            fontSize: 15, fontWeight: 700, color: '#0f172a',
            letterSpacing: 0.2,
          }}>
            {title}
          </span>
        </div>
        <div style={{
          fontFamily: 'var(--font-jp)',
          fontSize: 13, color: '#64748b',
          fontWeight: 400,
        }}>
          <span style={{ fontFamily: 'var(--font-num)', fontWeight: 700, color: '#0f172a', fontSize: 14 }}>{eta}</span>{completed && phase >= 3 ? "" : "秒"}
        </div>
      </div>

      {/* progress track */}
      <div style={{
        height: 6, borderRadius: 3,
        background: 'rgba(226,232,240,0.88)',
        position: 'relative', overflow: 'hidden',
      }}>
        <div style={{
          width: `${fillWidth}%`, height: '100%', borderRadius: 3,
          background: completed && phase >= 3
            ? 'linear-gradient(90deg, #38bdf8 0%, #7dd3fc 100%)'
            : 'linear-gradient(90deg, #d4a574 0%, #f0b674 100%)',
          boxShadow: completed && phase >= 3
            ? '0 0 14px rgba(56,189,248,0.7), 0 0 4px rgba(125,211,252,0.9)'
            : '0 0 14px rgba(240,182,116,0.7), 0 0 4px rgba(212,165,116,0.9)',
          position: 'relative',
          overflow: 'hidden',
        }}>
          <div className="shimmer" style={{
            position: 'absolute', inset: 0,
            background: 'linear-gradient(90deg, transparent 0%, rgba(255,255,255,0.62) 50%, transparent 100%)',
          }}/>
        </div>
      </div>

      <div style={{
        marginTop: 8,
        display: 'flex', justifyContent: 'space-between',
        fontFamily: 'var(--font-num)',
        fontSize: 11, color: '#94a3b8',
        letterSpacing: 0.3,
      }}>
        <span>{completed ? "図面作成中" : "スキャン中"}</span>
        <span>{fillWidth}%</span>
      </div>
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// Big complete button
// ─────────────────────────────────────────────────────────────
function CompleteButton({ completed, onClick }) {
  const [pressed, setPressed] = React.useState(false);
  return (
    <button
      onClick={onClick}
      onPointerDown={() => setPressed(true)}
      onPointerUp={() => setPressed(false)}
      onPointerLeave={() => setPressed(false)}
      style={{
        width: 84, height: 84, borderRadius: 42,
        border: 'none',
        background: 'linear-gradient(180deg, #f4d7aa 0%, #e9bb7b 100%)',
        boxShadow: pressed
          ? '0 4px 14px rgba(233,187,123,0.22), inset 0 1px 0 rgba(255,255,255,0.5), inset 0 -2px 6px rgba(15,23,42,0.08)'
          : '0 12px 24px rgba(233,187,123,0.24), inset 0 1px 0 rgba(255,255,255,0.56), inset 0 -3px 8px rgba(15,23,42,0.08)',
        transform: pressed ? 'scale(0.96)' : 'scale(1)',
        transition: 'transform 120ms cubic-bezier(0.2,0.7,0.2,1), box-shadow 200ms ease',
        cursor: 'pointer',
        display: 'flex', alignItems: 'center', justifyContent: 'center',
        fontFamily: 'var(--font-jp)',
        fontSize: 17, fontWeight: 700,
        color: '#5b3b12',
        letterSpacing: 1.5,
        position: 'relative',
      }}
    >
      <span style={{ marginRight: -1.5 }}>{completed ? "再開" : "完了"}</span>
    </button>
  );
}

// ─────────────────────────────────────────────────────────────
// Status bar (custom — white text)
// ─────────────────────────────────────────────────────────────
function StatusBar() {
  return (
    <div style={{
      display: 'flex', alignItems: 'center', justifyContent: 'space-between',
      padding: '21px 34px 0', height: 54, boxSizing: 'border-box',
      position: 'relative', zIndex: 30,
    }}>
      <div style={{
        fontFamily: 'var(--font-num)', fontWeight: 600,
        fontSize: 17, color: '#ffffff', letterSpacing: -0.2,
      }}>9:41</div>
      <div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
        <svg width="19" height="12" viewBox="0 0 19 12">
          <rect x="0" y="7.5" width="3.2" height="4.5" rx="0.7" fill="#fff"/>
          <rect x="4.8" y="5" width="3.2" height="7" rx="0.7" fill="#fff"/>
          <rect x="9.6" y="2.5" width="3.2" height="9.5" rx="0.7" fill="#fff"/>
          <rect x="14.4" y="0" width="3.2" height="12" rx="0.7" fill="#fff"/>
        </svg>
        <svg width="17" height="12" viewBox="0 0 17 12">
          <path d="M8.5 3.2C10.8 3.2 12.9 4.1 14.4 5.6L15.5 4.5C13.7 2.7 11.2 1.5 8.5 1.5C5.8 1.5 3.3 2.7 1.5 4.5L2.6 5.6C4.1 4.1 6.2 3.2 8.5 3.2Z" fill="#fff"/>
          <path d="M8.5 6.8C9.9 6.8 11.1 7.3 12 8.2L13.1 7.1C11.8 5.9 10.2 5.1 8.5 5.1C6.8 5.1 5.2 5.9 3.9 7.1L5 8.2C5.9 7.3 7.1 6.8 8.5 6.8Z" fill="#fff"/>
          <circle cx="8.5" cy="10.5" r="1.5" fill="#fff"/>
        </svg>
        <svg width="27" height="13" viewBox="0 0 27 13">
          <rect x="0.5" y="0.5" width="23" height="12" rx="3.5" stroke="#fff" strokeOpacity="0.4" fill="none"/>
          <rect x="2" y="2" width="20" height="9" rx="2" fill="#fff"/>
          <path d="M25 4.5V8.5C25.8 8.2 26.5 7.2 26.5 6.5C26.5 5.8 25.8 4.8 25 4.5Z" fill="#fff" fillOpacity="0.4"/>
        </svg>
      </div>
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// Full screen
// ─────────────────────────────────────────────────────────────
function ScanScreen() {
  const [completed, setCompleted] = React.useState(false);
  const [captureTick, setCaptureTick] = React.useState(0);
  const [phase, setPhase] = React.useState(0);
  const [metrics, setMetrics] = React.useState({
    walls: 0,
    ceilings: 0,
    openings: 0,
    area: 0,
    confidence: 64,
  });

  React.useEffect(() => {
    if (!completed) {
      setPhase(0);
      setMetrics({
        walls: 0,
        ceilings: 0,
        openings: 0,
        area: 0,
        confidence: 64,
      });
      return;
    }

    const timers = [
      setTimeout(() => {
        setPhase(1);
        setMetrics({ walls: 4, ceilings: 0, openings: 0, area: 7.8, confidence: 76 });
      }, 500),
      setTimeout(() => {
        setPhase(2);
        setMetrics({ walls: 8, ceilings: 3, openings: 0, area: 9.2, confidence: 88 });
      }, 1300),
      setTimeout(() => {
        setPhase(3);
        setMetrics({ walls: 8, ceilings: 3, openings: 1, area: 9.9, confidence: 94 });
      }, 2200),
    ];

    return () => timers.forEach((timer) => clearTimeout(timer));
  }, [completed]);

  const handleComplete = () => {
    if (completed) {
      setCompleted(false);
      return;
    }
    setCaptureTick((value) => value + 1);
    setCompleted(true);
  };

  return (
    <div
      data-screen-label="01 スキャン中"
      style={{
        width: W, height: H, position: 'relative',
        borderRadius: 0, overflow: 'hidden',
        background: '#f8fafc',
        boxShadow: 'none',
        fontFamily: 'var(--font-jp)',
      }}
    >
      <CameraPreview captureTick={captureTick} completed={completed} />

      {/* radial glow halo behind room */}
      {!completed && (
        <div style={{
          position: 'absolute',
          left: '50%', top: 480, transform: 'translate(-50%, -50%)',
          width: 520, height: 360, borderRadius: '50%',
          background: 'radial-gradient(closest-side, rgba(56,189,248,0.08), rgba(56,189,248,0) 70%)',
          pointerEvents: 'none',
        }} />
      )}

      {/* faint vertical grid */}
      {!completed && (
        <div style={{
          position: 'absolute', inset: 0,
          backgroundImage:
            'linear-gradient(to right, rgba(148,163,184,0.07) 1px, transparent 1px), ' +
            'linear-gradient(to bottom, rgba(148,163,184,0.07) 1px, transparent 1px)',
          backgroundSize: '32px 32px',
          maskImage: 'radial-gradient(ellipse at 50% 45%, #000 30%, transparent 80%)',
          WebkitMaskImage: 'radial-gradient(ellipse at 50% 45%, #000 30%, transparent 80%)',
          pointerEvents: 'none',
        }} />
      )}

      {/* LiDAR room (placed mid-frame) */}
      {!completed && <LidarRoom />}

      {/* sweeping scan line on top of room */}
      {!completed && (
        <div style={{ position: 'absolute', inset: 0, pointerEvents: 'none' }}>
          <ScanLine />
        </div>
      )}

      {completed && <RecognitionOverlay phase={phase} metrics={metrics} />}

      {/* top controls row: X + bubble */}
      <div style={{
        position: 'absolute', top: 18, left: 0, right: 0,
        padding: '0 16px',
        display: 'flex', alignItems: 'flex-start', justifyContent: 'space-between',
        zIndex: 20,
      }}>
        <CloseButton />
        <GuidanceBubble />
      </div>

      {/* progress card */}
      <div style={{
        position: 'absolute', left: 0, right: 0, top: 122, zIndex: 20,
      }}>
        <ProgressCard pct={75} completed={completed} phase={phase} metrics={metrics} />
      </div>

      {/* bottom area */}
      <div style={{
        position: 'absolute', left: 0, right: 0, bottom: 34,
        padding: '0 0 32px',
        display: 'flex', flexDirection: 'column', alignItems: 'center',
        gap: 14,
        zIndex: 20,
      }}>
        <div style={{
          fontFamily: 'var(--font-jp)',
          fontSize: 13,
          color: completed ? '#334155' : 'rgba(255,255,255,0.9)',
          letterSpacing: 0.4,
          fontWeight: 700,
          background: completed ? 'rgba(255,255,255,0.84)' : 'rgba(15,23,42,0.22)',
          border: completed ? '1px solid rgba(148,163,184,0.14)' : '1px solid rgba(255,255,255,0.18)',
          borderRadius: 999,
          padding: '7px 12px',
          backdropFilter: 'blur(14px)',
          WebkitBackdropFilter: 'blur(14px)',
        }}>
          {completed && phase >= 3 ? "間取りタブで平面図を確認" : completed ? "認識結果を確認中" : "スキャン完了したらタップ"}
        </div>
        <CompleteButton completed={completed} onClick={handleComplete} />
      </div>
      {/* keyframes */}
      <style>{`
        @keyframes scanSweep {
          0%   { transform: translateY(-260px); opacity: 0; }
          8%   { opacity: 1; }
          92%  { opacity: 1; }
          100% { transform: translateY(${H + 60}px); opacity: 0; }
        }
        .scan-sweep {
          animation: scanSweep 3.2s cubic-bezier(0.45, 0, 0.55, 1) infinite;
          will-change: transform, opacity;
        }
        @keyframes pulseDot {
          0%, 100% { transform: scale(1); opacity: 1; box-shadow: 0 0 10px rgba(240,182,116,0.9); }
          50%      { transform: scale(1.35); opacity: 0.7; box-shadow: 0 0 16px rgba(240,182,116,1); }
        }
        .pulse-dot { animation: pulseDot 1.4s ease-in-out infinite; }
        @keyframes shimmerSlide {
          0%   { transform: translateX(-100%); }
          100% { transform: translateX(200%); }
        }
        .shimmer { animation: shimmerSlide 1.8s linear infinite; }
      `}</style>
    </div>
  );
}

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<ScanScreen />);
