/* =========================================================
   Studio //Azuki — Under Construction
   Recreated from design_handoff_under_construction (canon).
   Tokens: Studio Azuki design system, Signal-dark (tube) set.
   ========================================================= */

/* Licensed faces (footer only) — confirm web-embedding rights before
   go-live; fallbacks below are the README-blessed substitutes. */
@font-face {
  font-family: 'Spot Mono';
  src: url('fonts/SpotMono-Regular.ttf') format('truetype');
  font-weight: 400; font-style: normal; font-display: swap;
}
/* (Styrene B was only ever the wordmark stand-in; the footer now uses the
   real logo artwork inline, so the licensed face is gone entirely.) */

:root {
  --signal-dark-ground: #0A0F0A;
  --signal-dark-ink: #F4EFE6;
  --signal-dark-muted: #7E8A82;
  --tally-on-dark: #F0455F;
  /* Channel-themable knobs — channels (data-ch) may ONLY override custom
     properties + visibility; never layout. See "Channels" section. */
  --tube-center: #121A12;
  --tube-edge: #0A0F0A;
  --grain-base: 0.1;
  --rail-yellow: #E6E627;
  --rail-cyan: #27E6E6;
  --rail-green: #62D695;
  --rail-red: #F0455F;
  --ease-snap: cubic-bezier(0.4, 0, 0.2, 1);
  --font-pixel: 'DotGothic16', 'Spot Mono', monospace;
  --font-mono: 'Spot Mono', 'JetBrains Mono', 'IBM Plex Mono', ui-monospace, monospace;
  /* Logo red from the brand lockup (#ED1F4C) — NOTE: a third red, distinct
     from --tally-on-dark and --azuki-red; logo artwork only. Flagged in
     SUGGESTIONS.md for Design. */
  --logo-red: #ED1F4C;
  --tex-static: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)'/%3E%3C/svg%3E");
}

html, body { margin: 0; padding: 0; }
body {
  background: var(--signal-dark-ground);
  /* Inherited base from the design system (the reference loads it globally) —
     line-height 1.5 sets every row's height; keep for pixel parity. */
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}
::selection { background: #E3334D; color: #FFFFFF; }
input::placeholder { color: inherit; opacity: 0.5; } /* 0.4 in the prototype — lifted for contrast (Design-approved) */

.screen {
  position: relative;
  isolation: isolate; /* lets CH 03's bars slot behind content via z-index -1 */
  width: 100%;
  height: 100svh;
  min-height: 420px;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  background: radial-gradient(ellipse 120% 90% at 50% 42%, var(--tube-center) 0%, var(--tube-edge) 74%);
}

.osd {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  padding: clamp(24px, 5svh, 56px) clamp(20px, 4.5vw, 72px) clamp(20px, 4svh, 40px);
  color: var(--signal-dark-ink);
}

/* ---------------- Header ---------------- */

.hdr {
  flex-shrink: 0;
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: baseline;
  gap: 8px 24px;
  font-family: var(--font-pixel);
  font-size: clamp(20px, 2.3vw, 30px);
}
.hdr-menu { letter-spacing: 0.18em; text-shadow: 0 0 12px rgba(244, 239, 230, 0.3); }
.hdr-dot { color: var(--signal-dark-muted); text-shadow: none; }
.hdr-jp {
  color: var(--signal-dark-muted);
  text-shadow: none;
  opacity: 0.75;
  letter-spacing: 0.24em;
  margin-left: 2px;
}
.ch-btn {
  font-family: var(--font-pixel);
  font-size: clamp(20px, 2.3vw, 30px);
  letter-spacing: 0.18em;
  background: none;
  border: none;
  padding: 0;
  cursor: pointer;
  color: var(--signal-dark-muted);
}
.ch-num { color: var(--signal-dark-ink); text-shadow: 0 0 12px rgba(244, 239, 230, 0.3); }

/* ---------------- Menu box ---------------- */

.center {
  flex: 1;
  min-height: 0;
  display: flex;
  align-items: center;
  justify-content: center;
}
.box {
  position: relative;
  width: min(100%, 1100px);
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: clamp(4px, 1svh, 10px);
  font-family: var(--font-pixel);
  font-size: clamp(20px, 2.4vw, 32px);
  letter-spacing: 0.08em;
  text-shadow: 0 0 10px rgba(244, 239, 230, 0.25);
}

.row {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  row-gap: 4px;
  padding: 9px 0;
}
.row-notify { row-gap: 10px; }

.marker { width: clamp(24px, 3vw, 36px); flex-shrink: 0; }
.row-notify .marker { font-size: clamp(17px, 2vw, 25px); }
.lab { width: clamp(150px, 20vw, 258px); flex-shrink: 0; }
.colon { width: clamp(16px, 2.2vw, 28px); flex-shrink: 0; }
.val { flex: 1; min-width: min(300px, 58vw); }
.val.val-channel { flex: 0 1 auto; min-width: 0; white-space: nowrap; }

.studio { text-shadow: 1px 0 currentColor, 0 0 10px rgba(244, 239, 230, 0.25); }
.azuki-red { color: var(--tally-on-dark); text-shadow: 1px 0 currentColor, 0 0 10px rgba(240, 69, 95, 0.35); }
.tag { flex: 1 1 auto; min-width: 0; padding-left: 0.35em; }

.chip {
  display: inline-block;
  background: var(--signal-dark-ink);
  color: var(--signal-dark-ground);
  padding: 1px 12px 2px;
  text-shadow: none;
}

.cursor { display: inline-block; animation: uc-blink 1.05s linear infinite; }

.d2 { animation: uc-dot2 1.8s steps(1) infinite; }
.d3 { animation: uc-dot3 1.8s steps(1) infinite; }
.dot-offset { animation-delay: -0.9s; }

/* ---------------- Notify form ---------------- */

.notify {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 12px 16px;
}
.email {
  flex: 1 1 200px;
  min-width: 180px;
  max-width: 420px;
  box-sizing: border-box;
  background: transparent;
  border: none;
  /* dashed 0.4 in the prototype — Design round 2: solid reads "type here" */
  border-bottom: 1px solid rgba(244, 239, 230, 0.5);
  outline: none;
  transition: border-color 220ms var(--ease-snap), box-shadow 220ms var(--ease-snap);
  font-family: var(--font-pixel);
  font-size: clamp(17px, 2vw, 28px);
  letter-spacing: 0.06em;
  color: var(--signal-dark-ink);
  padding: 2px 4px 5px;
  caret-color: var(--signal-dark-ink);
  text-shadow: none;
}
.enter {
  font-family: var(--font-pixel);
  font-size: clamp(16px, 1.9vw, 24px);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  background: none;
  border: 1.5px solid rgba(244, 239, 230, 0.5);
  color: var(--signal-dark-ink);
  padding: 4px 16px 5px;
  min-height: 40px;
  cursor: pointer;
  text-shadow: none;
  transition: background 220ms var(--ease-snap), color 220ms var(--ease-snap), border-color 220ms var(--ease-snap);
}
.enter:hover { background: #FFFFFF; color: #050705; border-color: #FFFFFF; transition-duration: 0s; }
/* Armed state (Design round 2): a valid email inverts the button — the
   subtle call to action. Eases in over the base 220ms as you finish typing. */
.email:valid ~ .enter { background: #FFFFFF; color: #050705; border-color: #FFFFFF; }

.logged { overflow-wrap: anywhere; }
.ns-mail { color: inherit; text-decoration: underline dotted; text-underline-offset: 4px; }

/* Pending + error states (activate once a real endpoint is wired) */
.is-sending .email, .is-sending .enter { opacity: 0.55; }
.is-sending .enter { cursor: default; }
.err { display: block; margin-top: 10px; }
.err[hidden] { display: none; }

/* Honeypot — visually gone, still submittable by naive bots */
.hp { position: absolute; width: 1px; height: 1px; opacity: 0; pointer-events: none; }

/* Focus — the OSD "row selected" idiom: underline doubles up (box-shadow,
   so no layout shift) and the ▸ cursor goes solid (below). Applies on any
   focus, not just keyboard — it's an affordance, not only a11y. */
.email:focus {
  border-bottom-color: rgba(244, 239, 230, 0.85);
  box-shadow: 0 1px 0 rgba(244, 239, 230, 0.85);
}
.enter:focus-visible, .ch-btn:focus-visible {
  outline: 1.5px dashed rgba(244, 239, 230, 0.6);
  outline-offset: 4px;
}
/* Cursor stops blinking while the row is active, and after LOGGED —
   the row is done; the fiction should say so. */
.row-notify:focus-within .cursor,
.row-notify.is-logged .cursor { animation: none; opacity: 1; }
/* The whole row is a click target for the input (wired in main.js);
   the ENTER button keeps its own pointer cursor from its base rule. */
.row-notify { cursor: text; }
.row-notify.is-logged { cursor: default; }

/* ---------------- SMPTE rail ---------------- */

.rail { height: clamp(8px, 1.9svh, 14px); flex-shrink: 0; display: flex; }
.rail i { flex: 1; }
.rail-yellow { background: var(--rail-yellow); }
.rail-cyan { background: var(--rail-cyan); }
.rail-green { background: var(--rail-green); }
.rail-red { background: var(--rail-red); }

/* ---------------- Footer ---------------- */

.foot {
  flex-shrink: 0;
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 12px 24px;
  padding: clamp(14px, 2.6svh, 22px) clamp(20px, 5vw, 48px);
}
.meta {
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.16em;
  color: var(--signal-dark-muted);
}
/* Wordmark — the real lockup (inline SVG paths, dark-surface variant: white
   type, slash trail fading into the tube). font-size is kept purely for the
   line-box strut so footer geometry stays identical to the old type version.
   Hover maps to the brand's light-variant colors: AZUKI + trail go logo red. */
.mark {
  font-size: clamp(15px, 1.6vw, 18px);
  opacity: 0.65;
  cursor: default;
  transition: opacity 220ms var(--ease-snap);
}
.mark-svg { height: clamp(11px, 1.2vw, 13.5px); width: auto; display: inline-block; vertical-align: middle; }
.mk-studio path, .mk-azuki { fill: #FFFFFF; transition: fill 120ms var(--ease-snap); }
.mk-s1 { fill: #282828; transition: fill 120ms var(--ease-snap); }
.mk-s2 { fill: #717171; transition: fill 120ms var(--ease-snap); }
.mark:hover { opacity: 1; }
.mark:hover .mk-azuki { fill: var(--logo-red); }
.mark:hover .mk-s2 { fill: color-mix(in srgb, var(--logo-red) 53%, transparent); }
.mark:hover .mk-s1 { fill: color-mix(in srgb, var(--logo-red) 20%, transparent); }

/* ---------------- Tube overlays ---------------- */

.track {
  position: absolute;
  left: 0; right: 0;
  top: -130px;
  height: 120px;
  pointer-events: none;
  background: linear-gradient(180deg, transparent 0%, rgba(244, 239, 230, 0.05) 42%, rgba(244, 239, 230, 0.09) 50%, rgba(244, 239, 230, 0.05) 58%, transparent 100%);
  animation: uc-track 9s linear infinite;
}
.scan {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background-image: repeating-linear-gradient(0deg, rgba(0, 0, 0, 0.55) 0px, rgba(0, 0, 0, 0.55) 1px, transparent 1px, transparent 3px);
  opacity: 0.3;
  animation: uc-flicker 6s linear infinite;
}
.grain {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background-image: var(--tex-static);
  background-size: 240px 240px;
  opacity: var(--grain-base);
  mix-blend-mode: screen;
  animation: uc-jitter 0.7s steps(1) infinite;
}
/* TV warming up: full-blast static on load, settled by JS after 620ms.
   Channel blip: 260ms spike on CH press. */
.grain.burst { opacity: 0.85; }
.grain.blip { opacity: 0.8; }

/* ---------------- Keyframes ---------------- */

@keyframes uc-blink { 0%, 49% { opacity: 1; } 50%, 100% { opacity: 0; } }
@keyframes uc-flicker { 0%, 100% { opacity: 0.30; } 6% { opacity: 0.38; } 7% { opacity: 0.26; } 31% { opacity: 0.34; } 32% { opacity: 0.28; } 58% { opacity: 0.36; } 59% { opacity: 0.30; } 83% { opacity: 0.40; } 84% { opacity: 0.30; } }
@keyframes uc-jitter { 0% { background-position: 0 0; } 12% { background-position: -52px 30px; } 25% { background-position: 40px -18px; } 37% { background-position: -14px -48px; } 50% { background-position: 60px 22px; } 62% { background-position: -38px 54px; } 75% { background-position: 18px -34px; } 87% { background-position: -60px -8px; } 100% { background-position: 0 0; } }
/* Prototype swept a fixed 1200px, which loops mid-screen on viewports taller
   than ~1330px — Design-approved fix: sweep the actual tube height. */
@keyframes uc-track { from { transform: translateY(0); } to { transform: translateY(calc(100svh + 260px)); } }
@keyframes uc-dot2 { 0%, 32% { opacity: 0; } 33%, 100% { opacity: 1; } }
@keyframes uc-dot3 { 0%, 65% { opacity: 0; } 66%, 100% { opacity: 1; } }

/* ---------------- Phone (≤719px) ---------------- */

/* NOTE: the handoff's authored media block also sets .row { row-gap: 6px },
   footer gap 5px, and box justify-content: space-evenly — but inline styles
   defeat all three in the prototype, so the signed-off rendering uses
   row-gap 4px/10px, footer gap 12px, and justify-content center. We match
   the rendering (per README: the standalone is source of truth). See
   SUGGESTIONS.md if Design wants the authored values instead. */
@media (max-width: 719px) {
  .row .lab { width: 96px; }
  .row .colon { width: 14px; }
  .row .val { min-width: 0; }
  .tag {
    flex: 0 0 100%;
    box-sizing: border-box;
    padding-left: clamp(24px, 3vw, 36px);
    font-size: 0.95em;
    letter-spacing: 0.05em;
  }
  .row .nval {
    flex: 1 1 100%;
    box-sizing: border-box;
    padding-left: clamp(24px, 3vw, 36px);
  }
  .foot {
    flex-direction: column;
    gap: 12px;
    text-align: center;
    padding-top: 14px;
    padding-bottom: 16px;
  }
  .mark { order: -1; }
}

/* Phone portrait: menu capped to a centered 3:4 box so the CRT read
   survives; static fills the rest of the screen. */
@media (max-width: 719px) and (orientation: portrait) {
  .box {
    aspect-ratio: 3 / 4;
    width: min(100%, (100svh - 220px) * 0.75);
  }
}

/* ---------------- Compact viewports (canon gap fixes, Design-approved) ----------------
   The canon envelope was 390×844 / 768×1024 / 1280×800. Below it, two real
   breaks: ≤~360px portrait (3:4 box taller than its content allows → rows
   collide with the header) and landscape phones (min-height 420 clips the
   footer). One shared compression set + a portrait-only aspect release. */

@media (max-width: 379px), (max-height: 480px) {
  .screen { min-height: 0; }
  .osd { padding-top: 16px; padding-bottom: 12px; }
  .row { padding: 4px 0; }
  .box { gap: 4px; }
  .foot { padding-top: 10px; padding-bottom: 12px; }
}
@media (max-width: 379px) and (orientation: portrait) {
  .box { aspect-ratio: auto; width: 100%; font-size: 18px; }
  .row .lab { width: 88px; }
}

/* ---------------- Channels (data-ch on .screen) ----------------
   Guardrail: a channel is a CSS filter over the same broadcast — custom
   properties + visibility only, no layout changes, at most one copy string
   (the .pv variants below). The 260ms CH blip masks every swap. */

/* Per-channel copy: all variants live in the HTML; CSS picks one. */
.pv { display: none; }
.pv-def { display: inline; }
.hv { display: none; }
.hv-def { display: inline; }
[data-ch="04"] .hv-def { display: none; }
[data-ch="04"] .hv-04 { display: inline; }
[data-ch="01"] .row-picture .pv-def { display: none; }
[data-ch="01"] .row-picture .pv-01 { display: inline; }
[data-ch="02"] .row-picture .pv-def { display: none; }
[data-ch="02"] .row-picture .pv-02 { display: inline; }
[data-ch="03"] .row-sound .pv-def { display: none; }
[data-ch="03"] .row-sound .pv-03 { display: inline; }

/* CH 01 — MONO: the red dies (canon: zero red is a legal state), rail goes
   to warm grey steps. PICTURE: B/W. */
[data-ch="01"] {
  --tally-on-dark: var(--signal-dark-ink);
  --logo-red: var(--signal-dark-ink); /* wordmark hover stays colorless on B/W */
  --rail-yellow: #EDEAE2;
  --rail-cyan: #ABA89F;
  --rail-green: #6F6D66;
  --rail-red: #38372F;
}
[data-ch="01"] .azuki-red { text-shadow: 1px 0 currentColor, 0 0 10px rgba(244, 239, 230, 0.25); }

/* CH 02 — BLUE BACK: the VCR "AV IN, no input" blue; the OSD renders over
   it, as real OSDs do. Rail hides (nothing is broadcasting). PICTURE: NO
   INPUT. Blue tuned as content/homage (NOT the benched accent blue). */
[data-ch="02"] {
  --tube-center: #1A26D8;
  --tube-edge: #0F17A6;
  --signal-dark-ground: #0F17A6; /* NOTIFY chip text follows the tube */
  --signal-dark-muted: #8B92C9;
}
[data-ch="02"] .rail { opacity: 0; }

/* CH 03 — TEST CARD: the killed 1C exploration, resurrected as a channel.
   The rail's four colors fill the tube as quiet vertical bars behind the
   OSD; the strip itself hides. SOUND: 1KHZ TONE. 調整中 ("calibrating")
   wakes up in the bar colors. */
[data-ch="03"]::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: linear-gradient(90deg,
    var(--rail-yellow) 0 25%, var(--rail-cyan) 25% 50%,
    var(--rail-green) 50% 75%, var(--rail-red) 75% 100%);
  opacity: 0.2;
}
[data-ch="03"] .rail { opacity: 0; }
[data-ch="03"] .hdr-jp { opacity: 1; }
[data-ch="03"] .jp-g1 { color: var(--rail-yellow); }
[data-ch="03"] .jp-g2 { color: var(--rail-cyan); }
[data-ch="03"] .jp-g3 { color: var(--rail-green); }

/* CH 04 — NO SIGNAL: the killed 1B exploration. Static, the CH readout, and
   the header announcing NO SIGNAL · 信号なし (its copy swap, via .hv above);
   channel-up is the only way out, exactly like a real TV. visibility (not
   display) keeps layout + any half-typed email intact. */
[data-ch="04"] {
  --grain-base: 0.55;
}
[data-ch="04"] .box,
[data-ch="04"] .foot,
[data-ch="04"] .rail { visibility: hidden; }

/* ---------------- Reduced motion ---------------- */

@media (prefers-reduced-motion: reduce) {
  .cursor, .d2, .d3, .grain, .scan, .track { animation: none; }
  .grain.burst { opacity: var(--grain-base); } /* skip the warm-up flash too */
}
