/*
 * Pickle component system.
 *
 * The .ex-* vocabulary is the stable API every site and every render string in
 * app.js consumes. This file dresses the six app UIs: the faucet, the explorer,
 * the bridge, the toolkit, .pkl names and mini-blocks. The marketing page in
 * web/ shares the tokens and the faces but not this rhythm, because it is a
 * document you read once and these are tools you use weekly.
 *
 *   - Flat surfaces on the #0A0A0B stage, 2px radius, one hairline.
 *   - Every rule paints through the register properties (--pickle-text,
 *     --pickle-line, --pickle-surface-1, --pickle-muted, --pickle-subtle,
 *     --pickle-accent-text, --pickle-ground) rather than through literals, so a
 *     section can redefine its own ground without duplicating a rule.
 *   - Mono uppercase micro-labels in IBM Plex Mono against Inter Tight display
 *     type. There is no second text family.
 *   - The signature layout patterns: numbered eyebrow headers, 1px-gap cell
 *     grids, hairline stat strips, waterfall bars.
 *   - Structure only. Everything with a duration lives in shared-ui/motion.css,
 *     which loads after this file: entrances, the scroll cascade, hover and
 *     press. The one exception is the cadence lanes and the pulse dot, whose
 *     motion IS the information they carry.
 *
 * Explorer-only pieces stay in explorer-ui/css/explorer.css.
 */

/* ============================================================ shell: nav bar */

/*
 * The shell host. shared-ui/shell.js replaces the contents of
 * `<header data-pickle-shell>` with the bar below, and that host needs two things
 * this rule gives it.
 *
 * First, it has to be the sticky box. `.ex-nav` declares `position: sticky` and
 * on the two apps that write their bar straight into <body> (explorer-ui and
 * pns-ui) it pins correctly. In the four that mount it through shell.js it did
 * not, and measuring showed why: the host's height is exactly the bar's 72px, and
 * a sticky element cannot move within a containing block its own size. So the bar
 * scrolled away on the faucet, the bridge, mini-blocks and all seven toolkit
 * pages - where the six-section subnav is the only navigation between the tools.
 * Nothing about the CSS looked wrong; only scrolling the page showed it.
 *
 * Second, min-height reserves the bar's space before the script runs. An empty
 * header is 0px tall, so the page painted 72px too high and then dropped.
 *
 * The z-index has to live HERE, on the host, and not be left to the .ex-nav
 * inside it. `position: sticky` establishes a stacking context unconditionally -
 * unlike relative or absolute, which need a non-auto z-index first - so the
 * moment this host became sticky it began trapping the bar's own
 * --pickle-z-nav inside itself. The host then competed with page content at
 * z-index 0, lost on document order because <main> comes after <header>, and the
 * toolkit's cells painted straight over the bar at 375px. Naming the level on the
 * box that actually stacks is what fixes it.
 */
[data-pickle-shell] {
  display: block;
  position: sticky;
  top: 0;
  z-index: var(--pickle-z-nav);
  min-height: var(--pickle-nav-h);
}

.ex-nav {
  position: sticky;
  top: 0;
  z-index: var(--pickle-z-nav);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0 var(--pickle-space-5);
  height: var(--pickle-nav-h);
  padding-inline: max(var(--pickle-gutter), calc((100vw - var(--pickle-content)) / 2));

  /* The bar keeps its own ink register on both grounds, and that is a choice
   * rather than a failure to invert. Making a sticky bar track the register
   * underneath it needs either mix-blend-mode: difference, which distorts the
   * accent's hue into something that is no longer the brand colour, or a
   * timeline-scope naming every paper act by hand. A persistent ink running
   * head over paper is a legitimate editorial form and removes both.
   *
   * Redeclaring the register properties here is what makes that work: without
   * them the bar would inherit a paper act's #121212 text and paint near-black
   * on near-black. */
  --pickle-text: #ffffff;
  --pickle-line: rgb(255 255 255 / 14%);
  --pickle-muted: #9aa3a0;
  --pickle-subtle: #6b7370;
  --pickle-accent-text: var(--pickle-mint);

  color: var(--pickle-text);
  /* Keyed to --pickle-bg (#0A0A0B), not to the #121212 the page used to be: at 82%
   * opacity a lighter ground reads as a grey band floating over black rather
   * than as the page's own surface. */
  background: rgb(10 10 11 / 78%);
  backdrop-filter: blur(20px) saturate(150%);
  border-bottom: 1px solid var(--pickle-line);
}

.ex-nav > * {
  display: flex;
  align-items: center;
  height: var(--pickle-nav-h);
}

/* The running head's act readout. Mono, small, and the only thing in the bar
 * that changes as the reader scrolls - the section eyebrow pattern reduced to
 * bar height.
 *
 * `display: none` by default and shown only where there is room: the bar already
 * carries a brand, six links, two buttons and a burger, and the readout is the
 * one element that is orientation rather than navigation, so it is the one that
 * should go first when space runs out. */
.ex-act {
  display: none;
  gap: .5rem;
  margin: 0;
  padding-left: var(--pickle-space-5);
  color: var(--pickle-subtle);
  font-family: var(--pickle-font-mono);
  font-size: var(--pickle-text-2xs);
  letter-spacing: var(--pickle-tracking-caps);
  text-transform: uppercase;
  white-space: nowrap;
  border-left: 1px solid var(--pickle-line);
}

/* Through the register, not the raw accent. The bar pins its own ink values so
 * this resolves to the same green either way - but routing it through
 * --pickle-accent-text means there is no exception to remember, and no exception
 * for tests/design-language.test.mjs to have to allow. */
.ex-act .n { color: var(--pickle-accent-text); }

/* Shown exactly where the link rail is hidden, and the thresholds are measured
 * rather than chosen.
 *
 * The bar's content column is capped at --pickle-content whatever the viewport, so
 * it is 1240px wide at 1440px and at 1920px alike. Brand, six links and two
 * buttons already fill it: measured, adding the readout pushed the action group
 * onto a second row at every width from 1360px up, including 1920px. Making room
 * would mean dropping a nav item or letting the bar span wider than the text
 * column it sits above - a misalignment that reads as a bug.
 *
 * So the readout appears below 1220px, where the rail is hidden and there is
 * real room. That is also where it earns the most: with no links on screen,
 * nothing else says which chapter you are in. Below 560px even the burger and
 * the testnet button leave no space, so it goes again.
 */
@media (min-width: 560px) and (max-width: 1219px) {
  .ex-act { display: flex; }
}

/* A single row, always: brand, links and actions share one 72px bar. The
 * subnav used to be forced onto a second row with `flex: 1 0 100%`, which put
 * the logo above the buttons. It now sits inline and scrolls sideways when it
 * runs out of width. */
/* One row where the contents fit, two where they wrap, and the background
 * follows either way. This was pinned at a flat 72px while `.ex-nav > *` gave
 * each row that same 72px, so on a phone the subnav row painted 72px BELOW the
 * bar's box - outside its background and its border, over the scrolling page,
 * on transparent ground. `overflow: visible` meant nothing clipped and nothing
 * looked wrong in the stylesheet. */
.ex-nav.stack {
  height: auto;
  min-height: var(--pickle-nav-h);
}

.ex-brand {
  gap: 10px;
  flex: 0 1 auto;
  min-width: 0;
  overflow: hidden;
  color: var(--pickle-text);
  font-family: var(--pickle-font-display);
  font-size: 1.16rem;
  font-weight: 600;
  letter-spacing: var(--pickle-tracking-tight);
  white-space: nowrap;
}

.ex-brand:hover { color: var(--pickle-text); }
.ex-brand img { width: 30px; height: 36px; object-fit: contain; flex: 0 0 auto; }

.ex-brand span {
  min-width: 0;
  overflow: hidden;
  color: var(--pickle-subtle);
  font-family: var(--pickle-font-mono);
  font-size: var(--pickle-text-2xs);
  font-weight: 400;
  letter-spacing: .13em;
  text-transform: uppercase;
  text-overflow: ellipsis;
}

/* Link rails scroll sideways rather than wrapping, so the bar keeps its
 * declared height on every viewport. */
.ex-links,
.ex-subnav {
  display: flex;
  align-items: center;
  gap: var(--pickle-space-2);
  min-width: 0;
  overflow-x: auto;
  overflow-y: hidden;
  scrollbar-width: none;
  overscroll-behavior-x: contain;
}

.ex-links::-webkit-scrollbar,
.ex-subnav::-webkit-scrollbar { height: 0; }

.ex-links { flex: 1 1 auto; }

.ex-subnav {
  flex: 1 1 auto;
  height: var(--pickle-nav-h);
}

/* A stacked bar is brand, subnav, sign-in, in that order, so the sign-in ends
 * the row on the right as it does in every other app. Where the three stop
 * fitting, the subnav takes a full row of its own under the other two rather
 * than letting the sign-in drop to a third row after it; 900px is where the
 * toolkit's six links already wrapped. */
@media (max-width: 899px) {
  .ex-nav.stack .ex-subnav { order: 1; flex-basis: 100%; }
}

/* Every interactive target in a bar stays 44px in both directions. */
.ex-nav a,
.ex-nav button,
.ex-tabs button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: var(--pickle-tap);
  min-height: var(--pickle-tap);
}

.ex-links a,
.ex-subnav a {
  flex: 0 0 auto;
  padding-inline: var(--pickle-space-4);
  border: 1px solid transparent;
  border-radius: var(--pickle-radius);
  color: var(--pickle-muted);
  font-size: var(--pickle-text-base);
  font-weight: 500;
  white-space: nowrap;
  transition: color var(--pickle-fast) var(--pickle-ease), background var(--pickle-fast) var(--pickle-ease);
}

/* No filled plate on hover. With the underline mark below doing the work, a
 * background as well is two signals for one state, and it is the one that made
 * the bar look like a row of buttons. */
.ex-links a:hover,
.ex-subnav a:hover { color: var(--pickle-text); }

/* The active link is marked UNDER the word rather than boxed around it.
 *
 * The hairline chip this replaced put a rounded border around one item in a row
 * of plain words, which read as a button among links and made the bar look like
 * a toolbar. A 2px rule under the label is the same information with none of
 * that: it belongs to the word, it lines up across the whole rail, and it is the
 * mark the section eyebrows already use elsewhere on the page.
 *
 * The rule is a pseudo-element rather than a border-bottom so it can be inset
 * from the link's padding and sit under the text instead of under the hit area,
 * which at 44px tall is a long way below the word. */
.ex-links a.on,
.ex-subnav a.on {
  color: var(--pickle-text);
  border-color: transparent;
  background: transparent;
}

.ex-links a,
.ex-subnav a { position: relative; }

.ex-links a.on::after,
.ex-subnav a.on::after {
  content: "";
  position: absolute;
  left: var(--pickle-space-4);
  right: var(--pickle-space-4);
  bottom: calc(50% - .95em);
  height: 2px;
  background: var(--pickle-mint);
}

/* Hover gets the same mark, faint, so the rail tells you where a click lands
 * before you make it. */
.ex-links a:not(.on)::after,
.ex-subnav a:not(.on)::after {
  content: "";
  position: absolute;
  left: var(--pickle-space-4);
  right: var(--pickle-space-4);
  bottom: calc(50% - .95em);
  height: 2px;
  background: var(--pickle-line);
  transform: scaleX(0);
  transform-origin: center;
  transition: transform var(--pickle-base) var(--pickle-ease);
}

.ex-links a:not(.on):hover::after,
.ex-subnav a:not(.on):hover::after { transform: scaleX(1); }

.ex-net {
  gap: 8px;
  flex: 0 0 auto;
  padding-inline: var(--pickle-space-3);
  color: var(--pickle-muted);
  font-family: var(--pickle-font-mono);
  font-size: var(--pickle-text-2xs);
  letter-spacing: .13em;
  text-transform: uppercase;
  white-space: nowrap;
}

.ex-net b { color: var(--pickle-accent-text); font-weight: 500; }

.ex-net::before {
  content: "";
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--pickle-mint);
  animation: pickle-pulse 2.2s infinite;
}

.ex-wallet { position: relative; gap: var(--pickle-space-3); flex: 0 0 auto; margin-left: auto; }

/* Ghost nav action (Docs). */
.ex-navghost {
  height: 42px;
  padding-inline: 20px;
  color: var(--pickle-accent-text);
  font-size: var(--pickle-text-base);
  font-weight: 500;
  border: 1px solid var(--pickle-mint-line);
  border-radius: var(--pickle-radius);
}

.ex-navghost:hover { color: var(--pickle-mint-hi); border-color: var(--pickle-mint); background: var(--pickle-mint-soft); }

/* A promise the product cannot keep yet, shipped as a disabled span rather
 * than a dead <a>: it is not a link, so it must not look or behave like one. */
.ex-soon {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  height: 42px;
  padding-inline: 22px;
  color: var(--pickle-subtle);
  font-size: var(--pickle-text-base);
  font-weight: 600;
  white-space: nowrap;
  cursor: not-allowed;
  background: rgb(255 255 255 / 4%);
  border: 1px solid rgb(255 255 255 / 12%);
  border-radius: var(--pickle-radius);
}

.ex-soon b {
  padding: 2px 7px;
  color: var(--pickle-faint);
  font-family: var(--pickle-font-mono);
  font-size: .58rem;
  font-weight: 400;
  letter-spacing: .12em;
  text-transform: uppercase;
  border: 1px solid rgb(255 255 255 / 12%);
  border-radius: var(--pickle-radius);
}

/* Burger + full-screen menu, shown only where the link rail does not fit.
 *
 * `.ex-nav .ex-burger`, not `.ex-burger`: the `.ex-nav button` tap-target rule
 * above says `display: inline-flex` at 0,1,1, which quietly beat this rule's
 * 0,1,0 - so the burger showed on desktop next to the full link rail, on all
 * seven UIs, at every width. The extra ancestor takes both of this pair to
 * 0,2,0 and the breakpoint decides again. */
.ex-nav .ex-burger {
  display: none;
  width: 42px;
  height: 42px;
  place-items: center;
  color: var(--pickle-text);
  cursor: pointer;
  background: none;
  border: 1px solid rgb(255 255 255 / 16%);
  border-radius: var(--pickle-radius);
}

.ex-mobmenu {
  position: fixed;
  inset: var(--pickle-nav-h) 0 0;
  z-index: var(--pickle-z-menu);
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 28px var(--pickle-gutter);
  overflow-y: auto;
  background: rgb(20 22 21 / 97%);
  backdrop-filter: blur(18px);
}

.ex-mobmenu[hidden] { display: none; }

.ex-mobmenu a {
  padding: 15px 0;
  color: var(--pickle-text);
  font-family: var(--pickle-font-display);
  font-size: 1.5rem;
  font-weight: 600;
  border-bottom: 1px solid var(--pickle-line);
}

.ex-mobmenu a.accent { color: var(--pickle-accent-text); border-bottom: 0; }

/* Scroll progress: a 2px brand line driven purely by CSS scroll timelines.
 * scaleX(0) is the base state, so browsers without animation-timeline simply
 * never show it. Injected by shell.js - decoration, not content. */
.ex-progress {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: var(--pickle-z-progress);
  height: 2px;
  background: var(--pickle-mint);
  transform: scaleX(0);
  transform-origin: 0 50%;
  pointer-events: none;
  animation: pickle-progress linear;
  animation-timeline: scroll(root block);
}

@keyframes pickle-progress { from { transform: scaleX(0); } to { transform: scaleX(1); } }

/* ================================================================ shell: page */

/* App pages: the same editorial rhythm as the marketing page, one step down.
 * They were opening 56px below the bar, which read as cramped next to the
 * 132px hero on the home page. */
.ex-wrap {
  width: min(100%, var(--pickle-content));
  margin-inline: auto;
  padding: var(--pickle-section-sm) var(--pickle-gutter) var(--pickle-section);
}

.ex-wrap.app { width: min(100%, var(--pickle-content-app)); }

/* ============================================================== page headings
 * The numbered eyebrow is the signature section header: a 26px dash, a dim
 * index, and a green mono label. Sites write:
 *   <p class="ex-kicker"><span class="n">01</span>Faucet</p>
 * Plain text content (no .n) still renders correctly.
 */

.ex-kicker {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  margin: 0 0 var(--pickle-kicker-gap);
  color: var(--pickle-accent-text);
  font-family: var(--pickle-font-mono);
  font-size: .72rem;
  font-weight: 400;
  letter-spacing: var(--pickle-tracking-caps-wide);
  text-transform: uppercase;
}

.ex-kicker::before {
  content: "";
  width: 26px;
  height: 1px;
  background: currentColor;
  opacity: .6;
}

.ex-kicker .n { color: var(--pickle-subtle); }

.ex-h {
  display: flex;
  flex-wrap: wrap;
  gap: var(--pickle-space-2) var(--pickle-space-3);
  align-items: baseline;
  margin: 0 0 var(--pickle-space-4);
  font-family: var(--pickle-font-display);
  font-size: var(--pickle-text-3xl);
  font-weight: 600;
  line-height: var(--pickle-leading-display);
  letter-spacing: var(--pickle-tracking-display);
}

.ex-h .mono { font-size: var(--pickle-text-lg); font-weight: 500; word-break: break-all; }
.ex-h .accent, .ex-display .accent { color: var(--pickle-accent-text); }

.ex-lede {
  max-width: 56ch;
  margin: 0 0 var(--pickle-sechead-gap);
  color: var(--pickle-muted);
  font-size: clamp(1rem, 1.4vw, 1.15rem);
  line-height: 1.7;
}

.ex-title {
  margin: 0 0 var(--pickle-space-4);
  font-family: var(--pickle-font-display);
  font-size: var(--pickle-text-xl);
  font-weight: 600;
}

.ex-crumb {
  margin: 0 0 var(--pickle-space-3);
  color: var(--pickle-subtle);
  font-family: var(--pickle-font-mono);
  font-size: var(--pickle-text-xs);
}

.ex-crumb a { color: var(--pickle-muted); }
.ex-crumb a:hover { color: var(--pickle-accent-text); }

.ex-pagehead {
  display: flex;
  flex-wrap: wrap;
  gap: var(--pickle-space-3);
  align-items: center;
  justify-content: space-between;
  margin-bottom: var(--pickle-space-5);
}

.ex-pagehead h2 {
  margin: 0;
  font-family: var(--pickle-font-display);
  font-size: var(--pickle-text-2xl);
  font-weight: 600;
  text-transform: none;
}

.ex-pagehead .ex-btn { flex: 0 0 auto; }

.ex-list-head {
  display: flex;
  /* wrap, or on a phone the caption is squeezed alongside a title that has
     already broken into two lines and neither of them is readable */
  flex-wrap: wrap;
  gap: var(--pickle-space-3);
  align-items: center;
  justify-content: space-between;
  margin: 0 0 var(--pickle-space-4);
  font-family: var(--pickle-font-display);
  font-size: var(--pickle-text-base);
  font-weight: 600;
}

.ex-more {
  color: var(--pickle-muted);
  font-family: var(--pickle-font-mono);
  font-size: var(--pickle-text-2xs);
  letter-spacing: .13em;
  text-transform: uppercase;
  white-space: nowrap;
}

/*
 * The chevron is DRAWN, from two borders, not typed. Neither Inter Tight nor
 * IBM Plex Mono carries U+2192, so the arrow that used to sit here rendered from
 * whatever system face the browser fell back to. shared-ui/shell.js ships an SVG
 * arrow (#i-arrow) for markup; a ::after cannot use it, so it gets geometry.
 *
 * And it belongs to LINKS only. `.ex-more` is also the class on plain count and
 * label spans - "blocks 1,234", "Live", "Local registry" - which were all being
 * given an arrow that pointed nowhere.
 */
a.ex-more::after {
  content: "";
  display: inline-block;
  width: .32em;
  height: .32em;
  margin-left: .55em;
  border-top: 1px solid currentColor;
  border-right: 1px solid currentColor;
  transform: translateY(-.06em) rotate(45deg);
  transition: transform var(--pickle-base) var(--pickle-ease);
}

.ex-more:hover { color: var(--pickle-accent-text); }
a.ex-more:hover::after { transform: translateY(-.06em) translateX(2px) rotate(45deg); }

/* ================================================================= sections
 * The editorial page is a stack of full-width sections, each 120px tall in the
 * gutter, with a centred 1240px measure inside. A section header is an eyebrow,
 * a display headline and a lede, capped at 840px and sitting 56px above the
 * content it introduces. This vertical rhythm is what makes the page read as an
 * editorial spread rather than a dashboard.
 */

.ex-section {
  padding: var(--pickle-section) 0;
}

.ex-section.sm { padding: var(--pickle-section-sm) 0; }
.ex-section.tight { padding: var(--pickle-space-7) 0; }

/* Sections that own a rule between them. */
.ex-section.ruled { border-bottom: 1px solid var(--pickle-line); }

.ex-measure {
  width: min(100%, var(--pickle-content));
  margin-inline: auto;
  padding-inline: var(--pickle-gutter);
}

.ex-sechead {
  max-width: 840px;
  margin-bottom: var(--pickle-sechead-gap);
}

.ex-sechead.center { margin-inline: auto; text-align: center; max-width: 760px; }
.ex-sechead.center .ex-kicker { justify-content: center; }
.ex-sechead .ex-lede { margin-bottom: 0; margin-top: 20px; }

/* The section headline. No font-size here on purpose: base.css sets the app-safe
 * step on h2, and the marketing page overrides it per scene in
 * web/public/css/scenes.css. A size at this specificity would land in the app
 * UIs and on the scene stages both, and the scene sizes are viewport-fitted. */
.ex-sechead h2 {
  letter-spacing: var(--pickle-tracking-display);
  line-height: var(--pickle-leading-display);
  /* A display serif reads best at a measure it cannot outrun. 22 characters is
   * roughly three words a line at 5rem, which is what makes a headline scan as
   * a headline rather than as a paragraph in a large size. */
  max-width: 22ch;
}

.ex-sechead.center h2 { margin-inline: auto; }

/* The quiet mono aside. It was only ever defined beside a section eyebrow, so
 * the same class used anywhere else - under an NFT grid, beneath a table - was
 * inheriting body type and reading as content rather than as a footnote. */
.ex-note {
  color: var(--pickle-subtle);
  font-family: var(--pickle-font-mono);
  font-size: var(--pickle-text-2xs);
  letter-spacing: .12em;
}

/* Beside a section eyebrow it also stops taking part in the baseline flow. */
.ex-sechead .ex-note { margin: 0; }

/* Standing on its own under a grid or a table, it needs the gap the eyebrow
 * variant gets from its container. */
.ex-nft-grid + .ex-note,
.ex-table + .ex-note { margin: var(--pickle-space-3) 0 0; }

.ex-secrow {
  display: flex;
  flex-wrap: wrap;
  gap: var(--pickle-space-4);
  align-items: baseline;
  justify-content: space-between;
  margin-bottom: var(--pickle-space-6);
}

/* ---- problem list: a hairline rule down the left of each item ------------ */

.ex-problems {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 20px;
}

.ex-problem { border-left: 2px solid rgb(255 255 255 / 10%); padding-left: 24px; }

.ex-problem .n {
  color: var(--pickle-accent-text);
  font-family: var(--pickle-font-mono);
  font-size: var(--pickle-text-xs);
  letter-spacing: .2em;
  text-transform: uppercase;
}

.ex-problem h3 {
  margin: 10px 0;
  font-size: 1.15rem;
  letter-spacing: -.02em;
}

.ex-problem p { color: var(--pickle-muted); font-size: var(--pickle-text-md); }

/* ---- thesis cells: big type, a 44x2 brand rule underneath ---------------- */

.ex-thesis {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 1px;
  background: var(--pickle-line);
  border: 1px solid var(--pickle-line);
  border-radius: var(--pickle-radius);
  overflow: hidden;
}

.ex-thesis > div {
  background: var(--pickle-surface-2);
  padding: 44px 34px;
  transition: background var(--pickle-fast) var(--pickle-ease);
}

.ex-thesis > div:hover { background: var(--pickle-surface-3); }

.ex-thesis .n {
  color: var(--pickle-subtle);
  font-family: var(--pickle-font-mono);
  font-size: var(--pickle-text-xs);
  letter-spacing: .2em;
}

.ex-thesis h3 {
  margin: 18px 0 14px;
  font-size: 1.7rem;
  letter-spacing: -.025em;
}

.ex-thesis p { color: var(--pickle-muted); font-size: var(--pickle-text-md); }
.ex-thesis .rule { width: 44px; height: 2px; margin-top: 26px; background: var(--pickle-mint); }

/* ---- roadmap: a phase column beside its body, ruled between rows --------- */

.ex-roadmap > div {
  display: grid;
  grid-template-columns: 190px minmax(0, 1fr);
  gap: 34px;
  align-items: start;
  padding: 34px 0;
  border-top: 1px solid var(--pickle-line);
}

.ex-roadmap > div:last-child { border-bottom: 1px solid var(--pickle-line); }

.ex-roadmap .phase {
  font-family: var(--pickle-font-display);
  font-size: 1.3rem;
  font-weight: 600;
  letter-spacing: -.02em;
}

.ex-roadmap p { color: var(--pickle-muted); }

.ex-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 14px 0 0;
  padding: 0;
  list-style: none;
}

.ex-tags li {
  padding: 6px 12px;
  color: var(--pickle-muted);
  font-size: var(--pickle-text-sm);
  border: 1px solid var(--pickle-line);
  border-radius: var(--pickle-radius);
}

/* ---- data table inside a panel ------------------------------------------ */

.ex-tablewrap {
  overflow-x: auto;
  padding: 22px 4px 4px;
  background: var(--pickle-surface-1);
  border: 1px solid var(--pickle-line);
  border-radius: var(--pickle-radius);
}

.ex-tablewrap .ex-table td { padding: 18px; vertical-align: top; }
.ex-tablewrap .ex-table th { padding: 0 18px 14px; }
.ex-tablewrap .ex-table td:first-child { color: var(--pickle-text); font-weight: 500; }
.ex-tablewrap .ex-table td.p { color: var(--pickle-accent-text); font-family: var(--pickle-font-mono); white-space: nowrap; }
.ex-tablewrap .ex-table tbody tr:hover { background: transparent; }

/* ---- closing call to action --------------------------------------------- */

.ex-cta {
  padding: 80px 40px;
  text-align: center;
  background: var(--pickle-surface-1);
  border: 1px solid var(--pickle-line);
  border-radius: var(--pickle-radius);
}

.ex-cta .ex-kicker { justify-content: center; }
.ex-cta h2 { font-size: var(--pickle-text-3xl); letter-spacing: -.03em; line-height: 1.08; }
.ex-cta .ex-lede { max-width: 600px; margin: 22px auto 0; }

.ex-cta .ex-actions {
  justify-content: center;
  margin: 36px 0 0;
}

/* ---- caveat block: amber hairline, used for "proposed" and risk notes ---- */

.ex-caveat {
  padding: 32px;
  border: 1px solid var(--pickle-amber-line);
  border-radius: var(--pickle-radius);
}

.ex-caveat h3 { margin-bottom: 14px; font-size: 1.15rem; letter-spacing: -.02em; }

.ex-caveat .cols {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 26px;
  color: var(--pickle-muted);
  font-size: var(--pickle-text-md);
}

.ex-footnote {
  margin-top: 18px;
  color: var(--pickle-subtle);
  font-family: var(--pickle-font-mono);
  font-size: var(--pickle-text-xs);
  line-height: 1.7;
}

/* ==================================================================== hero */

/* One column, not two. The old two-column hero put the headline in half a
 * viewport, and half a viewport is precisely what capped the display size at
 * 5.2rem - the structural reason the previous language could not go bigger.
 * Giving the headline the full measure is what makes 11rem possible. */
.ex-hero {
  display: grid;
  gap: var(--pickle-space-6);
  margin-bottom: var(--pickle-space-7);
}

/* No font-size: base.css sets the app-safe display step on h1, and the scene
 * stylesheet in web/ sizes its own headings against the viewport. A size here
 * would apply to both and defeat that fitting. */
.ex-hero h1,
.ex-display {
  margin: 0 0 var(--pickle-space-5);
  font-family: var(--pickle-font-display);
  font-weight: 600;
  line-height: var(--pickle-leading-display);
  letter-spacing: var(--pickle-tracking-display);
}

.ex-display { font-size: var(--pickle-text-display); }

.ex-hero h1 span { display: block; }
.ex-hero h1 .accent { color: var(--pickle-accent-text); }
.ex-hero .ex-lede { margin-bottom: var(--pickle-space-6); }
.ex-hero-art { position: relative; }

/* Faint blueprint grid behind the hero, fading out downward. */
/* The grid is absolute against its section, so the section has to be the
 * containing block. Stated with :has() rather than left to whichever wrapper
 * happens to be positioned: the class that needed it was deleted with the
 * design it belonged to, and the grid then sized itself against the page. */
/* clip, not hidden: the grid is inset -2px on purpose so no seam shows at the
 * edge of the section, and those two pixels were two pixels of sideways scroll
 * on every page carrying a hero. clip takes them back without making the
 * section a scroll container, which hidden would, breaking any sticky inside. */
.ex-section:has(> .ex-hero-grid) { position: relative; overflow-x: clip; }

.ex-hero-grid {
  position: absolute;
  inset: -2px;
  pointer-events: none;
  background-image:
    linear-gradient(rgb(255 255 255 / 5.5%) 1px, transparent 1px),
    linear-gradient(90deg, rgb(255 255 255 / 5.5%) 1px, transparent 1px);
  background-size: 96px 96px;
  mask-image: radial-gradient(ellipse 90% 60% at 50% 0%, #000 10%, transparent 75%);
}

/* The floating mark. Decorative; hidden on narrow viewports. */
.ex-mark {
  position: absolute;
  top: 60px;
  left: 37%;
  width: 196px;
  pointer-events: none;
  animation: pickle-float 9s ease-in-out infinite;
}

@keyframes pickle-float {
  0%, 100% { transform: translateY(0) rotate(-2deg); }
  50% { transform: translateY(-14px) rotate(2deg); }
}

/* ============================================================ cadence lanes
 * The execution pipeline visual. JS advances each lane on its own clock
 * (10 ms / 250 ms / 12 s) by elapsed time; CSS only paints the cells.
 */

.ex-lanes { display: flex; flex-direction: column; gap: var(--pickle-space-4); }

.ex-lane-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  margin-bottom: 9px;
}

/* A figure caption, in the idiom every other caption on the site uses: mono,
 * small, tracked caps, subtle. It was the one set in the sans face at body
 * scale, so the panel head read as body copy that had lost its paragraph. */
.ex-lane-head span {
  color: var(--pickle-subtle);
  font-family: var(--pickle-font-mono);
  font-size: var(--pickle-text-2xs);
  letter-spacing: .16em;
  text-transform: uppercase;
}

.ex-lane-head .rate {
  color: var(--pickle-accent-text);
  font-family: var(--pickle-font-mono);
  font-size: var(--pickle-text-xs);
}

.ex-lane { display: flex; gap: 4px; height: 38px; align-items: flex-end; }

.ex-lane .tick {
  flex: 1;
  height: 42%;
  border-radius: var(--pickle-radius);
  transition: background .08s linear, opacity .08s linear, height .08s linear;
}

/* Deterministic pseudo-random idle heights - inline styles are banned, and a
 * height per cell in markup would be noise. Two co-prime cycles give enough
 * visual variance for any cell count. */
.ex-lane .tick:nth-child(3n + 1) { height: 58%; }
.ex-lane .tick:nth-child(3n + 2) { height: 34%; }
.ex-lane .tick:nth-child(5n + 2) { height: 78%; }
.ex-lane .tick:nth-child(5n + 4) { height: 48%; }
.ex-lane .tick:nth-child(7n + 3) { height: 66%; }
.ex-lane .tick:nth-child(7n + 6) { height: 28%; }

.ex-lane[data-lane="mini"] .tick { background: var(--pickle-lane-mini-idle); }
.ex-lane[data-lane="evm"] .tick { background: var(--pickle-lane-evm-idle); }
.ex-lane[data-lane="l1"] .tick { background: var(--pickle-lane-l1-idle); }
.ex-lane-head .rate.mini { color: var(--pickle-lane-mini); }
.ex-lane-head .rate.evm { color: var(--pickle-lane-evm); }
.ex-lane-head .rate.l1 { color: var(--pickle-lane-l1); }

/* =============================================================== cell grids
 * The 1px-gap grid: hairline background, flat cells. The signature surface.
 */

.ex-cells {
  display: grid;
  gap: 1px;
  background: var(--pickle-line);
  border: 1px solid var(--pickle-line);
  border-radius: var(--pickle-radius);
  /* clip, not hidden: both clip the radius, but `hidden` also makes this a
   * scroll container, and a view() timeline inside it would resolve against a
   * box that never scrolls. shared-ui/motion.css cascades these cells. */
  overflow: clip;
}

.ex-cells.c2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.ex-cells.c3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.ex-cells.c4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }

.ex-cell {
  display: block;
  background: var(--pickle-surface-1);
  padding: var(--pickle-space-5);
  color: inherit;
  transition: background var(--pickle-fast) var(--pickle-ease);
}

a.ex-cell:hover, .ex-cell.hov:hover { background: var(--pickle-surface-3); color: inherit; }

.ex-cell h3 {
  display: flex;
  gap: 10px;
  align-items: center;
  margin: 0 0 var(--pickle-space-3);
  font-size: var(--pickle-text-lg);
}

/* A cell that navigates says so. The same drawn chevron .ex-appcard uses, on the
 * same terms: geometry rather than U+2192, which no shipped face carries.
 * Only on links - .ex-cell is also used for cells that merely group content. */
a.ex-cell h3::after,
.ex-cell.hov h3::after {
  content: "";
  flex: 0 0 auto;
  width: .4em;
  height: .4em;
  margin-left: auto;
  border-top: 1.5px solid var(--pickle-subtle);
  border-right: 1.5px solid var(--pickle-subtle);
  transform: rotate(45deg);
  transition: border-color var(--pickle-fast) var(--pickle-ease), transform var(--pickle-base) var(--pickle-ease);
}

a.ex-cell:hover h3::after,
.ex-cell.hov:hover h3::after {
  border-color: var(--pickle-accent-text);
  transform: translateX(3px) rotate(45deg);
}

.ex-cell > p {
  margin: 0;
  color: var(--pickle-muted);
  font-size: var(--pickle-text-sm);
  line-height: 1.6;
}

/* ================================================================ stat strip
 * Full-width figures separated by hairlines, mono labels underneath.
 */

.ex-strip {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  border-block: 1px solid var(--pickle-line);
  background: rgb(255 255 255 / 1.5%);
}

.ex-strip > div { padding: var(--pickle-space-6) var(--pickle-space-5); }
.ex-strip > div + div { border-left: 1px solid var(--pickle-line); }

.ex-strip b {
  display: block;
  font-family: var(--pickle-font-display);
  font-size: clamp(1.7rem, 3.2vw, 2.5rem);
  font-weight: 600;
  letter-spacing: -.04em;
  color: var(--pickle-text);
}

.ex-strip b.p { color: var(--pickle-accent-text); }
.ex-strip b small { font-size: .5em; font-weight: 600; }

.ex-strip span {
  display: block;
  margin-top: var(--pickle-space-2);
  color: var(--pickle-subtle);
  font-family: var(--pickle-font-mono);
  font-size: .68rem;
  letter-spacing: .16em;
  text-transform: uppercase;
}

/* ================================================================= surfaces */

.ex-panel,
.ex-appcard,
.ex-stat,
.ex-circle-card,
.ex-chart-card,
.ex-ms-card,
.ex-pending {
  background: var(--pickle-surface-1);
  border: 1px solid var(--pickle-line);
  border-radius: var(--pickle-radius);
}

.ex-panel { padding: var(--pickle-space-6); }
.ex-panel > h3 { margin: 0 0 var(--pickle-space-4); }
.ex-panel > :last-child { margin-bottom: 0; }

/* Two items, always: the label and whatever trailing mark the panel carries.
 * `space-between` distributes ITEMS, and every bare text run inside a flex box
 * becomes its own anonymous item - so a heading written as `L1 <svg> L2 <svg>`
 * spread four pieces across the full panel width instead of reading as a label.
 * Wrap a multi-part label in .ex-h3-label to keep it one item. */
.ex-panel h3,
.ex-chart-card h3 {
  display: flex;
  gap: var(--pickle-space-3);
  align-items: center;
  justify-content: space-between;
  font-family: var(--pickle-font-display);
  font-size: var(--pickle-text-lg);
  font-weight: 600;
}

/* A label made of several pieces, held together as one flex item. */
.ex-h3-label {
  display: inline-flex;
  gap: var(--pickle-space-2);
  align-items: center;
  min-width: 0;
}


/* --------------------------------------------------------------- app cards */

.ex-apps {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 1px;
  background: var(--pickle-line);
  border: 1px solid var(--pickle-line);
  border-radius: var(--pickle-radius);
  /* clip, not hidden: both clip the radius, but `hidden` also makes this a
   * scroll container, and a view() timeline inside it would resolve against a
   * box that never scrolls. shared-ui/motion.css cascades these cells. */
  overflow: clip;
}

.ex-appcard {
  display: block;
  border: 0;
  border-radius: 0;
  padding: var(--pickle-space-5) var(--pickle-space-5) var(--pickle-space-6);
  color: inherit;
  transition: background var(--pickle-fast) var(--pickle-ease);
}

.ex-appcard:hover { color: inherit; background: var(--pickle-surface-3); }

.ex-appcard small {
  display: block;
  margin-bottom: var(--pickle-space-3);
  color: var(--pickle-subtle);
  font-family: var(--pickle-font-mono);
  font-size: .62rem;
  font-weight: 400;
  letter-spacing: var(--pickle-tracking-caps);
  text-transform: uppercase;
}

.ex-appcard h3 {
  display: flex;
  gap: 10px;
  align-items: center;
  font-family: var(--pickle-font-display);
  font-size: var(--pickle-text-lg);
  font-weight: 600;
}

/* Drawn, for the reason given at `a.ex-more::after`. `margin-left: auto` pushes
 * it to the far edge of the flex row, which the glyph got from its own width. */
.ex-appcard h3::after {
  content: "";
  flex: 0 0 auto;
  width: .4em;
  height: .4em;
  margin-left: auto;
  border-top: 1.5px solid var(--pickle-subtle);
  border-right: 1.5px solid var(--pickle-subtle);
  transform: rotate(45deg);
  transition: border-color var(--pickle-fast) var(--pickle-ease), transform var(--pickle-base) var(--pickle-ease);
}

.ex-appcard:hover h3::after {
  border-color: var(--pickle-accent-text);
  transform: translateX(3px) rotate(45deg);
}

.ex-appcard p {
  margin-top: var(--pickle-space-2);
  color: var(--pickle-muted);
  font-size: var(--pickle-text-sm);
  line-height: 1.6;
}

/* Bare icon on a green hairline, replacing the old tinted plates. */
.ex-ico {
  flex: 0 0 auto;
  width: 1.1em;
  height: 1.1em;
  color: var(--pickle-accent-text);
  vertical-align: -.16em;
}

.ex-icoline {
  display: flex;
  align-items: center;
  height: 24px;
  margin-bottom: var(--pickle-space-4);
  padding-left: 10px;
  color: var(--pickle-accent-text);
  border-left: 1px solid rgb(0 231 136 / 45%);
}

/* ----------------------------------------------------------- choice / cards */

.ex-choice {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 1px;
  margin: 0 0 var(--pickle-space-5);
  background: var(--pickle-line);
  border: 1px solid var(--pickle-line);
  border-radius: var(--pickle-radius);
  overflow: clip;
}

.ex-choice a,
.ex-choice button {
  display: block;
  padding: var(--pickle-space-5);
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
  background: var(--pickle-surface-1);
  border: 0;
  transition: background var(--pickle-fast) var(--pickle-ease);
}

.ex-choice a:hover,
.ex-choice button:hover { color: inherit; background: var(--pickle-surface-3); }

.ex-choice small {
  display: block;
  margin-top: var(--pickle-space-2);
  color: var(--pickle-muted);
  font-size: var(--pickle-text-sm);
  line-height: 1.6;
}

.ex-ms-card {
  display: block;
  margin: 0 0 var(--pickle-space-2);
  padding: var(--pickle-space-4) var(--pickle-space-5);
  color: inherit;
  transition: border-color var(--pickle-fast) var(--pickle-ease);
}

.ex-ms-card:hover { color: inherit; border-color: var(--pickle-mint-line); }
.ex-ms-card h3 { margin: 0 0 var(--pickle-space-1); font-size: var(--pickle-text-base); }
.ex-ms-card p { color: var(--pickle-muted); font-size: var(--pickle-text-sm); }

.ex-pending { margin: 0 0 var(--pickle-space-2); padding: var(--pickle-space-4); }

/* ================================================================== metrics */

.ex-stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 11rem), 1fr));
  gap: 1px;
  margin: 0 0 var(--pickle-space-6);
  background: var(--pickle-line);
  border: 1px solid var(--pickle-line);
  border-radius: var(--pickle-radius);
  /* clip, not hidden: both clip the radius, but `hidden` also makes this a
   * scroll container, and a view() timeline inside it would resolve against a
   * box that never scrolls. shared-ui/motion.css cascades these cells. */
  overflow: clip;
}

.ex-stats.stack { grid-template-columns: 1fr; }
/* `.app` is the four-up strip on an app page. It was in the markup long before
 * it was in this file, which is why the faucet and two toolkit pages broke to a
 * 3+1 orphan row between roughly 560px and 767px. */
.ex-stats.dense,
.ex-stats.app { grid-template-columns: repeat(4, minmax(0, 1fr)); }

.ex-stat {
  display: flex;
  flex-direction: column;
  gap: var(--pickle-space-2);
  border: 0;
  border-radius: 0;
  padding: var(--pickle-space-4) var(--pickle-space-5);
}

.ex-stat span {
  color: var(--pickle-subtle);
  font-family: var(--pickle-font-mono);
  font-size: .62rem;
  font-weight: 400;
  letter-spacing: .16em;
  text-transform: uppercase;
}

.ex-stat b {
  display: block;
  color: var(--pickle-text);
  font-family: var(--pickle-font-display);
  font-size: var(--pickle-text-xl);
  font-weight: 600;
  letter-spacing: -.02em;
  line-height: 1.15;
}

.ex-stat b.p { color: var(--pickle-accent-text); }
.ex-stat.sm b { font-size: var(--pickle-text-lg); }

.ex-stat b.mono {
  font-family: var(--pickle-font-mono);
  font-size: var(--pickle-text-sm);
  font-weight: 500;
  overflow-wrap: anywhere;
}

.ex-stat em {
  display: flex;
  gap: var(--pickle-space-2);
  align-items: center;
  color: var(--pickle-muted);
  font-family: var(--pickle-font-mono);
  font-size: var(--pickle-text-2xs);
  font-style: normal;
}

.ex-stat em i {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1rem;
  height: 1rem;
  color: var(--pickle-accent-text);
  font-size: var(--pickle-text-2xs);
  font-style: normal;
  line-height: 1;
  border: 1px solid var(--pickle-mint-line);
  border-radius: var(--pickle-radius);
}

.ex-kpi {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 13rem), 1fr));
  gap: var(--pickle-space-5);
}

.ex-kpi div span {
  color: var(--pickle-subtle);
  font-family: var(--pickle-font-mono);
  font-size: .62rem;
  letter-spacing: .16em;
  text-transform: uppercase;
}

.ex-kpi div b {
  display: block;
  margin-top: var(--pickle-space-1);
  color: var(--pickle-text);
  font-family: var(--pickle-font-display);
  font-size: var(--pickle-text-xl);
  font-weight: 600;
}

.ex-kpi div b.p { color: var(--pickle-accent-text); }

.ex-balances {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 11rem), 1fr));
  gap: 1px;
  margin: var(--pickle-space-4) 0;
  background: var(--pickle-line);
  border: 1px solid var(--pickle-line);
  border-radius: var(--pickle-radius);
  /* clip, never hidden: see .ex-cells. hidden made this a scroll container and
   * the four stat tiles inside it on every address page never arrived. */
  overflow: clip;
}

.ex-bal { background: var(--pickle-surface-1); padding: var(--pickle-space-4) var(--pickle-space-5); }

.ex-bal span {
  color: var(--pickle-subtle);
  font-family: var(--pickle-font-mono);
  font-size: .62rem;
  letter-spacing: .16em;
  text-transform: uppercase;
}

.ex-bal b {
  display: block;
  margin-top: var(--pickle-space-1);
  color: var(--pickle-accent-text);
  font-family: var(--pickle-font-display);
  font-size: var(--pickle-text-lg);
  font-weight: 600;
}

/* Waterfall rows: hairline rows with a flat green fill behind the label. */
.ex-wf { display: flex; flex-direction: column; gap: 10px; }

.ex-wf > div {
  position: relative;
  display: grid;
  grid-template-columns: 1fr auto;
  gap: var(--pickle-space-4);
  align-items: center;
  overflow: hidden;
  padding: var(--pickle-space-4) var(--pickle-space-5);
  border: 1px solid var(--pickle-line);
  border-radius: var(--pickle-radius);
}

.ex-wf .fill {
  position: absolute;
  inset: 0 auto 0 0;
  background: rgb(0 231 136 / 16%);
}

/* Fill widths as classes, not inline styles: the strict style-src CSP forbids
 * style attributes, and an invariant test enforces it. */
.ex-wf .fill.w4 { width: 4%; }
.ex-wf .fill.w8 { width: 8%; }
.ex-wf .fill.w10 { width: 10%; }
.ex-wf .fill.w20 { width: 20%; }
.ex-wf .fill.w24 { width: 24%; }
.ex-wf .fill.w30 { width: 30%; }
.ex-wf .fill.w40 { width: 40%; }
.ex-wf .fill.w60 { width: 60%; }

.ex-wf span { position: relative; }
.ex-wf .pct { font-family: var(--pickle-font-mono); color: var(--pickle-text); }

/* ================================================================== layouts */

.ex-row,
.ex-split,
.ex-charts,
.ex-app-grid {
  display: grid;
  gap: var(--pickle-space-4);
  margin-bottom: var(--pickle-space-5);
}

.ex-row { grid-template-columns: auto auto minmax(0, 1fr); align-items: stretch; }
.ex-split { grid-template-columns: minmax(0, 1fr) minmax(0, 1.3fr); }
.ex-charts { grid-template-columns: minmax(0, 1.3fr) minmax(0, 1fr); }
.ex-app-grid { grid-template-columns: minmax(0, 1fr) minmax(0, 19rem); align-items: start; }

/* ================================================================== controls */

.ex-btn {
  display: inline-flex;
  gap: 10px;
  align-items: center;
  justify-content: center;
  min-height: var(--pickle-tap);
  padding: 0 var(--pickle-space-5);
  color: var(--pickle-text);
  font-family: inherit;
  font-size: var(--pickle-text-base);
  font-weight: 500;
  white-space: nowrap;
  cursor: pointer;
  background: transparent;
  border: 1px solid rgb(255 255 255 / 16%);
  border-radius: var(--pickle-radius);
  transition:
    color var(--pickle-fast) var(--pickle-ease),
    background var(--pickle-fast) var(--pickle-ease),
    border-color var(--pickle-fast) var(--pickle-ease);
}

a.ex-btn { color: var(--pickle-text); }

.ex-btn:hover {
  color: var(--pickle-text);
  background: rgb(0 231 136 / 8%);
  border-color: var(--pickle-mint-line);
}

/* The single primary action: flat brand fill, ink text. No gradient, no glow. */
.ex-btn.solid,
a.ex-btn.solid {
  color: var(--pickle-mint-ink);
  font-weight: 600;
  background: var(--pickle-mint);
  border-color: var(--pickle-mint);
}

.ex-btn.solid:hover,
a.ex-btn.solid:hover {
  color: var(--pickle-mint-ink);
  background: var(--pickle-mint-hi);
  border-color: var(--pickle-mint-hi);
}

/* An icon inside the solid button takes the button's ink, not the accent.
 * `.ex-ico` sets its own colour to the accent green, which is the right answer
 * on every surface in the system except this one: on a mint plate a mint glyph
 * is a hole. The label beside it is already near-black; the icon joins it. */
.ex-btn.solid .ex-ico,
a.ex-btn.solid .ex-ico { color: inherit; }

.ex-btn.ghost { border-color: transparent; color: var(--pickle-muted); }
.ex-btn.ghost:hover { color: var(--pickle-text); background: var(--pickle-surface-hover); }

.ex-btn.danger {
  color: var(--pickle-amber);
  background: var(--pickle-amber-soft);
  border-color: var(--pickle-amber-line);
}

.ex-btn.sm { min-height: 2.25rem; padding: 0 var(--pickle-space-3); font-size: var(--pickle-text-xs); }

.ex-btn.on {
  color: var(--pickle-accent-text);
  border-color: var(--pickle-mint-line);
  background: var(--pickle-mint-soft);
}

.ex-btn.named {
  max-width: 12rem;
  overflow: hidden;
  text-overflow: ellipsis;
  font-family: var(--pickle-font-mono);
  font-size: var(--pickle-text-sm);
  text-transform: none;
}

.ex-btn:disabled,
.ex-btn[aria-disabled="true"] { opacity: .45; }

.ex-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--pickle-space-3);
  margin: 0 0 var(--pickle-space-4);
}

.ex-copy,
.ex-iconbtn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 2rem;
  min-height: 2rem;
  padding: 0 var(--pickle-space-2);
  color: var(--pickle-muted);
  font-family: var(--pickle-font-mono);
  font-size: var(--pickle-text-2xs);
  cursor: pointer;
  background: transparent;
  border: 1px solid var(--pickle-line);
  border-radius: var(--pickle-radius);
}

.ex-copy:hover,
.ex-iconbtn:hover { color: var(--pickle-accent-text); border-color: var(--pickle-mint-line); }

/* ===================================================================== forms */

.ex-form label,
.ex-meta label {
  display: block;
  margin: 0 0 var(--pickle-space-2);
  color: var(--pickle-subtle);
  font-family: var(--pickle-font-mono);
  font-size: .68rem;
  font-weight: 400;
  letter-spacing: .16em;
  text-transform: uppercase;
}

.ex-form p,
.ex-meta { margin: 0 0 var(--pickle-space-4); }

.ex-form input,
.ex-form textarea,
.ex-form select,
.ex-meta input,
.ex-meta textarea {
  width: 100%;
  min-height: 2.875rem;
  padding: var(--pickle-space-3) var(--pickle-space-4);
  color: var(--pickle-text);
  font-family: inherit;
  font-size: var(--pickle-text-md);
  background: var(--pickle-surface-input);
  border: 1px solid var(--pickle-line);
  border-radius: var(--pickle-radius);
  outline: none;
  transition: border-color var(--pickle-fast) var(--pickle-ease);
}

.ex-form input.mono,
.ex-form textarea.mono { font-family: var(--pickle-font-mono); font-size: var(--pickle-text-sm); }

.ex-form textarea,
.ex-meta textarea { min-height: 7rem; resize: vertical; }

.ex-form input:focus,
.ex-form textarea:focus,
.ex-form select:focus,
.ex-meta input:focus,
.ex-meta textarea:focus { border-color: var(--pickle-mint); }

.ex-form input[aria-invalid="true"],
.ex-form textarea[aria-invalid="true"] { border-color: var(--pickle-rose-line); }
.ex-form input[type="file"] { padding: var(--pickle-space-2) var(--pickle-space-3); }

.ex-hint {
  margin: calc(var(--pickle-space-2) * -1) 0 var(--pickle-space-4);
  color: var(--pickle-subtle);
  font-size: var(--pickle-text-xs);
  line-height: 1.7;
}

.ex-hint .mono { color: var(--pickle-muted); overflow-wrap: anywhere; }

.ex-lookup {
  display: flex;
  flex-wrap: wrap;
  gap: var(--pickle-space-3);
  align-items: stretch;
  margin: 0 0 var(--pickle-space-4);
}

.ex-lookup input { flex: 1 1 14rem; margin: 0; }

.ex-preview {
  display: none;
  max-width: 14rem;
  margin: 0 0 var(--pickle-space-4);
  border: 1px solid var(--pickle-line);
  border-radius: var(--pickle-radius);
  object-fit: cover;
}

.ex-preview.on { display: block; }

/* ====================================================================== tabs */

.ex-tabs {
  display: flex;
  gap: var(--pickle-space-2);
  margin: 0 0 var(--pickle-space-4);
  overflow-x: auto;
  border-bottom: 1px solid var(--pickle-line);
  scrollbar-width: none;
}

.ex-tabs::-webkit-scrollbar { height: 0; }

.ex-tabs button {
  flex: 0 0 auto;
  padding: 0 var(--pickle-space-4);
  margin-bottom: -1px;
  color: var(--pickle-muted);
  font: inherit;
  font-size: var(--pickle-text-base);
  font-weight: 500;
  white-space: nowrap;
  cursor: pointer;
  background: none;
  border: 0;
  border-bottom: 1px solid transparent;
}

.ex-tabs button:hover { color: var(--pickle-text); }
.ex-tabs button.on { color: var(--pickle-accent-text); border-bottom-color: var(--pickle-mint); }

.ex-tabpanes > .ex-panel { display: none; }
.ex-tabpanes > .ex-panel.on { display: block; }
.ex-step { display: none; }
.ex-step.on { display: block; }

/* ==================================================================== tables */

.ex-scroll,
.ex-panel:has(> .ex-table) {
  overflow-x: auto;
  overscroll-behavior-x: contain;
}

.ex-table { width: 100%; font-size: var(--pickle-text-sm); }

.ex-table th {
  padding: 0 var(--pickle-space-4) var(--pickle-space-3);
  color: var(--pickle-subtle);
  font-family: var(--pickle-font-mono);
  font-size: .66rem;
  font-weight: 400;
  letter-spacing: .16em;
  text-align: left;
  text-transform: uppercase;
  white-space: nowrap;
  border-bottom: 1px solid var(--pickle-line);
}

.ex-table td {
  padding: var(--pickle-space-4);
  vertical-align: middle;
  border-bottom: 1px solid var(--pickle-line);
}

.ex-table tbody tr:last-child td { border-bottom: 0; }
.ex-table tbody tr { transition: background-color var(--pickle-fast) var(--pickle-ease); }
.ex-table tbody tr:hover { background: var(--pickle-surface-hover); }
.ex-table td.num, .ex-table th.num { text-align: right; }
.ex-table a { color: var(--pickle-text); }
.ex-table a:hover { color: var(--pickle-accent-text); }

/* Definition lists used for block / transaction detail. */
.ex-dl { display: grid; }

.ex-dl p {
  display: grid;
  grid-template-columns: minmax(6.5rem, 9rem) minmax(0, 1fr);
  gap: var(--pickle-space-4);
  align-items: start;
  margin: 0;
  padding: var(--pickle-space-3) 0;
  border-bottom: 1px solid var(--pickle-line);
}

.ex-dl p:last-child { border-bottom: 0; }

.ex-dl span {
  color: var(--pickle-subtle);
  font-family: var(--pickle-font-mono);
  font-size: var(--pickle-text-2xs);
  letter-spacing: .13em;
  text-transform: uppercase;
  padding-top: .2em;
}

.ex-dl b { font-weight: 500; overflow-wrap: anywhere; }

/* The same key/value rhythm as .ex-dl above, on real <dl> markup.
 *
 * .ex-dl is `<p><span>k</span><b>v</b></p>` and puts the hairline on the <p>.
 * A <dl> has no per-row element - dt and dd are separate grid items - so the
 * rule goes on both, and the row gap goes away because the padding now sets the
 * rhythm. Without this the toolkit's lookup was the one place in the product
 * where key/value detail had no rule between its rows. */
.ex-kv {
  display: grid;
  grid-template-columns: minmax(7rem, 9rem) minmax(0, 1fr);
  column-gap: var(--pickle-space-4);
  margin: 0;
}

.ex-kv dt,
.ex-kv dd {
  padding: var(--pickle-space-3) 0;
  border-bottom: 1px solid var(--pickle-line);
}

/* :last-of-type is per element name, so this clears the final row's pair. */
.ex-kv dt:last-of-type,
.ex-kv dd:last-of-type { border-bottom: 0; }

.ex-kv dt {
  color: var(--pickle-subtle);
  font-family: var(--pickle-font-mono);
  font-size: var(--pickle-text-2xs);
  letter-spacing: .13em;
  text-transform: uppercase;
}

.ex-kv dd { margin: 0; overflow-wrap: anywhere; }

/* --------------------------------------------------------------- block lists */

.ex-block-item { padding: var(--pickle-space-4) 0; border-bottom: 1px solid var(--pickle-line); }
.ex-block-item:last-child { border-bottom: 0; }

.ex-block-top {
  display: flex;
  gap: var(--pickle-space-3);
  align-items: baseline;
  justify-content: space-between;
}

.ex-block-top a {
  color: var(--pickle-accent-text);
  font-family: var(--pickle-font-mono);
  font-size: var(--pickle-text-md);
  font-weight: 500;
}

.ex-block-top time {
  color: var(--pickle-subtle);
  font-family: var(--pickle-font-mono);
  font-size: var(--pickle-text-2xs);
  white-space: nowrap;
}

.ex-block-meta { margin: var(--pickle-space-1) 0; color: var(--pickle-muted); font-size: var(--pickle-text-sm); }

.ex-hash {
  color: var(--pickle-subtle);
  font-size: var(--pickle-text-2xs);
  line-height: 1.6;
  overflow-wrap: anywhere;
}

/* ================================================================== feedback */

.ex-empty,
/* An error is a framed state, not a rose sentence floating in the middle of an
 * otherwise empty page. In local preview and whenever an RPC is down, this WAS
 * the whole page on four of the six tools. The frame is the panel every other
 * state uses, with a rose rule on its left edge and a mono label, so it reads as
 * the site saying something rather than as the site having failed. Rose stays on
 * the label and the rule, where it marks; the message itself is read in the
 * muted ink so a paragraph of it is not a paragraph of alarm. */
.ex-err {
  display: grid;
  gap: var(--pickle-space-2);
  margin: var(--pickle-space-5) 0;
  padding: var(--pickle-space-5) var(--pickle-space-5) var(--pickle-space-5) calc(var(--pickle-space-5) + 2px);
  color: var(--pickle-muted);
  font-size: var(--pickle-text-base);
  line-height: 1.6;
  text-align: left;
  background: var(--pickle-surface-1);
  border: 1px solid var(--pickle-line);
  border-left: 2px solid var(--pickle-rose);
  border-radius: var(--pickle-radius);
}

.ex-err::before {
  content: "Error";
  color: var(--pickle-rose);
  font-family: var(--pickle-font-mono);
  font-size: var(--pickle-text-2xs);
  letter-spacing: .16em;
  text-transform: uppercase;
}

.ex-table td.ex-empty { border-bottom: 0; }

.ex-out {
  margin: 0;
  padding: var(--pickle-space-3) var(--pickle-space-4);
  color: var(--pickle-muted);
  font-family: var(--pickle-font-mono);
  font-size: var(--pickle-text-xs);
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  background: var(--pickle-surface-input);
  border: 1px solid var(--pickle-line);
  border-radius: var(--pickle-radius);
}

.ex-out:empty { display: none; }
.ex-out.ok { color: var(--pickle-accent-text); border-color: var(--pickle-mint-line); }
.ex-out.err { color: var(--pickle-rose); border-color: var(--pickle-rose-line); }
.ex-out a { color: var(--pickle-accent-text); text-decoration: underline; text-underline-offset: .2em; }

.ex-out[aria-busy="true"]::before {
  content: "";
  display: inline-block;
  width: .7rem;
  height: .7rem;
  margin-right: var(--pickle-space-2);
  vertical-align: -1px;
  border: 2px solid var(--pickle-line);
  border-top-color: var(--pickle-mint);
  border-radius: 50%;
  animation: pickle-spin .7s linear infinite;
}

@keyframes pickle-spin { to { transform: rotate(1turn); } }

.ex-banner {
  display: flex;
  gap: var(--pickle-space-2);
  align-items: center;
  margin-bottom: var(--pickle-space-4);
  padding: var(--pickle-space-3) var(--pickle-space-4);
  font-size: var(--pickle-text-base);
  font-weight: 500;
  border: 1px solid var(--pickle-line);
  border-radius: var(--pickle-radius);
}

.ex-banner.ok { color: var(--pickle-accent-text); border-color: var(--pickle-mint-line); }
.ex-banner.bad { color: var(--pickle-rose); border-color: var(--pickle-rose-line); }

.ex-status {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.2rem;
  height: 1.2rem;
  font-family: var(--pickle-font-mono);
  font-size: var(--pickle-text-2xs);
  border: 1px solid;
  border-radius: var(--pickle-radius);
}

.ex-status.ok { color: var(--pickle-accent-text); border-color: var(--pickle-mint-line); }
.ex-status.bad { color: var(--pickle-rose); border-color: var(--pickle-rose-line); }

.ex-dot {
  display: inline-block;
  margin-right: var(--pickle-space-2);
  vertical-align: 1px;
  width: 6px;
  height: 6px;
  background: var(--pickle-mint);
  border-radius: 50%;
  animation: pickle-pulse 2.2s infinite;
}

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

.pickle-status-dot {
  display: inline-block;
  width: 6px;
  height: 6px;
  background: currentColor;
  border-radius: 50%;
}

.pickle-runtime { color: var(--pickle-subtle); }

/* Live value change: brief brand flash, colour only, no shadow. */
.flash { animation: pickle-flash .55s var(--pickle-ease); }
@keyframes pickle-flash { 0% { color: var(--pickle-accent-text); } 100% { } }

/* ---- skeletons ---------------------------------------------------------- */

.ex-skel {
  position: relative;
  overflow: hidden;
  border-radius: var(--pickle-radius);
  background: var(--pickle-surface-3);
  color: transparent;
  user-select: none;
}

.ex-skel::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(90deg, transparent, rgb(255 255 255 / 6%), transparent);
  transform: translateX(-100%);
  animation: pickle-shimmer 1.4s infinite;
}

@keyframes pickle-shimmer { to { transform: translateX(100%); } }

/* ---- toasts ------------------------------------------------------------- */

.ex-toasts {
  position: fixed;
  right: var(--pickle-space-4);
  bottom: var(--pickle-space-4);
  z-index: var(--pickle-z-modal);
  display: flex;
  flex-direction: column;
  gap: var(--pickle-space-2);
  width: min(22rem, calc(100vw - 2 * var(--pickle-space-4)));
  pointer-events: none;
}

.ex-toast {
  display: flex;
  gap: var(--pickle-space-2);
  align-items: flex-start;
  padding: var(--pickle-space-3) var(--pickle-space-4);
  color: var(--pickle-text);
  font-size: var(--pickle-text-sm);
  background: var(--pickle-surface-3);
  border: 1px solid var(--pickle-line);
  border-left: 2px solid var(--pickle-mint);
  border-radius: var(--pickle-radius);
  animation: pickle-toast-in .3s var(--pickle-ease);
  pointer-events: auto;
}

.ex-toast.err { border-left-color: var(--pickle-rose); }
.ex-toast.out { animation: pickle-toast-out .25s var(--pickle-ease) forwards; }

@keyframes pickle-toast-in { from { opacity: 0; transform: translateY(8px); } }
@keyframes pickle-toast-out { to { opacity: 0; transform: translateX(12px); } }

/* ---- realtime stream ----------------------------------------------------- */

.ex-stream .line { display: block; animation: pickle-line-in .28s var(--pickle-ease); }
.ex-stream .line.note { color: var(--pickle-subtle); }
.ex-stream .line.err { color: var(--pickle-rose); }
@keyframes pickle-line-in { from { opacity: 0; } }

/* ================================================== pills, badges, identity */

.ex-pill {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  height: 26px;
  padding: 0 11px;
  color: var(--pickle-muted);
  font-family: var(--pickle-font-mono);
  font-size: var(--pickle-text-2xs);
  font-weight: 400;
  letter-spacing: .13em;
  text-transform: uppercase;
  white-space: nowrap;
  background: transparent;
  border: 1px solid var(--pickle-line);
  border-radius: var(--pickle-radius);
}

.ex-pill.m, .ex-pill.mint { color: var(--pickle-accent-text); border-color: var(--pickle-mint-line); }
.ex-pill.warn { color: var(--pickle-amber); border-color: var(--pickle-amber-line); }
.ex-pill.contract, .ex-pill.token, .ex-pill.eoa { color: var(--pickle-muted); }

.ex-pill .ex-dot, .ex-pill i.dot {
  display: inline-block;
  margin: 0;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: currentColor;
  animation: pickle-pulse 2.2s infinite;
}

/* Badges collapse to the editorial trio: neutral mono, green for verified
 * things, amber for treasury / caution. The rainbow is retired. */
.ex-badge {
  display: inline-flex;
  flex: 0 0 auto;
  align-items: center;
  height: 22px;
  padding: 0 8px;
  color: var(--pickle-muted);
  font-family: var(--pickle-font-mono);
  font-size: .6rem;
  font-weight: 400;
  letter-spacing: .12em;
  text-transform: uppercase;
  white-space: nowrap;
  background: transparent;
  border: 1px solid var(--pickle-line);
  border-radius: var(--pickle-radius);
}

/* A badge that IS the link to its address, which is how a tagged from/to is
   rendered: the tag replaces the hex rather than sitting beside it. It must not
   take the global link colour, or the per-tag colours below stop meaning
   anything - so colour is inherited, and the affordance is the border and the
   underline on hover. */
.ex-badge-link {
  color: inherit;
  text-decoration: none;
  cursor: pointer;
}

.ex-badge-link:hover,
.ex-badge-link:focus-visible {
  border-color: currentColor;
  text-decoration: underline;
}

.ex-badge.verified,
.ex-badge.pns,
.ex-badge.stake,
.ex-badge.pickle,
.ex-badge.faucet,
.ex-badge.bridge,
.ex-badge.registry { color: var(--pickle-accent-text); border-color: var(--pickle-mint-line); }

/* Amber is the palette's "not quite yes": risk, in development, reserved.
 * .warn joins .treasury here rather than introducing a second amber. */
.ex-badge.treasury,
.ex-badge.warn { color: var(--pickle-amber); border-color: var(--pickle-amber-line); }

.ex-badge.contract,
.ex-badge.token,
.ex-badge.nft,
.ex-badge.toolkit,
.ex-badge.deployer,
.ex-badge.operator,
.ex-badge.tagged,
.ex-badge.named { color: var(--pickle-muted); border-color: var(--pickle-line); }

/* Deterministic address avatar: one green, opacity does the variation. */
.ex-ident {
  display: grid;
  flex: 0 0 auto;
  grid-template-columns: repeat(5, 1fr);
  gap: 1px;
  width: 2.5rem;
  height: 2.5rem;
  overflow: hidden;
  background: var(--pickle-bg-deep);
  border: 1px solid var(--pickle-line);
  border-radius: var(--pickle-radius);
}

.ex-ident i { display: block; background: var(--pickle-mint); }
.ex-ident.contract i, .ex-ident.token i, .ex-ident.nft i { background: var(--pickle-mint); }

.ex-ident i.o1 { opacity: .1; }
.ex-ident i.o2 { opacity: .2; }
.ex-ident i.o3 { opacity: .3; }
.ex-ident i.o4 { opacity: .4; }
.ex-ident i.o5 { opacity: .5; }
.ex-ident i.o6 { opacity: .6; }
.ex-ident i.o7 { opacity: .7; }
.ex-ident i.o8 { opacity: .8; }
.ex-ident i.o9 { opacity: .9; }
.ex-ident i.o10 { opacity: 1; }

.ex-flow {
  display: flex;
  flex-wrap: wrap;
  gap: var(--pickle-space-3);
  align-items: center;
  margin: 0 0 var(--pickle-space-4);
}

.ex-flow a { color: inherit; }

/* ================================================================= mono blob */

.ex-code {
  margin: var(--pickle-space-4) 0 0;
  padding: var(--pickle-space-4);
  max-height: 16rem;
  overflow: auto;
  color: var(--pickle-muted);
  font-size: var(--pickle-text-xs);
  line-height: 1.85;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  background: var(--pickle-surface-input);
  border: 1px solid var(--pickle-line);
  border-radius: var(--pickle-radius);
}

.ex-stream {
  height: min(62vh, 38rem);
  margin: 0;
  padding: var(--pickle-space-4);
  overflow: auto;
  color: var(--pickle-mint-hi);
  font: 400 var(--pickle-text-xs)/1.7 var(--pickle-font-mono);
  background: var(--pickle-surface-input);
  border: 1px solid var(--pickle-line);
  border-radius: var(--pickle-radius);
}

/* ============================================================ small figures
 * Two drawn elements in the main page's own grammar, so a tool page can carry
 * an instrument without inventing one. Both are structure; their motion is in
 * motion.css.
 */

/* The dotted feed: a line between two named ends, with the fold's dash pattern.
 * `2 6` at stroke 2, round caps, mint at 34%. The ends are HTML, never SVG
 * <text>, so they hold a real font size at every width. */
.ex-feed-fig {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  gap: var(--pickle-space-4);
  align-items: center;
  margin: var(--pickle-space-5) 0 var(--pickle-space-4);
}

.ex-feed-svg { display: block; width: 100%; height: 40px; overflow: visible; }

.ex-feed {
  fill: none;
  stroke: rgb(0 231 136 / 34%);
  stroke-width: 2;
  stroke-dasharray: 2 6;
  stroke-linecap: round;
}

.ex-feed-end {
  color: var(--pickle-subtle);
  font-family: var(--pickle-font-mono);
  font-size: var(--pickle-text-2xs);
  letter-spacing: .16em;
  text-transform: uppercase;
  white-space: nowrap;
}

.ex-feed-end b { color: var(--pickle-text); font-weight: 500; letter-spacing: 0; }

/* The gauge: a 10px bar on a 6% white track, mint fill, with a hairline legend
 * of mono caps above it. The fill's width is a custom property a script sets
 * through the CSSOM (`style.setProperty("--fill", ...)`), which the strict CSP
 * permits - only inline style attributes in markup are banned, and shell.js
 * paints the cadence lanes the same way. `.wait` turns the fill amber: the
 * palette's one word for "not yet". */
.ex-gauge-row {
  display: grid;
  gap: 8px;
  margin: var(--pickle-space-4) 0 var(--pickle-space-5);
}

.ex-gauge-legend {
  display: flex;
  gap: var(--pickle-space-4);
  align-items: baseline;
  justify-content: space-between;
  color: var(--pickle-subtle);
  font-family: var(--pickle-font-mono);
  font-size: var(--pickle-text-2xs);
  letter-spacing: .16em;
  text-transform: uppercase;
}

.ex-gauge-legend b {
  color: var(--pickle-text);
  font-size: var(--pickle-text-xs);
  font-weight: 500;
  letter-spacing: 0;
  text-transform: none;
}

.ex-gauge-row.ready .ex-gauge-legend b { color: var(--pickle-accent-text); }
.ex-gauge-row.wait .ex-gauge-legend b { color: var(--pickle-amber); }

.ex-gauge {
  height: 10px;
  overflow: clip;
  background: rgb(255 255 255 / 6%);
  border-radius: var(--pickle-radius);
}

.ex-gauge > i {
  display: block;
  width: var(--fill, 0%);
  height: 100%;
  background: var(--pickle-mint);
  border-radius: var(--pickle-radius);
}

.ex-gauge-row.wait .ex-gauge > i { background: var(--pickle-amber); }

/* =================================================================== marquee */

.ex-marquee {
  position: relative;
  overflow: hidden;
  padding: var(--pickle-space-4) 0;
  border-block: 1px solid var(--pickle-line);
  mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
}

.ex-marquee > div {
  display: flex;
  width: max-content;
  gap: 44px;
  animation: pickle-marquee 34s linear infinite;
}

.ex-marquee span {
  display: inline-flex;
  align-items: center;
  gap: 44px;
  color: var(--pickle-muted);
  font-family: var(--pickle-font-mono);
  font-size: var(--pickle-text-xs);
  letter-spacing: .2em;
  text-transform: uppercase;
  white-space: nowrap;
}

.ex-marquee span::after {
  content: "";
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: rgb(0 231 136 / 55%);
}

@keyframes pickle-marquee { from { transform: translateX(0); } to { transform: translateX(-50%); } }

@media (prefers-reduced-motion: reduce) {
  .ex-marquee > div { animation: none; }
}

/* ==================================================================== wallet */

.ex-wmodal {
  position: fixed;
  inset: 0;
  z-index: var(--pickle-z-modal);
  display: grid;
  place-items: center;
  padding: var(--pickle-space-4);
  background: rgb(20 22 21 / 85%);
  backdrop-filter: blur(12px);
}

.ex-wmodal[hidden] { display: none; }

.ex-wmodal-card {
  width: min(23rem, 100%);
  padding: var(--pickle-space-5) var(--pickle-space-5) var(--pickle-space-6);
  background: var(--pickle-surface-1);
  border: 1px solid var(--pickle-line);
  border-radius: var(--pickle-radius);
}

.ex-wmodal-head {
  display: flex;
  gap: var(--pickle-space-3);
  align-items: center;
  justify-content: space-between;
  margin-bottom: var(--pickle-space-2);
}

.ex-wmodal-head h2 { margin: 0; font-size: var(--pickle-text-lg); }

/* Why a wallet row failed. Errors from the picker used to be discarded when
   the modal was opened without a pending promise, so a rejected network prompt
   left the click doing nothing at all. */
.ex-werr {
  margin: 0;
  color: var(--pickle-rose);
  border-left: 2px solid var(--pickle-rose-line);
  padding-left: var(--pickle-space-3);
}

.ex-werr[hidden] { display: none; }

.ex-wlist { display: grid; gap: 1px; margin-top: var(--pickle-space-4); background: var(--pickle-line); border: 1px solid var(--pickle-line); border-radius: var(--pickle-radius); overflow: clip; }

.ex-wrow {
  display: flex;
  gap: var(--pickle-space-3);
  align-items: center;
  width: 100%;
  min-height: 3rem;
  padding: var(--pickle-space-2) var(--pickle-space-3);
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
  background: var(--pickle-surface-1);
  border: 0;
  transition: background var(--pickle-fast) var(--pickle-ease);
}

.ex-wrow:hover, .ex-wrow:focus-visible { background: var(--pickle-surface-3); }

.ex-wrow img, .ex-wicon { width: 28px; height: 28px; border-radius: var(--pickle-radius); }

.ex-wicon {
  display: grid;
  place-items: center;
  font-family: var(--pickle-font-mono);
  font-weight: 500;
  background: var(--pickle-surface-4);
}

.ex-wmenu {
  position: absolute;
  top: calc(100% - var(--pickle-space-2));
  right: 0;
  z-index: var(--pickle-z-menu);
  min-width: 15rem;
  padding: var(--pickle-space-1);
  background: var(--pickle-surface-3);
  border: 1px solid var(--pickle-line);
  border-radius: var(--pickle-radius);
}

.ex-wmenu[hidden] { display: none; }

/* The address is what this panel is FOR, so it is set in the page's ink rather
   than in the muted register the rest of a menu's furniture uses, and one tap
   or click selects the whole of it: a clipboard the browser refuses is a real
   answer (no secure context, no permission) and selecting it by hand is then
   the only way out. */
.ex-wmenu-addr {
  margin: var(--pickle-space-2);
  color: var(--pickle-text);
  font-family: var(--pickle-font-mono);
  font-size: var(--pickle-text-2xs);
  line-height: 1.45;
  overflow-wrap: anywhere;
  -webkit-user-select: all;
  user-select: all;
}

/* A column rather than a block, and with vertical padding, because one of these
   items carries a second line under its label. min-height stays the tap floor
   the smoke test measures and justify-content keeps a one-line item centred in
   it. align-items: stretch is not decoration: a <button> centres its content by
   default whatever display it is given, and measuring this rule without it
   showed every label sliding to the middle the moment one item had two lines. */
.ex-wmenu button {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: stretch;
  gap: 2px;
  width: 100%;
  min-height: 2.5rem;
  padding: var(--pickle-space-2) var(--pickle-space-3);
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
  background: transparent;
  border: 0;
  border-radius: var(--pickle-radius);
}

/* What "Switch wallet" will actually do, on the control itself rather than in a
   tooltip nobody on a touch screen will ever see: the account has no
   change-account call, so the press ends this session and opens sign-in again. */
.ex-wmenu-note {
  color: var(--pickle-subtle);
  font-family: var(--pickle-font-mono);
  font-size: var(--pickle-text-2xs);
  line-height: 1.35;
}

/* The one item that ends something, set apart by a hairline rather than by a
   colour: on this estate rose means an error, and signing out on purpose is
   not one. */
.ex-wmenu button.ex-wmenu-cut {
  margin-top: var(--pickle-space-1);
  border-top: 1px solid var(--pickle-line);
}

.ex-wmenu button:hover, .ex-wmenu button:focus-visible { background: var(--pickle-surface-hover); }

/* ==================================================================== footer */

.ex-footer {
  margin-top: var(--pickle-space-8);
  padding-top: var(--pickle-space-5);
  color: var(--pickle-subtle);
  font-family: var(--pickle-font-mono);
  font-size: var(--pickle-text-2xs);
  letter-spacing: .06em;
  border-top: 1px solid var(--pickle-line);
}

.ex-footer a { color: var(--pickle-muted); }
.ex-footer a:hover { color: var(--pickle-accent-text); }
.ex-footer .mono { color: var(--pickle-muted); }

/* The long-form status / disclaimer block used on the home footer. */
.ex-disc {
  max-width: 900px;
  margin-top: var(--pickle-space-5);
  color: var(--pickle-subtle);
  font-family: var(--pickle-font);
  font-size: .72rem;
  letter-spacing: 0;
  line-height: 1.7;
}

.ex-disc strong { color: var(--pickle-muted); font-weight: 500; }

/* ================================================================ utilities */

.mono { font-family: var(--pickle-font-mono); }
.num { font-variant-numeric: tabular-nums; }
.ex-xs { font-size: var(--pickle-text-xs); }
.ex-break { overflow-wrap: anywhere; }
.ex-center { text-align: center; }
.ex-stack-top { margin-top: var(--pickle-space-4); }
.ex-stack-top-lg { margin-top: var(--pickle-space-6); }

/* Long lists: skip layout and paint for rows far off-screen. */
.ex-block-item,
.ex-nft-card {
  content-visibility: auto;
  contain-intrinsic-size: auto 6rem;
}

/* =============================================================== responsive */

@media (max-width: 1219px) {
  .ex-nav .ex-links,
  .ex-nav .ex-navghost { display: none; }
  .ex-nav .ex-burger { display: grid; }
}

@media (max-width: 1023px) {
  .ex-problems, .ex-thesis, .ex-caveat .cols { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .ex-split,
  .ex-charts,
  .ex-app-grid,
  .ex-row { grid-template-columns: minmax(0, 1fr); }
  .ex-stats.dense,
  .ex-stats.app { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .ex-hero { grid-template-columns: minmax(0, 1fr); gap: var(--pickle-space-6); }
  .ex-mark { display: none; }
  .ex-cells.c4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .ex-apps { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 820px) {
  .ex-strip { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .ex-strip > div:nth-child(2n + 1) { border-left: 0; }
  .ex-strip > div:nth-child(n + 3) { border-top: 1px solid var(--pickle-line); }
}

@media (max-width: 767px) {
  :root { --pickle-section: 80px; --pickle-section-sm: 64px; --pickle-hero-top: 72px; --pickle-hero-bottom: 56px; --pickle-sechead-gap: 36px; }
  .ex-problems, .ex-thesis, .ex-caveat .cols { grid-template-columns: minmax(0, 1fr); }
  .ex-roadmap > div { grid-template-columns: minmax(0, 1fr); gap: 16px; }
  .ex-thesis > div { padding: 32px 24px; }
  .ex-cta { padding: 56px 24px; }
  .ex-dl p { grid-template-columns: minmax(0, 1fr); gap: var(--pickle-space-1); }
  /* One column: the label sits directly above its value, so the hairline
   * belongs under the pair rather than between the two halves of it. */
  .ex-kv { grid-template-columns: minmax(0, 1fr); }
  .ex-kv dt { padding-bottom: 0; border-bottom: 0; }
  .ex-actions > .ex-btn { flex: 1 1 9rem; }
  .ex-table { min-width: 36rem; }
  .ex-table:has(.ex-empty) { min-width: 0; }
  .ex-cells.c2, .ex-cells.c3 { grid-template-columns: minmax(0, 1fr); }
  .ex-choice { grid-template-columns: minmax(0, 1fr); }
}

@media (max-width: 660px) {
  /* THE ACCOUNT MENU HANGS OFF THE RIGHT OF .ex-wallet, so the room it has is
     the distance from the left edge of the screen to that box's right edge, and
     that box is not always the last thing in the bar. Measured on the arcade at
     375, where a mute switch and a burger follow it: the box's right edge is at
     241px and a 15rem panel put its own left edge at 1px, one pixel from
     falling off the phone. 13rem leaves a real gutter there and changes nothing
     above 660px; the address simply wraps onto one more line, which it is
     already written to do. */
  .ex-wmenu { min-width: 13rem; }

  .ex-strip { grid-template-columns: minmax(0, 1fr); }
  .ex-strip > div { border-left: 0 !important; }
  .ex-strip > div + div { border-top: 1px solid var(--pickle-line); }
  .ex-cells.c4, .ex-apps { grid-template-columns: minmax(0, 1fr); }
}

@media (max-width: 420px) {
  .ex-brand span { display: none; }
  .ex-wallet .ex-btn { max-width: 10.5rem; overflow: hidden; text-overflow: ellipsis; }
}
