/* ===========================================================
   v99 — COMMUNITY · SHARED FREQUENCIES
   Loaded by community.html alone.

   Everything structural is already in v92_pages_shell.css:
   .page-shell, .page-back, .page-hero, .page-rule, .page-bridge.
   This file adds only what that shell does not have — the network
   map, the two records and the signal ports — and touches nothing
   outside .community-page (the one exception, .v71-community-cta,
   lives in v71.css next to the component it varies).

   Motion contract. No canvas, no WebGL, no requestAnimationFrame,
   no permanent loop. Everything here is either a transition or a
   one-shot animation, and v99_community.js does nothing but decide
   when to arm them by adding a class. Two properties carry almost
   all of it — opacity and transform — so the compositor does the
   work and the main thread stays free.

   Mobile is the reference: 320 / 375 / 390 / 430 are designed
   first. The map does not shrink into a smaller copy of the desktop
   drawing; below 701px it becomes a different composition — an
   indented tree — with its own path set and its own node
   coordinates.
   =========================================================== */

/* -----------------------------------------------------------
   1. Opening
   Three paragraphs of intro instead of one: they need a little
   less air between them than the shell's default single lead.
   ----------------------------------------------------------- */
.community-page .page-hero-sub + .page-hero-sub {
  margin-top: .85rem;
}

/* -----------------------------------------------------------
   2. Network map — frame and readout
   ----------------------------------------------------------- */
.community-page .freq-map {
  width: min(var(--page-max), 100%);
  margin: clamp(2.4rem, 8vw, 4.4rem) auto 0;
  padding-inline: clamp(1.1rem, 5vw, 4rem);
}

.community-page .freq-map-status {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: center;
  gap: .5rem 1.1rem;
  margin: 0 0 clamp(1rem, 4vw, 1.6rem);
  font: 400 .6rem/1.4 var(--page-mono, monospace);
  letter-spacing: .2em;
  text-align: center;
}

/* The two readouts are stacked in one grid cell and cross-faded,
   so the line never reflows when the state changes. */
.community-page .freq-map-state {
  display: grid;
  justify-items: center;
}

.community-page .freq-state {
  grid-area: 1 / 1;
  font-weight: 700;
  transition: opacity .45s ease, color .45s ease;
}

.community-page .freq-state--searching {
  color: rgba(143, 244, 255, .5);
}

.community-page .freq-state--acquired {
  opacity: 0;
  color: #9ff6ff;
  text-shadow: 0 0 16px rgba(0, 220, 255, .5);
}

.community-page .freq-map[data-state="acquired"] .freq-state--searching { opacity: 0; }
.community-page .freq-map[data-state="acquired"] .freq-state--acquired  { opacity: 1; }

.community-page .freq-map-coords {
  color: rgba(143, 244, 255, .42);
}

/* -----------------------------------------------------------
   3. Network map — the drawing

   Narrow is the default: a tall indented tree. From 701px the box
   turns landscape and the wide branched layout takes over. Node
   positions travel between the two through --nx / --ny, and the
   two path sets live in the same SVG with one shown at a time.
   ----------------------------------------------------------- */
.community-page .freq-map-inner {
  position: relative;
  width: min(340px, 100%);
  margin-inline: auto;
  aspect-ratio: 3 / 4;
}

.community-page .freq-map-lines {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: visible;
}

.community-page .freq-lines--wide { display: none; }

.community-page .freq-line {
  fill: none;
  stroke: var(--page-hair-strong, rgba(120, 230, 255, .42));
  stroke-width: 1;
  stroke-linecap: round;
  stroke-linejoin: round;
  /* The box is stretched with preserveAspectRatio "none", so the
     stroke must refuse to be stretched with it. */
  vector-effect: non-scaling-stroke;
  /* pathLength normalises every run to 1 regardless of how long it
     actually is, so one dash covers a whole path, corners included. */
  stroke-dasharray: 1 1;
  stroke-dashoffset: 1;
  transition:
    stroke-dashoffset var(--lt, 400ms) cubic-bezier(.4, 0, .2, 1) var(--ld, 0ms),
    stroke .35s ease,
    opacity .35s ease;
}

/* The secondary runs are the two satellite links: thinner, dimmer,
   and never mistakable for a community connection. */
.community-page .freq-line--secondary {
  stroke: rgba(120, 230, 255, .26);
  stroke-width: .7;
  stroke-dasharray: .028 .028;
  stroke-dashoffset: 1;
}

.community-page .freq-map.is-live .freq-line { stroke-dashoffset: 0; }

/* Acquisition order. Core, trunk, AI ITALY and its satellite, then
   CROSSXHYPE and its satellite — the sequence the readout narrates.
   The last one lands at 2140ms; v99_community.js flips the readout
   at 2500ms and must stay behind that. */
.community-page .freq-line--trunk                     { --ld: 250ms;  --lt: 380ms; }
.community-page .freq-line--primary[data-link="ai"]   { --ld: 580ms;  --lt: 420ms; }
.community-page .freq-line--secondary[data-link="ai"] { --ld: 1020ms; --lt: 360ms; }
.community-page .freq-line--primary[data-link="cx"]   { --ld: 1340ms; --lt: 420ms; }
.community-page .freq-line--secondary[data-link="cx"] { --ld: 1780ms; --lt: 360ms; }

/* --- nodes ------------------------------------------------- */
.community-page .freq-node {
  position: absolute;
  left: var(--nx);
  top: var(--ny);
  display: grid;
  grid-auto-flow: column;
  align-items: center;
  gap: .5rem;
  width: max-content;
  max-width: 9.4rem;
  text-decoration: none;
  opacity: 0;
  /* Positioning uses `translate` so `transform` stays free for the
     dot's own scale — the two never fight over one property. */
  translate: -5px -50%;
  transition: opacity .42s ease var(--nd, 0ms);
}

.community-page .freq-map.is-live .freq-node { opacity: 1; }

.community-page .freq-node-text {
  display: grid;
  gap: .12rem;
  min-width: 0;
  text-align: left;
}

.community-page .freq-node-text b {
  color: var(--page-ink, rgba(238, 251, 255, .93));
  font: 700 .64rem/1.25 var(--page-mono, monospace);
  letter-spacing: .08em;
  overflow-wrap: anywhere;
}

.community-page .freq-node-text em {
  color: rgba(143, 244, 255, .58);
  font: 400 .52rem/1.2 var(--page-mono, monospace);
  font-style: normal;
  letter-spacing: .16em;
}

.community-page .freq-dot {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--page-accent, #00d9ff);
  box-shadow: 0 0 0 4px rgba(0, 217, 255, .12), 0 0 16px rgba(0, 217, 255, .5);
  transform: scale(.2);
  transition:
    transform .46s cubic-bezier(.2, 1.5, .35, 1) var(--nd, 0ms),
    box-shadow .3s ease,
    background .3s ease;
}

.community-page .freq-map.is-live .freq-dot { transform: scale(1); }

.community-page .freq-dot--core {
  width: 14px;
  height: 14px;
  background: #ffffff;
  box-shadow: 0 0 0 6px rgba(0, 217, 255, .1), 0 0 26px rgba(0, 217, 255, .65);
}

/* Satellites read as subordinate before a single word is read:
   smaller dot, hollow centre, dimmer label. */
.community-page .freq-dot--sat {
  width: 7px;
  height: 7px;
  background: rgba(4, 12, 22, .9);
  border: 1px solid rgba(120, 230, 255, .6);
  box-shadow: 0 0 10px rgba(0, 217, 255, .28);
}

.community-page .freq-node--sat .freq-node-text b {
  font-size: .56rem;
  font-weight: 400;
  color: rgba(214, 240, 252, .74);
}

.community-page .freq-node--sat .freq-node-text em { font-size: .48rem; }

.community-page .freq-node--core .freq-node-text b { font-size: .58rem; }

/* Narrow layout — indented tree, every label to the right of its dot.
   The trunk runs down the left gutter at x=10%, the branches at 26%,
   the satellites at 42%: no run ever passes through a label. */
.community-page .freq-node--core { --nx: 10%; --ny:  8%; --nd:    0ms; translate: -7px -50%; }
.community-page .freq-node--ai   { --nx: 26%; --ny: 30%; --nd:  860ms; }
.community-page .freq-node--tic  { --nx: 42%; --ny: 48%; --nd: 1260ms; }
.community-page .freq-node--cx   { --nx: 26%; --ny: 70%; --nd: 1620ms; }
.community-page .freq-node--bh   { --nx: 42%; --ny: 88%; --nd: 2020ms; }

/* --- link and probe states --------------------------------- */
.community-page .freq-line.is-linked {
  stroke: rgba(190, 246, 255, .92);
}

.community-page .freq-line--secondary.is-linked {
  stroke: rgba(160, 236, 255, .62);
}

.community-page .freq-node.is-linked .freq-dot {
  box-shadow: 0 0 0 5px rgba(0, 217, 255, .2), 0 0 24px rgba(0, 217, 255, .85);
}

.community-page .freq-node.is-linked .freq-node-text b { color: #ffffff; }

.community-page .freq-line.is-probing { stroke: #ffffff; }

.community-page a.freq-node:focus-visible {
  outline: 2px solid rgba(120, 235, 255, .9);
  outline-offset: 4px;
  border-radius: 6px;
}

/* --- legend and caption ------------------------------------ */
.community-page .freq-map-legend {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: .4rem 1.4rem;
  margin: clamp(1.1rem, 4vw, 1.8rem) 0 0;
  font: 400 .58rem/1.4 var(--page-mono, monospace);
  letter-spacing: .14em;
  color: rgba(214, 240, 252, .6);
  text-transform: uppercase;
}

.community-page .freq-map-legend > span {
  display: inline-flex;
  align-items: center;
  gap: .45rem;
}

.community-page .freq-legend-dot {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--page-accent, #00d9ff);
  box-shadow: 0 0 10px rgba(0, 217, 255, .5);
}

.community-page .freq-legend-dot--sat {
  width: 7px;
  height: 7px;
  background: rgba(4, 12, 22, .9);
  border: 1px solid rgba(120, 230, 255, .6);
  box-shadow: none;
}

.community-page .freq-map-note {
  margin: .55rem 0 0;
  color: rgba(143, 244, 255, .58);
  font: 400 .66rem/1.5 var(--page-mono, monospace);
  letter-spacing: .14em;
  text-align: center;
}

/* --- wide layout ------------------------------------------- */
@media (min-width: 701px) {
  .community-page .freq-map-inner {
    width: min(760px, 100%);
    aspect-ratio: 16 / 9;
  }

  .community-page .freq-lines--wide { display: block; }
  .community-page .freq-lines--tall { display: none; }

  /* Core on top with its label above; the two communities on the
     middle line with labels turned outwards; the two satellites
     below them with labels underneath. Every label sits on the one
     side its own runs never touch. */
  .community-page .freq-node--core { --nx: 50%; --ny: 16%; }
  .community-page .freq-node--ai   { --nx: 26%; --ny: 48%; }
  .community-page .freq-node--tic  { --nx: 26%; --ny: 86%; }
  .community-page .freq-node--cx   { --nx: 74%; --ny: 48%; }
  .community-page .freq-node--bh   { --nx: 74%; --ny: 86%; }

  .community-page .freq-node--core,
  .community-page .freq-node--sat {
    grid-auto-flow: row;
    justify-items: center;
    gap: .42rem;
  }

  .community-page .freq-node--core .freq-node-text,
  .community-page .freq-node--sat .freq-node-text { text-align: center; }

  .community-page .freq-node--core { translate: -50% calc(-100% + 7px); }
  .community-page .freq-node--core .freq-node-text { order: -1; }

  /* Satellite dots are 7px and come first, so half of one is 3.5px. */
  .community-page .freq-node--sat { translate: -50% -3.5px; }

  .community-page .freq-node--ai { translate: calc(-100% + 5px) -50%; }
  .community-page .freq-node--ai .freq-node-text { order: -1; text-align: right; }

  .community-page .freq-node--cx { translate: -5px -50%; }

  .community-page .freq-node { max-width: 11rem; }
}

/* -----------------------------------------------------------
   4. The records
   One column at every width: these are long readable entries,
   not tiles, and a two-up grid would halve the measure for
   nothing.
   ----------------------------------------------------------- */
.community-page .freq-list {
  width: min(var(--page-max), 100%);
  margin: clamp(2.6rem, 9vw, 5rem) auto 0;
  padding-inline: clamp(1.1rem, 5vw, 4rem);
}

.community-page .freq-card {
  position: relative;
  max-width: 62ch;
  margin-inline: auto;
  width: 100%;
  padding: clamp(1.2rem, 5vw, 2.1rem);
  border: 1px solid var(--card-edge);
  border-radius: 14px;
  background:
    radial-gradient(ellipse 90% 60% at 50% 0%, var(--card-tint), transparent 70%),
    linear-gradient(180deg, rgba(8, 18, 32, .55), rgba(4, 10, 20, .72));
  /* The navbar is fixed and its lower edge sits at 71px on compact
     widths and 78px from tablet up. This lands the card border
     roughly 25-40px clear of it at every breakpoint. */
  scroll-margin-top: clamp(96px, 14vw, 118px);
}

/* The one atmospheric difference between the two zones: AI ITALY
   keeps the archive's own blue, CROSSXHYPE drifts a few degrees
   towards violet. Same components, slightly different air. */
.community-page .freq-card--ai {
  --card-tint: rgba(0, 190, 255, .055);
  --card-edge: rgba(0, 220, 255, .22);
  --card-accent: #8ff4ff;
}

.community-page .freq-card--cx {
  --card-tint: rgba(126, 104, 255, .07);
  --card-edge: rgba(150, 140, 255, .24);
  --card-accent: #bdb2ff;
}

/* Corner ticks, in the same archive language as .page-figure-marks. */
.community-page .freq-card::before,
.community-page .freq-card::after {
  content: "";
  position: absolute;
  width: 14px;
  height: 14px;
  border: 0 solid var(--card-edge);
  pointer-events: none;
}

.community-page .freq-card::before {
  top: 9px; left: 9px;
  border-top-width: 1px; border-left-width: 1px;
}

.community-page .freq-card::after {
  bottom: 9px; right: 9px;
  border-bottom-width: 1px; border-right-width: 1px;
}

/* --- head: logo plate + identity --------------------------- */
.community-page .freq-card-head {
  display: flex;
  align-items: center;
  gap: clamp(.9rem, 4vw, 1.3rem);
}

/* The official images are square and small at the source: 150px
   for three of them, 92px for CROSSXHYPE. The plate is capped at
   88px so none is ever scaled beyond its own resolution, and
   `contain` keeps every one at its real proportions with no crop. */
.community-page .freq-plate {
  position: relative;
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  overflow: hidden;
  width: clamp(62px, 19vw, 88px);
  aspect-ratio: 1 / 1;
  padding: 6px;
  border: 1px solid var(--card-edge, rgba(0, 220, 255, .2));
  border-radius: 10px;
  background: rgba(2, 7, 14, .6);
  transition: border-color .3s ease, box-shadow .3s ease;
}

.community-page .freq-plate img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
  border-radius: 6px;
  transition: transform .45s var(--page-ease, ease);
}

/* One sweep across the emblem, on hover or on the acquisition —
   never idling. */
.community-page .freq-plate-scan {
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  height: 1px;
  background: linear-gradient(90deg, transparent, rgba(190, 246, 255, .85), transparent);
  opacity: 0;
  pointer-events: none;
}

.community-page .freq-card.is-armed .freq-plate-scan {
  animation: freq-sweep .85s ease .35s 1 both;
}

@keyframes freq-sweep {
  0%   { opacity: 0; transform: translateY(0); }
  15%  { opacity: 1; }
  85%  { opacity: 1; }
  100% { opacity: 0; transform: translateY(88px); }
}

.community-page .freq-card-id {
  display: grid;
  gap: .3rem;
  min-width: 0;
}

.community-page .freq-signal {
  color: var(--card-accent, #8ff4ff);
  font: 700 .6rem/1 var(--page-mono, monospace);
  letter-spacing: .2em;
  text-shadow: 0 0 14px rgba(0, 220, 255, .35);
}

.community-page .freq-card-id h2 {
  margin: 0;
  color: var(--sa-text, #effcff);
  font-family: var(--page-serif, serif);
  font-size: clamp(1.5rem, 6vw, 2.05rem);
  font-weight: 400;
  line-height: 1.1;
  letter-spacing: -.01em;
  /* Names are never broken mid-word. This used to say `anywhere`,
     which is what produced "CROSSXHYP / E". */
  overflow-wrap: normal;
}

.community-page .freq-role {
  color: var(--page-ink-soft, rgba(214, 240, 252, .78));
  font: 400 .78rem/1.35 var(--page-mono, monospace);
  letter-spacing: .04em;
}

/* One acquisition flicker per code, the first time its card is
   read. `both` holds the end state, `1` guarantees it never
   repeats. */
.community-page .freq-card.is-armed [data-glitch] {
  animation: freq-glitch .52s cubic-bezier(.3, 0, .2, 1) 1 both;
}

@keyframes freq-glitch {
  0%   { clip-path: inset(0 0 0 0);   transform: translateX(0);    opacity: .35; }
  12%  { clip-path: inset(0 0 62% 0); transform: translateX(-2px); opacity: 1; }
  26%  { clip-path: inset(56% 0 0 0); transform: translateX(2px); }
  40%  { clip-path: inset(0 0 28% 0); transform: translateX(-1px); }
  54%  { clip-path: inset(22% 0 0 0); transform: translateX(1px); }
  68%  { clip-path: inset(0 0 0 0);   transform: translateX(0); }
  100% { clip-path: inset(0 0 0 0);   transform: translateX(0);    opacity: 1; }
}

/* --- editorial blocks -------------------------------------- */
.community-page .freq-block {
  margin-top: clamp(1.1rem, 4vw, 1.5rem);
}

.community-page .freq-block-title {
  margin: 0 0 .7rem;
  color: rgba(143, 244, 255, .72);
  font: 700 .62rem/1.3 var(--page-mono, monospace);
  font-weight: 700;
  letter-spacing: .22em;
  text-transform: uppercase;
}

/* Micro-separator: a hairline that fades out from the left, with a
   single tick where the next block begins. */
.community-page .freq-sep {
  position: relative;
  height: 1px;
  margin: clamp(1.3rem, 5vw, 1.9rem) 0;
  border: 0;
  background: linear-gradient(90deg, var(--card-edge), transparent 72%);
}

.community-page .freq-sep::after {
  content: "";
  position: absolute;
  top: -2px;
  left: 0;
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--card-edge);
}

/* --- connection status ------------------------------------- */
.community-page .freq-status-code {
  margin: 0 0 .9rem;
  color: var(--page-ink, rgba(238, 251, 255, .93));
  font: 400 .66rem/1.5 var(--page-mono, monospace);
  letter-spacing: .1em;
  overflow-wrap: anywhere;
}

.community-page .freq-strength {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .5rem .8rem;
  margin: 0 0 1rem;
}

.community-page .freq-strength-label {
  color: rgba(143, 244, 255, .55);
  font: 400 .56rem/1 var(--page-mono, monospace);
  letter-spacing: .2em;
  text-transform: uppercase;
}

.community-page .freq-strength-bars {
  display: flex;
  align-items: flex-end;
  gap: 3px;
  height: 18px;
}

.community-page .freq-strength-bars i {
  width: 4px;
  border-radius: 1px;
  background: var(--card-accent, #8ff4ff);
  opacity: .22;
  transform: scaleY(.16);
  transform-origin: bottom center;
  transition:
    transform .5s cubic-bezier(.2, 1, .3, 1) var(--bd, 0ms),
    opacity .4s ease var(--bd, 0ms);
}

.community-page .freq-strength-bars i:nth-child(1) { height:  7px; --bd: 140ms; }
.community-page .freq-strength-bars i:nth-child(2) { height: 10px; --bd: 250ms; }
.community-page .freq-strength-bars i:nth-child(3) { height: 13px; --bd: 360ms; }
.community-page .freq-strength-bars i:nth-child(4) { height: 16px; --bd: 470ms; }
.community-page .freq-strength-bars i:nth-child(5) { height: 18px; --bd: 580ms; }

.community-page .freq-card.is-armed .freq-strength-bars i {
  transform: scaleY(1);
  opacity: .95;
}

/* The meter reads a connection, not an endorsement: the last bar
   stays open on purpose. Selective participation is not a full
   signal and should not be drawn as one. */
.community-page .freq-card.is-armed .freq-strength-bars i:nth-child(5) {
  opacity: .26;
}

.community-page .freq-strength-state {
  color: var(--card-accent, #8ff4ff);
  font: 700 .56rem/1 var(--page-mono, monospace);
  letter-spacing: .2em;
}

/* --- shared fields ----------------------------------------- */
.community-page .freq-chips {
  display: flex;
  flex-wrap: wrap;
  gap: .45rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.community-page .freq-chips li {
  padding: .34rem .68rem;
  border: 1px solid var(--card-edge);
  border-radius: 999px;
  background: rgba(2, 8, 16, .5);
  color: var(--page-ink-soft, rgba(214, 240, 252, .78));
  font: 400 .62rem/1.3 var(--page-mono, monospace);
  letter-spacing: .1em;
  text-transform: uppercase;
}

/* --- network record ---------------------------------------- */
.community-page .freq-record {
  margin-top: clamp(1.1rem, 4vw, 1.5rem);
  padding: clamp(.9rem, 4vw, 1.2rem);
  border: 1px dashed var(--card-edge);
  border-radius: 10px;
  background: rgba(2, 8, 16, .42);
}

.community-page .freq-record-code {
  margin: 0 0 .6rem;
  color: var(--card-accent, #8ff4ff);
  font: 700 .58rem/1.45 var(--page-mono, monospace);
  letter-spacing: .16em;
  overflow-wrap: anywhere;
}

/* --- signal ports ------------------------------------------ */
.community-page .freq-ports {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(84px, 1fr));
  gap: .5rem;
  margin-top: 1.1rem;
}

.community-page .freq-port {
  position: relative;
  overflow: hidden;
  display: grid;
  justify-items: center;
  align-content: center;
  gap: .38rem;
  min-height: 68px;
  padding: .6rem .35rem;
  border: 1px solid var(--card-edge);
  border-radius: 10px;
  background: rgba(2, 8, 16, .55);
  color: rgba(214, 240, 252, .8);
  text-decoration: none;
  transition:
    border-color .28s ease,
    background .28s ease,
    color .28s ease,
    transform .3s var(--page-ease, ease);
}

.community-page .freq-port svg {
  width: 22px;
  height: 22px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2.6;
  stroke-linecap: round;
  stroke-linejoin: round;
  transition: transform .38s var(--page-ease, ease);
}

.community-page .freq-port-name {
  font: 400 .54rem/1.2 var(--page-mono, monospace);
  letter-spacing: .12em;
  text-transform: uppercase;
  text-align: center;
}

.community-page .freq-port-scan {
  position: absolute;
  left: 5px;
  right: 5px;
  top: 4px;
  height: 1px;
  background: linear-gradient(90deg, transparent, rgba(190, 246, 255, .9), transparent);
  opacity: 0;
  pointer-events: none;
}

.community-page .freq-port:hover,
.community-page .freq-port:focus-visible,
.community-page .freq-port:active {
  border-color: rgba(160, 236, 255, .75);
  background: rgba(6, 20, 34, .8);
  color: #ffffff;
  transform: translateY(-2px);
}

.community-page .freq-port:hover .freq-port-scan,
.community-page .freq-port:focus-visible .freq-port-scan,
.community-page .freq-port:active .freq-port-scan {
  animation: freq-port-scan .58s ease 1 both;
}

@keyframes freq-port-scan {
  0%   { opacity: 0; transform: translateY(0); }
  22%  { opacity: 1; }
  100% { opacity: 0; transform: translateY(56px); }
}

/* One acquisition gesture each, so the row does not read as six
   copies of the same button. All of them are transform-only. */
.community-page .freq-port:nth-child(1):hover svg,
.community-page .freq-port:nth-child(1):focus-visible svg { transform: scale(1.12); }

.community-page .freq-port:nth-child(2):hover svg,
.community-page .freq-port:nth-child(2):focus-visible svg { transform: translateY(-3px); }

.community-page .freq-port:nth-child(3):hover svg,
.community-page .freq-port:nth-child(3):focus-visible svg { transform: scaleX(1.16); }

.community-page .freq-port:nth-child(4):hover svg,
.community-page .freq-port:nth-child(4):focus-visible svg { transform: rotate(-8deg) scale(1.06); }

.community-page .freq-port:nth-child(5):hover svg,
.community-page .freq-port:nth-child(5):focus-visible svg { transform: rotate(90deg); }

.community-page .freq-port:nth-child(6):hover svg,
.community-page .freq-port:nth-child(6):focus-visible svg { transform: translateY(-2px) scale(1.08); }

.community-page .freq-port:focus-visible {
  outline: 2px solid rgba(120, 235, 255, .9);
  outline-offset: 2px;
}

/* --- social footer ----------------------------------------- */
.community-page .freq-meta {
  margin-top: clamp(1.2rem, 4vw, 1.7rem);
  padding-top: clamp(.9rem, 3vw, 1.2rem);
  border-top: 1px solid var(--card-edge);
  display: grid;
  gap: .8rem;
}

.community-page .freq-meta-row {
  display: grid;
  gap: .28rem;
}

.community-page .freq-meta-label {
  color: rgba(143, 244, 255, .55);
  font: 400 .58rem/1 var(--page-mono, monospace);
  letter-spacing: .2em;
  text-transform: uppercase;
}

.community-page .freq-meta-value {
  color: var(--page-ink, rgba(238, 251, 255, .93));
  font: 400 .68rem/1.5 var(--page-mono, monospace);
  letter-spacing: .08em;
  overflow-wrap: anywhere;
}

.community-page .freq-links {
  display: flex;
  flex-wrap: wrap;
  gap: .3rem 1rem;
}

.community-page .freq-links a {
  color: var(--card-accent, #8ff4ff);
  text-decoration: none;
  border-bottom: 1px solid var(--card-edge);
  transition: color .25s ease, border-color .25s ease;
}

.community-page .freq-links a:hover,
.community-page .freq-links a:focus-visible {
  color: #ffffff;
  border-bottom-color: rgba(190, 246, 255, .8);
}

@media (min-width: 761px) {
  .community-page .freq-meta-row {
    grid-template-columns: 8.5rem 1fr;
    align-items: baseline;
    gap: 1rem;
  }
}

/* --- record prose ------------------------------------------ */
/* Restored after the connected profiles moved out: these rules used to
   name .freq-sub in the same selector list, so removing that class took
   them with it. */
.community-page .freq-block p,
.community-page .freq-record p {
  margin: 0;
  color: var(--page-ink-soft, rgba(214, 240, 252, .78));
  font-family: var(--page-serif, serif);
  font-size: clamp(1rem, 1.1vw, 1.08rem);
  line-height: 1.72;
}

.community-page .freq-block p + p,
.community-page .freq-record p + p {
  margin-top: .9rem;
}

/* The card runs 920px wide, so the prose needs its own measure or the
   lines would reach 120 characters. */
.community-page .freq-card > .freq-block,
.community-page .freq-card > .freq-record,
.community-page .freq-card > .freq-sep {
  width: min(64ch, 100%);
  margin-inline: clamp(1.2rem, 5vw, 2.1rem);
}

.community-page .freq-card > .freq-meta {
  width: auto;
  margin-inline: clamp(1.2rem, 5vw, 2.1rem);
}

/* -----------------------------------------------------------
   5. Divider between the two records
   The feather is the project's own mark, drawn once rather than
   pasted as an emoji, and it is the only ornament between the two
   zones.
   ----------------------------------------------------------- */
.community-page .freq-divider {
  display: flex;
  align-items: center;
  gap: 1rem;
  width: min(62ch, 100%);
  margin: clamp(2rem, 7vw, 3.2rem) auto;
}

.community-page .freq-divider-line {
  flex: 1;
  height: 1px;
  background: linear-gradient(90deg, transparent, rgba(0, 220, 255, .28), transparent);
}

.community-page .freq-divider-mark {
  width: 26px;
  height: 26px;
  flex: 0 0 auto;
  fill: none;
  stroke: rgba(120, 230, 255, .5);
  stroke-width: 1.4;
  stroke-linecap: round;
}

/* -----------------------------------------------------------
   6. Closing line
   ----------------------------------------------------------- */
.community-page .freq-close {
  width: min(62ch, 100%);
  margin: clamp(2.2rem, 8vw, 3.6rem) auto 0;
  padding-inline: clamp(1.1rem, 5vw, 4rem);
  color: rgba(214, 240, 252, .62);
  font-family: var(--page-serif, serif);
  font-size: clamp(.98rem, 1.1vw, 1.06rem);
  font-style: italic;
  line-height: 1.7;
  text-align: center;
}

/* -----------------------------------------------------------
   7. Reduced motion
   v99_community.js already writes the end state and registers no
   observer. This makes sure nothing left in CSS animates anyway:
   the page simply arrives finished.
   ----------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  .community-page .freq-line,
  .community-page .freq-node,
  .community-page .freq-dot,
  .community-page .freq-state,
  .community-page .freq-strength-bars i,
  .community-page .freq-port,
  .community-page .freq-port svg,
  .community-page .freq-plate img,
  .community-page .freq-links a {
    transition: none !important;
  }

  .community-page .freq-line { stroke-dashoffset: 0 !important; }
  .community-page .freq-node { opacity: 1 !important; }
  .community-page .freq-dot { transform: none !important; }
  .community-page .freq-strength-bars i { transform: scaleY(1) !important; opacity: .95; }
  .community-page .freq-strength-bars i:nth-child(5) { opacity: .26; }

  .community-page .freq-card.is-armed [data-glitch],
  .community-page .freq-card.is-armed .freq-plate-scan,
  .community-page .freq-port:hover .freq-port-scan,
  .community-page .freq-port:focus-visible .freq-port-scan,
  .community-page .freq-port:active .freq-port-scan {
    animation: none !important;
  }

  .community-page .freq-plate-scan { opacity: 0; }
  .community-page .freq-port:hover,
  .community-page .freq-port:focus-visible { transform: none; }
}

/* -----------------------------------------------------------
   8. HONORABLE SIGNALS

   A different register from the two records above, on purpose. The
   network is a diagram; this is a single archive entry. So the
   hierarchy inverts: there the emblem is small and the prose long,
   here the portrait leads and the interview is the destination.

   Self-contained by design — it shares only .freq-port and
   .freq-plate-scan with the records, and references neither
   AI ITALY nor CROSSXHYPE. Either side can be removed without
   touching the other.
   ----------------------------------------------------------- */
.community-page .honorable {
  --card-edge: rgba(196, 168, 255, .26);
  --card-accent: #d9c7ff;
  width: min(var(--page-max), 100%);
  margin: clamp(3rem, 10vw, 5.5rem) auto 0;
  padding-inline: clamp(1.1rem, 5vw, 4rem);
}

.community-page .honorable-head {
  max-width: 62ch;
  margin-inline: auto;
  text-align: center;
}

.community-page .honorable-kicker {
  margin: 0 0 .9rem;
  color: var(--card-accent);
  font: 700 .66rem/1.3 var(--page-mono, monospace);
  letter-spacing: .3em;
  text-transform: uppercase;
  text-shadow: 0 0 18px rgba(170, 140, 255, .4);
}

.community-page .honorable-intro {
  margin: 0;
  color: var(--page-ink-soft, rgba(214, 240, 252, .78));
  font-family: var(--page-serif, serif);
  font-size: clamp(1.02rem, 1.2vw, 1.16rem);
  font-style: italic;
  line-height: 1.72;
  text-wrap: pretty;
}

/* The arriving frequency. It leaves the core and stops here: it is
   drawn in its own SVG and never joins the map above, because this
   record is not a node of that network. */
.community-page .honorable-inbound {
  position: relative;
  width: min(62ch, 100%);
  height: 74px;
  margin: clamp(1.4rem, 5vw, 2.2rem) auto 0;
}

.community-page .honorable-inbound svg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: visible;
}

.community-page .freq-line--inbound {
  stroke: rgba(196, 168, 255, .5);
  stroke-width: .8;
  stroke-dasharray: .03 .03;
  stroke-dashoffset: 1;
  transition: stroke-dashoffset 1s cubic-bezier(.4, 0, .2, 1) 120ms;
}

.community-page .honorable-inbound.is-live .freq-line--inbound { stroke-dashoffset: 0; }
.community-page .honorable-inbound.is-instant .freq-line--inbound { transition: none; }

.community-page .honorable-inbound-tag {
  position: absolute;
  left: 50%;
  top: 4px;
  translate: -50% 0;
  padding: 0 .5rem;
  background: var(--sa-bg, #02060c);
  color: rgba(196, 168, 255, .55);
  font: 400 .52rem/1.4 var(--page-mono, monospace);
  letter-spacing: .2em;
  white-space: nowrap;
}

/* --- the record itself ------------------------------------- */
.community-page .honorable-card {
  display: grid;
  gap: clamp(1.2rem, 5vw, 2rem);
  width: min(62ch, 100%);
  margin: clamp(.6rem, 2vw, 1rem) auto 0;
  padding: clamp(1.2rem, 5vw, 2.1rem);
  border: 1px solid var(--card-edge);
  border-radius: 16px;
  background:
    radial-gradient(ellipse 80% 60% at 20% 0%, rgba(150, 110, 255, .09), transparent 68%),
    linear-gradient(180deg, rgba(14, 12, 30, .6), rgba(5, 6, 16, .74));
  scroll-margin-top: clamp(96px, 14vw, 118px);
}

/* The portrait is the only image on this page that may lead, and it
   is also the only one with the resolution for it: 400x400 at the
   source against 150 and 92 for the emblems. Capped at 260px so it
   is never interpolated past what it actually holds. */
.community-page .honorable-portrait {
  position: relative;
  overflow: hidden;
  width: min(260px, 100%);
  margin: 0 auto;
  aspect-ratio: 1 / 1;
  border: 1px solid var(--card-edge);
  border-radius: 14px;
  background: rgba(3, 4, 12, .7);
}

.community-page .honorable-portrait img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
}

.community-page .honorable-portrait-marks i {
  position: absolute;
  width: 13px;
  height: 13px;
  border: 0 solid rgba(214, 196, 255, .5);
  pointer-events: none;
}

.community-page .honorable-portrait-marks i:nth-child(1) { top: 8px; left: 8px; border-top-width: 1px; border-left-width: 1px; }
.community-page .honorable-portrait-marks i:nth-child(2) { top: 8px; right: 8px; border-top-width: 1px; border-right-width: 1px; }
.community-page .honorable-portrait-marks i:nth-child(3) { bottom: 8px; left: 8px; border-bottom-width: 1px; border-left-width: 1px; }
.community-page .honorable-portrait-marks i:nth-child(4) { bottom: 8px; right: 8px; border-bottom-width: 1px; border-right-width: 1px; }

.community-page .honorable-portrait-tag {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  padding: .5rem .6rem;
  background: linear-gradient(180deg, transparent, rgba(3, 4, 12, .88) 55%);
  color: rgba(214, 196, 255, .82);
  font: 400 .52rem/1.4 var(--page-mono, monospace);
  letter-spacing: .16em;
  text-align: center;
}

.community-page .honorable-card.is-armed .freq-plate-scan {
  animation: freq-sweep-tall 1.05s ease .3s 1 both;
}

@keyframes freq-sweep-tall {
  0%   { opacity: 0; transform: translateY(0); }
  14%  { opacity: 1; }
  86%  { opacity: 1; }
  100% { opacity: 0; transform: translateY(260px); }
}

.community-page .honorable-body > * { margin: 0; }

.community-page .honorable-code {
  color: var(--card-accent);
  font: 700 .58rem/1.45 var(--page-mono, monospace);
  letter-spacing: .18em;
  overflow-wrap: anywhere;
}

.community-page .honorable-body h2 {
  margin-top: .5rem;
  color: var(--sa-text, #effcff);
  font-family: var(--page-serif, serif);
  font-size: clamp(1.6rem, 6.5vw, 2.2rem);
  font-weight: 400;
  line-height: 1.08;
  letter-spacing: -.01em;
}

.community-page .honorable-handle {
  margin-top: .3rem;
  color: rgba(214, 196, 255, .68);
  font: 400 .72rem/1.3 var(--page-mono, monospace);
  letter-spacing: .12em;
}

.community-page .honorable-role {
  margin-top: .55rem;
  padding-bottom: 1rem;
  border-bottom: 1px solid var(--card-edge);
  color: var(--page-ink-soft, rgba(214, 240, 252, .74));
  font: 400 .76rem/1.4 var(--page-mono, monospace);
  letter-spacing: .04em;
}

.community-page .honorable-body > p[data-i18n] {
  margin-top: 1rem;
  color: var(--page-ink-soft, rgba(214, 240, 252, .8));
  font-family: var(--page-serif, serif);
  font-size: clamp(1rem, 1.1vw, 1.08rem);
  line-height: 1.72;
}

/* --- the interview, as a destination ----------------------- */
.community-page .honorable-cta {
  position: relative;
  display: grid;
  gap: .3rem;
  margin-top: clamp(1.3rem, 5vw, 1.9rem);
  padding: clamp(1rem, 4.5vw, 1.35rem) clamp(2.6rem, 9vw, 3.2rem) clamp(1rem, 4.5vw, 1.35rem) clamp(1rem, 4.5vw, 1.35rem);
  border: 1px solid rgba(196, 168, 255, .48);
  border-radius: 12px;
  background:
    radial-gradient(ellipse 70% 100% at 0% 50%, rgba(150, 110, 255, .16), transparent 70%),
    rgba(10, 8, 24, .75);
  text-decoration: none;
  transition: border-color .28s ease, box-shadow .28s ease, transform .28s var(--page-ease, ease);
}

.community-page .honorable-cta::before {
  content: "";
  position: absolute;
  left: 0;
  top: 12%;
  bottom: 12%;
  width: 2px;
  border-radius: 2px;
  background: linear-gradient(180deg, transparent, var(--card-accent), transparent);
}

.community-page .honorable-cta-code {
  color: rgba(214, 196, 255, .72);
  font: 700 .55rem/1.4 var(--page-mono, monospace);
  letter-spacing: .18em;
  overflow-wrap: anywhere;
}

.community-page .honorable-cta-title {
  color: #ffffff;
  font-family: var(--page-serif, serif);
  font-size: clamp(1.16rem, 4.6vw, 1.42rem);
  line-height: 1.2;
}

.community-page .honorable-cta-note {
  color: rgba(214, 240, 252, .62);
  font: 400 .68rem/1.5 var(--page-mono, monospace);
  letter-spacing: .04em;
}

.community-page .honorable-cta-arrow {
  position: absolute;
  right: clamp(1rem, 4vw, 1.35rem);
  top: 50%;
  translate: 0 -50%;
  color: var(--card-accent);
  font-size: 1.3rem;
  line-height: 1;
  transition: transform .3s var(--page-ease, ease);
}

.community-page .honorable-cta:hover,
.community-page .honorable-cta:focus-visible {
  border-color: rgba(220, 200, 255, .9);
  box-shadow: 0 0 34px rgba(150, 110, 255, .22);
  transform: translateY(-2px);
}

.community-page .honorable-cta:hover .honorable-cta-arrow,
.community-page .honorable-cta:focus-visible .honorable-cta-arrow {
  transform: translate(3px, -3px);
}

.community-page .honorable-cta:focus-visible {
  outline: 2px solid rgba(200, 176, 255, .95);
  outline-offset: 3px;
}

.community-page .honorable-ports {
  margin-top: clamp(1rem, 4vw, 1.4rem);
}

/* From tablet up the portrait moves beside the text instead of above
   it, and can grow, because the source is large enough to allow it. */
@media (min-width: 761px) {
  .community-page .honorable-card {
    grid-template-columns: minmax(220px, 300px) 1fr;
    align-items: start;
    width: min(920px, 100%);
    gap: clamp(1.6rem, 3vw, 2.4rem);
  }

  .community-page .honorable-portrait {
    width: 100%;
    max-width: 300px;
    margin: 0;
    position: sticky;
    top: clamp(96px, 12vw, 118px);
  }

  .community-page .honorable-inbound,
  .community-page .honorable-head { width: min(920px, 100%); }
}

@media (prefers-reduced-motion: reduce) {
  .community-page .freq-line--inbound { stroke-dashoffset: 0 !important; transition: none !important; }
  .community-page .honorable-card.is-armed .freq-plate-scan { animation: none !important; }
  .community-page .honorable-cta,
  .community-page .honorable-cta-arrow { transition: none !important; }
  .community-page .honorable-cta:hover,
  .community-page .honorable-cta:focus-visible { transform: none; }
  .community-page .honorable-portrait { position: static; }
}

/* The JS fallback also stamps .is-instant, for the case where the
   preference is set but the media query above is not the reason
   (no IntersectionObserver at all). */
.community-page .freq-map.is-instant .freq-line { stroke-dashoffset: 0; transition: none; }
.community-page .freq-map.is-instant .freq-node { opacity: 1; transition: none; }
.community-page .freq-map.is-instant .freq-dot { transform: scale(1); transition: none; }

/* ===========================================================
   9. PRESENCE PASS

   The three records were not equal before this block: Honorable
   Signals ran 920px wide with a 258px portrait, while the two
   community records ran at a 62ch measure with an 88px emblem. Read
   side by side, that reads as a difference in importance rather
   than a difference in kind.

   So the width and the visual area are levelled here, and the
   identity is what separates them instead:

     AI ITALY   — curatorial. A plotted field with marks and links
                  behind an emblem shown at its full native size.
     CROSSXHYPE — broadcast. A disc and a waveform; the logo stays
                  at 92px because that is all it has, and the frame
                  carries the presence instead of the scaling.
     MIYUKI     — editorial. Unchanged: it is the benchmark.

   Everything added here is static geometry or a one-shot reveal.
   No new observer, no loop, no canvas.
   =========================================================== */

/* --- shared: the records now match Honorable Signals ------- */
.community-page .freq-card {
  width: min(920px, 100%);
  max-width: 100%;
  padding: 0 0 clamp(1.2rem, 5vw, 2.1rem);
  overflow: hidden;
}

.community-page .freq-card::before { top: 0; left: 0; }
.community-page .freq-card::after { bottom: 0; right: 0; }

/* --- the masthead band ------------------------------------- */
.community-page .freq-masthead {
  position: relative;
  overflow: hidden;
  margin-bottom: clamp(1.4rem, 5vw, 2rem);
  border-bottom: 1px solid var(--card-edge);
}

.community-page .freq-masthead-id {
  position: relative;
  z-index: 2;
  display: flex;
  align-items: center;
  gap: clamp(1rem, 4vw, 1.6rem);
  padding: clamp(1.4rem, 6vw, 2.4rem) clamp(1.2rem, 5vw, 2.1rem);
}

/* The emblem at its real resolution: 150px native for AI ITALY, so
   150px on screen and not one pixel more. */
.community-page .freq-plate--lg {
  width: clamp(96px, 30vw, 150px);
  padding: 10px;
  border-radius: 14px;
  background: rgba(2, 7, 14, .72);
  box-shadow: 0 0 0 1px rgba(0, 220, 255, .1), 0 18px 40px rgba(0, 0, 0, .45);
}

.community-page .freq-masthead .freq-card-id { gap: .45rem; }

.community-page .freq-masthead h2 {
  font-size: clamp(1.8rem, 8vw, 2.9rem);
}

/* --- AI ITALY: the generative field ------------------------ */
.community-page .freq-masthead--ai {
  background:
    radial-gradient(ellipse 80% 120% at 12% 0%, rgba(0, 190, 255, .12), transparent 62%),
    linear-gradient(180deg, rgba(6, 20, 34, .7), rgba(4, 10, 20, .2));
}

.community-page .freq-field {
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  /* The field belongs behind the identity, and it must fade out on
     the side the emblem occupies or it would fight with it. */
  -webkit-mask-image: linear-gradient(90deg, transparent 8%, #000 58%, #000 100%);
          mask-image: linear-gradient(90deg, transparent 8%, #000 58%, #000 100%);
}

.community-page .freq-field svg {
  width: 100%;
  height: 100%;
  display: block;
}

.community-page .ff-grid path {
  fill: none;
  stroke: rgba(0, 220, 255, .16);
  stroke-width: .5;
  vector-effect: non-scaling-stroke;
}

.community-page .ff-links path {
  fill: none;
  stroke: rgba(120, 230, 255, .3);
  stroke-width: .7;
  vector-effect: non-scaling-stroke;
}

.community-page .ff-marks rect,
.community-page .ff-marks circle {
  fill: none;
  stroke: rgba(150, 236, 255, .55);
  stroke-width: 1;
  vector-effect: non-scaling-stroke;
}

.community-page .ff-marks rect:nth-child(2n) { fill: rgba(0, 200, 255, .12); }
.community-page .ff-marks circle:nth-child(3n) { fill: rgba(120, 230, 255, .16); }

/* One reveal of the field when the record is read, then nothing. */
.community-page .freq-field svg > g {
  opacity: 0;
  transition: opacity .9s ease var(--fd, 0ms);
}

.community-page .ff-grid  { --fd: 120ms; }
.community-page .ff-links { --fd: 420ms; }
.community-page .ff-marks { --fd: 280ms; }

.community-page .freq-card.is-armed .freq-field svg > g { opacity: 1; }

/* --- CROSSXHYPE: the broadcast node ------------------------ */
.community-page .freq-masthead--cx {
  background:
    radial-gradient(ellipse 70% 120% at 8% 0%, rgba(126, 104, 255, .16), transparent 60%),
    linear-gradient(180deg, rgba(18, 14, 38, .7), rgba(6, 6, 18, .2));
}

/* The broadcast disc. Two rings around the logo: the device that says
   "node" rather than "avatar". It was originally sized around a 92px
   logo; the source is now 900px, so the logo fills the disc and the
   rings are the framing rather than the compensation. */
.community-page .freq-disc {
  position: relative;
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  width: clamp(112px, 34vw, 168px);
  aspect-ratio: 1 / 1;
}

.community-page .freq-disc-ring {
  position: absolute;
  inset: 0;
  border-radius: 50%;
  border: 1px solid rgba(180, 160, 255, .3);
}

.community-page .freq-disc-ring:nth-child(2) {
  inset: 11%;
  border-color: rgba(180, 160, 255, .18);
  border-style: dashed;
}

.community-page .freq-plate--disc {
  width: 74%;
  padding: 4px;
  border: 0;
  border-radius: 50%;
  background: rgba(6, 5, 16, .85);
  box-shadow: 0 0 0 1px rgba(180, 160, 255, .35), 0 14px 34px rgba(0, 0, 0, .5);
}

.community-page .freq-plate--disc img { border-radius: 50%; }

/* The waveform. Fixed heights, raised once in sequence: it measures
   nothing and it does not keep running. */
.community-page .freq-wave {
  position: relative;
  z-index: 2;
  display: flex;
  align-items: flex-end;
  gap: clamp(2px, .8vw, 4px);
  height: clamp(38px, 11vw, 62px);
  padding: 0 clamp(1.2rem, 5vw, 2.1rem);
  overflow: hidden;
}

.community-page .freq-wave i {
  flex: 1 1 0;
  min-width: 1px;
  border-radius: 1px 1px 0 0;
  background: linear-gradient(180deg, rgba(196, 168, 255, .95), rgba(126, 104, 255, .3));
  transform: scaleY(.06);
  transform-origin: bottom center;
  transition: transform .55s cubic-bezier(.2, 1, .3, 1) var(--wd, 0ms);
}

.community-page .freq-card.is-armed .freq-wave i { transform: scaleY(1); }

.community-page .freq-wave i:nth-child(1)  { height: 34%; --wd:  40ms; }
.community-page .freq-wave i:nth-child(2)  { height: 58%; --wd:  70ms; }
.community-page .freq-wave i:nth-child(3)  { height: 26%; --wd: 100ms; }
.community-page .freq-wave i:nth-child(4)  { height: 78%; --wd: 130ms; }
.community-page .freq-wave i:nth-child(5)  { height: 44%; --wd: 160ms; }
.community-page .freq-wave i:nth-child(6)  { height: 92%; --wd: 190ms; }
.community-page .freq-wave i:nth-child(7)  { height: 36%; --wd: 220ms; }
.community-page .freq-wave i:nth-child(8)  { height: 66%; --wd: 250ms; }
.community-page .freq-wave i:nth-child(9)  { height: 22%; --wd: 280ms; }
.community-page .freq-wave i:nth-child(10) { height: 84%; --wd: 310ms; }
.community-page .freq-wave i:nth-child(11) { height: 48%; --wd: 340ms; }
.community-page .freq-wave i:nth-child(12) { height: 70%; --wd: 370ms; }
.community-page .freq-wave i:nth-child(13) { height: 30%; --wd: 400ms; }
.community-page .freq-wave i:nth-child(14) { height: 100%; --wd: 430ms; }
.community-page .freq-wave i:nth-child(15) { height: 40%; --wd: 460ms; }
.community-page .freq-wave i:nth-child(16) { height: 62%; --wd: 490ms; }
.community-page .freq-wave i:nth-child(17) { height: 28%; --wd: 520ms; }
.community-page .freq-wave i:nth-child(18) { height: 76%; --wd: 550ms; }
.community-page .freq-wave i:nth-child(19) { height: 52%; --wd: 580ms; }
.community-page .freq-wave i:nth-child(20) { height: 88%; --wd: 610ms; }
.community-page .freq-wave i:nth-child(21) { height: 32%; --wd: 640ms; }
.community-page .freq-wave i:nth-child(22) { height: 64%; --wd: 670ms; }
.community-page .freq-wave i:nth-child(23) { height: 24%; --wd: 700ms; }
.community-page .freq-wave i:nth-child(24) { height: 80%; --wd: 730ms; }
.community-page .freq-wave i:nth-child(25) { height: 46%; --wd: 760ms; }
.community-page .freq-wave i:nth-child(26) { height: 68%; --wd: 790ms; }
.community-page .freq-wave i:nth-child(27) { height: 20%; --wd: 820ms; }
.community-page .freq-wave i:nth-child(28) { height: 54%; --wd: 850ms; }

.community-page .freq-wave-tag {
  position: relative;
  z-index: 2;
  margin: .5rem 0 0;
  padding: 0 clamp(1.2rem, 5vw, 2.1rem) clamp(.9rem, 3vw, 1.2rem);
  color: rgba(196, 168, 255, .55);
  font: 400 .54rem/1.4 var(--page-mono, monospace);
  letter-spacing: .22em;
}

.community-page .freq-ports { margin-top: 1.1rem; }

/* --- wider viewports --------------------------------------- */
@media (min-width: 641px) {
}

/* The CROSSXHYPE masthead only turns horizontal once there is room for
   both halves. Tried at 641px it gave the identity 562px and left the
   waveform 104px, which is narrower than 28 bars can be — four of them
   ran off the viewport. Below this width the wave keeps the full card
   instead, stacked under the identity. */
@media (min-width: 901px) {
  .community-page .freq-masthead--cx {
    display: grid;
    grid-template-columns: minmax(0, auto) minmax(300px, 1fr);
    align-items: center;
    column-gap: clamp(1rem, 3vw, 2rem);
  }

  .community-page .freq-masthead--cx .freq-masthead-id { min-width: 0; }

  .community-page .freq-masthead--cx .freq-wave {
    height: clamp(56px, 8vw, 92px);
    padding-left: 0;
  }

  .community-page .freq-masthead--cx .freq-wave-tag {
    grid-column: 2;
    padding-left: 0;
    padding-bottom: 0;
    margin-top: .6rem;
  }
}

@media (min-width: 761px) {
  .community-page .freq-masthead-id {
    padding-block: clamp(2rem, 4vw, 3rem);
  }

  .community-page .freq-field {
    -webkit-mask-image: linear-gradient(90deg, transparent 22%, #000 62%, #000 100%);
            mask-image: linear-gradient(90deg, transparent 22%, #000 62%, #000 100%);
  }

  /* The port row can breathe once the card is 920px wide. */
  .community-page .freq-ports {
    grid-template-columns: repeat(auto-fit, minmax(104px, 1fr));
  }
}

@media (prefers-reduced-motion: reduce) {
  .community-page .freq-wave i,
  .community-page .freq-field svg > g {
    transition: none !important;
  }
  .community-page .freq-wave i { transform: scaleY(1) !important; }
  .community-page .freq-field svg > g { opacity: 1 !important; }
}

/* -----------------------------------------------------------
   10. THE SCALE

   Three of the five sources were replaced with large originals
   (@the_image_creator3 at 640, bettahai and Miyuki at 400), which
   makes it possible to state the hierarchy in size rather than
   merely imply it. One ladder, applied everywhere:

     300px  Miyuki      — its own record type, the benchmark
     210px  community   — AI ITALY's plate and CROSSXHYPE's disc
     170px  connected   — both profiles, equal to each other

   ai-italy.jpg is still the one small original (150px). It used to be
   treated as a frame rather than a picture -- capped at native size,
   with 28px of padding making up the rest of the 210px -- which left
   the emblem filling 51% of its own plate and 30px of empty ring on
   every side. Every plate on this page now fills its box, and this
   one is no exception: the padding drops to the 6px the .freq-plate
   family already uses and the cap is gone, so the emblem reads 196px
   inside a 210px plate.

   `object-fit` is untouched. The source is 150x150 and the plate is
   square, so `contain` already fills it edge to edge: there is no
   crop to make and `cover` would decide nothing. The price is a 1.31x
   upscale from a 150px original, which is the one thing a larger
   source would buy back -- drop a bigger ai-italy.jpg in its place
   and nothing here needs to change.
   ----------------------------------------------------------- */
.community-page .freq-plate--lg {
  width: clamp(122px, 38vw, 210px);
  padding: 6px;
}

.community-page .freq-disc {
  width: clamp(122px, 38vw, 210px);
}


.community-page .freq-card.is-armed .freq-masthead .freq-plate-scan {
  animation: freq-sweep-anchor .9s ease .3s 1 both;
}

@keyframes freq-sweep-anchor {
  0%   { opacity: 0; transform: translateY(0); }
  14%  { opacity: 1; }
  86%  { opacity: 1; }
  100% { opacity: 0; transform: translateY(210px); }
}

@media (prefers-reduced-motion: reduce) {
}

/* ===========================================================
   11. TYPOGRAPHY — no orphaned letters

   CROSSXHYPE was breaking as "CROSSXHYP / E". The cause was
   `overflow-wrap: anywhere` on the headings, added early to stop a
   long handle from overflowing a narrow card; it also gave the
   browser permission to break any word at any point, and a
   ten-letter name in a squeezed column is exactly where it takes
   that permission.

   The fix is structural rather than a per-viewport override:

     - headings never break inside a word again;
     - the type is fluid and sized against the space it actually
       has, not against the viewport alone;
     - below 560px the masthead stacks, so the title gets the whole
       card width instead of what is left beside a 122px plate.

   Long handles are handled where they belong — in the body copy and
   the metadata rows, which keep `anywhere`.
   =========================================================== */
.community-page h1,
.community-page h2,
.community-page h3,
.community-page .feature-kicker,
.community-page .freq-signal {
  overflow-wrap: normal;
  word-break: normal;
  hyphens: none;
}

/* THE_IMAGE_CREATOR3 is 18 characters with no break opportunity, so
   it gets a tighter fluid ramp than the shorter names. */
.community-page .feature--tic h2 {
  font-size: clamp(1.06rem, 5.6vw, 2.35rem);
  letter-spacing: -.015em;
}

.community-page .freq-masthead h2 {
  font-size: clamp(1.6rem, 7.4vw, 2.9rem);
}

/* Stack the masthead before the title runs out of room. At 560px the
   plate takes 122px and the remaining column can no longer hold
   CROSSXHYPE on one line at a readable size. */
@media (max-width: 559px) {
  .community-page .freq-masthead-id {
    display: grid;
    justify-items: start;
    gap: clamp(.9rem, 4vw, 1.2rem);
  }
}

/* ===========================================================
   12. FEATURE SECTIONS

   THE_IMAGE_CREATOR3 and BettahAI are no longer nested inside their
   community's record: each is a section of its own, tethered to its
   community by the line above it and by its signal code. They carry
   the same weight as Honorable Signals — which is untouched — and
   three different registers:

     THE_IMAGE_CREATOR3 — gallery. Offset outline plates behind the
                          image, crop marks, sampling ticks, a plate
                          tag. Image on the left.
     BETTAHAI           — broadcast. Concentric rings around a round
                          target, a frequency line under the copy
                          carrying the ports. Image on the right.
     MIYUKI             — editorial. Portrait rail and an interview
                          destination. Unchanged.

   Nothing here animates on a loop: the rings and ticks are static
   geometry, and the only movement is the one-shot reveal shared with
   the rest of the page.
   =========================================================== */
.community-page .feature {
  --card-edge: rgba(0, 220, 255, .22);
  --card-accent: #8ff4ff;
  width: min(920px, 100%);
  margin: clamp(1.6rem, 6vw, 2.6rem) auto 0;
  padding-inline: clamp(1.1rem, 5vw, 4rem);
  scroll-margin-top: clamp(96px, 14vw, 118px);
}

/* The tether. A short line dropping from the record above plus the
   code that names the community it belongs to: this is what keeps the
   hierarchy readable now that size no longer states it. */
.community-page .feature-tether {
  display: flex;
  align-items: center;
  gap: .8rem;
  margin: 0 0 clamp(1rem, 4vw, 1.5rem);
}

.community-page .feature-tether-line {
  flex: 0 0 auto;
  width: clamp(28px, 8vw, 64px);
  height: 1px;
  background: linear-gradient(90deg, transparent, var(--card-edge));
}

.community-page .feature-tether-tag {
  color: rgba(143, 244, 255, .62);
  font: 700 .56rem/1.4 var(--page-mono, monospace);
  letter-spacing: .2em;
  text-transform: uppercase;
  overflow-wrap: anywhere;
}

.community-page .feature-body {
  display: grid;
  /* A grid item's automatic minimum is min-content, and THE_IMAGE_CREATOR3
     with no break opportunity had a min-content of 312px — wider than the
     250px track at 320. The column blew out and carried the whole copy
     off-screen with it. Both children are told they may be narrower than
     their contents; the <wbr> in the name does the rest. */
  grid-auto-columns: minmax(0, 1fr);
  gap: clamp(1.4rem, 5vw, 2.4rem);
  padding: clamp(1.3rem, 5vw, 2.2rem);
  border: 1px solid var(--card-edge);
  border-radius: 16px;
  background: var(--feature-bg);
}

.community-page .feature-copy { min-width: 0; }
.community-page .feature-copy > * { margin: 0; }

.community-page .feature-kicker {
  color: var(--card-accent);
  font: 700 .58rem/1.45 var(--page-mono, monospace);
  letter-spacing: .18em;
}

.community-page .feature-copy h2 {
  margin-top: .55rem;
  font-size: clamp(1.7rem, 7vw, 2.6rem);
  color: var(--sa-text, #effcff);
  font-family: var(--page-serif, serif);
  font-weight: 400;
  line-height: 1.08;
}

.community-page .feature-role {
  margin-top: .5rem;
  padding-bottom: 1rem;
  border-bottom: 1px solid var(--card-edge);
  color: var(--page-ink-soft, rgba(214, 240, 252, .74));
  font: 400 .78rem/1.45 var(--page-mono, monospace);
  letter-spacing: .04em;
}

.community-page .feature-copy > p[data-i18n] {
  margin-top: 1rem;
  color: var(--page-ink-soft, rgba(214, 240, 252, .8));
  font-family: var(--page-serif, serif);
  font-size: clamp(1rem, 1.1vw, 1.08rem);
  line-height: 1.72;
}

.community-page .feature-rel {
  color: rgba(214, 240, 252, .72) !important;
  font-style: italic;
}

.community-page .feature-ports { margin-top: clamp(1.2rem, 4vw, 1.7rem); }
.community-page .feature-ports--one { grid-template-columns: minmax(104px, 168px); }

/* --- the plates -------------------------------------------- */
.community-page .feature-plate {
  position: relative;
  margin: 0;
  min-width: 0;
  justify-self: center;
  width: min(320px, 100%);
  aspect-ratio: 1 / 1;
}

.community-page .fp-frame {
  position: absolute;
  inset: 0;
  z-index: 2;
  display: block;
  overflow: hidden;
  background: rgba(2, 7, 14, .7);
}

.community-page .fp-frame img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.community-page .fp-tag {
  position: absolute;
  left: 0;
  right: 0;
  bottom: -1.6rem;
  z-index: 3;
  color: rgba(143, 244, 255, .5);
  font: 400 .52rem/1.4 var(--page-mono, monospace);
  letter-spacing: .2em;
  text-align: center;
}

/* --- THE_IMAGE_CREATOR3: the gallery plate ------------------ */
.community-page .feature--tic {
  --feature-bg:
    radial-gradient(ellipse 90% 70% at 10% 0%, rgba(0, 190, 255, .08), transparent 66%),
    linear-gradient(180deg, rgba(7, 19, 32, .6), rgba(4, 10, 20, .74));
}

.community-page .feature--tic .fp-frame {
  border: 1px solid rgba(120, 230, 255, .5);
  border-radius: 4px;
}

/* Two outlines offset behind the plate: the same image considered
   more than once, which is what a generative archive looks like from
   the outside. Pure CSS, no extra raster. */
.community-page .fp-ghost {
  position: absolute;
  inset: 0;
  z-index: 1;
  border: 1px solid rgba(120, 230, 255, .22);
  border-radius: 4px;
}

.community-page .fp-ghost--a { translate: 14px 14px; }
.community-page .fp-ghost--b { translate: 27px 27px; border-color: rgba(120, 230, 255, .12); }

.community-page .fp-marks i {
  position: absolute;
  z-index: 3;
  width: 14px;
  height: 14px;
  border: 0 solid rgba(190, 246, 255, .8);
}

.community-page .fp-marks i:nth-child(1) { top: -1px; left: -1px; border-top-width: 2px; border-left-width: 2px; }
.community-page .fp-marks i:nth-child(2) { top: -1px; right: -1px; border-top-width: 2px; border-right-width: 2px; }
.community-page .fp-marks i:nth-child(3) { bottom: -1px; left: -1px; border-bottom-width: 2px; border-left-width: 2px; }
.community-page .fp-marks i:nth-child(4) { bottom: -1px; right: -1px; border-bottom-width: 2px; border-right-width: 2px; }

/* Sampling ticks down the left edge of the frame. */
.community-page .fp-sample i {
  position: absolute;
  z-index: 3;
  left: 0;
  width: 9px;
  height: 1px;
  background: rgba(190, 246, 255, .55);
}

.community-page .fp-sample i:nth-child(1) { top: 26%; }
.community-page .fp-sample i:nth-child(2) { top: 50%; width: 15px; }
.community-page .fp-sample i:nth-child(3) { top: 74%; }

/* --- BETTAHAI: the broadcast target ------------------------- */
.community-page .feature--bh {
  --card-edge: rgba(150, 140, 255, .26);
  --card-accent: #bdb2ff;
  --feature-bg:
    radial-gradient(ellipse 90% 70% at 90% 0%, rgba(126, 104, 255, .11), transparent 66%),
    linear-gradient(180deg, rgba(17, 13, 36, .62), rgba(6, 6, 18, .74));
}

.community-page .feature--bh .feature-tether { flex-direction: row-reverse; }
.community-page .feature--bh .feature-tether-line {
  background: linear-gradient(270deg, transparent, var(--card-edge));
}
.community-page .feature--bh .feature-tether-tag { text-align: right; }

.community-page .feature--bh .feature-plate { width: min(300px, 100%); }

.community-page .feature--bh .fp-frame {
  inset: 13%;
  border-radius: 50%;
  border: 1px solid rgba(196, 168, 255, .55);
}

.community-page .fp-ring {
  position: absolute;
  z-index: 1;
  border-radius: 50%;
  border: 1px solid rgba(180, 160, 255, .3);
}

.community-page .fp-ring--a { inset: 0; }
.community-page .fp-ring--b { inset: 6.5%; border-style: dashed; border-color: rgba(180, 160, 255, .2); }
.community-page .fp-ring--c { inset: 24%; border-color: rgba(180, 160, 255, .14); }

.community-page .feature--bh .fp-tag { color: rgba(196, 168, 255, .55); }

/* The frequency line the ports sit on. Forty fixed heights raised
   once when the section is read, then still for good. */
.community-page .feature-wave {
  display: flex;
  align-items: flex-end;
  gap: 2px;
  height: clamp(26px, 7vw, 40px);
  margin-top: clamp(1.2rem, 4vw, 1.7rem);
  padding-bottom: 6px;
  border-bottom: 1px solid var(--card-edge);
  overflow: hidden;
}

.community-page .feature-wave i {
  flex: 1 1 0;
  min-width: 1px;
  border-radius: 1px 1px 0 0;
  background: linear-gradient(180deg, rgba(196, 168, 255, .85), rgba(126, 104, 255, .22));
  transform: scaleY(.05);
  transform-origin: bottom center;
  transition: transform .5s cubic-bezier(.2, 1, .3, 1) var(--wd, 0ms);
}

.community-page .feature.is-armed .feature-wave i { transform: scaleY(1); }

.community-page .feature-wave i:nth-child(5n+1) { height: 38%; }
.community-page .feature-wave i:nth-child(5n+2) { height: 72%; }
.community-page .feature-wave i:nth-child(5n+3) { height: 24%; }
.community-page .feature-wave i:nth-child(5n+4) { height: 90%; }
.community-page .feature-wave i:nth-child(5n+5) { height: 52%; }
.community-page .feature-wave i:nth-child(7n+1) { height: 30%; }
.community-page .feature-wave i:nth-child(7n+4) { height: 64%; }
.community-page .feature-wave i:nth-child(11n+3) { height: 82%; }
.community-page .feature-wave i:nth-child(13n+7) { height: 18%; }

.community-page .feature-wave i:nth-child(1)  { --wd:  20ms; }
.community-page .feature-wave i:nth-child(2)  { --wd:  40ms; }
.community-page .feature-wave i:nth-child(3)  { --wd:  60ms; }
.community-page .feature-wave i:nth-child(4)  { --wd:  80ms; }
.community-page .feature-wave i:nth-child(5)  { --wd: 100ms; }
.community-page .feature-wave i:nth-child(6)  { --wd: 120ms; }
.community-page .feature-wave i:nth-child(7)  { --wd: 140ms; }
.community-page .feature-wave i:nth-child(8)  { --wd: 160ms; }
.community-page .feature-wave i:nth-child(9)  { --wd: 180ms; }
.community-page .feature-wave i:nth-child(10) { --wd: 200ms; }
.community-page .feature-wave i:nth-child(n+11) { --wd: 220ms; }
.community-page .feature-wave i:nth-child(n+16) { --wd: 280ms; }
.community-page .feature-wave i:nth-child(n+21) { --wd: 340ms; }
.community-page .feature-wave i:nth-child(n+26) { --wd: 400ms; }
.community-page .feature-wave i:nth-child(n+31) { --wd: 460ms; }
.community-page .feature-wave i:nth-child(n+36) { --wd: 520ms; }

/* One sweep across each plate when its section is first read. */
.community-page .feature.is-armed .freq-plate-scan {
  animation: freq-sweep-feature 1s ease .35s 1 both;
}

@keyframes freq-sweep-feature {
  0%   { opacity: 0; transform: translateY(0); }
  14%  { opacity: 1; }
  86%  { opacity: 1; }
  100% { opacity: 0; transform: translateY(320px); }
}

/* --- from tablet up: the two compositions mirror each other -- */
@media (min-width: 761px) {
  .community-page .feature-body {
    align-items: center;
    column-gap: clamp(1.8rem, 4vw, 3rem);
  }

  /* gallery: plate leads */
  .community-page .feature--tic .feature-body {
    grid-template-columns: clamp(240px, 30vw, 300px) 1fr;
  }

  /* broadcast: copy leads, plate answers on the right */
  .community-page .feature--bh .feature-body {
    grid-template-columns: 1fr clamp(240px, 30vw, 300px);
  }

  .community-page .feature-plate { justify-self: stretch; width: 100%; }
  .community-page .feature--bh .feature-plate { width: 100%; }

  .community-page .fp-tag { bottom: -1.8rem; }
}

/* The offset outlines need room to the right and below the plate, and
   at the narrow end there is none: they collapse to a single, closer
   echo rather than overflowing the card. */
@media (max-width: 760px) {
  /* A percentage here was resolving against the shrunken grid track and
     left the plate at 169px while its siblings sat at 206 and 244. It is
     stated in absolute terms instead, capped by the track. */
  .community-page .feature-plate { width: min(280px, 100%); }
  .community-page .fp-ghost--a { translate: 9px 9px; }
  .community-page .fp-ghost--b { translate: 18px 18px; }
  .community-page .feature-body { padding-bottom: clamp(2.4rem, 8vw, 3rem); }
}

@media (prefers-reduced-motion: reduce) {
  .community-page .feature-wave i {
    transition: none !important;
    transform: scaleY(1) !important;
  }
  .community-page .feature.is-armed .freq-plate-scan { animation: none !important; }
}

/* ===========================================================
   13. NEURAL WINDOW

   A feed opened onto a white, clinical system, set against a page
   that is dark and blue. The contrast does the work, so the plate
   itself stays almost bare: a hairline, four corner brackets, three
   small readouts in the corners.

   The box carries 312/179 — the ratio measured from the stream, not
   16:9 — so poster and video occupy the identical rectangle and
   nothing moves when one replaces the other.
   =========================================================== */
.community-page .page-hero--neural {
  width: min(1320px, 100%);
  display: grid;
  gap: clamp(1.4rem, 5vw, 2.2rem);
}

.community-page .hero-lead > .page-hero-kicker { margin-bottom: .8rem; }

.community-page .hero-lead h1 {
  margin: 0;
  color: var(--sa-text, #effcff);
  font-family: var(--page-serif);
  font-size: clamp(2.1rem, 5vw, 3.9rem);
  font-weight: 400;
  line-height: 1.05;
  letter-spacing: -.02em;
  text-wrap: balance;
  text-shadow: 0 0 30px rgba(0, 220, 255, .13);
}

.community-page .hero-body { max-width: var(--page-measure); }

/* --- the plate --------------------------------------------- */
.community-page .neural-window {
  margin: 0;
  min-width: 0;
}

.community-page .nw-plate {
  position: relative;
  overflow: hidden;
  /* measured from the file: 1248 x 716 */
  aspect-ratio: 312 / 179;
  border: 1px solid rgba(150, 236, 255, .34);
  border-radius: 10px;
  background: #eef4f8;
  box-shadow:
    0 0 0 1px rgba(0, 0, 0, .5),
    0 26px 70px rgba(0, 0, 0, .55),
    0 0 90px rgba(0, 190, 255, .12);
}

.community-page .nw-poster,
.community-page .nw-poster img,
.community-page .nw-video {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Alice sits centre-right and the brain mass fills the left. Holding
     the frame centred keeps both inside the crop at every width. */
  object-position: 50% 50%;
}

.community-page .nw-video {
  z-index: 1;
  opacity: 0;
  transition: opacity .5s ease;
}

/* Raised only once the decoder actually has frames, so the poster is
   never replaced by an empty black rectangle. */
.community-page .nw-plate.is-playing .nw-video { opacity: 1; }

/* --- corner brackets and readouts -------------------------- */
.community-page .nw-marks i {
  position: absolute;
  z-index: 4;
  width: 18px;
  height: 18px;
  border: 0 solid rgba(0, 190, 255, .85);
  pointer-events: none;
}

.community-page .nw-marks i:nth-child(1) { top: 8px; left: 8px; border-top-width: 2px; border-left-width: 2px; }
.community-page .nw-marks i:nth-child(2) { top: 8px; right: 8px; border-top-width: 2px; border-right-width: 2px; }
.community-page .nw-marks i:nth-child(3) { bottom: 8px; left: 8px; border-bottom-width: 2px; border-left-width: 2px; }
.community-page .nw-marks i:nth-child(4) { bottom: 8px; right: 8px; border-bottom-width: 2px; border-right-width: 2px; }

.community-page .nw-tag {
  position: absolute;
  z-index: 4;
  margin: 0;
  padding: .28rem .5rem;
  border-radius: 3px;
  background: rgba(4, 12, 22, .72);
  color: rgba(190, 246, 255, .92);
  font: 400 .5rem/1 var(--page-mono, monospace);
  letter-spacing: .18em;
  white-space: nowrap;
  pointer-events: none;
}

.community-page .nw-tag b { color: #7ff0ff; font-weight: 700; }

.community-page .nw-tag--link { top: 14px; left: 34px; }
.community-page .nw-tag--node { top: 14px; right: 34px; }
.community-page .nw-tag--bus  { bottom: 14px; left: 34px; }

/* ===========================================================
   14. ELECTRICAL ACTIVITY

   Sporadic, never continuous. Every arc and pulse below is a
   one-shot animation with iteration-count 1, armed by a randomised
   timer in v99_community.js that exists only while the window is on
   screen. At most one event runs at a time.

   Nothing touches the picture itself: the arcs live in the cable
   region on the left and along the bottom, the displacement applies
   to the brackets and readouts, and Alice — centre-right — is never
   covered or deformed.
   =========================================================== */
.community-page .nw-arcs {
  position: absolute;
  inset: 0;
  z-index: 3;
  width: 100%;
  height: 100%;
  pointer-events: none;
  /* The right half of the frame holds the face. The overlay is faded
     out before it can reach it. */
  -webkit-mask-image: linear-gradient(90deg, #000 0%, #000 42%, transparent 62%);
          mask-image: linear-gradient(90deg, #000 0%, #000 42%, transparent 62%);
}

.community-page .nw-arc {
  fill: none;
  stroke: #7ff4ff;
  stroke-width: 1.4;
  stroke-linecap: round;
  stroke-linejoin: round;
  vector-effect: non-scaling-stroke;
  opacity: 0;
  filter: drop-shadow(0 0 4px rgba(0, 220, 255, .8));
}

.community-page .nw-track { fill: none; stroke: none; }

/* Peak opacity is held well below full white: a discharge, not a
   flash. 240ms, once. */
.community-page .nw-arc.is-firing {
  animation: nw-arc 240ms steps(4, end) 1 both;
}

@keyframes nw-arc {
  0%   { opacity: 0; }
  25%  { opacity: .82; }
  50%  { opacity: .28; }
  75%  { opacity: .7; }
  100% { opacity: 0; }
}

/* Pulses travelling along a cable. offset-path follows the same
   curves the tracks describe; they are transform-only and cheap. */
.community-page .nw-pulse {
  position: absolute;
  z-index: 3;
  top: 0;
  left: 0;
  width: 5px;
  height: 5px;
  margin: -2.5px 0 0 -2.5px;
  border-radius: 50%;
  background: #b9f7ff;
  box-shadow: 0 0 8px 2px rgba(0, 220, 255, .7);
  opacity: 0;
  offset-distance: 0%;
  pointer-events: none;
}

.community-page .nw-pulse--1 { offset-path: path("M6 60 C48 66 86 84 132 100"); }
.community-page .nw-pulse--2 { offset-path: path("M14 148 C56 140 92 128 140 132"); }
.community-page .nw-pulse--3 { offset-path: path("M4 104 C40 110 74 122 116 142"); }

.community-page .nw-pulse.is-firing {
  animation: nw-pulse 900ms cubic-bezier(.35, 0, .65, 1) 1 both;
}

@keyframes nw-pulse {
  0%   { offset-distance: 0%;   opacity: 0; }
  12%  { opacity: .9; }
  88%  { opacity: .9; }
  100% { offset-distance: 100%; opacity: 0; }
}

/* A single sync sweep across the plate. */
.community-page .nw-sync {
  position: absolute;
  z-index: 2;
  left: 0;
  right: 0;
  top: 0;
  height: 1px;
  background: linear-gradient(90deg, transparent, rgba(0, 210, 255, .55) 30%, rgba(190, 246, 255, .8), rgba(0, 210, 255, .55) 70%, transparent);
  opacity: 0;
  pointer-events: none;
}

.community-page .nw-sync.is-firing {
  animation: nw-sync 620ms linear 1 both;
}

@keyframes nw-sync {
  0%   { opacity: 0; transform: translateY(0); }
  10%  { opacity: .85; }
  90%  { opacity: .5; }
  100% { opacity: 0; transform: translateY(var(--nw-h, 380px)); }
}

/* Interface displacement. Two pixels on the brackets and readouts,
   nothing else — the frame twitches, the image does not. */
.community-page .nw-plate.is-glitching .nw-marks i,
.community-page .nw-plate.is-glitching .nw-tag {
  animation: nw-shift 200ms steps(3, end) 1 both;
}

@keyframes nw-shift {
  0%   { transform: translate(0, 0); }
  33%  { transform: translate(-2px, 1px); }
  66%  { transform: translate(2px, -1px); }
  100% { transform: translate(0, 0); }
}

/* ===========================================================
   15. CABLE BRIDGE

   The gap between the hero and the map is where the cables lose
   their organic character. The container is the gap: no absolute
   positioning across sections, no negative margins to maintain.
   =========================================================== */
.community-page .cable-bridge {
  position: relative;
  width: min(1320px, 100%);
  height: clamp(96px, 22vw, 190px);
  margin: 0 auto;
  padding-inline: clamp(1.1rem, 5vw, 4rem);
  pointer-events: none;
}

.community-page .cable-bridge svg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: visible;
}

.community-page .cb-set--wide { display: none; }

.community-page .cb-line {
  fill: none;
  stroke: rgba(120, 230, 255, .42);
  stroke-width: 1;
  stroke-linecap: round;
  vector-effect: non-scaling-stroke;
  stroke-dasharray: 1 1;
  stroke-dashoffset: 1;
  transition: stroke-dashoffset 1.1s cubic-bezier(.4, 0, .2, 1) var(--cd, 0ms);
}

.community-page .cb-line--1 { --cd: 120ms; stroke: rgba(150, 236, 255, .5); }
.community-page .cb-line--2 { --cd: 320ms; }
.community-page .cb-line--3 { --cd: 520ms; stroke: rgba(120, 230, 255, .3); }

.community-page .cable-bridge.is-live .cb-line { stroke-dashoffset: 0; }
.community-page .cable-bridge.is-instant .cb-line { transition: none; }

/* ===========================================================
   16. SIGNAL SPINE // 4072

   A cable down the right edge, not a scrollbar. It is fixed, it is
   aria-hidden, the rail takes no pointer events, and this module
   binds no wheel, touch or key handler anywhere. The native
   scrollbar and every input method keep working untouched.
   =========================================================== */
.community-page + .signal-spine,
.signal-spine {
  position: fixed;
  z-index: 60;
  right: max(6px, env(safe-area-inset-right));
  top: clamp(96px, 16vh, 150px);
  bottom: clamp(56px, 12vh, 120px);
  width: 2px;
  pointer-events: none;
}

.signal-spine .ss-rail {
  position: absolute;
  inset: 0;
  border-radius: 2px;
  background: linear-gradient(180deg,
    rgba(120, 230, 255, .06),
    rgba(120, 230, 255, .18) 12%,
    rgba(120, 230, 255, .18) 88%,
    rgba(120, 230, 255, .06));
}

/* The acquired portion. transform-only, so it composites. */
.signal-spine .ss-acquired {
  position: absolute;
  inset: 0;
  border-radius: 2px;
  background: linear-gradient(180deg, rgba(0, 200, 255, .75), rgba(120, 230, 255, .35));
  transform-origin: top center;
  transform: scaleY(var(--ss-progress, 0));
}

/* The pulse runs slightly ahead of the acquired edge. */
.signal-spine .ss-pulse {
  position: absolute;
  left: -2px;
  right: -2px;
  height: 42px;
  border-radius: 3px;
  background: linear-gradient(180deg, transparent, #9ff6ff 55%, transparent);
  box-shadow: 0 0 12px 2px rgba(0, 220, 255, .55);
  top: 0;
  transform: translateY(calc(var(--ss-progress, 0) * (100cqh - 42px)));
}

/* --- nodes -------------------------------------------------- */
.signal-spine .ss-nodes {
  position: absolute;
  inset: 0;
  display: block;
}

.signal-spine .ss-node {
  position: absolute;
  right: 0;
  top: var(--ss-pos, 0%);
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: .5rem;
  width: max-content;
  translate: 0 -50%;
  pointer-events: auto;
  /* the hit area is the dot, kept comfortable without widening the rail */
  padding: 10px 0 10px 10px;
}

.signal-spine .ss-node i {
  flex: 0 0 auto;
  width: 6px;
  height: 6px;
  margin-right: -2px;
  border-radius: 50%;
  background: rgba(4, 12, 22, .95);
  border: 1px solid rgba(120, 230, 255, .55);
  transition: background .3s ease, border-color .3s ease, box-shadow .3s ease, transform .3s ease;
}

.signal-spine .ss-node b {
  order: -1;
  padding: .22rem .45rem;
  border-radius: 3px;
  background: rgba(3, 10, 20, .9);
  color: rgba(190, 246, 255, .9);
  font: 400 .5rem/1.2 var(--page-mono, monospace);
  letter-spacing: .16em;
  white-space: nowrap;
  opacity: 0;
  translate: 6px 0;
  transition: opacity .28s ease, translate .28s ease;
}

/* Reached: the node acquires and stays acquired. */
.signal-spine .ss-node.is-reached i {
  background: #7ff0ff;
  border-color: #b9f7ff;
  box-shadow: 0 0 10px 2px rgba(0, 220, 255, .6);
}

/* One short acquisition flicker on arrival, then stable. */
.signal-spine .ss-node.is-arriving i {
  animation: ss-acquire 520ms ease 1 both;
}

@keyframes ss-acquire {
  0%   { transform: scale(1); }
  30%  { transform: scale(2.1); }
  55%  { transform: scale(1.25); }
  100% { transform: scale(1); }
}

/* Labels only when they are useful: current section, hover, focus. */
.signal-spine .ss-node.is-current b,
.signal-spine .ss-node:hover b,
.signal-spine .ss-node:focus-visible b {
  opacity: 1;
  translate: 0 0;
}

/* Miyuki is an Honorable Signal rather than a community: its marker is
   a ring instead of a filled node. */
.signal-spine .ss-node--archive i {
  width: 8px;
  height: 8px;
  background: transparent;
  border-width: 1px;
  border-color: rgba(214, 196, 255, .8);
}

.signal-spine .ss-node--archive.is-reached i {
  background: transparent;
  border-color: #d9c7ff;
  box-shadow: 0 0 10px 2px rgba(170, 140, 255, .55);
}

.signal-spine .ss-node--archive b { color: rgba(224, 210, 255, .92); }

.signal-spine .ss-node--end i { width: 4px; height: 4px; }

/* --- the tail ---------------------------------------------- */
.signal-spine .ss-tail {
  position: absolute;
  top: 100%;
  right: -3px;
  display: grid;
  justify-items: center;
  gap: .3rem;
  padding-top: .55rem;
  opacity: .55;
}

.signal-spine .ss-tail svg {
  width: 12px;
  height: 12px;
  fill: none;
  stroke: rgba(120, 230, 255, .7);
  stroke-width: 1.6;
  stroke-linecap: round;
}

.signal-spine .ss-tail b {
  color: rgba(143, 244, 255, .6);
  font: 400 .46rem/1 var(--page-mono, monospace);
  letter-spacing: .12em;
  writing-mode: vertical-rl;
}

/* --- scroll-driven progress -------------------------------- */
/* Where scroll timelines exist, the rail is driven entirely by the
   compositor: no listener, no rAF, nothing on the main thread. */
@supports (animation-timeline: scroll()) {
  .signal-spine .ss-acquired,
  .signal-spine .ss-pulse {
    animation-duration: 1s;
    animation-timing-function: linear;
    animation-fill-mode: both;
    animation-timeline: scroll(root block);
  }

  .signal-spine .ss-acquired { animation-name: ss-fill; }
  .signal-spine .ss-pulse { animation-name: ss-travel; }

  @keyframes ss-fill {
    from { transform: scaleY(0); }
    to   { transform: scaleY(1); }
  }

  @keyframes ss-travel {
    from { transform: translateY(0); }
    to   { transform: translateY(calc(100% - 42px)); }
  }
}

/* Without them, v99_community.js writes --ss-progress from a
   rAF-coalesced scroll listener. That is the only place a scroll
   listener exists in this feature, and only on that path. */
.signal-spine .ss-pulse { top: 0; }

html.ss-fallback .signal-spine .ss-pulse {
  transform: translateY(calc(var(--ss-progress, 0) * (var(--ss-height, 400px) - 42px)));
}

/* --- narrow ------------------------------------------------- */
@media (max-width: 760px) {
  .signal-spine {
    width: 1px;
    right: max(4px, env(safe-area-inset-right));
    top: clamp(84px, 14vh, 120px);
  }

  .signal-spine .ss-node i { width: 5px; height: 5px; }
  .signal-spine .ss-node--archive i { width: 7px; height: 7px; }
  .signal-spine .ss-node--end i { width: 3px; height: 3px; }

  /* Labels stay out of the way on touch: only the current node shows
     one, and hover does not exist here. */
  .signal-spine .ss-node:hover b { opacity: 0; }
  .signal-spine .ss-node.is-current b { opacity: 1; translate: 0 0; }
  .signal-spine .ss-tail svg { width: 10px; height: 10px; }
}

/* ===========================================================
   17. WIDE LAYOUT — text left, Neural Window right
   =========================================================== */
@media (min-width: 901px) {
  .community-page .page-hero--neural {
    grid-template-columns: minmax(0, 42fr) minmax(0, 58fr);
    grid-template-areas:
      "lead   window"
      "body   window";
    align-items: start;
    column-gap: clamp(1.8rem, 4vw, 3.2rem);
    row-gap: clamp(1.2rem, 3vw, 2rem);
  }

  .community-page .hero-lead { grid-area: lead; }
  .community-page .hero-body { grid-area: body; }
  .community-page .neural-window { grid-area: window; align-self: center; }

  .community-page .cb-set--wide { display: block; }
  .community-page .cb-set--tall { display: none; }
}

/* Narrow: the plate reaches for the edges of the viewport so it has
   real presence instead of becoming a thumbnail inside the padding. */
@media (max-width: 900px) {
  .community-page .neural-window {
    width: calc(100% + 2 * clamp(1.1rem, 5vw, 4rem) - 16px);
    margin-inline: calc(-1 * clamp(1.1rem, 5vw, 4rem) + 8px);
  }

  .community-page .nw-plate { border-radius: 8px; }
  .community-page .nw-tag { font-size: .44rem; letter-spacing: .12em; padding: .22rem .4rem; }
  .community-page .nw-tag--link { top: 10px; left: 26px; }
  .community-page .nw-tag--node { top: 10px; right: 26px; }
  .community-page .nw-tag--bus  { bottom: 10px; left: 26px; }
  .community-page .nw-marks i { width: 14px; height: 14px; }
}

/* At the very narrowest the bus readout and the link readout would
   collide along the bottom edge; the bus one steps out. */
@media (max-width: 400px) {
  .community-page .nw-tag--bus { display: none; }
}

/* ===========================================================
   18. REDUCED MOTION

   The video is never started and never fetched (v99_community.js
   returns before touching it), so the still frame is what the page
   shows. No arcs, no pulses, no glitch, no timer. The cables arrive
   already drawn and the spine is present but static.
   =========================================================== */
@media (prefers-reduced-motion: reduce) {
  .community-page .nw-video { display: none; }
  .community-page .nw-arcs,
  .community-page .nw-pulse,
  .community-page .nw-sync { display: none; }

  .community-page .nw-plate.is-glitching .nw-marks i,
  .community-page .nw-plate.is-glitching .nw-tag { animation: none !important; }

  .community-page .cb-line {
    stroke-dashoffset: 0 !important;
    transition: none !important;
  }

  .signal-spine .ss-acquired,
  .signal-spine .ss-pulse,
  .signal-spine .ss-node i,
  .signal-spine .ss-node b {
    transition: none !important;
    animation: none !important;
  }

  .signal-spine .ss-pulse { display: none; }
  .signal-spine .ss-node.is-arriving i { animation: none !important; }
}

/* ===========================================================
   19. VISIBILITY PASS

   The first implementation was too quiet to read: correct, cheap,
   and almost invisible. Everything below raises amplitude without
   raising cost — the added work is opacity, transform and
   stroke-dashoffset, which is what the compositor already handles.

   Three things change:
     · the Neural Window discharges become legible;
     · the cables actually carry something down to the map;
     · the images answer the cursor.
   =========================================================== */

/* -----------------------------------------------------------
   19a. Neural Window — louder discharges
   ----------------------------------------------------------- */

/* The mask used to cut the overlay off at 62% of the width, which
   removed most of the cable field along with the face. The cables
   run much further right than that; only Alice needs protecting. */
.community-page .nw-arcs {
  -webkit-mask-image: linear-gradient(90deg, #000 0%, #000 58%, transparent 76%);
          mask-image: linear-gradient(90deg, #000 0%, #000 58%, transparent 76%);
}

.community-page .nw-arc {
  stroke-width: 2.2;
  filter: drop-shadow(0 0 6px rgba(0, 230, 255, .95))
          drop-shadow(0 0 14px rgba(0, 190, 255, .55));
}

/* Longer, brighter, and it lingers long enough to be seen. */
.community-page .nw-arc.is-firing {
  animation: nw-arc 520ms steps(6, end) 1 both;
}

@keyframes nw-arc {
  0%   { opacity: 0;   stroke-width: 1.2; }
  15%  { opacity: 1;   stroke-width: 3.4; }
  30%  { opacity: .45; stroke-width: 2; }
  45%  { opacity: 1;   stroke-width: 3; }
  62%  { opacity: .6;  stroke-width: 2.2; }
  80%  { opacity: .9;  stroke-width: 2.6; }
  100% { opacity: 0;   stroke-width: 1.2; }
}

/* A halo bloom under the arc, so a discharge lights its surroundings
   instead of being a hairline on a bright plate. */
.community-page .nw-flash {
  position: absolute;
  z-index: 2;
  width: 46%;
  aspect-ratio: 1;
  left: -6%;
  top: 22%;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(0, 225, 255, .5), rgba(0, 190, 255, .16) 45%, transparent 70%);
  opacity: 0;
  mix-blend-mode: screen;
  pointer-events: none;
}

.community-page .nw-flash.is-firing {
  animation: nw-flash 620ms ease-out 1 both;
}

@keyframes nw-flash {
  0%   { opacity: 0;   transform: scale(.7); }
  18%  { opacity: .95; transform: scale(1); }
  46%  { opacity: .35; }
  64%  { opacity: .7; }
  100% { opacity: 0;   transform: scale(1.15); }
}

/* Pulses: bigger, brighter, with a trail behind them. */
.community-page .nw-pulse {
  width: 9px;
  height: 9px;
  margin: -4.5px 0 0 -4.5px;
  background: #e6fdff;
  box-shadow:
    0 0 10px 3px rgba(0, 230, 255, .95),
    0 0 26px 8px rgba(0, 190, 255, .45);
}

.community-page .nw-pulse.is-firing {
  animation: nw-pulse 1150ms cubic-bezier(.3, 0, .5, 1) 1 both;
}

@keyframes nw-pulse {
  0%   { offset-distance: 0%;   opacity: 0; transform: scale(.4); }
  10%  { opacity: 1; transform: scale(1.25); }
  50%  { transform: scale(1); }
  90%  { opacity: 1; }
  100% { offset-distance: 100%; opacity: 0; transform: scale(.5); }
}

/* The cable the pulse runs on lights up under it. */
.community-page .nw-track {
  stroke: rgba(0, 225, 255, 0);
  stroke-width: 2;
  vector-effect: non-scaling-stroke;
  transition: stroke .3s ease;
}

.community-page .nw-track.is-lit {
  stroke: rgba(0, 225, 255, .5);
  filter: drop-shadow(0 0 6px rgba(0, 220, 255, .7));
}

/* The sweep reads as a scan now rather than a hairline. */
.community-page .nw-sync {
  height: 3px;
  background: linear-gradient(90deg, transparent, rgba(0, 225, 255, .8) 20%, #ffffff 50%, rgba(0, 225, 255, .8) 80%, transparent);
  box-shadow: 0 0 18px 4px rgba(0, 220, 255, .55);
}

.community-page .nw-sync.is-firing {
  animation: nw-sync 900ms cubic-bezier(.4, 0, .6, 1) 1 both;
}

@keyframes nw-sync {
  0%   { opacity: 0; transform: translateY(0) scaleY(.4); }
  8%   { opacity: 1; transform: translateY(4%) scaleY(1); }
  92%  { opacity: .9; }
  100% { opacity: 0; transform: translateY(var(--nw-h, 380px)) scaleY(.4); }
}

/* Interface displacement: further, and the readouts flicker with it. */
@keyframes nw-shift {
  0%   { transform: translate(0, 0);      opacity: 1; }
  20%  { transform: translate(-4px, 2px); opacity: .35; }
  40%  { transform: translate(4px, -2px); opacity: 1; }
  60%  { transform: translate(-2px, -1px); opacity: .5; }
  80%  { transform: translate(3px, 1px);  opacity: 1; }
  100% { transform: translate(0, 0);      opacity: 1; }
}

.community-page .nw-plate.is-glitching .nw-marks i,
.community-page .nw-plate.is-glitching .nw-tag {
  animation: nw-shift 340ms steps(5, end) 1 both;
}

/* A burst of coordinates, fired with the other events. */
.community-page .nw-burst {
  position: absolute;
  z-index: 4;
  left: 34px;
  bottom: 38px;
  margin: 0;
  color: #b9f7ff;
  font: 400 .48rem/1.5 var(--page-mono, monospace);
  letter-spacing: .14em;
  text-shadow: 0 0 8px rgba(0, 220, 255, .9);
  opacity: 0;
  pointer-events: none;
  white-space: pre;
}

.community-page .nw-burst.is-firing {
  animation: nw-burst 1400ms steps(1, end) 1 both;
}

@keyframes nw-burst {
  0%   { opacity: 0; }
  8%   { opacity: .95; }
  22%  { opacity: .3; }
  36%  { opacity: .95; }
  84%  { opacity: .8; }
  100% { opacity: 0; }
}

/* The one continuous thing on the page: the ACTIVE indicator breathes.
   Two opacity keyframes on a 7px dot — the cheapest possible way to
   say the link is live rather than frozen. */
.community-page .nw-tag--link b::after {
  content: "";
  display: inline-block;
  width: 6px;
  height: 6px;
  margin-left: .4rem;
  border-radius: 50%;
  background: #7ff0ff;
  box-shadow: 0 0 8px 2px rgba(0, 220, 255, .8);
  vertical-align: middle;
  animation: nw-breathe 2.6s ease-in-out infinite;
}

@keyframes nw-breathe {
  0%, 100% { opacity: .35; }
  50%      { opacity: 1; }
}

/* -----------------------------------------------------------
   19b. Cable Bridge and map — something actually travels
   ----------------------------------------------------------- */

/* A short dash sent down the same path the cable describes. No
   offset-path, no second geometry to keep in sync: the pulse is the
   cable, drawn 6% at a time. */
.community-page .cb-pulse,
.community-page .freq-pulse {
  fill: none;
  stroke: #d9fbff;
  stroke-width: 2.4;
  stroke-linecap: round;
  vector-effect: non-scaling-stroke;
  stroke-dasharray: .06 .94;
  stroke-dashoffset: 1;
  opacity: 0;
  filter: drop-shadow(0 0 7px rgba(0, 230, 255, .95));
}

.community-page .cb-pulse.is-firing,
.community-page .freq-pulse.is-firing {
  animation: cb-travel 1500ms cubic-bezier(.4, 0, .55, 1) 1 both;
}

@keyframes cb-travel {
  0%   { stroke-dashoffset: 1;    opacity: 0; }
  10%  { opacity: 1; }
  85%  { opacity: 1; }
  100% { stroke-dashoffset: -.06; opacity: 0; }
}

/* The cables themselves read brighter once drawn. */
.community-page .cb-line {
  stroke: rgba(140, 234, 255, .58);
  stroke-width: 1.3;
}

.community-page .cb-line--1 { stroke: rgba(170, 242, 255, .68); }
.community-page .cb-line--3 { stroke: rgba(140, 234, 255, .42); }

/* Map: a lit branch should be unmistakable. */
.community-page .freq-line.is-linked {
  stroke: #d9fbff;
  stroke-width: 1.6;
  filter: drop-shadow(0 0 6px rgba(0, 225, 255, .8));
}

.community-page .freq-line--secondary.is-linked {
  stroke: rgba(190, 246, 255, .85);
  stroke-width: 1.1;
}

.community-page .freq-node.is-linked .freq-dot {
  box-shadow:
    0 0 0 6px rgba(0, 217, 255, .18),
    0 0 22px 6px rgba(0, 220, 255, .85);
  transform: scale(1.25);
}

/* The active node keeps a slow pulse while its card is being read.
   One transform, one element at a time. */
.community-page .freq-node.is-linked .freq-dot {
  animation: freq-node-pulse 2.4s ease-in-out infinite;
}

@keyframes freq-node-pulse {
  0%, 100% { box-shadow: 0 0 0 5px rgba(0, 217, 255, .14), 0 0 18px 4px rgba(0, 220, 255, .6); }
  50%      { box-shadow: 0 0 0 8px rgba(0, 217, 255, .06), 0 0 30px 9px rgba(0, 220, 255, .95); }
}

/* SIGNAL ACQUIRED arrives instead of merely appearing. */
.community-page .freq-state--acquired {
  font-weight: 700;
}

.community-page .freq-map[data-state="acquired"] .freq-state--acquired {
  animation: freq-acquired 900ms steps(3, end) 1 both;
}

@keyframes freq-acquired {
  0%   { opacity: 0; letter-spacing: .5em; }
  30%  { opacity: 1; letter-spacing: .2em; }
  45%  { opacity: .4; }
  60%  { opacity: 1; }
  100% { opacity: 1; letter-spacing: .2em; }
}

/* Spine: a brighter head on the pulse. */
.signal-spine .ss-pulse {
  height: 56px;
  background: linear-gradient(180deg, transparent, rgba(0, 225, 255, .6) 40%, #e6fdff 70%, transparent);
  box-shadow: 0 0 16px 3px rgba(0, 220, 255, .8);
}

.signal-spine .ss-node.is-current i {
  box-shadow: 0 0 0 4px rgba(0, 217, 255, .16), 0 0 16px 5px rgba(0, 220, 255, .9);
}

/* -----------------------------------------------------------
   19c. Hover on the images

   One overlay language reused by every plate on the page: a
   diagonal sweep, a cyan lift, brackets that snap in, and a small
   readout. Everything is opacity and transform, and it only exists
   while the pointer is on the element.
   ----------------------------------------------------------- */
/* .fp-frame is deliberately absent from this list: it is
   `position: absolute; inset: 0` inside its plate, and setting it to
   relative here is what knocked the BettahAI and THE_IMAGE_CREATOR3
   compositions out of place. It gets its own rule further down. */
.community-page .freq-plate,
.community-page .honorable-portrait {
  position: relative;
  isolation: isolate;
  transition: box-shadow .35s ease, border-color .35s ease;
}

.community-page .fp-frame {
  transition: box-shadow .35s ease, border-color .35s ease;
}

.community-page .freq-plate img,
.community-page .fp-frame img,
.community-page .honorable-portrait img {
  transition: transform .55s cubic-bezier(.2, .7, .3, 1), filter .4s ease;
}

/* the sweep */
.community-page .freq-plate::after,
.community-page .fp-frame::after,
.community-page .honorable-portrait::after {
  content: "";
  position: absolute;
  inset: -40%;
  z-index: 3;
  background: linear-gradient(115deg,
    transparent 38%,
    rgba(190, 246, 255, .05) 46%,
    rgba(0, 230, 255, .42) 50%,
    rgba(190, 246, 255, .05) 54%,
    transparent 62%);
  transform: translateX(-120%);
  opacity: 0;
  pointer-events: none;
}

/* the readout */
.community-page .freq-plate::before,
.community-page .fp-frame::before,
.community-page .honorable-portrait::before {
  content: "SIGNAL LINKED";
  position: absolute;
  z-index: 4;
  left: 0;
  right: 0;
  bottom: 0;
  padding: .3rem .4rem;
  background: linear-gradient(180deg, transparent, rgba(2, 10, 20, .92));
  color: #b9f7ff;
  font: 700 .46rem/1.3 var(--page-mono, monospace);
  letter-spacing: .18em;
  text-align: center;
  opacity: 0;
  transform: translateY(60%);
  transition: opacity .3s ease, transform .3s cubic-bezier(.2, 1, .3, 1);
  pointer-events: none;
}

.community-page .honorable-portrait::before { content: "OPEN ARCHIVE RECORD"; }
.community-page .fp-frame::before { content: "CONNECTED FREQUENCY"; }

/* --- the hover state ---------------------------------------- */
.community-page .freq-plate:hover,
.community-page .fp-frame:hover,
.community-page .honorable-portrait:hover,
.community-page a:hover .freq-plate,
.community-page a:focus-visible .freq-plate {
  border-color: rgba(150, 236, 255, .9);
  box-shadow:
    0 0 0 1px rgba(0, 225, 255, .5),
    0 0 34px rgba(0, 220, 255, .38),
    0 20px 44px rgba(0, 0, 0, .5);
}

/* The zoom itself moved to section 29, where it multiplies the
   plate's own base scale instead of overwriting the transform. Only
   the colour response stays here. */
.community-page .freq-plate:hover img,
.community-page .fp-frame:hover img,
.community-page .honorable-portrait:hover img {
  filter: saturate(1.15) contrast(1.04);
}

.community-page .freq-plate:hover::after,
.community-page .fp-frame:hover::after,
.community-page .honorable-portrait:hover::after {
  animation: hv-sweep 750ms cubic-bezier(.35, 0, .3, 1) 1 both;
}

@keyframes hv-sweep {
  0%   { transform: translateX(-120%); opacity: 0; }
  12%  { opacity: 1; }
  88%  { opacity: 1; }
  100% { transform: translateX(120%);  opacity: 0; }
}

.community-page .freq-plate:hover::before,
.community-page .fp-frame:hover::before,
.community-page .honorable-portrait:hover::before {
  opacity: 1;
  transform: translateY(0);
}

/* brackets snap in on the feature plates, which already own a set */
.community-page .feature-plate:hover .fp-marks i {
  border-color: #d9fbff;
  transition: border-color .25s ease;
}

.community-page .feature-plate:hover .fp-ghost--a { translate: 18px 18px; }
.community-page .feature-plate:hover .fp-ghost--b { translate: 34px 34px; }
.community-page .fp-ghost { transition: translate .45s cubic-bezier(.2, 1, .3, 1); }

/* the CROSSXHYPE disc rotates its dashed ring a little on hover */
.community-page .freq-disc:hover .freq-disc-ring:nth-child(2) {
  transform: rotate(28deg);
}

.community-page .freq-disc-ring { transition: transform .6s cubic-bezier(.2, 1, .3, 1); }

/* Touch has no hover: the readout would never appear, so it is shown
   briefly on tap instead. */
@media (hover: none) {
  .community-page .freq-plate:active::before,
  .community-page .fp-frame:active::before,
  .community-page .honorable-portrait:active::before {
    opacity: 1;
    transform: translateY(0);
  }
  .community-page .freq-plate::after,
  .community-page .fp-frame::after,
  .community-page .honorable-portrait::after { display: none; }
}

/* -----------------------------------------------------------
   19d. Reduced motion — everything added above stands still
   ----------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  .community-page .nw-flash,
  .community-page .nw-burst { display: none; }

  .community-page .nw-tag--link b::after,
  .community-page .freq-node.is-linked .freq-dot,
  .community-page .freq-map[data-state="acquired"] .freq-state--acquired,
  .community-page .cb-pulse,
  .community-page .freq-pulse {
    animation: none !important;
  }

  .community-page .cb-pulse,
  .community-page .freq-pulse { display: none; }

  .community-page .freq-plate::after,
  .community-page .fp-frame::after,
  .community-page .honorable-portrait::after { display: none; }

  .community-page .freq-plate img,
  .community-page .fp-frame img,
  .community-page .honorable-portrait img,
  .community-page .fp-ghost,
  .community-page .freq-disc-ring {
    transition: none !important;
  }

  .community-page .freq-plate:hover img,
  .community-page .fp-frame:hover img,
  .community-page .honorable-portrait:hover img { filter: none; }
}

/* ===========================================================
   20. COMPOSITION FIX

   The hover pass set `position: relative` on a list that included
   .fp-frame, which is `position: absolute; inset: 0` inside its
   plate. The later rule won and the frame fell out of its own
   placement — that is what moved the BettahAI and
   THE_IMAGE_CREATOR3 compositions.

   The frame keeps its absolute placement. Only the two elements
   that were already relative stay in the hover list, and nothing
   about hover is allowed to touch layout from here on.
   =========================================================== */
.community-page .fp-frame {
  position: absolute;
  inset: 0;
  isolation: isolate;
}

.community-page .feature--bh .fp-frame { inset: 13%; }

/* Hover is overlay only.
   This block used to try to *enforce* that with `width: auto` and
   `margin: revert-layer`, which is the opposite of what it claimed:
   `width: auto` on a figure that carries `aspect-ratio: 1 / 1` and a
   max-width made the portrait collapse from 300x300 to 220x220 and
   shift 40px sideways the moment the pointer arrived, while the
   picture inside it grew. That collapse was the second movement —
   the frame shrinking under a zooming image.

   Nothing replaces it. No rule anywhere sets a transform or a width
   on these containers, so there was never anything to neutralise;
   the guarantee comes from not writing layout properties in a hover
   state at all, which is now the case. */

/* The ghost plates behind the gallery frame moved on hover and
   pushed the composition. They stay where they were approved. */
.community-page .feature-plate:hover .fp-ghost--a { translate: 14px 14px; }
.community-page .feature-plate:hover .fp-ghost--b { translate: 27px 27px; }

/* ===========================================================
   21. BASELINE CURRENT

   The network reads as printed between events. From here there is
   always something moving, at a level well under the peaks:

     baseline (continuous, faint)  →  peak (sporadic, loud)

   Mechanism: one dash pattern per conductor, normalised by
   pathLength so it works on any path, animated on
   stroke-dashoffset alone. That is a compositor property, the
   animation is declarative, and no timer or rAF is involved.

   Durations are deliberately co-prime-ish and the delays negative,
   so the channels start mid-cycle and never fall into step.
   =========================================================== */
.community-page .nw-flow,
.community-page .cb-flow,
.community-page .freq-flow {
  fill: none;
  stroke-linecap: round;
  vector-effect: non-scaling-stroke;
  /* on + off = .33, so a full loop is one dashoffset of -.33 */
  stroke-dasharray: .04 .29;
  pointer-events: none;
}

@keyframes flow-run {
  from { stroke-dashoffset: 0; }
  to   { stroke-dashoffset: -.33; }
}

/* --- Neural Window: current around the machine, never on Alice --- */
.community-page .nw-flow {
  stroke: rgba(0, 220, 255, .75);
  stroke-width: 1.7;
  filter: drop-shadow(0 0 4px rgba(0, 220, 255, .7));
  animation: flow-run 5.2s linear infinite;
}

.community-page .nw-flow--2 { stroke-width: 1.4; animation-duration: 7.3s; animation-delay: -2.6s; opacity: .8; }
.community-page .nw-flow--3 { stroke-width: 1.2; animation-duration: 9.1s; animation-delay: -4.9s; opacity: .62; }

/* The cable itself is now faintly visible at rest, so the current
   has something to run along instead of floating. */
.community-page .nw-track {
  stroke: rgba(0, 200, 255, .16);
  stroke-width: 1.1;
}

/* --- Cable Bridge: three channels, three speeds ------------------ */
.community-page .cb-flow {
  stroke: rgba(140, 240, 255, .8);
  stroke-width: 1.8;
  filter: drop-shadow(0 0 5px rgba(0, 220, 255, .75));
  animation: flow-run 6.4s linear infinite;
}

.community-page .cb-flow--2 { stroke-width: 1.5; animation-duration: 8.9s;  animation-delay: -3.1s; opacity: .82; }
.community-page .cb-flow--3 { stroke-width: 1.3; animation-duration: 11.3s; animation-delay: -6.4s; opacity: .64; }

/* --- Network map: slower, quieter, always there ------------------ */
.community-page .freq-flow {
  stroke: rgba(120, 230, 255, .6);
  stroke-width: 1.3;
  filter: drop-shadow(0 0 4px rgba(0, 210, 255, .55));
  animation: flow-run 9.4s linear infinite;
  opacity: 0;
  transition: opacity .6s ease;
}

/* it only appears once the map has been acquired */
.community-page .freq-map.is-live .freq-flow { opacity: 1; }

.community-page .freq-flow:nth-of-type(even) { animation-duration: 12.7s; animation-delay: -5.2s; opacity: 0; }
.community-page .freq-map.is-live .freq-flow:nth-of-type(even) { opacity: .78; }

/* An acquired branch sits a step brighter than a dormant one. */
.community-page .freq-line.is-linked ~ .freq-flow,
.community-page .freq-map.is-live .freq-flow[data-link] {
  stroke: rgba(190, 246, 255, .85);
}

/* --- Signal Spine: the cable is powered -------------------------- */
.signal-spine .ss-drift {
  position: absolute;
  left: -2px;
  right: -2px;
  height: 26px;
  border-radius: 3px;
  background: linear-gradient(180deg, transparent, rgba(0, 220, 255, .55), transparent);
  opacity: .8;
  animation: ss-drift-run 11s linear infinite;
  pointer-events: none;
}

@keyframes ss-drift-run {
  from { transform: translateY(-30px); opacity: 0; }
  12%  { opacity: .75; }
  88%  { opacity: .75; }
  to   { transform: translateY(calc(100cqh + 30px)); opacity: 0; }
}

/* container-relative units need a container; the rail is one */
.signal-spine { container-type: size; }

/* ===========================================================
   22. MOBILE CONTAINER SYSTEM

   One gutter for the whole page instead of each block inventing
   its own: 12px at 320, growing to 16px by 430. Every main block
   derives its width from the space actually available.

   Scoped to <= 760px. The desktop composition is not touched.
   =========================================================== */
@media (max-width: 760px) {
  .community-page {
    --comm-gutter: clamp(12px, 3.6vw, 16px);
  }

  .community-page .page-hero--neural,
  .community-page .cable-bridge,
  .community-page .freq-map,
  .community-page .freq-list,
  .community-page .feature,
  .community-page .honorable,
  .community-page .freq-close {
    width: 100%;
    max-width: 100%;
    min-width: 0;
    margin-inline: auto;
    padding-inline: var(--comm-gutter);
    box-sizing: border-box;
  }

  /* cards fill the gutter box exactly */
  .community-page .freq-card,
  .community-page .feature-body,
  .community-page .honorable-card,
  .community-page .honorable-head,
  .community-page .honorable-inbound,
  .community-page .freq-divider {
    width: 100%;
    max-width: 100%;
    min-width: 0;
    margin-inline: auto;
    box-sizing: border-box;
  }

  /* the closing card obeys the same metric as everything else */
  .community-page .page-bridge {
    width: calc(100% - 2 * var(--comm-gutter));
    max-width: calc(100% - 2 * var(--comm-gutter));
    margin-inline: auto;
    box-sizing: border-box;
  }

  .community-page .freq-close { padding-inline: var(--comm-gutter); }

  /* prose inside a wide card no longer needs its own inset */
  .community-page .freq-card > .freq-block,
  .community-page .freq-card > .freq-record,
  .community-page .freq-card > .freq-sep,
  .community-page .freq-card > .freq-meta {
    width: auto;
    margin-inline: clamp(1rem, 4.5vw, 1.5rem);
  }

  /* --- nothing may push the layout sideways -------------------- */
  .community-page .freq-card-id,
  .community-page .freq-masthead-id,
  .community-page .feature-copy,
  .community-page .feature-body,
  .community-page .honorable-body,
  .community-page .freq-meta-row,
  .community-page .freq-strength,
  .community-page .freq-sub-content,
  .community-page .hero-lead,
  .community-page .hero-body {
    min-width: 0;
  }

  .community-page .freq-tag,
  .community-page .freq-status-code,
  .community-page .freq-record-code,
  .community-page .freq-sub-code,
  .community-page .feature-kicker,
  .community-page .feature-tether-tag,
  .community-page .honorable-code,
  .community-page .honorable-cta-code,
  .community-page .freq-meta-value {
    white-space: normal;
    overflow-wrap: anywhere;
  }

  /* --- Neural Window: near full-width, real ratio --------------- */
  .community-page .neural-window {
    width: calc(100% + 2 * var(--comm-gutter) - 20px);
    margin-inline: calc(-1 * var(--comm-gutter) + 10px);
    max-width: none;
  }

  .community-page .nw-tag { white-space: nowrap; }

  /* --- social ports: uniform grid, real touch targets ---------- */
  .community-page .freq-ports {
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: .45rem;
  }

  .community-page .freq-ports--one,
  .community-page .feature-ports--one {
    grid-template-columns: minmax(0, 1fr);
  }

  .community-page .freq-port {
    min-height: 72px;
    padding: .6rem .3rem;
  }

  .community-page .freq-port-name {
    font-size: .5rem;
    letter-spacing: .08em;
    overflow-wrap: anywhere;
  }
}

/* Two columns where three would squeeze the labels. The single-port
   row has to be restated here: it is declared in the wider block
   above, so without this the two-column rule would win on specificity
   and stretch THE_IMAGE_CREATOR3's lone Instagram port across a grid
   built for six. */
@media (max-width: 400px) {
  .community-page .freq-ports {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .community-page .freq-ports--one,
  .community-page .feature-ports--one {
    grid-template-columns: minmax(0, 1fr);
  }
}

/* ===========================================================
   23. NETWORK MAP · MOBILE

   Not the desktop drawing scaled down. A taller box, larger
   nodes, and real air between the branches — height is cheaper
   than legibility.
   =========================================================== */
@media (max-width: 700px) {
  .community-page .freq-map-inner {
    width: 100%;
    max-width: 340px;
    /* ~130px taller than the 3/4 box it replaces */
    aspect-ratio: 300 / 500;
  }

  .community-page .freq-node { max-width: min(62vw, 12rem); }

  .community-page .freq-node-text b {
    font-size: .7rem;
    letter-spacing: .06em;
    overflow-wrap: anywhere;
  }

  .community-page .freq-node-text em { font-size: .56rem; }
  .community-page .freq-node--sat .freq-node-text b { font-size: .62rem; }
  .community-page .freq-node--sat .freq-node-text em { font-size: .52rem; }
  .community-page .freq-node--core .freq-node-text b { font-size: .64rem; }

  .community-page .freq-dot { width: 12px; height: 12px; }
  .community-page .freq-dot--core { width: 16px; height: 16px; }
  .community-page .freq-dot--sat { width: 9px; height: 9px; }

  /* More vertical spread: the branches stop crowding each other. */
  .community-page .freq-node--core { --nx: 10%; --ny:  5%; }
  .community-page .freq-node--ai   { --nx: 27%; --ny: 27%; }
  .community-page .freq-node--tic  { --nx: 44%; --ny: 45%; }
  .community-page .freq-node--cx   { --nx: 27%; --ny: 71%; }
  .community-page .freq-node--bh   { --nx: 44%; --ny: 89%; }
}

/* The narrow path set follows the nodes. */
@media (max-width: 700px) {
  .community-page .cb-set--tall { display: block; }
}

/* ===========================================================
   24. SIGNAL SPINE · MOBILE

   A hairline that takes nothing from the content. Labels are off
   below 431px: a permanent "MIYUKI // ARCHIVE 17" hanging over the
   text is exactly what the brief rules out.
   =========================================================== */
@media (max-width: 760px) {
  .signal-spine {
    width: 1px;
    right: max(5px, env(safe-area-inset-right));
    top: clamp(80px, 13vh, 116px);
    bottom: clamp(48px, 10vh, 96px);
  }

  .signal-spine .ss-node i { width: 6px; height: 6px; }
  .signal-spine .ss-node--archive i { width: 8px; height: 8px; }
  .signal-spine .ss-node--end i { width: 4px; height: 4px; }
  .signal-spine .ss-node { padding: 12px 0 12px 12px; }

  .signal-spine .ss-pulse { height: 40px; }
  .signal-spine .ss-drift { height: 20px; }

  /* only the current section names itself, and only where it fits */
  .signal-spine .ss-node b {
    max-width: 46vw;
    white-space: normal;
    overflow-wrap: anywhere;
    text-align: right;
  }

  .signal-spine .ss-node:hover b { opacity: 0; }
  .signal-spine .ss-node.is-current b { opacity: 1; translate: 0 0; }
}

@media (max-width: 430px) {
  /* no label at all: the dot and the pulse carry the meaning */
  .signal-spine .ss-node b { display: none; }
  .signal-spine .ss-tail b { display: none; }
  .signal-spine .ss-tail svg { width: 9px; height: 9px; }
}

/* ===========================================================
   25. FEATURES · MOBILE

   Centred image, then header, text, ports. No forced mirroring,
   and still a feature rather than a small card.
   =========================================================== */
@media (max-width: 760px) {
  .community-page .feature-body {
    grid-template-columns: minmax(0, 1fr);
    justify-items: center;
    padding: clamp(1.1rem, 4.5vw, 1.6rem);
  }

  .community-page .feature-plate {
    width: min(300px, 100%);
    justify-self: center;
    margin-inline: auto;
  }

  .community-page .feature-copy { width: 100%; }

  .community-page .feature--bh .feature-tether { flex-direction: row; }
  .community-page .feature--bh .feature-tether-line {
    background: linear-gradient(90deg, transparent, var(--card-edge));
  }
  .community-page .feature--bh .feature-tether-tag { text-align: left; }

  /* the gallery ghosts need room inside the narrower plate */
  .community-page .fp-ghost--a { translate: 8px 8px; }
  .community-page .fp-ghost--b { translate: 16px 16px; }
  .community-page .feature-plate:hover .fp-ghost--a { translate: 8px 8px; }
  .community-page .feature-plate:hover .fp-ghost--b { translate: 16px 16px; }

  .community-page .honorable-portrait {
    width: min(300px, 100%);
    margin-inline: auto;
    position: static;
  }

  .community-page .honorable-card { justify-items: center; }
  .community-page .honorable-body { width: 100%; }

  .community-page .honorable-cta {
    padding-right: clamp(2.4rem, 10vw, 3rem);
  }
}

/* ===========================================================
   26. REDUCED MOTION — the baseline stops too
   =========================================================== */
@media (prefers-reduced-motion: reduce) {
  .community-page .nw-flow,
  .community-page .cb-flow,
  .community-page .freq-flow,
  .signal-spine .ss-drift {
    animation: none !important;
  }

  .community-page .nw-flow,
  .community-page .cb-flow,
  .community-page .freq-flow { stroke-dasharray: none; opacity: .35; }

  .signal-spine .ss-drift { display: none; }
}

/* -----------------------------------------------------------
   27. TABLET BAND · the closing card

   Between 761 and 900 the page is still one column but the mobile
   container rules have stopped applying, and "Torna al sito" was
   running the full width of the viewport, touching both edges. It
   gets the same inset as everything above it. Desktop (>=901) is
   untouched.
   ----------------------------------------------------------- */
@media (min-width: 761px) and (max-width: 900px) {
  .community-page .page-bridge {
    width: min(920px, calc(100% - 2 * clamp(1.1rem, 5vw, 4rem)));
    margin-inline: auto;
    box-sizing: border-box;
  }
}

/* ===========================================================
   28. SIGNAL A-01 · SEALED

   A temporary approval lock, drawn rather than hidden. The two
   blocks keep the footprint and the quality of the records they
   stand in for, so the page does not read as though something
   went missing — it reads as a system that found a frequency and
   refuses to open it.

   Nothing here is real cryptography. The hashes, block runs and
   redaction bars are graphics.

   Removing this section is safe once the lock is lifted; see
   _locked/signal-a01/RESTORE.md.
   =========================================================== */
.community-page .freq-card--ai.is-sealed {
  --card-tint: rgba(0, 190, 255, .05);
  --card-edge: rgba(0, 200, 255, .26);
  --card-accent: #7fe6ff;
}

.community-page .feature--tic.is-sealed {
  --card-edge: rgba(0, 200, 255, .24);
  --card-accent: #7fe6ff;
  --feature-bg:
    repeating-linear-gradient(135deg, rgba(0, 190, 255, .035) 0 2px, transparent 2px 9px),
    linear-gradient(180deg, rgba(5, 16, 28, .66), rgba(3, 8, 16, .78));
}

/* --- the masthead of the sealed record ---------------------- */
.community-page .freq-card--ai.is-sealed .freq-masthead--ai {
  background:
    repeating-linear-gradient(90deg, rgba(0, 200, 255, .05) 0 1px, transparent 1px 7px),
    radial-gradient(ellipse 80% 120% at 14% 0%, rgba(0, 190, 255, .1), transparent 62%),
    linear-gradient(180deg, rgba(5, 16, 28, .74), rgba(3, 8, 16, .3));
}

/* --- the sealed plate --------------------------------------- */
.community-page .enc-plate {
  position: relative;
  overflow: hidden;
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  width: clamp(122px, 38vw, 210px);
  aspect-ratio: 1 / 1;
  margin: clamp(1.4rem, 6vw, 2.4rem) 0 0 clamp(1.2rem, 5vw, 2.1rem);
  border: 1px solid var(--card-edge);
  border-radius: 12px;
  background: rgba(2, 8, 16, .82);
  box-shadow: inset 0 0 40px rgba(0, 160, 220, .12);
}

/* the block field: a grid of redaction cells at mixed weights */
.community-page .enc-field {
  position: absolute;
  inset: 0;
  display: grid;
  grid-template-columns: repeat(8, 1fr);
  gap: 2px;
  padding: 8px;
}

.community-page .enc-field--dense { grid-template-columns: repeat(9, 1fr); }

.community-page .enc-field i {
  border-radius: 1px;
  background: rgba(0, 200, 255, .1);
}

/* an irregular weave, so it reads as data rather than a checkerboard */
.community-page .enc-field i:nth-child(3n)   { background: rgba(0, 210, 255, .2); }
.community-page .enc-field i:nth-child(4n+1) { background: rgba(0, 210, 255, .34); }
.community-page .enc-field i:nth-child(7n+3) { background: rgba(120, 235, 255, .5); }
.community-page .enc-field i:nth-child(11n+5){ background: rgba(0, 190, 255, .06); }
.community-page .enc-field i:nth-child(13n)  { background: rgba(150, 240, 255, .62); }
.community-page .enc-field i:nth-child(17n+2){ background: transparent; }

/* the lock: drawn, not an emoji */
.community-page .enc-lock {
  position: relative;
  z-index: 2;
  display: block;
  width: 46%;
  filter: drop-shadow(0 0 10px rgba(0, 210, 255, .55));
}

.community-page .enc-lock--small { width: 34%; }

.community-page .enc-lock svg {
  width: 100%;
  height: auto;
  display: block;
  fill: none;
  stroke: #9fefff;
  stroke-width: 2.4;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.community-page .enc-body {
  fill: rgba(2, 12, 22, .92);
}

.community-page .enc-keyhole { fill: #9fefff; stroke: none; }

/* one sweep on arrival, then still */
.community-page .enc-scan {
  position: absolute;
  z-index: 3;
  left: 0;
  right: 0;
  top: 0;
  height: 2px;
  background: linear-gradient(90deg, transparent, rgba(150, 240, 255, .9), transparent);
  opacity: 0;
  pointer-events: none;
}

.community-page .is-armed .enc-scan,
.community-page .freq-card.is-armed .enc-scan {
  animation: enc-sweep 1.1s ease .3s 1 both;
}

@keyframes enc-sweep {
  0%   { opacity: 0; transform: translateY(0); }
  12%  { opacity: 1; }
  88%  { opacity: 1; }
  100% { opacity: 0; transform: translateY(210px); }
}

.community-page .enc-marks i {
  position: absolute;
  z-index: 3;
  width: 12px;
  height: 12px;
  border: 0 solid rgba(0, 210, 255, .8);
}

.community-page .enc-marks i:nth-child(1) { top: 6px; left: 6px; border-top-width: 2px; border-left-width: 2px; }
.community-page .enc-marks i:nth-child(2) { top: 6px; right: 6px; border-top-width: 2px; border-right-width: 2px; }
.community-page .enc-marks i:nth-child(3) { bottom: 6px; left: 6px; border-bottom-width: 2px; border-left-width: 2px; }
.community-page .enc-marks i:nth-child(4) { bottom: 6px; right: 6px; border-bottom-width: 2px; border-right-width: 2px; }

/* --- the readout -------------------------------------------- */
.community-page .enc-readout {
  grid-column: 1 / -1;
  display: grid;
  gap: .28rem;
  margin: 0;
  padding: 0 clamp(1.2rem, 5vw, 2.1rem) clamp(1rem, 4vw, 1.4rem);
  color: rgba(143, 235, 255, .62);
  font: 400 .52rem/1.5 var(--page-mono, monospace);
  letter-spacing: .16em;
  overflow-wrap: anywhere;
}

.community-page .enc-readout--sub {
  padding: 0;
  margin-top: 1.1rem;
  border-top: 1px solid var(--card-edge);
  padding-top: .9rem;
}

/* the two scrambling lines settle once, on arrival */
.community-page .is-armed [data-scramble] {
  animation: enc-scramble .9s steps(6, end) 1 both;
}

@keyframes enc-scramble {
  0%   { opacity: .25; letter-spacing: .5em; filter: blur(1px); }
  20%  { opacity: .9;  letter-spacing: .1em; }
  40%  { opacity: .4;  letter-spacing: .3em; }
  60%  { opacity: 1;   letter-spacing: .13em; }
  80%  { opacity: .6;  letter-spacing: .19em; }
  100% { opacity: 1;   letter-spacing: .16em; filter: blur(0); }
}

/* --- the meter reads locked, not weak ----------------------- */
.community-page .freq-strength-bars.is-sealed i {
  background: rgba(0, 200, 255, .3);
  opacity: .3 !important;
  transform: scaleY(.4) !important;
}

.community-page .freq-strength-bars.is-sealed i:nth-child(2n) {
  opacity: .16 !important;
}

.community-page .freq-strength-state--sealed { color: #7fe6ff; }

/* --- the subnode plate -------------------------------------- */
.community-page .feature-plate--sealed .enc-frame {
  display: grid;
  place-items: center;
  border: 1px solid var(--card-edge);
  border-radius: 4px;
  background: rgba(2, 8, 16, .86);
  overflow: hidden;
}

.community-page .enc-ring {
  position: absolute;
  inset: 0;
  z-index: 1;
  border-radius: 50%;
  border: 1px dashed rgba(0, 200, 255, .22);
  pointer-events: none;
}

.community-page .enc-ring--b { inset: 9%; border-style: dotted; opacity: .6; }

/* --- the sealed branch of the network map ------------------- */
/* Present, connected, and unmistakably not open: the run is dashed
   and the node is hollow with a lock tick through it. */
.community-page.is-a01-sealed .freq-line[data-link="ai"] {
  stroke-dasharray: 4 4;
  stroke: rgba(0, 200, 255, .38);
}

.community-page.is-a01-sealed .freq-line--secondary[data-link="ai"] {
  stroke-dasharray: 2 5;
}

.community-page .freq-node.is-sealed .freq-dot {
  background: rgba(2, 10, 20, .95);
  border: 1.5px solid #7fe6ff;
  box-shadow: 0 0 10px rgba(0, 200, 255, .5);
}

.community-page .freq-node.is-sealed .freq-node-text b { color: rgba(190, 240, 255, .9); }
.community-page .freq-node.is-sealed .freq-node-text em { color: rgba(127, 230, 255, .7); }

/* the current arrives at the sealed node and stops short of it */
.community-page.is-a01-sealed .freq-flow[data-link="ai"] {
  stroke: rgba(0, 200, 255, .45);
  stroke-dasharray: .03 .5;
}

/* --- the spine markers -------------------------------------- */
.signal-spine .ss-node.is-sealed i {
  background: transparent;
  border-color: rgba(127, 230, 255, .85);
  border-style: dashed;
}

.signal-spine .ss-node.is-sealed.is-reached i {
  background: transparent;
  border-style: solid;
  box-shadow: 0 0 8px rgba(0, 200, 255, .5);
}

/* --- narrow ------------------------------------------------- */
@media (max-width: 900px) {
  .community-page .enc-plate {
    margin: clamp(1.2rem, 5vw, 1.8rem) auto 0;
  }

  .community-page .freq-masthead--a01 .freq-masthead-id { padding-top: clamp(.8rem, 3vw, 1.2rem); }
}

@media (prefers-reduced-motion: reduce) {
  .community-page .is-armed .enc-scan,
  .community-page .freq-card.is-armed .enc-scan,
  .community-page .is-armed [data-scramble] {
    animation: none !important;
  }
  .community-page .enc-scan { opacity: 0; }
}

/* ===========================================================
   29. HOVER · RELATIVE ZOOM AND CONTAINED READOUTS

   Two separate faults, both visible on the same elements.

   1. The zoom was written as an absolute `transform: scale(1.06)`
      on the image. It happens that no image carried a base
      transform today, so it did not destroy one — but it is a
      pattern that will, the moment any picture needs its own crop.
      It is replaced by two custom properties multiplied together,
      so a base scale and the hover response can never overwrite
      each other.

   2. `object-fit` differs between the plates, and that is what
      made the same 6% read as three different gestures:

        BETTAHAI      cover    picture 220 in a 222 frame
        CROSSXHYPE    contain  picture 147 in a 155 frame
        MIYUKI        contain  picture 298 in a 300 frame

      With `cover` the picture already fills the frame, so growing
      it pushes content past the clip and reads as a zoom. With
      `contain` the picture is inset by its own padding; 6% of 147
      is 8.8px, which is more than the 8px of headroom the disc
      has, so the logo's rim was clipped by the round mask. A
      circular mark losing its edge reads as cropped, not nearer.

      Each plate now gets a hover amount that stays inside its own
      headroom. Rest states are untouched.

   The frame, the grid and every inset stay exactly where they
   were: only the picture inside the mask moves.
   =========================================================== */
.community-page .freq-plate img,
.community-page .fp-frame img,
.community-page .honorable-portrait img {
  /* the plate's own composition — never written by hover */
  --img-base: 1;
  /* the hover response — the only thing hover touches */
  --img-hover: 1;
  transform: scale(calc(var(--img-base) * var(--img-hover)));
  transform-origin: 50% 50%;
  will-change: transform;
}

/* How far each plate may grow before its own mask starts cutting
   the picture. Measured, not guessed. */
.community-page .fp-frame img { --img-hover-to: 1.05; }
.community-page .freq-plate img { --img-hover-to: 1.05; }
/* the disc has 4px of padding, so 3.5% is what fits without
   clipping the logo's rim */
.community-page .freq-plate--disc img { --img-hover-to: 1.035; }

.community-page .freq-plate:hover img,
.community-page .fp-frame:hover img,
.community-page .honorable-portrait:hover img,
.community-page a:hover .freq-plate img,
.community-page a:focus-visible .freq-plate img {
  /* multiplies the base rather than replacing the transform */
  --img-hover: var(--img-hover-to, 1.05);
  transform: scale(calc(var(--img-base) * var(--img-hover)));
}

/* -----------------------------------------------------------
   29b. The readout, contained

   CONNECTED FREQUENCY was nineteen characters on a circular
   222px frame, laid out as a full-bleed band. On a circle a
   full-width band at the very bottom runs past the curve, which
   is what pushed it over the edge of the composition.

   Circular plates get a centred pill, lifted onto the chord where
   there is real width, and the label is shortened to match the
   family the other plates already use.
   ----------------------------------------------------------- */
.community-page .fp-frame::before { content: "SIGNAL LINKED"; }

.community-page .freq-plate::before,
.community-page .fp-frame::before,
.community-page .honorable-portrait::before {
  box-sizing: border-box;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* circular frames: a pill on the chord, never a band on the rim */
.community-page .feature--bh .fp-frame::before,
.community-page .freq-plate--disc::before {
  left: 50%;
  right: auto;
  bottom: 15%;
  translate: -50% 0;
  width: max-content;
  max-width: 74%;
  padding: .26rem .55rem;
  border-radius: 999px;
  border: 1px solid rgba(0, 210, 255, .35);
  background: rgba(2, 10, 20, .92);
  letter-spacing: .12em;
  white-space: nowrap;
}

/* the pill starts from where it will settle, so nothing slides in
   from outside the mask */
.community-page .feature--bh .fp-frame::before,
.community-page .freq-plate--disc::before {
  transform: translateY(6px);
}

.community-page .feature--bh .fp-frame:hover::before,
.community-page .freq-plate--disc:hover::before {
  transform: translateY(0);
}

/* -----------------------------------------------------------
   29c. Touch

   `:hover` sticks after a tap on a touch screen. The zoom is
   pinned to its rest value there so nothing stays enlarged once
   the finger has gone.
   ----------------------------------------------------------- */
@media (hover: none) {
  .community-page .freq-plate:hover img,
  .community-page .fp-frame:hover img,
  .community-page .honorable-portrait:hover img,
  .community-page a:hover .freq-plate img {
    --img-hover: 1;
  }
}

@media (prefers-reduced-motion: reduce) {
  .community-page .freq-plate:hover img,
  .community-page .fp-frame:hover img,
  .community-page .honorable-portrait:hover img,
  .community-page a:hover .freq-plate img,
  .community-page a:focus-visible .freq-plate img {
    --img-hover: 1;
  }
  .community-page .feature--bh .fp-frame::before,
  .community-page .freq-plate--disc::before { transform: none; }
}

/* ===========================================================
   30. MIYUKI · HOVER AMOUNT

   Diagnosis first, because the reported "double zoom" was not one:
   walking section.honorable → article.honorable-card →
   figure.honorable-portrait → img under a simulated hover, exactly
   one level changes transform, the image, 1 → 1.045. No parent
   scales and no pseudo-element scales.

   What made it feel doubled is absolute travel. The portrait is the
   largest plate on the page at 300px, so the same kind of percentage
   moves far more pixels than anywhere else:

     MIYUKI      4.5% of 298  =  +13.4px   (6.7px of crop per side)
     BETTAHAI    5.0% of 220  =  +11.0px
     CROSSXHYPE  3.5% of 147  =   +5.2px

   On a face at that size, 6.7px per side reads as the camera lunging.
   The amount is corrected rather than compensated: 2%, which is
   +6px total and 3px per side, in line with the other plates in
   pixels rather than in percent.

   The personality moves to where the brief wants it — sweep, corner
   brackets, edge glow, readout — plus 2px of parallax carried in the
   same transform, so there is still only ever one level moving.

   Nothing about the layout changes: the figure, the card, the CTA,
   the ports and the portrait's own size are all untouched.
   =========================================================== */
.community-page .honorable-portrait img {
  --img-hover-to: 1.02;
  --img-shift: 0px;
  /* translate and scale live in one declaration on one element; they
     are never split across parent and child */
  transform: translateY(var(--img-shift)) scale(calc(var(--img-base) * var(--img-hover)));
}

.community-page .honorable-portrait:hover img {
  --img-shift: -2px;
  transform: translateY(var(--img-shift)) scale(calc(var(--img-base) * var(--img-hover)));
}

/* The response comes from the frame, not from the picture. */
.community-page .honorable-portrait:hover {
  border-color: rgba(214, 196, 255, .95);
  box-shadow:
    0 0 0 1px rgba(196, 168, 255, .55),
    0 0 40px rgba(150, 110, 255, .34),
    0 20px 44px rgba(0, 0, 0, .5);
}

.community-page .honorable-portrait:hover .honorable-portrait-marks i {
  border-color: #e6dcff;
  box-shadow: 0 0 10px rgba(196, 168, 255, .7);
}

.community-page .honorable-portrait-marks i {
  transition: border-color .3s ease, box-shadow .3s ease;
}

/* the sweep keeps the section's own violet rather than the page cyan */
.community-page .honorable-portrait::after {
  background: linear-gradient(115deg,
    transparent 38%,
    rgba(224, 210, 255, .06) 46%,
    rgba(170, 140, 255, .45) 50%,
    rgba(224, 210, 255, .06) 54%,
    transparent 62%);
}

@media (hover: none) {
  .community-page .honorable-portrait:hover img { --img-shift: 0px; }
}

@media (prefers-reduced-motion: reduce) {
  .community-page .honorable-portrait:hover img { --img-shift: 0px; }
  .community-page .honorable-portrait-marks i { transition: none !important; }
}

/* ===========================================================
   BETTAHAI · MOBILE READING ORDER  (mobile hotfix, 18 Aug 2026)

   Section 25 above is headed "Centred image, then header, text,
   ports" — but it never declared an order, so the DOM decided:
   `.feature-copy` holds the kicker, the name, the role, the two
   paragraphs, the waveform *and* the ports, and `.feature-plate`
   is its sibling. Collapsed to one column the plate can only
   land last, below the social ports. The comment described an
   intention that was never implemented, and on a real phone the
   feature lost its hierarchy completely.

   The copy is promoted into the feature grid with
   `display: contents`, which lets the plate take a position
   between the role and the editorial text without duplicating a
   single node or adding a second image. Order is then explicit:

     1 kicker · 2 BettahAI · 3 role · 4 plate
     5 editorial text · 6 waveform · 7 signal ports

   Row gap goes to zero because each block already carries its
   own margin-top; the rhythm below is the same one that was
   there before, with only the plate inserted into it.

   Scoped to `.feature--bh`. The desktop composition from 761px
   up is untouched, and no other feature is addressed.
   =========================================================== */
@media (max-width: 760px) {
  .community-page .feature--bh .feature-body {
    /* promoted children are full-width blocks, not centred boxes */
    justify-items: stretch;
    row-gap: 0;
  }

  .community-page .feature--bh .feature-copy { display: contents; }

  .community-page .feature--bh .feature-kicker { order: 1; }
  .community-page .feature--bh .feature-copy h2 { order: 2; }
  .community-page .feature--bh .feature-copy > .feature-role { order: 3; }
  .community-page .feature--bh .feature-plate { order: 4; }
  /* the role is also a p[data-i18n]; it keeps position 3 */
  .community-page .feature--bh .feature-copy > p[data-i18n]:not(.feature-role) { order: 5; }
  .community-page .feature--bh .feature-wave { order: 6; }
  .community-page .feature--bh .feature-ports { order: 7; }

  /* The plate arrives high in the feature and is given room on
     both sides of it. The lower value clears `.fp-tag`, which is
     absolutely placed 1.6rem below the frame. */
  .community-page .feature--bh .feature-plate {
    order: 4;
    justify-self: center;
    width: min(300px, 100%);
    max-width: 100%;
    margin-block: clamp(1.7rem, 6vw, 2.2rem) clamp(3.1rem, 10vw, 3.8rem);
    margin-inline: auto;
  }

  /* Nothing in the promoted set may widen the card. */
  .community-page .feature--bh .feature-kicker,
  .community-page .feature--bh .feature-copy h2,
  .community-page .feature--bh .feature-copy > p,
  .community-page .feature--bh .feature-wave,
  .community-page .feature--bh .feature-ports {
    min-width: 0;
    max-width: 100%;
  }
}

/* ===========================================================
   29. SIGNAL A-01 · DECRYPT

   L'autorizzazione e' arrivata. La sezione 28 resta dov'e': non e'
   piu' uno stato permanente ma lo stato INIZIALE, e questa sezione
   descrive il passaggio da quello all'identita' reale.

   Tre stati, sempre sullo stesso nodo -- non c'e' nessuna card che
   sparisce e nessuna che appare:

       .is-sealed      la targa cifrata copre l'identita'
       .is-decrypting  il velo si dissolve, il nome si compone
       (nessuna)       stato finale, stabile, zero costo

   Tutto passa per opacity, transform e clip-path. Nessun blur
   animato, nessun filtro, nessuna animazione infinita: le uniche
   che girano sono quelle gia' del progetto, e durano quanto il
   reveal. A stato finale raggiunto il JS toglie le classi e qui
   non resta nulla di attivo.
   =========================================================== */

/* --- il testo che cambia -------------------------------------
   Due span, uno per stato. Nessuna scrittura JS, nessun attributo
   letto a runtime: solo quale dei due e' in flusso. */
.community-page .dec-seal { display: none; }
.community-page .is-sealed .dec-real,
.community-page .is-decrypting .dec-real { display: none; }
.community-page .is-sealed .dec-seal,
.community-page .is-decrypting .dec-seal { display: inline; }

/* --- il velo cifrato ------------------------------------------
   Copre l'identita' mentre e' sigillata. Durante la decrittazione
   si apre dall'alto con una clip e svanisce; dopo esce dal flusso
   e non e' piu' nemmeno un layer da comporre. */
.community-page .dec-veil {
  position: absolute;
  inset: 0;
  z-index: 4;
  overflow: hidden;
  border-radius: inherit;
  background: linear-gradient(180deg, rgba(5, 16, 28, .92), rgba(3, 8, 16, .96));
  clip-path: inset(0 0 0 0);
  opacity: 1;
  transition: clip-path .58s cubic-bezier(.4, 0, .2, 1), opacity .42s ease .16s;
}

.community-page .dec-veil--plate { z-index: 3; }

.community-page .is-decrypting .dec-veil {
  clip-path: inset(0 0 100% 0);
  opacity: 0;
}

/* Ancorata alla card, non a un antenato qualsiasi: con un :not()
   discendente bastava un nodo intermedio non sigillato per spegnere il
   velo mentre lo stato era ancora sealed. */
.community-page .freq-card--ai:not(.is-sealed):not(.is-decrypting) .dec-veil,
.community-page .feature--tic:not(.is-sealed):not(.is-decrypting) .dec-veil {
  display: none;
}

/* il masthead e la targa devono poter ospitare un overlay */
.community-page .freq-masthead--ai { position: relative; }

/* --- il nome che si compone -----------------------------------
   Il JS scrive tre stringhe fisse e poi quella vera. Niente
   caratteri casuali, niente loop: quattro scritture in tutto. */
.community-page .dec-name { position: relative; }

.community-page .is-decrypting .dec-name {
  color: var(--card-accent, #8ff4ff);
  text-shadow: 0 0 12px rgba(0, 220, 255, .35);
}

/* --- il readout della sequenza --------------------------------
   Una riga sola, tolta dal DOM appena finita. */
.community-page .dec-readout {
  margin: .5rem 0 0;
  min-height: 1.1em;
  color: rgba(140, 236, 255, .92);
  font: 700 .58rem/1.2 "Courier New", Consolas, monospace;
  letter-spacing: .2em;
  text-transform: uppercase;
}

.community-page .dec-readout span {
  display: inline-block;
  opacity: 0;
  transform: translateY(3px);
  transition: opacity .22s ease, transform .22s ease;
}

.community-page .dec-readout.is-on span { opacity: 1; transform: none; }

/* --- l'immagine ricostruita dal segnale -----------------------
   Non appare: viene scoperta da una scansione verticale. Il costo
   e' una clip-path animata una volta sola. */
.community-page .is-sealed .freq-plate img,
.community-page .is-sealed .fp-frame img {
  opacity: 0;
  clip-path: inset(0 0 100% 0);
}

.community-page .is-decrypting .freq-plate img,
.community-page .is-decrypting .fp-frame img {
  opacity: 1;
  clip-path: inset(0 0 0 0);
  transition: clip-path .62s cubic-bezier(.3, 0, .2, 1) .12s, opacity .34s ease .12s;
}

/* --- le barre del segnale -------------------------------------
   Sigillate restano spente; si accendono a stato finale. */
.community-page .is-sealed .dec-bars i { opacity: .22; }
.community-page .dec-bars i { transition: opacity .3s ease; }

/* --- la mappa -------------------------------------------------
   Il nodo si accende quando il segnale lo raggiunge, non prima. */
.community-page .freq-node.is-sealed .freq-node-text b,
.community-page .freq-node.is-sealed .freq-node-text em { transition: color .4s ease; }

.community-page .freq-node.is-acquired .freq-dot {
  background: #8ff4ff;
  box-shadow: 0 0 14px rgba(0, 220, 255, .75);
  transition: background .38s ease, box-shadow .38s ease;
}

/* l'impulso che corre sulla connessione verso il satellite */
.community-page .freq-line--secondary[data-link="ai"].is-pulsing {
  stroke: #8ff4ff;
  stroke-dasharray: none;
  transition: stroke .5s ease;
}

/* --- reduced motion -------------------------------------------
   Nessun velo che si apre, nessun nome che si compone: si arriva
   allo stato finale quasi subito. L'informazione non dipende mai
   dall'animazione. */
@media (prefers-reduced-motion: reduce) {
  .community-page .dec-veil,
  .community-page .is-decrypting .dec-veil {
    transition: opacity .2s linear;
    clip-path: none;
  }

  .community-page .is-decrypting .freq-plate img,
  .community-page .is-decrypting .fp-frame img {
    clip-path: none;
    transition: opacity .2s linear;
  }

  .community-page .dec-readout span { transition: opacity .2s linear; transform: none; }
  .community-page .is-decrypting .dec-name { text-shadow: none; }
}
