Files
brk/website/styles/panes/explorer.css
2026-04-19 17:13:47 +02:00

581 lines
15 KiB
CSS
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#explorer {
width: 100%;
height: 100%;
display: flex;
overflow: hidden;
.dim {
opacity: 0.5;
}
@container aside (max-width: 767px) {
overflow-y: auto;
padding: var(--main-padding) 0;
flex-direction: column;
}
--cube: 4.5rem;
--face-step: 0.033;
/* Cube face-color derivations, resolved once at the #explorer
level so .cube state changes (hover / selected) don't force
Safari to re-evaluate `oklch(from var …)` on every paint — a
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-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
);
> * {
padding: 0 var(--main-padding);
@container aside (min-width: 768px) {
padding: var(--main-padding);
}
}
#chain {
flex-shrink: 0;
@container aside (max-width: 767px) {
overflow-x: auto;
}
@container aside (min-width: 768px) {
height: 100%;
overflow-y: auto;
padding-right: calc(var(--main-padding) / 2);
}
.blocks {
display: flex;
flex-direction: column-reverse;
--min-gap: 0rem;
--max-gap: calc(var(--cube) * 6);
--min-dt: 0;
--max-dt: 10800;
margin-right: var(--cube);
@container aside (max-width: 767px) {
flex-direction: row-reverse;
align-items: center;
height: 11.5rem;
width: max-content;
}
@container aside (min-width: 768px) {
margin-top: calc(var(--cube) * -0.25);
padding-bottom: 6rem;
}
}
.cube {
--t: pow(
clamp(
0,
(var(--dt, 600) - var(--min-dt)) / (var(--max-dt) - var(--min-dt)),
1
),
0.7
);
--block-gap: calc(
var(--min-gap) + var(--t) * (var(--max-gap) - var(--min-gap))
);
/* Iso projection constants. Changing these reshapes the whole
cube — they drive the per-face transforms below. */
--iso-scale: cos(30deg);
--ox: 0.3;
--oy: 0.6;
--empty-alpha: 0.4;
/* 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-bottom: var(--cube-neutral-bottom);
/* Fill-driven state. --liquid-y is the liquid's vertical scale;
--glass-y the glass-above-liquid's. --is-full / --is-empty
round to 0 or 1 and drive opacity so scaled-to-0 faces
vanish cleanly (no hairline AA seams). */
--liquid-y: calc(var(--iso-scale) * var(--fill));
--glass-y: calc(var(--iso-scale) * (1 - var(--fill)));
--is-full: round(down, calc(var(--fill) + 0.0025), 1);
--is-empty: round(down, calc(1.0025 - var(--fill)), 1);
margin-left: calc(var(--cube) * -0.25);
flex-shrink: 0;
position: relative;
cursor: pointer;
width: var(--cube);
height: var(--cube);
/* .cube is an <a>; reset the global anchor styles in
elements.css that would clip the iso silhouette
(overflow:hidden) and underline the empty link. */
overflow: visible;
text-decoration: none;
--state-ease: 50ms cubic-bezier(0.4, 0, 0.2, 1);
color: var(--color);
transition: color var(--state-ease);
user-select: none;
pointer-events: none;
&:hover {
color: var(--background-color);
--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-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;
}
/* Shared face-transform template. Each face div sets --orient,
--x, --y, --sx, --sy and its role (liquid/glass/face-text)
supplies --y-offset. Faces extend outside .cube's layout box
— the iso silhouette spans ~2·iso·cube × 2·cube, offset into
what would be the next cube's space. Clicks land only on the
transformed face rectangles, not the .cube's empty corners. */
.face {
position: absolute;
transform-origin: 0 0;
box-sizing: border-box;
width: var(--cube);
height: var(--cube);
transform: var(--orient)
translate(calc(var(--cube) * var(--x)), calc(var(--cube) * var(--y)))
scale(var(--sx, 1), var(--sy));
pointer-events: auto;
}
/* Roles:
.liquid opaque liquid (scales with fill)
.glass translucent glass shell
.face-text text overlay spanning the full rhombus
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 {
will-change: background-color;
transition: background-color var(--state-ease);
}
.liquid {
background: var(--fc);
opacity: calc(1 - var(--is-empty));
--sy: var(--liquid-y);
--y-offset: var(--glass-y);
}
.glass {
background: oklch(from var(--fc) l c h / var(--empty-alpha));
--sy: var(--glass-y);
--y-offset: 0;
}
.glass.top {
opacity: calc(1 - var(--is-full));
}
.face-text {
--sy: var(--iso-scale);
--y-offset: 0;
pointer-events: none;
padding: 0.1rem;
font-family: var(--font-mono);
font-size: var(--font-size-xs);
font-weight: 450;
}
.face-text.top,
.face-text.right {
display: flex;
flex-direction: column;
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 .height {
font-size: var(--font-size-sm);
font-weight: normal;
}
.face-text .fees {
display: flex;
flex-direction: column;
height: 100%;
justify-content: center;
align-items: center;
}
/* Pool line: raw (un-tinted) logo + miner name, ellipsis-clipped. */
.face-text .pool {
display: flex;
align-items: center;
justify-content: center;
gap: 0.1em;
width: 100%;
}
.face-text .pool img {
width: 1.25em;
height: 1.25em;
flex-shrink: 0;
}
.face-text .pool span {
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
line-height: 1;
}
/* Per-face geometry. The 3 unique orientations each cover two
faces (top+bottom share the iso-squash orient; right/left and
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 {
--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);
}
.bottom {
--fc: var(--face-bottom);
--x: calc(var(--ox) + 1 + var(--oy) / var(--iso-scale));
--y: var(--oy);
}
.top {
--fc: var(--face-top);
--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));
}
.right {
--fc: var(--face-right);
--x: calc(var(--ox) + 1);
--y: calc(
(var(--ox) + 1) * var(--iso-scale) + var(--oy) + var(--y-offset)
);
}
.left {
--fc: var(--face-left);
--x: var(--ox);
--y: calc(var(--oy) + var(--y-offset));
}
.rear-right {
--fc: var(--face-left);
--x: calc(var(--ox) + 1);
--y: calc(var(--oy) - var(--iso-scale) + var(--y-offset));
}
.rear-left {
--fc: var(--face-top);
--sx: -1;
--x: calc(var(--ox) + 1);
--y: calc(var(--ox) * var(--iso-scale) + var(--oy) + var(--y-offset));
}
& + & {
margin-bottom: var(--block-gap);
&::before {
content: "";
position: absolute;
top: calc(var(--cube) * 1.75);
left: calc(var(--cube) * 1.12);
width: 1px;
height: var(--block-gap);
background: var(--border-color);
z-index: -1;
}
@container aside (max-width: 767px) {
margin-bottom: 0;
margin-right: var(--block-gap);
&::before {
bottom: auto;
left: auto;
right: calc(-1 * var(--block-gap));
top: 50%;
width: var(--block-gap);
height: 1px;
}
}
}
}
}
#block-details,
#tx-details,
#addr-details {
flex: 1;
font-size: var(--font-size-sm);
line-height: var(--line-height-sm);
@container aside (min-width: 768px) {
overflow-y: auto;
padding-left: calc(var(--main-padding) / 2);
}
h1 {
margin-bottom: 1rem;
code {
font-size: 1.5rem;
font-weight: 300;
font-family: Lilex;
color: var(--off-color);
letter-spacing: -0.05rem;
}
}
.row {
display: flex;
justify-content: space-between;
gap: 1rem;
padding: 0.25rem 0;
border-bottom: 1px solid var(--border-color);
}
.label {
color: var(--off-color);
white-space: nowrap;
}
.value {
text-align: right;
word-break: break-all;
}
.transactions {
margin-top: 1rem;
.tx-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 0.5rem;
h2 {
font-size: var(--font-size-sm);
line-height: var(--line-height-sm);
}
}
.pagination {
display: flex;
align-items: center;
gap: 0.5rem;
button {
color: var(--off-color);
&:disabled {
opacity: 0.25;
pointer-events: none;
}
}
}
.tx {
border: 1px solid var(--border-color);
padding: 0.5rem;
margin-bottom: 0.5rem;
content-visibility: auto;
contain-intrinsic-block-size: auto 8rem;
.tx-head {
display: flex;
justify-content: space-between;
gap: 0.5rem;
margin-bottom: 0.5rem;
padding-bottom: 0.5rem;
border-bottom: 1px solid var(--border-color);
.txid {
font-family: Lilex;
font-size: var(--font-size-xs);
line-height: var(--line-height-xs);
color: var(--off-color);
overflow: hidden;
text-overflow: ellipsis;
}
.tx-time {
flex-shrink: 0;
color: var(--off-color);
}
}
.tx-body {
display: flex;
gap: 0.5rem;
font-size: var(--font-size-xs);
line-height: var(--line-height-xs);
}
.tx-inputs,
.tx-outputs {
flex: 1;
min-width: 0;
display: flex;
flex-direction: column;
gap: 0.125rem;
}
.tx-outputs {
padding-left: 0.5rem;
border-left: 1px solid var(--border-color);
}
.tx-io {
display: flex;
justify-content: space-between;
gap: 0.5rem;
.addr {
display: flex;
min-width: 0;
white-space: nowrap;
color: var(--off-color);
a {
display: flex;
min-width: 0;
}
.addr-head {
overflow: hidden;
text-overflow: ellipsis;
}
.addr-tail {
flex-shrink: 0;
}
&.coinbase {
color: var(--orange);
}
.coinbase-sig {
font-family: Lilex;
font-size: var(--font-size-xs);
color: var(--off-color);
display: block;
overflow: hidden;
text-overflow: ellipsis;
}
&.op-return {
color: var(--off-color);
}
}
.amount {
flex-shrink: 0;
text-align: right;
}
}
.show-more {
color: var(--off-color);
font-size: var(--font-size-xs);
padding: 0.25rem 0;
}
.tx-foot {
display: flex;
justify-content: space-between;
gap: 0.5rem;
margin-top: 0.5rem;
padding-top: 0.5rem;
border-top: 1px solid var(--border-color);
color: var(--off-color);
.total {
color: var(--orange);
}
}
}
}
}
}