/* ============================================================
   /jar/ — the firefly jar.

   The vault as fireflies in a mason jar, standing on a plank at
   night. Keeps the night palette the sky version used; drops the
   sea, the sand, the palms and the star field, which belonged to
   the island and not to a jar on a table.

   Motion budget: every effect here is an opacity, a transform or a
   stroke-dashoffset. Nothing animates a layout property, and the
   only per-frame writes come from atlas-jar.js's drift loop.
   ============================================================ */

:root{
  /* night, deepest to the wall behind the plank */
  --n-top:#060b1c; --n-high:#0b1430; --n-mid:#101c3c; --n-low:#16264a;
  /* the island's own timber, unlit */
  --n-wood:#5c3f26; --n-wood-dk:#3d2917; --n-wood-lt:#7d5634; --n-rope:#b08d52;
  --n-paper:#f3e8ca;
  --n-moon:#f7f2dc;
  /* ink that sits on the night */
  --sky-ink:#d8e3f7; --sky-mut:#93a7c9; --sky-dim:#7f92b4;
  --hand:'Kalam', cursive;
  --glow:#ffc46b;
}

html:has(.jar-page){background:#060b1c}
body.jar-page{
  background:
    radial-gradient(120% 78% at 50% 108%, rgba(255,178,71,.10) 0%, rgba(255,178,71,0) 58%),
    linear-gradient(180deg, var(--n-top) 0%, var(--n-high) 46%, var(--n-mid) 78%, var(--n-low) 100%);
  background-attachment:fixed;
  color:var(--sky-ink);
  font-family:var(--sans);
  overflow-x:hidden;
}
.jar-page ::selection{background:rgba(255,196,107,.28);color:#fff}
.jar-page main{padding:0}

/* ---- header + footer, on the dark ---- */
.jar-page .sitehead{background:transparent;border-bottom:1px solid rgba(178,205,255,.12)}
.jar-page .brand{color:var(--sky-ink)}
.jar-page .navlinks a{color:var(--sky-mut)}
.jar-page .navlinks a:hover{color:#fff}
.jar-page .navlinks a[aria-current="page"]{color:#fff;border-bottom-color:var(--glow)}
.jar-page .lockicon{color:var(--sky-dim)}
.jar-page .navtoggle{color:var(--sky-ink);border-color:rgba(178,205,255,.26)}
.jar-page .navtoggle:hover{border-color:var(--sky-ink)}
.jar-page .navlinks.is-open{border-top-color:rgba(178,205,255,.12)}
.jar-page .sitefoot{border-top-color:rgba(243,232,202,.16);margin-top:0}
.jar-page .sitefoot address{color:rgba(243,232,202,.66)}
.jar-page .sitefoot address a{color:rgba(243,232,202,.88);border-bottom-color:rgba(243,232,202,.32)}
.jar-page .sitefoot address a:hover{color:#fff;border-bottom-color:var(--n-moon)}

/* ============================================================
   the scene: copy on the left, jar on the right.

   The copy column is hard-capped. The Observatory's phase-A comp
   let it run to 42vw and the glass went straight through the
   headline; this is that finding taken as given rather than
   re-learned.
   ============================================================ */
.jar-scene{
  position:relative;
  display:grid;
  grid-template-columns:minmax(0,min(40ch,36vw)) minmax(0,1fr);
  grid-template-rows:auto auto;
  column-gap:clamp(24px,4vw,64px);
  align-content:center;
  max-width:1320px;
  margin:0 auto;
  padding:clamp(8px,2vh,26px) clamp(20px,4vw,52px) 0;
  min-height:calc(100vh - 58px);
}
/* copy and readout stack down the left; the jar owns the right for
   both rows. The readout has to be a grid child in its own right or
   the phone composition cannot reorder it below the jar. */
.jar-copy{grid-column:1;grid-row:1;align-self:end}
/* positioned, so the panels sit above the absolute canvas instead of
   under it — the vignette and the jar would otherwise paint over them */
.jar-meta{grid-column:1;grid-row:2;align-self:start;padding-top:22px;position:relative;z-index:2}
.jar-stage{grid-column:2;grid-row:1 / 3}

/* ---------------- the copy ---------------- */
.jar-copy{max-width:min(40ch,36vw);position:relative;z-index:2}
.jar-copy .eyebrow{
  font-family:var(--mono);font-size:10px;letter-spacing:.22em;text-transform:uppercase;
  color:var(--sky-dim);margin:0 0 10px;
}
.jar-copy h1{
  font-family:var(--hand);font-weight:700;
  font-size:clamp(32px,4.4vw,54px);line-height:1.06;
  color:#fff;margin:0 0 14px;
  text-shadow:0 0 30px rgba(255,196,107,.22);
}
.jar-copy .lede{color:var(--sky-mut);font-size:15.5px;line-height:1.62;margin:0 0 18px}
.jar-copy .lede b{color:var(--sky-ink);font-weight:600}
.jar-copy .lede code{
  font-family:var(--mono);font-size:.88em;color:#ffd79a;
  background:rgba(255,196,107,.08);border:1px solid rgba(255,196,107,.18);
  border-radius:4px;padding:1px 5px;
}

/* the readout — the honest one. Says what is drawn and what isn't. */
.jar-read{
  font-family:var(--mono);font-size:11.5px;line-height:1.85;
  color:var(--sky-dim);margin:0 0 20px;
  border-left:2px solid rgba(255,196,107,.28);padding-left:12px;
}
.jar-read b{color:var(--n-paper);font-weight:500}
.jar-read .warn{color:#ffc46b}

.jar-hint{
  display:inline-flex;align-items:center;gap:9px;
  font-family:var(--mono);font-size:11px;letter-spacing:.09em;text-transform:uppercase;
  color:var(--glow);margin:0;
}
.jar-hint i{
  width:7px;height:7px;border-radius:50%;background:var(--glow);
  box-shadow:0 0 10px 2px rgba(255,196,107,.6);
  animation:hintpulse 2.4s ease-in-out infinite;
}
@keyframes hintpulse{0%,100%{opacity:.35;transform:scale(.8)}50%{opacity:1;transform:scale(1.15)}}

/* ---------------- the stage ---------------- */
/* The canvas is the whole scene, not the right-hand column: in OPEN
   the swarm spreads across all of it, so it sits behind everything
   and the copy floats on top. */
.jar-canvas{
  position:absolute;inset:0;z-index:0;
  overflow:visible;                 /* the shelf runs off both edges */
}
.jar-svg{display:block;width:100%;height:100%;overflow:visible}

/* A spacer holding open the column the jar occupies while sealed, so
   the grid still reserves its space even though the svg is absolute. */
.jar-stage{grid-column:2;grid-row:1 / 3;height:min(84vh,780px);pointer-events:none}

/* ---- fireflies ----
   Rule inherited from the Observatory build: the script writes the
   transform on .ff, so the animation has to live on .ff-a. Put both
   on one element and the node snaps to the viewBox origin the
   instant its animation delay elapses. */
.ff{will-change:transform}
.ff-a{
  transform-box:fill-box;transform-origin:center;
  animation:breathe 4s ease-in-out infinite;
}
.ff-a.is-orphan{animation-name:ember}
.ff-core{mix-blend-mode:screen}
.ff-glow{mix-blend-mode:screen}

@keyframes breathe{
  0%,100%{opacity:.55;transform:scale(.92)}
  50%    {opacity:1;transform:scale(1.06)}
}
/* orphans do not pulse. Nothing links to them, and the picture says so. */
@keyframes ember{
  0%,100%{opacity:.34}
  50%    {opacity:.52}
}

/* ---- the glass: two marks, not ten ---- */
.jar-spec{
  transform-box:fill-box;transform-origin:center;
  animation:glint 9s ease-in-out infinite;
}
@keyframes glint{
  0%,100%{opacity:.30;transform:translateY(-16px)}
  50%    {opacity:.85;transform:translateY(26px)}
}
.jar-wash{
  transform-box:fill-box;transform-origin:center;
  animation:wash 7.5s ease-in-out infinite;
}
@keyframes wash{
  0%,100%{opacity:.72}
  50%    {opacity:1}
}
.jar-plank .pool{animation:wash 7.5s ease-in-out infinite}

/* ---- the lid: the only affordance in the sealed state ---- */
.jar-lidgrp{
  cursor:pointer;
  transform-box:fill-box;transform-origin:center bottom;
  transition:transform .38s cubic-bezier(.2,.8,.25,1),filter .38s ease;
}
.jar-lidgrp:hover,
.jar-lidgrp:focus-visible{
  transform:translateY(-8px) rotate(-1.8deg);
  filter:drop-shadow(0 6px 16px rgba(255,196,107,.34));
}
.jar-lidgrp:focus{outline:none}
.jar-lidgrp:focus-visible .jar-lidhit{
  stroke:var(--glow);stroke-width:2;stroke-dasharray:5 4;rx:10;
}

/* ============================================================
   OPEN — the second state.

   The lid comes off, the swarm walks out through the mouth, and the
   jar stops being an object you are looking at and becomes the edge
   of what you are looking through. What survives is the vignette and
   the shelf it was standing on, so you never leave the metaphor.
   ============================================================ */
.jar-vignette{opacity:0;transition:opacity .9s ease .25s}
.jar-svg.is-open .jar-vignette{opacity:1}

/* the glass demotes to a rim: the outline goes, the marks stay faint */
.jar-glassgrp,.jar-label,.jar-inner{
  transition:opacity .7s ease,transform .8s cubic-bezier(.2,.8,.25,1);
  transform-box:fill-box;transform-origin:center;
}
/* .12, not .16: any more and it reads as a ghost jar hanging in the
   room rather than as the glass you are now behind */
.jar-svg.is-open .jar-glassgrp{opacity:.12}
.jar-svg.is-open .jar-label{opacity:0;pointer-events:none}
.jar-svg.is-open .jar-inner{opacity:0}
/* the shelf stays lit — it is the half of the jar you keep */
.jar-svg.is-open .jar-plank .contact{opacity:.25}

/* the lid rises off and out of frame */
.jar-svg.is-open .jar-lidgrp{transform:translateY(-58px) rotate(-7deg);opacity:.42}
.jar-svg.is-open .jar-lidgrp:hover,
.jar-svg.is-open .jar-lidgrp:focus-visible{transform:translateY(-64px) rotate(-7deg);opacity:.8}

/* names, revealed rather than created — the morph never touches DOM */
.ff-name{
  font-family:var(--mono);
  font-size:var(--ff-name-size,11.5px);
  opacity:0;pointer-events:none;
  paint-order:stroke;
  stroke:rgba(4,6,15,.85);stroke-width:3px;stroke-linejoin:round;
  transition:opacity .45s ease .55s;
}
.jar-svg.is-open .ff-name{opacity:.86}

/* the copy gets out of the way once the swarm owns the scene */
.jar-scene.is-open .jar-copy .lede{
  opacity:0;max-height:0;overflow:hidden;margin-bottom:0;
  transition:opacity .3s ease,max-height .5s ease,margin .5s ease;
}
.jar-scene.is-open .jar-copy h1{font-size:clamp(22px,2.2vw,30px);transition:font-size .5s ease}
.jar-scene.is-open .jar-copy,
.jar-scene.is-open .jar-meta{
  background:rgba(6,10,22,.62);
  backdrop-filter:blur(9px);-webkit-backdrop-filter:blur(9px);
  border:1px solid rgba(178,205,255,.12);border-radius:12px;
  padding:14px 16px;
}
.jar-scene.is-open .jar-meta{margin-top:10px;padding-top:14px}
.jar-copy,.jar-meta{transition:background .5s ease,padding .5s ease,border-color .5s ease}

/* ---- dust in the room, outside the glass ---- */
.mote{
  fill:rgba(213,232,255,.5);
  transform-box:fill-box;transform-origin:center;
  animation:float 14s linear infinite;
}
@keyframes float{
  0%  {opacity:0;transform:translate(0,10px)}
  18% {opacity:.5}
  82% {opacity:.4}
  100%{opacity:0;transform:translate(9px,-46px)}
}

/* ---- the etched label ---- */
.lb-head{
  font-family:var(--mono);font-size:12.5px;letter-spacing:.24em;
  fill:rgba(243,232,202,.72);
}
.lb-row{
  font-family:var(--mono);font-size:12px;letter-spacing:.05em;
  fill:rgba(243,232,202,.62);
}
.lb-row.dim{fill:rgba(243,232,202,.42);font-size:11px}

/* ============================================================
   phone — a third composition, not a reflow.
   Jar upright in a band, copy above it, controls below. The
   Observatory's phase-A finding: at 390px the copy, the glass and
   the readout all want the middle third and land on each other.
   ============================================================ */
@media (max-width:900px){
  .jar-scene{
    display:flex;flex-direction:column;
    gap:0;
    padding:12px 20px 0;
    min-height:0;
  }
  /* copy above, jar in a band, readout below — the grid placement
     above is column-shaped and does not survive being stacked */
  .jar-copy,.jar-meta,.jar-stage{grid-column:auto;grid-row:auto}
  .jar-copy{max-width:none;order:1}
  .jar-stage{order:2;height:min(46vh,380px);margin:2px 0 6px}
  .jar-meta{order:3;padding-top:0}

  /* tightened until the jar's shoulder clears the fold on a 375×812
     frame — a page about a jar that opens below the fold is a page
     about a paragraph */
  .jar-copy h1{font-size:clamp(26px,7.2vw,34px);margin-bottom:10px}
  .jar-copy .lede{font-size:14.5px;line-height:1.55;margin-bottom:2px}
  .jar-copy .eyebrow{margin-bottom:7px}
  .jar-read{font-size:11px;line-height:1.75}

  /* The etching scales with the jar and lands at about five pixels
     here — texture pretending to be text. The readout directly below
     carries the same five numbers at a readable size, so the panel
     goes rather than lying about being legible. */
  .jar-label{display:none}
}

/* ============================================================
   reduced motion is a path, not a switch: the drift loop never
   starts (atlas-jar.js checks the same query), flicker becomes a
   static brightness, and the page still says everything it said.
   ============================================================ */
@media (prefers-reduced-motion:reduce){
  .ff-a,.jar-spec,.jar-wash,.jar-plank .pool,.mote,.jar-hint i{animation:none!important}
  .jar-lidgrp{transition:none}
  .ff-a{opacity:.85}
}

/* ============================================================
   /jar/ — the controls, the index and the card.

   Everything beside the jar lives in the left column, in one
   fixed-height slot, so opening a note never changes the page's
   geometry and the swarm never has to re-home around a panel.
   ============================================================ */
.jar-copy .eyebrow{color:var(--glow)}

.jar-controls{display:flex;flex-wrap:wrap;gap:8px;margin:0 0 16px}
.jbtn{
  display:inline-flex;align-items:center;gap:9px;
  font:inherit;font-family:var(--mono);font-size:12px;letter-spacing:.05em;
  color:var(--sky-ink);background:rgba(178,205,255,.06);
  border:1px solid rgba(178,205,255,.22);border-radius:999px;
  padding:9px 16px;cursor:pointer;
  transition:background .2s ease,border-color .2s ease,color .2s ease,box-shadow .2s ease;
}
.jbtn:hover{border-color:rgba(255,196,107,.6);color:#fff}
.jbtn:focus-visible{outline:2px solid var(--glow);outline-offset:2px}
.jbtn[aria-pressed="true"]{background:rgba(255,196,107,.14);border-color:rgba(255,196,107,.55);color:#ffe2ad}
.jbtn.primary{
  background:linear-gradient(180deg,#ffd18a,#f0a94a);color:#1a1206;border-color:transparent;
  font-weight:500;box-shadow:0 0 24px rgba(255,196,107,.28);
}
.jbtn.primary:hover{box-shadow:0 0 32px rgba(255,196,107,.5);color:#1a1206}
.jbtn.primary[aria-pressed="true"]{
  background:rgba(255,196,107,.14);color:#ffe2ad;border-color:rgba(255,196,107,.55);box-shadow:none;
}
.jbtn i{
  width:7px;height:7px;border-radius:50%;background:currentColor;
  animation:hintpulse 2.4s ease-in-out infinite;
}
.jbtn[aria-pressed="true"] i{animation:none;opacity:.6}

.jar-slot-h{
  font-family:var(--mono);font-size:10px;letter-spacing:.2em;text-transform:uppercase;
  color:var(--sky-dim);margin:0 0 8px;
}

/* ---- group chips (only drawn when the vault has more than one) ---- */
.jar-groups{display:flex;flex-wrap:wrap;gap:6px;margin:0 0 14px}
.jar-groups .jar-slot-h{flex-basis:100%;margin-bottom:2px}
.jchip{
  display:inline-flex;align-items:center;gap:7px;
  font:inherit;font-family:var(--mono);font-size:11px;color:var(--sky-mut);
  background:none;border:1px solid rgba(178,205,255,.18);border-radius:999px;
  padding:4px 10px;cursor:pointer;
}
.jchip i{width:7px;height:7px;border-radius:50%}
.jchip small{color:var(--sky-dim)}
.jchip:hover{color:#fff;border-color:rgba(178,205,255,.4)}
.jchip[aria-pressed="true"]{color:#fff;border-color:rgba(255,196,107,.6);background:rgba(255,196,107,.1)}

/* ---- the slot: index or card, same box ---- */
.jar-slot{
  height:clamp(150px,calc(100vh - 690px),300px);
  position:relative;
}
.jar-index-wrap,.jar-card{height:100%;overflow:auto;overscroll-behavior:contain;scrollbar-width:thin;
  scrollbar-color:rgba(178,205,255,.2) transparent}
.jar-index-wrap[hidden],.jar-card[hidden]{display:none}

.jar-index{list-style:none;margin:0;padding:0}
.jar-index button{
  display:grid;grid-template-columns:10px minmax(0,1fr) auto;align-items:center;gap:10px;
  width:100%;text-align:left;
  font:inherit;font-size:13.5px;color:var(--sky-ink);
  background:none;border:0;border-radius:8px;padding:7px 8px;cursor:pointer;
}
.jar-index i{width:7px;height:7px;border-radius:50%}
.jar-index span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.jar-index small{font-family:var(--mono);font-size:10.5px;color:var(--sky-dim)}
.jar-index button:hover,.jar-index li.is-hover button,.jar-index button:focus-visible{
  background:rgba(255,196,107,.09);color:#fff;outline:none;
}

.jar-card{position:relative;padding-right:4px}
.jar-card:focus{outline:none}
.jcard-x{
  position:absolute;top:0;right:2px;
  width:28px;height:28px;border-radius:50%;
  font:inherit;font-size:18px;line-height:1;color:var(--sky-mut);
  background:rgba(178,205,255,.06);border:1px solid rgba(178,205,255,.18);cursor:pointer;
}
.jcard-x:hover,.jcard-x:focus-visible{color:#fff;border-color:var(--glow);outline:none}
.jcard-eyebrow{
  display:flex;align-items:center;gap:8px;
  font-family:var(--mono);font-size:10.5px;letter-spacing:.12em;text-transform:uppercase;
  color:var(--sky-dim);margin:2px 40px 8px 0;
}
.jcard-eyebrow i{width:8px;height:8px;border-radius:50%;flex:none}
.jar-card h2{
  font-family:var(--hand);font-weight:700;font-size:22px;line-height:1.15;color:#fff;
  margin:0 36px 6px 0;
}
.jcard-stats{font-family:var(--mono);font-size:11.5px;color:var(--sky-mut);margin:0 0 10px}
.jtag{color:#ffd79a}
.jcard-text{font-size:14px;line-height:1.6;color:#c3cfe4;margin:0 0 14px}
.jcard-text.dim{color:var(--sky-dim);font-style:italic}
.jcard-near{list-style:none;margin:0 0 14px;padding:0;display:flex;flex-wrap:wrap;gap:6px}
.jcard-near button{
  display:inline-flex;align-items:center;gap:7px;max-width:100%;
  font:inherit;font-size:12.5px;color:var(--sky-ink);
  background:rgba(178,205,255,.05);border:1px solid rgba(178,205,255,.16);border-radius:999px;
  padding:4px 11px;cursor:pointer;
}
.jcard-near button:hover,.jcard-near button:focus-visible{border-color:rgba(255,196,107,.6);color:#fff;outline:none}
.jcard-near i{width:6px;height:6px;border-radius:50%;flex:none}
.jcard-read{
  display:inline-block;font-family:var(--mono);font-size:12px;color:var(--glow);
  text-decoration:none;border-bottom:1px solid rgba(255,196,107,.35);
}
.jcard-read:hover{color:#ffe2ad;border-bottom-color:var(--glow)}

.jar-noscript{max-width:60ch;margin:24px auto;padding:0 20px;color:var(--sky-mut)}

/* ---- the swarm, as something you can press ---- */
.jar-svg:not(.is-open) .jar-world{cursor:pointer}
.jar-svg.is-open .jar-glassgrp,
.jar-svg.is-open .jar-inner{pointer-events:none}
.ff{transition:opacity .35s ease}
.ff-hit{fill:transparent}
.jar-svg.is-open .ff-hit{cursor:pointer}
.jar-svg:not(.is-open) .ff-hit{pointer-events:none}
.ff-ring{
  fill:none;stroke-width:1.4;vector-effect:non-scaling-stroke;opacity:0;
  transform-box:fill-box;transform-origin:center;
  transition:opacity .25s ease;
}
.jar-svg.is-open .ff.is-hover .ff-ring{opacity:.45}
.jar-svg.is-open .ff.is-sel .ff-ring{opacity:.95;animation:ring 2.2s ease-in-out infinite}
@keyframes ring{0%,100%{transform:scale(1)}50%{transform:scale(1.35)}}

/* a focus dims everything it does not include to embers */
.jar-svg.has-focus .ff:not(.is-lit){opacity:.14}
.jar-svg.is-open.has-focus .ff.is-lit .ff-name,
.jar-svg.is-open .ff.is-hover .ff-name{display:inline!important;opacity:1;transition-delay:0s}

/* ---- the links: real [[wikilinks]], drawn only when asked ---- */
.ff-link{
  stroke:#ffd79a;stroke-width:1;vector-effect:non-scaling-stroke;
  opacity:0;transition:opacity .4s ease;
}
.jar-svg.is-open.show-links .ff-link{opacity:.28}
.jar-svg.is-open.has-focus.show-links .ff-link{opacity:.06}
.jar-svg.is-open .ff-link.is-lit,
.jar-svg.is-open.show-links .ff-link.is-lit{
  opacity:.85;stroke-width:1.4;stroke-dasharray:3 6;
  animation:flow 1.1s linear infinite;
}
@keyframes flow{to{stroke-dashoffset:-9}}

@media (max-width:900px){
  .jar-slot{height:auto;max-height:52vh}
  .jar-index-wrap,.jar-card{height:auto;max-height:52vh}
  .jar-meta{padding-bottom:18px}
}
@media (prefers-reduced-motion:reduce){
  .jbtn i,.ff-ring,.ff-link{animation:none!important}
}
