:root{
  --bg:#FAFAF8;
  --text:#111214;
  --muted:#8A8D93;
  --accent:#009dff;
  --glass-bg:rgba(255,255,255,0.86);
  --glass-border:rgba(0,0,0,0.12);
  --shadow-color:rgba(0,0,0,0.15);
  --glow: none;
}

/* "mirrors" easter egg: dark glossy midnight theme, toggled on <body> by
   main.js's onReveal("mirrors"). Deep blues + silver text + accent glow. */
body.theme-mirrors{
  --bg:#050914;
  --text:#EAF0FF;
  --muted:#8C9BC4;
  --accent:#6FE3FF;
  --glass-bg:rgba(18,24,46,0.55);
  --glass-border:rgba(160,190,255,0.22);
  --shadow-color:rgba(0,0,0,0.55);
  --glow: 0 0 18px rgba(111,227,255,0.55);
}

/* "abouttime" easter egg: soft golden-hour sepia grade. */
body.theme-abouttime{
  --bg:#F6E7CE;
  --text:#3E2B18;
  --muted:#9A7B50;
  --accent:#D98B3F;
  --glass-bg:rgba(246,231,206,0.6);
  --glass-border:rgba(154,105,50,0.28);
  --shadow-color:rgba(90,55,20,0.28);
  --glow: 0 0 16px rgba(217,139,63,0.45);
}

*{ box-sizing:border-box; margin:0; padding:0; }
html,body{ height:100%; overflow:hidden; background:var(--bg); }
body{
  font-family:'Inter', sans-serif; color:var(--text);
  transition:background-color .8s ease, color .8s ease;
}
a{ color:inherit; text-decoration:none; }
::selection{ background:var(--accent); color:#fff; }
a:focus-visible, button:focus-visible{ outline:2px solid var(--accent); outline-offset:3px; }

/* ---------- minimal chrome ---------- */
.chrome{
  position:fixed; inset:0; pointer-events:none; z-index:20;
  display:flex; flex-direction:column; justify-content:space-between;
  padding:clamp(18px,3vw,34px);
}
.mark{
  position:relative; display:inline-block;
  font-family:'Space Grotesk', sans-serif; font-weight:600; font-size:0.95rem;
  letter-spacing:-0.01em;
  pointer-events:auto; cursor:pointer;
}
.mark-name, .mark-email{ transition:opacity .25s ease; }
.mark-email{
  position:absolute; left:0; top:0; white-space:nowrap;
  color:var(--accent); opacity:0; pointer-events:none;
}
/* home screen only: hovering the name reveals the email instead of a
   "go home" affordance, which would be pointless while already home */
.mark:hover .mark-name{ opacity:0; }
.mark:hover .mark-email{ opacity:1; pointer-events:auto; }
/* inside an easter-egg theme, the name is the "go home" control — keep it
   as a name on hover, never swap to the email there */
body.theme-mirrors .mark:hover .mark-name,
body.theme-abouttime .mark:hover .mark-name{ opacity:1; }
body.theme-mirrors .mark:hover .mark-email,
body.theme-abouttime .mark:hover .mark-email{ opacity:0; pointer-events:none; }
.row{ position:relative; display:flex; justify-content:space-between; align-items:flex-start; gap:12px; flex-wrap:wrap; }
.social{ display:flex; gap:18px; pointer-events:auto; flex-wrap:wrap; opacity:1; transition:opacity .5s ease; }
body.theme-abouttime .social{ opacity:0; pointer-events:none; }

/* abouttime only: a line from the film, in the social row's place.
   display:none is the one unconditional default below 640px — narrow
   screens don't have room for both the name and a full sentence, and
   this way there's no state that can make it render there regardless
   of theme. */
.quote{
  display:none; position:absolute; top:0; right:0; max-width:min(320px,48vw);
  text-align:right; font-size:0.74rem; line-height:1.55; font-style:italic;
  color:var(--muted); opacity:0; transition:opacity .6s ease .1s;
}
@media (min-width:641px){
  .quote{ display:block; }
  body.theme-abouttime .quote{ opacity:0.85; }
}
.social a{
  font-size:0.72rem; letter-spacing:0.04em; text-transform:uppercase;
  color:var(--muted); transition:color .2s;
}
.social a:hover{ color:var(--accent); text-shadow:var(--glow); }
.social a:active{ color:var(--accent); }

@media (max-width:520px){
  .social{ gap:12px; }
  .social a{ font-size:0.66rem; }
  .caption .desc{ display:none; }
  .detail-desc{ max-width:none; }
}

/* active-panel caption, bottom-left, synced to the centered card */
.caption{
  display:flex; align-items:baseline; gap:10px;
  opacity:0; transform:translateY(6px);
  transition:opacity .35s ease, transform .35s ease;
}
.caption.show{ opacity:1; transform:translateY(0); }
.caption .idx{ font-size:0.72rem; color:var(--accent); letter-spacing:0.06em; text-shadow:var(--glow); }
.caption .name{ font-family:'Space Grotesk', sans-serif; font-weight:600; font-size:1rem; }
.caption .desc{ color:var(--muted); font-size:0.82rem; }

/* live stopwatch: time spent on the page, bottom-right.
   Keeps ticking in the background always — only shown on the "abouttime" page. */
.timer{
  position:absolute; right:clamp(18px,3vw,34px); bottom:clamp(18px,3vw,34px);
  font-variant-numeric:tabular-nums; font-size:0.72rem; letter-spacing:0.04em;
  color:var(--muted); opacity:0; visibility:hidden;
  transition:color .8s ease, opacity .5s ease;
}
body.theme-abouttime .timer{ opacity:0.75; visibility:visible; }

/* ---------- stage ---------- */
#stage{ position:fixed; inset:0; z-index:1; }
#stage canvas{ display:block; width:100%; height:100%; }

/* pointer-follower "View" label */
.cursor-label{
  position:fixed; top:0; left:0; z-index:15; pointer-events:none;
  font-size:0.68rem; letter-spacing:0.08em; text-transform:uppercase;
  color:var(--bg); background:var(--text);
  padding:9px 16px; border-radius:100px; white-space:nowrap;
  visibility:hidden;
  transition:background-color .8s ease, color .8s ease, box-shadow .8s ease;
  box-shadow:var(--glow);
}

/* abouttime only: a faint trailing ghost of the cursor's recent positions,
   decaying over half a second — time layering on itself as you move. */
.cursor-trail{ position:fixed; inset:0; z-index:16; pointer-events:none; overflow:hidden; }
.cursor-trail .echo{
  position:absolute; left:0; top:0; width:14px; height:14px; border-radius:50%;
  transform:translate(-50%,-50%);
  background:radial-gradient(circle, color-mix(in srgb, var(--accent) 65%, transparent) 0%, transparent 72%);
  animation:cursor-echo 0.5s ease-out forwards;
}
@keyframes cursor-echo{ to{ opacity:0; transform:translate(-50%,-50%) scale(0.45); } }

/* mirrors: a shard silhouette shared by the reflected cursor and the
   pieces it scatters into on double-click, so they read as one motif */
.shard-shape{
  clip-path:polygon(50% 0%, 78% 38%, 62% 100%, 22% 82%, 12% 30%);
  background:linear-gradient(160deg, color-mix(in srgb, var(--accent) 40%, white) 0%, color-mix(in srgb, var(--accent) 75%, transparent) 100%);
  box-shadow:var(--glow);
}
.mirror-shard{
  position:absolute; left:0; top:0; width:11px; height:14px; margin:-7px 0 0 -5.5px;
  opacity:0.85;
}

/* mirrors only: a ghost cursor reflected across the screen's vertical
   center, moving in lockstep with the real one */
.mirror-cursor{
  position:fixed; left:-10px; top:-12px; z-index:16; pointer-events:none;
  width:20px; height:25px;
  opacity:0; transition:opacity .35s ease;
}
body.theme-mirrors .mirror-cursor{ opacity:0.75; }

.no-webgl-fallback{
  display:none; position:fixed; inset:0; z-index:1;
  flex-direction:column; align-items:center; justify-content:center; gap:22px;
}
#stage.no-webgl{ display:none; }
#stage.no-webgl ~ .no-webgl-fallback{ display:flex; }
.no-webgl-fallback a{
  font-family:'Space Grotesk', sans-serif; font-size:1.4rem; font-weight:600;
  color:var(--muted); transition:color .2s;
}
.no-webgl-fallback a:hover{ color:var(--accent); }

/* ---------- architecture nodes: free-floating over the focused card ----------
   Real DOM dots, positioned in screen space and never clipped to the card's
   own bounds or covered by the detail panel below (z-index sits above it). */
.arch-edges{
  position:fixed; inset:0; width:100vw; height:100vh; pointer-events:none; z-index:32;
  overflow:visible;
}
.arch-edge{
  fill:none; stroke:var(--edge-color); stroke-linecap:round;
  filter:drop-shadow(0 2px 5px rgba(0,0,0,0.18)) drop-shadow(0 0 8px color-mix(in srgb, var(--edge-color) 55%, transparent));
}
.arch-edge.strong{ filter:drop-shadow(0 2px 6px rgba(0,0,0,0.2)) drop-shadow(0 0 12px color-mix(in srgb, var(--edge-color) 70%, transparent)); }

/* traveling glow overlay on top of each edge, like current moving through
   a wire — a dash pattern whose offset keeps decreasing loops seamlessly
   regardless of the path's actual length, so it works for every edge shape */
.arch-edge-flow{
  fill:none; stroke-linecap:round; mix-blend-mode:screen;
  stroke:color-mix(in srgb, var(--edge-color) 70%, white 30%);
  stroke-width:2.2px; stroke-dasharray:5 21;
  animation:arch-flow 1.7s linear infinite;
}
.arch-edge-flow.reverse{ animation-direction:reverse; }
@keyframes arch-flow{ to{ stroke-dashoffset:-26; } }
@media (prefers-reduced-motion: reduce){ .arch-edge-flow{ animation:none; opacity:0 !important; } }

.arch-nodes{ position:fixed; inset:0; pointer-events:none; z-index:33; }
.arch-node{
  position:fixed; left:0; top:0; width:20px; height:20px;
  transform:translate(-50%,-50%); border-radius:50%; pointer-events:auto; cursor:pointer;
  background:radial-gradient(circle, color-mix(in srgb, var(--node-color) 92%, transparent) 0%, color-mix(in srgb, var(--node-color) 45%, transparent) 55%, transparent 100%);
  box-shadow:0 4px 10px rgba(0,0,0,0.2), 0 0 14px color-mix(in srgb, var(--node-color) 55%, transparent);
  transition:box-shadow .25s ease, width .25s ease, height .25s ease;
}
.arch-node.core{
  width:30px; height:30px;
  box-shadow:0 0 22px color-mix(in srgb, var(--node-color) 70%, transparent);
}
.arch-node:hover, .arch-node.hover{
  width:28px; height:28px;
  box-shadow:0 0 30px color-mix(in srgb, var(--node-color) 85%, transparent);
}
.arch-node.core:hover, .arch-node.core.hover{ width:38px; height:38px; }
@media (prefers-reduced-motion: reduce){ .arch-node{ transition:none; } }
/* touch has no hover to grow into on approach, so give dots a bigger hit
   target outright rather than relying on the :hover-triggered size bump */
@media (pointer: coarse){
  .arch-node{ width:30px; height:30px; }
  .arch-node.core{ width:40px; height:40px; }
}

/* ---------- architecture-node tooltip (hover/click a node on a focused card) ---------- */
.arch-tooltip{
  position:fixed; z-index:34; left:0; top:0;
  transform:translate(-50%,-100%); pointer-events:none;
  background:var(--glass-bg); backdrop-filter:blur(10px);
  border:1px solid var(--glass-border); border-radius:10px;
  padding:7px 12px; box-shadow:0 10px 26px -14px var(--shadow-color);
  opacity:0; transition:opacity .25s ease, left .12s ease, top .12s ease;
  max-width:230px;
}
.arch-tooltip.pos-below{ transform:translate(-50%,0%); }
.arch-tooltip.show{ opacity:1; }
.arch-name{
  font-family:'Space Grotesk', sans-serif; font-weight:600; font-size:0.78rem;
  color:var(--text); white-space:nowrap;
}
.arch-role{
  font-size:0.68rem; color:var(--muted); margin-top:1px; white-space:nowrap;
}
.arch-live{
  font-size:0.66rem; color:var(--accent); margin-top:4px; white-space:nowrap;
  text-shadow:var(--glow); display:none;
}
.arch-live.show{ display:block; }
.arch-detail{
  font-size:0.76rem; line-height:1.5; color:var(--muted);
  margin-top:7px; white-space:normal; display:none;
}

/* ---------- detail panel (shown once focus mode settles) ---------- */
.detail{
  position:fixed; z-index:31; left:50%; bottom:0;
  transform:translate(-50%, 100%);
  width:min(620px, 90vw);
  padding:clamp(28px,4vw,44px) clamp(28px,4vw,44px) clamp(36px,5vw,52px);
  border-radius:24px 24px 0 0;
  background:var(--glass-bg);
  border:1px solid var(--glass-border);
  border-bottom:none;
  backdrop-filter:blur(22px);
  box-shadow:0 -20px 60px -20px var(--shadow-color);
  opacity:0; pointer-events:none;
  transition:opacity .5s ease, transform .5s cubic-bezier(.2,.85,.25,1),
    background-color .8s ease, border-color .8s ease, box-shadow .8s ease;
}
.detail.open{ opacity:1; pointer-events:auto; transform:translate(-50%, 0); }
.detail-index{ color:var(--accent); font-size:0.78rem; letter-spacing:0.1em; }
.detail-name{ font-family:'Space Grotesk', sans-serif; font-size:clamp(1.5rem,3.4vw,2.1rem); font-weight:600; margin-top:8px; }
.detail-desc{ color:var(--muted); margin-top:14px; font-size:0.95rem; line-height:1.55; max-width:56ch; }
.detail-tags{ display:flex; gap:8px; flex-wrap:wrap; margin-top:18px; }
.detail-tags span{
  font-size:0.68rem; color:var(--muted); border:1px solid var(--glass-border);
  padding:5px 11px; border-radius:100px; transition:border-color .8s ease;
}
.detail-link{
  display:inline-block; margin-top:22px; font-size:0.85rem; color:var(--accent);
  border-bottom:1px solid var(--accent); padding-bottom:2px; text-shadow:var(--glow);
}
.detail-close{
  position:absolute; top:20px; right:24px;
  width:32px; height:32px; border-radius:50%;
  border:1px solid var(--glass-border); background:transparent; color:var(--text);
  font-size:1.05rem; line-height:1; cursor:pointer;
  transition:border-color .2s, color .2s;
}
.detail-close:hover{ border-color:var(--accent); color:var(--accent); text-shadow:var(--glow); }

@media (prefers-reduced-motion: reduce){
  .caption, .detail, .arch-tooltip{ transition:none; }
}
