/* ComPons - the chart, as a product surface.
   Paper ground, green ink, pixel accents. The same palette the film uses, so the app and the film
   are recognisably one thing. */

@font-face { font-family: "Silkscreen"; font-display: swap; src: local("Silkscreen"); }

:root {
  --paper: #eef2e6;
  --paper-2: #e6ecdc;
  --sea: #e8eee0;
  --grat: #cedec8;
  --land: #3a8a4c;
  --coast: #1a522a;
  --ink: #143e21;
  --ink-2: #1c4124;
  --dark: #10301a;
  --needle: #c6d62a;
  --bad: #a33a2a;
  --rad: 0px;
}

* { margin: 0; padding: 0; box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  background: var(--paper) url("../img/bg.webp?v=40") center top / cover no-repeat fixed;
  color: var(--ink);
  font: 15px/1.55 "IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, monospace;
  min-height: 100dvh;
}
/* The chart is a ground, not a texture: on a phone a fixed cover background is repainted on every
   scroll frame and janks, so it scrolls with the page there instead. */
@media (max-width: 900px) {
  body { background-attachment: scroll; background-size: 1400px auto; }
}

.pixel { font-family: "Silkscreen", ui-monospace, monospace; font-weight: 700; letter-spacing: .02em; }

a { color: var(--coast); text-decoration: none; border-bottom: 1px solid var(--grat); }
a:hover { border-bottom-color: var(--coast); }

/* ── shell ─────────────────────────────────────────────────────────────────────────────── */
/* A sticky footer: the column is at least a screen tall and the footer takes the slack, so on a
   short tab it sits at the bottom instead of floating under the last card, and on a long one it
   still scrolls away normally. `100dvh` and not `100vh` because a phone's toolbar makes vh lie. */
.wrap {
  max-width: 1220px; margin: 0 auto; padding: 0 20px 32px;
  min-height: 100dvh; display: flex; flex-direction: column;
}
.wrap > section { flex: 0 0 auto; }
.wrap > footer { margin-top: auto; }

header {
  display: flex; align-items: center; gap: 16px;
  padding: 22px 0 18px; border-bottom: 3px solid var(--ink); margin-bottom: 22px;
  flex-wrap: wrap;
}
/* The wordmark is the one from the launch film - the logotype that exists in public, not a
   pixel-font approximation of it. Its own dark outline is the only edge it needs. */
.brand { display: flex; align-items: baseline; gap: 14px; border: 0; flex-wrap: wrap; }
.brand .mark { height: 46px; width: auto; display: block; }
.brand .strap { font-size: 11px; letter-spacing: .26em; text-transform: uppercase; color: var(--ink-2); }

/* An empty state carries the mascot. A bare line of text says "nothing here"; the character says
   "nothing here YET", which is the truthful reading before launch. */
.empty { display: flex; align-items: center; gap: 20px; padding: 10px 0 6px; text-align: left; }
/* A framed plate, not a cut-out. Keying the character off a lake means keying against water,
   shadow and reflection at once - a bordered vignette is honest to the film and reads like a
   plate pasted onto a chart, which is what this page already is. */
.empty img { width: 150px; height: auto; flex: 0 0 auto;
             border: 2px solid var(--ink); box-shadow: 4px 4px 0 rgba(20,62,33,.13); }
.empty b { display: block; margin-bottom: 4px; }
.empty .muted { display: block; max-width: 56ch; }

.spacer { flex: 1 1 auto; }

.epoch {
  border: 2px solid var(--ink); background: var(--paper); padding: 7px 14px;
  font-size: 12px; letter-spacing: .16em; text-transform: uppercase;
}
.epoch b { font-variant-numeric: tabular-nums; }

.btn {
  border: 2px solid var(--ink); background: var(--ink); color: var(--paper);
  padding: 9px 18px; font: inherit; font-size: 13px; cursor: pointer;
  letter-spacing: .1em; text-transform: uppercase;
}
.btn:hover { background: var(--coast); }
.btn.ghost { background: var(--paper); color: var(--ink); }
.btn.ghost:hover { background: var(--paper-2); }
.btn:disabled { opacity: .45; cursor: not-allowed; }

/* ── tabs ──────────────────────────────────────────────────────────────────────────────── */
nav.tabs { display: flex; gap: 0; border-bottom: 2px solid var(--ink); margin-bottom: 26px; flex-wrap: wrap; }
nav.tabs button {
  border: 2px solid transparent; border-bottom: none; background: none; color: var(--ink-2);
  padding: 11px 20px; font: inherit; font-size: 13px; cursor: pointer;
  letter-spacing: .14em; text-transform: uppercase; margin-bottom: -2px;
}
nav.tabs button[aria-selected="true"] {
  border-color: var(--ink); background: var(--paper); color: var(--ink);
  border-bottom: 2px solid var(--paper);
}

/* ── cards ─────────────────────────────────────────────────────────────────────────────── */
.card {
  border: 2px solid var(--ink); background: var(--paper);
  box-shadow: 6px 6px 0 rgba(20, 62, 33, .13);
  padding: 20px 22px; margin-bottom: 20px;
}
.card > h3 {
  font-size: 12px; letter-spacing: .26em; text-transform: uppercase;
  color: var(--ink-2); font-weight: 500; margin-bottom: 14px;
}
.grid { display: grid; gap: 20px; grid-template-columns: repeat(auto-fit, minmax(min(100%, 280px), 1fr)); }

.stat { display: flex; justify-content: space-between; align-items: baseline; gap: 14px; padding: 7px 0; }
.stat + .stat { border-top: 1px solid var(--grat); }
.stat dt { font-size: 12px; letter-spacing: .12em; text-transform: uppercase; color: var(--ink-2); }
.stat dd { font-variant-numeric: tabular-nums; text-align: right; }

.big { font-size: 34px; line-height: 1.1; font-variant-numeric: tabular-nums; }
.muted { color: var(--ink-2); font-size: 12px; letter-spacing: .1em; }

/* ── table ─────────────────────────────────────────────────────────────────────────────── */
.scroll { overflow-x: auto; }
table { width: 100%; border-collapse: collapse; min-width: 720px; }
th, td { text-align: right; padding: 11px 12px; border-bottom: 1px solid var(--grat); font-variant-numeric: tabular-nums; }
th:first-child, td:first-child { text-align: left; }
th { font-size: 11px; letter-spacing: .18em; text-transform: uppercase; color: var(--ink-2); font-weight: 500; }
tbody tr:hover { background: var(--paper-2); }

/* ── the depth strip: the same picture the film uses, as a live widget ─────────────────── */
.depth { display: flex; align-items: flex-end; gap: 2px; height: 54px; }
.depth i { flex: 1 1 0; background: var(--land); border: 1px solid var(--ink); border-bottom: none; min-height: 2px; }
/* Hollow must still READ. A 1px edge on pale paper disappeared, and an invisible bar is
   the same as no bar - which is the opposite of the point being made. */
.depth i.out { background: var(--paper); border-color: var(--coast); }

/* ── form bits ─────────────────────────────────────────────────────────────────────────── */
label { display: block; font-size: 11px; letter-spacing: .18em; text-transform: uppercase; color: var(--ink-2); margin-bottom: 6px; }
input[type="text"], input[type="number"], select {
  width: 100%; border: 2px solid var(--ink); background: var(--paper); color: var(--ink);
  padding: 10px 12px; font: inherit; margin-bottom: 14px;
}
input[type="range"] { width: 100%; accent-color: var(--coast); margin-bottom: 8px; }
.row { display: flex; gap: 12px; flex-wrap: wrap; }
.row > * { flex: 1 1 180px; }

.pill {
  display: inline-block; border: 2px solid var(--ink); padding: 3px 9px;
  font-size: 11px; letter-spacing: .14em; text-transform: uppercase;
}
.pill.on { background: var(--needle); }
.pill.off { background: var(--paper); color: var(--ink-2); }

.notice {
  border: 2px solid var(--ink); border-left-width: 8px; background: var(--paper);
  padding: 14px 18px; margin-bottom: 22px; font-size: 13px;
}

.docs h4 { font-size: 17px; margin: 22px 0 8px; }
.docs p { margin-bottom: 12px; max-width: 74ch; }
.docs ol { margin: 0 0 14px 22px; }
.docs li { margin-bottom: 7px; max-width: 72ch; }

footer { border-top: 2px solid var(--ink); padding-top: 18px; margin-top: 40px;
         font-size: 12px; color: var(--ink-2); }

/* ── responsive: measured at 320 / 360 / 390 / 430 ────────────────────────────────────── */
@media (max-width: 720px) {
  .wrap { padding: 0 14px 24px; }
  header { gap: 10px; padding: 16px 0 14px; }
  .brand .mark { height: 40px; }
  .epoch { font-size: 11px; padding: 6px 10px; }
  nav.tabs button { padding: 10px 13px; font-size: 12px; letter-spacing: .1em; }
  .big { font-size: 27px; }
  .card { padding: 16px; }
}
@media (max-width: 380px) {
  /* 🔴 `.brand span` hid the WRAPPER too, so the name vanished and only the logo was left -
     the opposite of the intent. Target the strapline alone. */
  .brand .strap { display: none; }
  .brand .mark { height: 38px; }
  nav.tabs button { padding: 9px 10px; font-size: 11px; letter-spacing: .06em; }
}


/* ── the hero band: the compass, the epoch, and the book, above the numbers ──────────────── */
.hero {
  display: grid; grid-template-columns: 168px 1fr; gap: 26px; align-items: center;
  border: 2px solid var(--ink); background: var(--paper);
  box-shadow: 6px 6px 0 rgba(20, 62, 33, .13);
  padding: 22px 26px; margin-bottom: 22px;
}
.hero .rose { position: relative; width: 168px; height: 168px; }
/* 🔴 `cover`, and no pixelation. The box is square and the plates are not: forcing width and
   height squashed a 1000x500 render into 168x168 instead of cropping it, and `pixelated` is for
   the pixel-art assets - on a soft 3D render it just makes it crunchy. */
.hero .rose img { position: absolute; inset: 0; width: 168px; height: 168px;
                  object-fit: cover; border: 2px solid var(--ink); }
.hero h2 { font-size: 27px; line-height: 1.25; margin-bottom: 8px; }
.hero p { font-size: 13px; color: var(--ink-2); max-width: 62ch; }

/* The epoch as a bar, because a countdown in words does not show how far through you are. */
.epochbar { height: 14px; border: 2px solid var(--ink); background: var(--paper); margin: 16px 0 8px; }
.epochbar i { display: block; height: 100%; background: var(--needle); }

/* ── the depth strip, live ────────────────────────────────────────────────────────────── */
.depth { display: flex; align-items: flex-end; gap: 2px; height: 64px; }
.depth i { flex: 1 1 0; background: var(--land); border: 2px solid var(--ink); border-bottom: none; min-height: 3px; }
/* Hollow must still READ. A 1px edge on pale paper disappeared, and an invisible bar is
   the same as no bar - which is the opposite of the point being made. */
.depth i.out { background: var(--paper); border-color: var(--coast); }
.depth i.px { background: var(--needle); flex: 0 0 4px; border-color: var(--ink); }
.depthwrap { margin-top: 10px; }
.depthwrap .muted { margin-top: 7px; }

/* A row-sized version of the same picture. */
.mini { display: inline-flex; align-items: flex-end; gap: 1px; height: 26px; width: 96px; vertical-align: middle; }
.mini i { flex: 1 1 0; background: var(--land); min-height: 2px; }
.mini i.out { background: var(--grat); }

/* A share meter, for votes. */
.meter { height: 10px; border: 2px solid var(--ink); background: var(--paper); min-width: 90px; }
.meter i { display: block; height: 100%; background: var(--land); }

/* ── the flywheel, in the docs ────────────────────────────────────────────────────────── */
.wheel { position: relative; width: 100%; max-width: 480px; aspect-ratio: 1; margin: 8px auto 22px; }
.wheel img.ring { position: absolute; inset: 0; width: 100%; height: 100%; image-rendering: pixelated; opacity: .9; }
.wheel img.mid { position: absolute; left: 50%; top: 50%; width: 32%; height: 32%; transform: translate(-50%, -50%); image-rendering: pixelated; }
.wheel b {
  position: absolute; font-size: 11px; letter-spacing: .12em; text-transform: uppercase;
  background: var(--paper); border: 2px solid var(--ink); padding: 4px 8px; white-space: nowrap;
}
.wheel b.n { left: 50%; top: -4%; transform: translateX(-50%); }
.wheel b.e { right: -6%; top: 50%; transform: translateY(-50%); }
.wheel b.s { left: 50%; bottom: -4%; transform: translateX(-50%); }
.wheel b.w { left: -6%; top: 50%; transform: translateY(-50%); }

/* ── responsive ───────────────────────────────────────────────────────────────────────── */
@media (max-width: 900px) {
  .hero { grid-template-columns: 1fr; gap: 16px; }
  .hero .rose { width: 116px; height: 116px; margin: 0 auto; }
  .hero .rose img { width: 116px; height: 116px; }
  .hero h2 { font-size: 22px; }
}

/* 🔴 Below 780 the tables STOP being tables. A horizontal scroll inside a card is a thing people
   never find - they read the three columns that fit and conclude the rest does not exist. Each
   row becomes a stacked card, and every cell carries its own header. */
@media (max-width: 780px) {
  table { min-width: 0; display: block; }
  thead { display: none; }
  tbody, tr, td { display: block; width: 100%; }
  tr {
    border: 2px solid var(--ink); background: var(--paper);
    margin-bottom: 12px; padding: 4px 12px 10px;
  }
  td { border: none; border-bottom: 1px solid var(--grat); text-align: right;
       display: flex; justify-content: space-between; align-items: center; gap: 14px; padding: 9px 0; }
  td:last-child { border-bottom: none; }
  td::before {
    content: attr(data-label); font-size: 10px; letter-spacing: .18em; text-transform: uppercase;
    color: var(--ink-2); text-align: left; flex: 0 0 auto;
  }
  td[colspan] { justify-content: flex-start; }
  td[colspan]::before { content: ""; }
  .wheel b { font-size: 9px; padding: 3px 5px; }
}
@media (max-width: 420px) {
  .wheel b.e, .wheel b.w { position: static; transform: none; display: block;
                           margin: 6px auto; width: max-content; }
}

@media (max-width: 620px) {
  .empty { flex-direction: column; align-items: flex-start; gap: 12px; }
  .empty img { width: 128px; }
}


/* ── the character, placed rather than sprinkled ─────────────────────────────────────────
   Each vignette is chosen for what it says where it sits: rowing on the vote tab because that is
   steering, facing forward and still on course because the chart does not move, holding the
   compass in the docs because that is the thing being explained. A mascot repeated for decoration
   stops being read after the second time. */
.side { display: flex; gap: 20px; align-items: center; margin-bottom: 16px; }
.side > img {
  width: 168px; height: auto; flex: 0 0 auto;
  border: 2px solid var(--ink); box-shadow: 4px 4px 0 rgba(20, 62, 33, .13);
}
.side > p, .side > div { flex: 1 1 auto; }
.notice.side { align-items: center; }
.notice.side > img { width: 120px; }

@media (max-width: 620px) {
  .side { flex-direction: column; align-items: flex-start; gap: 12px; }
  .side > img { width: 100%; max-width: 320px; }
  .notice.side > img { width: 100%; max-width: 260px; }
}


/* ── the splash ──────────────────────────────────────────────────────────────────────────
   🔴 A loading screen must not itself need loading. This one is a 45 KB clip and a PNG, on top of
   a page that is already built: it hides nothing that is still arriving. An earlier plan put a
   compressed GLB, three.js, a glTF loader and a Draco WASM decoder here, which is four megabytes
   of machinery in front of a page that weighs fifteen kilobytes. */
#splash {
  position: fixed; inset: 0; z-index: 90; background: var(--paper);
  display: grid; place-items: center;
  animation: splashout .55s ease-in 3.4s forwards;
}
.splashin { display: grid; justify-items: center; gap: 22px; padding: 20px; }
/* The walk is rendered ON the paper colour, so it needs no frame: a border round it would draw a
   box on a background that is already the page. */
#splashVid {
  width: 280px; height: 280px; object-fit: cover; display: block;
  animation: splashpop .7s cubic-bezier(.2,.9,.3,1.3) both;
}
.splashmark { width: 260px; height: auto; animation: splashpop .7s cubic-bezier(.2,.9,.3,1.3) .18s both; }
.splashbar { width: 260px; height: 12px; border: 2px solid var(--ink); background: var(--paper); }
.splashbar i { display: block; height: 100%; width: 0; background: var(--needle);
               animation: splashfill 3.3s linear .1s forwards; }

@keyframes splashpop { from { opacity: 0; transform: scale(.86) } to { opacity: 1; transform: none } }
@keyframes splashfill { to { width: 100% } }
@keyframes splashout { to { opacity: 0; visibility: hidden } }

/* 🔴 Reduced motion means no lurching movement. It does NOT mean no loading screen, and the
   earlier rule here read it that way: it collapsed the curtain to a 10 ms flash, so anyone with
   Reduce Motion switched on (a default many people keep on a phone) saw the splash blink and
   vanish. The curtain still holds its time; it cross-fades in place instead of popping, sliding
   and walking. */
@media (prefers-reduced-motion: reduce) {
  #splash { animation: splashout .5s ease-in 2.4s forwards; }
  #splashVid, .splashmark { animation: splashfade .4s ease-out both; }
  .splashbar i { animation: splashfill 2.3s linear .1s forwards; }
}
@keyframes splashfade { from { opacity: 0 } to { opacity: 1 } }
@media (max-width: 520px) {
  #splashVid { width: 220px; height: 220px; }
  .splashmark, .splashbar { width: 210px; }
}


/* A rendered cut-out has no background to frame, so it gets no border. Putting one round a
   transparent PNG draws a box round empty pixels. */
.side > img.cutout, .empty img.cutout {
  border: none; box-shadow: none; background: none;
}


/* A clip standing in for a still: same box, same framing, no border. `preload="none"` matters here
   because these sit on tabs a visitor may never open, and a page that fetches every video up front
   spends a visitor's data on frames nobody sees. */
.side > video.anim {
  width: 168px; height: 168px; flex: 0 0 auto; object-fit: cover; display: block;
}

/* He runs while the chain is being read, and stands still when it is not. The motion says what the
   machine is doing, which a spinner also does, except this one is the project's own character. */
.runner { width: 46px; height: 46px; object-fit: cover; vertical-align: -14px; margin-right: 8px; }

@media (max-width: 620px) {
  .side > video.anim { width: 100%; max-width: 320px; height: auto; aspect-ratio: 1; }
}

/* ── the stake dialog ──────────────────────────────────────────────────────────────────────
   A native <dialog>: focus trapping, Escape and the backdrop come from the browser, so there is
   no home-made modal to get wrong. */
#stakeDlg {
  /* margin:auto is what centres a <dialog> in its viewport-sized containing block. Without it
     the browser pins it to the top and it reads as a banner rather than a dialog. */
  margin: auto;
  border: 2px solid var(--ink); background: var(--paper); color: var(--ink);
  padding: 0; max-width: 460px; width: calc(100% - 40px);
  box-shadow: 0 18px 40px rgba(16, 48, 26, .22);
}
#stakeDlg::backdrop { background: rgba(16, 48, 26, .34); }
.dlgform { padding: 22px 24px 20px; }
.dlgform h3 { font-size: 13px; letter-spacing: .22em; text-transform: uppercase;
              color: var(--ink-2); font-weight: 500; margin-bottom: 16px; }
.dlgform .muted { display: block; margin: 14px 0 18px; }
#stakeList .stat:first-child { border-top: 1px solid var(--grat); }

/* ── diagrams in the docs ──────────────────────────────────────────────────────────────────
   Drawn in CSS from the same palette as everything else, so a diagram is never a picture of the
   product that can drift from it. Each one carries the number it illustrates. */
.diagram { margin: 14px 0 4px; }
.diagram .cap { font-size: 11px; letter-spacing: .16em; text-transform: uppercase;
                color: var(--ink-2); margin-top: 8px; }

/* the two books, side by side: what Pons leaves, and what a gauge fills */
.books { display: grid; grid-template-columns: minmax(0,1fr) minmax(0,1fr); gap: 18px; }

/* a v3 range, drawn against its pool: the narrow one has far more liquidity for the same money */
.range { position: relative; height: 46px; border: 2px solid var(--ink); background: var(--paper); }
.range i { position: absolute; top: 0; bottom: 0; background: var(--land); opacity: .55; }
.range b { position: absolute; top: -5px; bottom: -5px; width: 4px; background: var(--needle);
           outline: 2px solid var(--ink); left: 50%; margin-left: -2px; }

/* the boost, as the thing it is: one bar next to a taller one */
.boostbar { display: flex; align-items: flex-end; gap: 12px; height: 96px; }
.boostbar i { flex: 1 1 0; background: var(--land); border: 2px solid var(--ink); border-bottom: none;
              position: relative; }
.boostbar i span { position: absolute; left: 0; right: 0; top: -20px; text-align: center;
                   font-size: 11px; letter-spacing: .12em; color: var(--ink-2); }
.boostbar i.pale { background: var(--paper); }

/* where a fee goes, as one bar cut in proportion */
.split { display: flex; height: 34px; border: 2px solid var(--ink); }
.split i { display: flex; align-items: center; justify-content: center;
           font-size: 11px; letter-spacing: .12em; text-transform: uppercase; }
.split i + i { border-left: 2px solid var(--ink); }
.split i.voters { background: var(--land); color: var(--paper); }
.split i.treas { background: var(--needle); color: var(--ink); }

/* ── inside the stake dialog ───────────────────────────────────────────────────────────────
   A position is only worth staking if the price is inside it, so the panel draws exactly that:
   the pool's range, the position's band on it, and where the price currently sits. */
.dlghead { display: flex; align-items: flex-start; gap: 14px; margin-bottom: 16px; }
.dlghead > div:first-child { flex: 1 1 auto; min-width: 0; }
.dlgtitle { font-size: 17px; font-weight: 500; }
.dlgrow { display: flex; justify-content: space-between; align-items: baseline; gap: 12px;
          padding: 10px 0; border-top: 1px solid var(--grat); font-size: 12px;
          letter-spacing: .12em; text-transform: uppercase; color: var(--ink-2); }
.dlgrow b { font-size: 14px; letter-spacing: 0; text-transform: none; color: var(--ink);
            font-variant-numeric: tabular-nums; }

.pos { border-top: 1px solid var(--grat); padding: 14px 0; }
.pos:last-of-type { border-bottom: 1px solid var(--grat); }
.posline { display: flex; align-items: baseline; justify-content: space-between; gap: 12px;
           flex-wrap: wrap; margin-bottom: 10px; }
.posline .id { font-variant-numeric: tabular-nums; }
.posline .liq { color: var(--ink-2); font-size: 12px; }

/* the range bar: the pool across the width, the position as a block, the price as a needle */
.rangebar { position: relative; height: 30px; border: 2px solid var(--ink); background: var(--paper);
            margin-bottom: 10px; }
.rangebar i { position: absolute; top: 0; bottom: 0; background: var(--land); opacity: .5; }
.rangebar i.out { background: var(--grat); opacity: 1; }
.rangebar b { position: absolute; top: -4px; bottom: -4px; width: 4px; margin-left: -2px;
              background: var(--needle); outline: 2px solid var(--ink); }
.posfoot { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; }

@media (max-width: 520px) {
  .dlgtitle { font-size: 15px; }
  .posfoot .btn { width: 100%; }
}
