/* ==========================================================================
   hlcdev.xyz / NO SIGNAL — styles.css
   near-black / off-white / one accent. silence is part of the design.
   ========================================================================== */

/* ---------- 1. tokens ---------- */
:root {
  /* palette */
  --bg:        #070707;
  --bg-2:      #0d0d0c;
  --fg:        #d8d6cf;
  --fg-dim:    #8a8882;
  --fg-faint:  #4a4946;
  --line:      #1c1c1a;
  --noise:     rgba(216, 214, 207, .035);
  --glow:      rgba(216, 214, 207, .35);
  --signal:    #ff4a1c;             /* the ONLY accent. use sparingly. */
  --gold:      #f2c14e;             /* yellow bubble + spread shots only */

  /* type */
  --font: ui-monospace, "SF Mono", SFMono-Regular, "Cascadia Mono", "JetBrains Mono",
          Menlo, Consolas, "Liberation Mono", monospace;
  --t-xs: .6875rem;                 /* 11px meta / labels */
  --t-sm: .8125rem;                 /* 13px body / logs */
  --t-md: 1rem;
  --t-lg: 1.5rem;
  --t-xl: clamp(2rem, 6vw, 4.5rem); /* YOU FOUND IT. */
  --track: .12em;

  /* spacing — 4px pixel unit, 8px grid */
  --px: 4px;
  --s1: 8px;
  --s2: 16px;
  --s3: 24px;
  --s4: 48px;
  --s5: 96px;
  --s6: 160px;
  --gutter: clamp(16px, 5vw, 64px);

  /* timing */
  --t-instant: 60ms;
  --t-fast:    120ms;
  --t-base:    240ms;
  --t-slow:    600ms;
  --t-dwell:   1200ms;
  --ease-crt:  steps(4, end);
  --ease-soft: cubic-bezier(.2, .6, .2, 1);
  --blink:     1060ms;


  /* layers */
  --z-content:  1;
  --z-grain:    20;
  --z-scan:     30;
  --z-vignette: 31;
  --z-trail:    40;
  --z-dissolve: 50;

  color-scheme: dark;
}

/* amber phosphor mode (konami). a MODE, not a second accent. */
body.phosphor {
  --bg:       #080604;
  --bg-2:     #110d08;
  --fg:       #e8b56a;
  --fg-dim:   #9c7a48;
  --fg-faint: #54422a;
  --line:     #1f1911;
  --noise:    rgba(232, 181, 106, .04);
  --glow:     rgba(232, 181, 106, .45);
  --signal:   #ff5a24;
  --gold:     #fff1b8;
}

/* ---------- 2. reset / base ---------- */
*, *::before, *::after { box-sizing: border-box; }
[hidden] { display: none !important; }

html {
  background: var(--bg);
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}

html, body { margin: 0; padding: 0; }

body {
  min-height: 100vh;
  min-height: 100dvh;
  background: var(--bg);
  color: var(--fg);
  font-family: var(--font);
  font-size: var(--t-sm);
  font-weight: 400;
  line-height: 1.6;
  letter-spacing: .02em;
  text-shadow: 0 0 1px var(--glow);
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
  transition: background-color var(--t-slow) var(--ease-soft), color var(--t-slow) var(--ease-soft);
}

p, h1, pre, ul { margin: 0; }
ul { padding: 0; list-style: none; }
pre { font: inherit; white-space: pre-wrap; word-break: break-word; }
h1 { font: inherit; }

::selection { background: var(--fg); color: var(--bg); text-shadow: none; }

button {
  font: inherit;
  color: inherit;
  letter-spacing: inherit;
  background: none;
  border: 0;
  padding: 0;
  margin: 0;
  cursor: pointer;
  text-shadow: inherit;
  -webkit-tap-highlight-color: transparent;
}

/* pixel-style focus ring: hard, stepped, no blur */
:focus { outline: none; }
:focus-visible {
  outline: 1px solid var(--fg);
  outline-offset: 4px;
  box-shadow: 0 0 0 5px var(--bg), 0 0 0 6px var(--fg-faint);
}

.sr-only {
  position: absolute !important;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* ---------- 3. CRT layers ---------- */
/* scanlines — felt, not seen */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: var(--z-scan);
  pointer-events: none;
  background: repeating-linear-gradient(
    to bottom,
    transparent 0 2px,
    rgba(0, 0, 0, .22) 2px 3px
  );
}

/* vignette */
body::after {
  content: "";
  position: fixed;
  inset: 0;
  z-index: var(--z-vignette);
  pointer-events: none;
  background: radial-gradient(ellipse at center, transparent 55%, rgba(0, 0, 0, .55) 100%);
}

/* fx canvases: fixed, full viewport, never interactive */
#fx-grain,
#fx-trail,
#fx-dissolve {
  position: fixed;
  inset: 0;
  width: 100% !important;
  height: 100% !important;
  display: block;
  pointer-events: none;
  image-rendering: pixelated;
  image-rendering: crisp-edges;
}
#fx-grain    { z-index: var(--z-grain); opacity: .035; }
#fx-trail    { z-index: var(--z-trail); }
#fx-dissolve { z-index: var(--z-dissolve); }
#fx-dissolve[hidden] { display: none !important; }

/* single subtle screen dip — engineer toggles body.is-flicker for 90ms */
body.is-flicker #app { animation: crt-flicker 90ms steps(3, end) 1; }
@keyframes crt-flicker {
  0%   { opacity: 1;   filter: none; }
  40%  { opacity: .9;  filter: brightness(.85); }
  70%  { opacity: .97; filter: none; }
  100% { opacity: 1;   filter: none; }
}

/* ---------- 8. glitch helpers (applied/removed by effects.js) ----------
   .glitch-slice  — 2–4px horizontal band offset. set data-text="<text>" on
                    the element for the offset copy; duration via --glitch-ms.
   .glitch-split  — 1px two-tone split (signal + fg). 1-frame feel.
   .g-sig         — span for a single corrupted glyph in the accent.
   .is-glitching  — generic: suppresses transitions while glitching.
   default durations: slice 140ms, split 90ms (keep 60–180ms).       */
.glitch-slice, .is-glitch-slice,
.glitch-split, .is-glitch-split { position: relative; transition: none !important; }

.glitch-slice, .is-glitch-slice { animation: g-jitter var(--glitch-ms, 140ms) steps(3, end) 1; }
.glitch-slice[data-text]::after,
.is-glitch-slice[data-text]::after {
  content: attr(data-text);
  position: absolute;
  inset: 0;
  color: inherit;
  background: var(--bg);
  white-space: inherit;
  pointer-events: none;
  animation: g-slice var(--glitch-ms, 140ms) steps(3, end) 1 both;
}
@keyframes g-jitter {
  0%, 100% { transform: none; }
  33%      { transform: translateX(-1px); }
  66%      { transform: translateX(1px); }
}
@keyframes g-slice {
  0%   { clip-path: inset(38% 0 48% 0); transform: translateX(3px); }
  33%  { clip-path: inset(12% 0 70% 0); transform: translateX(-4px); }
  66%  { clip-path: inset(62% 0 22% 0); transform: translateX(2px); }
  100% { clip-path: inset(50% 0 50% 0); transform: none; }
}

.glitch-split, .is-glitch-split {
  animation: g-split var(--glitch-ms, 90ms) steps(2, end) 1;
}
@keyframes g-split {
  0%, 100% { text-shadow: -1px 0 var(--signal), 1px 0 var(--fg); }
}

.g-sig { color: var(--signal); text-shadow: 0 0 1px var(--signal); }

/* permanently unstable char (e.g. inside UNKNOWN label) */
.unstable { animation: unstable 3.7s steps(1, end) infinite; }
@keyframes unstable {
  0%, 91%, 100% { opacity: 1; }
  92%           { opacity: .2; }
  95%           { opacity: .7; }
}

/* ---------- 9. motion primitives ---------- */
@keyframes appear {
  from { opacity: 0; }
  to   { opacity: 1; }
}
@keyframes blink {
  0%, 50% { opacity: 1; }
  50.01%, 100% { opacity: 0; }
}

/* ---------- 10. full-screen game ---------- */
html, body { height: 100%; overflow: hidden; }
body { overscroll-behavior: none; user-select: none; -webkit-user-select: none; }

.offline {
  position: fixed;
  inset: 0;
  min-height: 0;
  display: grid;
  place-items: center;
}

#game {
  display: block;
  image-rendering: pixelated;
  image-rendering: crisp-edges;
  cursor: crosshair;
  touch-action: none;
  -webkit-tap-highlight-color: transparent;
}
#game:focus-visible { outline: none; box-shadow: none; }

/* ---------- 11. reduced motion ---------- */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 1ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 1ms !important;
  }
  #fx-grain, #fx-trail { display: none !important; }
  .glitch-slice, .glitch-split, .is-glitch-slice, .is-glitch-split,
  .glitch-slice::after, .is-glitch-slice::after { animation: none !important; }
  .glitch-slice::after, .is-glitch-slice::after { content: none !important; }
}
