/* ============================================================================
 * Hacktanic "coming soon" overlay — the unclosable terminal.
 *
 * Injected into the built index.html by maintenance/nginx.conf (sub_filter), so
 * the real SPA still renders behind the glass. This file is presentation only:
 * the actual lock is that /auth/v1, /rest/v1 and /storage/v1 return 503, so
 * there is nothing behind the overlay but the static marketing page.
 *
 * Palette + fonts mirror tailwind.config.js so the window looks native to the
 * site it covers: void #0a0a0a, coal #131313, bone #f2f0ea, bloodText #ff5b5b.
 * ==========================================================================*/

:root {
  --soon-void: #0a0a0a;
  --soon-coal: #131313;
  --soon-bone: #f2f0ea;
  --soon-blood: #e03e3e;
  --soon-blood-text: #ff5b5b;
  --soon-dim: #6f6a63;
}

/* Locked by JS too (inline style), but this keeps the page still if JS classes
   are all that survive. */
html.soon-locked,
html.soon-locked body {
  overflow: hidden !important;
}

/* ------------------------------- the scrim -------------------------------- */

#soon-scrim {
  position: fixed;
  inset: 0;
  z-index: 2147483647;          /* above anything the SPA can produce */
  display: flex;
  align-items: center;
  justify-content: center;
  padding: clamp(0.5rem, 3vw, 2rem);
  background: rgba(10, 10, 10, 0.86);
  backdrop-filter: blur(2px) saturate(0.6);
  -webkit-backdrop-filter: blur(2px) saturate(0.6);
  font-family: 'IBM Plex Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
  color: var(--soon-bone);
  /* Visible is the BASE state, never a state held by animation-fill-mode.
     Anything that later reassigns `animation` on this element (see the jitter
     below) would otherwise drop it back to the base rule and hide it. */
  opacity: 1;
  animation: soon-scrim-in 420ms ease-out both;
  /* the scrim itself swallows every click meant for the site behind it */
  cursor: default;
}

@keyframes soon-scrim-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}

/* CRT scanlines across the whole scrim, not just the window — sells the tube. */
#soon-scrim::after {
  content: '';
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: repeating-linear-gradient(
    to bottom,
    rgba(0, 0, 0, 0) 0px,
    rgba(0, 0, 0, 0) 2px,
    rgba(0, 0, 0, 0.28) 3px,
    rgba(0, 0, 0, 0.28) 4px
  );
  mix-blend-mode: multiply;
  animation: soon-flicker 5.5s steps(2, end) infinite;
}

@keyframes soon-flicker {
  0%, 96%, 100% { opacity: 1; }
  97%           { opacity: 0.72; }
  98%           { opacity: 1; }
  99%           { opacity: 0.85; }
}

/* ------------------------------ the window -------------------------------- */

#soon-window {
  position: relative;
  width: min(100%, 820px);
  max-height: min(94svh, 900px);
  display: flex;
  flex-direction: column;
  background: var(--soon-void);
  border: 1px solid rgba(224, 62, 62, 0.45);
  border-radius: 6px;
  box-shadow:
    0 24px 60px -24px rgba(224, 62, 62, 0.35),
    0 0 0 1px rgba(0, 0, 0, 0.6),
    0 0 120px -40px rgba(224, 62, 62, 0.5);
  overflow: hidden;
  /* Base state is the FINAL state. `.soon-jitter` below reassigns `animation`
     on this element, and a jitter that ended would otherwise revert the window
     to a hidden base rule — the window would simply disappear mid-visit. */
  transform: none;
  opacity: 1;
  animation: soon-window-in 520ms cubic-bezier(0.16, 1, 0.3, 1) 120ms both;
}

@keyframes soon-window-in {
  from { transform: translateY(14px) scale(0.985); opacity: 0; }
  to   { transform: none;                          opacity: 1; }
}

/* Occasional whole-window jitter, as if the signal drops for a frame. */
#soon-window.soon-jitter {
  animation: soon-jitter-kick 220ms steps(2, end) 1;
}

@keyframes soon-jitter-kick {
  0%   { transform: translate(0, 0); }
  25%  { transform: translate(-3px, 1px) skewX(0.6deg); }
  50%  { transform: translate(2px, -2px) skewX(-0.5deg); }
  75%  { transform: translate(-1px, 1px); }
  100% { transform: translate(0, 0); }
}

/* ------------------------------- title bar -------------------------------- */

#soon-titlebar {
  flex: none;
  display: flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.55rem 0.75rem;
  background: var(--soon-coal);
  border-bottom: 1px solid rgba(224, 62, 62, 0.28);
  font-size: 0.72rem;
  letter-spacing: 0.02em;
  color: var(--soon-dim);
  user-select: none;
}

.soon-dot {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  flex: none;
  background: #2a2a2a;
  border: 1px solid #000;
}
.soon-dot.is-live { background: var(--soon-blood); box-shadow: 0 0 8px rgba(224, 62, 62, 0.8); }

#soon-title {
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}

#soon-close {
  margin-left: auto;
  flex: none;
  appearance: none;
  background: transparent;
  border: 1px solid rgba(242, 240, 234, 0.15);
  border-radius: 3px;
  color: var(--soon-dim);
  font: inherit;
  line-height: 1;
  padding: 0.15rem 0.45rem;
  cursor: not-allowed;
}
#soon-close:hover { color: var(--soon-blood-text); border-color: rgba(224, 62, 62, 0.5); }

/* ------------------------------ window body ------------------------------- */

#soon-body {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;      /* scrolling the log must not scroll the page */
  padding: clamp(0.9rem, 2.5vw, 1.6rem);
  font-size: clamp(0.72rem, 0.5rem + 0.6vw, 0.86rem);
  line-height: 1.65;
}

/* ------------------------------- ascii art -------------------------------- */

.soon-art {
  margin: 0 0 1.1rem;
  color: var(--soon-blood-text);
  font-family: inherit;
  line-height: 1.0;
  white-space: pre;
  overflow: hidden;
  /* A wide glow turns 70 columns of block glyphs into mush at small sizes.
     Keep it tight enough that the letterforms survive. */
  text-shadow: 0 0 7px rgba(224, 62, 62, 0.4);
  position: relative;
}

/* 70 columns of ANSI-shadow block art. Sized so it always fits its container:
   0.62em per monospace column is the safe ratio for IBM Plex Mono. */
/* fitArt() measures the rendered glyphs and sets the real size; this is only a
   sane pre-measurement value so there is no flash of enormous text. */
#soon-art { font-size: 10px; display: block; }

/* RGB-split glitch: two clones of the art, offset and colour-shifted, each
   revealing a different horizontal slice on its own clock. */
.soon-art[data-glitch]::before,
.soon-art[data-glitch]::after {
  content: attr(data-glitch);
  position: absolute;
  top: 0;
  left: 0;
  white-space: pre;
  pointer-events: none;
}
.soon-art[data-glitch]::before {
  color: #00e5ff;
  animation: soon-glitch-a 3.4s steps(1, end) infinite;
}
.soon-art[data-glitch]::after {
  color: var(--soon-blood);
  animation: soon-glitch-b 2.7s steps(1, end) infinite;
}

@keyframes soon-glitch-a {
  0%, 88%, 100% { clip-path: inset(100% 0 0 0); transform: none; opacity: 0; }
  89%  { clip-path: inset(12% 0 62% 0); transform: translate(-3px, 0); opacity: 0.85; }
  91%  { clip-path: inset(48% 0 28% 0); transform: translate(2px, 0);  opacity: 0.85; }
  93%  { clip-path: inset(70% 0 12% 0); transform: translate(-2px, 0); opacity: 0.85; }
  95%  { clip-path: inset(100% 0 0 0); opacity: 0; }
}

@keyframes soon-glitch-b {
  0%, 82%, 100% { clip-path: inset(100% 0 0 0); transform: none; opacity: 0; }
  83%  { clip-path: inset(30% 0 44% 0); transform: translate(3px, 0);  opacity: 0.8; }
  86%  { clip-path: inset(60% 0 20% 0); transform: translate(-3px, 0); opacity: 0.8; }
  89%  { clip-path: inset(100% 0 0 0); opacity: 0; }
}

/* --------------------------------- log ------------------------------------ */

#soon-log { margin: 0 0 1rem; }

.soon-line { white-space: pre-wrap; word-break: break-word; }
.soon-ok    { color: #57d977; }
.soon-warn  { color: #ffb454; }
.soon-lock  { color: var(--soon-blood-text); }
.soon-dim   { color: var(--soon-dim); }

.soon-headline {
  margin: 1.1rem 0 0.35rem;
  color: var(--soon-bone);
  font-size: 1.06em;
  letter-spacing: 0.03em;
}
.soon-sub { color: var(--soon-dim); margin-bottom: 1rem; }

/* -------------------------- manifest + founder ----------------------------- */

#soon-manifest,
#soon-founder {
  margin: 0 0 1.2rem;
  padding: 0.75rem 0.9rem;
  border-left: 2px solid rgba(224, 62, 62, 0.5);
  background: rgba(224, 62, 62, 0.05);
  color: var(--soon-bone);
}
#soon-founder { white-space: pre-wrap; }

/* Item name in its own column so a long description wraps under itself
   instead of running back beneath the names. */
.soon-manifest-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 0.05rem 1.2rem;
  margin-top: 0.35rem;
}
@media (min-width: 560px) {
  .soon-manifest-grid { grid-template-columns: max-content 1fr; }
}
.soon-manifest-grid .mk { color: var(--soon-bone); white-space: nowrap; }
.soon-manifest-grid .mv { color: var(--soon-dim); }
@media (max-width: 559px) {
  .soon-manifest-grid .mv { padding: 0 0 0.35rem 1.6ch; }
}
#soon-manifest .k,
#soon-founder .k {
  color: var(--soon-blood-text);
  text-transform: uppercase;
  letter-spacing: 0.08em;
}
#soon-manifest .v,
#soon-founder .v { color: var(--soon-dim); }

/* The founder tier is the offer that actually converts — give it the loud
   border and let the manifest above it stay quiet. */
#soon-founder {
  border-left-color: var(--soon-blood-text);
  background: rgba(224, 62, 62, 0.1);
  box-shadow: inset 0 0 40px -20px rgba(224, 62, 62, 0.6);
}

/* -------------------------------- counter --------------------------------- */

#soon-counter { margin: 0 0 1.2rem; }
#soon-counter > div { margin-bottom: 0.2rem; }

.soon-bar {
  color: var(--soon-blood-text);
  white-space: pre;
}
.soon-count-label { color: var(--soon-bone); white-space: pre; }
.soon-count-label b { color: var(--soon-blood-text); font-weight: 400; }

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

#soon-form { margin: 0; display: block; }

.soon-field {
  display: flex;
  align-items: baseline;
  gap: 0.5ch;
  flex-wrap: wrap;
  margin-bottom: 0.5rem;
}
.soon-prompt { color: var(--soon-blood-text); flex: none; }

.soon-input {
  flex: 1 1 14ch;
  min-width: 0;
  appearance: none;
  background: transparent;
  border: 0;
  border-bottom: 1px dashed rgba(242, 240, 234, 0.25);
  color: var(--soon-bone);
  font: inherit;
  padding: 0.15rem 0.2rem;
  outline: none;
  caret-color: var(--soon-blood-text);
}
.soon-input::placeholder { color: #4a4640; }
.soon-input:focus { border-bottom-color: var(--soon-blood-text); background: rgba(224, 62, 62, 0.06); }

#soon-submit {
  margin-top: 0.5rem;
  appearance: none;
  background: transparent;
  border: 1px solid var(--soon-blood);
  border-radius: 3px;
  color: var(--soon-blood-text);
  font: inherit;
  letter-spacing: 0.08em;
  padding: 0.4rem 1.1rem;
  cursor: pointer;
  transition: background 140ms ease, color 140ms ease;
}
#soon-submit:hover:not(:disabled) { background: var(--soon-blood); color: var(--soon-void); }
#soon-submit:disabled { opacity: 0.45; cursor: wait; }

#soon-status { margin-top: 0.6rem; min-height: 1.4em; }

#soon-contact {
  margin: 1.3rem 0 0;
  padding-top: 0.9rem;
  border-top: 1px solid rgba(242, 240, 234, 0.08);
  color: var(--soon-dim);
}
#soon-contact a { color: var(--soon-blood-text); text-decoration: none; }
#soon-contact a:hover { text-decoration: underline; }

/* -------------------------------- cursor ---------------------------------- */

.soon-caret {
  display: inline-block;
  width: 0.62em;
  height: 1.05em;
  vertical-align: text-bottom;
  background: var(--soon-blood-text);
  animation: soon-blink 1.05s steps(1, end) infinite;
}

@keyframes soon-blink {
  0%, 49%   { opacity: 1; }
  50%, 100% { opacity: 0; }
}

/* --------------------------- reduced motion ------------------------------- */

@media (prefers-reduced-motion: reduce) {
  #soon-scrim,
  #soon-window { animation: none; opacity: 1; transform: none; }
  #soon-scrim::after { animation: none; }
  .soon-art[data-glitch]::before,
  .soon-art[data-glitch]::after { display: none; }
  .soon-caret { animation: none; opacity: 1; }
  #soon-window.soon-jitter { animation: none; }
}

/* ============================ tier comparison ==============================
 * Genuinely side by side on anything with room, stacked on a phone. Two 33ch
 * columns cannot be squeezed into 340px without becoming unreadable, and a
 * comparison nobody can read compares nothing.
 * ========================================================================= */

#soon-tiers {
  display: grid;
  grid-template-columns: 1fr;
  gap: 0.75rem;
  margin: 0 0 1.2rem;
}

@media (min-width: 620px) {
  #soon-tiers { grid-template-columns: 1fr 1fr; }
}

.soon-tier {
  border: 1px solid rgba(242, 240, 234, 0.14);
  border-radius: 4px;
  padding: 0.8rem 0.9rem;
  background: rgba(255, 255, 255, 0.02);
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
}

/* The first-100 column has to win the eye — it is the offer that converts. */
.soon-tier.is-top {
  border-color: var(--soon-blood);
  background: rgba(224, 62, 62, 0.1);
  box-shadow: inset 0 0 44px -22px rgba(224, 62, 62, 0.75);
}

.soon-tier-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.5ch;
  margin-bottom: 0.45rem;
  padding-bottom: 0.4rem;
  border-bottom: 1px dashed rgba(242, 240, 234, 0.14);
}
.soon-tier-rank { color: var(--soon-dim); font-size: 0.9em; }
.soon-tier.is-top .soon-tier-rank { color: var(--soon-blood-text); }
.soon-tier-name {
  color: var(--soon-bone);
  text-transform: uppercase;
  letter-spacing: 0.1em;
}
.soon-tier.is-top .soon-tier-name { color: var(--soon-blood-text); }

.soon-perk { display: flex; gap: 0.6ch; align-items: baseline; }
.soon-perk .tick { color: var(--soon-blood-text); flex: none; }
.soon-tier:not(.is-top) .soon-perk .tick { color: var(--soon-dim); }
.soon-perk .txt { color: var(--soon-bone); }
.soon-perk.is-absent .txt { color: #4a4640; text-decoration: line-through; }
.soon-perk.is-absent .tick { color: #3a3630; }

/* ============================== actions ================================== */

#soon-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.75rem;
  margin: 0 0 0.4rem;
}

#soon-signup-open {
  appearance: none;
  background: var(--soon-blood);
  border: 1px solid var(--soon-blood);
  border-radius: 3px;
  color: var(--soon-void);
  font: inherit;
  font-size: 1.02em;
  letter-spacing: 0.1em;
  padding: 0.55rem 1.4rem;
  cursor: pointer;
  transition: background 140ms ease, color 140ms ease, box-shadow 140ms ease;
}
#soon-signup-open:hover {
  background: transparent;
  color: var(--soon-blood-text);
  box-shadow: 0 0 24px -6px rgba(224, 62, 62, 0.7);
}
#soon-signup-open:focus-visible { outline: 2px solid var(--soon-bone); outline-offset: 2px; }

#soon-actions .hint { color: var(--soon-dim); }

/* ========================== the signup window =============================
 * A second terminal stacked over the first. Unlike the teaser behind it, this
 * one closes — it is a form, not a wall.
 * ======================================================================== */

#soon-signup-scrim {
  position: absolute;
  inset: 0;
  z-index: 5;
  display: none;
  align-items: center;
  justify-content: center;
  padding: clamp(0.5rem, 3vw, 2rem);
  background: rgba(10, 10, 10, 0.72);
}
#soon-signup-scrim.is-open { display: flex; }

#soon-signup-window {
  width: min(100%, 620px);
  max-height: min(90svh, 720px);
  display: flex;
  flex-direction: column;
  background: var(--soon-coal);
  border: 1px solid rgba(224, 62, 62, 0.6);
  border-radius: 6px;
  box-shadow: 0 30px 70px -30px rgba(0, 0, 0, 0.9), 0 0 90px -30px rgba(224, 62, 62, 0.55);
  overflow: hidden;
  animation: soon-signup-in 260ms cubic-bezier(0.16, 1, 0.3, 1) both;
}

@keyframes soon-signup-in {
  from { transform: translateY(10px) scale(0.98); opacity: 0; }
  to   { transform: none; opacity: 1; }
}

#soon-signup-body {
  padding: clamp(0.9rem, 2.5vw, 1.4rem);
  overflow-y: auto;
  overscroll-behavior: contain;
}

#soon-signup-close {
  margin-left: auto;
  appearance: none;
  background: transparent;
  border: 1px solid rgba(242, 240, 234, 0.2);
  border-radius: 3px;
  color: var(--soon-dim);
  font: inherit;
  line-height: 1;
  padding: 0.15rem 0.45rem;
  cursor: pointer;
}
#soon-signup-close:hover { color: var(--soon-blood-text); border-color: var(--soon-blood); }

/* success panel replaces the form in place */
#soon-success { display: none; }
#soon-success.is-open { display: block; }
#soon-success .big {
  color: var(--soon-blood-text);
  font-size: 1.1em;
  letter-spacing: 0.06em;
  margin-bottom: 0.6rem;
}

@media (prefers-reduced-motion: reduce) {
  #soon-signup-window { animation: none; }
}

/* ========================= the sign-up action bar ==========================
 * The signup button is the only thing on this page that matters, so it does
 * not live at the bottom of a scrolling column where it can be missed. It is
 * pinned outside #soon-body, which means it is on screen from the first frame
 * and stays there however far the visitor scrolls.
 * ========================================================================= */

#soon-footer {
  flex: none;
  display: flex;
  align-items: center;
  gap: 0.9rem;
  flex-wrap: wrap;
  padding: 0.8rem clamp(0.9rem, 2.5vw, 1.6rem);
  background: linear-gradient(to bottom, rgba(224, 62, 62, 0.08), rgba(19, 19, 19, 0.95));
  border-top: 1px solid rgba(224, 62, 62, 0.4);
}

.soon-cta {
  appearance: none;
  background: var(--soon-blood);
  border: 1px solid var(--soon-blood);
  border-radius: 3px;
  color: var(--soon-void);
  font-family: inherit;
  font-size: clamp(0.8rem, 0.6rem + 0.5vw, 0.95rem);
  font-weight: 600;
  letter-spacing: 0.12em;
  padding: 0.7rem 1.8rem;
  cursor: pointer;
  white-space: nowrap;
  transition: background 140ms ease, color 140ms ease, transform 90ms ease;
  animation: soon-pulse 2.6s ease-out infinite;
}
.soon-cta:hover {
  background: var(--soon-blood-text);
  border-color: var(--soon-blood-text);
  transform: translateY(-1px);
}
.soon-cta:active { transform: translateY(0); }
.soon-cta:focus-visible { outline: 2px solid var(--soon-bone); outline-offset: 3px; }

@keyframes soon-pulse {
  0%   { box-shadow: 0 0 0 0 rgba(224, 62, 62, 0.55); }
  70%  { box-shadow: 0 0 0 12px rgba(224, 62, 62, 0); }
  100% { box-shadow: 0 0 0 0 rgba(224, 62, 62, 0); }
}

#soon-footer-note {
  color: var(--soon-bone);
  font-size: 0.92em;
  line-height: 1.4;
  min-width: 0;
}
#soon-footer-note b { color: var(--soon-blood-text); font-weight: 400; }

/* The inline CTA high in the body, above the detail, for people who have
   already decided and should not have to read the manifest first. */
#soon-actions { margin: 0 0 1.3rem; }

@media (prefers-reduced-motion: reduce) {
  .soon-cta { animation: none; transition: none; }
}

/* On a short landscape phone the window is mostly chrome; give the body back
   its room and keep the action bar compact. */
@media (max-height: 500px) {
  #soon-footer { padding: 0.5rem 0.9rem; gap: 0.6rem; }
  .soon-cta { padding: 0.5rem 1.2rem; }
  #soon-footer-note { font-size: 0.85em; }
}
