From f41874f438b5d75579fba58b1ebb8ce84dc5ffbd Mon Sep 17 00:00:00 2001 From: nym21 Date: Wed, 3 Jun 2026 18:07:11 +0200 Subject: [PATCH] website: redesign part 6 --- ....woff2 => Lilex-Italic[wght]-v2_620.woff2} | Bin website/learn/data.js | 145 ++++++++++++++++++ website/learn/index.js | 32 ++-- website/learn/style.css | 98 ++++++++++-- website/main.js | 2 +- website/styles/fonts.css | 1 + 6 files changed, 255 insertions(+), 23 deletions(-) rename website/assets/fonts/{Lilex-Italic[wght]-v2_620.woff2.woff2 => Lilex-Italic[wght]-v2_620.woff2} (100%) diff --git a/website/assets/fonts/Lilex-Italic[wght]-v2_620.woff2.woff2 b/website/assets/fonts/Lilex-Italic[wght]-v2_620.woff2 similarity index 100% rename from website/assets/fonts/Lilex-Italic[wght]-v2_620.woff2.woff2 rename to website/assets/fonts/Lilex-Italic[wght]-v2_620.woff2 diff --git a/website/learn/data.js b/website/learn/data.js index 19a04c4cd..6b55ebd2b 100644 --- a/website/learn/data.js +++ b/website/learn/data.js @@ -144,4 +144,149 @@ export const sections = [ }, ], }, + { + title: "Ownership", + description: + "How coins are held across balances, entities, custody patterns, and long-term cohorts.", + chart: "Ownership overview", + children: [ + { + title: "Balances", + description: + "Address and entity balances grouped by size, concentration, and historical change.", + chart: "Balance cohorts", + children: [], + }, + { + title: "Entities", + description: + "Estimated ownership clusters and how their behavior changes through market regimes.", + chart: "Entity supply", + children: [], + }, + { + title: "Custody", + description: + "Coins associated with exchanges, funds, miners, and other observable custody groups.", + chart: "Custody balances", + children: [], + }, + ], + }, + { + title: "Liquidity", + description: + "How available supply changes as coins move between liquid, illiquid, and exchange venues.", + chart: "Liquidity overview", + children: [ + { + title: "Liquid Supply", + description: + "Coins held by entities that tend to spend, trade, or redistribute frequently.", + chart: "Liquid supply", + children: [], + }, + { + title: "Illiquid Supply", + description: + "Coins held by entities with low spending history and stronger accumulation behavior.", + chart: "Illiquid supply", + children: [], + }, + { + title: "Exchange Flow", + description: + "Deposits, withdrawals, and balance changes across known exchange clusters.", + chart: "Exchange netflow", + children: [], + }, + ], + }, + { + title: "Risk", + description: + "Stress, leverage, drawdown, and valuation conditions that shape market fragility.", + chart: "Risk overview", + children: [ + { + title: "Drawdown", + description: + "Distance from prior highs and the depth of cycle retracements over time.", + chart: "Drawdown", + children: [], + }, + { + title: "Stress", + description: + "Periods where losses, volatility, and fee pressure concentrate together.", + chart: "Network stress", + children: [], + }, + { + title: "Leverage", + description: + "Market conditions that indicate amplified exposure and forced positioning risk.", + chart: "Leverage proxy", + children: [], + }, + ], + }, + { + title: "Cycles", + description: + "How Bitcoin behaves across halvings, adoption waves, liquidity regimes, and market phases.", + chart: "Cycle overview", + children: [ + { + title: "Halvings", + description: + "Supply issuance changes and their relationship to market and miner behavior.", + chart: "Halving cycles", + children: [], + }, + { + title: "Phases", + description: + "Bull, bear, recovery, and transition periods described through on-chain behavior.", + chart: "Cycle phases", + children: [], + }, + { + title: "Comparisons", + description: + "Cycle-to-cycle comparisons normalized by time, price, drawdown, or supply behavior.", + chart: "Cycle comparison", + children: [], + }, + ], + }, + { + title: "Cohorts", + description: + "Groups of market participants organized by age, balance, cost basis, and observed behavior.", + chart: "Cohort overview", + children: [ + { + title: "Short Term", + description: + "Recently moved coins and holders more sensitive to price, volatility, and liquidity.", + chart: "Short-term holder supply", + children: [], + }, + { + title: "Long Term", + description: + "Older coins and holders with stronger dormancy, conviction, or lower spend frequency.", + chart: "Long-term holder supply", + children: [], + }, + { + title: "Cost Basis", + description: + "Estimated acquisition prices across cohorts and how they frame profit and loss.", + chart: "Cohort cost basis", + children: [], + }, + ], + }, ]; diff --git a/website/learn/index.js b/website/learn/index.js index 213418fec..27867e702 100644 --- a/website/learn/index.js +++ b/website/learn/index.js @@ -81,9 +81,12 @@ function createContents() { return nav; } -/** @param {HTMLElement} main */ -function initScrollSpy(main) { - const titles = [...main.querySelectorAll("h1[id], h2[id]")]; +/** + * @param {HTMLElement} main + * @param {HTMLElement} article + */ +function initScrollSpy(main, article) { + const titles = [...article.querySelectorAll("h1[id], h2[id]")]; const visible = new Set(); const links = new Map( [...main.querySelectorAll('nav a[href^="#"]')].map((link) => [ @@ -108,16 +111,19 @@ function initScrollSpy(main) { current = hash; } - const observer = new IntersectionObserver((entries) => { - for (const entry of entries) { - if (entry.isIntersecting) { - visible.add(entry.target.id); - } else { - visible.delete(entry.target.id); + const observer = new IntersectionObserver( + (entries) => { + for (const entry of entries) { + if (entry.isIntersecting) { + visible.add(entry.target.id); + } else { + visible.delete(entry.target.id); + } } - } - update(); - }); + update(); + }, + { root: article }, + ); for (const title of titles) { observer.observe(title); @@ -134,7 +140,7 @@ export function createLearnPage() { } main.append(article, createContents()); - initScrollSpy(main); + initScrollSpy(main, article); return main; } diff --git a/website/learn/style.css b/website/learn/style.css index 12536a6ea..32a0d492c 100644 --- a/website/learn/style.css +++ b/website/learn/style.css @@ -1,27 +1,59 @@ main.learn { + --sticky-h: 5rem; + --sidebar-top: 6rem; + --sidebar-bottom: 1rem; + display: grid; grid-template-columns: minmax(0, 1fr) 14rem; + grid-template-rows: minmax(0, 1fr); gap: 4rem; - padding: 8rem 2rem 6rem; + overflow: hidden; article { - width: min(100%, 52rem); - justify-self: center; + position: relative; + counter-reset: theme; + min-width: 0; + min-height: 0; + overflow: auto; + scroll-behavior: smooth; + scrollbar-gutter: stable; + + &::before { + content: ""; + position: sticky; + top: 0; + z-index: 2; + display: block; + width: min(100%, 52rem); + height: var(--sticky-h); + margin-inline: auto; + margin-bottom: calc(-1 * var(--sticky-h)); + background: var(--black); + pointer-events: none; + } + + > section { + counter-increment: theme; + counter-reset: topic; + width: min(100%, 52rem); + margin-inline: auto; + } > section + section { margin-top: 8rem; } section section { + counter-increment: topic; margin-top: 4rem; } } h1, h2 { - font-weight: 400; + position: sticky; + background: var(--black); line-height: 1; - scroll-margin-top: 6rem; a { position: relative; @@ -30,7 +62,6 @@ main.learn { text-decoration: none; &::before { - content: "#"; position: absolute; top: 50%; right: 100%; @@ -57,11 +88,30 @@ main.learn { } h1 { + z-index: 3; + top: var(--sticky-h); + scroll-margin-top: var(--sticky-h); + padding-bottom: 0.5rem; + border-bottom: 1px solid var(--dark-gray); font-size: 2.75rem; + + a::before { + content: counter(theme, upper-roman) ". "; + } } h2 { + z-index: 1; + top: var(--sticky-h); + scroll-margin-top: var(--sticky-h); + padding-top: 3.5rem; + padding-bottom: 0.5rem; + border-bottom: 1px dashed var(--dark-gray); font-size: 1.5rem; + + a::before { + content: counter(topic) ". "; + } } p { @@ -89,9 +139,12 @@ main.learn { } > nav { - position: sticky; - top: 6rem; - align-self: start; + counter-reset: content-theme; + min-height: 0; + overflow: auto; + scrollbar-gutter: stable; + padding-top: var(--sidebar-top); + padding-bottom: var(--sidebar-bottom); font-size: var(--font-size-xs); line-height: var(--line-height-sm); text-transform: uppercase; @@ -102,12 +155,21 @@ main.learn { padding: 0; } + > ol > li { + counter-increment: content-theme; + counter-reset: content-topic; + } + ol ol { margin-top: 0.5rem; margin-left: 1rem; color: var(--gray); } + ol ol > li { + counter-increment: content-topic; + } + li + li { margin-top: 0.5rem; } @@ -116,9 +178,27 @@ main.learn { color: inherit; text-decoration: none; + &::before { + opacity: 0.5; + } + &:hover { color: var(--orange); } } + + > ol > li > a::before { + content: counter(content-theme, upper-roman) ". "; + } + + ol ol > li > a::before { + content: counter(content-topic) ". "; + } + } +} + +@media (prefers-reduced-motion: reduce) { + main.learn article { + scroll-behavior: auto; } } diff --git a/website/main.js b/website/main.js index 373c265a4..5987b96df 100644 --- a/website/main.js +++ b/website/main.js @@ -27,7 +27,7 @@ function normalizePath(pathname) { function updateCurrentLink(pathname) { const currentPath = normalizePath(pathname); - for (const link of document.querySelectorAll("nav a")) { + for (const link of document.querySelectorAll("body > header > nav a")) { const linkPath = new URL(/** @type {HTMLAnchorElement} */ (link).href) .pathname; diff --git a/website/styles/fonts.css b/website/styles/fonts.css index c724514f9..a2989d984 100644 --- a/website/styles/fonts.css +++ b/website/styles/fonts.css @@ -46,6 +46,7 @@ h1, h2, h3 { font-family: var(--font-serif); + font-weight: 400; } code {