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

html,
body {
  height: 100%;
  background: #000;
  color: #e6e6e6;
  font-family: -apple-system, BlinkMacSystemFont, "Inter", "Helvetica Neue", Helvetica, Arial, sans-serif;
  font-feature-settings: "tnum" 1, "ss01" 1;
  -webkit-font-smoothing: antialiased;
  overflow: hidden;
}

#container {
  display: flex;
  flex-direction: column;
  /* Fallback for browsers without dvh support. */
  height: 100vh;
  /* Dynamic viewport height tracks the visible area as mobile browser
     chrome (Safari address bar, Chrome bottom bar) shows/hides, so the
     chart's x-axis row never gets clipped. */
  height: 100dvh;
  width: 100vw;
  padding: 24px 24px;
  /* Respect the iPhone home-bar / Android nav-bar safe area so the
     x-axis values stay above the OS UI on mobile. */
  padding-bottom: max(24px, env(safe-area-inset-bottom));
  gap: 24px;
  /* When the sidepanel is open, content shifts right so the chart isn't
     covered. Same timing/curve as the sidepanel slide-in for a unified
     animation. */
  transition: padding-left 150ms ease-out;
}

/* When the sidepanel is open the chart shrinks rather than being
   overlaid. The sidepanel sits 16px from the viewport's left edge and is
   340px wide; we add a 16px gap between it and the chart, so the chart's
   left edge needs to start at 16 + 340 + 16 = 372px. */
body.sidepanel-open #container {
  padding-left: calc(340px + 32px);
}

/* Top-left toggle is only shown when the sidepanel is closed. While it's
   open, the panel itself (and its × button) is the way to close it. */
body.sidepanel-open .icon-btn-tl {
  display: none;
}

#header {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  height: 48px;
}

.brand {
  display: flex;
  /* Align children on their text baseline so the smaller "About" link sits
     on the same baseline as the BTC HISTORICA wordmark. The dot has no
     text baseline of its own — `align-self: center` (below) re-centers it
     against the wordmark. */
  align-items: baseline;
  gap: 10px;
  position: fixed;
  /* Center vertically on the 48px header (which sits inside #container's
     24px top padding → vertical midline at y = 24 + 24 = 48px). */
  top: 48px;
  left: 28px;
  transform: translateY(-50%);
  z-index: 10;
  pointer-events: none;
}

.brand .dot {
  width: 7px;
  height: 7px;
  background: #fff;
  border-radius: 50%;
  box-shadow: 0 0 8px rgba(255, 255, 255, 0.6);
  /* Override the parent's baseline alignment so the dot stays vertically
     centered against the wordmark instead of dropping to the baseline. */
  align-self: center;
}

.brand .title {
  font-size: 21px;
  font-weight: 600;
  letter-spacing: 4px;
  color: #fff;
}

/* The brand row is `pointer-events: none` so the dot + title don't
   intercept clicks; the About link opts back into pointer events. */
.brand-link {
  margin-left: 16px;
  color: #555;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 1.5px;
  text-transform: uppercase;
  text-decoration: none;
  cursor: pointer;
  pointer-events: auto;
  transition: color 120ms ease;
}

.brand-link:hover {
  color: #cfcfcf;
}

/* Header action group (Start/Pause/Resume + Reload) — pinned to the
   viewport center so its position is independent of #container's
   padding-left shift when the sidepanel opens. */
.header-actions {
  position: fixed;
  top: 48px;
  /* see .brand for vertical midline math */
  left: 50%;
  transform: translate(-50%, -50%);
  display: flex;
  align-items: center;
  gap: 8px;
  z-index: 30;
}

.primary-btn,
.tertiary-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  box-sizing: border-box;
  height: 32px;
  padding: 0 16px 0 12px;
  border-radius: 2px;
  font-family: inherit;
  font-size: 11px;
  font-weight: 600;
  line-height: 1;
  letter-spacing: 1.5px;
  text-transform: uppercase;
  cursor: pointer;
  transition: background 120ms ease, color 120ms ease, border-color 120ms ease;
}

.primary-btn svg,
.tertiary-btn svg {
  width: 14px;
  height: 14px;
  display: block;
}

.primary-btn {
  background: #ffffff;
  color: #000000;
  border: 1px solid #ffffff;
}

.primary-btn:hover {
  background: #e6e6e6;
  border-color: #e6e6e6;
}

.primary-btn:active {
  background: #cfcfcf;
  border-color: #cfcfcf;
}

/* Ghost button — no visible border, transparent background, picks up a
   subtle white wash on hover/press. */
.tertiary-btn {
  background: transparent;
  color: #ffffff;
  border: 1px solid transparent;
}

.tertiary-btn:hover {
  background: rgba(255, 255, 255, 0.06);
}

.tertiary-btn:active {
  background: rgba(255, 255, 255, 0.14);
}

.primary-btn .icon-pause {
  display: none;
}

.primary-btn.playing .icon-play {
  display: none;
}

.primary-btn.playing .icon-pause {
  display: block;
}

.legend .sep {
  color: #333;
}

.hint {
  font-size: 11px;
  line-height: 1.5rem;
  color: #555;
  letter-spacing: 1px;
  text-transform: uppercase;
}

#chart-wrap {
  flex: 1 1 auto;
  position: relative;
  min-height: 0;
  /* border: 1px solid #111; */
  border-radius: 2px;
  overflow: hidden;
  background: #000;
  /* Force a stacking context so the LightweightCharts canvas (which is
     promoted to its own compositor layer) and #event-overlay paint into
     the same layer — required for backdrop-filter on the overlay to
     sample the chart pixels behind it. */
  isolation: isolate;
}

#chart {
  position: absolute;
  inset: 0;
}

/* During playback the crosshair is driven programmatically — block mouse
   hover on the chart canvas so a stray cursor doesn't override it. */
body.playback #chart {
  pointer-events: none;
}

/* Mask that hides the future portion of the chart line during playback.
   JS sets `left`/`right` to cover everything from the current playback
   x-coordinate to the right edge of the plot area (price-axis numbers
   stay visible). The chart's full data is always loaded so the price
   scale stays at the page-load range. */
#playback-mask {
  position: absolute;
  top: 0;
  bottom: 0;
  background: rgba(0, 0, 0, 0.8);
  pointer-events: none;
  z-index: 7;
}

#playback-mask.hidden {
  display: none;
}

/* Genesis-block "explosion": a small radial burst of 8 white lines drawn
   on top of the genesis dot when playback starts. JS positions the
   container at the dot's coordinates; Motion animates each line from a
   collapsed scaleX(0) outwards to scaleX(1) while fading. */
.explosion {
  position: absolute;
  width: 0;
  height: 0;
  pointer-events: none;
  z-index: 9;
}

.explosion.hidden {
  display: none;
}

.explosion-line {
  position: absolute;
  top: 0;
  left: 0;
  width: 0;
  height: 1.25px;
  background: #ffffff;
  /* Anchor the line so its inner end is offset from the burst origin —
     gives a short empty gap at the center, like sparks flying outward. */
  transform-origin: 0 50%;
  transform: rotate(var(--angle)) translateX(2px);
  opacity: 0;
  box-shadow: 0 0 6px rgba(255, 255, 255, 0.85);
}

#event-overlay {
  position: absolute;
  left: 0;
  bottom: 80px;
  padding: 16px;
  background: rgba(0, 0, 0, 0.1);
  backdrop-filter: blur(18px);
  -webkit-backdrop-filter: blur(18px);
  pointer-events: none;
  /* Hug content horizontally; max-width is set inline from JS (560px) so
     the overlay's right edge sits flush with the 24px gap to the hover
     line when flipped, and the title text never leaves a trailing gap. */
  width: max-content;
  z-index: 10;
  transition: opacity 220ms ease, left 60ms linear;
}

#event-overlay.hidden {
  opacity: 0;
}

.event-date {
  font-size: 10px;
  color: #888;
  letter-spacing: 2px;
  text-transform: uppercase;
  margin-bottom: 8px;
}

.event-title {
  font-size: 48px;
  line-height: 1.25;
  font-weight: 500;
  color: #ffffff;
  /* Clamp to max 3 lines */
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

#price-label {
  position: absolute;
  right: 0;
  top: 0;
  transform: translateY(-50%);
  background: #ffffff;
  color: #000000;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.5px;
  font-variant-numeric: tabular-nums;
  /* Padding-left matches lightweight-charts' internal padding for the
     y-axis tick labels (border + tick mark + small text margin) so the
     label's text left edge sits in the exact same column as the y-axis
     numbers when JS positions the box at the price-scale td's left
     edge. */
  padding: 3px 8px;
  pointer-events: none;
  z-index: 11;
  white-space: nowrap;
  box-shadow: 0 0 0 1px #000;
  transition: opacity 80ms ease;
}

#price-label.hidden {
  opacity: 0;
}

#date-label {
  position: absolute;
  left: 0;
  bottom: 0;
  transform: translateX(-50%);
  background: #ffffff;
  color: #000000;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.5px;
  font-variant-numeric: tabular-nums;
  padding: 3px 8px;
  pointer-events: none;
  z-index: 11;
  white-space: nowrap;
  box-shadow: 0 0 0 1px #000;
  transition: opacity 80ms ease;
}

#date-label.hidden {
  opacity: 0;
}

/* Top-right chart-type toggle */
.chart-toggle {
  position: fixed;
  /* Centered on the header's vertical midline (see .brand). */
  top: 48px;
  right: 28px;
  transform: translateY(-50%);
  display: flex;
  gap: 4px;
  z-index: 30;
}

.toggle-btn {
  width: 32px;
  height: 32px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: transparent;
  border: 1px solid #2a2a2a;
  color: #ffffff;
  cursor: pointer;
  padding: 0;
  border-radius: 2px;
  transition: background 120ms ease, color 120ms ease, border-color 120ms ease;
}

.toggle-btn:hover {
  border-color: #555;
}

.toggle-btn.selected {
  background: #ffffff;
  color: #000000;
  border-color: #ffffff;
}

.toggle-btn svg {
  display: block;
  width: 16px;
  height: 16px;
}

/* Centered hint overlay shown until user hovers an event */
.hint-overlay {
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  font-size: 12px;
  letter-spacing: 3px;
  text-transform: uppercase;
  color: #888;
  pointer-events: none;
  z-index: 5;
  text-align: center;
  white-space: nowrap;
  transition: opacity 400ms ease;
}

.hint-overlay.fade {
  opacity: 0;
}

body.sidepanel-open .hint-overlay {
  left: calc(50% + 170px);
}

/* Sidepanel toggle — anchored inside the canvas at the top-left corner. */
.icon-btn-tl {
  position: absolute;
  top: 16px;
  left: 16px;
  z-index: 30;
}

/* Floating left sidepanel — overlays the chart, doesn't resize it.
   Anchored to match the chart's bounds: 16px from the left edge of the
   viewport, top/bottom aligned with #chart-wrap (header height +
   #container's top/bottom padding). Frosted-glass backdrop keeps the
   chart faintly visible behind the panel. */
.sidepanel {
  position: fixed;
  /* Top/bottom match #chart-wrap so the panel is the same height as the
     chart. #container has 24px top + bottom padding and a 24px gap; the
     header is 48px → chart-wrap starts at 24+48+24 = 96px and ends 24px
     from the viewport bottom. */
  top: 96px;
  bottom: 24px;
  left: 16px;
  width: 340px;
  max-width: calc(100vw - 32px);
  background: transparent;
  border: 1px solid #1a1a1a;
  border-radius: 2px;
  overflow: hidden;
  transform: translateX(calc(-100% - 16px));
  /* Same timing/curve as the previous push-aside layout for consistency. */
  transition: transform 150ms ease-out;
  z-index: 40;
  color: #e6e6e6;
  display: flex;
  flex-direction: column;
}

/* Backdrop layer is a pseudo-element so the parent's `transform` (used for
   the slide animation) doesn't suppress backdrop-filter rendering — a known
   Chromium quirk when both live on the same element. */
.sidepanel::before {
  content: "";
  position: absolute;
  inset: 0;
  background: rgba(10, 10, 10, 0.5);
  backdrop-filter: blur(18px) saturate(140%);
  -webkit-backdrop-filter: blur(18px) saturate(140%);
  z-index: -1;
}

.sidepanel.open {
  transform: translateX(0);
}

.sidepanel-header {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 16px;
  border-bottom: 1px solid #181818;
}

.sidepanel-title {
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 3px;
  color: #888;
  text-transform: uppercase;
}

.sidepanel-close {
  width: 32px;
  height: 32px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: transparent;
  border: none;
  border-radius: 2px;
  color: #888;
  font-size: 18px;
  line-height: 1;
  cursor: pointer;
  padding: 0;
  transition: background 120ms ease, color 120ms ease;
}

.sidepanel-close:hover {
  background: rgba(255, 255, 255, 0.06);
  color: #fff;
}

.sidepanel-close:active {
  background: rgba(255, 255, 255, 0.14);
  color: #fff;
}

.suggestion-list-wrap {
  flex: 1 1 auto;
  position: relative;
  overflow-y: auto;
  scrollbar-width: thin;
  scrollbar-color: #2a2a2a transparent;
}

.suggestion-list-wrap::-webkit-scrollbar {
  width: 4px;
}

.suggestion-list-wrap::-webkit-scrollbar-track {
  background: transparent;
}

.suggestion-list-wrap::-webkit-scrollbar-thumb {
  background: #2a2a2a;
  border-radius: 2px;
}

.suggestion-list-wrap::-webkit-scrollbar-thumb:hover {
  background: #555;
}

.suggestion-list {
  list-style: none;
  padding: 0;
  margin: 0;
}

.suggestion-item {
  padding: 14px 24px;
  border-bottom: 1px solid #181818;
  display: flex;
  flex-direction: column;
  gap: 24px;
}

.suggestion-text {
  font-size: 16px;
  font-weight: 600;
  line-height: 1.4;
  color: #e6e6e6;
  word-break: break-word;
}

.suggestion-controls {
  display: flex;
  align-items: center;
  gap: 8px;
}

.vote-btn {
  background: transparent;
  border: 1px solid #2a2a2a;
  color: #888;
  width: 24px;
  height: 24px;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  font-size: 11px;
  border-radius: 2px;
  transition: color 120ms ease, border-color 120ms ease, background 120ms ease;
  padding: 0;
}

.vote-btn:hover:not(:disabled) {
  color: #fff;
  border-color: #555;
}

.vote-btn:disabled {
  cursor: default;
}

.vote-btn.voted-up {
  color: #4caf50;
  border-color: #4caf50;
}

.vote-btn.voted-down {
  color: #e53935;
  border-color: #e53935;
}

.suggestion-score {
  font-size: 12px;
  font-variant-numeric: tabular-nums;
  color: #aaa;
  min-width: 22px;
  text-align: center;
}

.suggest-form {
  flex: 0 0 auto;
  padding: 24px 20px;
  border-top: 1px solid #181818;
  display: flex;
  align-items: flex-end;
  gap: 8px;
}

.suggest-input {
  flex: 1;
  min-width: 0;
  background: #0a0a0a;
  border: 1px solid #2a2a2a;
  color: #fff;
  height: 48px;
  padding: 12px 12px;
  font-size: 16px;
  font-family: inherit;
  outline: none;
  border-radius: 2px;
  transition: border-color 120ms ease;
  resize: none;
  overflow: hidden;
  line-height: 1.4;
  min-height: 44px;
}

.suggest-input:focus {
  border-color: #555;
}

.suggest-input::placeholder {
  color: #555;
}

/* Briefly applied by JS when an attempted suggestion is rejected (e.g.
   profanity filter, network error). The error message is shown via the
   placeholder text — the border tint is the visual cue. */
.suggest-input--error {
  border-color: #b85c5c;
}

.suggest-input--error::placeholder {
  color: #b85c5c;
}

.suggest-submit {
  background: #ffffff;
  color: #000;
  height: 48px;
  border: none;
  font-size: 12px;
  letter-spacing: 1.5px;
  text-transform: uppercase;
  padding: 0 14px;
  cursor: pointer;
  font-weight: 600;
  border-radius: 2px;
  transition: background 120ms ease, opacity 120ms ease;
}

.suggest-submit:hover:not(:disabled) {
  background: #ddd;
}

.suggest-submit:disabled {
  opacity: 0.35;
  cursor: default;
}

.empty-state {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  color: #555;
  font-size: 16px;
  letter-spacing: 1.5px;
  text-transform: uppercase;
  text-align: center;
  pointer-events: none;
  line-height: 1.7;
}

.empty-state.hidden {
  display: none;
}

#hover-h-line {
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  height: 1px;
  /* Dashed pattern: 5px dash + 5px gap = 10px stride. */
  background-image: linear-gradient(to right, #5a5a5a 50%, transparent 50%);
  background-size: 10px 1px;
  background-repeat: repeat-x;
  pointer-events: none;
  /* Above the playback mask (z-index 7) so the dotted price line stays
     visible across the chart during playback. */
  z-index: 8;
  transform: translateY(-0.5px);
  transition: opacity 80ms ease;
}

#hover-h-line.hidden {
  opacity: 0;
}

#event-dots {
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 6;
}

.event-dot {
  position: absolute;
  background: rgba(255, 255, 255, .65);
  border-radius: 50%;
  transform: translateX(-50%);
  box-shadow: 0 0 6px rgba(255, 255, 255, 0.45);
  /* width / height are set in JS to match the candle width */
}

.event-dot.halving {
  background: rgba(247, 147, 26, .75);
  box-shadow: 0 0 8px rgba(247, 147, 26, 0.65);
}

#footer {
  display: flex;
  justify-content: space-between;
  font-size: 10px;
  color: #555;
  letter-spacing: 1px;
}

#hover-readout {
  font-variant-numeric: tabular-nums;
  color: #888;
}

/* About modal — white card on a dark scrim, soft white outer glow. */
.modal {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: flex;
  align-items: center;
  justify-content: center;
}

.modal.hidden {
  display: none;
}

.modal-overlay {
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, 0.5);
  width: 100%;
  height: 100%;
}

.modal-content {
  position: relative;
  background: #ffffff;
  color: #000000;
  border-radius: 4px;
  /* Cap the card at 560px wide but never exceed the viewport (with a
     16px breathing margin on each side). On narrow screens this lets
     the card shrink instead of forcing horizontal scroll. */
  width: 560px;
  max-width: calc(100vw - 32px);
  padding: 24px 24px;
  /* Soft white blurred glow around the card. */
  box-shadow: 0 0 32px 0 rgba(255, 255, 255, 0.18);
}

.modal-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
}

.modal-title {
  font-size: 22px;
  font-weight: 600;
  letter-spacing: 2px;
  text-transform: uppercase;
  color: #000000;
}

.modal-body {
  margin-top: 20px;
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.modal-text {
  font-size: 13px;
  line-height: 1.6;
  color: #333333;
}

.modal-credit {
  font-size: 13px;
  font-weight: 700;
  color: #000000;
}

/* Same shape + behavior as the sidepanel close button, but tuned for a
   white background (dark icon, dark hover/press wash). */
.modal-close {
  width: 32px;
  height: 32px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: transparent;
  border: none;
  border-radius: 2px;
  color: #888;
  font-size: 18px;
  line-height: 1;
  cursor: pointer;
  padding: 0;
  transition: background 120ms ease, color 120ms ease;
}

.modal-close:hover {
  background: rgba(0, 0, 0, 0.06);
  color: #000;
}

.modal-close:active {
  background: rgba(0, 0, 0, 0.14);
  color: #000;
}

/* Override TradingView crosshair styling — handled in JS, but add subtle touches */

/* ------------------------------------------------------------------------
   Mobile layout (≤ 640px)
   - Container padded 16px on both sides.
   - Navbar stacks vertically: wordmark on top, About link beneath it,
     then the primary + secondary buttons.
   - Chart-toggle pinned to the chart's top-right (it would otherwise
     collide with the stacked header that grows in height).
   - Sidepanel covers the chart instead of pushing it; close it to see
     the chart again.
   - The container's height: 100dvh + padding-bottom: env(safe-area-inset-
     bottom) (set globally above) keep the x-axis off the browser UI.
------------------------------------------------------------------------ */
@media (max-width: 640px) {
  #container {
    padding: 16px;
    padding-bottom: max(16px, env(safe-area-inset-bottom));
    gap: 24px;
  }

  body.sidepanel-open #container {
    /* Don't try to fit the chart next to a 340px sidepanel on a 375px
       screen — let the floating sidepanel overlay the chart instead. */
    padding-left: 16px;
  }

  /* Stack header items vertically: wordmark row, About link row,
     buttons row. `position: relative` so the chart-toggle (declared
     below) can anchor to the header's top-right corner. */
  #header {
    position: relative;
    flex-direction: column;
    align-items: flex-start;
    height: auto;
    gap: 8px;
  }

  /* Brand: enable wrap so the About link drops to its own row beneath
     the wordmark. */
  .brand {
    position: static;
    transform: none;
    pointer-events: auto;
    flex-wrap: wrap;
    align-items: center;
  }

  .brand-link {
    flex-basis: 100%;
    /* Indent under the wordmark (dot 7px + flex gap 10px = 17px). */
    margin-left: 17px;
  }

  /* Header actions row sits below the brand in the column flow. */
  .header-actions {
    position: static;
    transform: none;
  }

  /* Chart-toggle lives inside the header. On mobile anchor it to the
     header's top-right so it sits alongside the wordmark row while the
     About link and primary/secondary buttons stack beneath it. Desktop
     keeps the original position: fixed (which ignores the DOM parent). */
  .chart-toggle {
    position: absolute;
    top: 0;
    right: 0;
    transform: none;
  }

  /* On mobile the sidepanel takes nearly the full viewport — the 340px
     desktop width would leave no room for the chart. */
  .sidepanel {
    top: 16px;
    bottom: max(16px, env(safe-area-inset-bottom));
    left: 16px;
    right: 16px;
    width: auto;
    max-width: none;
  }

  /* Hide the "Hover the chart…" hint on touch — it can't be acted on. */
  .hint-overlay {
    display: none;
  }

  /* Shrink the event-overlay headline so it fits inside the narrower
     plot area. The JS that sizes the overlay already caps to the
     chart-wrap's available width, so the box itself can't overflow. */
  .event-title {
    font-size: 24px;
  }
}