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

/* Layout tokens for the fixed chrome — two stacked bars, the nav with the
   ticker pinned directly beneath it. --nav-h is the contract between them:
   the nav *is* this tall (declared, not inferred from its padding), and the
   ticker sits at exactly this offset. That used to be a comment policing two
   hand-matched literals, and the 900px breakpoint broke it — shrinking the
   nav's padding took it to 73.8px while the ticker stayed pinned at 82px, so
   an 8.2px strip of scrolling page content showed through the seam on every
   phone. Now the breakpoint moves the token and both bars follow.

   --content-top is the first y at which page content may begin. Deriving it
   from the same pair is what stops the mirror-image bug: at 900px the legal
   and detail pages had *less* top padding (104px) than the chrome is tall
   (106px), so their first heading rendered underneath the ticker. */
:root{
  --nav-h:82px;
  --ticker-h:32px;
  --chrome-h:calc(var(--nav-h) + var(--ticker-h));
  /* 0.875rem = the 14px of clearance the desktop layout has always had
     (8rem of top padding, less the 114px chrome). Expressed as an offset from
     the chrome rather than an absolute, so it survives every breakpoint. */
  --content-top:calc(var(--chrome-h) + 0.875rem);
}

/* Colour tokens carry a contrast contract, not just a palette. Every value that
   ends up as text was measured against the *darkest* surface it can land on —
   --bg3 for both themes, since cards and code chips sit on it — and clears
   WCAG AA 4.5:1 there, not merely on the page background. Changing one of these
   means re-measuring on --bg3, not eyeballing it on --bg. */
:root{
  --gold:#C9A84C;
  --gold-light:#E8C97A;
  --bg:#05080F;
  --bg2:#080D18;
  --bg3:#0D1525;
  --border:#1A2540;
  --text:#D8DCEC;
  /* 5.47:1 on --bg3. The old #687A9E measured 4.23 there — it cleared AA on the
     page background and quietly failed on every card. */
  --muted:#7C8DB0;
  --accent:#3A7BFF;
  /* --accent is a glow and a chart stroke; it is too light to sit under white
     badge text (3.85:1). --accent-deep is the same blue, darkened enough to
     carry #fff at 5.14:1, and is used *only* where the accent becomes a fill
     behind text. Keep the two in step if the brand blue ever moves. */
  --accent-deep:#2C66E0;
  --heading:#fff;
  --nav-bg:rgba(5,8,15,0.85);
  --ticker-bg:rgba(5,8,15,0.9);
  --grid-line:rgba(58,123,255,0.03);
  --pulse-bg:rgba(201,168,76,0.15);
  --bar-bg:rgba(201,168,76,0.2);
  --up:#4CAF90;
  --dn:#E25B5B;
}
/* Light mode inverts the surfaces but not the contrast contract above. Gold is
   the hard case: it has to work as *ink* on cream (#F7F5F0 → #E6E2DA) and as a
   *fill* under white button text, and both constraints pull the same way, so a
   single darkened token serves both. #A8872E — mid-gold, matching the dark
   theme's brightness — failed both at once: 3.12:1 as text, 3.40:1 as a button.
   The value below is the same hue at higher saturation, which reads as a deeper
   antique gold on cream rather than as a washed-out yellow. */
html[data-theme="light"]{
  --gold:#7A5D0E;        /* 4.78:1 on --bg3 as text; 6.18:1 under #fff as a fill */
  --gold-light:#8C6C15;  /* hover state — visibly lifted, still 4.91:1 under #fff */
  --bg:#F7F5F0;
  --bg2:#EFECE5;
  --bg3:#E6E2DA;
  --border:#D4CFC4;
  --text:#2A2A2A;
  --muted:#5F5F5F;       /* 4.94:1 on --bg3; #6B6B6B measured 4.12 there */
  --accent:#2A62D6;
  --accent-deep:#2A62D6; /* already 5.50:1 under #fff — no darkening needed here */
  --heading:#111111;
  --nav-bg:rgba(247,245,240,0.88);
  --ticker-bg:rgba(247,245,240,0.92);
  --grid-line:rgba(42,98,214,0.04);
  --pulse-bg:rgba(122,93,14,0.1);
  --bar-bg:rgba(122,93,14,0.15);
  --up:#2E8B57;
  --dn:#D32F2F;
}
html{scroll-behavior:smooth}
body{
  background:var(--bg);
  color:var(--text);
  font-family:'DM Sans',sans-serif;
  font-weight:300;
  font-size:16px;
  line-height:1.7;
  overflow-x:hidden;
}

/* GRID OVERLAY */
body::before{
  content:'';
  position:fixed;
  inset:0;
  background-image:
    linear-gradient(var(--grid-line) 1px,transparent 1px),
    linear-gradient(90deg,var(--grid-line) 1px,transparent 1px);
  background-size:60px 60px;
  pointer-events:none;
  z-index:0;
}

/* FOCUS
   Nothing in this stylesheet sets outline:none, so the browser default already
   survived — but the default ring is the colour the UA picked for *its* palette,
   and against a gold-filled button on a near-black page it is close to
   invisible. One ring, stated once, for every control on the site.

   Gold rather than white: it is the only accent already measured against every
   surface a control can sit on in both themes, and it is the ring dyna.css has
   always drawn on the catalog cards, so this generalises an existing decision
   instead of introducing a second one. Every button fill here is --gold,
   --heading or transparent over --bg/--bg2/--bg3, and the ring lands on the
   background rather than on the fill, so 3px of offset keeps it legible on all
   of them. `outline` follows `border-radius`, so the pills and rounded buttons
   get a rounded ring at no cost.

   :where() holds the specificity at zero. Two controls sit flush inside
   overflow:hidden containers that would clip an outward ring — the stretched
   card link and the detail-page zoom trigger — and both override this with a
   plain class selector and a negative offset. Zero specificity is what lets
   them, without !important.

   :focus-visible, not :focus: a mouse click on a button should not leave a ring
   behind it, which is the entire reason the pseudo-class exists. */
:where(a,button,summary,[tabindex]):focus-visible{
  outline:2px solid var(--gold);
  outline-offset:3px;
}

/* SKIP LINK
   WCAG 2.4.1 Bypass Blocks. Every page here puts a six-link nav and a scrolling
   ticker ahead of its content, so without this a keyboard or screen-reader user
   traverses the entire chrome on each of 26 pages with no way past it.

   Hidden with opacity, not display:none or visibility:hidden. Both of those
   remove an element from the tab order, which is the one property this link
   cannot lose — it is invisible precisely until the moment it is reached. It is
   the first child of <body> on every page, so Tab finds it before the logo.

   top:var(--content-top) drops it clear of the fixed chrome. The token already
   knows the chrome is 114px, and 106px at <=900px; a literal here would be a
   fourth hand-matched offset of exactly the kind the token was introduced to
   delete. z-index:98 sits *below* the ticker (99) and nav (100) rather than
   above them, because it is positioned past the bottom edge of both and has
   nothing to win a paint order against — joining the 100/101/102 stack the
   mobile menu depends on would be one more ordering to keep in step for no gain.

   No transition, deliberately. This link appearing IS the focus indicator, and
   a focus indicator has to be immediate — the same reason the buttons stopped
   using transition:all. Nothing for the reduced-motion block to switch off. */
.skip-link{
  position:fixed;
  top:var(--content-top);left:4rem;
  z-index:98;
  padding:0.7rem 1.1rem;
  border:1px solid var(--border);
  border-radius:6px;
  background:var(--bg2);
  color:var(--heading);
  font-family:'DM Mono',monospace;
  font-size:0.7rem;letter-spacing:0.12em;text-transform:uppercase;
  text-decoration:none;
  opacity:0;pointer-events:none;
}
.skip-link:focus{opacity:1;pointer-events:auto}

/* The skip link's destination. <main> is a scroll-and-focus target, not a
   control, and tabindex="-1" is what makes focus actually land on it rather
   than only moving the sequential-navigation starting point — which Safari and
   VoiceOver have never treated the same way Chrome does.

   That attribute also brings it inside the site-wide :where(...[tabindex])
   ring above, which would then draw a 2px gold box around the whole page
   content — the full scroll height of the home page. This is the third
   override of the single ring and the only one replacing it with nothing,
   because there is nothing here to indicate: a landmark accepts no input. What
   tells a sighted keyboard user the skip worked is the link vanishing and the
   next Tab landing inside the content. :focus rather than :focus-visible so it
   holds whichever of the two the browser decides applies to a programmatic
   focus that followed a keypress. */
main[tabindex="-1"]:focus{outline:none}

/* NAV */
nav{
  position:fixed;top:0;left:0;right:0;z-index:100;
  display:flex;align-items:center;justify-content:space-between;
  /* Height is declared, not left to the tallest child (.nav-logo, 40.8px) plus
     whatever padding the breakpoint happens to apply — that inference is what
     the ticker offset kept drifting away from. Vertical padding is gone;
     align-items handles the centring. */
  height:var(--nav-h);
  padding:0 4rem;
  border-bottom:1px solid var(--border);
  background:var(--nav-bg);
  backdrop-filter:blur(16px);
}
.nav-logo{
  font-family:'Cormorant Garamond',serif;
  font-size:1.5rem;font-weight:600;
  letter-spacing:0.04em;
  color:var(--heading);
  text-decoration:none;
}
.nav-logo span{color:var(--gold)}
.nav-links{display:flex;gap:2.5rem;list-style:none}
.nav-links a{
  font-size:0.8rem;letter-spacing:0.12em;text-transform:uppercase;
  color:var(--muted);text-decoration:none;
  transition:color 0.25s;
}
.nav-links a:hover{color:var(--gold)}
.nav-links .nav-pill{
  background:var(--heading);color:var(--bg);
  padding:0.35rem 1rem;border-radius:100px;
  font-weight:500;
  transition:background 0.25s,color 0.25s,opacity 0.25s;
}
.nav-links .nav-pill:hover{color:var(--bg);opacity:0.85}
/* Current page. The styling hangs off aria-current itself rather than a class,
   so the visual state and the accessible state cannot drift apart — there is one
   attribute and it drives both. Only /dyna ever carries it; the other five links
   are hash anchors into the home page and are never "the page". Gold rather than
   the default white fill because gold-on-bg is the one pairing already measured
   in both themes: the light-mode token was tuned to carry white text as a fill,
   which is exactly the job it does here. */
.nav-links a[aria-current="page"]{color:var(--gold)}
.nav-links .nav-pill[aria-current="page"]{background:var(--gold);color:var(--bg)}

/* NAV RIGHT GROUP */
.nav-right{display:flex;align-items:center;gap:1rem}

/* HAMBURGER (hidden on desktop) */
.hamburger{
  display:none;flex-direction:column;justify-content:center;gap:5px;
  background:none;border:none;cursor:pointer;padding:0.5rem;
}
.hamburger span{
  display:block;width:22px;height:2px;background:var(--heading);
  border-radius:2px;transition:transform 0.3s,opacity 0.3s;
}
.hamburger.active span:nth-child(1){transform:translateY(7px) rotate(45deg)}
.hamburger.active span:nth-child(2){opacity:0}
.hamburger.active span:nth-child(3){transform:translateY(-7px) rotate(-45deg)}

/* TICKER */
.ticker{
  position:fixed;top:var(--nav-h);left:0;right:0;z-index:99;
  background:var(--ticker-bg);
  border-bottom:1px solid var(--border);
  overflow:hidden;height:var(--ticker-h);
  display:flex;align-items:center;
}
.ticker-inner{
  display:flex;gap:3rem;
  animation:tickerScroll 30s linear infinite;
  white-space:nowrap;
}
.ticker-item{
  font-family:'DM Mono',monospace;
  font-size:0.7rem;letter-spacing:0.08em;
  color:var(--muted);
  display:inline-flex;align-items:center;gap:0.6rem;
}
/* Gold pip before each instrument — carries the visual rhythm the old
   up/down price colours used to provide. */
.ticker-item::before{
  content:'';
  width:4px;height:4px;border-radius:50%;
  background:var(--gold);
  opacity:0.65;
  flex-shrink:0;
}
@keyframes tickerScroll{
  0%{transform:translateX(0)}
  100%{transform:translateX(-50%)}
}

/* HERO */
.hero{
  min-height:100vh;
  display:flex;align-items:center;
  padding:var(--content-top) 4rem 4rem;
  position:relative;
  overflow:hidden;
}
.hero-orb{
  position:absolute;
  border-radius:50%;
  pointer-events:none;
  filter:blur(120px);
  opacity:0.12;
}
.hero-orb-1{
  width:700px;height:700px;
  background:radial-gradient(circle,var(--gold),transparent 70%);
  top:-200px;right:-200px;
}
.hero-orb-2{
  width:500px;height:500px;
  background:radial-gradient(circle,var(--accent),transparent 70%);
  bottom:-100px;left:-100px;
}

/* HERO CHART */
/* The chart's resting opacity is a token because it drops at both breakpoints —
   it widens to 90vw on phones and sits directly behind the headline, so it has
   to fade back to stay out of the text's way. That used to be three separate
   redefinitions of @keyframes chartReveal, which meant the reduced-motion
   fallback at the foot of this file would have needed the same three literals a
   fourth time. One token, read by the animation and by the static fallback. */
:root{--chart-opacity:0.75}
.hero-chart{
  position:absolute;
  right:2%;top:50%;
  transform:translateY(-50%);
  width:56vw;max-width:760px;
  z-index:0;
  pointer-events:none;
  opacity:0;
  animation:chartReveal 1s ease forwards 0.3s;
}
@keyframes chartReveal{to{opacity:var(--chart-opacity)}}
.chart-svg{width:100%;height:auto;display:block}

/* Grid */
.cg-grid line{stroke:var(--border);stroke-width:0.5;stroke-dasharray:4 4}

/* Price labels */
.cg-label{
  font-family:'DM Mono',monospace;font-size:8px;
  fill:var(--muted);letter-spacing:0.05em;opacity:0.7;
}

/* Breakout zone */
.cg-zone{fill:var(--gold);opacity:0.06}

/* Area fill */
.cg-area{fill:url(#areaFill)}

/* Volume bars */
.cg-vol-up{fill:var(--up)}
.cg-vol-dn{fill:var(--dn)}
.cg-vol{opacity:0;animation:volCycle 12s ease infinite 0.3s}
@keyframes volCycle{
  0%,33%{opacity:0}
  42%{opacity:0.25}
  58%{opacity:0.25}
  67%,100%{opacity:0}
}

/* Candlestick wicks */
.cg-wick-up{stroke:var(--up);stroke-width:1}
.cg-wick-dn{stroke:var(--dn);stroke-width:1}

/* Candlestick bodies */
.cg-body-up{fill:var(--up)}
.cg-body-dn{fill:var(--dn)}

/* Moving average */
.cg-ma{
  fill:none;stroke:var(--accent);stroke-width:1.2;
  opacity:0.45;
  stroke-dasharray:800;stroke-dashoffset:800;
  animation:maCycle 12s ease infinite 0.3s;
}
@keyframes maCycle{
  0%{stroke-dashoffset:800}
  25%{stroke-dashoffset:0}
  75%{stroke-dashoffset:0}
  100%{stroke-dashoffset:800}
}

/* Signal markers */
.cg-arrow-buy{fill:var(--up)}
.cg-arrow-sell{fill:var(--dn)}
.cg-sig-label{
  font-family:'DM Mono',monospace;font-size:8px;
  letter-spacing:0.1em;text-anchor:middle;
}
.cg-sig-label-buy{fill:var(--up)}
.cg-sig-label-sell{fill:var(--dn)}
.cg-sig{opacity:0;animation:sigCycle 12s ease infinite 0.3s}
.cg-sig-1{animation-delay:0.3s}
.cg-sig-2{animation-delay:0.6s}
.cg-sig-3{animation-delay:0.9s}
.cg-sig-4{animation-delay:1.2s}
@keyframes sigCycle{
  0%,25%{opacity:0}
  33%{opacity:1}
  67%{opacity:1}
  75%,100%{opacity:0}
}

.hero-content{
  position:relative;z-index:1;
  max-width:780px;
}
.hero-eyebrow{
  font-family:'DM Mono',monospace;
  font-size:0.7rem;letter-spacing:0.2em;text-transform:uppercase;
  color:var(--gold);margin-bottom:1.5rem;
  display:flex;align-items:center;gap:0.75rem;
}
.hero-eyebrow::before{
  content:'';display:block;width:32px;height:1px;background:var(--gold);
}
h1{
  font-family:'Cormorant Garamond',serif;
  font-size:clamp(3rem,7vw,6rem);
  font-weight:300;line-height:1.05;
  letter-spacing:-0.01em;
  color:var(--heading);margin-bottom:1.5rem;
}
h1 em{font-style:italic;color:var(--gold)}
.hero-sub{
  font-size:1.05rem;font-weight:300;
  color:var(--muted);max-width:520px;
  line-height:1.8;margin-bottom:2.5rem;
}
.hero-actions{display:flex;gap:1rem;flex-wrap:wrap}
.btn-primary{
  padding:0.85rem 2.25rem;
  background:var(--gold);color:var(--bg);
  font-size:0.8rem;letter-spacing:0.12em;text-transform:uppercase;
  font-weight:500;border:none;cursor:pointer;
  /* Named, not `all`. `all` includes `outline`, so the focus ring faded in over
     a quarter second — a focus indicator has to be immediate, and it is the one
     state a keyboard user needs to see the instant it lands. Hover only ever
     moves the background here. */
  transition:background 0.25s;text-decoration:none;display:inline-block;
}
.btn-primary:hover{background:var(--gold-light)}
.cta-btn-wrap{display:flex;flex-direction:column;align-items:center;gap:0.35rem}
.coming-soon{
  font-size:0.65rem;letter-spacing:0.1em;text-transform:uppercase;
  color:var(--muted);font-family:'DM Mono',monospace;
}
.btn-outline{
  padding:0.85rem 2.25rem;
  border:1px solid var(--border);color:var(--text);
  background:transparent;
  font-size:0.8rem;letter-spacing:0.12em;text-transform:uppercase;
  font-weight:300;cursor:pointer;
  /* Named for the same reason as .btn-primary above. */
  transition:border-color 0.25s,color 0.25s;text-decoration:none;display:inline-block;
}
.btn-outline:hover{border-color:var(--gold);color:var(--gold)}
.btn-inverse{
  padding:0.85rem 2.25rem;
  background:var(--heading);color:var(--bg);
  font-size:0.8rem;letter-spacing:0.12em;text-transform:uppercase;
  font-weight:500;border:1px solid var(--heading);cursor:pointer;
  transition:opacity 0.25s;text-decoration:none;display:inline-block;
}
.btn-inverse:hover{opacity:0.85;color:var(--bg)}

/* The hero's only Telegram route. The hero declares no background, so this sits
   on --bg: --gold as ink measures 5.67:1 (light) and 10.1:1 (dark) there.
   Underlined rather than colour-only, because colour alone is not a link
   affordance. Hover thickens the rule instead of moving to --gold-light —
   gold-light is a hover *fill* with white text on it, and as ink on cream it
   would drop this to 4.51:1, a hair off the floor for a hover state nobody
   audits. */
.hero-tg{
  margin-top:1.5rem;max-width:520px;
  font-size:0.9rem;font-weight:300;line-height:1.7;
  color:var(--muted);
}
.hero-tg a{
  color:var(--gold);font-weight:500;
  text-decoration:underline;text-underline-offset:0.25em;
  text-decoration-thickness:1px;
  /* Named, not `all` — see .btn-primary. */
  transition:text-decoration-thickness 0.25s;
}
.hero-tg a:hover{text-decoration-thickness:2px}

/* HERO STATS */
.hero-stats{
  display:flex;gap:2.5rem;
  margin-top:3rem;z-index:1;
}
.hero-stat{
  padding-left:1.25rem;
  border-left:1px solid var(--border);
}
.hero-stat-num{
  font-family:'Cormorant Garamond',serif;
  font-size:3rem;font-weight:600;color:var(--heading);
  line-height:1;
}
.hero-stat-num span{color:var(--gold);font-size:1.75rem;vertical-align:baseline}
.hero-stat-label{
  font-size:0.7rem;letter-spacing:0.15em;text-transform:uppercase;
  color:var(--muted);margin-top:0.35rem;
}

/* SECTION BASE */
section{position:relative;z-index:1;padding:7rem 4rem}
/* An in-page anchor has to clear the fixed chrome or it lands underneath it.
   Same token as the page top padding, so a jumped-to section comes to rest
   exactly where a freshly loaded page's content starts. */
section[id]{scroll-margin-top:var(--content-top)}
.section-tag{
  font-family:'DM Mono',monospace;
  font-size:0.7rem;letter-spacing:0.18em;text-transform:uppercase;
  color:var(--gold);margin-bottom:1rem;
}
h2{
  font-family:'Cormorant Garamond',serif;
  font-size:clamp(2.2rem,4.5vw,3.8rem);
  font-weight:300;color:var(--heading);
  line-height:1.1;letter-spacing:-0.01em;
  margin-bottom:1.25rem;
}
h2 em{font-style:italic;color:var(--gold)}
.section-alt{background:var(--bg2)}

/* MARQUEE */
.marquee-section{
  padding:2rem 0;
  border-top:1px solid var(--border);
  border-bottom:1px solid var(--border);
  overflow:hidden;
}
.marquee-inner{
  display:flex;gap:4rem;
  animation:marquee 25s linear infinite;
  white-space:nowrap;
}
.marquee-word{
  font-family:'Cormorant Garamond',serif;
  font-size:1.1rem;font-style:italic;
  color:var(--muted);letter-spacing:0.05em;
}
.marquee-dot{color:var(--gold)}
@keyframes marquee{
  0%{transform:translateX(0)}
  100%{transform:translateX(-50%)}
}

/* INDICATOR CATEGORIES GRID */
.categories-grid{
  display:grid;grid-template-columns:repeat(3,1fr);
  gap:1px;background:var(--border);border:1px solid var(--border);
  margin-top:3rem;
}
.categories-cta{margin-top:3rem;text-align:center}

/* FEATURES GRID */
.features-grid{
  display:grid;grid-template-columns:repeat(3,1fr);
  gap:1px;background:var(--border);border:1px solid var(--border);
  margin-top:3rem;
}

/* SHARED DYNA CARD */
.dyna-card{
  padding:2.5rem 2rem;background:var(--bg);
  transition:background 0.3s;
  position:relative;overflow:hidden;
}
.section-alt .dyna-card{background:var(--bg2)}
.dyna-card::before{
  content:'';position:absolute;
  top:0;left:0;right:0;height:2px;
  background:linear-gradient(90deg,transparent,var(--gold),transparent);
  opacity:0;transition:opacity 0.3s;
}
.dyna-card:hover{background:var(--bg3)}
.dyna-card:hover::before{opacity:1}
.dyna-card-icon{width:40px;height:40px;margin-bottom:1.5rem}
.dyna-card-icon svg{
  width:28px;height:28px;
  stroke:var(--gold);fill:none;stroke-width:1.5;
}
.dyna-card h3{margin-bottom:0.75rem}
.dyna-card p{font-size:0.9rem;color:var(--muted);line-height:1.8}
h3{
  font-family:'Cormorant Garamond',serif;
  font-size:1.6rem;font-weight:400;color:var(--heading);
  margin-bottom:0.75rem;line-height:1.2;
}

/* HOW IT WORKS STEPS */
.dyna-steps{
  display:grid;grid-template-columns:repeat(4,1fr);
  margin-top:3rem;
}
.dyna-step{
  padding:2.5rem 2rem;
  border:1px solid var(--border);
  margin-right:-1px;margin-bottom:-1px;
  position:relative;
}
/* The -1px pulls each step onto its neighbour's border so the shared edge is one
   line and not two. The step that *ends a row* has no neighbour to pull onto, so
   the margin just hangs its right border 1px past the grid.

   That matters because .categories-grid and .features-grid sit directly above
   and below in the same 64→1336 box, and their right rule is the *container's*
   own border, ending at 1336. The steps grid has no container border — its rule
   is the last step's right border, which the negative margin pushed out to
   1337. So the three stacked grids' right edges disagreed by exactly 1px at
   every width above 640. (Compare the painted rules, not the child boxes: the
   two border models put the child edge in different places by design.)

   The 640px block already names this and fixes only the stacked case; these two
   rules cover the other two layouts. */
.dyna-step:nth-child(4n){margin-right:0}
.step-num{
  font-family:'DM Mono',monospace;
  font-size:0.65rem;letter-spacing:0.15em;
  color:var(--muted);margin-bottom:1.5rem;
}
.step-title{
  font-family:'Cormorant Garamond',serif;
  font-size:1.3rem;color:var(--heading);margin-bottom:0.75rem;
}
.step-desc{font-size:0.85rem;color:var(--muted);line-height:1.8}
.step-connector{
  position:absolute;top:2.5rem;right:-16px;
  font-size:1.2rem;color:var(--muted);z-index:2;
}

/* SUPPORTED MARKETS */
.markets-grid{
  display:flex;flex-wrap:wrap;justify-content:center;gap:1rem;
  margin-top:3rem;
}
.market-badge{
  font-family:'DM Mono',monospace;
  font-size:0.8rem;letter-spacing:0.1em;text-transform:uppercase;
  color:var(--muted);
  border:1px solid var(--border);
  padding:0.85rem 1.75rem;
  transition:border-color 0.25s,color 0.25s;
}
.market-badge:hover{border-color:var(--gold);color:var(--gold)}

/* PRICING */
.pricing-grid{
  display:grid;grid-template-columns:1fr 1fr;
  gap:1px;background:var(--border);border:1px solid var(--border);
  margin-top:3rem;max-width:800px;margin-left:auto;margin-right:auto;
}
/* Flex column so both cards' CTAs sit on the same baseline even though Pro has
   one more feature and a note underneath. */
.pricing-card{
  padding:3rem 2.5rem;background:var(--bg);
  display:flex;flex-direction:column;
}
.pricing-card-premium{border-left:2px solid var(--gold)}
.pricing-tier-label{
  font-family:'DM Mono',monospace;
  font-size:0.7rem;letter-spacing:0.15em;text-transform:uppercase;
  color:var(--gold);margin-bottom:1rem;
}
.pricing-price{
  font-family:'Cormorant Garamond',serif;
  font-size:3.5rem;font-weight:300;color:var(--heading);
  line-height:1;margin-bottom:2rem;
}
/* "Invite Only" is words, not a number — at the 3.5rem price size it would
   wrap inside the card. */
.pricing-price-text{font-size:2.1rem;letter-spacing:-0.005em}
.pricing-features{list-style:none;display:flex;flex-direction:column;gap:0.75rem;flex:1}
.pricing-features li{
  font-size:0.9rem;color:var(--muted);line-height:1.6;
  padding-left:1.5rem;position:relative;
}
.pricing-features li::before{
  content:'';position:absolute;left:0;top:8px;
  width:6px;height:6px;border-radius:50%;
  background:var(--gold);
}
.pricing-note{
  margin-top:1.5rem;
  font-size:0.85rem;line-height:1.65;color:var(--muted);
}
/* The grid makes both cards as tall as the taller one (Pro — one more feature
   plus the note). Letting the feature list absorb that slack pushes the
   shorter card's CTA down to match, while keeping a fixed gap above it.
   align-self stops the flex column from stretching the button to full width. */
.pricing-cta{
  margin-top:2rem;
  align-self:flex-start;
}

/* CTA SECTION */
.cta-section{background:var(--bg2)}
.cta-sub{
  max-width:520px;margin:0 auto 2.5rem;
  color:var(--muted);font-size:1.05rem;line-height:1.8;
}

/* FOOTER */
footer{
  border-top:1px solid var(--border);
  padding:3rem 4rem;
  display:flex;flex-direction:column;gap:2.25rem;
}
.footer-main{display:flex;justify-content:space-between;align-items:center}
.footer-logo{
  font-family:'Cormorant Garamond',serif;
  font-size:1.2rem;font-weight:600;color:var(--heading);letter-spacing:0.04em;text-decoration:none;
  flex:1;
}
.footer-logo span{color:var(--gold)}
.footer-copy{
  font-size:0.75rem;color:var(--muted);
  letter-spacing:0.08em;flex:1;text-align:right;
}
.footer-links{display:flex;flex-wrap:wrap;gap:2rem}
.footer-links a{
  font-size:0.75rem;letter-spacing:0.1em;text-transform:uppercase;
  color:var(--muted);text-decoration:none;transition:color 0.25s;
}
.footer-links a:hover{color:var(--gold)}

/* The four outbound profiles render as marks, not words. As uppercase labels
   they were four of the row's seven items and roughly two-thirds of its width,
   which put the site's own sections (Indicators, Features, Pricing) in the
   minority in a footer whose first job is navigating the site. Icons make the
   split read correctly: words for here, marks for elsewhere.

   Inside .footer-links rather than a fourth child of .footer-main, so the
   footer's three-column space-between layout is untouched. The tighter gap is
   because 18px squares need less separation than uppercase text does; the 2rem
   parent gap still holds the marks clear of the last word link.

   fill:currentColor is what lets one colour rule theme all four glyphs in both
   themes, and it is why the paths carry no fill of their own. display:block on
   the svg kills the inline-baseline gap that would otherwise make the row a few
   pixels taller than the text beside it. */
.footer-social{display:flex;align-items:center;gap:1.1rem}
/* The padding/negative-margin pair is the tap target, not spacing: an 18px glyph
   is an 18px target, under WCAG 2.5.8's 24x24 minimum. 4px of padding takes the
   hit area to 26px and the matching -4px margin gives the pixels back to the
   layout, so the row measures exactly as it looks. The gap is 1.1rem, so the
   grown boxes still do not touch. */
.footer-social a{display:flex;padding:4px;margin:-4px;color:var(--muted);transition:color 0.25s}
.footer-social a:hover{color:var(--gold)}
.footer-social svg{display:block;width:18px;height:18px;fill:currentColor}

/* Footer legal row. The risk warning lives in the shared footer rather than only
   on disclaimer.html, because a visitor who lands on a detail page from search
   and leaves without clicking anything must still have seen it. Short enough to
   read, with the full text one link away. */
.footer-legal{
  display:flex;justify-content:space-between;align-items:flex-start;gap:2.5rem;
  border-top:1px solid var(--border);padding-top:1.75rem;
}
.footer-disclaimer{
  max-width:82ch;
  font-size:0.75rem;line-height:1.85;color:var(--muted);
}
.footer-disclaimer strong{color:var(--text);font-weight:500}
.footer-disclaimer a{
  color:var(--gold);text-decoration:none;
  border-bottom:1px dotted var(--gold);
}
.footer-disclaimer a:hover{border-bottom-style:solid}
.footer-legal-links{display:flex;gap:1.5rem;flex-shrink:0}
.footer-legal-links a{
  font-size:0.75rem;letter-spacing:0.1em;text-transform:uppercase;
  color:var(--muted);text-decoration:none;transition:color 0.25s;
  white-space:nowrap;
}
.footer-legal-links a:hover{color:var(--gold)}

/* LEGAL PAGES — disclaimer.html, privacy.html */
.page-legal{
  position:relative;z-index:1;
  max-width:820px;margin:0 auto;
  padding:var(--content-top) 4rem 6rem;
}
.legal-header{margin-bottom:3rem}
.legal-header h1{font-size:clamp(2.2rem,5vw,3.2rem);line-height:1.15;margin-top:0.75rem}
.legal-updated{
  margin-top:1rem;
  font-family:'DM Mono',monospace;font-size:0.72rem;letter-spacing:0.16em;
  text-transform:uppercase;color:var(--muted);
}
.legal-prose{color:var(--text)}
.legal-prose > * + *{margin-top:1.2rem}
.legal-prose p,.legal-prose li{font-size:0.98rem;line-height:1.9;color:var(--text)}
.legal-prose h2{
  font-family:'Cormorant Garamond',serif;
  font-size:1.6rem;font-weight:400;color:var(--heading);
  letter-spacing:-0.01em;
  margin-top:3rem;padding-top:1.75rem;
  border-top:1px solid var(--border);
}
.legal-prose h2:first-child{margin-top:0;padding-top:0;border-top:0}
.legal-prose ul{list-style:disc;padding-left:1.25rem;display:flex;flex-direction:column;gap:0.6rem}
.legal-prose li::marker{color:var(--gold)}
.legal-prose strong{color:var(--heading);font-weight:500}
.legal-prose a{color:var(--gold);text-decoration:none;border-bottom:1px dotted var(--gold)}
.legal-prose a:hover{border-bottom-style:solid}
.legal-prose code{
  font-family:'DM Mono',monospace;
  font-size:0.88em;
  padding:0.1em 0.36em;
  color:var(--gold-light);
  background:var(--bg3);
  border:1px solid var(--border);
  border-radius:4px;
  /* Hostnames and storage keys wrap mid-token rather than overflowing on mobile. */
  overflow-wrap:anywhere;
}
/* Same reason as .detail-prose code: gold-light on cream drops below body-text
   contrast, and the mono font plus the chip already read as code. */
html[data-theme="light"] .legal-prose code{color:var(--text)}
/* Pulled out of the flow of small print so it cannot be skimmed past. */
.legal-callout{
  padding:1.5rem 1.75rem;
  background:var(--bg3);border:1px solid var(--border);border-left:2px solid var(--gold);
  border-radius:4px;
}
.legal-callout p{margin:0}

/* 404 — served by Workers at any unmatched URL, so it is chrome plus a way out
   and nothing else. Top padding comes from --content-top like every other page;
   the min-height keeps the footer off the fold on a tall desktop viewport
   without pinning it, which would fight the fixed chrome. */
.page-404{
  position:relative;z-index:1;
  max-width:720px;margin:0 auto;
  padding:var(--content-top) 4rem 6rem;
  min-height:calc(100vh - var(--chrome-h) - 6rem);
  display:flex;flex-direction:column;align-items:center;justify-content:center;
  text-align:center;
}
.code-404{
  font-family:'DM Mono',monospace;
  font-size:clamp(3.5rem,12vw,6rem);line-height:1;
  color:var(--gold);letter-spacing:0.08em;
}
.page-404 h1{font-size:clamp(1.9rem,5vw,2.8rem);line-height:1.2;margin-top:1.25rem}
.lead-404{
  margin-top:1.25rem;max-width:430px;
  font-size:1rem;font-weight:300;line-height:1.8;color:var(--muted);
}
.actions-404{display:flex;gap:1rem;flex-wrap:wrap;justify-content:center;margin-top:2.25rem}
.links-404{
  display:flex;gap:1.5rem;flex-wrap:wrap;justify-content:center;
  margin-top:3rem;padding-top:2rem;border-top:1px solid var(--border);
  width:100%;list-style:none;
}
.links-404 a{
  font-family:'DM Mono',monospace;
  font-size:0.72rem;letter-spacing:0.14em;text-transform:uppercase;
  color:var(--muted);text-decoration:none;transition:color 0.25s;
}
.links-404 a:hover{color:var(--gold)}

/* SCROLL REVEAL */
.reveal{opacity:0;transform:translateY(24px);transition:opacity 0.7s ease,transform 0.7s ease}
.reveal.visible{opacity:1;transform:none}

/* LIGHT MODE OVERRIDES */
html[data-theme="light"] .hero-orb{opacity:0.08}
html[data-theme="light"] .btn-primary{color:#fff}

/* THEME TOGGLE */
.theme-toggle{
  background:none;
  border:none;
  cursor:pointer;
  padding:0;
  line-height:1;
  display:flex;
  align-items:center;
}
.toggle-track{
  position:relative;
  display:flex;
  align-items:center;
  width:52px;
  height:28px;
  background:var(--bg3);
  border:1px solid var(--muted);
  border-radius:14px;
  padding:0 4px;
  transition:background 0.3s,border-color 0.3s;
}
.theme-toggle:hover .toggle-track{
  border-color:var(--gold);
}
.toggle-icon{
  font-size:0.75rem;
  line-height:1;
  z-index:1;
  transition:opacity 0.25s;
}
.toggle-sun{
  margin-right:auto;
  opacity:0.4;
  color:var(--gold);
}
.toggle-moon{
  margin-left:auto;
  opacity:1;
  color:var(--muted);
}
.toggle-thumb{
  position:absolute;
  top:3px;
  left:3px;
  width:20px;
  height:20px;
  background:var(--gold);
  border-radius:50%;
  transition:transform 0.3s cubic-bezier(0.4,0,0.2,1);
  box-shadow:0 1px 3px rgba(0,0,0,0.3);
}
[data-theme="light"] .toggle-thumb{
  transform:translateX(24px);
}
[data-theme="light"] .toggle-sun{
  opacity:1;
}
[data-theme="light"] .toggle-moon{
  opacity:0.4;
}
[data-theme="light"] .toggle-track{
  background:var(--bg3);
}

/* ── Mid-width breakpoint ── */
/* Breakpoints below tighten the side and bottom padding only. Top padding
   comes from --content-top and must not be restated here — hand-set top
   values at each breakpoint are precisely what drifted out of sync with the
   chrome. To move content down, move the token. */
@media(max-width:1200px){
  nav{padding:0 2rem}
  /* Follows the nav's side padding so the revealed link lines up with the logo
     above it rather than floating in from an inset the layout no longer uses. */
  .skip-link{left:2rem}
  .nav-links{gap:1.5rem}
  .nav-links a{font-size:0.7rem;letter-spacing:0.08em}
  :root{--chart-opacity:0.45}
  footer{padding:3rem 2rem}
  .footer-links{gap:1.25rem}
  .page-legal{padding-inline:2.5rem;padding-bottom:5rem}
  .page-404{padding-inline:2.5rem;padding-bottom:5rem}
}

@media(max-width:900px){
  /* A shorter bar on phones, where vertical space is the scarce axis. This is
     the single edit that resizes the chrome: the ticker offset, the anchor
     scroll margin and every page's top padding all read the same token. */
  :root{--nav-h:74px;--chart-opacity:0.3}
  nav{padding:0 1.5rem;z-index:102}
  .skip-link{left:1.5rem}
  nav.menu-open{backdrop-filter:none;background:var(--bg)}
  /* The open menu is a fixed, full-viewport overlay at z-index 101, painted
     inside nav's own stacking context. Anything in the bar that must stay above
     it needs its own lift — a static child paints below a positioned sibling no
     matter what nav's z-index is. The logo was missed: it stayed in the focus
     trap's tab order (it is the wrap-around target) while being covered and
     unclickable, so a keyboard user landed on an invisible link. */
  .nav-logo,.nav-right{position:relative;z-index:102}
  .hamburger{display:flex}
  .nav-links{
    display:flex;flex-direction:column;align-items:center;justify-content:center;gap:2.5rem;
    position:fixed;top:0;left:0;right:0;bottom:0;
    background:var(--bg);
    /* visibility, not opacity alone. An invisible element is still in the tab
       order and still read by a screen reader, so the closed menu used to sit
       between the logo and the theme toggle as six phantom links. visibility
       is the only one of these three that removes it from both.
       It animates discretely but interpolates as `visible` whenever either end
       is visible, so listing it here keeps the 0.3s fade on the way out and
       drops the links from the tab order once the fade has finished — which is
       why the transition must name it explicitly rather than just opacity. */
    opacity:0;visibility:hidden;pointer-events:none;
    transition:opacity 0.3s,visibility 0.3s;
    z-index:101;
  }
  .nav-links.open{opacity:1;visibility:visible;pointer-events:auto}
  .nav-links a{font-size:1.2rem;letter-spacing:0.15em;color:var(--heading)}
  .nav-links .nav-pill{color:var(--bg)}
  section{padding:5rem 1.5rem}
  .hero{padding-inline:1.5rem;padding-bottom:3rem}
  .hero-chart{width:90vw;max-width:none;right:-10%}
  .hero-stats{gap:1.5rem;flex-wrap:wrap}
  .categories-grid{grid-template-columns:1fr 1fr}
  /* 9 category cards in 2 columns leave one empty cell, which renders as a solid
     block of the grid's --border background. Let the last card span the row. */
  .categories-grid .dyna-card:last-child{grid-column:1/-1}
  .features-grid{grid-template-columns:1fr 1fr}
  .dyna-steps{grid-template-columns:1fr 1fr}
  /* Two columns means every even step ends a row, and its connector — which
     points right, at the step beside it — has nothing to its right but the
     container edge. Rotating it down is not the fix: after step 2 comes step 3,
     which sits below-*left*, so a down arrow would aim at step 4 and assert the
     wrong reading order. The row break already reads as a wrap; the 01–04
     numbering carries the sequence, exactly as it does when they stack. */
  .dyna-step:nth-child(2n) .step-connector{display:none}
  /* Two columns move the row-ending step from 4n to 2n — see the base rule. */
  .dyna-step:nth-child(2n){margin-right:0}
  .pricing-grid{grid-template-columns:1fr}
  /* Full-bleed CTA with tighter side padding — at 390px the default 2.25rem
     padding leaves "Browse Free Indicators" too little room and it wraps to a
     second line. */
  .pricing-cta{
    align-self:stretch;
    text-align:center;
    padding-left:1rem;padding-right:1rem;
    letter-spacing:0.08em;
  }
  .markets-grid{gap:0.75rem}
  .market-badge{padding:0.65rem 1.25rem;font-size:0.7rem}
  footer{gap:1.75rem;text-align:center;padding:2rem 1.5rem}
  .footer-main{flex-direction:column;gap:1.5rem}
  .footer-links{flex-wrap:wrap;justify-content:center;gap:1rem}
  .footer-copy{text-align:center}
  .footer-legal{flex-direction:column;align-items:center;gap:1.25rem}
  .footer-legal-links{flex-wrap:wrap;justify-content:center;gap:1.25rem}
  .page-legal{padding-inline:1.25rem;padding-bottom:4rem}
  .page-404{padding-inline:1.25rem;padding-bottom:4rem}
  .actions-404 .btn-primary,.actions-404 .btn-outline{width:100%}
  .legal-prose h2{margin-top:2.5rem}
  .legal-callout{padding:1.25rem 1.25rem}
}

/* ── Phone breakpoint ── */
/* The three card grids drop to a single column here and nowhere earlier. Two
   columns still read well down to ~640px, where a card is ~290px wide; below
   that the 2rem of side padding leaves barely 200px for the text and every
   description breaks across four or five lines. One column above 640px is the
   opposite failure — a 40px icon and one line of copy stretched across the
   whole row — which is why this is a separate breakpoint and not a change to
   the 900px one. Side/bottom padding only, as above: top padding is
   --content-top's job. */
@media(max-width:640px){
  .categories-grid{grid-template-columns:1fr}
  .features-grid{grid-template-columns:1fr}
  .dyna-steps{grid-template-columns:1fr}
  /* The last-child row span exists only to fill the odd cell left by 9 cards in
     two columns. In one column there is no odd cell. */
  .categories-grid .dyna-card:last-child{grid-column:auto}
  /* The connector points right, at the card's right edge, to the step beside
     it. Stacked, there is nothing to its right — it would sit at the end of
     each step aiming off the screen. The 01–04 numbering carries the sequence
     on its own. */
  .step-connector{display:none}
  /* -1px pulls each step onto its neighbour's border so the shared edge is one
     line, not two. Vertically that's still wanted; horizontally there is no
     neighbour left, and the negative margin just hangs the right border 1px
     past the grid, out of line with the two grids above. */
  .dyna-step{margin-right:0}
}

/* ── Reduced motion ── */
/* Everything above assumes motion is welcome: two infinite marquees, a 12s
   looping chart, 13 scroll-reveals and a smooth-scrolling anchor jump. Under
   prefers-reduced-motion:reduce all of it stops — but "stopped" is not the same
   as "gone", and that distinction is the whole of this block.

   Four parts of the hero chart *arrive* through their animation from a resting
   state that is invisible: the chart wrapper at opacity:0, the volume bars at
   0, the four signal markers at 0, and the moving average with its stroke
   dashed entirely off the end of the path. Cancelling the animation and
   stopping there would delete the product demo from the page for exactly the
   users who asked for less movement. Each is restored below to the value its
   keyframes peak at, so the loop's whole story shows at once — which for a
   still image is the clearer picture anyway.

   Last block in the file on purpose: the universal rule has to outrank the
   breakpoints above it, and !important alone would not settle the two rules
   that follow it here. Catalog card hovers are handled in dyna.css, which
   loads after this file. */
@media(prefers-reduced-motion:reduce){
  /* Anchor jumps land instantly. A smooth scroll is several hundred ms of
     movement the user did not initiate and cannot interrupt. */
  html{scroll-behavior:auto}
  *,*::before,*::after{
    animation:none!important;
    transition:none!important;
    scroll-behavior:auto!important;
  }
  /* Sections are simply present. The IntersectionObserver still adds .visible,
     but this makes the resting state correct for anything it never reaches. */
  .reveal{opacity:1;transform:none}
  /* Hero chart end states, per the note above. --chart-opacity is the same
     token the animation targets, so this stays right at every breakpoint. */
  .hero-chart{opacity:var(--chart-opacity)}
  .cg-vol{opacity:0.25}        /* volCycle peak */
  .cg-sig{opacity:1}           /* sigCycle peak */
  .cg-ma{stroke-dashoffset:0}  /* maCycle fully drawn */
}
