/* ============================================================================
   marketplace.css
   ----------------------------------------------------------------------------
   The Cognia marketplace page chrome. Every block below is either transcribed
   from _reference/ycglobe-index.html (provenance noted as "orig Lnn") or is a
   new region the brief adds, expressed through src/shared/tokens.css so it uses
   no colour, blur, shadow or type value the original page did not already ship.

   Load order: tokens.css, tokens-dark.css, this file, then the module
   stylesheets (top-creators.css, activity-bar.css, recall-drawer.css) — each of
   those restates the `.panel` chrome under its own root class, so they must come
   last. tokens-dark.css sits directly after tokens.css because it is one
   `[data-theme="dark"]` block that re-points the same token names; everything
   below therefore themes itself, and the dark section at the foot of this file
   carries only the fixes a token swap cannot express.
   ========================================================================== */

/* -- wordmark face (local only, no CDN) ----------------------------------- */
@font-face{
  font-family:Jost;
  src:url("../../assets/fonts/jost.ttf") format("truetype");
  font-weight:100 900; font-style:normal; font-display:swap;
}

/* -- base (orig L52-55) --------------------------------------------------- */
*{ box-sizing:border-box; }
html,body{ margin:0; height:100%; background:var(--paper); overflow:hidden; }
body{ font-family:var(--font-body); color:var(--ink); }
button,input,select{ font:inherit; color:inherit; }
button{ cursor:pointer; }
[hidden]{ display:none !important; }
.mono{ font-family:var(--font-mono); font-variant-numeric:tabular-nums; }
.muted{ color:var(--graphite); }
.sr-only{ position:absolute; width:1px; height:1px; padding:0; margin:-1px; overflow:hidden;
  clip:rect(0 0 0 0); white-space:nowrap; border:0; }
:focus-visible{ outline:2px solid var(--brand); outline-offset:2px; }

/* ── the graph, in the original's map slot (orig L55, #map) ─────────────── */
#graph{ position:fixed; inset:0; touch-action:none; background:var(--paper); }
#graph canvas{ display:block; }

/* graph module chrome. .graph-overlay/.hub-label are the engine's own nodes;
   .graph-tip is orig .tip (L310-311), .graph-pulse is orig .pulse (L306-309),
   .graph-pin is orig .unipin (L276, L285-290). */
.graph-overlay{ position:absolute; inset:0; pointer-events:none; overflow:hidden; }
.hub-label{ position:absolute; pointer-events:none; width:max-content; max-width:172px;
  font:var(--fw-semibold) 11px/1.25 var(--font-body);
  text-shadow:0 1px 3px var(--paper), 1px 0 3px var(--paper), -1px 0 3px var(--paper); }
.hub-label .hud{ display:block; margin-top:3px; color:var(--graphite);
  font:9px/1.2 var(--font-mono); letter-spacing:.025em; }
.graph-tip{ position:fixed; z-index:20; pointer-events:none; max-width:280px; padding:8px 11px;
  border-radius:var(--r-8, 8px); background:var(--ink-tip); color:var(--white);
  font-size:var(--fs-md); box-shadow:var(--sh-2); }
.graph-tip b{ font-weight:var(--fw-semibold); }
.graph-tip .mono{ display:block; margin-top:4px; color:var(--border); font-size:var(--fs-sm); }
.graph-pulse{ position:absolute; width:15px; height:15px; margin:-7.5px; border-radius:50%;
  background:var(--pc,var(--pulse-default)); box-shadow:var(--sh-pulse); pointer-events:none; }
.graph-pulse.hollow{ background:transparent; box-shadow:0 0 0 2.5px var(--white);
  border:2px solid var(--pc,var(--pulse-default)); }
.graph-pulse::before,.graph-pulse::after{ content:""; position:absolute; inset:-1px; border-radius:50%;
  border:2px solid var(--pc,var(--pulse-default)); animation:pring 3s ease-out infinite; }
.graph-pulse::after{ animation-delay:1.5s; }
@keyframes pring{ 0%{ transform:scale(1); opacity:.5 } 100%{ transform:scale(2.4); opacity:0 } }
.graph-pin{ position:absolute; display:flex; flex-direction:column; align-items:center;
  transform:translate(-50%,-100%); pointer-events:none; }
.graph-pin button{ pointer-events:auto; margin:0 auto 6px; border:1px solid var(--brand-35);
  border-radius:20px; padding:4px 10px; background:var(--glass-fill-92); color:var(--brand);
  font:var(--fw-semibold) 10px var(--font-display); box-shadow:var(--sh-2); }
.pin-badge{ width:40px; height:40px; border-radius:50%; background:var(--white);
  border:2px solid var(--brand); display:grid; place-items:center; position:relative;
  box-shadow:var(--sh-2-badge); font:var(--fw-black) 13px var(--font-display); }
.pin-badge::after{ content:""; position:absolute; inset:-4px; border-radius:50%;
  border:2px solid var(--brand); animation:pring 2.4s ease-out infinite; }
.pin-label{ margin-top:5px; max-width:180px; white-space:nowrap; overflow:hidden;
  text-overflow:ellipsis; padding:2px 7px; border-radius:10px; background:var(--glass-fill-85);
  font-size:var(--fs-md); font-weight:var(--fw-bold); box-shadow:var(--sh-1); }

/* ── left panel: header + filters (orig L125-176, .sidebar) ─────────────── */
.sidebar{ position:fixed; top:12px; left:12px; bottom:12px; width:296px; z-index:10;
  display:flex; flex-direction:column;
  background:var(--paper-70);
  -webkit-backdrop-filter:var(--blur-sidebar); backdrop-filter:var(--blur-sidebar);
  border:1px solid var(--brand-20); border-radius:var(--r-18, 18px);
  box-shadow:var(--sh-4-sidebar); overflow:hidden; }
.head{ padding:14px 16px 12px; border-bottom:1px solid var(--border); }
/* the back-link slot, and the 8px it pushes the brand row down (orig L129-130) */
.head a.back{ font-size:var(--fs-md); color:var(--graphite); text-decoration:none; }
.head a.back:hover{ color:var(--brand); }
/* The brand row is the site nav's trigger since v2: src/shared/nav.js replaces
   this container's contents with the accordion, and marks it so. The markup
   the page ships inside it is the pre-mount state — the same mark and wordmark,
   in the same place — so the head never renders empty while the module boots.
   The mounted nav owns its own box (the trigger carries the 8px itself, as 4px
   of margin plus 4px of padding), which is why the container gives it up. */
.head .navmount{ display:flex; align-items:center; gap:9px; margin-top:8px; }
.head .navmount[data-nav-mounted]{ display:block; margin-top:0; }
.head .row{ display:flex; align-items:center; gap:9px; margin-top:8px; }
.head .brandlogo{ width:30px; height:30px; border-radius:7px; flex:0 0 auto; object-fit:contain; }
/* the wordmark, in the landing stub's face and tracking (bakeoff/astra L24),
   dropped from 31px to the sidebar heading's 19px (orig .head h1) */
.wordmark{ font:300 19px/1 Jost, var(--font-display); letter-spacing:.28em;
  color:var(--brand); padding-left:.14em; }
.head p{ font-size:var(--fs-md); color:var(--graphite); margin:8px 0 0; line-height:var(--lh-body); }
.netline{ margin-top:8px; font-size:var(--fs-sm); color:var(--graphite); }
.netline b{ color:var(--ink); }
/* the one route into demo.html from this page. Same declarations as a.back
   above — the head's link style — one step down the scale so it sits under
   the netline as a footnote rather than beside the wordmark as an action. */
.head a.demolink{ display:inline-block; margin-top:6px;
  font-size:var(--fs-sm); color:var(--graphite); text-decoration:none;
  transition:color var(--dur-140) var(--ease); }
.head a.demolink:hover{ color:var(--brand); }
.head a.demolink:focus-visible{ outline:2px solid var(--brand-55); outline-offset:2px;
  border-radius:3px; }

.filters{ flex:1; overflow-y:auto; overscroll-behavior:contain; }
.searchwrap{ position:relative; margin:12px 16px 0; z-index:5; }
.search{ display:flex; align-items:center; gap:8px; border:1px solid var(--border);
  background:var(--white); padding:7px 10px; border-radius:var(--r-10, 10px); }
.search input{ border:none; outline:none; font-family:inherit; font-size:var(--fs-base);
  width:100%; background:transparent; }
.suggest{ position:absolute; left:0; right:0; top:calc(100% + 4px); z-index:40;
  background:var(--white); border:1px solid var(--border); border-radius:var(--r-8, 8px);
  box-shadow:var(--sh-3-suggest); max-height:340px; overflow-y:auto; display:none; }
.suggest.open{ display:block; }
.sitem{ display:flex; align-items:center; gap:9px; padding:7px 10px; cursor:pointer;
  border-bottom:1px solid var(--divider-warm); background:none; border-left:0; border-right:0;
  border-top:0; width:100%; text-align:left; }
.sitem:last-child{ border-bottom:none; }
.sitem:hover,.sitem:focus-visible{ background:var(--brand-09); }
.sitem .snm{ flex:1; font-size:var(--fs-base-p); min-width:0; white-space:nowrap;
  overflow:hidden; text-overflow:ellipsis; }
.sitem .sdot{ width:9px; height:9px; border-radius:50%; flex:0 0 auto;
  box-shadow:var(--sh-ring-soft); }
.sitem .sct{ font:var(--fw-semibold) var(--fs-sm) var(--font-mono); color:var(--graphite); }

.chips{ display:none; flex-wrap:wrap; gap:6px; margin:10px 16px 0; }
.chips.show{ display:flex; }
.chip-f{ display:inline-flex; align-items:center; gap:5px; font-size:var(--fs-md);
  padding:3px 6px 3px 9px; border-radius:20px; background:var(--white);
  border:1px solid var(--border); cursor:pointer; color:var(--ink); }
.chip-f:hover{ border-color:var(--brand); background:var(--brand-08); }
.chip-f b{ font-weight:var(--fw-bold); color:var(--graphite); font-size:var(--fs-base); }
.chip-reset{ font-size:var(--fs-md); color:var(--brand); cursor:pointer; align-self:center;
  padding:3px 5px; font-weight:var(--fw-bold); background:none; border:0; }

.grp{ padding:12px 16px; border-bottom:1px solid var(--border); }
.grp .lbl{ font-size:var(--fs-sm); font-weight:var(--fw-bold); text-transform:uppercase;
  letter-spacing:.1em; color:var(--acc); margin-bottom:8px; display:flex;
  justify-content:space-between; gap:8px; cursor:pointer; }
.grp .lbl a{ color:var(--graphite); cursor:pointer; text-decoration:underline;
  font-weight:var(--fw-medium); text-transform:none; letter-spacing:0; display:none; }
.grp .lbl a.show{ display:inline; }
.grp .lbl:focus-visible{ outline:2px solid var(--brand-55); outline-offset:2px;
  border-radius:4px; }
.grp .lbl .gchev{ margin-left:auto; padding-left:8px; color:var(--brand);
  font-size:var(--fs-lg); transition:transform .15s; }
.grp.collapsed .lbl .gchev{ transform:rotate(-90deg); }
.grp.collapsed > *:not(.lbl), .grp.collapsed .morelink{ display:none; }
.morelink{ font-size:var(--fs-md); color:var(--brand); cursor:pointer; padding:8px 4px 2px;
  user-select:none; font-weight:var(--fw-semibold); background:none; border:0; text-align:left; }
.chk{ display:flex; align-items:center; gap:8px; padding:4px 6px; cursor:pointer;
  user-select:none; font-size:var(--fs-base-p); border-radius:7px; width:100%;
  background:none; border:0; text-align:left; color:inherit; }
.chk:hover{ background:color-mix(in srgb, var(--brand) 8%, transparent); }
.chk .dot{ width:9px; height:9px; border-radius:50%; flex:0 0 auto; }
.chk .nm{ flex:1; }
.chk .ct{ font:var(--fw-semibold) 10.5px/1 var(--font-mono); color:var(--graphite); }
.chk.off{ opacity:.4; }
.chk.xtra{ display:none; } .exp .chk.xtra{ display:flex; }
.toggles{ display:flex; flex-wrap:wrap; gap:6px; }
.tg{ font-size:var(--fs-md); padding:5px 9px; border:1px solid var(--border);
  background:var(--white); cursor:pointer; display:inline-flex; align-items:center; gap:6px;
  border-radius:var(--r-8, 8px); color:var(--ink); }
.tg .sdot{ width:9px; height:9px; border-radius:50%; flex:0 0 auto; }
.tg .tgct{ font:var(--fw-semibold) var(--fs-sm) var(--font-mono); color:var(--graphite); }
.tg.on{ background:var(--brand); color:var(--white); border-color:var(--brand); }
.tg.on .tgct{ color:var(--white); }
.count{ padding:10px 16px; font-size:var(--fs-md); color:var(--graphite);
  border-top:1px solid var(--border); flex:0 0 auto; }
.count b{ color:var(--ink); }

/* ── floating panel chrome (orig L207-241) ──────────────────────────────── */
.panel-head{ display:flex; align-items:center; gap:9px; padding:11px 13px 9px;
  user-select:none; flex:0 0 auto; position:relative; }
.panel-head .ph-title{ font-family:var(--font-display); font-weight:var(--fw-semibold);
  font-size:var(--fs-lg-p); }
.panel-head .ph-sub{ font-size:var(--fs-base); color:var(--graphite); }
.panel-head .ph-sub b{ color:var(--ink); }
.panel-head .ph-btn{ cursor:pointer; color:var(--brand); font-size:var(--fs-2xl);
  line-height:1; padding:2px 5px; border-radius:6px; background:none; border:0; }
.panel-head .ph-btn:hover{ background:var(--brand-14); }
.panel-head #rzchev{ margin-left:6px; transition:transform .15s; }
.panel.collapsed #rzchev{ transform:rotate(-90deg); }
/* the original's collapsed head has no such margin — it relied on #rzdock's
   `margin-left:auto`, which this page does not carry — so it is dropped when
   collapsed, and the collapsed box measures the reference's width exactly */
.panel.collapsed #rzchev{ margin-left:0; }
.panel-body{ flex:1 1 auto; overflow:hidden; padding:0 13px 12px; min-height:0; }
.panel.collapsed .panel-body{ display:none; }
.panel.collapsed .panel-head{ padding:9px 12px; }
#resultsbar.collapsed .ph-title{ display:none; }
.rz-logo{ width:24px; height:24px; border-radius:6px; background:var(--brand);
  display:grid; place-items:center; flex:0 0 auto; }
.rz-logo span{ color:var(--white); font:300 14px/1 Jost, var(--font-display);
  letter-spacing:.06em; }
.panel-head .rz-seg{ display:inline-flex; gap:2px; padding:2px; border-radius:var(--r-8, 8px);
  background:rgba(0,0,0,.055); margin-left:auto; }
.panel-head .rz-seg button{ border:none; background:none; cursor:pointer;
  font:var(--fw-semibold) 10.5px var(--font-display); color:var(--graphite);
  padding:3px 8px; border-radius:6px; line-height:1; }
.panel-head .rz-seg button.on{ background:var(--brand); color:var(--white); }
.panel.collapsed .rz-seg{ display:none; }
/* §4 — the header grab bar, now on every viewport. The original shipped this
   pill only for the phone (orig .rz-grab, L2769 initRzGrab) and gave the desktop
   a bare top-edge hit strip whose hairline grew 0 → 46px on hover (orig L235-236).
   Two resize affordances on the same 9px edge would sit on top of each other, so
   the pill is the one visible handle and .rz-top stays behind it as a second hit
   area over the same edge. NOTES §15's animated hairline is retired with it. */
.rz-grab{ display:block; height:14px; position:relative; cursor:ns-resize;
  touch-action:none; flex:0 0 auto; margin-bottom:-5px; }
.rz-grab::before{ content:""; position:absolute; left:50%; top:5px; transform:translateX(-50%);
  width:44px; height:4px; border-radius:2px; background:var(--brand-55); }
.rz-grab:hover::before,.rz-grab:active::before{ background:var(--brand); }
.rz-grab:focus-visible{ outline:2px solid var(--brand); outline-offset:-2px; border-radius:4px; }
.panel.collapsed .rz-grab{ display:none; }
/* The original's top-edge strip, inverted: it used to be the desktop handle and
   was hidden while collapsed (orig L237). The pill now owns the top edge whenever
   the panel is open — two overlapping hit areas only fight each other — so this
   one appears exactly when the pill is gone, and is what §7's "dragging up from
   collapsed expands" grabs. Absolutely positioned, so it adds nothing to the
   collapsed box's measured size. */
.rz-top{ display:none; position:absolute; top:0; left:14px; right:14px; height:9px;
  cursor:ns-resize; z-index:6; touch-action:none; }
.panel.collapsed .rz-top{ display:block; }

/* the right column slots: Top Creators over the activity bar. The original gave
   Leading Universities 280x188 at top 12 and the two panels this column merges
   (Influencers 150 + 12 gap + Mafias 180 = 342) from top 212. (orig initPanels)

   §3: Top Creators is nudged down off the top gutter (12 → 20) and grown to 240
   so its eight rows read at a glance. §2: the activity panel starts under it and
   runs to the page's own bottom gutter — the 12px the sidebar and the strip both
   use — instead of stopping at a fixed 342. Its internal scroll is unchanged. */
.col-slot{ position:fixed; right:12px; width:280px; z-index:12; display:flex; }
.col-slot > *{ flex:1; min-width:0; }
#creatorsbox{ top:20px; height:320px; }
#activitybox{ top:352px; bottom:12px; height:auto; }

/* §3 — bigger, more legible Top Creators rows. The module is read-only, so its
   metrics are raised from here, scoped to this slot. The original's Leading
   Universities row (orig L266-272: 12px name, 11px count, 5px bar, 8px gap,
   2px/3px padding) is the floor these sit above, not the ceiling. */
/* Row sizing lives in the module (top-creators.css) since the spacing pass:
   56 px rows, 32 px avatar, 6 px bar. The page owns placement and the title
   only — overriding the rows here shrank them back to 48 px. */
#creatorsbox .ph-title{ font-size:var(--fs-xl); }

/* ── bottom strip: memory rows (orig #resultsbar, dockBottom) ───────────── */
/* §4 — the height is a variable the drag writes and localStorage restores; 208px
   is the original's dockBottom default and the drag minimum. §7 — collapsed, the
   panel takes the original's toggleCollapse geometry exactly: right released,
   width and height auto, so it shrinks to its own header and the graph reclaims
   the space (measured in the reference at 1280x720: 111.72 x 44, left 320,
   bottom 12). The settle after a drag animates `height` — the panel genuinely
   has to reserve the space, since the camera's frame padding is measured from
   its rect, so a transform would lie about the layout. It runs once, for 220ms,
   on release only, and the reduced-motion block below collapses it to nothing. */
#resultsbar{ position:fixed; z-index:12; display:flex; flex-direction:column; overflow:hidden;
  left:320px; right:316px; bottom:12px; height:var(--strip-h, 208px);
  background:var(--paper-66);
  -webkit-backdrop-filter:var(--blur-panel); backdrop-filter:var(--blur-panel);
  border:1px solid var(--brand-20); border-radius:var(--r-16, 16px);
  box-shadow:var(--sh-4-panel); }
#resultsbar.snapping{ transition:height .22s cubic-bezier(.32,.72,0,1); }
#resultsbar.collapsed{ right:auto; width:auto; height:auto; }
#rzrows{ height:100%; overflow-y:auto; overflow-x:hidden; -webkit-overflow-scrolling:touch;
  overscroll-behavior:contain; scrollbar-width:thin;
  scrollbar-color:var(--border) transparent; }
.memory-row{ width:100%; display:grid;
  grid-template-columns:28px minmax(150px,1.15fr) minmax(120px,1fr) 70px 66px;
  align-items:center; gap:10px; padding:7px 6px; text-align:left;
  background:transparent; border:0; border-bottom:1px solid color-mix(in srgb, var(--border) 45%, transparent);
  font-size:var(--fs-md); color:var(--ink); border-radius:6px; }
.memory-row:hover{ background:var(--brand-06); }
.memory-row[aria-current="true"]{ background:var(--brand-08); }
.memory-row .avatar{ width:26px; height:26px; border-radius:7px; overflow:hidden;
  border:1px solid var(--border); flex:0 0 auto; display:grid; place-items:center;
  background:var(--white); }
.memory-row .avatar svg{ display:block; width:100%; height:100%; }
/* the creator identicon is a second target inside the row button, so it says
   so under the pointer: a brand ring, and nothing at rest */
.memory-row .avatar.agentchip{ cursor:pointer;
  transition:border-color var(--dur-140) var(--ease), box-shadow var(--dur-140) var(--ease); }
.memory-row .avatar.agentchip:hover{ border-color:var(--brand);
  box-shadow:0 0 0 2px var(--brand-20); }
.memory-row .rtitle,.memory-row .rdesc{ white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.memory-row .rtitle{ font-weight:var(--fw-semibold); }
.memory-row .rdesc{ font-size:var(--fs-sm); color:var(--graphite); }
.memory-row .rprice{ font-size:var(--fs-sm); font-family:var(--font-mono);
  font-variant-numeric:tabular-nums; }
.memory-row .rinfo{ font-size:var(--fs-sm); color:var(--brand); text-align:right; }
.memory-row.rowflash{ animation:rowflash 2.4s ease; }
@keyframes rowflash{ 0%,55%{ background:var(--brand-16); } 100%{ background:transparent; } }
.rz-empty{ padding:14px 8px; font-size:var(--fs-md-p); color:var(--graphite); }

/* ── detail card (orig L178-205, .detail) ───────────────────────────────────
   The original's shell, transcribed: 330px wide, 18px radius, 66% paper under
   blur(22px) saturate(1.25), a 1px brand-20 edge and the same shadow. Two
   things differ from orig L180, and both are the brief's §1:
   (a) the card is a FIXED-HEIGHT flex column instead of a content-height box
       with `max-height` — the header and the Recall footer are pinned and only
       `.body` scrolls, so the card never grows with content;
   (b) `overflow-y:auto` therefore moves from the card to `.body`.
   Visibility stays the `hidden` attribute (NOTES §2), so the engine's
   label-collision selector `#detail:not([hidden])` reserves it only when open. */
.detail{ position:fixed; top:16px; right:16px; width:330px; max-width:calc(100vw - 332px);
  z-index:30; border-radius:var(--r-18, 18px);
  background:var(--paper-66);
  -webkit-backdrop-filter:var(--blur-detail); backdrop-filter:var(--blur-detail);
  border:1px solid var(--brand-20); box-shadow:var(--sh-4-detail);
  display:flex; flex-direction:column; overflow:hidden;
  height:min(560px, calc(100vh - 32px)); }
.detail .dh{ padding:14px 16px; border-bottom:1px solid var(--border); position:relative;
  cursor:grab; flex:0 0 auto; }
.detail .x{ position:absolute; top:6px; right:8px; z-index:5; cursor:pointer;
  color:var(--graphite); font-size:var(--fs-18); line-height:1; padding:6px 9px;
  border-radius:var(--r-8, 8px); background:none; border:0; }
.detail .x:hover{ background:var(--brand-12); color:var(--ink); }

/* the header's logo-tile row (orig L191-193, .dh .top / .flogo). The tile is the
   original's 46px at radius 10 — the brief's table rounds it to 44. */
.detail .dh .top{ display:flex; align-items:center; gap:11px; padding-right:26px; }
.detail .flogo{ width:46px; height:46px; border-radius:var(--r-10, 10px); overflow:hidden;
  background:var(--white); border:1px solid var(--border); flex:0 0 auto; }
.detail .flogo svg{ display:block; width:100%; height:100%; }
.detail .dh .ti{ min-width:0; flex:1; }
.detail h2{ font-family:var(--font-display); font-size:var(--fs-17); font-weight:var(--fw-semibold);
  margin:0; letter-spacing:var(--ls-tight); line-height:1.25; }
.detail .sub{ font:var(--fs-md) var(--font-mono); color:var(--graphite); margin-top:4px;
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.detail .chip{ display:inline-block; font-size:var(--fs-sm); font-weight:var(--fw-semibold);
  text-transform:uppercase; letter-spacing:var(--ls-06); color:var(--white);
  padding:2px 7px; margin-right:5px; border-radius:3px; }
.detail .chip.ghost{ color:var(--graphite); background:transparent; border:1px solid var(--border); }
.detail .chiprow{ margin-top:9px; }

/* the icon-button row (orig L194-196, .socrow / .socbtn) */
.socrow{ display:flex; flex-wrap:wrap; gap:7px; margin-top:12px; }
.socbtn{ width:34px; height:34px; display:grid; place-items:center; border-radius:var(--r-8, 8px);
  border:1px solid var(--glass-edge-60); background:var(--glass-fill-50);
  box-shadow:var(--sh-1-card); text-decoration:none;
  font:var(--fw-bold) var(--fs-lg) var(--font-body); color:var(--ink); }
.socbtn:hover{ background:var(--brand-12); border-color:var(--brand); }
.socbtn[aria-pressed="true"]{ background:var(--brand); border-color:var(--brand); color:var(--white); }

/* only the body scrolls */
.detail .body{ padding:14px 16px; flex:1 1 auto; min-height:0;
  overflow-y:auto; overflow-x:hidden; overscroll-behavior:contain; scrollbar-width:thin;
  scrollbar-color:var(--border) transparent; }
/* the on-chain provenance badge's place in the body (it renders only when the
   chain confirms the memory; the slot is empty otherwise and costs no height) */
.detail .proof-slot:empty{ display:none; }

/* the slim pinned Recall footer — the card's one action, in the same pattern
   the recall drawer already uses (the brief's §1: the original had none) */
.detail .dfoot{ display:flex; align-items:center; gap:10px; flex:0 0 auto;
  padding:8px 12px 8px 16px; border-top:1px solid var(--border); background:var(--paper-97);
  -webkit-backdrop-filter:var(--blur-10); backdrop-filter:var(--blur-10); }
/* the price line: the fee the record carries, or the beta's "Free" — read,
   never computed (marketplace.js priceHTML) */
.detail .dfoot .amt{ font:var(--fs-lg-p) var(--font-mono); font-variant-numeric:tabular-nums;
  min-width:0; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.detail .dfoot .amt span{ font-size:var(--fs-sm); color:var(--graphite); }
/* the whole button is the target — 44px tall, the touch minimum — at the same
   face, radius and colour it always had */
.detail .dfoot .btn-recall{ margin-left:auto; flex:0 0 auto; min-height:44px;
  padding:0 22px; font-size:var(--fs-lg); }

/* the receipt preview the third icon button toggles — real split, no invented
   transaction: nothing has been recalled yet, and the block says so */
.receipt{ margin-top:12px; padding:9px 11px; border-radius:var(--r-11, 11px);
  background:var(--glass-fill-55); border:1px solid var(--glass-edge-85); }
.receipt .rcp-h{ font:var(--fw-bold) var(--fs-sm) var(--font-display); letter-spacing:var(--ls-09);
  text-transform:uppercase; color:var(--acc); margin-bottom:7px; }
.receipt .rcp-r{ display:flex; justify-content:space-between; gap:10px;
  font-size:var(--fs-md); color:var(--graphite); margin-top:3px; }
.receipt .rcp-r b{ font-family:var(--font-mono); color:var(--ink); font-weight:var(--fw-semibold); }
.receipt .rcp-note{ margin-top:7px; font-size:var(--fs-sm); color:var(--graphite); }
.detail .body p{ font-size:var(--fs-base-p); line-height:var(--lh-loose); margin:0 0 12px; }
.detail .kv{ font-size:var(--fs-md); color:var(--graphite); margin-bottom:6px; }
.detail .kv b{ color:var(--ink); }
.fsec{ margin-top:16px; }
.fsec .fh{ font-size:var(--fs-sm); font-weight:var(--fw-bold); text-transform:uppercase;
  letter-spacing:.1em; color:var(--acc); margin-bottom:9px; }
.creator-row{ display:flex; align-items:center; gap:10px; padding:8px;
  border:1px solid var(--glass-edge-60); border-radius:11px; background:var(--glass-fill-50);
  box-shadow:var(--sh-1-card); }
/* the row is an <a> now (NOTES §32). It inherits the card's ink rather than
   the UA link colour, and answers the pointer with .lin-link's own hover —
   the same border and fill the lineage rows beneath it already move to. */
a.creator-row{ color:inherit; text-decoration:none;
  transition:border-color var(--dur-140) var(--ease), background var(--dur-140) var(--ease); }
a.creator-row:hover{ border-color:var(--brand-55); background:var(--glass-fill-72); }
a.creator-row:focus-visible{ outline:2px solid var(--brand-55); outline-offset:2px; }
a.creator-row:hover .cn{ color:var(--brand); }
.creator-row .cr-open{ width:auto; flex:0 0 auto; }
/* the agent:// token in the card's meta line */
.detail .sub a.agentlink{ color:inherit; text-decoration:none;
  transition:color var(--dur-140) var(--ease); }
.detail .sub a.agentlink:hover{ color:var(--brand); text-decoration:underline;
  text-underline-offset:2px; }
.detail .sub a.agentlink:focus-visible{ outline:2px solid var(--brand-55); outline-offset:2px;
  border-radius:3px; }
.creator-row .cav{ width:34px; height:34px; border-radius:9px; overflow:hidden; flex:0 0 auto;
  border:1px solid var(--border); background:var(--white); }
.creator-row .cav svg{ display:block; width:100%; height:100%; }
.creator-row .ci{ min-width:0; flex:1; }
/* .cn and .cm are spans; as inline boxes they stacked only when the id happened
   to wrap, which broke the meta line mid-phrase (found while the demo transcribed
   this card). Block boxes give the ellipsis a width and keep the meta on its
   own line at every card width. */
.creator-row .cn{ display:block; font:var(--fw-semibold) var(--fs-base-p) var(--font-mono);
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.creator-row .cm{ display:block; font-size:var(--fs-sm-p); color:var(--graphite); margin-top:2px; }

/* The performance figures live in the original's `.kv` row rhythm now (orig
   L187: `Region / Team size / Status`), so the two-column `.perf` grid is gone.
   `.kv b` is the original's label weight; `.kv .kvn` is the one addition — the
   monospace numeral, so success rates and recall counts stay column-aligned. */
.detail .kv .kvn{ font-family:var(--font-mono); font-variant-numeric:tabular-nums;
  color:var(--ink); }
.detail .kv .sv{ margin-left:4px; }
.detail .kv .sv b{ font-family:var(--font-mono); font-weight:var(--fw-semibold); }

.btn-recall{ border:1px solid var(--brand); background:var(--brand);
  color:var(--white); font:var(--fw-semibold) var(--fs-base-p) var(--font-display);
  padding:9px 16px; border-radius:11px; transition:background .14s ease, transform .12s ease; }
.btn-recall:hover{ background:var(--brand-88); border-color:var(--brand-88); }
.btn-recall:active{ transform:scale(.97); }
.btn-recall:focus-visible{ outline:2px solid var(--brand-55); outline-offset:2px; }

/* compatibility chips */
.compat{ display:flex; flex-wrap:wrap; gap:5px; }
.compat .cchip{ font-size:var(--fs-sm-p); font-weight:var(--fw-semibold); color:var(--ink);
  padding:2px 9px; border-radius:20px; background:var(--glass-fill-55);
  border:1px solid var(--glass-edge-85); box-shadow:var(--sh-1-tight); }
.compat .cchip.limited{ color:var(--graphite); }
.compat .cchip i{ font-style:normal; margin-right:4px; }

/* freshness meter — SPEC §29 */
.fresh-meter{ margin-top:4px; }
.fresh-bar{ height:8px; border-radius:4px; background:color-mix(in srgb, var(--border) 70%, transparent);
  overflow:hidden; }
.fresh-bar i{ display:block; height:100%; border-radius:4px; background:var(--brand); opacity:.85; }
.fresh-bar.aging i{ background:var(--regdot); }
.fresh-bar.stale i{ background:var(--danger); }
.fresh-num{ display:flex; justify-content:space-between; font-size:var(--fs-sm);
  color:var(--graphite); margin-top:5px; }
.fresh-num b{ font-family:var(--font-mono); color:var(--ink); }
.decay{ margin-top:10px; padding:9px 11px; border-radius:11px;
  background:var(--glass-fill-55); border:1px solid var(--glass-edge-85); }
.decay .dh2{ font:var(--fw-bold) var(--fs-sm) var(--font-display); letter-spacing:var(--ls-09);
  text-transform:uppercase; color:var(--regdot); }
.decay.stale .dh2{ color:var(--danger); }
.decay p{ font-size:var(--fs-md) !important; line-height:var(--lh-relaxed) !important;
  margin:5px 0 0 !important; color:var(--graphite); }
.decay .offbanner{ display:flex; align-items:center; gap:7px; margin-top:8px;
  font-size:var(--fs-base); font-weight:var(--fw-semibold); color:var(--danger); }
.reddot{ width:9px; height:9px; border-radius:50%; background:var(--danger-strong);
  display:inline-block; box-shadow:var(--sh-ring-danger); flex:0 0 auto; }

/* lineage links */
.lineage{ display:flex; flex-direction:column; gap:6px; }
.lin-link{ display:flex; align-items:center; gap:8px; padding:6px 8px; border-radius:9px;
  background:var(--glass-fill-50); border:1px solid var(--glass-edge-60);
  font-size:var(--fs-md); color:var(--ink); text-align:left; width:100%;
  box-shadow:var(--sh-1-card); }
.lin-link:hover{ border-color:var(--brand-55); background:var(--glass-fill-72); }
.lin-link .lid{ font-family:var(--font-mono); font-weight:var(--fw-semibold); flex:0 0 auto; }
.lin-link .lnm{ min-width:0; flex:1; color:var(--graphite); white-space:nowrap;
  overflow:hidden; text-overflow:ellipsis; }
.lin-link .lrole{ font-size:var(--fs-xs); text-transform:uppercase; letter-spacing:var(--ls-05);
  color:var(--brand); flex:0 0 auto; }
.lin-none{ font-size:var(--fs-md); color:var(--graphite); }

/* ── the card's deep sections ─────────────────────────────────────────────
   The memory detail page was ruled into the card, so six more sections live
   under the four the card already carries — proof of experience, the outcome
   receipt, quality dimensions, the royalty split, the lineage tree and the
   `.md` payload itself. All six are collapsed at rest and open on the shared
   accordion from src/shared/nav.js: the same ~200ms grid-row reveal and the
   same keyboard model as the brand-row nav, so the card and the sidebar move
   the same way.

   The header IS `.fsec .fh` — the card's own uppercase section label — made a
   full-width button with the site's ▾ chevron on the right. Nothing new is
   introduced above the card's existing row rhythm: rows are `.kv`-height, the
   bars are the freshness meter's 8px track, and every block sits on the
   `.receipt` / `.decay` glass the card already uses. */
.dsec{ border-top:1px solid var(--border); }
.dsec:first-of-type{ margin-top:16px; }     /* the .fsec gap, once */
.dsec-h{ display:flex; align-items:center; gap:8px; width:100%;
  padding:11px 2px; background:none; border:0; text-align:left;
  font-size:var(--fs-sm); font-weight:var(--fw-bold); text-transform:uppercase;
  letter-spacing:.1em; color:var(--acc);
  transition:color var(--dur-140) var(--ease); }
/* pointer-only, so a tap does not leave the header stuck in its hover ink */
@media (hover:hover){
  .dsec-h:hover{ color:var(--ink); }
  .dsec-h:hover .acc-chev{ color:var(--ink); }
}
.dsec-h .dsec-t{ min-width:0; }
/* the one-line summary the closed row carries, so a shut section still says
   what is inside it: the count, the score, the amount */
.dsec-h .dsec-m{ margin-left:auto; font:var(--fw-semibold) var(--fs-sm) var(--font-mono);
  color:var(--graphite); text-transform:none; letter-spacing:0; }
.dsec-h .dsec-m + .acc-chev{ margin-left:6px; }
.dsec-body{ padding:2px 2px 14px; }

/* rows inside a section, at the card's `.kv` rhythm */
/* A label/value row that survives long values (a guest provenance sentence, a
   long creator id, a transaction hash). The value may shrink and WRAP; nothing
   here has a fixed height or `nowrap`, so rows grow with their content and the
   label and value never overlap. When the value cannot share the line it drops
   under the label (flex-wrap); on the phone it always does. */
.dsec-r{ display:flex; flex-wrap:wrap; align-items:baseline; gap:2px 10px; font-size:var(--fs-md);
  color:var(--graphite); margin-bottom:6px; }
.dsec-r > span:first-child{ flex:1 1 auto; min-width:0; }
.dsec-r b{ font-family:var(--font-mono); font-variant-numeric:tabular-nums;
  color:var(--ink); font-weight:var(--fw-semibold); flex:1 1 140px; min-width:0; max-width:100%;
  text-align:right; white-space:normal; overflow-wrap:anywhere; line-height:1.4; }
.dsec-r b.rv-plain{ font-family:var(--font-body); }
.dsec-note{ font-size:var(--fs-sm); color:var(--graphite); line-height:var(--lh-relaxed);
  margin-top:8px; }
.dsec-sub{ font:var(--fw-bold) var(--fs-sm) var(--font-display); letter-spacing:var(--ls-09);
  text-transform:uppercase; color:var(--graphite); margin:10px 0 6px; }
.dsec-sub:first-child{ margin-top:0; }

/* verification results — a check row and its verdict pill */
.pv{ display:flex; flex-wrap:wrap; gap:5px; }
.pv-i{ display:inline-flex; align-items:center; gap:5px; font-size:var(--fs-sm-p);
  font-weight:var(--fw-semibold); color:var(--ink); padding:2px 9px; border-radius:20px;
  background:var(--glass-fill-55); border:1px solid var(--glass-edge-85);
  box-shadow:var(--sh-1-tight); }
.pv-i i{ font-style:normal; color:var(--ok-text); }
/* an unverified check is not a failed one: it is stated, dashed, and grey —
   colour is never the only carrier (the same rule the dark block states) */
.pv-i.pv-unk{ color:var(--graphite); border-style:dashed; }
.pv-i.pv-unk i{ color:var(--graphite); }

/* quality dimensions — the freshness meter's track, five times */
.qd{ display:flex; flex-direction:column; gap:8px; }
.qd-r{ display:grid; grid-template-columns:1fr auto; gap:2px 8px; align-items:center; }
.qd-r .qd-l{ font-size:var(--fs-md); color:var(--graphite); }
.qd-r .qd-v{ font:var(--fw-semibold) var(--fs-md) var(--font-mono);
  font-variant-numeric:tabular-nums; color:var(--ink); }
.qd-bar{ grid-column:1/-1; height:8px; border-radius:4px;
  background:color-mix(in srgb, var(--border) 70%, transparent); overflow:hidden; }
.qd-bar i{ display:block; height:100%; border-radius:4px; background:var(--brand);
  opacity:.85; }
.qd-r.qd-agg{ margin-top:2px; padding-top:8px; border-top:1px solid var(--border); }
.qd-r.qd-agg .qd-l{ color:var(--ink); font-weight:var(--fw-semibold); }
.qd-r.qd-agg .qd-bar i{ opacity:1; }

/* the royalty split — one stacked bar, then the three shares */
.rs-bar{ display:flex; height:8px; border-radius:4px; overflow:hidden;
  background:color-mix(in srgb, var(--border) 70%, transparent); margin-bottom:10px; }
.rs-bar i{ display:block; height:100%; }
.rs-k{ width:9px; height:9px; border-radius:2px; flex:0 0 auto; }
.dsec-r.rs-r{ align-items:center; }

/* the outcome receipt */
.rcpt-hash{ display:block; font:var(--fs-sm) var(--font-mono); color:var(--ink);
  word-break:break-all; line-height:var(--lh-relaxed); padding:7px 9px;
  border-radius:var(--r-8, 8px); background:var(--glass-fill-55);
  border:1px solid var(--glass-edge-85); margin-bottom:9px; }
.rcpt-open{ display:inline-flex; align-items:center; gap:6px; font-size:var(--fs-md);
  font-weight:var(--fw-semibold); color:var(--brand); background:none;
  border:1px solid var(--brand-24); border-radius:var(--r-8, 8px); padding:5px 10px;
  transition:background var(--dur-140) var(--ease), border-color var(--dur-140) var(--ease); }
.rcpt-open:hover{ background:var(--brand-08); border-color:var(--brand); }

/* the lineage tree — the card's .lin-link row, indented by generation */
.ltree{ display:flex; flex-direction:column; gap:6px; }
.ltree .lt-row{ position:relative; }
.ltree .lt-row[data-gen="1"]{ margin-left:12px; }
.ltree .lt-row[data-gen="2"]{ margin-left:24px; }
/* the elbow: the tree's only new mark, in the hairline the card already uses */
.ltree .lt-row[data-gen]:not([data-gen="0"])::before{
  content:""; position:absolute; left:-8px; top:-7px; bottom:50%; width:7px;
  border-left:1px solid var(--border); border-bottom:1px solid var(--border);
  border-bottom-left-radius:6px; pointer-events:none; }
.ltree .lin-link.is-this{ border-color:var(--brand-35); background:var(--brand-08);
  cursor:default; }
.ltree .lin-link.is-this .lnm{ color:var(--ink); }
.lt-fork{ display:flex; align-items:center; gap:6px; margin-top:9px;
  font-size:var(--fs-md); font-weight:var(--fw-semibold); color:var(--brand);
  background:none; border:1px solid var(--brand-24); border-radius:var(--r-8, 8px);
  padding:5px 10px; text-decoration:none; width:auto;
  transition:background var(--dur-140) var(--ease), border-color var(--dur-140) var(--ease); }
a.lt-fork:hover{ background:var(--brand-08); border-color:var(--brand); }
/* not built yet: visible, muted, dashed — never dimmed (dark contrast floor) */
.lt-fork.is-soon{ color:var(--graphite); border-style:dashed; cursor:default; }
.lt-fork .nav-tag{ font:var(--fw-semibold) var(--fs-sm)/1 var(--font-mono);
  color:var(--graphite); }

/* the rendered payload */
.md-body{ font-size:var(--fs-md-p); line-height:var(--lh-relaxed); color:var(--ink); }
.md-body > :first-child{ margin-top:0; }
.md-body h1,.md-body h2,.md-body h3,.md-body h4,.md-body h5,.md-body h6{
  font-family:var(--font-display); font-size:var(--fs-base-p); font-weight:var(--fw-bold);
  letter-spacing:var(--ls-tight); color:var(--ink); margin:12px 0 5px; }
.md-body h1{ font-size:var(--fs-lg); }
.md-body p{ font-size:var(--fs-md-p) !important; line-height:var(--lh-relaxed) !important;
  margin:0 0 8px !important; color:var(--graphite); }
.md-body ul,.md-body ol{ margin:0 0 8px; padding-left:18px; color:var(--graphite); }
.md-body li{ margin-bottom:3px; }
.md-body code{ font:var(--fs-sm) var(--font-mono); color:var(--ink);
  background:var(--glass-fill-55); border:1px solid var(--glass-edge-85);
  border-radius:4px; padding:0 4px; }
.md-body pre{ margin:0 0 9px; padding:8px 9px; border-radius:var(--r-8, 8px);
  background:var(--glass-fill-55); border:1px solid var(--glass-edge-85);
  overflow-x:auto; }
.md-body pre code{ background:none; border:0; padding:0; white-space:pre; }
.md-body hr{ border:0; border-top:1px solid var(--border); margin:10px 0; }
.md-body strong{ color:var(--ink); font-weight:var(--fw-semibold); }
.md-state{ font-size:var(--fs-md); color:var(--graphite); }
.md-raw{ display:inline-block; margin-top:8px; font-size:var(--fs-sm);
  color:var(--brand); text-decoration:none; }
.md-raw:hover{ text-decoration:underline; text-underline-offset:2px; }

/* ── the receipt modal ────────────────────────────────────────────────────
   The card's own glass at dialog size, on the page's modal scrim. It is the
   one thing on the card that leaves the card, because a receipt is a document
   and a 298px column cannot hold one legibly. */
#rcptModal{ position:fixed; inset:0; z-index:3200; display:none; }
#rcptModal.on{ display:block; }
#rcptModal .rm-scrim{ position:absolute; inset:0; background:var(--scrim-modal);
  -webkit-backdrop-filter:var(--blur-xs); backdrop-filter:var(--blur-xs); }
#rcptModal .rm-box{ position:absolute; top:50%; left:50%; transform:translate(-50%,-50%);
  width:min(460px, calc(100vw - 32px)); max-height:min(560px, calc(100vh - 48px));
  display:flex; flex-direction:column; overflow:hidden;
  border-radius:var(--r-18, 18px); background:var(--paper-95);
  -webkit-backdrop-filter:var(--blur-detail); backdrop-filter:var(--blur-detail);
  border:1px solid var(--brand-22); box-shadow:var(--sh-4-detail); }
#rcptModal .rm-h{ display:flex; align-items:center; gap:10px; flex:0 0 auto;
  padding:12px 14px; border-bottom:1px solid var(--border); }
#rcptModal .rm-t{ font-family:var(--font-display); font-size:var(--fs-lg-p);
  font-weight:var(--fw-semibold); }
#rcptModal .rm-x{ margin-left:auto; color:var(--graphite); font-size:var(--fs-18);
  line-height:1; padding:6px 9px; border-radius:var(--r-8, 8px); background:none; border:0; }
#rcptModal .rm-x:hover{ background:var(--brand-12); color:var(--ink); }
#rcptModal .rm-b{ flex:1 1 auto; min-height:0; overflow:auto; padding:12px 14px;
  overscroll-behavior:contain; }
#rcptModal pre{ margin:0; font:var(--fs-md) var(--font-mono); color:var(--ink);
  white-space:pre; }
#rcptModal .rm-f{ flex:0 0 auto; padding:9px 14px; border-top:1px solid var(--border);
  font-size:var(--fs-sm); color:var(--graphite); }

/* the activity feed's actor tokens, tagged by marketplace.js with the agent
   they name (NOTES §32). Untagged tokens — the viewer's own live rows — get
   nothing, so the affordance never promises a page that does not exist. */
#activitybox :is(.act-actor,.act-agent)[data-agent]:not([data-agent=""]){
  cursor:pointer; transition:color var(--dur-140) var(--ease); }
#activitybox :is(.act-actor,.act-agent)[data-agent]:not([data-agent=""]):hover{
  color:var(--brand); text-decoration:underline; text-underline-offset:2px; }
/* there is no hover on touch, and the token is the one link on this page with
   no shape of its own to give it away, so it states itself at rest instead */
@media (hover:none){
  #activitybox :is(.act-actor,.act-agent)[data-agent]:not([data-agent=""]){
    text-decoration:underline dotted; text-underline-offset:2px;
    text-decoration-thickness:1px; }
}

/* ── Top Creators: the host-added profile link ───────────────────────────
   The module's rows are <button>s and may not be edited, so marketplace.js
   wraps each one and lays this anchor over the row's bottom-right corner —
   inside the 13.5px hover line the module already reserves and reveals, so
   the link costs no height and the ranking cannot jump. */
#creatorsbox .tc-wrap{ position:relative; display:block; flex:0 0 auto; }
#creatorsbox .tc-profile{ position:absolute; right:6px; bottom:7px;
  font:var(--fs-sm)/1.15 var(--font-mono-short); color:var(--brand);
  text-decoration:none; padding:1px 3px; border-radius:4px;
  background:var(--paper-97); white-space:nowrap;
  opacity:0; transition:opacity var(--dur-320) var(--ease); }
#creatorsbox .tc-wrap:hover .tc-profile,
#creatorsbox .tc-profile:focus-visible{ opacity:1; }
#creatorsbox .tc-profile:hover{ text-decoration:underline; text-underline-offset:2px; }
#creatorsbox .tc-profile:focus-visible{ outline:2px solid var(--brand-55); outline-offset:1px; }
/* the hover line is the row's, so it must not vanish when the pointer
   crosses onto the link, which is a sibling of the row and not inside it */
#creatorsbox .tc-wrap:hover .tc-meta{ opacity:1; }
/* and it gives up the width the link occupies rather than running under it */
#creatorsbox .tc-meta{ padding-right:52px; }
@media (hover:none){
  #creatorsbox .tc-profile{ opacity:1; }
}
@media (prefers-reduced-motion:reduce){
  #creatorsbox .tc-profile{ transition:none; }
}

/* ── tile toolbar (orig L353-366, #dbBtn and friends) ───────────────────── */
/* Five equal glass tiles on the original's 38px / 8px-gap rhythm, so the row
   steps 320 · 366 · 412 · 458 · 504. No tile carries the original's filled
   primary treatment any more: Frame matches is gone, nothing replaced it. */
#xBtn,#tourBtn,#orbitBtn,#recenterBtn,#themeBtn{ position:fixed; top:12px; z-index:900;
  width:38px; height:38px; border-radius:11px; cursor:pointer; display:grid; place-items:center;
  padding:0; color:var(--brand); background:var(--paper-72); text-decoration:none;
  -webkit-backdrop-filter:var(--blur-tile); backdrop-filter:var(--blur-tile);
  border:1px solid var(--brand-20); box-shadow:var(--sh-3-tile);
  transition:background .14s ease, border-color .14s ease, opacity .14s ease; }
#xBtn{ left:320px; }
#tourBtn{ left:366px; font-size:var(--fs-2xl); }
#orbitBtn{ left:412px; }
#recenterBtn{ left:458px; }
#themeBtn{ left:504px; }
#xBtn svg{ width:15px; height:15px; display:block; }
#orbitBtn svg,#recenterBtn svg,#themeBtn svg{ width:18px; height:18px; display:block; }
#orbitBtn[aria-pressed="false"]{ opacity:.7; }
#xBtn:hover,#tourBtn:hover,#orbitBtn:hover,#recenterBtn:hover,#themeBtn:hover{
  background:var(--brand-14); opacity:1; }
/* two glyphs stacked in one cell, so a state swap cross-fades instead of
   cutting. 140ms is the row's hover budget; reduced motion collapses it. */
.tile-ic{ display:grid; place-items:center; width:18px; height:18px; }
.tile-ic > svg{ grid-area:1/1; transition:opacity .14s ease, transform .14s ease; }
#orbitBtn .ic-play{ opacity:0; transform:scale(.72) rotate(-16deg); }
#orbitBtn[aria-pressed="false"] .ic-play{ opacity:1; transform:none; }
#orbitBtn[aria-pressed="false"] .ic-pause{ opacity:0; transform:scale(.72) rotate(16deg); }
/* the theme tile is live: marketplace.js flips data-theme on the root and the
   two glyphs cross-fade on the row's existing 140ms hover budget, exactly as the
   orbit tile's play/pause pair does. The icon is derived from the attribute, so
   it cannot disagree with the theme the page is actually in. */
#themeBtn .ic-sun{ opacity:0; transform:scale(.72) rotate(-16deg); }
html[data-theme="dark"] #themeBtn .ic-sun{ opacity:1; transform:none; }
html[data-theme="dark"] #themeBtn .ic-moon{ opacity:0; transform:scale(.72) rotate(16deg); }
/* both sit just above the strip, so they ride its measured height (--strip-chrome
   is the strip's real outer height, written by the resize/collapse code) */
.fps{ position:fixed; left:320px; bottom:calc(var(--strip-chrome, 208px) + 24px); z-index:11;
  font:9px var(--font-mono); color:var(--graphite); pointer-events:none; }
.orbit-note{ position:fixed; right:316px; bottom:calc(var(--strip-chrome, 208px) + 24px); z-index:11;
  font:9px var(--font-mono); color:var(--graphite); pointer-events:none; }

/* floating reset chip (orig L278-284, #resetFly) */
#resetFly{ position:fixed; top:12px; left:50%; transform:translateX(-50%); z-index:901;
  display:none; align-items:center; gap:7px; font:var(--fw-semibold) var(--fs-md-p) var(--font-display);
  color:var(--brand); cursor:pointer; padding:8px 14px; border-radius:20px;
  background:var(--paper-62);
  -webkit-backdrop-filter:var(--blur-lg); backdrop-filter:var(--blur-lg);
  border:1px solid var(--brand-24); box-shadow:var(--sh-3-reset); }
#resetFly.show{ display:inline-flex; }
#resetFly:hover{ background:var(--brand); color:var(--white); }

/* ── onboarding tour (orig L318-330, L617-623) ─────────────────────────── */
#tour{ position:fixed; inset:0; z-index:3000; display:none; }
#tour.on{ display:block; }
#tourScrim{ position:absolute; inset:0; background:transparent;
  transition:background .3s, backdrop-filter .3s; }
#tour.greet #tourScrim{ background:var(--scrim-tour);
  -webkit-backdrop-filter:var(--blur-sm); backdrop-filter:var(--blur-sm); }
#tourHole{ position:absolute; border-radius:var(--r-16, 16px); box-shadow:var(--sh-tour-hole);
  border:2px solid var(--glass-edge-90); opacity:0; pointer-events:none;
  transition:left .4s cubic-bezier(.3,.7,.3,1), top .4s cubic-bezier(.3,.7,.3,1),
    width .4s cubic-bezier(.3,.7,.3,1), height .4s cubic-bezier(.3,.7,.3,1), opacity .4s ease; }
#tourTip{ position:absolute; width:min(300px, calc(100vw - 24px)); background:var(--white);
  border-radius:14px; padding:15px 16px 12px; box-shadow:var(--sh-5-tour);
  transition:left .35s, top .35s; }
#tourTip .tt-mark{ display:none; margin-bottom:9px; font:300 22px/1 Jost, var(--font-display);
  letter-spacing:.28em; color:var(--brand); }
#tourTip .tt-title{ font-family:var(--font-display); font-weight:var(--fw-bold);
  font-size:var(--fs-16); margin-bottom:6px; color:var(--tour-ink); }
#tourTip .tt-lead{ font-size:var(--fs-lg-p); line-height:var(--lh-relaxed); color:var(--tour-ink); }
#tourTip .tt-type{ font-size:var(--fs-lg); line-height:var(--lh-relaxed); color:var(--tour-muted);
  margin-top:4px; min-height:20px; }
#tourTip .tt-caret{ display:inline-block; width:2px; height:1em; background:var(--brand);
  vertical-align:-2px; margin-left:1px; animation:ttblink 1s step-end infinite; }
@keyframes ttblink{ 50%{ opacity:0; } }
#tourTip .tt-row{ display:flex; align-items:center; justify-content:space-between; margin-top:12px; }
#tourTip .tt-skip{ font-size:var(--fs-base); color:var(--tour-skip); cursor:pointer;
  background:none; border:none; padding:4px; }
#tourTip .tt-next{ font-size:var(--fs-base-p); font-weight:var(--fw-semibold); color:var(--white);
  background:var(--brand); border:none; border-radius:var(--r-8, 8px); padding:8px 14px; cursor:pointer; }
/* the last step's second action, beside Done. The row is space-between, so
   the gap only takes effect once four items fill it. */
#tourTip .tt-row{ gap:6px; }
#tourTip .tt-demo{ font-size:var(--fs-base); color:var(--brand); text-decoration:none;
  white-space:nowrap; padding:4px;
  transition:color var(--dur-140) var(--ease); }
#tourTip .tt-demo:hover{ text-decoration:underline; text-underline-offset:2px; }
#tourTip .tt-demo:focus-visible{ outline:2px solid var(--brand-55); outline-offset:1px;
  border-radius:4px; }
#tourTip .tt-dots{ display:flex; gap:5px; flex:0 1 auto; overflow:hidden; }
#tourTip .tt-dots i{ width:6px; height:6px; border-radius:50%; background:var(--tour-dot-off); }
#tourTip .tt-dots i.on{ background:var(--brand); }

/* ── phone chrome (orig L624-714) ──────────────────────────────────────── */
#mofilter,#moscrim{ display:none; }

@media (max-width:768px){
  /* the original's phone dashboard: a top row of three tiles, the results bar at
     the bottom, the graph between; the sidebar becomes a centred sheet. */
  #creatorsbox,#activitybox{ position:fixed !important; top:6px !important; bottom:auto !important;
    height:132px !important; width:calc((100vw - 24px)/3) !important; right:auto !important; z-index:20; }
  #creatorsbox{ left:6px !important; }
  #activitybox{ left:calc((100vw - 24px)/3 + 12px) !important; }
  /* the original's phone tile rules for #unibox / #influbox (orig L658-668),
     applied to the two modules that now occupy those slots */
  #creatorsbox .panel-head,#activitybox .panel-head{ padding:8px 9px 4px; }
  #creatorsbox .ph-title,#activitybox .ph-title{ font-size:var(--fs-md-p); }
  #creatorsbox .ph-sub,#activitybox .ph-sub{ display:none !important; }
  #creatorsbox .panel-body,#activitybox .panel-body{ padding:0 8px 8px; }
  #creatorsbox .tc-row{ padding:2px 2px; }
  #creatorsbox .tc-nm{ font-size:11px; } #creatorsbox .tc-ct{ font-size:var(--fs-sm); }
  /* the phone tile is (100vw-24)/3 wide — 122px at 390 — and the word
     "profile" does not fit beside a 4-hex URI. The affordance keeps the same
     place and the same link and drops to its arrow, permanently visible
     because there is no hover here. The reserved line under it is blank on
     this breakpoint (.tc-meta never reveals without hover), so the arrow sits
     in space nothing else is using. See NOTES §32 for the touch-size limit. */
  #creatorsbox .tc-profile{ font-size:var(--fs-xs); right:1px; bottom:1px;
    padding:3px 4px; opacity:1; background:none; }
  #creatorsbox .tc-profile .word{ display:none; }
  #creatorsbox .tc-meta{ padding-right:0; }
  #activitybox .act-row{ gap:6px; padding:3px 2px; }
  #activitybox .act-amt{ font-size:10.5px; }
  #activitybox .act-av,#activitybox .act-av .av-a,#activitybox .act-av .av-b,
  #activitybox .act-av svg,#activitybox .act-av img{ width:20px; height:20px; }
  /* the original's tile rows are one short name; these are whole sentences, so
     they get the same single-line ellipsis the tile rows already used */
  #activitybox .act-line{ font-size:11px; white-space:nowrap; overflow:hidden;
    text-overflow:ellipsis; min-width:0; }
  #activitybox .act-i{ min-width:0; }
  /* a 122px tile cannot wrap seven chips and still show a feed: the chip row
     scrolls sideways instead, so every kind stays reachable */
  #activitybox .act-chips{ flex-wrap:nowrap; overflow-x:auto; scrollbar-width:none;
    -webkit-overflow-scrolling:touch; overscroll-behavior:contain; }
  #activitybox .act-chips::-webkit-scrollbar{ display:none; }
  #activitybox .act-chip{ flex:0 0 auto; }
  #mofilter{ display:flex; flex-direction:column; position:fixed; top:6px; right:6px;
    overflow:hidden; width:calc((100vw - 24px)/3); height:132px; z-index:20;
    border-radius:var(--r-16, 16px); padding:8px 9px; color:var(--ink);
    background:var(--paper-66);
    -webkit-backdrop-filter:var(--blur-10); backdrop-filter:var(--blur-10);
    border:1px solid var(--brand-20); box-shadow:var(--sh-3-mofilter); }
  #mofilter .mf-h{ font:var(--fw-bold) var(--fs-md-p) var(--font-display); color:var(--acc);
    margin-bottom:6px; display:flex; align-items:center; gap:5px; flex:0 0 auto; }
  #mofilter .mf-h .mf-n{ font:var(--fw-bold) var(--fs-xs) var(--font-mono); color:var(--brand); }
  #mofilter .mf-reset{ display:none; margin-left:auto; font:var(--fw-bold) var(--fs-xs) var(--font-display);
    color:var(--white); background:var(--brand); border:0; border-radius:6px; padding:3px 7px;
    cursor:pointer; white-space:nowrap; }
  #mofilter .mf-reset.show{ display:inline-flex; align-items:center; }
  #mofilter .mf-body{ display:flex; flex-direction:column; gap:5px; overflow-y:auto; min-height:0;
    -webkit-overflow-scrolling:touch; overscroll-behavior:contain; }
  #mofilter .mf-grp{ font:var(--fw-bold) 8.5px var(--font-body); text-transform:uppercase;
    letter-spacing:var(--ls-08); color:var(--graphite); margin-top:2px; }
  #mofilter .mf-chips{ display:flex; flex-wrap:wrap; gap:4px; }
  #mofilter .mfc{ font-size:var(--fs-xs-p); padding:3px 6px; border-radius:7px;
    border:1px solid var(--border); background:var(--white); cursor:pointer;
    display:inline-flex; align-items:center; gap:4px; white-space:nowrap; color:var(--ink); }
  #mofilter .mfc[data-d]::before{ content:""; width:6px; height:6px; border-radius:50%; background:var(--d); }
  #mofilter .mfc.on{ background:var(--brand); color:var(--white); border-color:var(--brand); }
  #mofilter .mf-more{ margin-top:auto; font:var(--fw-semibold) var(--fs-sm) var(--font-body);
    color:var(--brand); background:none; border:none; cursor:pointer; text-align:left;
    padding:5px 0 1px; flex:0 0 auto; }

  #resultsbar{ left:6px !important; right:6px !important;
    bottom:calc(16px + env(safe-area-inset-bottom,0px)) !important; top:auto !important;
    height:var(--strip-h, 172px) !important; }
  /* collapsed on a phone keeps the original's shrink-to-header box too */
  #resultsbar.collapsed{ right:auto !important; width:auto !important; height:auto !important; }
  #resultsbar .panel-head{ padding:7px 10px 4px; }
  #resultsbar .ph-title{ font-size:var(--fs-md-p); }
  #resultsbar .ph-sub{ font-size:var(--fs-md); }
  #resultsbar .rz-logo{ width:20px; height:20px; border-radius:5px; }
  #resultsbar .rz-logo span{ font-size:11px; }
  .panel-head .rz-seg button{ font-size:var(--fs-xs-p); padding:3px 7px; }
  /* a fatter touch target for the same pill; the top-edge strip stands down so
     it cannot swallow the pill's touches (orig L238) */
  .rz-grab{ height:18px; margin-bottom:-4px; }
  .rz-grab::before{ top:7px; }
  .memory-row{ grid-template-columns:24px minmax(96px,1fr) 58px; padding:9px 6px; min-height:48px; gap:8px; }
  .memory-row .rdesc,.memory-row .rinfo{ display:none; }
  .memory-row .rtitle{ font-size:var(--fs-sm); white-space:normal;
    display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical; overflow:hidden; }
  .memory-row .avatar{ width:23px; height:23px; }

  /* the icon stack rides the strip's measured height, as the original's deps
     list did while its grab bar was dragged (orig initRzGrab) */
  /* the row becomes a stack, first tile nearest the strip, same 46px pitch */
  #xBtn{ left:6px !important; right:auto !important; top:auto !important;
    bottom:calc(var(--strip-chrome, 172px) + 24px + env(safe-area-inset-bottom,0px)) !important; }
  #tourBtn{ left:6px !important; top:auto !important;
    bottom:calc(var(--strip-chrome, 172px) + 70px + env(safe-area-inset-bottom,0px)) !important; }
  #orbitBtn{ left:6px !important; top:auto !important;
    bottom:calc(var(--strip-chrome, 172px) + 116px + env(safe-area-inset-bottom,0px)) !important; }
  #recenterBtn{ left:6px !important; top:auto !important;
    bottom:calc(var(--strip-chrome, 172px) + 162px + env(safe-area-inset-bottom,0px)) !important; }
  #themeBtn{ left:6px !important; top:auto !important;
    bottom:calc(var(--strip-chrome, 172px) + 208px + env(safe-area-inset-bottom,0px)) !important; }
  #resetFly{ display:none !important; }
  /* the original's icon stack sat beside a 312px-wide centred card; this sheet is
     full-bleed so the stack would cover it — it stands down while the sheet is up */
  body:has(#detail:not([hidden])) #xBtn,
  body:has(#detail:not([hidden])) #tourBtn,
  body:has(#detail:not([hidden])) #orbitBtn,
  body:has(#detail:not([hidden])) #recenterBtn,
  body:has(#detail:not([hidden])) #themeBtn{ display:none; }
  .fps{ left:auto; right:8px; font-size:8px;
    bottom:calc(var(--strip-chrome, 172px) + 22px + env(safe-area-inset-bottom,0px)); }
  .orbit-note{ left:8px; right:auto; font-size:8px;
    bottom:calc(var(--strip-chrome, 172px) + 22px + env(safe-area-inset-bottom,0px)); }
  .hub-label{ font-size:9px; max-width:118px; }
  .hub-label .hud{ font-size:8px; }

  .sidebar{ top:50% !important; left:50% !important; right:auto !important; bottom:auto !important;
    transform:translate(-50%,-50%) scale(.98); width:min(86vw,340px) !important;
    max-height:64vh !important; border-radius:var(--r-18, 18px) !important; opacity:0;
    pointer-events:none; transition:opacity .2s, transform .2s; z-index:60; }
  .sidebar.mopen{ opacity:1; pointer-events:auto; transform:translate(-50%,-50%) scale(1); }
  #moscrim{ display:none; position:fixed; inset:0; background:var(--scrim-mobile); z-index:55; }
  #moscrim.on{ display:block; }
  .search input{ font-size:var(--fs-16); }   /* iOS zooms into inputs below 16px */

  /* the card is a full-bleed bottom sheet here, and it rides the strip too. The
     desktop card is already a fixed-height flex column with a pinned footer, so
     the phone sheet is the same object at sheet height — the separate sticky
     bar the phone used to need is gone. */
  .detail{ top:auto !important; left:6px !important; right:6px !important;
    bottom:calc(var(--strip-chrome, 172px) + 24px + env(safe-area-inset-bottom,0px)) !important;
    width:auto !important; max-width:none !important; z-index:56 !important;
    height:min(56dvh, calc(100dvh - var(--strip-chrome, 172px) - 96px)) !important; }
  .detail .dh{ padding:12px 13px; cursor:default; }
  .detail .dh .top{ gap:9px; }
  .detail .flogo{ width:38px; height:38px; }
  .detail h2{ font-size:var(--fs-2xl); }
  .detail .sub{ font-size:var(--fs-sm-p); }
  .detail .body{ padding:12px 13px 8px; }
  .detail .body p{ font-size:var(--fs-base); margin-bottom:10px; }
  .detail .kv{ font-size:var(--fs-sm-p); }
  .detail .x{ width:44px; height:44px; }
  .socbtn{ width:30px; height:30px; font-size:var(--fs-md); }
  .detail .dfoot{ padding:10px 13px calc(10px + env(safe-area-inset-bottom,0px)); }

  /* the deep sections on a phone: a taller header row for the thumb, and the
     payload at the sheet's own body size */
  .dsec-h{ padding:13px 2px; }
  .dsec-r{ font-size:var(--fs-sm-p); flex-direction:column; align-items:flex-start; gap:1px; }
  .dsec-r > span:first-child{ flex:0 0 auto; }
  .dsec-r b{ flex:0 0 auto; width:100%; text-align:left; }
  .md-body{ font-size:var(--fs-md); }
  .md-body p{ font-size:var(--fs-md) !important; }
  #rcptModal .rm-box{ width:calc(100vw - 24px); max-height:calc(100dvh - 96px); }
  #rcptModal pre{ font-size:var(--fs-sm); }
}

/* ── accessibility fallbacks ───────────────────────────────────────────── */
@media (prefers-reduced-motion: reduce){
  *,*::before,*::after{ animation:none !important; transition-duration:.01ms !important; }
}
@media (prefers-reduced-transparency: reduce){
  .sidebar,.detail,#resultsbar,#mofilter{ background:var(--paper); backdrop-filter:none;
    -webkit-backdrop-filter:none; }
}

/* ============================================================================
   DARK — the fixes a token swap cannot express
   ----------------------------------------------------------------------------
   tokens-dark.css re-points every colour token, so the great majority of this
   file themes itself. Three classes of problem survive that, and only those are
   listed below (docs/design/dark-mode.md, "Component wiring outside the
   engine"; demonstrated in prototype/dark/preview.css):

     1. Foregrounds that borrowed `--white`. `--white` is a light-mode surface
        that doubled as a foreground. On dark it is a SURFACE (#2B241F), so any
        text still inheriting it would sit near-invisibly on its own ground.
        Filled controls take `--on-brand`, badges `--on-category`, the graph
        tooltip `--ink`.
     2. Literals and mixtures no token reaches — `rgba(0,0,0,.055)`,
        `color-mix(... , transparent)`, the identicon helper's baked SVG fills.
     3. Opacity used as emphasis. Dimming a foreground on dark drops it under
        the contrast floor, so the false/disabled states are re-expressed as
        opaque colour plus a non-colour cue (strike-through, dashed border).

   Every rule is scoped to [data-theme="dark"], which is also why the light
   theme is untouched: none of this can match while the attribute is absent.
   ========================================================================== */

/* 1 · foregrounds on filled brand controls ------------------------------- */
[data-theme="dark"] :is(.btn-recall,.tg.on,.tg.on .tgct,.rz-logo span,
  .panel-head .rz-seg button.on,.socbtn[aria-pressed="true"],#tourTip .tt-next,
  #mofilter .mfc.on,#mofilter .mf-reset,#resetFly:hover){ color:var(--on-brand); }
[data-theme="dark"] .detail .chip:not(.ghost){ color:var(--on-category); }
/* the tooltip ground is dark in BOTH themes, so its text is the one foreground
   that must change value rather than merely be re-pointed */
[data-theme="dark"] .graph-tip{ color:var(--ink); border:1px solid var(--border); }
[data-theme="dark"] .graph-tip .mono{ color:var(--graphite); }

/* 2 · graph annotations need a ground, not a halo ------------------------ */
/* the light halo is three paper-coloured text-shadows; on dark it would ring
   the glyphs in charcoal. A flat backing plate is both cheaper and legible. */
[data-theme="dark"] .hub-label{
  color:var(--ink); background:var(--label-ground); text-shadow:none;
  border-radius:3px; padding:2px 3px; }
[data-theme="dark"] :is(.fps,.orbit-note){
  background:var(--label-ground); border-radius:3px; padding:2px 3px; }
[data-theme="dark"] .graph-pulse.hollow{ box-shadow:0 0 0 2.5px var(--ink); }
[data-theme="dark"] input::placeholder{ color:var(--graphite); opacity:1; }

/* 3 · opacity and mixtures re-expressed as opaque colour ----------------- */
/* a 40% foreground fails the contrast floor on dark, so the "off" state is
   carried by colour plus a strike-through instead of by dimming */
[data-theme="dark"] .chk.off{ opacity:1; color:var(--graphite); text-decoration:line-through; }
[data-theme="dark"] #orbitBtn[aria-pressed="false"]{ opacity:1; border-style:dashed; }
[data-theme="dark"] .chk:hover{ background:var(--brand-08); }
[data-theme="dark"] .memory-row{ border-bottom-color:var(--border); }
[data-theme="dark"] .panel-head .rz-seg{ background:var(--paper); }
/* border-box keeps the track exactly 8px, so the added boundary costs no
   layout — deliberately not the prototype's 10px, which would shift the card */
[data-theme="dark"] .fresh-bar{ background:var(--paper); border:1px solid var(--border); }
[data-theme="dark"] .fresh-bar i{ opacity:1; }

/* the shared identicon helper bakes literal light pastels into its SVG, and a
   token override cannot reach a fill attribute. Neutral grounds preserve the
   hash geometry and identity; see NOTES — the helper itself is module-owned. */
/* identicon dark fills now live in src/shared/identicon.js (inline var() fills);
   the page-level override that used to sit here resolved to the same tokens */

/* reduced transparency: the base rule above covers four page panels with
   --paper. On dark a panel must read as a raised surface, and the three module
   panels need the same treatment. */
@media (prefers-reduced-transparency: reduce){
  [data-theme="dark"] :is(.sidebar,.detail,#resultsbar,#mofilter,.tc-panel,.act-panel,.rd-surface){
    background:var(--surface); backdrop-filter:none; -webkit-backdrop-filter:none; }
}

/* ── the switch itself ───────────────────────────────────────────────────
   Theming is instant by design, not a crossfade: 600 rows easing between two
   grounds is a smear, not a transition. marketplace.js sets this attribute for
   the commit and drops it two frames later. Transitions only — animations keep
   running, so neither the recall run nor the pulse restarts. */
html[data-theme-switching],
html[data-theme-switching] *,
html[data-theme-switching] *::before,
html[data-theme-switching] *::after{ transition:none !important; }
