/* ==================================================================
   let it be dull — the engine
   One base page. One live word. Hold it and one of five things
   happens, picked at random. Nothing on the page admits it.

   Effects are namespaced by a body class the engine toggles:
     body.fx-understatement   the colour bloom
     body.fx-distortion       the signal failure
     body.fx-type             the word infestation
     body.fx-webcam           the dullest camera
     body.fx-office-*         the text adventure (off / term / on)
   ================================================================== */

:root{
  --ground:#306AC0;   /* YInMn Blue */
  --paper:#EEF2FA;
  --void:#12001F;
  --black:#02010A;
  --lime:#C6FF00;
  --magenta:#FF00A0;
  --cyan:#00E5FF;
  --phos:#33ff66;     /* terminal green */

  --fire:.9s;         /* going up   */
  --cool:2.4s;        /* coming down, slower on purpose */
  --ease:cubic-bezier(.16,1,.3,1);
}

*,*::before,*::after{box-sizing:border-box}
html,body{height:100%}
body{
  margin:0;
  background:var(--ground);
  color:var(--paper);
  font-family:'Libre Franklin',Arial,Helvetica,sans-serif;
  -webkit-font-smoothing:antialiased;
  overflow-x:hidden;
  transition:background-color var(--cool) var(--ease);
}
body.fx-active{ overflow:hidden }

/* ---------- the flat page: the thing that gets interrupted ---------- */
.page{position:relative;z-index:1;min-height:100%;display:flex;flex-direction:column}

nav{display:flex;gap:22px;flex-wrap:wrap;padding:26px 6vw 0;font-size:14px;line-height:1.5}
nav a{color:var(--paper);text-decoration:none;border-bottom:1px solid transparent;transition:border-color .2s}
nav a:hover,nav a:focus-visible{border-color:currentColor}

/* social — top right, quiet */
.social{position:absolute;top:24px;right:6vw;z-index:5;display:flex;gap:18px;align-items:center}
.social a{color:var(--paper);opacity:.85;transition:opacity .2s;display:block;line-height:0}
.social a:hover,.social a:focus-visible{opacity:1;outline:none}
.social svg{width:20px;height:20px;fill:currentColor;display:block}

main{flex:1;display:flex;flex-direction:column;justify-content:center;padding:8vh 6vw}

.statement{margin:0;font-weight:100;font-size:clamp(3.2rem,15.5vw,17rem);
  line-height:.86;letter-spacing:-.045em;max-width:14ch}

.facts{margin:clamp(28px,5vh,56px) 0 0;font-size:14px;line-height:1.55;max-width:46ch}
.facts p{margin:0 0 10px}

footer{padding:0 6vw 30px;font-size:14px;line-height:1.5;display:flex;justify-content:space-between;gap:20px;flex-wrap:wrap}

/* the one live word */
.dull{
  display:inline-block;cursor:pointer;color:inherit;outline:none;
  font-variation-settings:"wght" 100;
  transition:
    font-variation-settings var(--cool) var(--ease),
    color var(--cool) var(--ease),
    letter-spacing var(--cool) var(--ease),
    text-shadow var(--cool) var(--ease);
}
.dull:focus-visible{text-decoration:underline;text-underline-offset:.12em}

/* ==================================================================
   1. understatement — the colour bloom
   ================================================================== */
.bloom{
  position:fixed;inset:-45%;
  background:conic-gradient(from 0deg,#FF00A0,#A800FF,#00E5FF,#C6FF00,#FF6A00,#FF00A0);
  filter:blur(70px);mix-blend-mode:screen;
  opacity:0;transform:scale(.15);pointer-events:none;z-index:0;
  animation:dull-turn 26s linear infinite;
  transition:opacity var(--cool) var(--ease), transform var(--cool) var(--ease);
}
body.fx-understatement .bloom{ opacity:.9;transform:scale(1);transition-duration:var(--fire) }
@keyframes dull-turn{ to{ rotate:360deg } }

.flash{position:fixed;inset:0;background:#fff;opacity:0;pointer-events:none;z-index:2}
body.firing .flash{ animation:dull-blink .42s linear }
@keyframes dull-blink{ 0%{opacity:0} 10%{opacity:.85} 100%{opacity:0} }

body.fx-understatement{ background:var(--void);transition-duration:var(--fire) }
body.fx-understatement .dull{
  font-variation-settings:"wght" 900;color:var(--lime);
  letter-spacing:-.055em;text-shadow:5px 0 var(--magenta),-5px 0 var(--cyan);
  transition-duration:var(--fire);
}

/* ==================================================================
   2. distortion — signal failure (no page warp; overlays only)
   ================================================================== */
body.fx-distortion{ background:var(--black);transition-duration:.35s }

.ghost{
  position:fixed;inset:0;z-index:3;pointer-events:none;opacity:0;
  mix-blend-mode:screen;font-family:inherit;
  transition:opacity var(--cool) var(--ease);
}
body.fx-distortion .ghost{ opacity:1;transition-duration:.35s }
.ghost .band{
  position:absolute;left:0;right:0;display:flex;align-items:center;
  padding:0 6vw;font-size:clamp(3.2rem,15.5vw,17rem);
  line-height:.86;letter-spacing:-.045em;font-variation-settings:"wght" 900;
  white-space:nowrap;overflow:hidden;
}
body.fx-distortion .ghost .band{ animation:dull-tear .6s steps(4,end) infinite }
.g1{color:#FF0044}
.g2{color:#00FF88}
.g3{color:#3355FF}
body.fx-distortion .g2 .band{ animation-duration:.42s;animation-direction:reverse }
body.fx-distortion .g3 .band{ animation-duration:.77s }
@keyframes dull-tear{
  0%{transform:translateX(0)} 20%{transform:translateX(-38vw)}
  40%{transform:translateX(21vw)} 60%{transform:translateX(-8vw)}
  80%{transform:translateX(46vw)} 100%{transform:translateX(0)}
}

.crt{
  position:fixed;inset:0;z-index:6;pointer-events:none;opacity:0;
  background:repeating-linear-gradient(to bottom, rgba(0,0,0,.55) 0 1px, transparent 1px 3px);
  transition:opacity var(--cool) var(--ease);
}
body.fx-distortion .crt{ opacity:1;transition-duration:.35s }

.roll{
  position:fixed;left:0;right:0;height:22vh;z-index:7;pointer-events:none;opacity:0;
  background:linear-gradient(to bottom,transparent,rgba(255,255,255,.35),transparent);
  mix-blend-mode:overlay;
}
body.fx-distortion .roll{ opacity:1;animation:dull-sweep 1.1s linear infinite }
@keyframes dull-sweep{ from{ top:-25vh } to{ top:105vh } }

.snow{position:fixed;inset:0;z-index:8;pointer-events:none;opacity:0;mix-blend-mode:overlay}
body.fx-distortion .snow{ opacity:.5 }

/* ==================================================================
   3. type — the word infestation
   ================================================================== */
.swarm{
  position:fixed;inset:0;z-index:3;pointer-events:none;overflow:hidden;opacity:0;
  transition:opacity var(--cool) var(--ease);
}
body.fx-type .swarm{ opacity:1;transition-duration:.18s }
body.fx-type{ background:#0A0A0A;transition-duration:.55s }
body.fx-type .page{ opacity:.12;transition:opacity .55s var(--ease) }

.swrow{
  position:absolute;left:-120%;width:340%;white-space:nowrap;
  line-height:.82;letter-spacing:-.05em;transform:translateX(0);will-change:transform;
}
body.fx-type .swrow{ animation:dull-march linear infinite }
body.fx-type .swrow.rev{ animation-direction:reverse }
@keyframes dull-march{ to{ transform:translateX(-33.34%) } }
.swrow span{ padding-right:.14em }

.core{
  position:fixed;left:50%;top:50%;z-index:4;
  transform:translate(-50%,-50%) scale(.2);
  font-size:min(30vw,26rem);font-variation-settings:"wght" 900;
  letter-spacing:-.07em;line-height:1;color:var(--paper);
  opacity:0;pointer-events:none;mix-blend-mode:difference;
  transition:transform var(--cool) var(--ease), opacity var(--cool) var(--ease);
}
body.fx-type .core{
  opacity:1;transform:translate(-50%,-50%) scale(1);
  transition-duration:.55s;animation:dull-pulse 1.1s var(--ease) infinite;
}
@keyframes dull-pulse{
  0%,100%{ font-variation-settings:"wght" 900;letter-spacing:-.07em }
  50%    { font-variation-settings:"wght" 120;letter-spacing:.02em }
}

/* ==================================================================
   4. webcam — the dullest camera
   ================================================================== */
.feed{
  position:fixed;inset:0;z-index:5;background:#000;opacity:0;pointer-events:none;
  transition:opacity var(--cool) var(--ease);
}
body.fx-webcam .feed{ opacity:1;transition-duration:.5s }
.feed video{
  position:absolute;inset:0;width:100%;height:100%;object-fit:cover;
  filter:saturate(.72) contrast(1.08) brightness(.94);
}
.feed::after{
  content:"";position:absolute;inset:0;pointer-events:none;
  background:
    radial-gradient(120% 100% at 50% 50%, transparent 60%, rgba(0,0,0,.45)),
    repeating-linear-gradient(to bottom, rgba(0,0,0,.10) 0 1px, transparent 1px 3px);
  mix-blend-mode:multiply;
}
.osd{
  position:absolute;inset:0;z-index:1;pointer-events:none;
  font-family:'Courier New',monospace;color:#f4f4f4;
  text-shadow:0 0 2px #000,1px 1px 0 #000;
  font-size:clamp(11px,1.5vw,15px);letter-spacing:.02em;
}
.osd .tl{position:absolute;top:18px;left:20px;line-height:1.5}
.osd .tr{position:absolute;top:18px;right:20px;text-align:right;line-height:1.5}
.osd .bl{position:absolute;bottom:18px;left:20px}
.osd .br{position:absolute;bottom:18px;right:20px;text-align:right}
.rec{color:#ff2f2f;font-weight:bold}
.rec::before{
  content:"";display:inline-block;width:.62em;height:.62em;
  background:#ff2f2f;border-radius:50%;margin-right:.5em;vertical-align:.02em;
  animation:dull-recblink 1.4s steps(1,end) infinite;
}
@keyframes dull-recblink{ 50%{ opacity:0 } }

/* ==================================================================
   5. office — the text adventure
   ================================================================== */
body.fx-office-off .page{ animation:dull-crtOff .62s steps(60,end) forwards }
body.fx-office-on  .page{ animation:dull-crtOn  .55s var(--ease) forwards }
@keyframes dull-crtOff{
  0%{transform:scale(1);filter:brightness(1);opacity:1}
  55%{transform:scaleY(.006) scaleX(1);filter:brightness(3.5)}
  88%{transform:scaleY(.006) scaleX(.02);filter:brightness(3.5);opacity:1}
  100%{transform:scaleY(.006) scaleX(0);filter:brightness(8);opacity:0}
}
@keyframes dull-crtOn{
  0%{transform:scaleY(.006) scaleX(0);filter:brightness(8);opacity:0}
  12%{transform:scaleY(.006) scaleX(.02);filter:brightness(3.5);opacity:1}
  45%{transform:scaleY(.006) scaleX(1);filter:brightness(3.5)}
  100%{transform:scale(1);filter:brightness(1);opacity:1}
}

.term{
  position:fixed;inset:0;z-index:9;background:#020402;color:var(--phos);
  font-family:'Courier New',monospace;font-size:clamp(13px,1.7vw,16px);
  line-height:1.5;padding:min(6vh,48px) min(6vw,64px);
  display:none;flex-direction:column;text-shadow:0 0 4px rgba(51,255,102,.45);
}
body.fx-office-term .term{ display:flex }
.term::after{
  content:"";position:absolute;inset:0;pointer-events:none;z-index:2;
  background:
    radial-gradient(120% 120% at 50% 50%, transparent 62%, rgba(0,0,0,.55)),
    repeating-linear-gradient(to bottom, rgba(0,0,0,.16) 0 1px, transparent 1px 3px);
}
.term.flick{ animation:dull-flick .12s steps(2,end) 2 }
@keyframes dull-flick{ 50%{ filter:brightness(1.6) } }
.status{
  border-bottom:1px solid rgba(51,255,102,.35);padding-bottom:8px;margin-bottom:14px;
  display:flex;gap:2.5em;flex-wrap:wrap;letter-spacing:.06em;opacity:.9;
  text-transform:uppercase;font-size:.86em;
}
.scroll{flex:1;overflow-y:auto;white-space:pre-wrap;word-break:break-word}
.scroll::-webkit-scrollbar{width:8px}
.scroll::-webkit-scrollbar-thumb{background:rgba(51,255,102,.3)}
.scroll .echo{ color:#bfffcf }
.scroll .sys{ color:#9dffb6;opacity:.85 }
.inputline{display:flex;align-items:center;gap:.5ch;margin-top:6px}
.inputline .p{color:var(--phos)}
#dull-cmd{flex:1;background:transparent;border:0;outline:0;color:var(--phos);
  font:inherit;text-shadow:inherit;caret-color:var(--phos)}

/* ---------- reduced motion ---------- */
@media (prefers-reduced-motion: reduce){
  :root{ --fire:1ms; --cool:1ms }
  .bloom,body.firing .flash,
  body.fx-distortion .ghost .band,body.fx-distortion .roll,
  body.fx-type .swrow,body.fx-type .core,
  body.fx-office-off .page,body.fx-office-on .page{ animation:none }
}
