:root{
  --ink:#0B0710;           /* near-black, warm violet undertone */
  --ink-2:#170D22;
  --cream:#F5F1EC;         /* warm off-white, not the old cold cream */
  --cream-dim:rgba(245,241,236,.68);
  /* was .38 — measured contrast on --ink was ~3.2:1, under WCAG AA's 4.5:1 for
     body-sized text (this token is used for real copy: .note, #depth, price
     captions, footer note). .5 measures ~4.8:1, keeps the 3-tier hierarchy
     (full cream > dim > faint) intact, visually still reads as the quietest tier. */
  --cream-faint:rgba(245,241,236,.5);
  --rule:rgba(245,241,236,.18);
  --accent:#FF2D6B;        /* hot crimson-pink — primary energy, CTAs */
  --accent-2:#C6FF4D;      /* acid lime — maximalist pop, secondary */
  --accent-3:#3DD6FF;      /* electric cyan — tech glow, tertiary/AI moments */
  --glass-bg:rgba(245,241,236,.06);
  --glass-border:rgba(245,241,236,.18);
  --ease-snap:cubic-bezier(.16,.84,.32,1);
  --display:"Unbounded","Arial Black",sans-serif;
  --body:"Manrope",-apple-system,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif;
  --mono:"JetBrains Mono","Courier New",monospace;
}
*{box-sizing:border-box}
html{scroll-behavior:auto}
body{
  margin:0;
  background:var(--ink);
  color:var(--cream);
  font-family:var(--body);
  font-weight:400;
  -webkit-font-smoothing:antialiased;
  overflow-x:hidden;
}
a{color:inherit}
::selection{background:var(--accent); color:var(--ink)}

/* ---------- skip link ---------- */
.skip-link{
  position:fixed; top:-4rem; left:1rem; z-index:100;
  background:var(--accent-2); color:var(--ink); text-decoration:none;
  padding:.85rem 1.4rem; font-family:var(--mono); font-size:.78rem; font-weight:600;
  letter-spacing:.06em; border-radius:2px; transition:top .25s var(--ease-snap);
}
.skip-link:focus{top:1rem}

/* ---------- focus states ----------
   Everything interactive gets an explicit, on-brand ring against --ink —
   browser-default focus outlines are barely visible on a near-black page. */
a:focus-visible,
button:focus-visible,
input:focus-visible,
textarea:focus-visible,
[tabindex]:focus-visible{
  outline:2px solid var(--accent-2);
  outline-offset:3px;
  border-radius:1px;
}
.cta:focus-visible{outline-offset:5px}
.navtoggle:focus-visible{outline-offset:2px}

/* ---------- WebGL layer ---------- */
#gl{position:fixed; inset:0; width:100%; height:100%; display:block; z-index:0}
body.no-gl #gl{display:none}
body.no-gl{background:radial-gradient(130% 90% at 50% -10%, #2a1233 0%, var(--ink) 55%), var(--ink)}

#grain{
  position:fixed; inset:0; z-index:2; pointer-events:none;
  opacity:.45; mix-blend-mode:overlay;
  background-image:var(--grain);
  background-size:180px 180px;
}
#vignette{
  position:fixed; inset:0; z-index:2; pointer-events:none;
  background:radial-gradient(120% 90% at 50% 50%, transparent 38%, rgba(5,2,8,.76) 100%);
}

/* ---------- top nav ---------- */
#nav{
  position:fixed; top:0; left:0; right:0; z-index:10;
  display:flex; align-items:center; justify-content:space-between;
  padding:1.5rem clamp(1.5rem,5vw,3.5rem);
  background:linear-gradient(to bottom, rgba(11,7,16,.8), transparent);
  pointer-events:none;
  transition:background .3s var(--ease-snap), box-shadow .3s var(--ease-snap), backdrop-filter .3s var(--ease-snap);
}
#nav *{pointer-events:auto}
/* Past a small scroll threshold (toggled in site.js) the nav solidifies into
   a blurred glass bar instead of staying a gradient that fades to fully
   transparent — without this, whatever scrolls up under the transparent
   lower half of the bar visually collides with the logo/links. */
#nav.scrolled{
  background:rgba(9,6,13,.86);
  backdrop-filter:blur(16px) saturate(1.4);
  -webkit-backdrop-filter:blur(16px) saturate(1.4);
  box-shadow:0 1px 0 rgba(245,241,236,.08), 0 16px 32px -20px rgba(0,0,0,.75);
}
/* backdrop-filter on #nav makes it a new CSS containing block for its
   position:fixed .navlinks child the moment the mobile full-screen menu
   overlay is in play — .navlinks's inset:0/translateY(-100%) off-screen
   math then resolves against the slim nav bar's own ~90px height instead
   of the viewport, so the last couple of nav items (language switcher,
   sign-in button) end up rendering just below the bar instead of fully
   hidden. Only triggers once .scrolled is added, which is exactly why this
   was invisible until the page was actually scrolled. A solid near-opaque
   background gets the same "can't see through it" result on this narrow a
   bar without the containing-block side effect, so drop the blur here only.*/
@media (max-width:760px){
  #nav.scrolled{background:rgba(9,6,13,.97); backdrop-filter:none; -webkit-backdrop-filter:none}
}
@media (prefers-reduced-motion:reduce){#nav{transition:none}}
.logo{
  display:inline-flex; align-items:center; gap:.55rem;
  font-family:var(--display); font-weight:700; font-size:1.15rem; letter-spacing:-.01em;
  text-decoration:none; color:var(--cream); text-transform:uppercase;
}
.logo img{width:1.6rem; height:1.6rem; display:block; transform-origin:50% 0%; animation:nav-icon-sway 3.6s ease-in-out infinite}
@keyframes nav-icon-sway{0%,100%{transform:rotate(-4deg)} 50%{transform:rotate(4deg)}}
.navlinks{display:flex; gap:2.2rem; list-style:none; margin:0; padding:0}
.navlinks a{
  position:relative;
  font-size:.7rem; letter-spacing:.14em; text-transform:uppercase; font-weight:600;
  text-decoration:none; color:var(--cream-dim);
  transition:color .3s ease;
  padding-bottom:.3rem;
}
/* Sweeping gradient underline instead of a flat color-swap — the nav's only
   "alive" element besides the ambient canvas behind it, so it's built to be
   noticed without competing with that background. Excluded from .nav-signin,
   which already has its own physical press-motion (see below). */
.navlinks a:not(.nav-signin)::after{
  content:''; position:absolute; left:0; right:0; bottom:0; height:2px;
  background:linear-gradient(90deg, var(--accent), var(--accent-2));
  transform:scaleX(0); transform-origin:left;
  transition:transform .35s var(--ease-snap);
}
.navlinks a:hover,.navlinks a.current{color:var(--accent-2)}
.navlinks a:not(.nav-signin):hover::after,
.navlinks a:not(.nav-signin):focus-visible::after,
.navlinks a.current:not(.nav-signin)::after{transform:scaleX(1)}
.navlinks a.nav-advisory{display:inline-flex; align-items:center; gap:.4rem}
.navlinks a.nav-advisory img{width:.95rem; height:.95rem; display:block; opacity:.85; transform-origin:50% 0%; animation:nav-icon-sway 3.6s ease-in-out infinite}
.navlinks a.nav-advisory:hover img{opacity:1}
@media (prefers-reduced-motion:reduce){
  .logo img, .navlinks a.nav-advisory img{animation:none}
  .navlinks a:not(.nav-signin)::after{transition:none}
}
.navtoggle{display:none}

/* ---------- nav sign-in button ----------
   Was a soft gradient pill with a blurred glow and a diagonal shine
   loop — a generic template pattern lifted from nowhere in particular,
   and the only button on the whole site that didn't match the CTA
   language defined above (solid fill, hard ink border, flat offset
   shadow with zero blur, physical shift on hover). Rebuilt on that
   same system instead of inventing a second one just for the nav.
   Swapped to the signed-in label by assets/account.js on any page
   that loads it and has this ID. */
.navlinks li a.nav-signin{
  background:var(--accent); color:var(--ink);
  padding:.5rem 1.15rem; border-radius:4px; border:2px solid var(--ink);
  font-weight:700; letter-spacing:.06em; text-transform:uppercase; font-size:.74rem;
  box-shadow:3px 3px 0 var(--accent-2);
  transition:transform .16s var(--ease-snap), box-shadow .16s var(--ease-snap);
}
.navlinks li a.nav-signin:hover{
  color:var(--ink); border-color:var(--ink);
  transform:translate(-2px,-2px);
  box-shadow:5px 5px 0 var(--accent-2), 0 0 22px rgba(255,45,107,.4);
}
.navlinks li a.nav-signin.is-signed-in{
  background:rgba(198,255,77,.14); color:var(--accent-2);
  border:1.5px solid var(--accent-2); box-shadow:none; padding:.44rem 1.15rem;
}
.navlinks li a.nav-signin.is-signed-in:hover{background:rgba(198,255,77,.22)}
@media (max-width:760px){
  .navlinks li a.nav-signin{padding:.65rem 1.6rem; font-size:.78rem}
}

/* ---------- language switcher (nav) — one globe button, a dropdown ----------
   Replaces five always-visible text links with a single icon; the five
   options move into a menu that only exists in the DOM's visual flow when
   open. Same open/close/focus-trap shape as .navtoggle, see
   AnchorsEngine._initLangMenu in site.js. */
.lang-switch{position:relative; display:flex; align-items:center}
.globe-btn{
  display:flex; align-items:center; justify-content:center;
  width:2.2rem; height:2.2rem; padding:0; border-radius:50%;
  background:transparent; border:1px solid transparent; cursor:pointer;
  color:var(--accent-2); transition:border-color .25s ease, background .25s ease, transform .25s var(--ease-snap);
}
.globe-btn svg{width:1.15rem; height:1.15rem; display:block}
.globe-btn:hover,.globe-btn[aria-expanded="true"]{
  border-color:var(--glass-border); background:var(--glass-bg); transform:scale(1.08);
}
/* Two-tone accent — lime globe lines, pink meridian — so the icon itself
   carries both brand colours rather than a flat single-colour glyph. */
.globe-btn svg .meridian{stroke:var(--accent)}

.lang-menu{
  position:absolute; top:calc(100% + .7rem); right:0; z-index:20;
  display:flex; flex-direction:column; gap:.1rem;
  min-width:9.5rem; margin:0; padding:.5rem;
  list-style:none; border-radius:12px;
  background:rgba(23,13,34,.92); border:1px solid var(--glass-border);
  backdrop-filter:blur(16px) saturate(1.3); -webkit-backdrop-filter:blur(16px) saturate(1.3);
  box-shadow:0 20px 50px -12px rgba(0,0,0,.8);
  opacity:0; transform:translateY(-6px) scale(.97); pointer-events:none;
  transition:opacity .16s var(--ease-snap), transform .16s var(--ease-snap);
}
.lang-menu.open{opacity:1; transform:translateY(0) scale(1); pointer-events:auto}
.lang-menu a{
  display:block; padding:.55rem .7rem; border-radius:7px;
  font-family:var(--mono); font-size:.74rem; letter-spacing:.04em; font-weight:600;
  text-decoration:none; color:var(--cream-dim); transition:background .2s ease, color .2s ease;
}
.lang-menu a:hover{background:var(--glass-bg); color:var(--accent-2)}
.lang-menu a.current{color:var(--ink); background:var(--accent-2)}
.lang-menu a.current:hover{background:var(--accent-2)}
/* Arabic's RTL flip mirrors the nav (logo/menu swap sides), so the dropdown
   opens from the visual left there instead of trailing off past the edge. */
html[dir="rtl"] .lang-menu{right:auto; left:0}
@media (max-width:760px){
  .globe-btn{width:2.6rem; height:2.6rem}
  .globe-btn svg{width:1.35rem; height:1.35rem}
  .lang-menu{position:static; margin-top:1rem; opacity:1; transform:none; pointer-events:auto;
    background:transparent; border:0; backdrop-filter:none; -webkit-backdrop-filter:none; box-shadow:none;
    align-items:center; display:none;}
  .lang-menu.open{display:flex}
  .lang-menu a{font-size:1rem; text-align:center}
}
@media (max-width:760px){
  .navlinks{
    position:fixed; inset:0; z-index:9; background:var(--ink);
    flex-direction:column; align-items:center; justify-content:center;
    gap:2rem; transform:translateY(-100%); transition:transform .5s cubic-bezier(.6,0,.2,1);
    overflow-y:auto; padding:3rem 0;
  }
  .navlinks.open{transform:translateY(0)}
  .navlinks a{font-size:1.1rem}
  .navtoggle{
    display:block; background:none; border:2px solid var(--rule); color:var(--cream);
    width:2.6rem; height:2.6rem; z-index:11; position:relative;
  }
  /* .lang-switch is a row on desktop because the open menu there is
     position:absolute and doesn't affect layout. On mobile the open menu
     becomes position:static (real content, not an overlay), so a row still
     puts the globe button beside it and vertically centers the short button
     against the now much-taller list — dragging the globe off to one side
     and shoving Tools/Advisory/Log In into new positions the instant it
     opens. That's what actually caused "clicking near Tools changes the
     language": the tap landed where Tools used to be, which the reflow had
     just handed to a language link. Column stacking keeps the whole group
     centered as one unit with no post-open jump. */
  .lang-switch{flex-direction:column; gap:.6rem}
}

/* ---------- footer ---------- */
#site-footer{
  position:relative; z-index:3;
  padding:4rem clamp(1.5rem,5vw,3.5rem) 3rem;
  border-top:2px solid var(--rule);
  display:flex; flex-wrap:wrap; gap:2rem; justify-content:space-between; align-items:flex-end;
  background:var(--ink);
}
#site-footer .fnote{font-size:.78rem; color:var(--cream-faint); max-width:26rem; line-height:1.6}
#site-footer .flinks{display:flex; gap:1.6rem; list-style:none; margin:0; padding:0; align-items:center}
#site-footer .flinks a{font-size:.72rem; letter-spacing:.1em; text-transform:uppercase; font-weight:600; text-decoration:none; color:var(--cream-dim)}
#site-footer .flinks a:hover{color:var(--accent-2)}
/* Contact moved out of the primary nav and lives only here now — styled as a
   real button rather than a plain text link, so it still reads as the site's
   one persistent call to action. */
#site-footer .flinks a.cta-mini{
  padding:.6rem 1.3rem; color:var(--ink); background:var(--accent-2);
  border:2px solid var(--ink); box-shadow:4px 4px 0 var(--accent);
  transition:transform .2s var(--ease-snap), box-shadow .2s var(--ease-snap);
}
#site-footer .flinks a.cta-mini:hover{
  color:var(--ink); transform:translate(-2px,-2px); box-shadow:6px 6px 0 var(--accent);
}

/* ---------- scroll content ---------- */
#scroll{position:relative; z-index:3}
.act{position:relative; min-height:130vh; display:flex; align-items:center; padding:0 clamp(1.5rem,7vw,9rem)}
.act-inner{
  max-width:46rem; will-change:transform,opacity;
  opacity:0; transform:translateY(2.4rem);
  transition:opacity .8s var(--ease-snap), transform .8s var(--ease-snap);
}
.act-inner.in{opacity:1; transform:translateY(0)}
@media (prefers-reduced-motion:reduce){
  .act-inner{opacity:1; transform:none; transition:none}
}
.act.right{justify-content:flex-end}
.act.right .act-inner{text-align:right}
.act.center{justify-content:center}
.act.center .act-inner{text-align:center}
.act.compact{min-height:auto; padding-top:8rem; padding-bottom:6rem}

.eyebrow{
  font-family:var(--mono); font-size:.72rem; letter-spacing:.1em; text-transform:uppercase;
  color:var(--accent-2); margin:0 0 1.6rem; font-weight:500; text-shadow:0 2px 18px rgba(5,2,8,.9);
}
.band{
  font-family:var(--mono); font-size:.72rem; letter-spacing:.08em; text-transform:uppercase;
  color:var(--accent-3); margin:0 0 1rem; font-weight:500; text-shadow:0 2px 18px rgba(5,2,8,.9);
}
h1{font-family:var(--display); font-weight:700; font-size:clamp(3rem,11vw,8.4rem); line-height:.94; letter-spacing:-.02em; margin:0 0 2rem; text-wrap:balance; text-shadow:0 4px 40px rgba(5,2,8,.85), 0 1px 4px rgba(5,2,8,.9)}
h2{font-family:var(--display); font-weight:700; font-size:clamp(1.9rem,5vw,3.8rem); line-height:1.04; letter-spacing:-.015em; margin:0 0 1.6rem; text-wrap:balance; text-shadow:0 4px 32px rgba(5,2,8,.85), 0 1px 4px rgba(5,2,8,.9)}
h3{font-family:var(--display); font-weight:600; font-size:clamp(1.25rem,2.4vw,1.7rem); line-height:1.22; margin:0 0 1rem; text-shadow:0 2px 20px rgba(5,2,8,.85)}
.lede{font-size:clamp(1.05rem,1.9vw,1.4rem); line-height:1.6; color:var(--cream-dim); margin:0 0 1.2rem; max-width:34rem; text-shadow:0 2px 20px rgba(5,2,8,.9)}
.act.right .lede{margin-left:auto}
.act.center .lede{margin-left:auto;margin-right:auto}
.note{font-size:.92rem; line-height:1.7; color:var(--cream-faint); margin:2rem 0 0; max-width:30rem; text-shadow:0 2px 16px rgba(5,2,8,.9)}
.act.center .note{margin-left:auto;margin-right:auto}
.rule{width:4.5rem; height:3px; background:var(--accent); margin:0 0 2rem}
.act.right .rule{margin-left:auto}
.act.center .rule{margin-left:auto;margin-right:auto}

/* interactive band marker (click-to-trigger) */
.band-btn{
  display:inline-flex; align-items:center; gap:.6rem;
  background:none; border:2px solid var(--rule); color:var(--cream);
  padding:.6rem 1.15rem; margin-top:1.4rem;
  font-family:var(--body); font-size:.7rem; font-weight:600; letter-spacing:.1em; text-transform:uppercase;
  cursor:pointer; transition:border-color .3s var(--ease-snap), background .3s var(--ease-snap), transform .3s var(--ease-snap);
}
.band-btn:hover,.band-btn:focus-visible{border-color:var(--accent); background:rgba(255,45,107,.1); transform:translateX(3px)}
.band-btn .dot{width:7px; height:7px; border-radius:50%; background:var(--accent-2); box-shadow:0 0 8px var(--accent-2)}

/* detail panel revealed by click-trigger */
.detail{
  max-height:0; overflow:hidden; opacity:0;
  transition:max-height .6s cubic-bezier(.4,0,.2,1), opacity .5s ease;
  margin-top:1.6rem; border-left:3px solid var(--accent); padding-left:1.4rem;
}
.detail.open{max-height:20rem; opacity:1}
.detail p{font-size:.88rem; line-height:1.7; color:var(--cream-dim); margin:0}
/* Gated tool results need more room than an FAQ answer — the grader's full
   breakdown runs to 25 checks across six categories, so this cap has to be
   generous enough that a long result is never silently clipped. */
.detail.tool-result.open{max-height:400rem}

/* ---------- score dial (Grader, Readiness Score) ---------- */
.dial-wrap{position:relative; width:9rem; height:9rem; flex-shrink:0}
.dial-wrap svg{width:100%; height:100%; transform:rotate(-90deg)}
.dial-track{fill:none; stroke:var(--rule); stroke-width:8}
.dial-value{fill:none; stroke:var(--accent-2); stroke-width:8; stroke-linecap:round}
.dial-number{
  position:absolute; inset:0; display:flex; align-items:center; justify-content:center;
  font-family:var(--display); font-weight:700; font-size:2.1rem; color:var(--cream);
}

/* ---------- toggle rows (Package Configurator) ---------- */
.toggle-row{
  display:flex; align-items:center; justify-content:space-between; gap:1rem;
  padding:1rem 0; border-top:1px solid var(--rule); cursor:pointer; user-select:none;
}
.toggle-row:first-child{border-top:none}
.toggle-row .label{font-size:.92rem; color:var(--cream)}
.toggle-row .sub{font-size:.76rem; color:var(--cream-faint); margin-top:.2rem}
.toggle{
  position:relative; width:2.75rem; height:1.5rem; border-radius:99px;
  background:var(--rule); flex-shrink:0; transition:background .3s var(--ease-snap);
}
.toggle::after{
  content:''; position:absolute; top:2px; left:2px; width:1.25rem; height:1.25rem;
  border-radius:50%; background:var(--cream); transition:transform .3s var(--ease-snap);
}
.toggle-row[aria-pressed="true"] .toggle{background:var(--accent-2)}
.toggle-row[aria-pressed="true"] .toggle::after{transform:translateX(1.25rem); background:var(--ink)}
.toggle-row:focus-visible{outline:2px solid var(--accent-2); outline-offset:3px}

/* ---------- jump-nav pills (tools.html) ---------- */
.jump-nav{display:flex; flex-wrap:wrap; gap:.7rem; margin-top:2rem}
.jump-nav a{
  font-family:var(--mono); font-size:.72rem; letter-spacing:.08em; text-transform:uppercase;
  color:var(--cream-dim); text-decoration:none; border:1px solid var(--rule); border-radius:99px;
  padding:.55rem 1.1rem; transition:border-color .3s ease, color .3s ease;
}
.jump-nav a:hover{border-color:var(--accent-2); color:var(--accent-2)}

/* ---------- tool result rows ---------- */
.result-row{display:flex; align-items:baseline; justify-content:space-between; gap:1rem; padding:.7rem 0; border-top:1px solid var(--rule)}
.result-row:first-child{border-top:none}
.result-row .k{font-size:.85rem; color:var(--cream-faint)}
.result-row .v{font-family:var(--display); font-size:1.3rem; color:var(--cream)}
.result-row .v.accent{color:var(--accent-2)}

/* hero */
#hero{min-height:100vh; position:relative}
/* Desktop-only: at 1440x900 the hero eyebrow's top row was overlapping the
   ANCHORS logo/nav links, because the flex-centered .act-inner can start
   above y=0 when its content (the 3-line display heading) is taller than the
   viewport. Scoped to min-width:761px — mobile's hero never had this
   collision, and adding the same padding there was pushing the CTA row down
   into the scroll cue instead (a second bug this created and then fixed
   below). Doesn't change type scale/spacing, just reserves clearance. */
@media (min-width:761px){
  #hero{padding-top:clamp(6rem,14vh,9rem)}
}

/* CTA — hard offset shadow for graphic punch, glow blooms in on hover */
.cta{
  display:inline-block; margin-top:2.4rem; padding:1.1rem 2.6rem;
  border:2px solid var(--ink); color:var(--ink); text-decoration:none;
  background:var(--accent);
  font-size:.76rem; font-weight:700; letter-spacing:.14em; text-transform:uppercase;
  box-shadow:6px 6px 0 var(--accent-2);
  transition:transform .3s var(--ease-snap), box-shadow .3s var(--ease-snap);
}
.cta:hover,.cta:focus-visible{transform:translate(-3px,-3px); box-shadow:9px 9px 0 var(--accent-2), 0 0 34px rgba(255,45,107,.4)}
.cta.ghost{border-color:var(--cream); color:var(--cream); background:none; box-shadow:6px 6px 0 var(--rule)}
.cta.ghost:hover{background:var(--cream); color:var(--ink); box-shadow:9px 9px 0 var(--accent)}
.cta.ai{border-color:var(--ink); background:var(--accent-3); color:var(--ink); box-shadow:6px 6px 0 var(--accent)}
.cta.ai:hover{box-shadow:9px 9px 0 var(--accent), 0 0 34px rgba(61,214,255,.45)}
.cta-row{display:flex; gap:1.2rem; flex-wrap:wrap}
.act.center .cta-row{justify-content:center}
.act.right .cta-row{justify-content:flex-end}

/* glass panel */
.glass{
  background:var(--glass-bg); border:2px solid var(--glass-border);
  -webkit-backdrop-filter:blur(18px) saturate(150%); backdrop-filter:blur(18px) saturate(150%);
}
.glow-ring{position:relative}
.glow-ring::before{
  content:''; position:absolute; inset:-2px; border-radius:inherit; z-index:-1;
  background:linear-gradient(135deg, var(--accent), var(--accent-3));
  opacity:.4; filter:blur(16px);
}

/* animated gradient mesh backdrop — three-color, more saturated for the maximalist read */
.mesh{position:absolute; inset:0; z-index:1; pointer-events:none; overflow:hidden}
.mesh::before,.mesh::after{
  content:''; position:absolute; width:60vw; height:60vw; border-radius:50%;
  filter:blur(85px); opacity:.24; mix-blend-mode:screen;
  animation:meshdrift 20s ease-in-out infinite alternate;
}
.mesh::before{background:var(--accent); top:-15%; left:-10%}
.mesh::after{background:var(--accent-3); bottom:-20%; right:-10%; animation-delay:-8s}
@keyframes meshdrift{
  0%{transform:translate(0,0) scale(1)}
  100%{transform:translate(6vw,4vw) scale(1.15)}
}

/* depth gauge */
#gauge{position:fixed; right:clamp(1rem,2.5vw,2.4rem); top:50%; transform:translateY(-50%); z-index:4; display:flex; flex-direction:column; gap:.55rem; align-items:center}
/* Ticks are now real keyboard targets (role=button, tabindex=0 — see site.js).
   The visible mark stays a thin 2px line; a larger invisible hit area sits
   behind it so it's still comfortably clickable/tappable and shows a proper
   focus ring without inflating the visual device. */
#gauge .tick{
  position:relative; width:2px; height:1.6rem; background:var(--rule);
  transition:background .5s ease, height .5s ease; cursor:pointer;
}
#gauge .tick::before{
  content:''; position:absolute; inset:-.6rem -.9rem; /* ~2rem square hit area */
}
#gauge .tick.on{background:var(--accent-2); height:2.4rem; box-shadow:0 0 8px var(--accent-2)}
#gauge .tick:focus-visible{outline:2px solid var(--accent-2); outline-offset:4px}
#depth{position:fixed; left:clamp(1rem,2.5vw,2.4rem); bottom:clamp(1rem,2.5vw,2.2rem); z-index:4; font-family:var(--mono); font-size:.64rem; letter-spacing:.14em; color:var(--cream-faint); font-variant-numeric:tabular-nums}

/* ---------- generic content sections (inner pages) ---------- */
.section{position:relative; z-index:3; padding:7rem clamp(1.5rem,6vw,6rem)}
.section-head{max-width:40rem; margin:0 auto 4rem}
.section-head.left{margin:0 0 4rem}
.grid-3{display:grid; grid-template-columns:repeat(auto-fit,minmax(15rem,1fr)); gap:2rem; max-width:76rem; margin:0 auto}
.card{
  border:2px solid var(--rule); padding:2.2rem; background:rgba(245,241,236,.03);
  opacity:0; transform:translateY(2rem) scale(.97);
  transition:opacity .4s var(--ease-snap), transform .4s var(--ease-snap), border-color .12s var(--ease-snap), box-shadow .12s var(--ease-snap);
}
.card.in{opacity:1; transform:translateY(0) scale(1)}
.card:hover{border-color:var(--accent); transform:translateY(-6px) scale(1.01); box-shadow:9px 9px 0 var(--accent-2); transition-duration:.12s}
.card:active{transform:translateY(-2px) scale(.98); transition-duration:.06s}
.card .num{font-family:var(--mono); font-size:1.5rem; color:var(--accent); margin:0 0 1rem; font-weight:600}

/* Compact portfolio teaser cards (homepage) — a .card variant with an image
   instead of padded text, so the sharp hover/reveal motion above applies
   here too without a second set of rules. */
.portfolio-card{padding:0; overflow:hidden; display:block; text-decoration:none; color:inherit}
.portfolio-card img{display:block; width:100%; aspect-ratio:16/9; object-fit:cover}
.portfolio-card .plabel{display:flex; align-items:baseline; justify-content:space-between; gap:.6rem; padding:1rem 1.1rem}
.portfolio-card .pname{font-family:var(--display); font-weight:700; font-size:.92rem}
.portfolio-card .pnum{font-family:var(--mono); font-size:.62rem; color:var(--accent-2); letter-spacing:.08em}

@media (prefers-reduced-motion:reduce){
  .card{opacity:1; transform:none; transition:border-color .12s ease, box-shadow .12s ease}
  .card:hover,.card:active{transform:none}
}

/* pricing card — edgy clipped corner */
.price-card{
  position:relative; border:2px solid var(--rule); padding:2.6rem;
  background:rgba(245,241,236,.03);
  clip-path:polygon(0 0, calc(100% - 2rem) 0, 100% 2rem, 100% 100%, 0 100%);
  transition:border-color .4s var(--ease-snap), transform .4s var(--ease-snap);
}
.price-card.hi{border-color:var(--accent)}
.price-card:hover{transform:translateY(-4px)}
.price-card .tier-name{font-family:var(--mono); font-size:.72rem; letter-spacing:.1em; text-transform:uppercase; color:var(--accent-2); margin:0 0 .8rem}
.price-card .price{font-family:var(--display); font-weight:700; font-size:clamp(2.2rem,4.5vw,3rem); margin:0 0 .3rem; color:var(--cream)}
.price-card .price span{font-family:var(--mono); font-size:.9rem; font-weight:400; color:var(--cream-faint)}
.price-card .for{font-size:.82rem; color:var(--cream-faint); margin:0 0 1.6rem}
.price-card ul{list-style:none; margin:0 0 1.8rem; padding:0}
.price-card li{font-size:.92rem; color:var(--cream-dim); padding:.55rem 0; border-top:1px solid var(--rule)}
.price-card li:first-child{border-top:none}

/* "actively building" badge (products.html) — a live pulse reads as more
   compelling than a static "coming soon", the same open-loop principle
   as everywhere else on this site that shows work in progress. */
.building-badge{
  display:inline-flex; align-items:center; gap:.5rem;
  font-family:var(--mono); font-size:.66rem; letter-spacing:.1em; text-transform:uppercase;
  color:var(--accent-3); border:1px solid var(--accent-3); border-radius:99px;
  padding:.4rem 1rem; margin-bottom:1.2rem;
}
.building-badge .pulse{width:.4rem; height:.4rem; border-radius:99px; background:var(--accent-3); animation:building-pulse 1.6s ease-in-out infinite; flex:0 0 auto}
@keyframes building-pulse{0%,100%{opacity:.35} 50%{opacity:1}}
@media (prefers-reduced-motion:reduce){.building-badge .pulse{animation:none}}

.stat-row{display:flex; flex-wrap:wrap; gap:3rem; max-width:60rem; margin:0 auto}
.stat{min-width:9rem}
.stat .n{font-family:var(--display); font-weight:700; font-size:clamp(2.2rem,5vw,3.4rem); line-height:1}
.stat .l{font-family:var(--mono); font-size:.72rem; letter-spacing:.1em; text-transform:uppercase; color:var(--cream-faint); margin-top:.6rem}

/* forms (contact / lead magnet) */
.field{margin-bottom:1.4rem; max-width:32rem}
.field label{display:block; font-family:var(--mono); font-size:.7rem; letter-spacing:.1em; text-transform:uppercase; color:var(--accent-2); margin-bottom:.6rem}
.field input,.field textarea{
  width:100%; background:transparent; border:none; border-bottom:2px solid var(--rule);
  color:var(--cream); font-family:var(--body); font-size:1rem; padding:.7rem 0;
  outline:none; transition:border-color .3s ease;
}
.field input:focus,.field textarea:focus{border-color:var(--accent)}
.field textarea{resize:vertical; min-height:6rem}

.status-line{font-family:var(--mono); font-size:.8rem; color:var(--cream-faint); margin-top:1rem; min-height:1.4em}

/* ---------- client portal: project cards (account.html dashboard) ---------- */
.projects-heading{font-family:var(--mono); font-size:.72rem; letter-spacing:.12em; text-transform:uppercase; color:var(--accent-2); margin:0 0 1rem}
.project-card{border:1px solid var(--rule); border-radius:.9rem; padding:1.3rem 1.4rem; margin-bottom:1.2rem}
.project-head{display:flex; align-items:center; justify-content:space-between; gap:1rem}
.project-head h3{margin:0; font-size:1.05rem}
.project-notes{color:var(--cream-dim); font-size:.86rem; margin:.6rem 0 0}
.status-badge{
  font-family:var(--mono); font-size:.62rem; letter-spacing:.08em; text-transform:uppercase;
  padding:.28rem .7rem; border-radius:99px; white-space:nowrap; border:1px solid var(--rule); color:var(--cream-dim);
}
.status-badge.status-in_progress{color:var(--accent-3); border-color:var(--accent-3)}
.status-badge.status-review{color:var(--accent); border-color:var(--accent)}
.status-badge.status-live,.status-badge.status-paid,.status-badge.status-done{color:var(--accent-2); border-color:var(--accent-2)}
.status-badge.status-overdue{color:var(--accent); border-color:var(--accent); background:rgba(255,45,107,.1)}
.milestones{list-style:none; margin:1rem 0 0; padding:0; display:flex; flex-direction:column; gap:.5rem}
.milestone{display:flex; align-items:center; gap:.6rem; font-size:.86rem; color:var(--cream-dim)}
.milestone .dot{width:.5rem; height:.5rem; border-radius:99px; background:var(--rule); flex:0 0 auto}
.milestone-in_progress .dot{background:var(--accent-3)}
.milestone-done .dot{background:var(--accent-2)}
.milestone-done{color:var(--cream-faint); text-decoration:line-through}
.milestone-due{margin-inline-start:auto; font-family:var(--mono); font-size:.7rem; color:var(--cream-faint)}
.deliverables{display:flex; flex-wrap:wrap; gap:.6rem 1.2rem; margin-top:1rem}
.deliverable-link{font-size:.86rem; color:var(--accent-3); text-decoration:none}
.deliverable-link:hover{text-decoration:underline}
.invoices{margin-top:1rem; border-top:1px solid var(--rule); padding-top:1rem}
.invoice-row{display:grid; grid-template-columns:1fr auto auto auto; align-items:center; gap:1rem; font-size:.84rem; padding:.4rem 0}
.invoice-row a{color:var(--accent-3); text-decoration:none; font-size:.78rem; white-space:nowrap}
.invoice-row a:hover{text-decoration:underline}

/* ---------- account page: log in / create account switcher ----------
   Both paths hit the same passwordless email-code endpoint underneath
   (the backend already no-ops a blank name/company against an existing
   user — see anchors_find_or_create_user in api/auth.php) — this is a
   front-end-only choice so a returning visitor isn't asked for a name
   and company they already gave us the first time. */
.auth-tabs{display:flex; border-bottom:1px solid var(--rule); margin-bottom:1.8rem}
.auth-tab{
  flex:1; background:none; border:none; padding:0 0 .9rem; cursor:pointer;
  font-family:var(--mono); font-size:.76rem; font-weight:600; letter-spacing:.08em; text-transform:uppercase;
  color:var(--cream-faint); border-bottom:2px solid transparent; margin-bottom:-1px;
  transition:color .2s ease, border-color .2s ease;
}
.auth-tab:hover{color:var(--cream-dim)}
.auth-tab.is-active{color:var(--accent-2); border-color:var(--accent-2)}
.signup-only{display:none}
.mode-signup .signup-only{display:block}
.status-line.err{color:#FF6B8B}
.status-line.ok{color:var(--accent-2)}

@media (max-width:640px){
  #gauge{display:none}
  .act{min-height:110vh}
  .stat-row{gap:1.8rem}
}
@media (prefers-reduced-motion:reduce){
  .act-inner{transition:none !important}
}

/* ---------- kinetic type (scroll-velocity skew, applied via JS) ---------- */
.kinetic{display:inline-block; will-change:transform; transform-origin:50% 50%}

/* ---------- marquee ticker ---------- */
.marquee{
  overflow:hidden; position:relative; z-index:3;
  border-top:2px solid var(--rule); border-bottom:2px solid var(--rule);
  padding:1.15rem 0; background:var(--ink-2);
}
.marquee-track{display:flex; width:max-content; animation:marquee-scroll 26s linear infinite}
.marquee-track .group{display:flex; align-items:center}
.marquee-track span{
  display:inline-block; padding:0 1.6rem; font-family:var(--mono); font-size:.85rem;
  letter-spacing:.08em; text-transform:uppercase; color:var(--cream-dim); white-space:nowrap;
}
.marquee-track span.pop{color:var(--accent-2)}
.marquee-track span.sep{color:var(--accent); padding:0 .4rem}
@keyframes marquee-scroll{from{transform:translateX(0)}to{transform:translateX(-50%)}}
@media (prefers-reduced-motion:reduce){.marquee-track{animation:none}}

/* ---------- ghost numerals (background graphic device) ---------- */
.ghost-num{
  position:absolute; font-family:var(--display); font-weight:800;
  font-size:clamp(9rem,24vw,22rem); line-height:1; color:transparent;
  -webkit-text-stroke:1.5px var(--rule); z-index:0; pointer-events:none; user-select:none;
}

/* ---------- diagonal section cuts (used sparingly) ---------- */
.section.cut-top{clip-path:polygon(0 5vw,100% 0,100% 100%,0 100%); padding-top:10rem}
.section.cut-bottom{clip-path:polygon(0 0,100% 0,100% calc(100% - 5vw),0 100%); padding-bottom:10rem}


/* ---------- portfolio rail — coverflow tiles with live site embeds ----------
   Used on the home page and on designed-by-anchors.html. See assets/rail.js;
   several rules here are relied on by that script and are noted where so. */

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

.rail-wrap{position:relative}

/* The pause control. WCAG 2.2.2 needs auto-moving content to be stoppable by a
   real control — hover-pause is no use to a keyboard or touch visitor — and it
   sits before the rail in source order so it's reachable first. 44px min target. */
.rail-toggle{
  display:inline-flex; align-items:center; justify-content:center; gap:.5rem;
  min-width:44px; min-height:44px; padding:.4rem .9rem;
  background:var(--glass-bg); border:1px solid var(--glass-border); border-radius:99px;
  color:var(--cream-dim); font-family:var(--mono); font-size:.66rem;
  letter-spacing:.12em; text-transform:uppercase; cursor:pointer;
  transition:color .3s ease, border-color .3s ease;
}
.rail-toggle:hover{color:var(--accent-2); border-color:var(--accent-2)}
.rail-toggle::before{content:"❙❙"; font-size:.7em; letter-spacing:-.1em}
.rail-toggle[data-state="paused"]::before{content:"▶"; letter-spacing:0}

.work-rail{
  display:flex;
  gap:1.4rem;
  list-style:none;
  margin:1rem 0 0;
  overflow-x:auto;
  overscroll-behavior-x:contain;   /* stops trackpad overscroll firing browser back-nav */
  -webkit-overflow-scrolling:touch;
  /* Vertical padding is load-bearing twice over: it's the headroom the centre
     tile's focus ring needs, and without it overflow-x:auto's implicit
     overflow-y:auto clips the ring and spawns a phantom vertical scrollbar.
     (The scale itself peaks at exactly 1.0, so tiles never exceed layout size.) */
  padding:2.4rem clamp(1.2rem,6vw,5rem) 2.8rem;
  margin-inline:calc(-1 * clamp(1.2rem,6vw,5rem));
  scrollbar-width:thin;
  scrollbar-color:var(--rule) transparent;
  /* Deliberately no scroll-snap: it fights the continuous scale and, on iOS,
     ping-pongs against programmatic scrolling during momentum. */
}
.work-rail::-webkit-scrollbar{height:6px}
.work-rail::-webkit-scrollbar-track{background:transparent}
.work-rail::-webkit-scrollbar-thumb{background:var(--rule); border-radius:99px}
.work-rail::-webkit-scrollbar-thumb:hover{background:var(--cream-faint)}

.work-tile{
  flex:0 0 auto;
  width:clamp(250px,30vw,400px);
  /* Wider than the rail's own edge padding, so a tile focused at either end
     scrolls clear rather than landing under the gutter (WCAG 2.4.11). */
  scroll-margin-inline:clamp(1.4rem,7vw,6rem);
  /* rail.js measures THIS element and transforms .tile-inner. Never put a
     transform here — measuring a transformed element feeds back on itself. */
}
.tile-inner{
  position:relative;
  isolation:isolate;               /* keeps one tile's shield off its neighbour */
  display:block;
  padding:10px;
  border-radius:16px;
  background:var(--glass-bg);
  border:1px solid var(--glass-border);
  backdrop-filter:blur(14px) saturate(1.25);
  -webkit-backdrop-filter:blur(14px) saturate(1.25);
  transform-origin:center center;
  will-change:transform, opacity;
  /* Fast + snap-eased on purpose — a tile becoming centred should read as a
     hard cut into focus, matching the site's chromatic/kinetic energy, not a
     slow cinematic crossfade. The transform itself (set per-frame by rail.js,
     following scroll 1:1) is deliberately NOT transitioned — a transition
     there would lag behind the scroll instead of tracking it. */
  transition:border-color .12s var(--ease-snap), box-shadow .16s var(--ease-snap);
}
.work-tile.is-centre .tile-inner{
  border-color:var(--accent-2);
  box-shadow:0 20px 55px -14px rgba(0,0,0,.85), 0 0 0 2px var(--accent-2), 0 0 34px -6px rgba(198,255,77,.55);
}

.stage{
  position:relative; display:block; overflow:hidden;
  width:100%; aspect-ratio:16/9;
  border-radius:9px; background:var(--ink-2);
}
.stage .shot{
  position:absolute; inset:0;
  width:100%; height:100%;
  object-fit:cover; object-position:top center;
  transition:opacity .18s var(--ease-snap);
}
/* The embed. pointer-events:none is what makes it purely a moving picture —
   without it the framed site swallows every wheel, touch and click over the
   tile. It sits UNDER the link's shield (z-index below .tile-link::after).
   Fade is quick — a hard reveal, matching the rest of the rail's snappier
   motion — rather than a slow crossfade. */
.stage .live{
  position:absolute; top:0; left:0;
  width:1600px; height:900px; border:0;
  transform-origin:0 0;            /* rail.js sets the scale factor */
  pointer-events:none;
  opacity:0; transition:opacity .2s var(--ease-snap);
  z-index:1;
}
.stage .live.on{opacity:1}
.work-tile.is-live .shot{opacity:0}

.work-meta{
  display:flex; align-items:baseline; justify-content:space-between;
  gap:.75rem; padding:.85rem .3rem .25rem; margin:0;
}
.work-cat{
  font-family:var(--display); font-weight:700;
  font-size:clamp(.86rem,1.4vw,1rem); line-height:1.25;
  text-decoration:none; color:inherit;
}
.work-sub{
  font-family:var(--mono); font-size:.6rem; letter-spacing:.1em;
  text-transform:uppercase; color:var(--cream-faint); white-space:nowrap;
}
/* The shield: the link itself covers the whole tile, above the embed. Keeping
   it a real <a> rather than a JS click handler is what preserves middle-click,
   ctrl/cmd-click and "open in new tab". */
.tile-link::after{content:""; position:absolute; inset:0; z-index:3}
.tile-link:focus-visible{outline:3px solid var(--accent-2); outline-offset:4px}
.work-tile.is-centre .work-cat{color:var(--accent-2)}
.work-cat::after{
  content:"↗"; font-family:var(--body); margin-inline-start:.35em;
  color:var(--accent-2); opacity:0; transition:opacity .35s ease;
}
.work-tile.is-centre .work-cat::after{opacity:1}

.rail-hint{
  font-family:var(--mono); font-size:.64rem; letter-spacing:.12em;
  text-transform:uppercase; color:var(--cream-faint); margin:.4rem 0 0;
}

/* No live embeds and no drift under reduced motion (rail.js enforces the same
   thing); the centre cue becomes a static ring instead of a size change. */
@media (prefers-reduced-motion: reduce){
  .tile-inner{transition:none}
  .stage .live{display:none}
}
/* Forced-colours mode drops box-shadow entirely, so the centre tile needs an
   outline to stay distinguishable. */
@media (forced-colors: active){
  .work-tile.is-centre .tile-inner{outline:3px solid Highlight}
}
@media print{
  .stage .live{display:none}
  .work-rail{overflow:visible; flex-wrap:wrap}
}
@media (max-width:760px){
  .work-tile{width:clamp(240px,80vw,320px)}
  .work-rail{gap:1rem}
}

/* ---------- liquid-glass infinite carousel (Designed by Anchors) ----------
   A different showcase mechanism from the homepage's coverflow rail above:
   a continuously auto-scrolling row of frosted, tinted glass cards instead of
   a centre-weighted 3D stack. Track holds each item twice back-to-back so a
   translateX(-50%) loop is seamless; the second half is aria-hidden/inert to
   screen readers and keyboard nav. Driven by assets/glass-carousel.js. */
.glass-rail{
  position:relative; overflow:hidden; margin:1.2rem -1.5rem 0; padding:1.4rem 0;
  -webkit-mask-image:linear-gradient(to right, transparent, #000 6%, #000 94%, transparent);
  mask-image:linear-gradient(to right, transparent, #000 6%, #000 94%, transparent);
}
.glass-track{
  display:flex; gap:1.6rem; width:max-content;
  animation:glass-scroll 46s linear infinite;
  padding:0 1.5rem;
}
.glass-track.paused,.glass-track.hover-pause{animation-play-state:paused}
@keyframes glass-scroll{from{transform:translateX(0)}to{transform:translateX(-50%)}}

.glass-card{
  --mx:50%; --my:50%;
  position:relative; flex:0 0 auto; width:min(74vw,300px);
  border-radius:1.3rem; overflow:hidden; display:block; text-decoration:none; color:inherit;
  background:
    radial-gradient(120% 130% at 12% -10%, rgba(255,45,107,.22), transparent 55%),
    radial-gradient(120% 130% at 100% 115%, rgba(198,255,77,.16), transparent 55%),
    linear-gradient(165deg, rgba(245,241,236,.09), rgba(245,241,236,.02));
  border:1px solid rgba(245,241,236,.16);
  backdrop-filter:blur(18px) saturate(1.5);
  -webkit-backdrop-filter:blur(18px) saturate(1.5);
  box-shadow:0 20px 40px -22px rgba(0,0,0,.65), inset 0 1px 0 rgba(255,255,255,.16);
  transform:translateY(0) scale(1);
  transition:transform .35s var(--ease-snap), box-shadow .35s var(--ease-snap), border-color .35s var(--ease-snap);
}
.glass-card::after{
  content:""; position:absolute; top:0; left:10%; right:10%; height:1px; z-index:2; pointer-events:none;
  background:linear-gradient(90deg, transparent, rgba(255,255,255,.6), transparent);
}
.glass-card .glass-glow{
  position:absolute; inset:0; z-index:1; pointer-events:none; opacity:0;
  background:radial-gradient(180px circle at var(--mx) var(--my), rgba(255,255,255,.28), transparent 62%);
  transition:opacity .3s ease;
}
.glass-card .glass-shine{
  position:absolute; inset:0; z-index:2; pointer-events:none;
  background:linear-gradient(115deg, transparent 42%, rgba(255,255,255,.4) 50%, transparent 58%);
  transform:translateX(-130%);
  transition:transform .7s cubic-bezier(.2,.9,.3,1);
}
.glass-card img{
  position:relative; z-index:0; display:block; width:100%; aspect-ratio:16/9; object-fit:cover;
  filter:saturate(1.08) contrast(1.03);
}
.glass-meta{
  position:absolute; left:0; right:0; bottom:0; z-index:3;
  display:flex; align-items:baseline; gap:.7rem; padding:1.1rem 1.1rem 1rem;
  background:linear-gradient(to top, rgba(8,5,12,.88), transparent);
}
.glass-num{font-family:var(--mono); font-size:.68rem; color:var(--accent-2); font-weight:600; letter-spacing:.04em}
.glass-name{font-family:var(--display); font-weight:700; font-size:.98rem; color:var(--cream); letter-spacing:-.01em}
.glass-card:hover,.glass-card:focus-visible{
  transform:translateY(-10px) scale(1.045);
  border-color:rgba(198,255,77,.55);
  box-shadow:0 32px 60px -20px rgba(0,0,0,.75), 0 0 42px rgba(255,45,107,.28), inset 0 1px 0 rgba(255,255,255,.32);
}
.glass-card:hover .glass-glow,.glass-card:focus-visible .glass-glow{opacity:1}
.glass-card:hover .glass-shine,.glass-card:focus-visible .glass-shine{transform:translateX(130%)}
.glass-card:focus-visible{outline:2px solid var(--accent-2); outline-offset:3px}

/* ---------- static glass tiles (Products, Services) ----------
   Same frosted/tinted glass recipe as .glass-card above, adapted for
   content-heavy cards that need to sit still and hold real text — price,
   bullets, a CTA — rather than a photo+caption scrolling past. Pointer-
   reactive glow tracks the cursor the same way (see the small inline
   script on each page that sets --mx/--my on pointermove). */
.glass-tiles{display:grid; grid-template-columns:repeat(auto-fit,minmax(19rem,1fr)); gap:1.6rem; max-width:76rem; margin:0 auto}
.glass-tile{
  --mx:50%; --my:50%;
  position:relative; padding:2.2rem; border-radius:1.3rem; overflow:hidden;
  background:
    radial-gradient(120% 130% at 12% -10%, rgba(255,45,107,.22), transparent 55%),
    radial-gradient(120% 130% at 100% 115%, rgba(198,255,77,.16), transparent 55%),
    linear-gradient(165deg, rgba(245,241,236,.09), rgba(245,241,236,.02));
  border:1px solid rgba(245,241,236,.16);
  backdrop-filter:blur(18px) saturate(1.5);
  -webkit-backdrop-filter:blur(18px) saturate(1.5);
  box-shadow:0 20px 40px -22px rgba(0,0,0,.65), inset 0 1px 0 rgba(255,255,255,.16);
  transition:transform .35s var(--ease-snap), box-shadow .35s var(--ease-snap), border-color .35s var(--ease-snap);
}
.glass-tile.hi{border-color:rgba(255,45,107,.5)}
.glass-tile::after{
  content:""; position:absolute; top:0; left:10%; right:10%; height:1px; z-index:2; pointer-events:none;
  background:linear-gradient(90deg, transparent, rgba(255,255,255,.6), transparent);
}
.glass-tile .glass-glow{
  position:absolute; inset:0; z-index:0; pointer-events:none; opacity:0;
  background:radial-gradient(220px circle at var(--mx) var(--my), rgba(255,255,255,.16), transparent 62%);
  transition:opacity .3s ease;
}
.glass-tile:hover .glass-glow,.glass-tile:focus-within .glass-glow{opacity:1}
.glass-tile:hover,.glass-tile:focus-within{
  transform:translateY(-6px);
  border-color:rgba(198,255,77,.55);
  box-shadow:0 28px 50px -20px rgba(0,0,0,.7), 0 0 34px rgba(255,45,107,.22), inset 0 1px 0 rgba(255,255,255,.28);
}
.glass-tile > *{position:relative; z-index:1}
.glass-tile ul{list-style:none; margin:1.1rem 0; padding:0}
.glass-tile li{font-size:.9rem; color:var(--cream-dim); padding:.55rem 0; border-top:1px solid rgba(245,241,236,.14)}
.glass-tile li:first-child{border-top:none}

.category-block{margin-top:1.3rem; padding-top:1.1rem; border-top:1px solid rgba(245,241,236,.14)}
.category-label{font-family:var(--mono); font-size:.66rem; letter-spacing:.1em; text-transform:uppercase; color:var(--accent-2); margin:0 0 .35rem}
.category-item{font-size:.88rem; color:var(--cream-dim); margin:0}
.category-block.is-empty .category-label{color:var(--cream-faint)}
.category-block.is-empty .category-item{color:var(--cream-faint); font-style:italic}
.category-block.is-empty .category-item a{color:var(--accent-3); font-style:normal}

@media (prefers-reduced-motion:reduce){
  .glass-track{animation:none}
  .glass-rail{overflow-x:auto; -webkit-overflow-scrolling:touch}
  .glass-card.dup{display:none}
  .glass-card,.glass-card .glass-shine{transition:none}
}
@media (forced-colors:active){
  .glass-card:hover,.glass-card:focus-visible{outline:3px solid Highlight}
}
@media print{
  .glass-rail{overflow-x:visible; mask-image:none}
  .glass-track{animation:none; flex-wrap:wrap}
  .glass-card.dup{display:none}
}
@media (max-width:760px){
  .glass-card{width:clamp(220px,78vw,290px)}
  .glass-rail{margin-inline:-1rem}
}

/* ---------- WebGL shader glass carousel (Designed by Anchors) ----------
   The real-time refraction/chromatic-aberration version of the carousel
   above — assets/glass-shader-carousel.js renders the distorted photo into
   #glass-gl and swaps this in over the CSS version when WebGL is available.
   Text lives in real DOM nodes overlaid on the canvas (glass-gl-labels) so
   titles/CTAs stay crisp while only the photo behind them warps. */
#glass-gl{
  display:none; width:100%; height:24rem; margin:1.2rem 0 0; border-radius:1.3rem;
}
.glass-gl-wrap{position:relative}
.glass-gl-labels{
  position:absolute; top:0; left:0; pointer-events:none;
}
.glass-gl-tile{
  position:absolute; top:50%; left:0; pointer-events:none;
  padding:0 1.5rem; opacity:0; transition:opacity .25s ease, transform .2s var(--ease-snap);
  text-align:left; display:flex; flex-direction:column; gap:.5rem;
}
.glass-gl-tag{
  font-family:var(--mono); font-size:.6rem; letter-spacing:.12em; text-transform:uppercase;
  color:var(--accent-2); margin:0; line-height:1;
  text-shadow:0 1px 6px rgba(0,0,0,.8);
}
.glass-gl-title{
  font-family:var(--display); font-weight:700; font-size:1.2rem; color:var(--cream);
  margin:0; letter-spacing:-.01em; line-height:1.15;
  text-shadow:0 2px 10px rgba(0,0,0,.85);
}
.glass-gl-desc{
  font-size:.8rem; color:var(--cream-dim); margin:0; line-height:1.4;
  max-width:14rem; text-shadow:0 1px 8px rgba(0,0,0,.9);
}
.glass-gl-enter{
  display:inline-block; align-self:flex-start; font-family:var(--mono); font-size:.66rem; letter-spacing:.08em;
  text-transform:uppercase; color:var(--ink); background:var(--accent-2);
  padding:.4rem .9rem; border-radius:99px; margin-top:.2rem;
  transition:background .2s ease, transform .2s var(--ease-snap), box-shadow .2s ease;
}
/* .is-hover is toggled per-frame by glass-shader-carousel.js to match
   whichever tile the pointer is actually over — the shader's own bulge/CA
   response lives in the pixels, this is the DOM half of the same signal so
   the hover feedback reads clearly instead of hiding entirely inside a
   subtle lens-distortion effect. */
.glass-gl-tile.is-hover .glass-gl-enter{
  background:var(--cream); transform:scale(1.08);
  box-shadow:0 6px 18px -6px rgba(198,255,77,.6);
}
@media (max-width:760px){
  #glass-gl{height:20rem}
  .glass-gl-desc{display:none}
}

/* ---------- floating WhatsApp button ----------
   Recoloured to the brand accents rather than WhatsApp's own green, so it
   reads as an Anchors element that happens to open WhatsApp, not a
   third-party widget bolted onto the page. Sits below the mobile full-screen
   nav overlay (z-index 9) so opening the menu doesn't leave it floating on top. */
.wa-float{
  position:fixed; bottom:1.7rem; right:1.7rem; z-index:6;
  width:3.4rem; height:3.4rem; border-radius:50%;
  display:flex; align-items:center; justify-content:center;
  background:rgba(11,7,16,.55); backdrop-filter:blur(10px); -webkit-backdrop-filter:blur(10px);
  border:1.5px solid var(--accent-2);
  color:var(--accent-2);
  box-shadow:0 10px 30px -8px rgba(0,0,0,.6), inset 0 0 0 1px rgba(198,255,77,.12);
  transition:transform .14s var(--ease-snap), box-shadow .2s var(--ease-snap), border-color .2s var(--ease-snap), color .2s var(--ease-snap), background .2s var(--ease-snap);
}
.wa-float svg{
  width:1.5rem; height:1.5rem; display:block;
  fill:none; stroke:currentColor; stroke-width:1.7; stroke-linecap:round; stroke-linejoin:round;
}
.wa-float::before{
  content:''; position:absolute; inset:-1.5px; border-radius:50%;
  border:1.5px solid var(--accent-2); opacity:.55; pointer-events:none;
  animation:wa-pulse 2.4s var(--ease-snap) infinite;
}
@keyframes wa-pulse{
  0%{transform:scale(1); opacity:.5}
  70%{transform:scale(1.5); opacity:0}
  100%{transform:scale(1.5); opacity:0}
}
.wa-float:hover,.wa-float:focus-visible{
  transform:scale(1.1) translateY(-2px) rotate(-3deg);
  border-color:var(--accent); color:var(--accent);
  background:rgba(255,45,107,.1);
  box-shadow:0 14px 38px -6px rgba(0,0,0,.7), 0 0 30px rgba(255,45,107,.5), inset 0 0 0 1px rgba(255,45,107,.25);
}
@media (prefers-reduced-motion:reduce){.wa-float::before{animation:none}}
/* Mirrors to the opposite corner in RTL, matching how the rest of the nav flips. */
html[dir="rtl"] .wa-float{right:auto; left:1.7rem}
@media (max-width:760px){
  .wa-float{width:3.1rem; height:3.1rem; bottom:1.2rem; right:1.2rem}
  html[dir="rtl"] .wa-float{right:auto; left:1.2rem}
}
@media print{.wa-float{display:none}}

/* ---------- floating Site Grader button ----------
   Same recipe as .wa-float (frosted circle, pulse ring, brand accents) since
   the two are meant to read as siblings, just stacked above it so neither
   corner gets crowded. Site Grader lost its own top-nav slot when it merged
   into Tools; this is now the only nav-level way to reach it from anywhere. */
.gift-float{
  position:fixed; bottom:5.7rem; right:1.7rem; z-index:6;
  width:3.4rem; height:3.4rem; border-radius:50%;
  display:flex; align-items:center; justify-content:center;
  background:rgba(11,7,16,.55); backdrop-filter:blur(10px); -webkit-backdrop-filter:blur(10px);
  border:1.5px solid var(--accent-2);
  color:var(--accent-2);
  box-shadow:0 10px 30px -8px rgba(0,0,0,.6), inset 0 0 0 1px rgba(198,255,77,.12);
  transition:transform .14s var(--ease-snap), box-shadow .2s var(--ease-snap), border-color .2s var(--ease-snap), color .2s var(--ease-snap), background .2s var(--ease-snap);
}
.gift-float svg{
  width:1.5rem; height:1.5rem; display:block;
  fill:none; stroke:currentColor; stroke-width:1.7; stroke-linecap:round; stroke-linejoin:round;
}
.gift-float::before{
  content:''; position:absolute; inset:-1.5px; border-radius:50%;
  border:1.5px solid var(--accent-2); opacity:.55; pointer-events:none;
  animation:wa-pulse 2.4s var(--ease-snap) infinite; animation-delay:1.2s;
}
.gift-float:hover,.gift-float:focus-visible{
  transform:scale(1.1) translateY(-2px) rotate(3deg);
  border-color:var(--accent); color:var(--accent);
  background:rgba(255,45,107,.1);
  box-shadow:0 14px 38px -6px rgba(0,0,0,.7), 0 0 30px rgba(255,45,107,.5), inset 0 0 0 1px rgba(255,45,107,.25);
}
@media (prefers-reduced-motion:reduce){.gift-float::before{animation:none}}
html[dir="rtl"] .gift-float{right:auto; left:1.7rem}
@media (max-width:760px){
  .gift-float{width:3.1rem; height:3.1rem; bottom:4.7rem; right:1.2rem}
  html[dir="rtl"] .gift-float{right:auto; left:1.2rem}
}
@media print{.gift-float{display:none}}

/* ---------- cookie consent banner ----------
   Only ever appears once assets/consent.js has a real Meta Pixel ID
   configured — dormant otherwise. Equal-weight accept/reject buttons on
   purpose: a bigger "Accept" and a buried "Decline" is the dark pattern
   GDPR guidance specifically calls out. */
.consent-banner{
  position:fixed; left:0; right:0; bottom:0; z-index:50;
  display:flex; flex-wrap:wrap; align-items:center; justify-content:center; gap:1.2rem 2rem;
  padding:1.2rem 1.6rem; background:rgba(11,7,16,.92);
  backdrop-filter:blur(14px); -webkit-backdrop-filter:blur(14px);
  border-top:1.5px solid var(--rule);
  transform:translateY(100%); transition:transform .3s var(--ease-snap);
}
.consent-banner.is-visible{transform:translateY(0)}
.consent-banner p{
  margin:0; max-width:44rem; font-size:.88rem; line-height:1.6; color:var(--cream-dim);
}
.consent-banner p a{color:var(--accent-2)}
.consent-actions{display:flex; gap:.8rem; flex-shrink:0}
.consent-actions .cta{padding:.7rem 1.4rem; font-size:.85rem; border:none; cursor:pointer}
.consent-actions .cta.ghost{border:2px solid var(--rule); background:transparent; color:var(--cream-dim)}
@media (max-width:600px){
  .consent-banner{justify-content:flex-start; padding:1.2rem}
  .consent-actions{width:100%}
  .consent-actions .cta{flex:1}
}
@media print{.consent-banner{display:none}}
