/* gemforge.org — studio site. Brand: HQ gold octagon on near-black
   (matches ~/.gemforge/channels/gemforgehq/config.yaml). Ambient motion
   mirrors the reel template's drift + shine motifs, dialed way down. */

:root {
  --bg: #0a0a0f;
  --bg-raise: #12121a;
  --text: #f7f5ee;
  --muted: #a89f8c;
  --gold: #d4a857;
  --gold-bright: #e8c078;
  --gold-dim: rgba(212, 168, 87, 0.35);
  --gold-faint: rgba(212, 168, 87, 0.14);
  --line: rgba(247, 245, 238, 0.10);
  /* Gems page palette — one gemstone doesn't carry the whole catalog. */
  --emerald: #4ade80;
  --ruby: #fb7185;
  --sapphire: #60a5fa;
  --diamond: #d9f1fb;
}

* { margin: 0; padding: 0; box-sizing: border-box; }

/* overflow-x: clip (not hidden) on BOTH html and body: `hidden` on body
   alone propagates oddly to the viewport and some mobile engines still let
   you pan sideways into empty background; `clip` forbids horizontal
   scrolling outright without creating a scroll container. */
html { scroll-behavior: smooth; overflow-x: clip; }

body {
  background: var(--bg);
  color: var(--text);
  font-family: Inter, -apple-system, BlinkMacSystemFont, system-ui, "Segoe UI", sans-serif;
  font-size: 17px;
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  overflow-x: clip;
}

::selection { background: var(--gold); color: #14100a; }

/* ---------- ambient background (fixed, non-interactive) ---------- */

.ambient {
  position: fixed; inset: 0;
  pointer-events: none;
  z-index: 0;
  overflow: hidden;
}
.ambient .glow {
  position: absolute; inset: -10%;
  will-change: transform;
}
.ambient .glow.a {
  background: radial-gradient(50% 34% at 42% -6%, rgba(212, 168, 87, 0.14) 0%, transparent 70%);
  animation: drift-a 26s ease-in-out infinite alternate;
}
.ambient .glow.b {
  background: radial-gradient(38% 30% at 90% 72%, rgba(212, 168, 87, 0.06) 0%, transparent 70%);
  animation: drift-b 32s ease-in-out infinite alternate;
}
@keyframes drift-a { from { transform: translate(0, 0) scale(1); } to { transform: translate(-3%, 2%) scale(1.12); } }
@keyframes drift-b { from { transform: translate(0, 0) scale(1); } to { transform: translate(3%, -3%) scale(1.15); } }

/* Gems page only: the catalog spans more than one gemstone, so the background
   itself is tinted with the whole palette rather than lit by colored glows.
   This layer sits at z-index -2 — BELOW the prism mesh (.ambient::after, -1) —
   so the facet texture overlays the color and it reads as the substrate, not
   spotlights on top of it. The four gemstone hues are overlapping full-bleed
   radial fields blended into a single dark wash. Fades in once on load (opacity
   only, so it never fights drift's transform), then drifts like the gold glows. */
@keyframes gem-glow-in { from { opacity: 0; } to { opacity: 1; } }
.gems-ambient::before {
  content: "";
  position: absolute;
  inset: -10%;
  z-index: -2;
  background:
    radial-gradient(58% 48% at 20% 16%, rgba(74, 222, 128, 0.18) 0%, transparent 68%),
    radial-gradient(54% 46% at 82% 18%, rgba(251, 113, 133, 0.15) 0%, transparent 68%),
    radial-gradient(58% 50% at 84% 82%, rgba(96, 165, 250, 0.16) 0%, transparent 68%),
    radial-gradient(52% 46% at 18% 84%, rgba(217, 241, 251, 0.10) 0%, transparent 68%);
  opacity: 0;
  animation: gem-glow-in 1200ms ease-out 120ms forwards, drift-a 30s ease-in-out infinite alternate;
  will-change: transform, opacity;
}
/* The facet mesh itself is recolored, not lit from the front: the gems page
   swaps in prism-gems.svg (same geometry, but each facet + its edge stroke is
   the gemstone hue for its position — emerald TL, ruby TR, sapphire BR, diamond
   BL — at the SAME per-facet opacity as the gold original). So the pattern is
   identical to the studio's gold mesh, just in the catalog's colors. Fades in
   once on load. Override lives just below the base .ambient::after rule. */

/* Faceted prism mesh across the whole background (generated asset —
   scratchpad make_prism.py). Sits under the glows and glint sweeps so the
   flashes read as light moving over facets. */
.ambient::after {
  content: "";
  position: absolute;
  inset: 0;
  background: url("/assets/prism.svg") center / cover no-repeat;
  opacity: 0.6;
  z-index: -1;
  /* Every arrival fades the mesh in — so returning to the gold page brings
     its color in as gradually as the gems page brings in the gemstones.
     mesh-in has no `to` block: each page's mesh rises to its own static
     opacity (0.6 gold here, 1 on the gems override below). */
  animation: mesh-in 1300ms ease-out 120ms both;
}
@keyframes mesh-in { from { opacity: 0; } }
/* Gems page: the gemstone-recolored mesh, bumped slightly brighter than the
   gold 0.6 (gemstone hues read a touch darker than luminous gold over black). */
.gems-ambient::after {
  background-image: url("/assets/prism-gems.svg");
  opacity: 1;
}

/* Glint flashes — narrow streaks that cross fast (~3s) then rest a long
   time. Rest periods are co-prime (23/37/53s) and angles/directions differ,
   so which glint fires next, and where streaks happen to overlap, keeps
   changing — quick and rare reads as light catching a facet, not a
   spotlight panning. */
.ambient .sheen { position: absolute; inset: 0; will-change: transform; }
.ambient .sheen.s1 {
  background: linear-gradient(112deg,
    transparent 46%, rgba(212, 168, 87, 0.05) 50%, transparent 54%);
  animation: glint-a 23s ease-in-out -7s infinite;
}
.ambient .sheen.s2 {
  background: linear-gradient(97deg,
    transparent 43%, rgba(212, 168, 87, 0.028) 45.5%, transparent 48%,
    transparent 52%, rgba(212, 168, 87, 0.034) 54.5%, transparent 57%);
  animation: glint-b 37s ease-in-out -19s infinite;
}
.ambient .sheen.s3 {
  background: linear-gradient(126deg,
    transparent 42%, rgba(212, 168, 87, 0.035) 50%, transparent 58%);
  animation: glint-c 53s ease-in-out -31s infinite;
}
@keyframes glint-a {
  0%   { transform: translateX(-115%); }
  14%  { transform: translateX(115%); }
  100% { transform: translateX(115%); }
}
@keyframes glint-b {
  0%   { transform: translateX(115%); }
  11%  { transform: translateX(-115%); }
  100% { transform: translateX(-115%); }
}
@keyframes glint-c {
  0%   { transform: translateX(-115%); }
  16%  { transform: translateX(115%); }
  100% { transform: translateX(115%); }
}

/* Viewport-fixed vignette above the content: an off-center pool of light
   with a diagonal falloff, so elements brighten as they scroll through the
   center of the screen and dim toward the edges. */
.vignette {
  position: fixed;
  inset: 0;
  z-index: 2;
  pointer-events: none;
  background:
    radial-gradient(ellipse 68% 58% at 52% 42%,
      rgba(238, 214, 168, 0.06) 0%, rgba(238, 214, 168, 0.025) 35%, transparent 62%),
    linear-gradient(115deg,
      rgba(2, 2, 5, 0.55) 0%, transparent 30%,
      transparent 66%, rgba(2, 2, 5, 0.6) 100%),
    radial-gradient(ellipse 88% 76% at 52% 42%,
      transparent 32%, rgba(2, 2, 5, 0.42) 72%, rgba(2, 2, 5, 0.75) 100%);
}

.wrap {
  position: relative;
  z-index: 1;
  width: 100%;
  max-width: 780px;
  margin: 0 auto;
  padding: 0 28px;
}

/* ---------- header ---------- */

header.site {
  padding: 34px 0 0;
}
header.site .wrap {
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.brand {
  display: flex;
  align-items: center;
  gap: 12px;
  text-decoration: none;
  color: var(--text);
}
.brand img { width: 34px; height: 34px; display: block; }
.brand .word {
  font-family: Georgia, "Times New Roman", serif;
  font-weight: 700;
  letter-spacing: 0.2em;
  font-size: 16px;
}
nav.site a {
  color: var(--muted);
  text-decoration: none;
  font-size: 15px;
  margin-left: 26px;
  padding-bottom: 5px;
  border-bottom: 2px solid transparent;
  transition: color 160ms ease, border-color 160ms ease;
}
nav.site a:hover { color: var(--gold); }
nav.site a.here { color: var(--gold); border-bottom-color: var(--gold-dim); }

/* ---------- hero ---------- */

main { flex: 1; }

.hero {
  position: relative;
  padding: 108px 0 28px;
}
.hero h1 {
  font-family: Georgia, "Times New Roman", serif;
  font-size: clamp(38px, 6.4vw, 60px);
  line-height: 1.1;
  font-weight: 700;
  letter-spacing: -0.005em;
  max-width: 12em;
}
.hero h1 .gold { color: var(--gold); }
/* Gems page title: a soft iridescent sheen, not a rainbow. A cohesive cool
   trio (emerald → sapphire → diamond) each blended most of the way toward the
   near-white text color, so the word reads as one light word with a gemstone
   shimmer rather than five saturated blocks fighting the colored background.
   Sweeps across once on load, then settles — the "colors arriving" beat. */
.hero h1 .gem-text {
  background: linear-gradient(100deg,
    color-mix(in srgb, var(--emerald) 38%, var(--text)),
    color-mix(in srgb, var(--sapphire) 36%, var(--text)) 50%,
    color-mix(in srgb, var(--diamond) 50%, var(--text)));
  background-size: 260% 100%;
  background-position: 130% 0;
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  -webkit-text-fill-color: transparent;
  animation: gem-sweep-in 1300ms cubic-bezier(0.33, 1, 0.68, 1) 200ms both;
}
@keyframes gem-sweep-in {
  from { background-position: 130% 0; }
  to   { background-position: 0% 0; }
}
.hero .sub {
  margin-top: 24px;
  font-size: clamp(17px, 2.4vw, 20px);
  color: color-mix(in srgb, var(--muted) 68%, var(--text));
  max-width: 30em;
}
.hero .sub strong { color: var(--text); font-weight: 600; }

/* Copy that sits directly over the faceted background gets a soft dark halo:
   a blurred, offset-less shadow in the base color darkens the busy facets
   right behind the glyphs, lifting contrast without changing the text color
   or showing a visible hard shadow. The hero title takes a gentler one, but
   NOT the gradient-clipped word (a shadow behind transparent-filled text
   ghosts the glyph shapes). */
.hero .sub,
.aside-note,
.wrap h2 {
  text-shadow: 0 1px 14px rgba(3, 4, 10, 0.6);
}
.hero h1 { text-shadow: 0 1px 16px rgba(3, 4, 10, 0.5); }
.hero h1 .gem-text { text-shadow: none; }

/* Faceted octagon gem, slowly turning. Two counter-rotating stroke groups. */
.hero-gem {
  position: absolute;
  top: -14px;
  /* never let the gem cross the viewport edge (overflow-x:hidden would slice
     it with a hard line): past ~1080px wide it sits at -170px, below that it
     slides inward to stay fully on-screen */
  right: max(-170px, calc(372px - 50vw));
  width: 360px;
  height: 360px;
  opacity: 0.65;
  pointer-events: none;
  z-index: -1;
  -webkit-mask-image: radial-gradient(ellipse 105% 105% at 62% 36%, #000 48%, transparent 82%);
  mask-image: radial-gradient(ellipse 105% 105% at 62% 36%, #000 48%, transparent 82%);
}
.hero-gem g { transform-origin: 100px 100px; }
.hero-gem .spin-slow { animation: spin 120s linear infinite; }
.hero-gem .spin-rev  { animation: spin 90s linear infinite reverse; }
@keyframes spin { to { transform: rotate(360deg); } }

@media (max-width: 900px) {
  .hero-gem { opacity: 0.4; width: 300px; height: 300px; }
}
@media (max-width: 600px) {
  .hero-gem { display: none; }
  .hero { padding-top: 84px; }
}

/* ---------- sections ---------- */

section { padding: 48px 0; }
section + section { border-top: 1px solid var(--line); }

h2 {
  display: flex;
  align-items: center;
  gap: 14px;
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--gold);
  margin-bottom: 20px;
}
h2::after {
  content: "";
  height: 1px;
  flex: 0 0 44px;
  background: linear-gradient(90deg, var(--gold-dim), transparent);
}

.prose p { max-width: 36em; }
.prose p + p { margin-top: 14px; }
.prose a:not(.gem-teaser) { color: var(--gold); text-decoration: none; border-bottom: 1px solid var(--gold-dim); transition: border-color 160ms ease; }
.prose a:not(.gem-teaser):hover { border-bottom-color: var(--gold); }

/* ---------- channels ---------- */

/* Gem-cut cards: beveled octagon plates. The li is the accent "edge" layer,
   the inner a is the same shape 1.5px smaller, so the bevel reads as a thin
   gem outline in the channel's color. box-shadow can't escape a clip-path,
   so hover feedback is lift + edge brightening. */
.channels {
  list-style: none;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 14px;
}
.channels li {
  --acc: var(--gold);
  clip-path: polygon(18px 0, calc(100% - 18px) 0, 100% 18px, 100% calc(100% - 18px),
                     calc(100% - 18px) 100%, 18px 100%, 0 calc(100% - 18px), 0 18px);
  padding: 1.5px;
  /* opaque rim (mixed with the dark base, not transparent) so the animated
     background sheens behind it can't flicker through the gold edge */
  background: linear-gradient(160deg,
    color-mix(in srgb, var(--acc) 60%, #101016),
    color-mix(in srgb, var(--acc) 14%, #101016) 55%,
    color-mix(in srgb, var(--acc) 38%, #101016));
  transition: transform 180ms ease;
}
.channels li:hover { transform: translateY(-2px); }
.channels li:active {
  transform: translateY(1px) scale(0.985);
  transition-duration: 70ms;
}
.channels li:active a { background-color: #0e0e15; }
.channels li a {
  position: relative;
  display: block;
  height: 100%;
  text-align: center;
  padding: 24px 26px 21px;
  clip-path: polygon(17px 0, calc(100% - 17px) 0, 100% 17px, 100% calc(100% - 17px),
                     calc(100% - 17px) 100%, 17px 100%, 0 calc(100% - 17px), 0 17px);
  background:
    radial-gradient(90% 70% at 18% 0%, color-mix(in srgb, var(--acc) 9%, transparent), transparent 60%),
    var(--bg-raise);
  text-decoration: none;
  transition: background-color 180ms ease;
}
/* traveling facet glint — quick pass, long pause; staggered per card below */
.channels li a::after {
  content: "";
  position: absolute;
  top: 0; bottom: 0;
  left: -50%; width: 200%;
  pointer-events: none;
  background: linear-gradient(115deg,
    transparent 45%,
    color-mix(in srgb, var(--acc) 11%, transparent) 50%,
    transparent 55%);
  animation: cardglint 12s ease-in-out infinite backwards;
}
@keyframes cardglint {
  0%   { transform: translateX(-58%); }
  16%  { transform: translateX(58%); }
  100% { transform: translateX(58%); }
}
.channels li:nth-child(1) a::after { animation-delay: 0.8s; animation-duration: 13s; }
.channels li:nth-child(2) a::after { animation-delay: 3.4s; animation-duration: 11s; }
.channels li:nth-child(3) a::after { animation-delay: 6.1s; animation-duration: 14s; }
.channels li:nth-child(4) a::after { animation-delay: 8.7s; animation-duration: 12s; }
.channels li:nth-child(5) a::after { animation-delay: 10.9s; animation-duration: 15s; }
.channels li:hover a { background-color: #16161f; }
/* 3D table-cut overlay: a smaller "table" face floating inside the plate,
   its own gold edge ring, and four 45-degree bevel lines connecting the two
   faces' cut corners — a gemstone seen from directly above. One span per
   card; the corner lines are painted as four small gradient patches. */
.g3d {
  --ti: 14px;   /* table inset from the outer face */
  --tc: 12px;   /* table corner cut */
  --oc: 17px;   /* the face's own corner cut (outer card cut minus rim) */
  /* horizontal/vertical reach of each connector line */
  --s: calc(var(--ti) + var(--tc) - var(--oc));
  /* opaque (mixed with the dark base, not transparent) so crossings with the
     table ring repaint rather than alpha-stack into bright spots. One color
     per corner, tracking the ring's 160deg gradient: bright at top-left,
     dimmest past the middle, lifting again toward bottom-right. */
  --lc-tl: color-mix(in srgb, var(--acc, #d4a857) 46%, #101016);
  --lc-tr: color-mix(in srgb, var(--acc, #d4a857) 27%, #101016);
  --lc-br: color-mix(in srgb, var(--acc, #d4a857) 33%, #101016);
  --lc-bl: color-mix(in srgb, var(--acc, #d4a857) 23%, #101016);
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  /* Two connector lines per corner: each vertex of the outer cut joins its
     matching vertex on the table cut. Corner-keyword gradients paint their
     patch's exact diagonal at any aspect ratio, so each line gets a patch
     sized to its bounding box: a steep one (--s wide, --ti tall) beside the
     corner cut and a shallow one (--ti wide, --s tall) below/above it.
     TL and BR corners carry TL-BR diagonals (to top right); TR and BL carry
     TR-BL diagonals (to bottom right). */
  background-image:
    linear-gradient(to top right,    transparent calc(50% - 0.75px), var(--lc-tl) calc(50% - 0.75px), var(--lc-tl) calc(50% + 0.75px), transparent calc(50% + 0.75px)),
    linear-gradient(to top right,    transparent calc(50% - 0.75px), var(--lc-tl) calc(50% - 0.75px), var(--lc-tl) calc(50% + 0.75px), transparent calc(50% + 0.75px)),
    linear-gradient(to bottom right, transparent calc(50% - 0.75px), var(--lc-tr) calc(50% - 0.75px), var(--lc-tr) calc(50% + 0.75px), transparent calc(50% + 0.75px)),
    linear-gradient(to bottom right, transparent calc(50% - 0.75px), var(--lc-tr) calc(50% - 0.75px), var(--lc-tr) calc(50% + 0.75px), transparent calc(50% + 0.75px)),
    linear-gradient(to top right,    transparent calc(50% - 0.75px), var(--lc-br) calc(50% - 0.75px), var(--lc-br) calc(50% + 0.75px), transparent calc(50% + 0.75px)),
    linear-gradient(to top right,    transparent calc(50% - 0.75px), var(--lc-br) calc(50% - 0.75px), var(--lc-br) calc(50% + 0.75px), transparent calc(50% + 0.75px)),
    linear-gradient(to bottom right, transparent calc(50% - 0.75px), var(--lc-bl) calc(50% - 0.75px), var(--lc-bl) calc(50% + 0.75px), transparent calc(50% + 0.75px)),
    linear-gradient(to bottom right, transparent calc(50% - 0.75px), var(--lc-bl) calc(50% - 0.75px), var(--lc-bl) calc(50% + 0.75px), transparent calc(50% + 0.75px));
  /* patches overshoot both endpoints by ~2px so the strokes bury their tips
     in the outer rim and table ring instead of tapering short; the card's
     clip-path and the rings swallow the excess */
  --sw: calc(var(--s) + 2px);
  --tw: calc(var(--ti) + 4px);
  --op: calc(var(--oc) - 1px);
  background-size:
    var(--sw) var(--tw),
    var(--tw) var(--sw),
    var(--sw) var(--tw),
    var(--tw) var(--sw),
    var(--sw) var(--tw),
    var(--tw) var(--sw),
    var(--sw) var(--tw),
    var(--tw) var(--sw);
  background-repeat: no-repeat;
  background-position:
    top -2px left var(--op),
    top var(--op) left -2px,
    top -2px right var(--op),
    top var(--op) right -2px,
    bottom -2px right var(--op),
    bottom var(--op) right -2px,
    bottom -2px left var(--op),
    bottom var(--op) left -2px;
}
.g3d::before {
  content: "";
  position: absolute;
  inset: var(--ti);
  clip-path: polygon(var(--tc) 0, calc(100% - var(--tc)) 0, 100% var(--tc), 100% calc(100% - var(--tc)),
                     calc(100% - var(--tc)) 100%, var(--tc) 100%, 0 calc(100% - var(--tc)), 0 var(--tc));
  background: linear-gradient(160deg,
    color-mix(in srgb, var(--acc, #d4a857) 50%, #101016),
    color-mix(in srgb, var(--acc, #d4a857) 16%, #101016) 55%,
    color-mix(in srgb, var(--acc, #d4a857) 34%, #101016));
}
.g3d::after {
  content: "";
  position: absolute;
  inset: calc(var(--ti) + 1.5px);
  clip-path: polygon(calc(var(--tc) - 1px) 0, calc(100% - var(--tc) + 1px) 0, 100% calc(var(--tc) - 1px), 100% calc(100% - var(--tc) + 1px),
                     calc(100% - var(--tc) + 1px) 100%, calc(var(--tc) - 1px) 100%, 0 calc(100% - var(--tc) + 1px), 0 calc(var(--tc) - 1px));
  background:
    radial-gradient(120% 110% at 30% 0%, color-mix(in srgb, var(--acc, #d4a857) 13%, transparent), transparent 60%),
    #16161f;
}

.channels .handle {
  color: var(--acc);
  font-weight: 600;
  font-size: 15.5px;
  display: flex;
  align-items: center;
  justify-content: center;
  position: relative;
  z-index: 1;
}
.channels .what {
  color: var(--muted);
  font-size: 14px;
  display: block;
  margin-top: 4px;
  position: relative;
  z-index: 1;
}

/* HQ: the flagship plate, centered above the spokes. */
.channels li.hub {
  grid-column: 1 / -1;
  justify-self: center;
  width: min(100%, 440px);
}
.channels li.hub a { text-align: center; padding: 28px 30px 24px; }
.channels li.hub .mark { width: 44px; height: 44px; display: block; margin: 0 auto 10px; position: relative; z-index: 1; }
.channels li.hub .g3d { --ti: 16px; --tc: 14px; --oc: 17px; }
.channels li.hub .handle { justify-content: center; font-size: 17px; }
.channels li.hub .what { margin-top: 5px; }

@media (max-width: 560px) {
  .channels { grid-template-columns: 1fr; }
}

/* ---------- gems teaser (home) ---------- */

.gem-teaser {
  position: relative;
  z-index: 0;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 18px;
  margin-top: 22px;
  padding: 21px 26px;
  clip-path: polygon(16px 0, calc(100% - 16px) 0, 100% 16px, 100% calc(100% - 16px),
                     calc(100% - 16px) 100%, 16px 100%, 0 calc(100% - 16px), 0 16px);
  background: linear-gradient(160deg,
    color-mix(in srgb, #d4a857 35%, #101016),
    color-mix(in srgb, #d4a857 12%, #101016) 55%,
    color-mix(in srgb, #d4a857 28%, #101016));
  text-decoration: none;
  transition: transform 180ms ease;
}
.gem-teaser:hover { transform: translateY(-2px); }
.gem-teaser::before {
  content: "";
  position: absolute;
  inset: 1.5px;
  z-index: -1;
  clip-path: polygon(15px 0, calc(100% - 15px) 0, 100% 15px, 100% calc(100% - 15px),
                     calc(100% - 15px) 100%, 15px 100%, 0 calc(100% - 15px), 0 15px);
  background:
    radial-gradient(90% 70% at 18% 0%, rgba(212, 168, 87, 0.09), transparent 60%),
    var(--bg-raise);
}
/* Hover feedback lives entirely on this separate glow layer — a plain
   opacity fade of a soft gradient, nothing near white to clip and nothing
   that touches the rim or the g3d connector lines. filter:brightness()
   multiplies every pixel including the already-bright rim gradient, which
   can clip a bright stretch to flat white — reads as an abnormally bright,
   hard-edged (non-smooth) line rather than an even lift. */
.gem-teaser::after {
  content: "";
  position: absolute;
  inset: 1.5px;
  z-index: -1;
  clip-path: polygon(15px 0, calc(100% - 15px) 0, 100% 15px, 100% calc(100% - 15px),
                     calc(100% - 15px) 100%, 15px 100%, 0 calc(100% - 15px), 0 15px);
  background:
    radial-gradient(90% 70% at 18% 0%, rgba(212, 168, 87, 0.16), transparent 60%),
    radial-gradient(75% 65% at 80% 100%, rgba(212, 168, 87, 0.12), transparent 60%);
  opacity: 0;
  transition: opacity 200ms ease;
  pointer-events: none;
}
.gem-teaser:hover::after { opacity: 1; }
/* One-shot facet glint on hover-in, echoing .channels' ambient sweep but
   triggered rather than continuous — a real child span, since ::before and
   ::after above are both already spoken for. */
.gem-teaser .glint {
  position: absolute;
  inset: 1.5px;
  z-index: -1;
  overflow: hidden;
  pointer-events: none;
  clip-path: polygon(15px 0, calc(100% - 15px) 0, 100% 15px, 100% calc(100% - 15px),
                     calc(100% - 15px) 100%, 15px 100%, 0 calc(100% - 15px), 0 15px);
}
.gem-teaser .glint::after {
  content: "";
  position: absolute;
  top: 0; bottom: 0;
  left: -20%;
  width: 45%;
  background: linear-gradient(115deg,
    transparent 30%,
    rgba(212, 168, 87, 0.22) 50%,
    transparent 70%);
  transform: translateX(-120%);
}
.gem-teaser:hover .glint::after { animation: teaserglint 700ms ease-out; }
@keyframes teaserglint {
  from { transform: translateX(-120%); }
  to   { transform: translateX(320%); }
}
.gem-teaser:active { transform: translateY(1px) scale(0.995); transition-duration: 70ms; }
.gem-teaser { justify-content: center; text-align: center; }
.gem-teaser > span:not(.g3d) { position: relative; z-index: 1; }
.gem-teaser .g3d { --ti: 12px; --tc: 10px; --oc: 15px; }
.gem-teaser > span:first-child { display: block; }
.gem-teaser .t { display: block; color: var(--text); font-weight: 600; }
.gem-teaser .d { display: block; color: var(--muted); font-size: 14.5px; margin-top: 2px; }

/* ---------- gem card (gems page) ---------- */

/* Each gem carries a single gemstone identity (--gem), the way the home
   channel cards each take one --acc. The page's mesh already shows the whole
   palette; a card committing to one gem reads cleaner than a rainbow, and the
   catalog goes multicolor as more gems (each its own stone) launch. --gem-2 is
   a second stone that shimmers through the rim so the plate still ties to the
   full palette. GEM 001 = emerald. */
.gem-card {
  --gem: var(--emerald);
  --gem-bright: #6ee79b;
  --gem-2: var(--sapphire);
  position: relative;
  z-index: 0;
  clip-path: polygon(22px 0, calc(100% - 22px) 0, 100% 22px, 100% calc(100% - 22px),
                     calc(100% - 22px) 100%, 22px 100%, 0 calc(100% - 22px), 0 22px);
  background: linear-gradient(160deg,
    color-mix(in srgb, var(--gem) 55%, #101016),
    color-mix(in srgb, var(--gem-2) 16%, #101016) 55%,
    color-mix(in srgb, var(--gem) 38%, #101016));
  padding: 30px 32px;
  max-width: 42em;
}
.gem-card::before {
  content: "";
  position: absolute;
  inset: 1.5px;
  z-index: -1;
  clip-path: polygon(21px 0, calc(100% - 21px) 0, 100% 21px, 100% calc(100% - 21px),
                     calc(100% - 21px) 100%, 21px 100%, 0 calc(100% - 21px), 0 21px);
  background:
    radial-gradient(90% 70% at 18% 0%, color-mix(in srgb, var(--gem) 12%, transparent), transparent 60%),
    var(--bg-raise);
}
.gem-card { text-align: center; }
.gem-card .g3d { --ti: 17px; --tc: 15px; --oc: 21px; --acc: var(--gem); }
.gem-card .badge, .gem-card h3, .gem-card p, .gem-card .gem-actions {
  position: relative;
  z-index: 1;
}
.gem-card p { margin-left: auto; margin-right: auto; }
.gem-card .gem-actions { justify-content: center; }
.gem-card .gem-no {
  position: absolute;
  z-index: 1;
  top: 26px; right: 32px;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.2em;
  color: color-mix(in srgb, var(--gem) 62%, transparent);
}
/* Narrow screens: the corner label collides with the centered badge, so it
   stacks above it instead. Stays position:relative (not static) — the base
   rule's z-index only lifts it above the opaque g3d face while positioned. */
@media (max-width: 480px) {
  .gem-card .gem-no { position: relative; top: 0; right: 0; display: block; margin-bottom: 8px; }
}
.gem-card h3 { font-size: 22px; font-weight: 700; letter-spacing: -0.01em; }
.gem-card .badge {
  display: inline-block;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.08em;
  color: var(--gem);
  border: 1px solid color-mix(in srgb, var(--gem) 40%, transparent);
  border-radius: 999px;
  padding: 3px 12px;
  margin-bottom: 14px;
}
.gem-card p { color: var(--muted); margin-top: 10px; max-width: 34em; }
.gem-card p strong { color: var(--text); font-weight: 600; }

.gem-actions { margin-top: 24px; display: flex; gap: 14px; flex-wrap: wrap; }
/* Plain CSS `border` doesn't follow a clip-path bevel — the corner miters
   get clipped away with nothing drawn along the diagonal cut, leaving gaps
   in the outline. Same two-layer rim technique as .gem-card/.gem-teaser
   instead: the element itself is the border color, ::before is the inset
   face, each with its own (1px-smaller) clip-path. */
.btn {
  position: relative;
  z-index: 0;
  display: inline-block;
  text-decoration: none;
  font-weight: 600;
  font-size: 15px;
  clip-path: polygon(8px 0, calc(100% - 8px) 0, 100% 8px, 100% calc(100% - 8px),
                     calc(100% - 8px) 100%, 8px 100%, 0 calc(100% - 8px), 0 8px);
  padding: 11px 20px;
  transition: transform 160ms ease, background 160ms ease, box-shadow 160ms ease;
}
.btn::before {
  content: "";
  position: absolute;
  inset: 1.5px;
  z-index: -1;
  clip-path: polygon(7px 0, calc(100% - 7px) 0, 100% 7px, 100% calc(100% - 7px),
                     calc(100% - 7px) 100%, 7px 100%, 0 calc(100% - 7px), 0 7px);
  transition: background 160ms ease;
}
.btn:hover { transform: translateY(-1px); }
.btn:active { transform: translateY(1px) scale(0.97); transition-duration: 70ms; }
.btn.solid {
  background: var(--gold-bright);
  color: #14100a;
  /* clip-path clips box-shadow along with the box; drop-shadow is a filter,
     so it renders from the already-clipped shape instead of disappearing. */
  filter: drop-shadow(0 8px 12px rgba(212, 168, 87, 0.35));
}
.btn.solid::before { background: var(--gold); }
.btn.solid:hover::before { background: var(--gold-bright); }
.btn.ghost { color: var(--gold); background: var(--gold-dim); }
.btn.ghost::before { background: var(--bg-raise); }
.btn.ghost:hover { background: var(--gold); }

/* Gem-card buttons take the card's gemstone identity instead of gold. Scoped
   to .gem-card so the base gold .btn stays available elsewhere; both inherit
   --gem / --gem-bright from the card. */
.gem-card .btn.solid {
  background: var(--gem-bright);
  color: #06140d;
  filter: drop-shadow(0 8px 12px color-mix(in srgb, var(--gem) 32%, transparent));
}
.gem-card .btn.solid::before { background: var(--gem); }
.gem-card .btn.solid:hover::before { background: var(--gem-bright); }
.gem-card .btn.ghost { color: var(--gem); background: color-mix(in srgb, var(--gem) 40%, transparent); }
.gem-card .btn.ghost::before { background: var(--bg-raise); }
.gem-card .btn.ghost:hover { background: var(--gem); }

.aside-note { margin-top: 30px; color: color-mix(in srgb, var(--muted) 74%, var(--text)); font-size: 15px; max-width: 36em; }

/* ---------- footer ---------- */

footer.site {
  border-top: 1px solid var(--line);
  margin-top: 48px;
  padding: 26px 0 34px;
  position: relative;
  z-index: 1;
}
footer.site .wrap {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
  color: var(--muted);
  font-size: 14px;
}
footer.site .fbrand { display: flex; align-items: center; gap: 10px; }
footer.site .fbrand img { width: 18px; height: 18px; opacity: 0.7; }
footer.site a { color: var(--muted); text-decoration: none; transition: color 160ms ease; }
footer.site a:hover { color: var(--gold); }

/* ---------- entrance ---------- */

.fade-in { animation: rise 640ms cubic-bezier(0.33, 1, 0.68, 1) both; }
.fade-in.d1 { animation-delay: 90ms; }
.fade-in.d2 { animation-delay: 180ms; }
@keyframes rise {
  from { opacity: 0; transform: translateY(14px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* Back/forward navigation restores a page from the bfcache in its finished
   state, so the one-shot entrance animations never re-run on a return trip.
   Each page's pageshow handler toggles this class when restored: it yanks the
   entrance animations off, forces a reflow, then removes the class — which
   restarts them from frame zero. Scoped to the ONE-SHOT entrances only; the
   infinite ambient loops (drift, glints, hero gem) are left alone so they
   don't visibly jump back to their first frame. */
body.anim-reset .fade-in,
body.anim-reset .hero h1 .gem-text,
body.anim-reset .gems-ambient::before,
body.anim-reset .ambient::after {
  animation: none !important;
}

/* Cross-document view transition: same-origin navigations crossfade the two
   pages, so on back/forward the gemstone mesh dissolves directly into the
   gold one (and vice versa) rather than dropping out and re-entering. On
   those arrivals the inline pagereveal handler adds .vt-hold to pin the
   entrance animations at their final state — the crossfade is the motion.
   Forward link clicks keep the entrance bloom, just under the crossfade.
   Browsers without view transitions ignore all of this. */
@view-transition { navigation: auto; }
::view-transition-old(root),
::view-transition-new(root) { animation-duration: 700ms; }
html.vt-hold .fade-in,
html.vt-hold .hero h1 .gem-text,
html.vt-hold .gems-ambient::before,
html.vt-hold .ambient::after {
  animation: none !important;
}

@media (prefers-reduced-motion: reduce) {
  .fade-in { animation: none; }
  .ambient .glow, .ambient .sheen, .ambient::after, .hero-gem g, .channels li a::after, .gem-teaser:hover .glint::after { animation: none; }
  .gems-ambient::before { opacity: 1; animation: none; }
  .gems-ambient::after { opacity: 1; animation: none; }
  .hero h1 .gem-text { animation: none; background-position: 0% 0; }
  .btn:hover, .channels li:hover, .gem-teaser:hover,
  .btn:active, .channels li:active, .gem-teaser:active { transform: none; }
  .gem-teaser::after { transition: none; }
  ::view-transition-old(root), ::view-transition-new(root) { animation: none; }
}
