// entry-core.jsx — shared machinery for the standalone entry rituals.
// • follows the OS light/dark like the title page (no in-page toggle)
// • isRight() + reveal(): progressive answer masking ("realis" → ______ that fills)
// • EntryStage: puts the REAL title page (kopelasia.html) behind the ritual, then on
//   solve fades the ritual out to the mode's base colour and lifts that veil to land
//   on the live page — a clean fade-to-black (or -white) based on mode.

const { useState: useS, useEffect: useE, useRef: useR } = React;

const BLUE  = "#2E7BE0";
const HELV  = "'Helvetica Neue', Helvetica, 'Inter', Arial, sans-serif";
const TIMES = "'Times New Roman', Times, serif";
const MONO  = "'Roboto Mono', ui-monospace, SFMono-Regular, Menlo, monospace";

const ANSWER = "realis";
const RED = "#C6362C"; // denial — the one non-bitonal, non-blue signal
const isRight = (v) => (v || "").trim().toLowerCase().replace(/[.!?·\s]+$/, "") === ANSWER;
// display casing is forced — first letter upper, rest lower — whatever the user
// types; matching stays case-agnostic (isRight lowercases anyway).
function normCase(s) { const t = s || ""; return t ? t.charAt(0).toUpperCase() + t.slice(1).toLowerCase() : t; }

// the answer revealed only as far as the typed text matches (correct prefix); the
// rest stay as blanks ('_'). Constant char count, so the ring's textLength keeps
// fitting the circle. casing: 'upper' | 'lower' | 'title'.
function reveal(typed, casing) {
  const t = (typed || "").toLowerCase();
  let n = 0; while (n < ANSWER.length && n < t.length && t[n] === ANSWER[n]) n++;
  let out = "";
  for (let i = 0; i < ANSWER.length; i++) {
    if (i < n) out += (casing === "upper") ? ANSWER[i].toUpperCase() : (casing === "title" && i === 0) ? ANSWER[i].toUpperCase() : ANSWER[i];
    else out += "_";
  }
  return out;
}

function useMode() {
  const [osNight, setOsNight] = useS(() => typeof matchMedia === "undefined" || matchMedia("(prefers-color-scheme: dark)").matches);
  useE(() => {
    if (!window.matchMedia) return;
    const mq = matchMedia("(prefers-color-scheme: dark)");
    const on = (e) => setOsNight(e.matches);
    mq.addEventListener ? mq.addEventListener("change", on) : mq.addListener(on);
    return () => { mq.removeEventListener ? mq.removeEventListener("change", on) : mq.removeListener(on); };
  }, []);
  // BACKWARDS, site-wide default: rowing faces backwards — light theme at night,
  // night theme by day (auto-detected, then inverted). Matches the title page's
  // "Backwards" tweak default.
  const night = !osNight;
  return night
    ? { night: true, base: "#06080B", ink: "#FFFFFF", accent2: "#1E6FD6" }
    : { night: false, base: "#E4E6EA", ink: "#0A0B0E", accent2: "#2A63BC" };
}

// solve() fades the ritual to the base colour, holds, then lifts the veil to
// reveal the page beneath. holdMs / fadeS make the pace tweakable per entry.
function useReveal(holdMs = 640) {
  // once solved, the lock stays open on this browser — straight to the page
  const KEY = "kopelasia-entry-solved";
  const already = (() => { try { return localStorage.getItem(KEY) === "1"; } catch (e) { return false; } })();
  const [content, setContent] = useS(already);
  const [veilGone, setVeilGone] = useS(already);
  const solve = () => { if (content) return; try { localStorage.setItem(KEY, "1"); } catch (e) {} setContent(true); setTimeout(() => setVeilGone(true), holdMs); };
  return { content, veilGone, solve };
}

function EntryStage({ mode, rev, fadeS = 0.8, children }) {
  return (
    <React.Fragment>
      <iframe src={"kopelasia final.html" + (location.hash || "")} title="kopelasía — title page"
        style={{ position: "fixed", inset: 0, width: "100%", height: "100%", border: 0, display: "block", zIndex: 0 }} />
      <div style={{ position: "fixed", inset: 0, zIndex: 10, background: mode.base, opacity: rev.veilGone ? 0 : 1,
        transition: "opacity " + fadeS + "s ease", pointerEvents: rev.veilGone ? "none" : "auto" }}>
        <div style={{ position: "absolute", inset: 0, opacity: rev.content ? 0 : 1, transition: "opacity .55s ease" }}>
          {children}
        </div>
      </div>
    </React.Fragment>
  );
}

Object.assign(window, { BLUE, RED, HELV, TIMES, MONO, isRight, reveal, normCase, useMode, useReveal, EntryStage });
