/* Round 6 (2026-10-21): band variety, node field, pixel corners, the pixel portrait loader, pixel glyphs, motion graphics, hero and
   closing-band mascots, stats band. Loaded after v2-pages.css on every page. Spec: DESIGN.md "Round 6". */

/* ---------- band variants: any .sx or .pp can take one; the rotation lives in macros.j2 bc(i) ---------- */
.sx.sx-tint, .pp.sx-tint { background: var(--bg-2); }
.sx.sx-white, .pp.sx-white { background: var(--white); --surface: var(--bg); --stage: linear-gradient(160deg, var(--bg), var(--bg-2)); }   /* cards on a white band take the page colour, so they still read as cards */
.sx.sx-dusk, .pp.sx-dusk { background: var(--dusk); }
.sx.sx-grid, .pp.sx-grid { background-color: var(--bg); background-image: linear-gradient(var(--grid) 1px, transparent 1px), linear-gradient(90deg, var(--grid) 1px, transparent 1px); background-size: 52px 52px; }
.sx.sx-glow, .pp.sx-glow { background: radial-gradient(46% 62% at 10% 18%, color-mix(in srgb, var(--accent) 15%, transparent), transparent 70%), radial-gradient(40% 55% at 94% 86%, color-mix(in srgb, #7A5CFF 11%, transparent), transparent 70%), var(--bg); }
/* the dark app-window band: local tokens flip to the navy set, so every component inside adapts without its own rules */
.sx.sx-navy, .pp.sx-navy {
  --bg: #0A1630; --bg-2: #0D1B38; --surface: #0F1D3A; --tint: #0C1A36; --tint-2: #10224A; --dusk: #0E1636;
  --ink: #E8EEF9; --ink-2: #C3D0E6; --muted: #98A9C6; --line: #1E2F50; --line-2: #2A3F66; --accent-ink: #4FD1FF;
  --acc-grad: linear-gradient(100deg, #00A8F0 0%, #00C8FF 50%, #00E6FF 100%);
  --stage: linear-gradient(160deg, #0F1D3A, #0A1630); --grid: rgba(120, 205, 255, .07); --pxc: #0A1630;
  --win: #0F1C36; --win-ink: #E8EEF9; --win-muted: #98A9C6; --win-line: #1E2F50; --win-2: #13223F;
  --shadow: 0 30px 60px -30px rgba(0, 0, 0, .6), 0 12px 24px -16px rgba(0, 0, 0, .5);
  background: radial-gradient(50% 70% at 88% 12%, rgba(0, 187, 255, .16), transparent 70%), radial-gradient(40% 60% at 6% 92%, rgba(122, 92, 255, .14), transparent 70%), #0A1630;
  color: var(--ink); color-scheme: dark; }
.sx-navy .xcard, .sx-navy .xprice, .sx-navy .xind, .sx-navy .thread { box-shadow: inset 0 0 0 1px var(--line-2); }
.sx-navy .btn-cut { --bg: #0A1630; --ink: #E8EEF9; }
/* pixel edge colours follow the band they open */
.bd-edge { --pxc: var(--bg); }
.sx-tint > .bd-edge, .pp.sx-tint > .bd-edge { --pxc: var(--bg-2); }
.sx-white > .bd-edge { --pxc: var(--white); }
.sx-dusk > .bd-edge { --pxc: var(--dusk); }
.sx-navy > .bd-edge { --pxc: #0A1630; }
.sx > .wrap, .pp > .wrap { position: relative; z-index: 1; }

/* ---------- node field on a band: the homepage constellation (v2-r6.js bandNodes) ---------- */
.sx > canvas.nodes, .pp > canvas.nodes { position: absolute; inset: 0; z-index: 0; width: 100%; height: 100%; pointer-events: none;
  -webkit-mask-image: linear-gradient(180deg, transparent 0, #000 16%, #000 84%, transparent 100%); mask-image: linear-gradient(180deg, transparent 0, #000 16%, #000 84%, transparent 100%); }
.no-js canvas.nodes { display: none; }

/* ---------- pixel corners: three squares stepping down the chamfer of the card family (top-right cut) ---------- */
.xcard::before, .xprice::before, .xind::before, .cs-card::before {
  content: ""; position: absolute; z-index: 2; top: 9px; right: calc(var(--c, 26px) - 4px); width: 6px; height: 6px; background: var(--accent); pointer-events: none;
  box-shadow: calc((var(--c, 26px) - 13px) * .5) calc((var(--c, 26px) - 13px) * .5) 0 -1px color-mix(in srgb, var(--accent) 55%, transparent), calc(var(--c, 26px) - 13px) calc(var(--c, 26px) - 13px) 0 0 var(--accent); }
.xcard:hover::before, .xprice:hover::before, .xind:hover::before, .cs-card:hover::before { animation: pxblip 520ms steps(2, end) 1; }
@keyframes pxblip { 0% { opacity: 1; } 40% { opacity: 0; } 70% { opacity: 1; } 100% { opacity: 1; } }

/* ---------- pixel portrait loader (v2-r6.js pxres): the real photo resolves from big squares ---------- */
[data-pxres] { position: relative; }
[data-pxres] > canvas.pxres { position: absolute; inset: 0; width: 100%; height: 100%; z-index: 3; pointer-events: none; image-rendering: pixelated; }
.js [data-pxres]:not(.pxres-ready):not(.pxres-off) > img { opacity: 0; }
.pxres-off > img, .pxres-ready > img { opacity: 1; }
.no-js [data-pxres] > img { opacity: 1; }

/* ---------- pixel glyphs: squares pop in along the diagonal when the glyph scrolls into view ---------- */
.pxart { display: block; fill: var(--accent); overflow: visible; }
.pxart rect { transform-box: fill-box; transform-origin: center; }
.js .pxart:not(.on) rect { opacity: 0; transform: scale(.4); }
.js .pxart.on rect { animation: glyphPop 160ms cubic-bezier(.175, .885, .32, 1.12) var(--d, 0ms) both; }
@keyframes glyphPop { from { opacity: 0; transform: scale(.4); } to { opacity: 1; transform: scale(1); } }
.faq-q { margin-top: var(--sp-7); width: 70px; height: auto; opacity: .95; fill: var(--accent); }
[data-theme="dark"] .pxart { fill: var(--cyan); }
.pxart.alt rect:nth-child(3n) { fill: color-mix(in srgb, var(--accent) 45%, transparent); }
@media (max-width: 980px) { .faq-q { display: none; } }

/* ---------- motion bits ---------- */
@media (prefers-reduced-motion: no-preference) {
  /* process steps: the dashed line draws, nodes fill as it passes, a packet runs along it */
  .js .xsteps::after { content: ""; position: absolute; left: 7px; top: 3px; height: 10px; width: 10px; background: var(--cyan); opacity: 0; box-shadow: 0 0 14px 2px var(--cyan); }
  .js .xsteps.run::after { animation: stepPacket 1800ms linear 1100ms 1 both, stepPacketLoop 1800ms linear 5800ms infinite both; }
  .js .xsteps::before { transform-origin: 0 50%; transform: scaleX(0); }
  .js .xsteps.run::before { transform: scaleX(1); transition: transform 720ms var(--ease); }
  .js .xsteps.run li::before { transition-delay: calc(var(--i, 0) * 90ms + 240ms); }
  /* fit panel: the check squares pop in turn (secondary action after the panel lands) */
  .js .xfit.in .yes .ck-ico { animation: ckPop 220ms cubic-bezier(.175, .885, .32, 1.275) calc(var(--k, 0) * 60ms + 260ms) both; }
  .js .xfit.in .no .ck-ico { animation: ckShift 240ms var(--ease) calc(var(--k, 0) * 60ms + 320ms) 2 both; }
  .js .xchecks.in .ck-ico { animation: ckPop 220ms cubic-bezier(.175, .885, .32, 1.275) calc(var(--k, 0) * 55ms + 200ms) both; }
  /* row numerals fill while the row is on screen */
  .js .xrow .n { transition: color 160ms var(--ease), -webkit-text-stroke-color 160ms var(--ease); }
  .js .xrow.in.mid .n { color: var(--accent); -webkit-text-stroke-color: var(--accent); }
  /* review stars fill in turn */
  .js .rv.in .stars svg { animation: starIn 180ms cubic-bezier(.175, .885, .32, 1.275) calc(var(--s, 0) * 70ms + 160ms) both; }
  /* stage corner squares breathe */
  .stage::after { animation: breathe 4s ease-in-out infinite; }
  .ph-mascot .m-stage { animation: none; }
}
@keyframes stepPacket { 0% { opacity: 0; left: 7px; } 8% { opacity: 1; } 92% { opacity: 1; } 100% { opacity: 0; left: calc(100% - 17px); } }
@keyframes stepPacketLoop { 0% { opacity: 0; left: 7px; } 8% { opacity: 1; } 92% { opacity: 1; } 100% { opacity: 0; left: calc(100% - 17px); } }
@keyframes ckPop { from { opacity: 0; transform: scale(.5); } to { opacity: 1; transform: none; } }
@keyframes ckShift { 0%, 100% { transform: none; } 50% { transform: translateX(2px); } }
@keyframes starIn { from { opacity: 0; transform: scale(.5); } to { opacity: 1; transform: none; } }
@keyframes breathe { 0%, 100% { opacity: 1; } 50% { opacity: .6; } }
@media (max-width: 640px) {
  .js .xsteps.run::after { display: none; }
}

/* ---------- mascots: the hero of a page with no visual, and the closing band ---------- */
.ph.has-m .ph-in { grid-template-columns: minmax(0, 1fr) auto; }
.ph.has-m.no-vis .ph-in { grid-template-columns: minmax(0, 1fr) auto; }
.ph-m { justify-self: center; align-self: center; padding-right: clamp(0px, 3vw, 56px); }
.ph-mascot { --ms: clamp(200px, 21vw, 300px); }
.ph-mascot .m-stage { filter: drop-shadow(0 18px 30px rgba(0, 140, 230, .3)); }
@media (max-width: 980px) {
  .ph.has-m .ph-in, .ph.has-m.no-vis .ph-in { grid-template-columns: minmax(0, 1fr); }
  .ph-m { display: none; }
}
.xcta-mascot { --ms: clamp(190px, 18vw, 260px); }

/* ---------- stats band: big counted numbers on a navy band ---------- */
.xstats { display: grid; grid-template-columns: repeat(var(--cols, 4), minmax(0, 1fr)); gap: var(--grid-gap); }
.xstat { position: relative; padding: var(--sp-6) var(--sp-5) var(--sp-5); background: var(--surface); box-shadow: inset 0 0 0 1px var(--line-2); --c: 22px;
  clip-path: polygon(0 0, calc(100% - var(--c)) 0, 100% var(--c), 100% 100%, var(--c) 100%, 0 calc(100% - var(--c))); }
.xstat b { display: block; font: 800 clamp(40px, 4.6vw, 64px)/1 var(--f-head); letter-spacing: -.035em; background: var(--acc-grad); -webkit-background-clip: text; background-clip: text; color: transparent; }
.xstat span { display: block; margin-top: var(--sp-3); color: var(--ink-2); font-size: 15px; line-height: 1.45; }
.xstat i { position: absolute; left: var(--sp-5); right: var(--sp-5); bottom: 0; height: 3px; background: linear-gradient(90deg, var(--accent), transparent); transform-origin: 0 50%; }
.js .xstat:not(.in) i { transform: scaleX(0); }
.js .xstat.in i { transform: scaleX(1); transition: transform 900ms var(--ease) 200ms; }
@media (max-width: 980px) { .xstats { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 480px) { .xstat { padding: var(--sp-5) var(--sp-4) var(--sp-4); } }

/* ---------- photo frames: fill the frame, no bands ---------- */
.photo-frame img { aspect-ratio: 4 / 5; width: 100%; height: 100%; object-fit: cover; object-position: 50% 16%; }
.photo-frame { aspect-ratio: 4 / 5; }
.stage img, .xdev .screen img, .cs-card .shot img { object-fit: cover; }

/* ---------- small spacing fixes from the audit ---------- */
.sources-wrap { padding: 56px 0 var(--sp-8); }
.sources-wrap .sources { margin-top: 0; }
.xprose + .rv-list, .xrows + .xprose { margin-top: var(--sp-6); }
/* the strip that opens a closing band keeps clear of the content above it: the band before it always has at least 72 px under its content,
   and the strip is 48 px tall, so it never reaches the links; this guards a section that ends with a short padding */
main > section:has(+ .xcta) { padding-bottom: max(var(--sec-y), 96px); }

/* pixel glyph slots next to a section head */
.sx-glyph { margin: calc(var(--head-gap) * -.15) 0 var(--sp-6); min-height: 60px; }
.sx-glyph .pxart { width: auto; height: 58px; }
.sx-glyph-r { display: flex; justify-content: flex-end; margin-top: calc(var(--head-gap) * -1.5); margin-bottom: var(--sp-6); }
@media (max-width: 980px) { .sx-glyph-r { display: none; } .sx-glyph { margin-top: calc(var(--sp-3) * -1); } }
