Files
brk/website/src/explorer/chain/cube/style.css
2026-05-17 22:12:44 +02:00

219 lines
5.1 KiB
CSS

@property --pulse-mix {
syntax: "<number>";
inherits: true;
initial-value: 0;
}
:root {
--cube-size: 4.5rem;
--iso-scale: calc(sqrt(3) / 2);
--cube-empty-alpha: 0.4;
--face-step: 0.033;
}
.cube {
--cube-width: calc(var(--cube-size) * 2 * var(--iso-scale));
--cube-height: calc(var(--cube-size) * 2);
--cube-face-base: var(--border-color);
--face-top: light-dark(
var(--cube-face-base),
oklch(from var(--cube-face-base) calc(l + var(--face-step) * 2) c h)
);
--face-right: light-dark(
oklch(from var(--cube-face-base) calc(l - var(--face-step) * 2) c h),
var(--cube-face-base)
);
--face-left: light-dark(
oklch(from var(--cube-face-base) calc(l - var(--face-step)) c h),
oklch(from var(--cube-face-base) calc(l + var(--face-step)) c h)
);
--face-bottom: oklch(
from var(--cube-face-base) calc(l - var(--face-step) * 3) c h
);
--is-full: round(down, var(--fill), 1);
--is-empty: round(down, calc(1 - var(--fill)), 1);
flex-shrink: 0;
position: relative;
width: var(--cube-width);
height: var(--cube-height);
/* .cube can be an <a>; reset anchor styles that would clip the iso
silhouette or underline the empty link. */
overflow: visible;
text-decoration: none;
color: var(--color);
user-select: none;
pointer-events: none;
/* Hover/active styling is gated on the anchor tag: only <a> cubes
(confirmed blocks) react to pointer state. Plain <div> projected
previews stay visually inert. --face-color-base is resolved lazily,
so the orange override below feeds the face declarations too. */
&:is(a):hover,
&:is(a):active,
&.selected {
color: var(--background-color);
--face-color-base: var(--inv-border-color);
--face-top: var(--face-color-base);
--face-right: oklch(
from var(--face-color-base) calc(l - var(--face-step) * 2) c h
);
--face-left: oklch(
from var(--face-color-base) calc(l - var(--face-step)) c h
);
--face-bottom: oklch(
from var(--face-color-base) calc(l - var(--face-step) * 3) c h
);
}
&:is(a):active,
&.selected {
color: var(--black);
--face-color-base: var(--orange);
}
&.projected {
animation: cube-pulse 4s ease-in-out infinite;
--cube-face-base: color-mix(
in oklch,
var(--border-color),
var(--background-color) calc(var(--pulse-mix) * 100%)
);
}
/* visibility (not color:transparent) so child <img> hides too */
&.skeleton .face-text {
visibility: hidden;
}
.face {
position: absolute;
transform-origin: 0 0;
box-sizing: border-box;
width: var(--cube-size);
height: var(--cube-size);
transform: translateY(50%) var(--face-orient)
translate(
calc(var(--cube-size) * var(--face-x)),
calc(var(--cube-size) * var(--face-y))
)
scale(var(--face-scale-x, 1), var(--face-scale-y));
pointer-events: auto;
}
/* will-change on painted roles only so each gets its own compositor
layer for snappy hover/select repaints. */
.liquid,
.glass {
will-change: background-color;
}
.liquid {
background: var(--face-color);
opacity: calc(1 - var(--is-empty));
--face-scale-y: calc(var(--iso-scale) * var(--fill));
--face-stack-shift: calc(var(--iso-scale) * (1 - var(--fill)));
}
.glass {
background: oklch(from var(--face-color) l c h / var(--cube-empty-alpha));
--face-scale-y: calc(var(--iso-scale) * (1 - var(--fill)));
--face-stack-shift: 0;
}
.face-text {
--face-scale-y: var(--iso-scale);
--face-stack-shift: 0;
pointer-events: none;
padding: 0.1rem;
font-family: var(--font-mono);
font-size: var(--font-size-xs);
font-weight: 450;
display: flex;
flex-direction: column;
align-items: center;
text-align: center;
&.top {
justify-content: center;
text-transform: uppercase;
}
&.right {
justify-content: space-between;
}
&.left {
justify-content: center;
}
p {
margin: 0;
}
}
.top,
.bottom {
--face-orient: rotate(30deg) skewX(-30deg);
--face-scale-y: var(--iso-scale);
}
.right,
.rear-left {
--face-orient: rotate(-30deg) skewX(-30deg);
}
.left,
.rear-right {
--face-orient: rotate(30deg) skewX(30deg);
}
.top,
.rear-right {
--face-y: calc(var(--face-stack-shift) - var(--iso-scale));
}
.left,
.rear-left {
--face-y: var(--face-stack-shift);
}
.right {
--face-y: calc(var(--face-stack-shift) + var(--iso-scale));
}
.bottom {
--face-y: 0;
}
.top {
--face-color: var(--face-top);
--face-x: 0;
}
.bottom {
--face-color: var(--face-bottom);
--face-x: 1;
}
.right {
--face-color: var(--face-right);
--face-x: 1;
}
.left {
--face-color: var(--face-left);
--face-x: 0;
}
.rear-right {
--face-color: var(--face-left);
--face-x: 1;
}
.rear-left {
--face-color: var(--face-top);
--face-x: 1;
--face-scale-x: -1;
}
.liquid.top {
--face-x: calc(1 - var(--fill));
}
}
@keyframes cube-pulse {
0%,
100% {
--pulse-mix: 0.5;
}
50% {
--pulse-mix: 1;
}
}