/* ──────────────────────────────────────────────────────────────────
   Monero Dog ($MOG) landing.

   Structural DNA is the no-utility-token repo's: a fixed viewport shell
   that never scrolls, brand lockup and live price welded to the top
   corners, a hero that scrolls internally, hairline card grids, a
   staggered rise-on-load cascade, reveal-on-scroll bands below the fold.

   Everything about the palette and the personality is inverted. That
   site is warm cream, soft, deadpan-institutional. This one is black,
   high contrast, glowing Monero orange, chrome, and cocky.

   THE ORGANISING IDEA: BACKLIT.
   Both source images are lit the same way. One orange source sits behind
   the subject and everything in front of it is a silhouette with a
   burning rim. The fur is not orange, the EDGE of the fur is orange. The
   mountains are not orange, their lit flank is. Three rules follow, and
   every component below obeys them:

     1. Light is directional. Borders are never uniform: bright top
        hairline, dim bottom. A 1px solid orange box on all four sides is
        the signature of a generic dark theme and it is banned here.
     2. Glow is an edge, not a blur. Light lives in 1px rims plus one
        large ambient disc. Only fixed layers bloom.
     3. Chrome is scarce. Exactly three consumers: the wordmark, the hero
        accent line, the stat counters. Chrome everywhere is a logo.
        Chrome in three places is a brand.

   Signature shape is the lens chamfer, off the pit vipers: three
   "hardware" objects (market grid, terminal, primary CTA) get an angled
   cut on two opposite corners. Everything else is 2px or square.

   NO EM DASHES anywhere on this site, including in CSS content: values
   and including in these comments. Middots or slashes. Note that the
   ─── rules in these comment headers are U+2500 box drawing, which is a
   different character and is fine. Do not let a find and replace eat them.
   ────────────────────────────────────────────────────────────────── */

:root {
  color-scheme: dark;

  /* ── GROUND ──────────────────────────────────────────────────────
     Four blacks, not one. The page reads as a single black field but
     objects on it separate by a few points of luminance, which is how
     the art works: the dog is not outlined, he is a slightly different
     black.

     NOTE: assets-src/build-assets.py parses --ground out of this file to
     floor the mascot's JPEG blacks to the same value. If you change it,
     re-run `pnpm assets` or the hero image will show as a faintly grey
     square against the page. */
  --ground:      #000000;
  --ground-2:    #0A0503;  /* warm black: foot wash, disclaimer, scroll shade */
  --surface:     #190904;  /* warm card fill: market cells, cases, quarters */
  --surface-2:   #241008;  /* hover / open state of any --surface object */
  --surface-3:   #1F0C05;  /* terminal body, deliberately between the two */

  /* ── ORANGE ──────────────────────────────────────────────────────
     Three oranges, three jobs. Do not swap them.

     --o is the brand and it measures 7.15:1 on --ground, so unlike almost
     every brand colour it may be set as real body text. Use it that way,
     it is the whole point of this palette.

     On --surface (#190904) --o drops to 6.61:1. Still AA for body text
     but no longer AAA, so inside a card prefer --o-art (7.14:1). */
  --o:           #FF6600;  /* official Monero orange. TEXT OK on --ground. */
  --o-art:       #FD7501;  /* the sun disc in the art. TEXT OK anywhere.   */
  --o-lift:      #FF8A1F;  /* rim light. Text, focus rings, hover.         */
  --o-hot:       #FFA24D;  /* 10.53:1 chrome gradient's warm base.         */
  --o-ember:     #FFB870;  /* one-shot flash peak only. Never at rest.     */
  /* FILL AND GLOW ONLY below this line. --o-mid is 5.50:1 and legal for
     body text, but it is reserved for gradient ends so the scale stays
     readable. --o-burnt is 4.00:1: LARGE TEXT ONLY. --o-char is 2.47:1
     and is DECORATION ONLY, never a word. */
  --o-mid:       #E15509;
  --o-burnt:     #B74A16;
  --o-char:      #7C3A10;

  /* ── CHROME ──────────────────────────────────────────────────────
     The wordmark metal, sampled off the banner. Six stops, because a
     mirror has a horizon and a smooth two-stop silver reads as plastic.

     The scale bottoms out at --chrome-3 (9.41:1) on purpose. Anything
     darker fails as soon as the hero backlight lifts the ground behind it,
     and the wordmark is the one thing on the page that cannot afford it. */
  --chrome-hi:   #F5EFEA;  /* 18.42:1  top specular edge            */
  --chrome:      #E8DED7;  /* 15.86:1  safe flat chrome, the fallback */
  --chrome-2:    #DCD0C8;  /* 13.90:1  midtone, secondary chrome text */
  --chrome-3:    #B9ABA2;  /*  9.41:1  below the mirror horizon      */

  /* ── WARM NEUTRALS ───────────────────────────────────────────────
     Body copy and labels. The page never uses pure white, which would be
     colder than any pixel in the source art.

     --label is the QUIETEST TEXT TONE ON THE PAGE and that is a hard
     floor, not a preference. It is coupled to the canvas tableau: the
     tableau's alpha ceiling of 0.26 was derived from this exact value.
     A dimmer label tone (the first draft used #9A8778) forces the ceiling
     down to 0.205 and the background mark stops reading. See the README,
     "Contrast is measured against the tableau". */
  --bone:        #D5B49A;  /* 10.82:1  body copy, ledes, answers      */
  --bone-2:      #C9B4A4;  /* 10.55:1  secondary body, terminal out   */
  --label:       #A89485;  /*  7.24:1  every uppercase micro-label    */
  /* --ash is the Monero chevron grey, 2.45:1. DECORATION ONLY: dots,
     dividers, the idle status dot, terminal window lamps. Never a word. */
  --ash:         #4C4C4C;

  /* ── HAIRLINES ───────────────────────────────────────────────────
     Directional by design. --line-lit is the TOP edge of a framed object
     (the light is behind it), --line the sides, --line-dim the bottom.
     Never put one value on all four sides. That is the generic look. */
  --line-lit:    rgba(255, 102, 0, 0.42);
  --line:        rgba(255, 102, 0, 0.17);
  --line-dim:    rgba(255, 102, 0, 0.07);
  --line-cold:   rgba(232, 222, 215, 0.10);  /* chrome hairline: FAQ, foot */
  --line-solid:  #331408;  /* 1.24:1 opaque divider, for gap-as-border grids */

  /* ── STATE ───────────────────────────────────────────────────────
     Orange is the brand and therefore carries NO state information.
     Live is green, stale is amber, down is red, so the ticker still
     means something on a page that is orange edge to edge. */
  --up:          #35C06B;  /* 8.90:1  */
  --up-soft:     #6FE39B;  /* 13.14:1 flash peak for an upward move */
  --down:        #FF4D3D;  /* 6.38:1  */
  --prelaunch:   #DCD0C8;  /* chrome: not live yet, nothing is wrong */

  /* ── GLOW ────────────────────────────────────────────────────────
     Composed shadows, not colours. Keep every blur radius here small.
     A large-radius shadow on a child of the internally scrolling hero
     repaints its full blur on every frame; if you ever need one, it is
     legal on FIXED layers only. */
  --rim-top:     inset 0 1px 0 0 rgba(255, 138, 31, 0.34);
  --rim-bottom:  inset 0 -1px 0 0 rgba(255, 102, 0, 0.06);
  --glow-sm:     0 2px 10px -4px rgba(255, 102, 0, 0.40);
  --glow-md:     0 10px 30px -14px rgba(253, 117, 1, 0.55);
  --bloom-text:  0 0 26px rgba(255, 138, 31, 0.30);

  /* ── GEOMETRY ────────────────────────────────────────────────────
     The pit-viper cut. A chamfer larger than about 6% of the box width
     starts eating the corner content, hence the step down on phones. */
  --chamfer:     18px;
  --cut: polygon(
    0 0,
    calc(100% - var(--chamfer)) 0,
    100% var(--chamfer),
    100% 100%,
    var(--chamfer) 100%,
    0 calc(100% - var(--chamfer))
  );
  --r-sharp:     2px;

  /* ── MOTION ──────────────────────────────────────────────────────
     Harder and faster than the reference's 0.16/1/0.3/1. Fast out, hard
     stop, no overshoot. MOG arrives, it does not settle in. */
  --ease:        cubic-bezier(0.2, 0.9, 0.24, 1);
  --ease-out:    cubic-bezier(0.33, 1, 0.68, 1);
  --t-fast:      160ms;
  --t-base:      280ms;
  --t-slow:      620ms;
}

*, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; }
html, body { height: 100%; }

/* The hidden attribute must beat any component's own display rule. Without
   this, `hidden` on .ca-copy is silently defeated by the button's display
   and the pre-launch copy button stays on screen. Do not remove. */
[hidden] { display: none !important; }

body {
  font-family: 'Archivo', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  background: var(--ground);
  color: var(--bone);
  /* On a dark ground these THIN the strokes, which counteracts the optical
     thickening of light-on-dark text. Same declaration as the cream
     reference, opposite reason. */
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow-x: hidden;
}

::selection { background: var(--o); color: #000; }  /* 7.15:1 both ways */

.page {
  position: fixed;
  inset: 0;
  width: 100vw;
  /* Small-viewport-height units, never dvh. dvh changes value continuously
     as a mobile URL bar collapses, which relayouts this flex column on
     every scroll frame and makes the inner scroller jump. svh is stable. */
  height: 100vh;
  height: 100svh;
  display: flex;
  flex-direction: column;
  background: var(--ground);
  /* The page itself never scrolls. That lets the brand and ticker (absolute,
     top corners) and the foot (flex-pinned) stay welded to the viewport
     while the hero takes the middle slot and scrolls internally. */
  overflow: hidden;
}

/* Top scroll shade, inverted to black and taller than the reference's,
   because the chrome passing under it is heavier. */
.page::before {
  content: '';
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 104px;
  z-index: 7;
  pointer-events: none;
  background: linear-gradient(to bottom,
    #000 0%, rgba(0,0,0,0.96) 38%, rgba(0,0,0,0.62) 70%, rgba(0,0,0,0) 100%);
}

/* Ambient washes: an orange floor bounce and a faint top-left spill. Both
   live on a fixed layer so their large gradients paint once. */
.page::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
  background:
    radial-gradient(ellipse 80% 42% at 50% 104%,
      rgba(255,102,0,0.20) 0%, rgba(225,85,9,0.07) 42%, rgba(0,0,0,0) 72%),
    radial-gradient(ellipse 60% 50% at 8% 4%,
      rgba(255,102,0,0.06) 0%, rgba(0,0,0,0) 70%);
}

/* ─── Chrome text ───
   Applied to exactly three things: .brand-name, .hero-title .accent,
   .stat-num. See the legibility contract below before adding a fourth. */
.chrome {
  /* 1. Opaque fallback FIRST. If background-clip:text is unsupported,
        blocked, printed, or in forced colours, this is what ships. */
  color: var(--chrome);

  /* 2. Two stacked layers: a barely-there vertical brush texture on top,
        then the mirror gradient. The brush must be first or the gradient
        washes it out. */
  background-image:
    repeating-linear-gradient(
      90deg,
      rgba(255,255,255,0.000) 0px,
      rgba(255,255,255,0.000) 1px,
      rgba(255,255,255,0.050) 1px,
      rgba(255,255,255,0.050) 2px,
      rgba(0,0,0,0.055)       2px,
      rgba(0,0,0,0.055)       3px
    ),
    linear-gradient(
      180deg,
      var(--chrome-hi)    0%,    /* specular top edge          */
      var(--chrome)      30%,    /* upper face, still bright   */
      var(--chrome-hi)   55%,    /* carries the glyph's mass   */
      #FDFAF7            60%,    /* the hot line above the horizon */
      var(--chrome-3)    62%,    /* THE HORIZON. 2% wide, near hard. 9.41:1 */
      var(--chrome-2)    74%,    /* reflected ground           */
      var(--chrome)      90%,    /* bounce back up             */
      #EDBE86            97%,    /* warm kick: orange clouds bouncing up */
      var(--o-hot)      100%     /* the base catches the light */
    );
  background-size: 3px 100%, 100% 100%;
  background-repeat: repeat, no-repeat;

  -webkit-background-clip: text;
          background-clip: text;
  -webkit-text-fill-color: transparent;

  /* 3. The glyph is now transparent and has no edge against black. A 1px
        warm dark drop gives it a lip; the soft bloom is light leaking
        around the metal the way it does in the banner. */
  /* Bloom only. An earlier draft also carried a 1px black drop, which is
     pointless against a black ground and, with the fill transparent, only
     muddied the antialiased edges. */
  text-shadow: 0 0 30px rgba(255,102,0,0.26);
}

/* THE LOAD-BEARING DETAIL is the 2%-wide stop at 60% to 62%: the mirror
   horizon. A smooth silver ramp looks like grey plastic. A near-hard value
   inversion is what the eye reads as reflective metal. Do not smooth it.

   IT SITS AT 62%, NOT AT 50%, AND THAT POSITION IS LOAD-BEARING TOO. The
   gradient is sized to the element's BOX, but these glyphs are set at a
   line-height below 1, so they overflow that box and their visual mass lands
   around the middle of the ramp. A horizon at 50% therefore drew the darkest
   band straight across the bulk of every letter and the accent line rendered
   as near-black lettering. Pushing it to 62% keeps the mass in the bright
   upper region and leaves the dark band under the baseline where it reads as
   a reflection. Verified by screenshotting the element and sampling rows.

   THE WARM KICK at 97% to 100% is not decoration either. Without it the
   chrome is a floating silver logo that could belong to any brand. With it,
   the metal is standing in the same orange room as the dog.

   LEGIBILITY CONTRACT: the darkest stop is --chrome-3 at 9.41:1, so the
   wordmark stays readable even where the backlight lifts the ground behind
   it. An earlier draft ran the horizon down to 3.56:1 and the accent line
   rendered as near-black lettering: the punchline was the least legible
   thing on the page. Do not darken these stops again. Never apply .chrome to
   .market-value, .ticker-price or any label. */

@supports not ((-webkit-background-clip: text) or (background-clip: text)) {
  .chrome {
    background-image: none;
    -webkit-text-fill-color: var(--chrome);
    color: var(--chrome);
  }
}
@media (forced-colors: active) {
  /* Windows High Contrast suppresses background images, and a transparent
     text fill over a suppressed background renders LITERALLY INVISIBLE.
     This is the single most common way a gradient wordmark disappears for
     a real user. Do not delete this block. */
  .chrome {
    background-image: none;
    -webkit-text-fill-color: revert;
    color: CanvasText;
    text-shadow: none;
  }
}
@media print {
  .chrome {
    background-image: none;
    -webkit-text-fill-color: #000;
    color: #000;
    text-shadow: none;
  }
}

/* ─── Changeover banner ───
   TEMPORARY. Delete this block, the .banner markup in index.html, and the
   banner IIFE in scripts.js together when it has served its purpose.

   It is chrome-on-warm-black rather than orange-on-black on purpose: an orange
   bar directly above an orange-accented page reads as part of the design and
   gets skipped. This is meant to be read once and then dismissed, so it sits
   slightly apart from the palette without shouting. */
.banner {
  position: fixed;
  top: 0; left: 0; right: 0;
  z-index: 30;
  display: flex;
  align-items: center;
  gap: 18px;
  padding: 13px 22px;
  padding-left: max(22px, env(safe-area-inset-left));
  background: #1C0E06;
  border-bottom: 1px solid var(--line-lit);
  box-shadow: 0 8px 26px -14px rgba(0,0,0,0.9);
}
.banner-text {
  flex: 1 1 auto;
  margin: 0 auto;
  max-width: 1080px;
  text-align: center;
  font-size: 13.5px;
  font-variation-settings: 'wdth' 96;
  line-height: 1.5;
  color: var(--bone);
}
.banner-text strong { color: var(--o); font-weight: 700; }
.banner-close {
  flex: 0 0 auto;
  width: 30px; height: 30px;
  display: grid; place-items: center;
  background: transparent;
  border: 1px solid var(--line);
  border-radius: var(--r-sharp);
  color: var(--label);
  font-size: 18px;
  line-height: 1;
  cursor: pointer;
  transition: color var(--t-fast) ease, border-color var(--t-fast) ease;
}
.banner-close:hover { color: var(--o); border-color: var(--line-lit); }

/* The banner is fixed, so everything else welded to the viewport top has to
   clear it. .page is the fixed shell; pushing its top down and shortening it
   keeps the internal scroller and the flex-pinned foot correct rather than
   letting the banner overlap them. */
/* The fallbacks are the measured heights at each breakpoint, not round
   numbers: without JS nothing sets --banner-h, and a fallback that is too
   small lets the banner sit on top of the brand lockup. */
body.has-banner .page { top: var(--banner-h, 68px); height: calc(100svh - var(--banner-h, 68px)); }
body.has-banner .skip { top: var(--banner-h, 68px); }

@media (max-width: 720px) {
  /* The shell goes static here and the document scrolls, so reserve space with
     padding instead of offsetting a fixed element. */
  body.has-banner .page { top: 0; height: auto; padding-top: var(--banner-h, 96px); }
  /* The brand, ticker and scroll shade become viewport-fixed at this width,
     which means moving .page does not move them. They need the offset too. */
  body.has-banner .brand,
  body.has-banner .ticker,
  body.has-banner .page::before { top: var(--banner-h, 96px); }
}
@media (max-width: 560px) {
  .banner { padding: 11px 14px; gap: 10px; }
  .banner-text { font-size: 12px; text-align: left; }
}
@media (prefers-reduced-motion: reduce) { .banner { transition: none; } }

/* ─── Brand (top-left) ─── */
.brand {
  position: absolute;
  top: 0; left: 0;
  padding: 26px 40px;
  z-index: 10;
  display: flex;
  align-items: center;
  gap: 12px;
  user-select: none;
}
.brand-mark {
  width: 34px; height: 34px;
  display: block;
  filter: drop-shadow(0 0 14px rgba(255,102,0,0.45));
  transition: filter var(--t-base) ease;
}
.brand:hover .brand-mark { filter: drop-shadow(0 0 22px rgba(255,102,0,0.72)); }
.brand-text { display: flex; flex-direction: column; line-height: 1; }
.brand-name {
  font-size: clamp(19px, 2.2vw, 24px);
  font-weight: 900;
  font-variation-settings: 'wdth' 120;
  letter-spacing: 0.01em;
}
.brand-ticker {
  margin-top: 4px;
  font-family: 'Martian Mono', ui-monospace, monospace;
  font-size: 9.5px;
  font-weight: 500;
  font-variation-settings: 'wdth' 100;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--label);
}

/* ─── Live ticker pill (top-right) ───
   The price is chrome, not content: it stays pinned to the viewport corner
   so the number is on screen no matter how far the hero has scrolled.
   Unlike the reference's bare text this gets a container, so it reads as
   instrumentation rather than as a floating number. */
.ticker {
  position: absolute;
  top: 0; right: 0;
  margin: 22px 32px;
  padding: 9px 14px;
  z-index: 10;
  display: flex;
  align-items: center;
  gap: 10px;
  background: rgba(25, 9, 4, 0.72);
  border: 1px solid var(--line);
  border-top-color: var(--line-lit);
  border-radius: var(--r-sharp);
  box-shadow: var(--rim-top), var(--glow-sm);
  user-select: none;
}
.ticker-dot {
  width: 7px; height: 7px;
  border-radius: 50%;
  background: var(--ash);
  flex: 0 0 auto;
  position: relative;
  transition: background var(--t-base) ease;
}
.ticker-dot[data-state="live"] {
  background: var(--up);
  box-shadow: 0 0 10px rgba(53,192,107,0.7);
}
.ticker-dot[data-state="live"]::after {
  content: '';
  position: absolute; inset: -3px;
  border-radius: 50%;
  background: var(--up);
  opacity: 0.32;
  animation: pulse 2.4s var(--ease-out) infinite;
}
.ticker-dot[data-state="stale"] {
  background: var(--o-lift);
  box-shadow: 0 0 10px rgba(255,138,31,0.6);
}
.ticker-dot[data-state="down"] {
  background: var(--down);
  box-shadow: 0 0 10px rgba(255,77,61,0.6);
}
@keyframes pulse   { 0% { transform: scale(0.6); opacity: 0.45; } 100% { transform: scale(2.4); opacity: 0; } }
@keyframes breathe { 0%, 100% { opacity: 1; } 50% { opacity: 0.45; } }

.ticker-label {
  font-family: 'Martian Mono', ui-monospace, monospace;
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.22em;
  color: var(--label);
}
.ticker-price {
  font-family: 'Martian Mono', ui-monospace, monospace;
  font-size: 14px;
  font-weight: 600;
  font-variation-settings: 'wdth' 95;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.01em;
  color: var(--chrome-2);
}
.ticker-price[data-state="live"] { text-shadow: var(--bloom-text); }

/* ─── Canvas tableau ─── */
.canvas-wrap { position: absolute; inset: 0; z-index: 1; pointer-events: none; }
#markCanvas { display: block; width: 100%; height: 100%; }

/* The hero backlight: the M disc behind the dog, and the page's one big
   light. It lives on a FIXED layer, so this very large soft gradient is
   painted once and never repaints as the hero scrolls over it. */
.canvas-wrap::before {
  content: '';
  position: absolute;
  left: 50%;
  top: 24vh;
  /* Sized and placed to sit BEHIND THE DOG, not behind the page. An earlier
     draft ran this at min(120vh, 1000px) and 0.95 alpha, which turned the
     whole viewport orange and quietly voided every contrast ratio in this
     file, all of which are measured against black. The mascot photograph
     already contains a painted disc; this layer is the halo around it. */
  width: min(88vh, 800px);
  aspect-ratio: 1;
  transform: translate(-50%, -50%);
  border-radius: 50%;
  /* PEAK ALPHA IS 0.085, WELL UNDER THE TABLEAU'S 0.26 CEILING, and the
     binding constraint here is not text contrast but A HARD EDGE ON THE
     MASCOT. The hero image is an opaque square whose blacks are floored to
     exactly --ground, so wherever this layer is brighter than pure black the
     image reads as a darker rectangle sitting on the glow. At 0.26 the step
     across its border measured 69 levels and the square was plainly visible.
     Under about 20 levels the step stops being perceptible, which is what
     sets the value here. Measured, not guessed.

     So this is an ambient bloom rather than a second disc. The photograph
     already contains the painted disc and its glow; duplicating it in CSS is
     what created the artifact. If you raise this, re-measure the border. */
  background: radial-gradient(circle at 50% 50%,
    rgba(255,128,20,0.085) 0%,
    rgba(255,106,2,0.075) 34%,
    rgba(253,117,1,0.055) 52%,
    rgba(226,85,9,0.030)  66%,
    rgba(183,74,22,0.012) 78%,
    rgba(120,44,10,0.000) 92%);
  filter: blur(0.5px);  /* kills gradient banding, costs nothing */
  opacity: 0;
  animation: ignite 1100ms var(--ease-out) forwards;
}
/* THE SIGNATURE MOMENT: the page turns the light on before the dog appears. */
@keyframes ignite {
  0%   { opacity: 0; transform: translate(-50%,-50%) scale(0.86); }
  60%  { opacity: 1; transform: translate(-50%,-50%) scale(1.02); }
  100% { opacity: 1; transform: translate(-50%,-50%) scale(1); }
}

/* ─── Vignette ───
   Inverted from the reference, which painted cream inward to protect its
   copy. This paints black inward: same job, opposite hue, and it is what
   makes the disc look like it is BEHIND the dog rather than on top. */
.vignette {
  position: absolute;
  inset: 0;
  z-index: 3;
  pointer-events: none;
  background: radial-gradient(ellipse 76% 66% at 50% 44%,
    rgba(0,0,0,0.62)  0%,
    rgba(0,0,0,0.40) 26%,
    rgba(0,0,0,0.10) 52%,
    rgba(0,0,0,0.86) 100%);
}

/* ─── Hero ─── */
.hero {
  position: relative;
  z-index: 5;
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overflow-x: hidden;
  display: flex;
  align-items: flex-start;
  justify-content: center;
  padding: 116px 32px 56px;
  scrollbar-width: thin;
  scrollbar-color: #45200F transparent;
}
/* The reference never styled its scrollbar. On black, a default light bar
   is a wound. */
.hero::-webkit-scrollbar { width: 10px; }
.hero::-webkit-scrollbar-track { background: transparent; }
.hero::-webkit-scrollbar-thumb {
  background: #45200F;
  border: 3px solid #000;
  border-radius: 0;
}
.hero::-webkit-scrollbar-thumb:hover { background: var(--o-char); }

.hero-inner {
  width: 100%;
  max-width: 790px;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
}

/* ─── The dog ───
   The source is 800x800 on pure black with its blacks floored to --ground,
   so it composites onto the page with no visible seam. Do not round it, do
   not put it in a card, do not give it a border. */
.mog {
  width: clamp(168px, 22vw, 268px);
  height: auto;
  display: block;
  /* Two shadows: a tight orange rim reinforcing the backlight already in
     the art, and a wide soft one that sits the dog on a ground plane. */
  filter:
    drop-shadow(0 0 22px rgba(255,102,0,0.42))
    drop-shadow(0 26px 44px rgba(0,0,0,0.9));
  /* FEATHER THE EDGES. The asset is an opaque square whose blacks are floored
     to exactly --ground, which blends perfectly on a pure black page and not
     at all once anything is lit behind it: the ambient bloom and the canvas
     tableau both sit under the hero, so the square read as a darker rectangle
     with a measured 60-level step at its border.

     Dimming the atmosphere until the step vanished would have cost the
     atmosphere. Fading the image's own edges fixes it wherever the step comes
     from. The horizontal fade is the wider one because the left and right
     margins of the source are empty black; vertically it is kept tight, since
     the disc is tangent to the top edge and the dog's chest runs to the
     bottom, and neither should be clipped.

     Two layers intersected. Where mask-composite is unsupported the first
     layer still applies on its own, which degrades to a horizontal-only fade
     rather than to a hard square. */
  -webkit-mask-image:
    linear-gradient(90deg, transparent 0, #000 9%, #000 91%, transparent 100%),
    linear-gradient(180deg, transparent 0, #000 5%, #000 95%, transparent 100%);
  -webkit-mask-composite: source-in;
  mask-image:
    linear-gradient(90deg, transparent 0, #000 9%, #000 91%, transparent 100%),
    linear-gradient(180deg, transparent 0, #000 5%, #000 95%, transparent 100%);
  mask-composite: intersect;
  opacity: 0;
  transform: translateY(24px);
  animation:
    rise var(--t-slow) var(--ease) 180ms forwards,
    bob 8s ease-in-out 1.1s infinite;
  will-change: transform;
}
/* Vertical only, and slower than the reference's 7s. The reference rotated
   its peanut; rotating a photographed face reads as a glitch, and a mogging
   dog does not bounce. */
@keyframes bob { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-9px); } }

@keyframes rise { to { opacity: 1; transform: translateY(0); } }

/* Staggered load cascade. 40% faster than the reference's institutional
   unfurl, with harder easing. */
.eyebrow, .hero-title span, .hero-sub, .hero-tagline,
.market, .ca, .ctas, .ctas-hint, .terminal {
  opacity: 0;
  transform: translateY(18px);
  animation: rise var(--t-slow) var(--ease) forwards;
}
.hero-title .line1,
.hero-title .line2,
.hero-title .line3 { transform: translateY(24px); }
.eyebrow            { animation-delay: 320ms; }
.hero-title .line1  { animation-delay: 400ms; }
.hero-title .line2  { animation-delay: 470ms; }
.hero-title .line3  { animation-delay: 560ms; }
.hero-sub           { animation-delay: 640ms; }
.hero-tagline       { animation-delay: 710ms; }
.market             { animation-delay: 800ms; }
.ca                 { animation-delay: 880ms; }
.ctas               { animation-delay: 950ms; }
.ctas-hint          { animation-delay: 1010ms; }
.terminal           { animation-delay: 1090ms; }

.eyebrow {
  margin-top: 28px;
  font-family: 'Martian Mono', ui-monospace, monospace;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.34em;
  text-transform: uppercase;
  color: var(--label);
}
.eyebrow .sep { margin: 0 0.7em; color: var(--o-char); }

.hero-title {
  margin-top: 26px;
  font-size: clamp(40px, 7vw, 86px);
  font-weight: 800;
  font-variation-settings: 'wdth' 114;
  letter-spacing: -0.02em;
  line-height: 0.94;
  /* line-height under 1 clips descenders in some engines. */
  padding-bottom: 0.06em;
  color: var(--chrome-2);
}
.hero-title span { display: block; }
.hero-title .accent {
  display: inline-block;
  font-weight: 900;
  font-variation-settings: 'wdth' 122;
  letter-spacing: 0.005em;
  text-transform: uppercase;
}

.hero-sub {
  margin-top: 26px;
  max-width: 620px;
  font-size: clamp(15px, 1.35vw, 17px);
  font-weight: 400;
  font-variation-settings: 'wdth' 96;
  line-height: 1.62;
  color: var(--bone);
}
/* The tagline is brand-orange body text, which is the payoff of a palette
   whose accent measures 7.15:1 on its own ground. */
.hero-tagline {
  margin-top: 18px;
  font-family: 'Martian Mono', ui-monospace, monospace;
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.10em;
  text-transform: uppercase;
  line-height: 1.5;
  color: var(--o);
}
.hero-tagline .dot { margin: 0 0.6em; color: var(--o-char); }

/* ─── Live market band ─── */
.market { margin-top: 36px; width: 100%; }

/* The gap-as-divider trick gives a border layer for free: 1px of padding
   plus a background turns it into a full chamfered hairline frame in one
   element. clip-path here is safe because nothing inside is focusable. */
.market-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 1px;
  padding: 1px;
  background: var(--line-solid);
  clip-path: var(--cut);
  box-shadow: var(--glow-md);
}
.market-cell {
  position: relative;
  background: var(--surface);
  padding: 18px 14px 20px;
  text-align: center;
  transition: background var(--t-base) ease;
}
/* The rim cannot be a border here, because the grid gap IS the border. */
.market-cell::before {
  content: '';
  position: absolute; inset: 0;
  pointer-events: none;
  box-shadow: var(--rim-top), var(--rim-bottom);
}
.market-cell:hover { background: var(--surface-2); }

.market-label {
  font-family: 'Martian Mono', ui-monospace, monospace;
  font-size: 9.5px;
  font-weight: 600;
  letter-spacing: 0.20em;
  text-transform: uppercase;
  color: var(--label);
}
.market-value {
  margin-top: 10px;
  font-family: 'Martian Mono', ui-monospace, monospace;
  font-size: clamp(17px, 2.2vw, 25px);
  font-weight: 600;
  font-variation-settings: 'wdth' 90;
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.01em;
  line-height: 1.1;
  color: var(--chrome-2);
}
.market-value.is-up   { color: var(--up); }
.market-value.is-down { color: var(--down); }

/* The missing-number placeholder. It is the literal string NO DATA, styled
   to read as a redaction while the characters stay real, because that is
   exactly what a screen reader announces. It carries no digits, so it can
   never be mistaken for a fabricated zero. */
.is-empty {
  font-size: 11px !important;
  font-weight: 600;
  font-variation-settings: 'wdth' 100;
  letter-spacing: 0.18em;
  color: var(--label) !important;
  background: #000;
  box-shadow: inset 0 -1px 0 0 var(--o-char);
  padding: 3px 7px;
  display: inline-block;
}

.market-meta {
  margin-top: 18px;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 14px 10px;
  text-align: center;
}
.market-meta dt {
  font-family: 'Martian Mono', ui-monospace, monospace;
  font-size: 9px;
  font-weight: 600;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--label);
}
.market-meta dd {
  margin-top: 5px;
  font-family: 'Martian Mono', ui-monospace, monospace;
  font-size: 11.5px;
  font-variation-settings: 'wdth' 90;
  font-variant-numeric: tabular-nums;
  line-height: 1.4;
  color: var(--bone-2);
}

.market-note {
  margin-top: 16px;
  font-size: 11.5px;
  font-variation-settings: 'wdth' 96;
  letter-spacing: 0.02em;
  line-height: 1.5;
  color: var(--label);
}
/* Never dim a note with opacity. Opacity composites the text against the
   ground and voids every ratio measured in this file. Use a real tone. */
.market.is-stale .market-note { color: var(--o-lift); }
.market.is-down  .market-note { color: var(--down); }

/* A refresh that actually moved a number gets a one-shot flash: colour and
   a bloom that decays, directional where direction is known. */
.market-value.is-flash { animation: flash 700ms var(--ease-out); }
@keyframes flash {
  0%   { color: var(--o-ember); text-shadow: 0 0 20px rgba(255,184,112,0.75); }
  55%  { text-shadow: 0 0 10px rgba(255,184,112,0.28); }
  100% { text-shadow: none; }
}
/* These must come AFTER .is-flash so the animation-name override wins. */
.market-value.is-up.is-flash   { animation-name: flash-up; }
.market-value.is-down.is-flash { animation-name: flash-down; }
@keyframes flash-up {
  0%   { color: var(--up-soft); text-shadow: 0 0 20px rgba(111,227,155,0.7); }
  100% { color: var(--up); text-shadow: none; }
}
@keyframes flash-down {
  0%   { color: #FF8A7C; text-shadow: 0 0 20px rgba(255,77,61,0.7); }
  100% { color: var(--down); text-shadow: none; }
}

/* ─── Contract address ─── */
.ca { margin-top: 28px; width: 100%; max-width: 560px; }
.ca-label {
  font-family: 'Martian Mono', ui-monospace, monospace;
  font-size: 9.5px;
  font-weight: 600;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--label);
  text-align: left;
}
.ca-row {
  margin-top: 9px;
  display: flex;
  align-items: stretch;
  background: var(--surface);
  border: 1px solid var(--line);
  border-top-color: var(--line-lit);
  border-bottom-color: var(--line-dim);
  border-radius: var(--r-sharp);
  box-shadow: var(--rim-top), var(--rim-bottom);
  overflow: hidden;
}
.ca-text {
  flex: 1 1 auto;
  min-width: 0;
  padding: 12px 14px;
  font-family: 'Martian Mono', ui-monospace, monospace;
  /* Condensed, which is what fits a 44-character base58 mint in one row
     without hyphenating. */
  font-variation-settings: 'wdth' 82;
  font-size: 12px;
  line-height: 1.55;
  color: var(--bone-2);
  text-align: left;
  overflow-wrap: anywhere;
  user-select: all;  /* one click selects the whole mint */
}
/* break-all is right for a 44-character base58 mint and wrong for a sentence:
   in pre-launch this element holds prose, and breaking mid-word rendered it as
   "permanen / tly". Scope the hard break to the state that actually needs it. */
html[data-mint]:not([data-mint=""]) .ca-text { word-break: break-all; }
.ca-copy {
  flex: 0 0 auto;
  border: 0;
  border-left: 1px solid var(--line);
  background: transparent;
  color: var(--o);  /* 7.15:1: brand orange doing real work as a label */
  padding: 0 18px;
  font-family: 'Martian Mono', ui-monospace, monospace;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  cursor: pointer;
  transition: background var(--t-fast) ease, color var(--t-fast) ease;
}
.ca-copy:hover  { background: rgba(255,102,0,0.12); color: var(--o-lift); }
.ca-copy:active { background: rgba(255,102,0,0.20); }
.ca-copy.is-copied { background: var(--up); color: #000; }  /* 8.90:1 inverted */

/* ─── CTAs ─── */
.ctas {
  margin-top: 32px;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: 20px 28px;
}
.cta { text-decoration: none; }

/* The loudest object on the page, and the only solid orange fill above the
   fold. Black on orange measures 7.15:1. */
.cta.primary {
  font-size: 15px;
  font-weight: 800;
  font-variation-settings: 'wdth' 108;
  letter-spacing: 0.10em;
  text-transform: uppercase;
  color: #000;
  background: linear-gradient(176deg, var(--o-lift) 0%, var(--o) 46%, var(--o-mid) 100%);
  padding: 15px 30px;
  border: 0;
  clip-path: var(--cut);
  box-shadow: var(--glow-md);
  /* box-shadow is deliberately NOT transitioned: it would repaint its blur
     every frame. filter:brightness is one composited property and carries
     the whole hover. */
  transition: transform var(--t-base) var(--ease), filter var(--t-base) ease;
}
.cta.primary:hover  { transform: translateY(-2px); filter: brightness(1.10) saturate(1.06); }
.cta.primary:active { transform: translateY(0); filter: brightness(0.94); }

/* Pre-launch. Never use opacity for a disabled state: it halves every
   measured ratio and there is no entry in the ledger for "orange at 50%
   over black". This keeps 7.15:1 and simply stops being a filled slab. */
.cta.primary.is-prelaunch,
.cta.primary[aria-disabled="true"] {
  background: none;
  color: var(--o);
  box-shadow: inset 0 0 0 1px var(--line-lit);
  cursor: not-allowed;
  pointer-events: none;
  filter: none;
  transform: none;
}
.cta.primary.is-prelaunch::after {
  content: ' / SOON';
  color: var(--label);
}

.cta.secondary {
  font-size: 14px;
  font-weight: 600;
  letter-spacing: 0.06em;
  color: var(--bone);
  border-bottom: 1px solid transparent;
  padding-bottom: 2px;
  transition: color var(--t-base) ease, border-color var(--t-base) ease;
}
.cta.secondary:hover { color: var(--chrome); border-bottom-color: var(--o); }
.cta .arrow {
  display: inline-block;
  margin-left: 4px;
  transition: transform var(--t-base) var(--ease);
}
.cta:hover .arrow { transform: translate(3px, -2px); }  /* diagonal glyph, diagonal move */

/* Pre-launch promotes the community link to the page's primary action, so
   there is still one obvious thing to do. */
html[data-mint=""] .cta-community {
  font-weight: 800;
  font-variation-settings: 'wdth' 108;
  letter-spacing: 0.10em;
  text-transform: uppercase;
  color: var(--o);
  border-bottom-color: var(--o);
}

.ctas-hint {
  margin-top: 18px;
  max-width: 460px;
  font-size: 11.5px;
  font-variation-settings: 'wdth' 96;
  line-height: 1.55;
  color: var(--label);
}

/* ─── Pre-launch presentation ───
   All of this is driven by an attribute selector on <html>, which is why it
   works with JavaScript disabled. That is the state the site actually lives
   in until the mint exists. JS only UPGRADES the page to live. */
html[data-mint=""] .ca-copy       { display: none; }
html[data-mint=""] [data-mint-only] { display: none; }
html[data-mint=""] .ticker-dot[data-state] {
  background: var(--prelaunch);
  box-shadow: none;
  animation: breathe 3.2s ease-in-out infinite;
}
html[data-mint=""] .ticker-dot[data-state]::after { display: none; }

/* ─── Terminal block (the mog check) ─── */
.terminal {
  margin-top: 44px;
  width: 100%;
  max-width: 600px;
  padding: 1px;
  background: linear-gradient(180deg, var(--line-lit) 0%, var(--line) 30%, var(--line-dim) 100%);
  clip-path: var(--cut);
  text-align: left;
  box-shadow: var(--glow-md);
}
.terminal-bar {
  display: flex;
  align-items: center;
  gap: 7px;
  padding: 11px 16px;
  background: #120703;
  border-bottom: 1px solid var(--line-dim);
}
.terminal-bar .tdot { width: 8px; height: 8px; border-radius: 50%; background: var(--ash); }
.terminal-bar .tdot:first-child { background: var(--o-char); }
.terminal-bar .tlabel {
  margin-left: auto;
  font-family: 'Martian Mono', ui-monospace, monospace;
  font-size: 9.5px;
  font-weight: 600;
  letter-spacing: 0.18em;
  color: var(--label);
}
.terminal pre {
  margin: 0;
  padding: 18px 20px 20px;
  background: var(--surface-3);
  font-family: 'Martian Mono', ui-monospace, monospace;
  font-variation-settings: 'wdth' 82;
  font-size: 12.5px;
  line-height: 1.68;
  color: var(--bone-2);
  white-space: pre;
  overflow-x: auto;
}
.terminal .prompt { color: var(--o); }
.terminal .cmd    { color: var(--chrome-2); }
.terminal .cmt    { color: var(--label); }
.terminal .out    { color: var(--bone-2); }
.terminal .tree   { color: var(--label); }
.terminal .nil    { color: var(--o-lift); }
.terminal .ok     { color: var(--up); }
.terminal .cursor {
  display: inline-block;
  width: 7px; height: 14px;
  margin-left: 4px;
  vertical-align: -2px;
  background: var(--o);
  box-shadow: 0 0 8px rgba(255,102,0,0.8);
  animation: blink 1.05s steps(1) infinite;
}
@keyframes blink { 0%, 50% { opacity: 1; } 50.01%, 100% { opacity: 0; } }

/* ─── Shared section scaffolding ─── */
.band {
  position: relative;
  margin-top: 96px;
  padding-top: 64px;
  width: 100%;
  text-align: left;
  border-top: 1px solid transparent;
}
/* The rule is not uniform: it is brightest where the light is and fades to
   nothing at the edges. A flat 1px line straight across a black page is the
   giveaway of a template. */
.band::before {
  content: '';
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 1px;
  background: linear-gradient(90deg,
    rgba(255,102,0,0) 0%, var(--o) 22%, var(--o-lift) 50%, var(--o) 78%, rgba(255,102,0,0) 100%);
  opacity: 0.55;
}
.band-tight { margin-top: 72px; padding-top: 44px; }
.band-title {
  font-size: clamp(26px, 3.6vw, 40px);
  font-weight: 800;
  font-variation-settings: 'wdth' 112;
  letter-spacing: -0.016em;
  line-height: 1.08;
  text-align: center;
  color: var(--chrome-2);
}
.band-lede {
  margin: 20px auto 0;
  max-width: 660px;
  font-size: clamp(15px, 1.3vw, 16px);
  font-variation-settings: 'wdth' 96;
  line-height: 1.66;
  text-align: center;
  color: var(--bone);
}

/* Reveal-on-scroll. INVERTED on purpose, exactly as the reference does it:
   a .reveal band is VISIBLE by default and the script ARMS it to hide. So
   if scripts.js never runs (JS off, a script error, a blocked file) the
   page degrades to a static page rather than a blank one. A
   <noscript><style> fix is not available here: the CSP has no
   'unsafe-inline' in style-src and would block it. */
.reveal { transition: opacity 700ms var(--ease), transform 700ms var(--ease); }
.reveal.is-armed { opacity: 0; transform: translateY(26px); }
.reveal.is-armed.is-in { opacity: 1; transform: translateY(0); }

/* ─── Case grid ───
   Same gap-as-divider mechanics as the market band, but NO chamfer: the
   chamfer belongs to the three hardware objects only. */
.cases {
  margin-top: 42px;
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 1px;
  padding: 1px;
  background: var(--line-solid);
  border-radius: var(--r-sharp);
  overflow: hidden;
}
.case {
  position: relative;
  background: var(--surface);
  padding: 24px 24px 26px;
  transition: background var(--t-base) ease;
}
.case::before {
  content: '';
  position: absolute; inset: 0;
  pointer-events: none;
  box-shadow: var(--rim-top), var(--rim-bottom);
}
.case:hover { background: var(--surface-2); }
/* Hover lifts the left edge into the light. */
.case::after {
  content: '';
  position: absolute;
  left: 0; top: 0; bottom: 0;
  width: 2px;
  background: var(--o);
  transform: scaleY(0);
  transform-origin: top;
  transition: transform var(--t-base) var(--ease);
}
.case:hover::after { transform: scaleY(1); }
.case-num {
  font-family: 'Martian Mono', ui-monospace, monospace;
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.14em;
  color: var(--o-art);  /* 7.14:1 on --surface */
}
.case h3 {
  margin-top: 12px;
  font-size: 16px;
  font-weight: 700;
  font-variation-settings: 'wdth' 106;
  letter-spacing: -0.006em;
  line-height: 1.24;
  color: var(--chrome-2);
}
.case p {
  margin-top: 10px;
  font-size: 13.5px;
  font-variation-settings: 'wdth' 96;
  line-height: 1.6;
  color: var(--bone);
}

/* ─── Roadmap ─── */
.roadmap {
  margin-top: 42px;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 1px;
  padding: 1px;
  background: var(--line-solid);
  border-radius: var(--r-sharp);
  overflow: hidden;
}
.quarter {
  position: relative;
  background: var(--surface);
  padding: 22px 18px 24px;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 12px;
}
.quarter::before {
  content: '';
  position: absolute; inset: 0;
  pointer-events: none;
  box-shadow: var(--rim-top), var(--rim-bottom);
}
.quarter-item {
  font-size: 15px;
  font-weight: 700;
  font-variation-settings: 'wdth' 106;
  letter-spacing: -0.006em;
  line-height: 1.3;
  color: var(--chrome-2);
}
.quarter-q {
  display: block;
  margin-bottom: 7px;
  font-family: 'Martian Mono', ui-monospace, monospace;
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.18em;
  color: var(--o-art);
}
.quarter-status {
  margin-top: auto;
  font-family: 'Martian Mono', ui-monospace, monospace;
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  line-height: 1.4;
  color: var(--up);
}

/* ─── Static counters ─── */
.stats {
  margin-top: 8px;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 1px;
  padding: 1px;
  background: var(--line-solid);
  border-radius: var(--r-sharp);
  overflow: hidden;
}
.stat {
  position: relative;
  background: var(--surface);
  padding: 26px 14px 24px;
  text-align: center;
}
.stat::before {
  content: '';
  position: absolute; inset: 0;
  pointer-events: none;
  box-shadow: var(--rim-top), var(--rim-bottom);
}
.stat-num {
  font-family: 'Martian Mono', ui-monospace, monospace;
  font-size: clamp(30px, 5vw, 46px);
  font-weight: 700;
  font-variation-settings: 'wdth' 88;
  /* Tabular figures keep the chrome gradient from shimmying: a proportional
     glyph swap would slide the gradient under the text. */
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.035em;
  line-height: 1;
}
.stat-label {
  margin-top: 10px;
  font-family: 'Martian Mono', ui-monospace, monospace;
  font-size: 9.5px;
  font-weight: 600;
  letter-spacing: 0.18em;
  line-height: 1.3;
  color: var(--label);
}

/* ─── FAQ ───
   Hairlines here are chrome rather than orange on purpose. This is the
   coolest, quietest region on the page and orange rules would make it
   shout. It is the one place the light system relents. */
.faq { margin-top: 38px; border-top: 1px solid var(--line-cold); }
.faq details { border-bottom: 1px solid var(--line-cold); }
.faq summary {
  position: relative;
  padding: 19px 38px 19px 2px;
  cursor: pointer;
  list-style: none;
  font-size: 16px;
  font-weight: 600;
  font-variation-settings: 'wdth' 104;
  letter-spacing: -0.004em;
  line-height: 1.35;
  color: var(--chrome-2);
  transition: color var(--t-fast) ease;
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary:hover { color: var(--o-lift); }
.faq details[open] summary { color: var(--o); }
/* A plus that becomes a minus, drawn with two gradients on one pseudo
   element because both of summary's pseudo slots are otherwise spoken for. */
.faq summary::after {
  content: '';
  position: absolute;
  top: 50%; right: 4px;
  width: 12px; height: 12px;
  transform: translateY(-50%);
  background:
    linear-gradient(var(--o) 0 0) center / 12px 1.5px no-repeat,
    linear-gradient(var(--o) 0 0) center / 1.5px 12px no-repeat;
  transition: transform var(--t-base) var(--ease);
}
.faq details[open] summary::after {
  transform: translateY(-50%) rotate(180deg);
  background: linear-gradient(var(--o-lift) 0 0) center / 12px 1.5px no-repeat;
}
.faq-answer {
  padding: 0 38px 20px 2px;
  font-size: 14px;
  font-variation-settings: 'wdth' 96;
  line-height: 1.64;
  color: var(--bone);
}

/* ─── Disclaimer ───
   Quieter than everything above it, deliberately. It is the one honest
   thing on a meme coin page, and dressing it in glow would read as sarcasm. */
.disclaimer {
  margin-top: 72px;
  padding: 22px 24px;
  background: var(--ground-2);
  border: 1px solid var(--line-dim);
  border-left: 2px solid var(--o-burnt);
  border-radius: var(--r-sharp);
  font-size: 12.5px;
  font-variation-settings: 'wdth' 96;
  letter-spacing: 0.01em;
  line-height: 1.66;
  text-align: left;
  color: var(--bone-2);
}
.disclaimer strong {
  display: block;
  margin-bottom: 9px;
  font-family: 'Martian Mono', ui-monospace, monospace;
  font-size: 9.5px;
  font-weight: 600;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--label);
}

/* ─── Foot ─── */
.foot {
  position: relative;
  z-index: 10;
  flex: 0 0 auto;
  padding: 22px 40px;
  padding-bottom: calc(22px + env(safe-area-inset-bottom));
  text-align: center;
  font-family: 'Martian Mono', ui-monospace, monospace;
  font-size: 9.5px;
  font-weight: 600;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--label);
  background: linear-gradient(to top, #000 58%, rgba(0,0,0,0));
  box-shadow: 0 -1px 0 var(--line-dim);
}
.foot a {
  color: var(--label);
  text-decoration: none;
  transition: color var(--t-base) ease;
}
.foot a:hover { color: var(--o); }
.foot .sep { margin: 0 0.7em; color: var(--o-char); }

/* ─── Skip link ───
   Must be MORE visible than the reference's, not less. On a black page a
   black-on-black skip link that fails to draw is invisible rather than
   merely low contrast. position:fixed because .page clips. */
.skip {
  position: fixed;
  top: 0; left: 0;
  z-index: 20;
  padding: 12px 20px;
  background: #000;
  border: 2px solid var(--o);
  border-radius: 0 0 var(--r-sharp) 0;
  box-shadow: var(--glow-md);
  color: var(--chrome);
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-decoration: none;
  transform: translateY(-130%);
  transition: transform var(--t-base) var(--ease);
}
.skip:focus { transform: translateY(0); }

/* Visible only to screen readers. Never revealed, in any state. */
.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* ─── Focus ─── */
a:focus-visible,
button:focus-visible,
summary:focus-visible {
  outline: 2px solid var(--o-lift);  /* 8.91:1 on black */
  outline-offset: 3px;
  border-radius: var(--r-sharp);
}
/* Inside .ca-row's overflow:hidden an outset ring is clipped off. Draw in. */
.ca-copy:focus-visible { outline-offset: -4px; }
/* On an orange fill an orange ring is invisible, and clip-path removes an
   outline entirely, so the chamfered CTA gets an inset double ring. */
.cta.primary:focus-visible,
.ca-copy.is-copied:focus-visible {
  outline: none;
  box-shadow: inset 0 0 0 2px #000, inset 0 0 0 5px var(--chrome), var(--glow-md);
}

/* ─── Responsive ─── */
@media (max-width: 1024px) {
  :root { --chamfer: 14px; }
  .hero-inner { max-width: 720px; }
  .mog { width: clamp(160px, 22vw, 220px); }
}

@media (max-width: 860px) {
  .market-grid, .market-meta, .roadmap, .stats { grid-template-columns: repeat(2, 1fr); }
  .cases { grid-template-columns: 1fr; }
  .band { margin-top: 72px; padding-top: 48px; }
}

/* THE FIXED SHELL IS ABANDONED BELOW 720px.
   An inner overflow-y:auto container on iOS Safari loses native momentum
   handoff, fights the address-bar collapse, breaks scroll restoration and
   kills pull-to-refresh. Below this width, scrolling goes back to the
   document and the chrome that was absolute-inside-a-fixed-shell becomes
   viewport-fixed instead. */
@media (max-width: 720px) {
  html, body { height: auto; overflow-x: hidden; }
  .page {
    position: static;
    height: auto;
    min-height: 100svh;
    overflow: visible;
  }
  .hero {
    overflow: visible;
    min-height: 0;
    flex: 0 1 auto;
    justify-content: flex-start;
    padding: 96px 20px 48px;
  }
  .brand, .ticker { position: fixed; }
  .page::before { position: fixed; height: 84px; }
  .page::after, .canvas-wrap, .vignette { position: fixed; }
  .foot { position: static; }
}

@media (max-width: 560px) {
  :root { --chamfer: 12px; }
  .brand  { padding: 16px 18px; gap: 9px; }
  .ticker { margin: 14px 14px; padding: 7px 11px; }
  .ticker-label { display: none; }
  .brand-name { font-size: 18px; }
  .brand-mark { width: 28px; height: 28px; }
  .mog {
    width: clamp(128px, 34vw, 176px);
    /* One shadow, not two: re-filtering an image that also runs an infinite
       transform is the most expensive thing on a phone. */
    filter: drop-shadow(0 0 18px rgba(255,102,0,0.45));
  }
  .eyebrow { font-size: 9.5px; letter-spacing: 0.24em; }
  .hero-title { font-size: clamp(30px, 8.6vw, 42px); letter-spacing: -0.014em; font-variation-settings: 'wdth' 108; }
  .hero-sub { margin-top: 20px; font-size: 15px; }
  .market-cell { padding: 15px 10px 17px; }
  .market-value { font-size: 18px; }
  .terminal { max-width: 100%; }
  .terminal pre { font-size: 11px; font-variation-settings: 'wdth' 78; }
  .ctas { flex-direction: column; gap: 14px; }
  .cta.primary { width: 100%; text-align: center; }
  .stat-num { font-size: clamp(26px, 7vw, 34px); }
  .foot { font-size: 9px; letter-spacing: 0.18em; padding: 18px 20px; }
  .foot .sep { margin: 0 0.45em; }
}

@media (max-width: 400px) {
  .ca-row { flex-direction: column; }
  .ca-copy {
    border-left: none;
    border-top: 1px solid var(--line);
    padding: 12px 0;
  }
  .ca-text { font-variation-settings: 'wdth' 75; }
  .hero-title { font-size: clamp(26px, 9.2vw, 34px); }
  .terminal pre { font-size: 10px; line-height: 1.6; }
}

@media (max-width: 340px) {
  .market-grid, .market-meta, .roadmap, .stats { grid-template-columns: 1fr; }
}

/* Landscape phones and split windows, where the shell is still fixed. */
@media (max-height: 680px) and (min-width: 721px) {
  .page::before { height: 64px; }
  .hero { padding: 64px 24px 32px; }
  .mog { width: clamp(104px, 13vw, 140px); }
  .eyebrow, .hero-title, .hero-sub { margin-top: 18px; }
  .market { margin-top: 22px; }
  .ca { margin-top: 18px; }
  .ctas { margin-top: 20px; }
  .canvas-wrap::before { top: 22vh; width: min(96vh, 760px); }
}

/* Touch devices: fold hover-only affordances into a resting state so they
   are not simply dead. */
@media (hover: none) {
  .case::after { transform: scaleY(1); opacity: 0.4; }
  .cta.primary:hover { transform: none; filter: none; }
}

/* ─── Reduced motion ─── */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
  .mog { animation: none; opacity: 1; transform: none; }
  .eyebrow, .hero-title span, .hero-sub, .hero-tagline,
  .market, .ca, .ctas, .ctas-hint, .terminal { opacity: 1; transform: none; }
  .ticker-dot::after { display: none; }
  html[data-mint=""] .ticker-dot[data-state] { animation: none; opacity: 1; }
  .terminal .cursor { animation: none; opacity: 1; }
  /* Never leave a band hidden when the script that reveals it is muted. */
  .reveal.is-armed { opacity: 1; transform: none; }
  /* The disc must end up LIT, not stranded at opacity 0. */
  .canvas-wrap::before {
    animation: none;
    opacity: 1;
    transform: translate(-50%, -50%) scale(1);
  }
  .market-value.is-flash { animation: none; }
}
