/* ============================================================
   FOOTER — ported from ../isladjan-footer-reference.html
   Sits in normal document flow, below the parallax hero.
   ============================================================ */

@font-face{
  font-display:fallback; font-family:vcr-osd-mono; font-style:normal; font-weight:400;
  src:url(assets/fonts/vcr_osd_mono01.woff2) format("woff2");
}
@font-face{
  font-display:fallback; font-family:ibm-plex-mono; font-style:normal; font-weight:400;
  src:url(assets/fonts/ibmplexmono.woff2) format("woff2");
}
@font-face{
  font-display:fallback; font-family:departure-mono; font-style:normal; font-weight:400;
  src:url(assets/fonts/departureMono-Regular.woff2) format("woff2");
}

:root{
  --color-white:#fff;
  --color-darkGray:#252525;
  --color-yellow:#ffc900;
  --color-author:#b8b8b8;
  --font1:"vcr-osd-mono", ui-monospace, Menlo, Consolas, monospace;
  --font2:"ibm-plex-mono", ui-monospace, Menlo, Consolas, monospace;
  --font3:"departure-mono", ui-monospace, Menlo, Consolas, monospace;
  --line: rgba(255,255,255,.12);

  /* how far the parallax scrolls — must match .scrollElement's height
     in par.css. Used to give .wrapper real in-flow height (see below)
     so the footer lands right after the hero. Keep these two in sync. */
  --parallax-scroll-distance: 6000px;
}

/* black backdrop behind/around the hero + footer seam, so there's no
   white flash at the edges of the fixed SVG or on overscroll bounce */
body{ background:#000; }

/* par.css's .wrapper only contains position:fixed/absolute children, so
   it naturally renders as an empty, zero-height box. Left alone, that lets
   the footer's margin below collapse THROUGH it (empty boxes are
   margin-collapse-transparent), which drags .wrapper — and therefore
   .scrollElement, which is positioned relative to it — down by the
   footer's margin, silently doubling the scroll distance. Giving .wrapper
   real height stops it from being "empty" so nothing collapses through,
   and lets the footer just follow it in normal flow (no margin needed). */
.wrapper{ min-height:var(--parallax-scroll-distance); }

/* PIN RELEASE — par.css keeps the hero svg permanently position:fixed, so
   once scrolled far enough for the footer (z-index:5) to reach the
   viewport, it paints OVER the still-fixed animation instead of the
   animation finishing and scrolling away first. pin-release.js toggles
   this class the instant the hero's scroll distance is exhausted, handing
   the svg off from viewport-fixed to document-absolute. Landing it at
   (scroll-distance - 100vh) — one viewport height short of the bottom —
   matches its fixed-state position exactly at that scroll offset (no
   jump), and puts its bottom edge flush with .wrapper's bottom edge /
   the footer's top edge (no gap, no overlap): the svg then scrolls away
   with the page instead of hovering over what follows it. */
svg.parallax.pin-released{
  position:absolute !important;
  top:calc(var(--parallax-scroll-distance) - 100vh) !important;
}

.max-width{ margin:0 auto; max-width:min(90svw, 1300px); width:100%; }

/* ============================================================
   FOOTER SHELL — mirrors live DOM:
   footer > .footer-expander + .footer-outer >
     .grid-scene(z1) + .mq(z3) + .footer-inner(z2)
   ============================================================ */
.site-footer{
  --height-top-row:250px;         /* marquee band height   (live) */
  --height-footer-expander:150px; /* spacer above the band (live) */
  position:relative;
  z-index:5;                      /* above the fixed parallax svg (z-index:3) */
  opacity:0;                      /* faded in by scene3's ScrollTrigger (par.js) */
  background:var(--color-darkGray);
  color:var(--color-white);
  overflow:hidden;
  isolation:isolate;
  box-sizing:border-box;
}
.site-footer *{ box-sizing:border-box; }
.footer-expander{ height:var(--height-footer-expander); }
.footer-outer{ position:relative; }
.footer-inner{
  position:relative;
  z-index:2;
  display:flex;
  flex-direction:column;
  justify-content:space-between;
  padding-bottom:3rem;   /* spacer below the nav row, so it isn't flush with the viewport edge */
  font-family:var(--font3);
}
.footer-inner a{ color:var(--color-white); text-decoration:none; }

/* ============================================================
   SCROLL TO TOP — brackets slide apart on hover, text -> yellow
   ============================================================ */
.scroll-to-top{
  position:absolute;
  right:0;
  top:calc(var(--height-footer-expander)*-1 + 1rem);
  display:flex;
  align-items:flex-end;
  line-height:1;
  font-size:.9rem;
  letter-spacing:1px;
  text-transform:uppercase;
  transition:color .3s;
}
.scroll-to-top .bracket:first-child{ margin-right:10px; transition:transform .3s; }
.scroll-to-top .bracket:last-child{  margin-left:10px;  transition:transform .3s; }
.scroll-to-top:hover{ color:var(--color-yellow); }
.scroll-to-top:hover .bracket:first-child{ transform:translateX(-7px); }
.scroll-to-top:hover .bracket:last-child{  transform:translateX(7px); }
.scroll-to-top svg.arrow-small{ width:14.4px; height:18px; margin-left:.7rem; overflow:hidden; }

/* reserves the marquee band inside the flow (live .empty-space) */
.empty-space{ height:var(--height-top-row); pointer-events:none; }

/* ============================================================
   COMPONENT 2 — EMAIL MARQUEE
   One underlined email per 100vw (live: li.email-wrapper{width:100vw}).
   rAF-driven: hover eases to a stop instead of a hard pause.
   ============================================================ */
.mq{
  position:absolute;
  top:calc(var(--height-footer-expander)*-1 + 40px);
  left:0;
  width:100%;
  height:var(--height-top-row);
  display:flex;
  align-items:center;
  overflow:hidden;
  z-index:3;
  pointer-events:none;            /* only the links are interactive */
  font-family:var(--font3);
  font-size:5rem;                 /* live ladder below */
}
.mq-track{ display:flex; width:max-content; will-change:transform; }
.mq-item{ flex:0 0 auto; width:100vw; white-space:nowrap; }
.email-link{
  display:inline-block;
  width:fit-content;
  color:var(--color-white);
  pointer-events:all;
}
.email-link .text{
  position:relative;              /* anchors the .text-glow overlay below */
  display:inline-block;
  text-decoration:underline;
  text-decoration-thickness:4px;
  text-underline-offset:4px;
}
.email-link .at-sign{ font-family:var(--font2); }

/* gradient overlay: an exact duplicate of the text, gradient-filled via
   background-clip, stacked on top of the real (white) text. Its opacity is
   driven every frame by footer.js via --glow, mapped from the marquee's
   current speed (0 at full speed => white, 1 when stopped => full colour),
   so the colour blends in as the scroll slows and drains out as it resumes.
   No CSS transition: vel is already eased per-frame, so --glow is smooth. */
.email-link .text-glow{
  position:absolute; inset:0;
  background:linear-gradient(90deg, #4f7cff 0%, #9b5cf0 50%, #17c9b2 100%);
  background-clip:text; -webkit-background-clip:text;
  color:transparent; -webkit-text-fill-color:transparent;
  opacity:var(--glow, 0);
  pointer-events:none;
}

/* ============================================================
   COMPONENT 1 — NAV ROW (slide + arrow-reveal hover)
   .row: links (order 1) | social (order 2) | author (order 3, 100%)
   NOTE: scoped to .footer-inner — ".row" is generic and the pop-out menu
   (menu.js/menu.css) also uses .row, so an unscoped rule collides with it.
   ============================================================ */
.footer-inner .row{
  display:flex;
  flex-direction:row;
  flex-wrap:wrap;
  justify-content:space-between;
  align-items:flex-end;
}
.footer-inner .row ul{ list-style:none; margin:0; padding:0; }
.footer-inner .row .arrow-link{
  width:20px; height:20px;
  flex:none;                 /* never shrink; stays on the label's line */
  opacity:0;
  transition:opacity .3s;
}
/* inline-flex keeps the arrow + label on one line so the arrow can't wrap
   above the label on narrow columns */
.footer-inner .row a{ display:inline-flex; align-items:center; font-size:1rem; transition:color .3s; }

/* column 1 — site links */
.column-links{ flex:1 1 50%; order:1; position:relative; top:20px; z-index:2; }
.column-links ul.links{ translate:-15px 0; }
.column-links ul.links li{ margin-bottom:2px; width:fit-content; translate:-23px; transition:translate .3s; }
.column-links ul.links .arrow-link{ margin-right:5px; }
.column-links ul.links li:hover{ translate:0; }
.column-links ul.links li:hover .arrow-link{ opacity:1; }
.column-links ul.links a:hover,
.column-links ul.links a[aria-current="page"] span{ color:var(--color-yellow); }
.column-links ul.links a[aria-current="page"] .arrow-link{ opacity:1; }

/* column 2 — author / copyright (full-width, centered, behind columns) */
.column-author{
  flex:1 1 100%; order:3;
  display:flex; justify-content:center;
  position:relative; top:-10px; z-index:1;
  color:var(--color-author);
  font-family:var(--font1);
  text-transform:uppercase;
}
.column-author .sign{ font-family:var(--font2); font-size:1.2rem; position:relative; top:1px; }

/* column 3 — social links, mirrored */
.column-social{ flex:1 1 50%; order:2; position:relative; top:20px; z-index:2; }
.column-social ul.social{
  display:flex; flex-direction:column;
  align-items:flex-end; justify-content:flex-end;
  text-align:right;
  translate:15px 0;
}
.column-social ul.social li{ margin-bottom:2px; width:fit-content; translate:23px; transition:translate .3s; }
.column-social ul.social .arrow-link{ margin-left:5px; rotate:180deg; }
.column-social ul.social li:hover{ translate:0; }
.column-social ul.social li:hover .arrow-link{ opacity:1; }
.column-social ul.social a:hover{ color:var(--color-yellow); }

/* ============================================================
   COMPONENT 3 — PERSPECTIVE GRID FLOOR (2D canvas)
   Static projected floor with a small gaussian bump travelling
   right -> left under the text. Live: WebGL canvas-wrapper
   {bottom:0; height:135%; z-index:1}.
   ============================================================ */
.grid-scene{
  position:absolute;
  bottom:0; left:0;
  width:100%; height:135%;
  overflow:hidden;
  pointer-events:none;
  z-index:1;
}
.grid-canvas{ position:absolute; inset:0; width:100%; height:100%; display:block; }
/* fog: grid dissolves into the background toward the horizon */
.grid-scene::after{
  content:"";
  position:absolute; inset:0;
  background:linear-gradient(to top, transparent 45%, var(--color-darkGray) 70%);
}

/* ============================================================
   A11Y — respect reduced motion (JS also checks this)
   ============================================================ */
@media (prefers-reduced-motion: reduce){
  .mq-track{ transform:none !important; }
}

/* ============================================================
   RESPONSIVE — same ladder as live
   ============================================================ */
@media (max-width:1921px){ .mq{ font-size:4rem; } }
@media (max-width:1600px){ .mq{ font-size:3.5rem; } }
@media (max-width:1300px){
  .site-footer{ --height-top-row:190px; --height-footer-expander:100px; }
  .grid-scene{ height:120%; }
}
@media (max-width:1100px){ .mq{ font-size:3rem; } }
@media (max-width:800px){
  .site-footer{ --height-top-row:200px; --height-footer-expander:0px; }
  .grid-scene{ height:100%; }
  .mq{ font-size:2rem; }
  .email-link .text{ text-decoration-thickness:2px; }
  .scroll-to-top{ scale:.9; top:1rem; transform-origin:100% 0; }
  .column-links, .column-social{ top:0; }
}
@media (max-width:490px){
  .mq{ font-size:1.8rem; }
  .mq-item{ width:150vw; }
  .scroll-to-top .hide{ display:none; }
  .column-author{ font-size:.8rem; }
  .column-links ul.links li, .column-social ul.social li{ margin-bottom:7px; }
}
