website: snap

This commit is contained in:
nym21
2026-04-19 17:13:47 +02:00
parent fd2b93367d
commit a5d3be465e
13 changed files with 247 additions and 186 deletions

View File

@@ -108,15 +108,14 @@ pub fn generate_main_client(
writeln!(output, " constructor(options) {{").unwrap();
writeln!(output, " super(options);").unwrap();
writeln!(output, " /** @type {{SeriesTree}} */").unwrap();
writeln!(output, " this.series = this._buildTree('');").unwrap();
writeln!(output, " this.series = this._buildTree();").unwrap();
writeln!(output, " }}\n").unwrap();
writeln!(output, " /**").unwrap();
writeln!(output, " * @private").unwrap();
writeln!(output, " * @param {{string}} basePath").unwrap();
writeln!(output, " * @returns {{SeriesTree}}").unwrap();
writeln!(output, " */").unwrap();
writeln!(output, " _buildTree(basePath) {{").unwrap();
writeln!(output, " _buildTree() {{").unwrap();
writeln!(output, " return {{").unwrap();
let mut generated = BTreeSet::new();
generate_tree_initializer(

View File

@@ -1936,7 +1936,7 @@ impl ActivityOutputsRealizedSupplyUnrealizedPattern2 {
/// Pattern struct for repeated tree structure.
pub struct BlockChangeCumulativeDeltaSumPattern {
pub block: CentsUsdPattern4,
pub change_1m: ToPattern2,
pub change_1m: ToPattern,
pub cumulative: CentsUsdPattern,
pub delta: AbsoluteRatePattern2,
pub sum: _1m1w1y24hPattern5,
@@ -1947,7 +1947,7 @@ impl BlockChangeCumulativeDeltaSumPattern {
pub fn new(client: Arc<BrkClientBase>, acc: String) -> Self {
Self {
block: CentsUsdPattern4::new(client.clone(), _m(&acc, "realized_pnl")),
change_1m: ToPattern2::new(client.clone(), _m(&acc, "pnl_change_1m_to")),
change_1m: ToPattern::new(client.clone(), _m(&acc, "pnl_change_1m_to")),
cumulative: CentsUsdPattern::new(client.clone(), _m(&acc, "realized_pnl_cumulative")),
delta: AbsoluteRatePattern2::new(client.clone(), _m(&acc, "realized_pnl_delta")),
sum: _1m1w1y24hPattern5::new(client.clone(), _m(&acc, "realized_pnl_sum")),
@@ -3174,16 +3174,16 @@ impl InPattern2 {
/// Pattern struct for repeated tree structure.
pub struct InPattern {
pub in_loss: ToPattern,
pub in_profit: ToPattern,
pub in_loss: SharePattern,
pub in_profit: SharePattern,
}
impl InPattern {
/// Create a new pattern node with accumulated series name.
pub fn new(client: Arc<BrkClientBase>, acc: String) -> Self {
Self {
in_loss: ToPattern::new(client.clone(), _m(&acc, "loss_to_own")),
in_profit: ToPattern::new(client.clone(), _m(&acc, "profit_to_own")),
in_loss: SharePattern::new(client.clone(), _m(&acc, "loss_share")),
in_profit: SharePattern::new(client.clone(), _m(&acc, "profit_share")),
}
}
}
@@ -3243,12 +3243,12 @@ pub struct SdSmaPattern {
}
/// Pattern struct for repeated tree structure.
pub struct ToPattern2 {
pub struct ToPattern {
pub to_mcap: BpsPercentRatioPattern,
pub to_rcap: BpsPercentRatioPattern,
}
impl ToPattern2 {
impl ToPattern {
/// Create a new pattern node with accumulated series name.
pub fn new(client: Arc<BrkClientBase>, acc: String) -> Self {
Self {
@@ -3301,15 +3301,15 @@ impl PricePattern {
}
/// Pattern struct for repeated tree structure.
pub struct ToPattern {
pub to_own: BpsPercentRatioPattern2,
pub struct SharePattern {
pub share: BpsPercentRatioPattern2,
}
impl ToPattern {
impl SharePattern {
/// Create a new pattern node with accumulated series name.
pub fn new(client: Arc<BrkClientBase>, acc: String) -> Self {
Self {
to_own: BpsPercentRatioPattern2::new(client.clone(), acc.clone()),
share: BpsPercentRatioPattern2::new(client.clone(), acc.clone()),
}
}
}

View File

@@ -3001,7 +3001,7 @@ function createActivityOutputsRealizedSupplyUnrealizedPattern2(client, acc) {
/**
* @typedef {Object} BlockChangeCumulativeDeltaSumPattern
* @property {CentsUsdPattern4} block
* @property {ToPattern2} change1m
* @property {ToPattern} change1m
* @property {CentsUsdPattern} cumulative
* @property {AbsoluteRatePattern2} delta
* @property {_1m1w1y24hPattern5} sum
@@ -3016,7 +3016,7 @@ function createActivityOutputsRealizedSupplyUnrealizedPattern2(client, acc) {
function createBlockChangeCumulativeDeltaSumPattern(client, acc) {
return {
block: createCentsUsdPattern4(client, _m(acc, 'realized_pnl')),
change1m: createToPattern2(client, _m(acc, 'pnl_change_1m_to')),
change1m: createToPattern(client, _m(acc, 'pnl_change_1m_to')),
cumulative: createCentsUsdPattern(client, _m(acc, 'realized_pnl_cumulative')),
delta: createAbsoluteRatePattern2(client, _m(acc, 'realized_pnl_delta')),
sum: create_1m1w1y24hPattern5(client, _m(acc, 'realized_pnl_sum')),
@@ -4446,8 +4446,8 @@ function createInPattern2(client, acc) {
/**
* @typedef {Object} InPattern
* @property {ToPattern} inLoss
* @property {ToPattern} inProfit
* @property {SharePattern} inLoss
* @property {SharePattern} inProfit
*/
/**
@@ -4458,8 +4458,8 @@ function createInPattern2(client, acc) {
*/
function createInPattern(client, acc) {
return {
inLoss: createToPattern(client, _m(acc, 'loss_to_own')),
inProfit: createToPattern(client, _m(acc, 'profit_to_own')),
inLoss: createSharePattern(client, _m(acc, 'loss_share')),
inProfit: createSharePattern(client, _m(acc, 'profit_share')),
};
}
@@ -4528,18 +4528,18 @@ function createRatioValuePattern(client, acc) {
*/
/**
* @typedef {Object} ToPattern2
* @typedef {Object} ToPattern
* @property {BpsPercentRatioPattern} toMcap
* @property {BpsPercentRatioPattern} toRcap
*/
/**
* Create a ToPattern2 pattern node
* Create a ToPattern pattern node
* @param {BrkClientBase} client
* @param {string} acc - Accumulated series name
* @returns {ToPattern2}
* @returns {ToPattern}
*/
function createToPattern2(client, acc) {
function createToPattern(client, acc) {
return {
toMcap: createBpsPercentRatioPattern(client, _m(acc, 'mcap')),
toRcap: createBpsPercentRatioPattern(client, _m(acc, 'rcap')),
@@ -4598,19 +4598,19 @@ function createPricePattern(client, acc) {
}
/**
* @typedef {Object} ToPattern
* @property {BpsPercentRatioPattern2} toOwn
* @typedef {Object} SharePattern
* @property {BpsPercentRatioPattern2} share
*/
/**
* Create a ToPattern pattern node
* Create a SharePattern pattern node
* @param {BrkClientBase} client
* @param {string} acc - Accumulated series name
* @returns {ToPattern}
* @returns {SharePattern}
*/
function createToPattern(client, acc) {
function createSharePattern(client, acc) {
return {
toOwn: createBpsPercentRatioPattern2(client, acc),
share: createBpsPercentRatioPattern2(client, acc),
};
}
@@ -8188,15 +8188,14 @@ class BrkClient extends BrkClientBase {
constructor(options) {
super(options);
/** @type {SeriesTree} */
this.series = this._buildTree('');
this.series = this._buildTree();
}
/**
* @private
* @param {string} basePath
* @returns {SeriesTree}
*/
_buildTree(basePath) {
_buildTree() {
return {
blocks: {
blockhash: createSeriesPattern18(this, 'blockhash'),

View File

@@ -3054,7 +3054,7 @@ class BlockChangeCumulativeDeltaSumPattern:
def __init__(self, client: BrkClientBase, acc: str):
"""Create pattern node with accumulated series name."""
self.block: CentsUsdPattern4 = CentsUsdPattern4(client, _m(acc, 'realized_pnl'))
self.change_1m: ToPattern2 = ToPattern2(client, _m(acc, 'pnl_change_1m_to'))
self.change_1m: ToPattern = ToPattern(client, _m(acc, 'pnl_change_1m_to'))
self.cumulative: CentsUsdPattern = CentsUsdPattern(client, _m(acc, 'realized_pnl_cumulative'))
self.delta: AbsoluteRatePattern2 = AbsoluteRatePattern2(client, _m(acc, 'realized_pnl_delta'))
self.sum: _1m1w1y24hPattern5 = _1m1w1y24hPattern5(client, _m(acc, 'realized_pnl_sum'))
@@ -3672,8 +3672,8 @@ class InPattern:
def __init__(self, client: BrkClientBase, acc: str):
"""Create pattern node with accumulated series name."""
self.in_loss: ToPattern = ToPattern(client, _m(acc, 'loss_to_own'))
self.in_profit: ToPattern = ToPattern(client, _m(acc, 'profit_to_own'))
self.in_loss: SharePattern = SharePattern(client, _m(acc, 'loss_share'))
self.in_profit: SharePattern = SharePattern(client, _m(acc, 'profit_share'))
class PerPattern:
"""Pattern struct for repeated tree structure."""
@@ -3703,7 +3703,7 @@ class SdSmaPattern:
"""Pattern struct for repeated tree structure."""
pass
class ToPattern2:
class ToPattern:
"""Pattern struct for repeated tree structure."""
def __init__(self, client: BrkClientBase, acc: str):
@@ -3732,12 +3732,12 @@ class PricePattern:
"""Create pattern node with accumulated series name."""
self.price: BpsCentsPercentilesRatioSatsUsdPattern = BpsCentsPercentilesRatioSatsUsdPattern(client, acc)
class ToPattern:
class SharePattern:
"""Pattern struct for repeated tree structure."""
def __init__(self, client: BrkClientBase, acc: str):
"""Create pattern node with accumulated series name."""
self.to_own: BpsPercentRatioPattern2 = BpsPercentRatioPattern2(client, acc)
self.share: BpsPercentRatioPattern2 = BpsPercentRatioPattern2(client, acc)
class TransferPattern:
"""Pattern struct for repeated tree structure."""

View File

@@ -81,13 +81,13 @@
* Relative patterns by capability:
* Unrealized patterns by capability level
* @typedef {Brk.LossNetNuplProfitPattern} BasicRelativePattern
* @typedef {Brk.GrossInvestedInvestorLossNetNuplProfitSentimentPattern2} FullRelativePattern
* @typedef {Brk.CapitalizedGrossInvestedLossNetNuplProfitSentimentPattern2} FullRelativePattern
*
* Profitability bucket pattern (supply + realized_cap + unrealized_pnl + nupl)
* @typedef {Brk.NuplRealizedSupplyUnrealizedPattern} RealizedSupplyPattern
*
* Realized pattern (full: cap + gross + capitalized + loss + mvrv + net + peak + price + profit + sell + sopr)
* @typedef {Brk.CapGrossInvestorLossMvrvNetPeakPriceProfitSellSoprPattern} RealizedPattern
* @typedef {Brk.CapCapitalizedGrossLossMvrvNetPeakPriceProfitSellSoprPattern} RealizedPattern
*
* Transfer volume pattern (block + cumulative + inProfit/inLoss + sum windows)
* @typedef {Brk.AverageBlockCumulativeInSumPattern} TransferVolumePattern
@@ -242,19 +242,6 @@
* @typedef {CohortFull | CohortLongTerm} CohortWithNuplPercentiles
* @typedef {{ name: string, title: string, list: readonly CohortWithNuplPercentiles[], all: CohortAll }} CohortGroupWithNuplPercentiles
*
* Cohorts with RealizedWithExtras (realizedCapRelToOwnMarketCap + realizedProfitToLossRatio)
* @typedef {CohortAll | CohortFull | CohortWithPercentiles} CohortWithRealizedExtras
*
* Cohorts with circulating supply relative series (supplyRelToCirculatingSupply etc.)
* These have GlobalRelativePattern or FullRelativePattern (same as RelativeWithMarketCap/RelativeWithNupl)
* @typedef {CohortFull | CohortLongTerm | CohortWithAdjusted | CohortBasicWithMarketCap} UtxoCohortWithCirculatingSupplyRelative
*
* Address cohorts with circulating supply relative series (all address amount cohorts have these)
* @typedef {AddrCohortObject} AddrCohortWithCirculatingSupplyRelative
*
* All cohorts with circulating supply relative series
* @typedef {UtxoCohortWithCirculatingSupplyRelative | AddrCohortWithCirculatingSupplyRelative} CohortWithCirculatingSupplyRelative
*
* Delta patterns with absolute + rate rolling windows
* @typedef {Brk.AbsoluteRatePattern} DeltaPattern
* @typedef {Brk.AbsoluteRatePattern2} FiatDeltaPattern

View File

@@ -38,6 +38,7 @@ export function initChain(parent, callbacks) {
olderObserver = new IntersectionObserver(
(entries) => {
return; // edge fetching disabled for layout debugging
if (entries[0].isIntersecting) loadOlder();
},
{ root: chainEl },
@@ -46,6 +47,7 @@ export function initChain(parent, callbacks) {
chainEl.addEventListener(
"scroll",
() => {
return; // edge fetching disabled for layout debugging
const nearStart =
(chainEl.scrollHeight > chainEl.clientHeight &&
chainEl.scrollTop <= 50) ||

View File

@@ -38,32 +38,37 @@ export function createCointimeSection() {
},
]);
const prices = /** @type {const} */ ([
/** @type {readonly { pattern: PriceRatioPercentilesPattern, name: string, title: (name: string) => string, color: Color, defaultActive: boolean }[]} */
const prices = [
{
pattern: cointimePrices.trueMarketMean,
name: "True Market Mean",
title: (name) => name,
color: colors.trueMarketMean,
defaultActive: true,
},
{
pattern: cointimePrices.vaulted,
name: "Vaulted",
title: (name) => `${name} Price`,
color: colors.vaulted,
defaultActive: true,
},
{
pattern: cointimePrices.active,
name: "Active",
title: (name) => `${name} Price`,
color: colors.active,
defaultActive: true,
},
{
pattern: cointimePrices.cointime,
name: "Cointime",
title: (name) => `${name} Price`,
color: colors.cointime,
defaultActive: true,
},
]);
];
const caps = /** @type {const} */ ([
{
@@ -187,11 +192,11 @@ export function createCointimeSection() {
),
],
},
...prices.map(({ pattern, name, color }) => ({
...prices.map(({ pattern, name, title, color }) => ({
name,
tree: priceRatioPercentilesTree({
pattern,
title: `${name} Price`,
title: title(name),
legend: name,
color,
priceReferences: [

View File

@@ -254,9 +254,6 @@ export function createSelect({
? unsortedChoices.toSorted((a, b) => toLabel(a).localeCompare(toLabel(b)))
: unsortedChoices;
const field = window.document.createElement("div");
field.classList.add("field");
const initialKey = toKey(initialValue);
/** @param {string} key */
@@ -266,56 +263,59 @@ export function createSelect({
if (choices.length === 1) {
const span = window.document.createElement("span");
span.textContent = toLabel(choices[0]);
field.append(span);
} else {
const select = window.document.createElement("select");
select.id = id ?? "";
select.name = id ?? "";
field.append(select);
/** @param {T} choice */
const createOption = (choice) => {
const option = window.document.createElement("option");
option.value = toKey(choice);
option.textContent = toLabel(choice);
if (toKey(choice) === initialKey) {
option.selected = true;
}
return option;
};
if (groups) {
groups.forEach(({ label, items }) => {
const optgroup = window.document.createElement("optgroup");
optgroup.label = label;
items.forEach((choice) => optgroup.append(createOption(choice)));
select.append(optgroup);
});
} else {
choices.forEach((choice) => select.append(createOption(choice)));
}
select.addEventListener("change", () => {
onChange?.(fromKey(select.value));
});
const remaining = choices.length - 1;
if (remaining > 0) {
const small = window.document.createElement("small");
small.textContent = `+${remaining}`;
field.append(small);
const arrow = window.document.createElement("span");
arrow.textContent = "↓";
field.append(arrow);
}
field.addEventListener("click", (e) => {
if (e.target !== select) {
select.showPicker();
}
});
return span;
}
const field = window.document.createElement("div");
field.classList.add("field");
const select = window.document.createElement("select");
select.id = id ?? "";
select.name = id ?? "";
field.append(select);
/** @param {T} choice */
const createOption = (choice) => {
const option = window.document.createElement("option");
option.value = toKey(choice);
option.textContent = toLabel(choice);
if (toKey(choice) === initialKey) {
option.selected = true;
}
return option;
};
if (groups) {
groups.forEach(({ label, items }) => {
const optgroup = window.document.createElement("optgroup");
optgroup.label = label;
items.forEach((choice) => optgroup.append(createOption(choice)));
select.append(optgroup);
});
} else {
choices.forEach((choice) => select.append(createOption(choice)));
}
select.addEventListener("change", () => {
onChange?.(fromKey(select.value));
});
const remaining = choices.length - 1;
if (remaining > 0) {
const small = window.document.createElement("small");
small.textContent = `+${remaining}`;
field.append(small);
const arrow = window.document.createElement("span");
arrow.textContent = "↓";
field.append(arrow);
}
field.addEventListener("click", (e) => {
if (e.target !== select) {
select.showPicker();
}
});
return field;
}

View File

@@ -70,7 +70,7 @@
pointer-events: auto;
}
> span {
> *:nth-child(2) {
color: var(--gray);
padding: 0 0.75rem;
}
@@ -105,7 +105,7 @@
> label {
> span {
display: flex !important;
display: flex;
}
&:has(input:not(:checked)) {
@@ -115,11 +115,11 @@
&:hover {
* {
color: var(--off-color) !important;
color: var(--off-color);
}
> span.main > span.name {
text-decoration-color: var(--orange) !important;
text-decoration-color: var(--orange);
}
}

View File

@@ -30,18 +30,28 @@ a {
text-decoration-color: inherit;
}
&[target="_blank"]::after {
color: var(--off-color);
content: "↗";
font-weight: 400;
font-size: 1rem;
&[target="_blank"] {
&::after {
color: var(--off-color);
content: "↗";
font-weight: 400;
font-size: 1rem;
margin-top: 0.1rem;
margin-left: 0.375rem;
line-height: 1;
margin-top: 0.1rem;
margin-left: 0.375rem;
line-height: 1;
&:hover {
text-decoration: none;
&:hover {
text-decoration: none;
}
}
&:hover::after {
color: var(--color);
}
&:active::after {
color: var(--orange);
}
}
}
@@ -55,6 +65,8 @@ aside {
z-index: 1;
overflow: hidden;
background: var(--background-color);
container-type: inline-size;
container-name: aside;
html[data-layout="split"] & {
grid-column: 2;
@@ -208,11 +220,6 @@ select {
outline: none;
}
summary > small {
margin-left: 0.375rem;
opacity: 0.5;
}
small {
color: var(--off-color);
font-weight: var(--font-weight-base);
@@ -249,28 +256,33 @@ summary {
&::-webkit-details-marker {
display: none;
}
> small {
margin-left: 0.375rem;
opacity: 0.5;
}
&:hover > small {
color: var(--color);
}
&:active > small {
color: var(--orange);
}
}
:is(a, button, summary) {
&:hover {
&,
*,
&::after {
color: var(--color);
}
color: var(--color);
}
&:active {
&,
*,
&::after {
color: var(--orange);
}
color: var(--orange);
}
}
html[data-layout="split"] .full-only {
display: none !important;
display: none;
}
#layout-button {

View File

@@ -36,7 +36,7 @@ main {
}
html[data-layout="full"] & {
width: 100% !important;
width: 100%;
}
html[data-layout="split"] & {

View File

@@ -61,7 +61,6 @@ li[data-highlight] {
> a::after,
> details:not([open]) > summary::after {
color: var(--orange) !important;
content: "";
background-color: var(--orange);
width: 0.375rem;

View File

@@ -8,7 +8,7 @@
opacity: 0.5;
}
@media (max-width: 767px) {
@container aside (max-width: 767px) {
overflow-y: auto;
padding: var(--main-padding) 0;
flex-direction: column;
@@ -23,25 +23,58 @@
known source of jank there. Each interaction state gets its own
set; the .cube rule below just swaps which set --face-right /
--face-left / --face-top / --face-bottom reference. */
--cube-neutral-right: light-dark(oklch(from var(--light-gray) calc(l - var(--face-step) * 2) c h), var(--dark-gray));
--cube-neutral-left: light-dark(oklch(from var(--light-gray) calc(l - var(--face-step)) c h), oklch(from var(--dark-gray) calc(l + var(--face-step)) c h));
--cube-neutral-top: light-dark(var(--light-gray), oklch(from var(--dark-gray) calc(l + var(--face-step) * 2) c h));
--cube-neutral-bottom: oklch(from var(--border-color) calc(l - var(--face-step) * 3) c h);
--cube-neutral-right: light-dark(
oklch(from var(--light-gray) calc(l - var(--face-step) * 2) c h),
var(--dark-gray)
);
--cube-neutral-left: light-dark(
oklch(from var(--light-gray) calc(l - var(--face-step)) c h),
oklch(from var(--dark-gray) calc(l + var(--face-step)) c h)
);
--cube-neutral-top: light-dark(
var(--light-gray),
oklch(from var(--dark-gray) calc(l + var(--face-step) * 2) c h)
);
--cube-neutral-bottom: oklch(
from var(--border-color) calc(l - var(--face-step) * 3) c h
);
--cube-hover-right: light-dark(oklch(from var(--dark-gray) calc(l - var(--face-step) * 2) c h), var(--light-gray));
--cube-hover-left: light-dark(oklch(from var(--dark-gray) calc(l - var(--face-step)) c h), oklch(from var(--light-gray) calc(l + var(--face-step)) c h));
--cube-hover-top: light-dark(var(--dark-gray), oklch(from var(--light-gray) calc(l + var(--face-step) * 2) c h));
--cube-hover-bottom: oklch(from var(--inv-border-color) calc(l - var(--face-step) * 3) c h);
--cube-hover-right: light-dark(
oklch(from var(--dark-gray) calc(l - var(--face-step) * 2) c h),
var(--light-gray)
);
--cube-hover-left: light-dark(
oklch(from var(--dark-gray) calc(l - var(--face-step)) c h),
oklch(from var(--light-gray) calc(l + var(--face-step)) c h)
);
--cube-hover-top: light-dark(
var(--dark-gray),
oklch(from var(--light-gray) calc(l + var(--face-step) * 2) c h)
);
--cube-hover-bottom: oklch(
from var(--inv-border-color) calc(l - var(--face-step) * 3) c h
);
--cube-selected-right: light-dark(oklch(from var(--orange) calc(l - var(--face-step) * 2) c h), var(--orange));
--cube-selected-left: light-dark(oklch(from var(--orange) calc(l - var(--face-step)) c h), oklch(from var(--orange) calc(l + var(--face-step)) c h));
--cube-selected-top: light-dark(var(--orange), oklch(from var(--orange) calc(l + var(--face-step) * 2) c h));
--cube-selected-bottom: oklch(from var(--orange) calc(l - var(--face-step) * 3) c h);
--cube-selected-right: light-dark(
oklch(from var(--orange) calc(l - var(--face-step) * 2) c h),
var(--orange)
);
--cube-selected-left: light-dark(
oklch(from var(--orange) calc(l - var(--face-step)) c h),
oklch(from var(--orange) calc(l + var(--face-step)) c h)
);
--cube-selected-top: light-dark(
var(--orange),
oklch(from var(--orange) calc(l + var(--face-step) * 2) c h)
);
--cube-selected-bottom: oklch(
from var(--orange) calc(l - var(--face-step) * 3) c h
);
> * {
padding: 0 var(--main-padding);
@media (min-width: 768px) {
@container aside (min-width: 768px) {
padding: var(--main-padding);
}
}
@@ -49,11 +82,11 @@
#chain {
flex-shrink: 0;
@media (max-width: 767px) {
@container aside (max-width: 767px) {
overflow-x: auto;
}
@media (min-width: 768px) {
@container aside (min-width: 768px) {
height: 100%;
overflow-y: auto;
padding-right: calc(var(--main-padding) / 2);
@@ -67,16 +100,16 @@
--min-dt: 0;
--max-dt: 10800;
margin-right: var(--cube);
margin-top: calc(var(--cube) * -0.25);
@media (max-width: 767px) {
--max-gap: calc(var(--cube) * 1.5);
@container aside (max-width: 767px) {
flex-direction: row-reverse;
align-items: center;
height: 11.5rem;
width: max-content;
}
@media (min-width: 768px) {
@container aside (min-width: 768px) {
margin-top: calc(var(--cube) * -0.25);
padding-bottom: 6rem;
}
}
@@ -103,9 +136,9 @@
/* Face colors reference the precomputed sets on #explorer
(see top of file). Hover / selected rules just switch which
set each --face-* points at. */
--face-right: var(--cube-neutral-right);
--face-left: var(--cube-neutral-left);
--face-top: var(--cube-neutral-top);
--face-right: var(--cube-neutral-right);
--face-left: var(--cube-neutral-left);
--face-top: var(--cube-neutral-top);
--face-bottom: var(--cube-neutral-bottom);
/* Fill-driven state. --liquid-y is the liquid's vertical scale;
@@ -136,25 +169,27 @@
&:hover {
color: var(--background-color);
--face-right: var(--cube-hover-right);
--face-left: var(--cube-hover-left);
--face-top: var(--cube-hover-top);
--face-right: var(--cube-hover-right);
--face-left: var(--cube-hover-left);
--face-top: var(--cube-hover-top);
--face-bottom: var(--cube-hover-bottom);
}
&:active,
&.selected {
color: var(--black);
--face-right: var(--cube-selected-right);
--face-left: var(--cube-selected-left);
--face-top: var(--cube-selected-top);
--face-right: var(--cube-selected-right);
--face-left: var(--cube-selected-left);
--face-top: var(--cube-selected-top);
--face-bottom: var(--cube-selected-bottom);
}
/* Skeleton state (cube painted but data is stale while a new
chunk loads): hide text AND the pool logo. Using visibility
rather than color:transparent so the raw <img> logo hides too. */
&.skeleton .face-text { visibility: hidden; }
&.skeleton .face-text {
visibility: hidden;
}
/* Shared face-transform template. Each face div sets --orient,
--x, --y, --sx, --sy and its role (liquid/glass/face-text)
@@ -181,7 +216,8 @@
will-change is on the painted roles only (not .face-text,
whose background never changes) so each liquid/glass gets its
own compositor layer for snappy hover/select repaints. */
.liquid, .glass {
.liquid,
.glass {
will-change: background-color;
transition: background-color var(--state-ease);
}
@@ -196,7 +232,9 @@
--sy: var(--glass-y);
--y-offset: 0;
}
.glass.top { opacity: calc(1 - var(--is-full)); }
.glass.top {
opacity: calc(1 - var(--is-full));
}
.face-text {
--sy: var(--iso-scale);
@@ -214,9 +252,16 @@
align-items: center;
text-align: center;
}
.face-text.top { justify-content: center; text-transform: uppercase; }
.face-text.right { justify-content: space-between; }
.face-text p { margin: 0; }
.face-text.top {
justify-content: center;
text-transform: uppercase;
}
.face-text.right {
justify-content: space-between;
}
.face-text p {
margin: 0;
}
.face-text .height {
font-size: var(--font-size-sm);
font-weight: normal;
@@ -254,12 +299,19 @@
their rear twins share the side-face orients). --sy is only
shared on the top/bottom pair (always full iso rhombus);
side faces inherit --sy from their role (liquid/glass/face-text). */
.top, .bottom {
.top,
.bottom {
--orient: rotate(30deg) skewX(-30deg);
--sy: var(--iso-scale);
}
.right, .rear-left { --orient: rotate(-30deg) skewX(-30deg); }
.left, .rear-right { --orient: rotate(30deg) skewX(30deg); }
.right,
.rear-left {
--orient: rotate(-30deg) skewX(-30deg);
}
.left,
.rear-right {
--orient: rotate(30deg) skewX(30deg);
}
.bottom {
--fc: var(--face-bottom);
@@ -268,14 +320,20 @@
}
.top {
--fc: var(--face-top);
--x: calc(var(--ox) + var(--top-x-shift, 0) + var(--oy) / var(--iso-scale));
--x: calc(
var(--ox) + var(--top-x-shift, 0) + var(--oy) / var(--iso-scale)
);
--y: calc(var(--oy) - var(--iso-scale) + var(--y-offset));
}
.liquid.top { --top-x-shift: calc(1 - var(--fill)); }
.liquid.top {
--top-x-shift: calc(1 - var(--fill));
}
.right {
--fc: var(--face-right);
--x: calc(var(--ox) + 1);
--y: calc((var(--ox) + 1) * var(--iso-scale) + var(--oy) + var(--y-offset));
--y: calc(
(var(--ox) + 1) * var(--iso-scale) + var(--oy) + var(--y-offset)
);
}
.left {
--fc: var(--face-left);
@@ -308,7 +366,7 @@
z-index: -1;
}
@media (max-width: 767px) {
@container aside (max-width: 767px) {
margin-bottom: 0;
margin-right: var(--block-gap);
@@ -332,7 +390,7 @@
font-size: var(--font-size-sm);
line-height: var(--line-height-sm);
@media (min-width: 768px) {
@container aside (min-width: 768px) {
overflow-y: auto;
padding-left: calc(var(--main-padding) / 2);
}
@@ -342,7 +400,7 @@
code {
font-size: 1.5rem;
font-weight: 300 !important;
font-weight: 300;
font-family: Lilex;
color: var(--off-color);
letter-spacing: -0.05rem;