/* ─────────────────────────────────────────────────────────────────────────
   Avatar frames — unlockable animated rings around profile pictures
   (docs/AVATAR_FRAMES.md).

   One class per frame id (`af-<id>`), applied to the `.af-frame` wrapper
   that avatar-frames.js puts around an <img>. Frames are deliberately
   COLOURFUL cosmetics (the owner's call, 2026-09-14): theme-check exempts
   hued colours by design, and neutral-token rings were invisible on the
   monochrome skin. Each frame defines its palette in --af-c1..c3/--af-glow;
   the shared ring rules reference those so a frame is one small block.

   Ring thickness/masks are percentage-based so the same frame scales from
   the 40px navbar avatar to the profile header.
   ───────────────────────────────────────────────────────────────────────── */

.af-frame {
  position: relative;
  display: inline-grid;
  place-items: center;
  box-sizing: border-box;
  /* The ring is a CIRCLE whatever the host did to the picture it wraps.
     Without this, a surface that gives its avatar a margin (the dashboard
     welcome avatar's `margin-bottom`) or a percentage size that cannot
     resolve against a shrink-to-fit wrapper (the sidebar's
     `.avatar-container img { width/height: 100% }`) made the wrapper taller
     than it is wide — and every ring, glow and artwork then drew as an
     off-centre ellipse (owner report 2026-09-14). */
  aspect-ratio: 1 / 1;
  border-radius: 50%;
  /* breathing room so the ring is never clipped by an overflow-hidden parent */
  padding: max(4px, 8%);
  --af-c1: #7c8db5;
  --af-c2: #c9d6ea;
  --af-c3: #ffffff;
  --af-glow: rgba(124, 141, 181, .55);
}

.af-frame > img,
.af-frame > .af-sample {
  position: relative;
  z-index: 1;
  border-radius: 50%;
  /* Spacing belongs to the WRAPPER, never to the picture inside it: a margin
     here sits inside the grid cell and pushes the avatar off the ring's
     centre. avatar-frames.js moves the <img>'s own margin onto the wrapper
     when it wraps, so the surface keeps its spacing and the ring stays
     concentric. */
  margin: 0;
}

/* The wrapped <img> keeps WHATEVER size its surface gave it (the navbar's
   40px, .ig-avatar's own size…). Setting width/height here broke that
   contract and produced the shrunken, off-centre navbar avatar. */

/* ── ART frames ────────────────────────────────────────────────────────
   Full-artwork rings (dragons, lightning, fire) generated through the
   external image API (scripts/gen-frame-art.js). The artwork is a square
   with a solid black centre; the mask is an ANNULUS — it cuts BOTH the
   centre hole the avatar sits in AND the square's outer edges/corners, so
   only a circular band of artwork shows. Without the outer stops the raw
   square slab is visible around the avatar (owner bug report 2026-09-14).
   .af-has-art hides the CSS conic ring so only the artwork + glow remain. */
.af-frame .af-art {
  position: absolute;
  inset: -16%;
  width: 132%;
  height: 132%;
  object-fit: cover;
  border-radius: 0;
  pointer-events: none;
  z-index: 2;
  -webkit-mask: radial-gradient(closest-side, transparent 56%, #000 61%, #000 82%, transparent 87%);
          mask: radial-gradient(closest-side, transparent 56%, #000 61%, #000 82%, transparent 87%);
  animation: af-rotate 40s linear infinite;
}
.af-frame.af-has-art { padding: max(2px, 3.5%); }
.af-frame.af-has-art::before { display: none; }
.af-frame.af-has-art .af-orbit { display: none; }

/* soft coloured halo behind the avatar — makes even the calmest frames read */
.af-frame::after,
.af-frame::before,
.af-frame .af-orbit {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: 50%;
  pointer-events: none;
}

/* ── Shared keyframes ────────────────────────────────────────────────── */
@keyframes af-rotate      { to { transform: rotate(360deg); } }
@keyframes af-rotate-rev  { to { transform: rotate(-360deg); } }
@keyframes af-pulse-soft  { 0%, 100% { opacity: .55; } 50% { opacity: 1; } }
@keyframes af-glow-pulse  {
  0%, 100% { box-shadow: 0 0 6px 1px var(--af-glow); }
  50%      { box-shadow: 0 0 18px 5px var(--af-glow); }
}
@keyframes af-beacon      { 0%, 100% { opacity: .3; } 8% { opacity: 1; } 16% { opacity: .4; } 24% { opacity: 1; } }
@keyframes af-spin-glow   {
  0%, 100% { filter: drop-shadow(0 0 3px var(--af-glow)); }
  50%      { filter: drop-shadow(0 0 10px var(--af-glow)); }
}

/* Conic backgrounds paint a RING, not a disc — every frame whose ::before
   carries a (repeating-)conic-gradient must also carry this mask. */
.af-bronze_pulse::before, .af-silver_orbit::before, .af-gold_flare::before,
.af-prism_nova::before, .af-infinity_core::before, .af-module::before {
  -webkit-mask: radial-gradient(farthest-side, transparent calc(100% - max(4px, 12%)), #000 calc(100% - max(3px, 11%)));
          mask: radial-gradient(farthest-side, transparent calc(100% - max(4px, 12%)), #000 calc(100% - max(3px, 11%)));
}

/* ── Badge-count ladder ─────────────────────────────────────────────── */

/* 1 badge — warm ember: a glowing amber ring that breathes */
.af-ember { --af-c1: #ff6a3d; --af-c2: #ffb56b; --af-glow: rgba(255, 122, 61, .6); }
.af-ember::before {
  border: 2px solid var(--af-c1);
  animation: af-pulse-soft 2.6s ease-in-out infinite;
}
.af-ember::after {
  inset: -3%;
  border: 2px solid var(--af-c2);
  animation: af-glow-pulse 2.6s ease-in-out infinite;
  border-style: solid;
  box-shadow: 0 0 12px 2px var(--af-glow);
}

/* 5 badges — molten copper rotating ring */
.af-bronze_pulse { --af-c1: #8c4a1f; --af-c2: #e0a96d; --af-c3: #ffc98f; --af-glow: rgba(196, 116, 53, .6); }
.af-bronze_pulse::before {
  background: conic-gradient(from 0deg, var(--af-c1), var(--af-c2), var(--af-c3), var(--af-c2), var(--af-c1));
  animation: af-rotate 6s linear infinite;
}
.af-bronze_pulse::after {
  inset: -4%;
  border: 2px solid transparent;
  background: radial-gradient(closest-side, transparent 78%, var(--af-glow) 92%, transparent 100%);
  animation: af-pulse-soft 3s ease-in-out infinite;
}

/* 12 badges — ice silver: fast two-tone ring + white satellite */
.af-silver_orbit { --af-c1: #9fb8d8; --af-c2: #eef4fc; --af-c3: #6d87ad; --af-glow: rgba(159, 197, 236, .75); }
.af-silver_orbit::before {
  background: conic-gradient(from 90deg, var(--af-c1), var(--af-c2), var(--af-c3), var(--af-c2), var(--af-c1));
  animation: af-rotate 2.4s linear infinite, af-spin-glow 2.4s linear infinite;
}
.af-silver_orbit .af-orbit {
  inset: -10%;
  animation: af-rotate 4s linear infinite;
}
.af-silver_orbit .af-orbit::before {
  content: '';
  position: absolute;
  top: 0;
  left: calc(50% - 5%);
  width: 10%;
  aspect-ratio: 1;
  border-radius: 50%;
  background: radial-gradient(circle at 35% 35%, #ffffff, var(--af-c1));
  box-shadow: 0 0 8px 2px var(--af-glow);
}

/* 25 badges — radiant gold: twin rings, comet sparks */
.af-gold_flare { --af-c1: #ffd76e; --af-c2: #f5a623; --af-c3: #b8860b; --af-glow: rgba(255, 193, 69, .8); }
.af-gold_flare::before {
  background: conic-gradient(from 0deg, var(--af-c1), var(--af-c2), var(--af-c3), var(--af-c2), var(--af-c1));
  animation: af-rotate 3s linear infinite, af-spin-glow 3s linear infinite;
}
.af-gold_flare::after {
  inset: -7%;
  border: 2px dashed var(--af-c2);
  animation: af-rotate-rev 8s linear infinite;
  opacity: .9;
}
.af-gold_flare .af-orbit {
  inset: -13%;
  animation: af-rotate-rev 5s linear infinite;
}
.af-gold_flare .af-orbit::before {
  content: '';
  position: absolute;
  top: 0;
  left: calc(50% - 4.5%);
  width: 9%;
  aspect-ratio: 1;
  border-radius: 50%;
  background: radial-gradient(circle at 35% 35%, #fffbe8, var(--af-c2));
  box-shadow: 0 0 10px 3px var(--af-glow);
}

/* 40 badges — prism nova: full rainbow conic + dashed halo + spark */
.af-prism_nova { --af-c1: #ff5f6d; --af-c2: #ffc371; --af-c3: #38f9d7; --af-glow: rgba(150, 120, 255, .8); }
.af-prism_nova::before {
  background: conic-gradient(from 45deg,
    var(--af-c1), var(--af-c2), #a6ff8d, var(--af-c3), #61c2ff, #b06ffb, var(--af-c1));
  animation: af-rotate 2.2s linear infinite, af-spin-glow 2.2s linear infinite;
}
.af-prism_nova::after {
  inset: -9%;
  border: 2px dotted #b06ffb;
  animation: af-rotate-rev 6s linear infinite;
  opacity: .85;
}
.af-prism_nova .af-orbit {
  inset: -14%;
  animation: af-rotate 5s linear infinite;
}
.af-prism_nova .af-orbit::before {
  content: '';
  position: absolute;
  top: 0;
  left: calc(50% - 4%);
  width: 8%;
  aspect-ratio: 1;
  border-radius: 50%;
  background: radial-gradient(circle at 35% 35%, #ffffff, var(--af-c3));
  box-shadow: 0 0 10px 3px var(--af-glow);
}

/* 60 badges — infinity core: violet↔cyan plasma, everything at once */
.af-infinity_core { --af-c1: #8b5cf6; --af-c2: #22d3ee; --af-c3: #f0abfc; --af-glow: rgba(139, 92, 246, .85); }
.af-infinity_core::before {
  background: conic-gradient(from 0deg, var(--af-c1), var(--af-c2), var(--af-c3), var(--af-c2), var(--af-c1));
  animation: af-rotate 1.8s linear infinite, af-spin-glow 1.8s linear infinite;
}
.af-infinity_core::after {
  inset: -8%;
  border: 2px dashed var(--af-c2);
  animation: af-rotate-rev 4s linear infinite;
  opacity: .9;
}
.af-infinity_core .af-orbit {
  inset: -15%;
  animation: af-rotate-rev 7s linear infinite;
}
.af-infinity_core .af-orbit::before {
  content: '';
  position: absolute;
  top: 0;
  left: calc(50% - 5%);
  width: 10%;
  aspect-ratio: 1;
  border-radius: 50%;
  background: radial-gradient(circle at 35% 35%, #ffffff, var(--af-c1));
  box-shadow: 0 0 14px 4px var(--af-glow), 0 0 4px 1px rgba(34, 211, 238, .9);
}

/* ── Module frames — one per completed masterclass module ──────────── */
/* Shared segmented rotating ring; each module sets its palette + rhythm. */
.af-module::before {
  background: repeating-conic-gradient(var(--af-c1) 0deg var(--af-seg, 14deg),
               transparent var(--af-seg, 14deg) calc(var(--af-seg, 14deg) + var(--af-gap, 10deg)));
  animation: af-rotate var(--af-speed, 12s) linear infinite;
  filter: drop-shadow(0 0 4px var(--af-glow));
}
.af-module::after {
  inset: -4%;
  border: 3px solid var(--af-c2);
  opacity: .8;
}

/* Module 1 — chat: rose muse, slow and elegant */
.af-muse_ring { --af-c1: #f472b6; --af-c2: #fbcfe8; --af-glow: rgba(244, 114, 182, .7);
  --af-seg: 40deg; --af-gap: 20deg; --af-speed: 16s; }

/* Module 2 — image: amber shutter blades, crisp and quick */
.af-shutter_halo { --af-c1: #f59e0b; --af-c2: #fde68a; --af-glow: rgba(245, 158, 11, .7);
  --af-seg: 22deg; --af-gap: 23deg; --af-speed: 9s; }
.af-shutter_halo .af-orbit { inset: -8%; animation: af-rotate-rev 6s linear infinite; }
.af-shutter_halo .af-orbit::before {
  content: '';
  position: absolute;
  top: -2%;
  left: calc(50% - 4%);
  width: 8%;
  aspect-ratio: 1;
  border-radius: 50%;
  background: radial-gradient(circle at 35% 35%, #fffbeb, var(--af-c1));
  box-shadow: 0 0 8px 2px var(--af-glow);
}

/* Module 3 — video: cyan streak, fast + glowing aura */
.af-motion_aura { --af-c1: #22d3ee; --af-c2: #a5f3fc; --af-glow: rgba(34, 211, 238, .8);
  --af-seg: 55deg; --af-gap: 5deg; --af-speed: 4s; }
.af-motion_aura::after { animation: af-glow-pulse 1.6s ease-in-out infinite; }

/* Module 4 — social: blue beacon blink (thin halo only — a fat border
   would swallow the face at the 40px navbar size) */
.af-beacon_ring { --af-c1: #3b82f6; --af-c2: #93c5fd; --af-glow: rgba(59, 130, 246, .8);
  --af-seg: 8deg; --af-gap: 12deg; --af-speed: 20s; }
.af-beacon_ring::after {
  inset: -4%;
  border: 2px solid var(--af-c2);
  animation: af-beacon 3s ease-in-out infinite;
}

/* Module 5 — tools: emerald circuit dashes + travelling node */
.af-circuit_crown { --af-c1: #10b981; --af-c2: #6ee7b7; --af-glow: rgba(16, 185, 129, .75);
  --af-seg: 6deg; --af-gap: 6deg; --af-speed: 14s; }
.af-circuit_crown .af-orbit { inset: -7%; animation: af-rotate 3.5s linear infinite; }
.af-circuit_crown .af-orbit::before {
  content: '';
  position: absolute;
  top: 0;
  left: calc(50% - 4.5%);
  width: 9%;
  aspect-ratio: 1;
  border-radius: 50%;
  background: radial-gradient(circle at 35% 35%, #ecfdf5, var(--af-c1));
  box-shadow: 0 0 9px 3px var(--af-glow);
}

/* Module 6 — business: stately gold double signet */
.af-signet { --af-c1: #d4af37; --af-c2: #f1d97e; --af-glow: rgba(212, 175, 55, .75);
  --af-seg: 90deg; --af-gap: 30deg; --af-speed: 22s; }
.af-signet::after { border-style: double; border-width: 4px; }

/* Module 7 — monetize: money-green vault segments + glow */
.af-vault_ring { --af-c1: #22c55e; --af-c2: #86efac; --af-glow: rgba(34, 197, 94, .8);
  --af-seg: 30deg; --af-gap: 6deg; --af-speed: 10s; }
.af-vault_ring::after { animation: af-glow-pulse 2.8s ease-in-out infinite; }

/* Module 8 — exploration: teal compass glow, wide calm ring */
.af-compass_glow { --af-c1: #14b8a6; --af-c2: #99f6e4; --af-glow: rgba(20, 184, 166, .75);
  --af-seg: 70deg; --af-gap: 110deg; --af-speed: 18s; }
.af-compass_glow .af-orbit { inset: -10%; animation: af-rotate-rev 8s linear infinite; }
.af-compass_glow .af-orbit::before {
  content: '';
  position: absolute;
  top: 0;
  left: calc(50% - 3%);
  width: 6%;
  aspect-ratio: 1;
  border-radius: 50%;
  background: radial-gradient(circle at 35% 35%, #f0fdfa, var(--af-c1));
  box-shadow: 0 0 7px 2px var(--af-glow);
}

/* ── Picker / shelf UI ──────────────────────────────────────────────── */

.af-picker {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
  gap: 14px;
}
.af-card {
  position: relative;
  background: var(--surface-raised);
  border: 1px solid var(--line);
  border-radius: 16px;
  padding: 16px 10px 12px;
  text-align: center;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  cursor: pointer;
  transition: border-color .15s ease, transform .15s ease, box-shadow .15s ease;
}
.af-card:hover { border-color: var(--line-strong); transform: translateY(-2px); }
.af-card.af-selected {
  border-color: var(--brand-fill);
  box-shadow: 0 0 0 2px var(--brand-fill-soft), 0 6px 18px var(--shadow-md);
}
.af-card.af-locked { cursor: default; }

/* Locked frames stay FULL COLOUR — the whole point of a locked card is
   showing the member what pursuing the module buys them. A lock badge and
   slight dim only. */
.af-card.af-locked .af-preview-wrap { opacity: .8; }
.af-lock-badge {
  position: absolute;
  top: 8px; right: 8px;
  width: 22px; height: 22px;
  border-radius: 50%;
  display: grid; place-items: center;
  background: var(--scrim-strong);
  color: var(--ink-inverse);
  font-size: 11px;
  z-index: 2;
}

.af-preview-wrap {
  width: 96px;
  height: 96px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  position: relative;
}
.af-preview-wrap img:not(.af-art), .af-preview-wrap .af-sample {
  width: 72px;
  height: 72px;
  border-radius: 50%;
  object-fit: cover;
}

.af-name { font-weight: 600; font-size: .85rem; color: var(--ink); }
.af-cond { font-size: .72rem; color: var(--ink-muted); line-height: 1.3; }
.af-progress {
  width: 100%;
  height: 6px;
  border-radius: 4px;
  background: var(--scrim-soft);
  overflow: hidden;
}
.af-progress-fill { height: 100%; border-radius: 4px; background: var(--brand-gradient); transition: width .4s ease; }
.af-action {
  border: none;
  border-radius: 999px;
  padding: 6px 18px;
  font-size: .75rem;
  font-weight: 600;
  background: var(--brand-fill);
  color: var(--brand-ink);
  cursor: pointer;
}
.af-action:hover { background: var(--brand-fill-hover); }
.af-action.af-equipped { background: var(--scrim-soft); color: var(--ink-soft); cursor: default; }
.af-lock-line { font-size: .7rem; color: var(--ink-muted); display: flex; align-items: center; gap: 4px; justify-content: center; }

/* inline picker error (also the Equip failure feedback path) */
.af-picker-error {
  grid-column: 1 / -1;
  display: none;
  align-items: center;
  gap: 8px;
  font-size: .78rem;
  color: var(--status-danger);
  background: var(--surface-sunken);
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: 8px 12px;
}
.af-picker-error.af-visible { display: flex; }

/* Section shells (badges-page shelf, profile panel) */
.af-section { margin: 18px 0; }
.af-section-title {
  display: flex; align-items: center; gap: 8px;
  font-size: .95rem; font-weight: 700; color: var(--ink);
  margin-bottom: 10px;
}
.af-section-title .bi { color: var(--brand-ink); }

/* "Current look" hero on the /badges shelf — instant visual confirmation
   when a frame is equipped, since the navbar avatar may be hidden here. */
.af-hero {
  display: flex;
  align-items: center;
  gap: 16px;
  background: var(--surface-sunken);
  border: 1px solid var(--line-soft);
  border-radius: 16px;
  padding: 14px 18px;
  margin-bottom: 14px;
}
.af-hero-preview { width: 88px; height: 88px; display: grid; place-items: center; }
.af-hero-preview img:not(.af-art) { width: 64px; height: 64px; border-radius: 50%; object-fit: cover; }
.af-hero-name { font-weight: 700; font-size: .95rem; color: var(--ink); }
.af-hero-sub { font-size: .75rem; color: var(--ink-muted); margin-top: 2px; }

/* Module-card chip on /badges — "finish this module, unlock this frame" */
.af-module-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: .72rem;
  padding: 3px 10px;
  border-radius: 999px;
  background: var(--brand-fill-soft);
  color: var(--brand-ink);
  border: 1px solid var(--line-soft);
}
.af-module-chip .af-chip-dot {
  width: 18px; height: 18px; border-radius: 50%;
  display: inline-block; position: relative;
  background: var(--surface-raised);
}
.af-module-chip.af-done { background: var(--scrim-soft); color: var(--ink-soft); }

/* tiny transient toast (equip feedback where window.showToast is absent) */
.af-mini-toast {
  position: fixed;
  bottom: 24px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 1090;
  background: var(--ink);
  color: var(--ink-inverse);
  border-radius: 999px;
  padding: 9px 18px;
  font-size: .8rem;
  font-weight: 600;
  box-shadow: var(--shadow-lg);
  opacity: 0;
  transition: opacity .25s ease, bottom .25s ease;
}
.af-mini-toast.af-shown { opacity: 1; bottom: 32px; }

/* Motion sensitivity: keep the rings, drop the movement */
@media (prefers-reduced-motion: reduce) {
  .af-frame::before, .af-frame::after, .af-frame .af-orbit { animation: none !important; }
}
