/* dgwebcamet frontend — direction "camera oscura".
   Two stages: NAVY for the ceremonial screens (welcome, consent, thank-you, errors)
   where the audience of an experience room looks, and COOL WHITE for the working
   screens (setup, calibration) where the screen is the participant's key light and the
   camera needs it. Black only under the stimulus. Brand palette (docs/brand-identity.md):
   navy, teal, blue, orange; Inter for everything, Plex Mono for readouts.
   Orange marks the ONE action or the ONE correction on a screen; teal means "this is
   fine". Nothing else is coloured. */

@font-face {
    font-family: "Inter";
    src: url("fonts/inter-latin-300-normal.woff2") format("woff2");
    font-weight: 300;
    font-display: swap;
}
@font-face {
    font-family: "Inter";
    src: url("fonts/inter-latin-400-normal.woff2") format("woff2");
    font-weight: 400;
    font-display: swap;
}
@font-face {
    font-family: "Inter";
    src: url("fonts/inter-latin-500-normal.woff2") format("woff2");
    font-weight: 500;
    font-display: swap;
}
@font-face {
    font-family: "Inter";
    src: url("fonts/inter-latin-600-normal.woff2") format("woff2");
    font-weight: 600;
    font-display: swap;
}
@font-face {
    font-family: "IBM Plex Mono";
    src: url("fonts/ibm-plex-mono-latin-400-normal.woff2") format("woff2");
    font-weight: 400;
    font-display: swap;
}

:root {
    --navy: #0f172a;
    --white: #f5f7fa;
    --ink: #0f172a;
    --ink-70: #55606e;
    --ink-40: #8a95a3;
    --line: #dde3ea;
    --fog: #aeb8c6;      /* secondary text on navy */
    --fog-40: #6b7686;   /* readout labels on navy */
    --teal: #14b8a6;
    --blue: #3b82f6;
    --orange: #E86C3D;
    --mirror: #1a2330;   /* camera slot ground before the stream is up */
    --black: #000;
    --font: "Inter", "Helvetica Neue", Arial, sans-serif;
    --mono: "IBM Plex Mono", ui-monospace, Menlo, monospace;
    --gutter: 5vw;
}

* { margin: 0; padding: 0; box-sizing: border-box; }

html, body { height: 100%; }

body {
    background: var(--white);
    color: var(--ink);
    font-family: var(--font);
    font-size: clamp(16px, 1.25vw, 20px);
    line-height: 1.45;
    -webkit-font-smoothing: antialiased;
}

.app { min-height: 100vh; }

/* ── stages ─────────────────────────────────────────────────────────────── */

.stage {
    position: relative;
    min-height: 100vh;
    padding: 6vh var(--gutter) 6vh;
    display: flex;
    flex-direction: column;
    animation: rise 320ms ease-out;
}

.stage--dark { background: var(--navy); color: #eef2f7; }

.stage--light { background: var(--white); color: var(--ink); }

.stage--black {
    background: var(--black);
    justify-content: center;
    padding: 0;
    cursor: none;
}

.stage--calibration {
    position: fixed;
    inset: 0;
    padding: 0;
    cursor: none;
    overflow: hidden;
    animation: none;
}

@keyframes rise {
    from { opacity: 0; }
    to { opacity: 1; }
}

/* ── header: wordmark + phase trail ──────────────────────────────────────── */

.header {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 2rem;
}

.wordmark { font-weight: 300; font-size: 1.25em; letter-spacing: 0.02em; }

.wordmark b { font-weight: 600; }

.trail { display: flex; gap: 1.6em; font-size: 0.85em; letter-spacing: 0.02em; }

.trail-item { display: flex; align-items: center; gap: 0.5em; opacity: 0.45; }

.trail-item--on { opacity: 1; }

.trail-dot { width: 0.65em; height: 0.65em; border-radius: 50%; border: 1.5px solid currentColor; }

.trail-item--on .trail-dot { background: var(--teal); border-color: var(--teal); }

/* ── type ───────────────────────────────────────────────────────────────── */

.display {
    font-weight: 300;
    font-size: clamp(3.2rem, 9vw, 8.5rem);
    line-height: 0.98;
    letter-spacing: -0.03em;
    text-wrap: balance;
}

.display--m {
    font-weight: 300;
    font-size: clamp(2.4rem, 5vw, 4.6rem);
    line-height: 1.05;
    letter-spacing: -0.02em;
    text-wrap: balance;
}

.title {
    font-weight: 400;
    font-size: clamp(1.6rem, 3vw, 2.8rem);
    line-height: 1.15;
    letter-spacing: -0.015em;
    text-wrap: balance;
}

.lede { font-size: 1.35em; line-height: 1.4; max-width: 30ch; }

.stage--dark .lede { color: var(--fog); }

.stage--light .lede { color: var(--ink-70); }

.hint { font-size: 0.95em; color: var(--ink-70); }

.stage--dark .hint { color: var(--fog); }

.readout-label {
    font-family: var(--mono);
    font-size: 0.75em;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--fog-40);
}

.stage--light .readout-label { color: var(--ink-40); }

.readout-value { font-weight: 300; font-size: 3.2em; line-height: 1; letter-spacing: -0.02em; font-variant-numeric: tabular-nums; }

.readout { display: flex; flex-direction: column; gap: 0.5em; }

/* ── controls ───────────────────────────────────────────────────────────── */

.btn {
    font-family: var(--font);
    font-weight: 600;
    font-size: 1.05em;
    color: #fff;
    background: var(--orange);
    border: none;
    border-radius: 999px;
    height: 3.2em;
    padding: 0 2.2em;
    cursor: pointer;
    transition: transform 120ms ease, background 120ms ease;
}

.btn:hover:not(:disabled) { background: #d55f33; transform: translateY(-1px); }

.btn:disabled { background: rgba(174, 184, 198, 0.25); color: var(--fog); cursor: default; }

.btn:focus-visible, .consent-check:focus-within {
    outline: 3px solid var(--blue);
    outline-offset: 3px;
}

.btn--ghost { background: transparent; color: #eef2f7; font-weight: 500; border: 1.5px solid rgba(238, 242, 247, 0.35); }

.btn--ghost:hover:not(:disabled) { background: rgba(238, 242, 247, 0.08); transform: none; }

.btn-row { display: flex; gap: 1em; flex-wrap: wrap; align-items: center; }

/* ── welcome / thank-you / errors (dark) ────────────────────────────────── */

.hero {
    flex: 1;
    display: grid;
    grid-template-columns: minmax(0, 1.1fr) minmax(0, 0.9fr);
    align-items: center;
    gap: 4vw;
}

.hero-text { display: flex; flex-direction: column; gap: 1.6em; align-items: flex-start; }

.hero-mark { justify-self: center; width: min(40vw, 62vh); height: auto; }

.iris-glow { fill: var(--teal); }

.iris-spin { transform-origin: 50% 50%; animation: spin 80s linear infinite; }

.iris-spin--back { animation: spinback 120s linear infinite; }

@keyframes spin { to { transform: rotate(360deg); } }

@keyframes spinback { to { transform: rotate(-360deg); } }

.centered {
    flex: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    text-align: center;
    gap: 1.4em;
}

.centered .lede { max-width: 36ch; }

/* ── consent (dark) ─────────────────────────────────────────────────────── */

.consent { flex: 1; display: flex; flex-direction: column; gap: 6vh; padding-top: 6vh; }

.facts {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 3vw;
}

.fact { display: flex; flex-direction: column; gap: 1em; font-size: 1.15em; line-height: 1.35; }

.fact svg { width: 2.8em; height: 2.8em; stroke: var(--teal); }

.consent-foot { margin-top: auto; display: flex; flex-direction: column; gap: 2.4em; align-items: flex-start; }

.consent-check { display: flex; align-items: center; gap: 0.9em; font-size: 1.15em; cursor: pointer; }

.consent-check input {
    appearance: none;
    width: 1.5em;
    height: 1.5em;
    border: 2px solid var(--teal);
    border-radius: 0.3em;
    display: grid;
    place-content: center;
    cursor: pointer;
}

.consent-check input::before {
    content: "";
    width: 0.8em;
    height: 0.8em;
    clip-path: polygon(14% 44%, 0 65%, 50% 100%, 100% 16%, 80% 0%, 43% 62%);
    background: var(--teal);
    transform: scale(0);
    transition: transform 100ms ease;
}

.consent-check input:checked::before { transform: scale(1); }

.consent-version { font-family: var(--mono); font-size: 0.7em; color: var(--fog-40); letter-spacing: 0.04em; }

/* ── setup (light, live) ────────────────────────────────────────────────── */

/* The mirror is the camera slot: it must stay mounted for the whole app life (the
   stream is attached once by the glue), so it is fixed and merely hidden outside the
   setup screen. Its geometry is shared with the setup grid through --mirror-w. */
:root { --mirror-w: min(52vw, 72vh); --mirror-top: 26vh; }

.camera-slot {
    position: fixed;
    top: var(--mirror-top);
    left: var(--gutter);
    width: var(--mirror-w);
    aspect-ratio: 4 / 3;
    visibility: hidden;
    z-index: 1; /* above the stage, a later positioned sibling that would paint over it */
    border-radius: 1.5vw;
    overflow: hidden;
    background: var(--mirror);
}

.camera-slot--visible { visibility: visible; }

.camera {
    width: 100%;
    height: 100%;
    object-fit: cover;
    transform: scaleX(-1); /* mirror: the participant expects a mirror, the pipeline gets the raw frame */
}

.oval { position: absolute; inset: 0; width: 100%; height: 100%; }

.oval-shade { fill: var(--navy); fill-opacity: 0.55; }

.oval-line { fill: none; stroke: var(--orange); stroke-width: 3; transition: stroke 200ms ease; }

.oval-tol { fill: none; stroke: var(--orange); stroke-opacity: 0.35; stroke-width: 1.5; stroke-dasharray: 6 8; transition: stroke 200ms ease; }

.oval--ok .oval-line, .oval--ok .oval-tol { stroke: var(--teal); }

.oval--idle .oval-line, .oval--idle .oval-tol { stroke: #eef2f7; stroke-opacity: 0.6; }

.mirror-tag {
    position: absolute;
    left: 1.2em;
    bottom: 1em;
    font-family: var(--mono);
    font-size: 0.7em;
    letter-spacing: 0.06em;
    color: var(--ink-40);
}

.setup { flex: 1; display: flex; flex-direction: column; }

.setup-fs { display: flex; flex-direction: column; gap: 1em; align-items: flex-start; margin-top: 0.8em; }

.setup-head { position: absolute; top: 15vh; left: var(--gutter); right: var(--gutter); }

.checks {
    position: absolute;
    top: calc(var(--mirror-top) + 1vh);
    left: calc(var(--gutter) + var(--mirror-w) + 6vw);
    right: var(--gutter);
    display: flex;
    flex-direction: column;
    gap: 4.5vh;
}

.check { display: grid; grid-template-columns: 2.4em minmax(0, 1fr); gap: 1.2em; align-items: start; }

.check-icon { width: 2.4em; height: 2.4em; stroke: var(--ink-40); }

.check--ok .check-icon { stroke: var(--teal); }

.check--fix .check-icon { stroke: var(--orange); }

.check-body { display: flex; flex-direction: column; gap: 0.45em; }

.check-name { font-size: 1.3em; font-weight: 500; }

.check-line { color: var(--ink-70); }

.meter { position: relative; height: 0.5em; background: var(--line); border-radius: 999px; margin-top: 0.3em; }

.meter-band { position: absolute; top: 0; bottom: 0; background: var(--teal); opacity: 0.35; border-radius: 999px; }

.meter-mark {
    position: absolute;
    top: -0.25em;
    width: 0.3em;
    height: 1em;
    margin-left: -0.15em;
    border-radius: 0.15em;
    background: var(--ink-40);
    transition: left 120ms linear;
}

.check--ok .meter-mark { background: var(--teal); }

.check--fix .meter-mark { background: var(--orange); }

.setup-foot {
    position: absolute;
    bottom: 7vh;
    left: calc(var(--gutter) + var(--mirror-w) + 6vw);
    right: var(--gutter);
    display: flex;
    align-items: center;
    gap: 1em;
    color: var(--ink-70);
}

.ring { width: 2.4em; height: 2.4em; flex: none; }

.ring-track { fill: none; stroke: var(--line); stroke-width: 4; }

.ring-fill {
    fill: none;
    stroke: var(--teal);
    stroke-width: 4;
    stroke-linecap: round;
    stroke-dasharray: 226;
    transform: rotate(-90deg);
    transform-origin: 50% 50%;
    transition: stroke-dashoffset 120ms linear;
}

/* ── calibration intro (light, timed) ───────────────────────────────────── */

.intro {
    flex: 1;
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    align-items: center;
    gap: 5vw;
}

.intro-text { display: flex; flex-direction: column; gap: 1.4em; align-items: flex-start; }

.demo {
    position: relative;
    width: 100%;
    aspect-ratio: 8 / 5;
    background: #fff;
    border-radius: 1vw;
    box-shadow: 0 0 0 1.5px var(--line), 0 24px 48px rgba(15, 23, 42, 0.08);
    overflow: hidden;
}

.demo-grid { position: absolute; inset: 0; width: 100%; height: 100%; }

.demo-grid circle { fill: var(--line); }

.demo-dot { position: absolute; left: 0; top: 0; width: 0; height: 0; animation: demo-path 8s ease-in-out infinite; }

.demo-ring {
    position: absolute;
    left: 0;
    top: 0;
    transform: translate(-50%, -50%);
    width: 9%;
    height: 9%;
    border: 3px solid var(--navy);
    border-radius: 50%;
    animation: demo-ring 8s ease-in-out infinite;
}

.demo-core { position: absolute; left: 0; top: 0; transform: translate(-50%, -50%); width: 8px; height: 8px; background: var(--navy); border-radius: 50%; }

@keyframes demo-path {
    0%, 20%  { transform: translate(20%, 24%); }
    30%, 50% { transform: translate(50%, 24%); }
    60%, 80% { transform: translate(80%, 24%); }
    90%, 100% { transform: translate(20%, 55%); }
}

@keyframes demo-ring {
    0%, 25%  { width: 9%; height: 9%; opacity: 1; }
    35%, 50% { width: 8px; height: 8px; opacity: 0.2; }
    55%      { width: 9%; height: 9%; opacity: 1; }
    65%, 80% { width: 8px; height: 8px; opacity: 0.2; }
    85%      { width: 9%; height: 9%; opacity: 1; }
    95%, 100% { width: 8px; height: 8px; opacity: 0.2; }
}

.intro-wait { display: flex; align-items: center; gap: 1em; color: var(--ink-70); }

/* ── calibration dot ────────────────────────────────────────────────────── */

.cal-dot {
    position: absolute;
    left: 0;
    top: 0;
    width: 100px;
    height: 100px;
    transition: transform 500ms ease-in-out;
    display: flex;
    align-items: center;
    justify-content: center;
}

.cal-dot-ring {
    position: absolute;
    width: 100px;
    height: 100px;
    border: 3px solid var(--navy);
    border-radius: 50%;
    transition: width 500ms ease-in, height 500ms ease-in, opacity 500ms ease-in;
}

.cal-dot-core { width: 8px; height: 8px; background: var(--navy); border-radius: 50%; }

.cal-dot--ring .cal-dot-ring { width: 100px; height: 100px; opacity: 1; }

.cal-dot--contracting .cal-dot-ring { width: 10px; height: 10px; opacity: 0.4; }

.cal-dot--held .cal-dot-ring { width: 10px; height: 10px; opacity: 0; }

/* ── waiting / sending ──────────────────────────────────────────────────── */

.iris-pulse svg { width: 5em; height: 5em; }

.iris-outer { fill: none; stroke: currentColor; stroke-width: 2; }

.iris-core { fill: currentColor; }

.iris-breathing { animation: breathe 2.4s ease-in-out infinite; transform-origin: center; }

@keyframes breathe {
    0%, 100% { transform: scale(1); opacity: 1; }
    50% { transform: scale(0.82); opacity: 0.6; }
}

.progress-track { width: min(20rem, 60vw); height: 4px; background: var(--line); border-radius: 2px; overflow: hidden; }

.progress-fill { height: 100%; background: var(--teal); transition: width 200ms linear; }

/* ── stimulus ───────────────────────────────────────────────────────────── */

.stimulus-media { max-width: 100vw; max-height: 100vh; display: block; margin: auto; }

/* Validation targets (study "fill" stimuli): stretch to the exact viewport so a
   marker at (x%, y%) of the SVG viewBox sits at the same normalized viewport
   point — the calibration targets' own convention (Webet.Calibration.target). */
.stimulus-media--fill { width: 100vw; height: 100vh; max-width: none; max-height: none; }

/* ── thank-you with live gaze (dark) ────────────────────────────────────── */

.done {
    flex: 1;
    display: grid;
    grid-template-columns: minmax(0, 0.8fr) minmax(0, 1.2fr);
    align-items: center;
    gap: 4vw;
}

.done-text { display: flex; flex-direction: column; gap: 1.6em; }

.done-readouts { display: flex; flex-direction: column; gap: 1.6em; margin-top: 0.4em; }

.replay {
    position: relative;
    width: 100%;
    border-radius: 0.8vw;
    overflow: hidden;
    background: #1c2536;
    box-shadow: 0 30px 60px rgba(0, 0, 0, 0.35);
}

.replay img { display: block; width: 100%; height: auto; }

.replay-video { display: block; width: 100%; aspect-ratio: 16 / 9; }

.replay-layer { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; }

.fix circle { fill: rgba(15, 23, 42, 0.55); stroke: #fff; stroke-width: 2.5; }

.fix text { fill: #fff; font-family: var(--font); font-weight: 600; font-size: 24px; }

.fix-path { stroke: #fff; stroke-opacity: 0.6; stroke-width: 2.5; stroke-linejoin: round; }

.replay-tag {
    position: absolute;
    left: 1.2em;
    bottom: 1em;
    font-family: var(--mono);
    font-size: 0.7em;
    letter-spacing: 0.06em;
    color: rgba(238, 242, 247, 0.7);
}

/* ── quality floor ──────────────────────────────────────────────────────── */

@media (prefers-reduced-motion: reduce) {
    .stage { animation: none; }
    .iris-breathing, .iris-spin, .demo-dot, .demo-ring { animation: none; }
    .btn { transition: none; }
    /* the calibration dot's motion IS the measurement — it stays */
}

@media (max-width: 900px) {
    .hero, .intro, .done { grid-template-columns: 1fr; }
    .hero-mark { display: none; }
    .facts { grid-template-columns: 1fr; }
    .trail-item span { display: none; }
}
