mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-04-30 09:30:00 -07:00
440 lines
35 KiB
HTML
440 lines
35 KiB
HTML
<!doctype html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="utf-8"/>
|
||
<title>bitview logo (svg)</title>
|
||
<style>
|
||
/* Website's Lilex (the site's --font-mono). Italic file omitted
|
||
— no italic text on the cube. */
|
||
@font-face {
|
||
font-family: Lilex;
|
||
src: url("../fonts/Lilex[wght]-v2_620.woff2") format("woff2");
|
||
font-weight: 100 700;
|
||
font-display: block;
|
||
}
|
||
|
||
:root {
|
||
color-scheme: light dark;
|
||
/* Cube edge declared as a unitless rem-count so a <number> is
|
||
available for maths (Firefox still stumbles on the
|
||
length/length-to-number calc trick). --cube is the length used
|
||
by layout; --cube-px is the px value (assuming 1rem = 16px);
|
||
--face-scale is the 100/cube-px multiplier applied to CSS
|
||
values inside a <foreignObject>, where 1 CSS px == 1 SVG user
|
||
unit — we multiply to get the intended screen px back. */
|
||
--cube-rem: 4.5;
|
||
--cube: calc(var(--cube-rem) * 1rem);
|
||
--cube-px: calc(var(--cube-rem) * 16);
|
||
--face-scale: calc(100 / var(--cube-px));
|
||
--orange: oklch(67.64% 0.191 44.41);
|
||
--white: oklch(95% 0 0);
|
||
--black: oklch(15% 0 0);
|
||
--light-gray: oklch(90% 0 0);
|
||
--dark-gray: oklch(20% 0 0);
|
||
--border-color: light-dark(var(--light-gray), var(--dark-gray));
|
||
--background-color: light-dark(var(--white), var(--black));
|
||
--fill: 0.5;
|
||
--empty-alpha: 0.4;
|
||
--face-step: 0.033;
|
||
--iso-scale: 0.866;
|
||
--font-size-xs: 0.75rem;
|
||
--font-size-sm: 0.875rem;
|
||
}
|
||
|
||
/* ---- page chrome ---- */
|
||
html, body { margin: 0; padding: 0; }
|
||
body {
|
||
font: 14px/1.4 -apple-system, system-ui, sans-serif;
|
||
color: #111;
|
||
background: #f7f8fa;
|
||
}
|
||
.wrap { max-width: 1440px; margin: 0 auto; padding: 40px 24px 80px; }
|
||
section { margin: 0 0 12px; }
|
||
.row {
|
||
display: grid;
|
||
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
|
||
gap: 12px;
|
||
}
|
||
.tile {
|
||
position: relative;
|
||
aspect-ratio: 1;
|
||
border-radius: 14px;
|
||
display: grid; place-items: center;
|
||
overflow: hidden;
|
||
box-shadow: 0 0 0 1px rgba(0,0,0,0.08);
|
||
}
|
||
.tile .label {
|
||
position: absolute; left: 10px; bottom: 8px;
|
||
font: 11px/1.4 ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
||
color: rgba(0,0,0,0.55);
|
||
background: rgba(255,255,255,0.7); padding: 2px 6px; border-radius: 4px;
|
||
backdrop-filter: blur(6px);
|
||
}
|
||
.tile.scheme-light { color-scheme: light; }
|
||
.tile.scheme-dark { color-scheme: dark; color: #e8e8ea; }
|
||
.tile.scheme-dark .label { color: rgba(255,255,255,0.75); background: rgba(0,0,0,0.4); }
|
||
.bg-auto { background: var(--background-color); }
|
||
.bg-paper { background: light-dark(#f0ece3, #2a2823); }
|
||
.bg-gradient { background: linear-gradient(135deg, oklch(70% 0.16 260), oklch(72% 0.19 330)); }
|
||
.bg-image-1 { background: url('https://picsum.photos/seed/brk1/440/440') center/cover; }
|
||
.bg-image-2 { background: url('https://picsum.photos/seed/brk2/440/440') center/cover; }
|
||
|
||
/* ---- cube slot: just holds the svg ---- */
|
||
.logo-slot {
|
||
position: relative;
|
||
width: 160px; height: 160px;
|
||
display: grid; place-items: center;
|
||
}
|
||
.logo-slot svg {
|
||
/* viewBox 0 0 173.2 200 matches the iso hex aspect (2·iso : 2).
|
||
No preserveAspectRatio trickery — 1 cube unit = 100 viewBox
|
||
units in both dimensions, so face transforms can use HTML's
|
||
demo.html values scaled ×100. */
|
||
width: calc(var(--cube) * var(--iso-scale) * 2);
|
||
height: calc(var(--cube) * 2);
|
||
overflow: visible;
|
||
}
|
||
|
||
/* Face-text: HTML inside <foreignObject> inherits the face's
|
||
SVG transform (rotate + skewX + translate + scaleY(iso)), so
|
||
text reads in-plane with each face — same skew/compression as
|
||
the HTML demo. Styling mirrors demo.html's .cube .text rules.
|
||
Font sizes and stamp dimensions are multiplied by --face-scale
|
||
(= 100 / --cube-px) so that a CSS value inside the foreignObject
|
||
renders at the same *screen* px as outside. */
|
||
.face-text {
|
||
position: relative;
|
||
width: 100%;
|
||
height: 100%;
|
||
padding: 0.1rem;
|
||
box-sizing: border-box;
|
||
font-family: Lilex, ui-monospace, monospace;
|
||
font-size: calc(var(--font-size-xs) * var(--face-scale));
|
||
font-weight: 500;
|
||
pointer-events: none;
|
||
}
|
||
.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: calc(var(--font-size-sm) * var(--face-scale));
|
||
font-weight: normal;
|
||
}
|
||
.face-text .fees {
|
||
display: flex;
|
||
flex-direction: column;
|
||
height: 100%;
|
||
justify-content: center;
|
||
align-items: center;
|
||
}
|
||
.face-text .dim { opacity: 0.5; }
|
||
|
||
/* 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%;
|
||
box-sizing: border-box;
|
||
padding: 0.1rem;
|
||
}
|
||
.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;
|
||
}
|
||
.face-text .pool img.foundryusa { content: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGlkPSJiIiBkYXRhLW5hbWU9IkxheWVyIDIiIHN0eWxlPSJ6b29tOiAxOyIgdmlld0JveD0iMCAwIDMyIDc2Ij48ZGVmcz48c3R5bGU+LmQgeyBmaWxsOiAjZmZmOyB9IC5lIHsgZmlsbDogI2ZmODIwMDsgfTwvc3R5bGU+PC9kZWZzPjxnIGlkPSJjIiBkYXRhLW5hbWU9ImIiPjxjaXJjbGUgY2xhc3M9ImUiIGN4PSIyNCIgY3k9IjMyIiByPSI4Ii8+PGNpcmNsZSBjbGFzcz0iZSIgY3g9IjI0IiBjeT0iNTYiIHI9IjgiLz48Y2lyY2xlIGNsYXNzPSJlIiBjeD0iOCIgY3k9IjY4IiByPSI4Ii8+PGc+PGNpcmNsZSBjbGFzcz0iZCIgY3g9IjI0IiBjeT0iOCIgcj0iOCIvPjxjaXJjbGUgY2xhc3M9ImQiIGN4PSI4IiBjeT0iMjAiIHI9IjgiLz48Y2lyY2xlIGNsYXNzPSJkIiBjeD0iOCIgY3k9IjQ0IiByPSI4Ii8+PC9nPjwvZz48L3N2Zz4="); }
|
||
.face-text .pool img.antpool { content: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI0MCIgaGVpZ2h0PSI0NiIgdmlld0JveD0iMCAwIDQwIDQ2IiB2ZXJzaW9uPSIxLjEiPjxwYXRoIGQ9IiIgc3Ryb2tlPSJub25lIiBmaWxsPSIjMTBhYzdjIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiLz48cGF0aCBkPSJNIDEwIDE2Ljc2OCBMIDEuNTAwIDMyLjQ4OSAxLjE4NCAzNC43NDQgTCAwLjg2NyAzNyA1LjA4NyAzNyBMIDkuMzA3IDM3IDE0LjczNiAzMS44NjUgTCAyMC4xNjUgMjYuNzMxIDI1LjM2NCAzMS44NjUgTCAzMC41NjMgMzcgMzQuNzIyIDM3IEwgMzguODgyIDM3IDM5LjUxMCAzNS45ODMgTCA0MC4xMzkgMzQuOTY2IDMwLjkwMyAxNy45ODMgTCAyMS42NjggMSAyMC4wODQgMS4wMjQgTCAxOC41MDAgMS4wNDggMTAgMTYuNzY4IE0gMTcuNjY4IDMzLjA0NiBMIDE1IDM1LjE0NSAxNSAzNi43MDUgTCAxNSAzOC4yNjQgMTcuMDgyIDQxLjYzMiBMIDE5LjE2MyA0NSAyMC4zODIgNDUgTCAyMS42MDEgNDUgMjMuNzMwIDQwLjYxOSBMIDI1Ljg1OCAzNi4yMzggMjMuMDk3IDMzLjU5MyBMIDIwLjMzNiAzMC45NDggMTcuNjY4IDMzLjA0NiIgc3Ryb2tlPSJub25lIiBmaWxsPSIjMGNhYzdjIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiLz48L3N2Zz4="); }
|
||
.face-text .pool img.viabtc { content: url("data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyB3aWR0aD0iODBweCIgaGVpZ2h0PSI4MHB4IiB2aWV3Qm94PSIwIDAgODAgODAiIHZlcnNpb249IjEuMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+CiAgICA8dGl0bGU+VmlhQlRDPC90aXRsZT4KICAgIDxnIGlkPSLpobXpnaItMSIgc3Ryb2tlPSJub25lIiBzdHJva2Utd2lkdGg9IjEiIGZpbGw9Im5vbmUiIGZpbGwtcnVsZT0iZXZlbm9kZCI+CiAgICAgICAgPGcgaWQ9IueUu+advyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTE4Ni4wMDAwMDAsIC0xODYzLjAwMDAwMCkiIGZpbGwtcnVsZT0ibm9uemVybyI+CiAgICAgICAgICAgIDxnIGlkPSJWaWFCVEMiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDE4Ni4wMDAwMDAsIDE4NjMuMDAwMDAwKSI+CiAgICAgICAgICAgICAgICA8ZyBpZD0iQi1Db3B5LTEzIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgxLjAwMDAwMCwgMC4wMDAwMDApIj4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNNjIuMDcxOTQyNCwxNy44NDE3MjY2IEw2MS44MTI5NDk2LDE4LjE1ODI3MzQgTDYxLjU1Mzk1NjgsMTcuODcwNTAzNiBDNTYuNTQ2NzYyNiwxMi42MzMwOTM1IDUwLjA0MzE2NTUsOS4yOTQ5NjQwMyA0Mi44NDg5MjA5LDguNDAyODc3NyBMNDIuNTMyMzc0MSw4LjM3NDEwMDcyIEw0Mi41MzIzNzQxLDEuNjI5MzkyMDZlLTE1IEw0Mi45MDY0NzQ4LDAuMDI4Nzc2OTc4NCBDNTMuMTUxMDc5MSwxLjA5MzUyNTE4IDYyLjM4ODQ4OTIsNi4wMTQzODg0OSA2OC45NDk2NDAzLDEzLjc1NTM5NTcgTDY5LjM4MTI5NSwxNC4yNzMzODEzIEw2OC43MTk0MjQ1LDE0LjMzMDkzNTMgQzY2LjEwMDcxOTQsMTQuNTMyMzc0MSA2My43MTIyMzAyLDE1Ljc5ODU2MTIgNjIuMDcxOTQyNCwxNy44NDE3MjY2IFoiIGlkPSJTaGFwZV80XyIgZmlsbD0iIzUyQ0JDQSI+PC9wYXRoPgogICAgICAgICAgICAgICAgICAgIDxwYXRoIGQ9Ik03Ni41NzU1Mzk2LDMwLjA3MTk0MjQgTDc3LjAwNzE5NDIsMjkuNTgyNzMzOCBMNzcuMTUxMDc5MSwzMC4yMTU4MjczIEM3Ny44MTI5NDk2LDMyLjk3ODQxNzMgNzguMTU4MjczNCwzNS44ODQ4OTIxIDc4LjE1ODI3MzQsMzguOTY0MDI4OCBDNzguMTU4MjczNCw0NS4wMDcxOTQyIDc2LjcxOTQyNDUsNTAuOTkyODA1OCA3NC4wMTQzODg1LDU2LjM3NDEwMDcgTDczLjg0MTcyNjYsNTYuNzE5NDI0NSBMNjYuOTkyODA1OCw1MS45MTM2NjkxIEw2Ny4xMDc5MTM3LDUxLjY1NDY3NjMgQzY4LjkyMDg2MzMsNDcuNzk4NTYxMiA2OS44OTkyODA2LDQzLjQyNDQ2MDQgNjkuODk5MjgwNiwzOC45NjQwMjg4IEM2OS44OTkyODA2LDM3LjE3OTg1NjEgNjkuNzU1Mzk1NywzNS40NTMyMzc0IDY5LjQzODg0ODksMzMuNjk3ODQxNyBMNjkuMzgxMjk1LDMzLjMyMzc0MSBMNjkuNzg0MTcyNywzMy4yOTQ5NjQgQzcyLjQ2MDQzMTcsMzMuMTUxMDc5MSA3NC44Nzc2OTc4LDMyIDc2LjU3NTUzOTYsMzAuMDcxOTQyNCBaIiBpZD0iU2hhcGVfNV8iIGZpbGw9IiM1MkNCQ0EiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNOC4yODc3Njk3OCwzOC45NjQwMjg4IEM4LjI4Nzc2OTc4LDQzLjQyNDQ2MDQgOS4yMzc0MTAwNyw0Ny43OTg1NjEyIDExLjA3OTEzNjcsNTEuNjU0Njc2MyBMMTEuMTk0MjQ0Niw1MS45MTM2NjkxIEw0LjMxNjU0Njc2LDU2LjcxOTQyNDUgTDQuMTQzODg0ODksNTYuMzc0MTAwNyBDMS40MTAwNzE5NCw1MS4wNzkxMzY3IDMuMjc0NzU4NTZlLTE1LDQ1LjE3OTg1NjEgMy4yNzQ3NTg1NmUtMTUsMzguOTY0MDI4OCBDMy4yNzQ3NTg1NmUtMTUsMzYuMjg3NzY5OCAwLjI4Nzc2OTc4NCwzMy42MTE1MTA4IDAuODM0NTMyMzc0LDMwLjkwNjQ3NDggTDAuOTQ5NjQwMjg4LDMwLjMwMjE1ODMgTDEuNDEwMDcxOTQsMzAuNzA1MDM2IEMzLjE2NTQ2NzYzLDMyLjMxNjU0NjggNS41NTM5NTY4MywzMy4yNjYxODcxIDcuOTQyNDQ2MDQsMzMuMjY2MTg3MSBMOC44MDU3NTU0LDMzLjI2NjE4NzEgTDguNzQ4MjAxNDQsMzMuNjY5MDY0NyBDOC40MzE2NTQ2OCwzNS40NTMyMzc0IDguMjg3NzY5NzgsMzcuMTc5ODU2MSA4LjI4Nzc2OTc4LDM4Ljk2NDAyODggWiIgaWQ9IlNoYXBlXzZfIiBmaWxsPSIjNTJDQkNBIj48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTE2LjI1ODk5MjgsMTguMzAyMTU4MyBMMTUuOTcxMjIzLDE4LjYxODcwNSBMMTUuNzEyMjMwMiwxOC4yNzMzODEzIEMxNC4yMTU4MjczLDE2LjIwMTQzODggMTEuOTQyNDQ2LDE0LjczMzgxMjkgOS40MTAwNzE5NCwxNC4zMDIxNTgzIEw4LjgwNTc1NTQsMTQuMjE1ODI3MyBMOS4xNzk4NTYxMiwxMy43NTUzOTU3IEMxNS42ODM0NTMyLDUuOTg1NjExNTEgMjUuMDM1OTcxMiwxLjAwNzE5NDI0IDM1LjI1MTc5ODYsMC4wMjg3NzY5Nzg0IEwzNS42MjU4OTkzLDQuMTUzMzUyMzJlLTE2IEwzNS42MjU4OTkzLDguMzc0MTAwNzIgTDM1LjMwOTM1MjUsOC40MDI4Nzc3IEMyNy45NzEyMjMsOS4yOTQ5NjQwMyAyMS4xNTEwNzkxLDEyLjg2MzMwOTQgMTYuMjU4OTkyOCwxOC4zMDIxNTgzIFoiIGlkPSJTaGFwZV83XyIgZmlsbD0iIzUyQ0JDQSI+PC9wYXRoPgogICAgICAgICAgICAgICAgICAgIDxwYXRoIGQ9Ik0xNC43NjI1ODk5LDU3Ljg3MDUwMzYgTDE0Ljk2NDAyODgsNTguMTI5NDk2NCBDMTguOTA2NDc0OCw2My4wNzkxMzY3IDI0LjI4Nzc2OTgsNjYuNzA1MDM2IDMwLjI3MzM4MTMsNjguNDg5MjA4NiBMMzAuNjQ3NDgyLDY4LjYwNDMxNjUgTDMwLjQ3NDgyMDEsNjguOTc4NDE3MyBDMjkuODcwNTAzNiw3MC4yNzMzODEzIDI5LjUyNTE3OTksNzEuNzQxMDA3MiAyOS41MjUxNzk5LDczLjE1MTA3OTEgQzI5LjUyNTE3OTksNzQuMjczMzgxMyAyOS43MjY2MTg3LDc1LjM2NjkwNjUgMzAuMTAwNzE5NCw3Ni40NjA0MzE3IEwzMC4zMzA5MzUzLDc3LjA2NDc0ODIgTDI5LjY5Nzg0MTcsNzYuOTIwODYzMyBDMjEuMDY0NzQ4Miw3NC43OTEzNjY5IDEzLjQ2NzYyNTksNjkuODEyOTQ5NiA4LjE3MjY2MTg3LDYyLjkwNjQ3NDggTDcuOTQyNDQ2MDQsNjIuNjE4NzA1IEwxNC43NjI1ODk5LDU3Ljg3MDUwMzYgWiIgaWQ9IlNoYXBlXzhfIiBmaWxsPSIjNTJDQkNBIj48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTQ3LjY1NDY3NjMsNjguOTc4NDE3MyBMNDcuNDgyMDE0NCw2OC42MDQzMTY1IEw0Ny44NTYxMTUxLDY4LjQ4OTIwODYgQzUzLjg3MDUwMzYsNjYuNzA1MDM2IDU5LjIyMzAyMTYsNjMuMDc5MTM2NyA2My4xNjU0Njc2LDU4LjEyOTQ5NjQgTDYzLjM2NjkwNjUsNTcuODcwNTAzNiBMNzAuMTU4MjczNCw2Mi41ODk5MjgxIEw2OS45MjgwNTc2LDYyLjg3NzY5NzggQzY0LjU3NTUzOTYsNjkuNzg0MTcyNyA1Ni45NDk2NDAzLDc0Ljc5MTM2NjkgNDguNDAyODc3Nyw3Ni44OTIwODYzIEw0Ny43Njk3ODQyLDc3LjAzNTk3MTIgTDQ4LDc2LjQzMTY1NDcgQzQ4LjM3NDEwMDcsNzUuMzM4MTI5NSA0OC41NzU1Mzk2LDc0LjI0NDYwNDMgNDguNTc1NTM5Niw3My4xMjIzMDIyIEM0OC42MDQzMTY1LDcxLjc0MTAwNzIgNDguMjU4OTkyOCw3MC4yNzMzODEzIDQ3LjY1NDY3NjMsNjguOTc4NDE3MyBaIiBpZD0iU2hhcGVfOV8iIGZpbGw9IiM1MkNCQ0EiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNNjkuNDY3NjI1OSwzMC42MTg3MDUgQzY1LjY5Nzg0MTcsMzAuNjE4NzA1IDYyLjYxODcwNSwyNy41NjgzNDUzIDYyLjYxODcwNSwyMy43Njk3ODQyIEM2Mi42MTg3MDUsMTkuOTcxMjIzIDY1LjY2OTA2NDcsMTYuOTIwODYzMyA2OS40Njc2MjU5LDE2LjkyMDg2MzMgQzczLjIzNzQxMDEsMTYuOTIwODYzMyA3Ni4zMTY1NDY4LDE5Ljk3MTIyMyA3Ni4zMTY1NDY4LDIzLjc2OTc4NDIgQzc2LjMxNjU0NjgsMjcuNTY4MzQ1MyA3My4yMzc0MTAxLDMwLjYxODcwNSA2OS40Njc2MjU5LDMwLjYxODcwNSBaIE03Ljk0MjQ0NjA0LDMwLjYxODcwNSBDNC4xNzI2NjE4NywzMC42MTg3MDUgMS4wOTM1MjUxOCwyNy41NjgzNDUzIDEuMDkzNTI1MTgsMjMuNzY5Nzg0MiBDMS4wOTM1MjUxOCwxOS45NzEyMjMgNC4xNDM4ODQ4OSwxNi45MjA4NjMzIDcuOTQyNDQ2MDQsMTYuOTIwODYzMyBDMTEuNzQxMDA3MiwxNi45MjA4NjMzIDE0Ljc5MTM2NjksMTkuOTcxMjIzIDE0Ljc5MTM2NjksMjMuNzY5Nzg0MiBDMTQuNzkxMzY2OSwyNy41NjgzNDUzIDExLjcxMjIzMDIsMzAuNjE4NzA1IDcuOTQyNDQ2MDQsMzAuNjE4NzA1IFogTTM5LjA3OTEzNjcsODAgQzM1LjMwOTM1MjUsODAgMzIuMjMwMjE1OCw3Ni45NDk2NDAzIDMyLjIzMDIxNTgsNzMuMTUxMDc5MSBDMzIuMjMwMjE1OCw2OS4zNTI1MTggMzUuMzA5MzUyNSw2Ni4zMDIxNTgzIDM5LjA3OTEzNjcsNjYuMzAyMTU4MyBDNDIuODQ4OTIwOSw2Ni4zMDIxNTgzIDQ1LjkyODA1NzYsNjkuMzUyNTE4IDQ1LjkyODA1NzYsNzMuMTUxMDc5MSBDNDUuOTI4MDU3Niw3Ni45NDk2NDAzIDQyLjg0ODkyMDksODAgMzkuMDc5MTM2Nyw4MCBaIiBpZD0iQ29tYmluZWQtU2hhcGUiIGZpbGw9IiM1MkNCQ0EiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNNDguNjYxODcwNSwzMi40MzE2NTQ3IEM0Ny40NTMyMzc0LDM3LjM4MTI5NSAzOS44NTYxMTUxLDM0Ljg0ODkyMDkgMzcuMzUyNTE4LDM0LjI0NDYwNDMgTDM5LjU2ODM0NTMsMjUuNTgyNzMzOCBDNDEuOTg1NjExNSwyNi4xMjk0OTY0IDQ5Ljg3MDUwMzYsMjcuMzM4MTI5NSA0OC42NjE4NzA1LDMyLjQzMTY1NDcgTDQ4LjY2MTg3MDUsMzIuNDMxNjU0NyBaIE00Ny4yODA1NzU1LDQ2LjUwMzU5NzEgQzQ1Ljg5OTI4MDYsNTEuOTcxMjIzIDM2LjgwNTc1NTQsNDkuMDA3MTk0MiAzMy44NDE3MjY2LDQ4LjI1ODk5MjggTDM2LjI1ODk5MjgsMzguNjc2MjU5IEMzOS4xNjU0Njc2LDM5LjQyNDQ2MDQgNDguNjYxODcwNSw0MC44NjMzMDk0IDQ3LjI4MDU3NTUsNDYuNTAzNTk3MSBMNDcuMjgwNTc1NSw0Ni41MDM1OTcxIFogTTQ4LjUxNzk4NTYsMjIuNDc0ODIwMSBMNTAuMjczMzgxMywxNS4zMzgxMjk1IEw0NS45NTY4MzQ1LDE0LjE4NzA1MDQgTDQ0LjIwMTQzODgsMjEuMTc5ODU2MSBDNDMuMDUwMzU5NywyMC44NjMzMDk0IDQxLjkyODA1NzYsMjAuNjYxODcwNSA0MC43MTk0MjQ1LDIwLjM0NTMyMzcgTDQyLjQ3NDgyMDEsMTMuMzUyNTE4IEwzOC4xNTgyNzM0LDEyLjI4Nzc2OTggTDM2LjM0NTMyMzcsMTkuNDI0NDYwNCBDMzUuNDI0NDYwNCwxOS4xOTQyNDQ2IDM0LjQ0NjA0MzIsMTguOTY0MDI4OCAzMy41MjUxNzk5LDE4LjgyMDE0MzkgTDI3LjUxMDc5MTQsMTcuMjk0OTY0IEwyNi4zNTk3MTIyLDIxLjkyODA1NzYgTDI5LjU1Mzk1NjgsMjIuNjc2MjU5IEMzMS4zMDkzNTI1LDIzLjEzNjY5MDYgMzEuNTk3MTIyMywyNC4yNTg5OTI4IDMxLjU5NzEyMjMsMjUuMTc5ODU2MSBMMjkuNTUzOTU2OCwzMy4yOTQ5NjQgQzI5LjY5Nzg0MTcsMzMuMzgxMjk1IDI5Ljg3MDUwMzYsMzMuMzgxMjk1IDMwLjAxNDM4ODUsMzMuNDM4ODQ4OSBDMjkuODcwNTAzNiwzMy4zNTI1MTggMjkuNjk3ODQxNywzMy4zNTI1MTggMjkuNTUzOTU2OCwzMy4yOTQ5NjQgTDI2LjcwNTAzNiw0NC44MDU3NTU0IEMyNi40NzQ4MjAxLDQ1LjMyMzc0MSAyNS45NTY4MzQ1LDQ2LjE4NzA1MDQgMjQuNzE5NDI0NSw0NS44NzA1MDM2IEMyNC44MDU3NTU0LDQ1Ljk1NjgzNDUgMjEuNTI1MTc5OSw0NS4xMjIzMDIyIDIxLjUyNTE3OTksNDUuMTIyMzAyMiBMMTkuMzA5MzUyNSw1MC4xMjk0OTY0IEwyNC45MjA4NjMzLDUxLjUxMDc5MTQgQzI1Ljk4NTYxMTUsNTEuODI3MzM4MSAyNi45NjQwMjg4LDUyLjAyODc3NyAyOC4wMjg3NzcsNTIuMzQ1MzIzNyBMMjYuMjE1ODI3Myw1OS41NjgzNDUzIEwzMC41MzIzNzQxLDYwLjYzMzA5MzUgTDMyLjM0NTMyMzcsNTMuNDk2NDAyOSBDMzMuNDk2NDAyOSw1My44MTI5NDk2IDM0LjcwNTAzNiw1NC4xMDA3MTk0IDM1LjgyNzMzODEsNTQuNDE3MjY2MiBMMzQuMDE0Mzg4NSw2MS40Njc2MjU5IEwzOC4zMzA5MzUzLDYyLjUzMjM3NDEgTDQwLjE0Mzg4NDksNTUuMzA5MzUyNSBDNDcuNTk3MTIyMyw1Ni42OTA2NDc1IDUzLjEyMjMwMjIsNTYuMTQzODg0OSA1NS40ODIwMTQ0LDQ5LjQ2NzYyNTkgQzU3LjM4MTI5NSw0NC4wODYzMzA5IDU1LjM5NTY4MzUsNDAuODkyMDg2MyA1MS40NTMyMzc0LDM4LjkwNjQ3NDggQzU0LjQxNzI2NjIsMzguMzAyMTU4MyA1Ni41NDY3NjI2LDM2LjQwMjg3NzcgNTcuMTUxMDc5MSwzMi41MTc5ODU2IEM1Ny45ODU2MTE1LDI3LjE5NDI0NDYgNTMuOTg1NjExNSwyNC4zNzQxMDA3IDQ4LjUxNzk4NTYsMjIuNDc0ODIwMSBaIiBpZD0iU2hhcGVfMTBfIiBmaWxsPSIjRkZCOTAwIj48L3BhdGg+CiAgICAgICAgICAgICAgICA8L2c+CiAgICAgICAgICAgIDwvZz4KICAgICAgICA8L2c+CiAgICA8L2c+Cjwvc3ZnPg=="); }
|
||
.face-text .pool img.f2pool { content: url("data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyB3aWR0aD0iODBweCIgaGVpZ2h0PSI4MHB4IiB2aWV3Qm94PSIwIDAgODAgODAiIHZlcnNpb249IjEuMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+CiAgICA8dGl0bGU+RjJQb29sPC90aXRsZT4KICAgIDxkZWZzPgogICAgICAgIDxwb2x5Z29uIGlkPSJwYXRoLTEiIHBvaW50cz0iMCAwIDgwIDAgODAgODAuMDAwMjk2MyAwIDgwLjAwMDI5NjMiPjwvcG9seWdvbj4KICAgIDwvZGVmcz4KICAgIDxnIGlkPSLpobXpnaItMSIgc3Ryb2tlPSJub25lIiBzdHJva2Utd2lkdGg9IjEiIGZpbGw9Im5vbmUiIGZpbGwtcnVsZT0iZXZlbm9kZCI+CiAgICAgICAgPGcgaWQ9IueUu+advyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTE4Ni4wMDAwMDAsIC05NTcuMDAwMDAwKSI+CiAgICAgICAgICAgIDxnIGlkPSJGMlBvb2wiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDE4Ni4wMDAwMDAsIDk1Ny4wMDAwMDApIj4KICAgICAgICAgICAgICAgIDxnIGlkPSLnvJbnu4QiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDAuMDAwMDAwLCAtMC4wMDAwMDApIj4KICAgICAgICAgICAgICAgICAgICA8Zz4KICAgICAgICAgICAgICAgICAgICAgICAgPG1hc2sgaWQ9Im1hc2stMiIgZmlsbD0id2hpdGUiPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgPHVzZSB4bGluazpocmVmPSIjcGF0aC0xIj48L3VzZT4KICAgICAgICAgICAgICAgICAgICAgICAgPC9tYXNrPgogICAgICAgICAgICAgICAgICAgICAgICA8ZyBpZD0iQ2xpcC0yIj48L2c+CiAgICAgICAgICAgICAgICAgICAgICAgIDxwYXRoIGQ9Ik00MC4wMDAxNDgxLDAgQzE3LjkwODIxNDUsMCAwLDE3LjkwODIxNDUgMCw0MC4wMDAxNDgxIEMwLDYyLjA5MjA4MTggMTcuOTA4MjE0NSw4MC4wMDAyOTYzIDQwLjAwMDE0ODEsODAuMDAwMjk2MyBDNjIuMDkyMDgxOCw4MC4wMDAyOTYzIDgwLjAwMDI5NjMsNjIuMDkyMDgxOCA4MC4wMDAyOTYzLDQwLjAwMDE0ODEgQzgwLjAwMDI5NjMsMTcuOTA4MjE0NSA2Mi4wOTIwODE4LDAgNDAuMDAwMTQ4MSwwIiBpZD0iRmlsbC0xIiBmaWxsPSIjNDA2MkZGIiBtYXNrPSJ1cmwoI21hc2stMikiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8L2c+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTUwLjQ4ODQ4MzMsNjMuMDgxODYzMyBDNDMuNjI5MTk4Niw1OS4wODE4NDg1IDQzLjM3NzM0NTgsNTEuMDk2NjMzNyA0My4zNzczNDU4LDUxLjA5NjYzMzcgQzQyLjc4MDMwNjYsNTUuNDQzMzE2NSA0My45MDc3MTgyLDU5Ljg1MDc0MDIgNDYuNTE4MDk4Miw2My4zNzgxNjA3IEM0NC41MzU4Njg3LDYzLjM5Mjk3NTUgNDIuNTU2NjAyMSw2My4yNjQwODYyIDQwLjU5MjE1MDMsNjIuOTkxNDkyNiBDMzcuMjIwMjg2LDY1Ljc2MzM1NDcgMzIuNzc0MzQzNiw2Ni44NTIyNDc2IDI4LjUwMzIxNjcsNjUuOTU0NDY2NSBDMzAuNjkyODU0NCw2NS4wNDc3OTY1IDMxLjg3NjU2MjUsNjIuNjY0MDgzOSAzMS4yNzM1OTczLDYwLjM3MDc0MjEgQzIyLjA1ODc0ODQsNTUuNzkyOTQ3NCAxNy44MzY1MTA1LDQ1LjgwNzcyNTIgMjEuNDM2NTIzOCwzNC41NDg0MjQzIEMyNC4wNzY1MzM2LDM3LjQwMDI4NjcgMjcuNDY0Njk0MywzOS40NTM2Mjc2IDMxLjIxNDMzNzgsNDAuNDc0MzcyMSBDMzcuODY2MjE0Myw0Mi4yMjI1MjY4IDQxLjQzNjU5NzksMzcuMjE1MTAwOCAzOC41MDMyNTM3LDMyLjk3ODA0ODEgQzQ1LjQ1MTQyNzYsMzMuNzMzNjA2NCA2MC40NTg4OTA2LDQzLjczMjE2MiA2MS41NDAzNzYxLDU4LjE2MzMyNjUgQzU4LjUzODg4MzUsNjEuMDQxODU1NyA1NC42NDU1MzU3LDYyLjgxMjIzMjYgNTAuNTAzMjk4Miw2My4xODU1Njc0IEw1MC40ODg0ODMzLDYzLjA4MTg2MzMgWiBNMjcuOTQwMjUxNiwyNC41NjMyMDIxIEMyNy45NDAyNTE2LDI0LjU2MzIwMjEgMjYuOTYyNDcwMiwzNS4yMTUwOTM0IDMyLjA3MzYwMDMsMzcuODk2NTg0OCBDMzIuMDczNjAwMywzNy44OTY1ODQ4IDI4LjQ4ODQwMTgsMzkuMzc4MDcxOCAyMS43MDMxOTE1LDMzLjU0MTAxMzEgQzIyLjgwMjQ1NDgsMjkuOTczNTkyNSAyNC45NjI0NjI4LDI2LjgyNjkxNDIgMjcuODk1ODA3LDI0LjUxODc1NzUgTDI3Ljk0MDI1MTYsMjQuNTYzMjAyMSBaIE0zNy41ODQ3MzE4LDEyLjI4MTY3NTEgQzM3LjU4NDczMTgsMTIuMjgxNjc1MSAzNi4yODEwMjMzLDIxLjE3MDU5NjkgNDEuNzE4MDgwNCwyNS4wMDc2NDgyIEMzOC4yMzY1ODYxLDI2Ljc0MDk4NzkgMzAuODQzOTY2MSwyMi45MzM1NjY0IDI4Ljc2OTg4NDMsMjMuNTI2MTYxMiBDMzAuMzE1MDc1MiwxOC44MzEzMjkgMzMuNDYxNzUzNiwxNC44Mjk4MzI3IDM3LjY1ODgwNjEsMTIuMjIyNDE1NiBMMzcuNTg0NzMxOCwxMi4yODE2NzUxIFogTTUyLjM5OTYwMTUsNTQuMzU1OTA1IEM1Mi40NDk5NzIsNTUuMzIwMzUzIDUzLjI3MDcxNTgsNTYuMDYxMDk2NSA1NC4yMzUxNjM4LDU2LjAxMjIwNzUgQzU1LjA4NTUzNzQsNTUuOTY3NzYyOCA1NS43ODAzNTQ3LDU1LjMxODg3MTYgNTUuODgxMDk1OSw1NC40NzI5NDI1IEw1NS44ODEwOTU5LDU0LjM1NTkwNSBDNTUuNzkyMjA2Niw1My4zOTQ0MiA1NC45NDAzNTE2LDUyLjY4NjI2OTIgNTMuOTc4ODY2Niw1Mi43NzUxNTg0IEM1My4xNDE4MjY1LDUyLjg1MzY3NzIgNTIuNDc2NjM4OCw1My41MTczODM0IDUyLjM5OTYwMTUsNTQuMzU1OTA1IEw1Mi4zOTk2MDE1LDU0LjM1NTkwNSBaIiBpZD0iRmlsbC0zIiBmaWxsPSIjRkZGRkZGIj48L3BhdGg+CiAgICAgICAgICAgICAgICA8L2c+CiAgICAgICAgICAgIDwvZz4KICAgICAgICA8L2c+CiAgICA8L2c+Cjwvc3ZnPg=="); }
|
||
.face-text .pool img.marapool { content: url("data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyB3aWR0aD0iMjU2IiBoZWlnaHQ9IjI1NiIgdmlld0JveD0iMCAwIDI1NiAyNTYiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxwYXRoIGQ9Ik0wIDMuNjAwOEMwIDIuMzQzMTMgMCAxLjcxNDMgMC4yNDQ3NTcgMS4yMzM5NEMwLjQ2MDA1MiAwLjgxMTQgMC44MDM1ODcgMC40Njc4NjQgMS4yMjYxMyAwLjI1MjU3QzEuNzA2NDkgMC4wMDc4MTI1IDIuMzM1MzIgMC4wMDc4MTI1IDMuNTkyOTggMC4wMDc4MTI1SDI1Mi40MDdDMjUzLjY2NSAwLjAwNzgxMjUgMjU0LjI5NCAwLjAwNzgxMjUgMjU0Ljc3NCAwLjI1MjU3QzI1NS4xOTYgMC40Njc4NjQgMjU1LjU0IDAuODExNCAyNTUuNzU1IDEuMjMzOTRDMjU2IDEuNzE0MyAyNTYgMi4zNDMxMyAyNTYgMy42MDA4VjI1Mi40MTVDMjU2IDI1My42NzIgMjU2IDI1NC4zMDEgMjU1Ljc1NSAyNTQuNzgyQzI1NS41NCAyNTUuMjA0IDI1NS4xOTYgMjU1LjU0OCAyNTQuNzc0IDI1NS43NjNDMjU0LjI5NCAyNTYuMDA4IDI1My42NjUgMjU2LjAwOCAyNTIuNDA3IDI1Ni4wMDhIMy41OTI5OUMyLjMzNTMyIDI1Ni4wMDggMS43MDY0OSAyNTYuMDA4IDEuMjI2MTMgMjU1Ljc2M0MwLjgwMzU4NyAyNTUuNTQ4IDAuNDYwMDUyIDI1NS4yMDQgMC4yNDQ3NTcgMjU0Ljc4MkMwIDI1NC4zMDEgMCAyNTMuNjcyIDAgMjUyLjQxNVYzLjYwMDhaIiBmaWxsPSIjMjcyNTI1Ii8+CjxwYXRoIGQ9Ik01OS4yODUgNDguMDYyNUM1OC43ODg5IDQ4LjA2MjUgNTguMzg2NyA0OC40NjQ3IDU4LjM4NjcgNDguOTYwN1YxNTkuNDQ1QzU4LjM4NjcgMTU5Ljk0MSA1OC43ODg5IDE2MC4zNDMgNTkuMjg1IDE2MC4zNDNIODAuMDc0OUM4MC41NzA5IDE2MC4zNDMgODAuOTczMSAxNTkuOTQxIDgwLjk3MzEgMTU5LjQ0NVY4Mi4zODlIODQuNjMzNUwxMTcuNjQ5IDE1OS43OTdDMTE3Ljc5IDE2MC4xMjggMTE4LjExNiAxNjAuMzQzIDExOC40NzUgMTYwLjM0M0gxMzcuODA5QzEzOC4xNjkgMTYwLjM0MyAxMzguNDk0IDE2MC4xMjggMTM4LjYzNSAxNTkuNzk3TDE3MS42NTEgODIuMzg5SDE3NS4zMTFWMTU5LjQ0NUMxNzUuMzExIDE1OS45NDEgMTc1LjcxNCAxNjAuMzQzIDE3Ni4yMSAxNjAuMzQzSDE5N0MxOTcuNDk2IDE2MC4zNDMgMTk3Ljg5OCAxNTkuOTQxIDE5Ny44OTggMTU5LjQ0NVY0OC45NjA3QzE5Ny44OTggNDguNDY0NyAxOTcuNDk2IDQ4LjA2MjUgMTk3IDQ4LjA2MjVIMTY0LjI5QzE2My45MzEgNDguMDYyNSAxNjMuNjA1IDQ4LjI3NzMgMTYzLjQ2NCA0OC42MDg0TDEyOS45NzIgMTI3LjE0SDEyNi4zMTJMOTIuODIwMiA0OC42MDg0QzkyLjY3OSA0OC4yNzczIDkyLjM1MzkgNDguMDYyNSA5MS45OTQgNDguMDYyNUg1OS4yODVaIiBmaWxsPSIjRUVFQ0U4Ii8+CjxwYXRoIGQ9Ik01OC4zODY3IDE5NC45MjZDNTguMzg2NyAxOTQuNDMgNTguNzg4OSAxOTQuMDI3IDU5LjI4NSAxOTQuMDI3SDE5Ni45OTlDMTk3LjQ5NiAxOTQuMDI3IDE5Ny44OTggMTk0LjQzIDE5Ny44OTggMTk0LjkyNlYyMTUuNTg1QzE5Ny44OTggMjE2LjA4MSAxOTcuNDk2IDIxNi40ODQgMTk2Ljk5OSAyMTYuNDg0SDU5LjI4NUM1OC43ODg5IDIxNi40ODQgNTguMzg2NyAyMTYuMDgxIDU4LjM4NjcgMjE1LjU4NVYxOTQuOTI2WiIgZmlsbD0iI0YyQTkwMCIvPgo8L3N2Zz4K"); }
|
||
.face-text .pool img.unknown { content: url("data:image/svg+xml;base64,PHN2ZyBmaWxsPSJub25lIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjUuMjcgMyAxMy40OCAxOCI+IDxwYXRoIGQ9Ik01LjY0MTcgMTguMzY5NkM1LjE1ODM0IDE3Ljg4NzEgNS4xNTgzMyAxNy4xMTMgNS42NDE2OSAxNi42MzA0QzcuMjY5OTIgMTUuMDA1MSA5LjUxNzYxIDE0IDEyIDE0QzE0LjQ4MjUgMTQgMTYuNzMwMSAxNS4wMDUgMTguMzU4MyAxNi42MzA0QzE4Ljg0MTcgMTcuMTEyOSAxOC44NDE3IDE3Ljg4NzEgMTguMzU4NCAxOC4zNjk2QzE2LjczMDEgMTkuOTk0OSAxNC40ODI0IDIxIDEyIDIxQzkuNTE3NTkgMjEgNy4yNjk5MyAxOS45OTUgNS42NDE3IDE4LjM2OTZaIiBmaWxsPSIjYjRiNGI0Ij48L3BhdGg+IDxwYXRoIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBkPSJNOC41MDAwMyA3LjVIMTUuNVY4SDE2QzE2IDEwLjYzNzIgMTQuMzE4OCAxMyAxMiAxM0M5LjY4MTIzIDEzIDguMDAwMDMgMTAuNjM3MiA4LjAwMDAzIDhIOC41MDAwM1Y3LjVaTTkuMDIyNzMgOC41QzkuMjEyNjYgMTAuNTY3OCAxMC41NjU4IDEyIDEyIDEyQzEzLjQzNDMgMTIgMTQuNzg3NCAxMC41Njc4IDE0Ljk3NzMgOC41SDkuMDIyNzNaIiBmaWxsPSIjYjRiNGI0Ij48L3BhdGg+IDxwYXRoIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBkPSJNMTIgM0MxNC40ODUzIDMgMTYuNSA1LjIzODU4IDE2LjUgOEg3LjUwMDAzQzcuNTAwMDMgNS4yMzg1OCA5LjUxNDc1IDMgMTIgM1pNMTIgNy41QzEyLjgyODUgNy41IDEzLjUgNi44Mjg0MyAxMy41IDZDMTMuNSA1LjE3MTU3IDEyLjgyODUgNC41IDEyIDQuNUMxMS4xNzE2IDQuNSAxMC41IDUuMTcxNTcgMTAuNSA2QzEwLjUgNi44Mjg0MyAxMS4xNzE2IDcuNSAxMiA3LjVaIiBmaWxsPSIjYjRiNGI0Ij48L3BhdGg+IDxwYXRoIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBkPSJNNi41MDAwMyA4LjVDNi41MDAwMyA4LjIyMzg2IDYuNzIzODkgOCA3LjAwMDAzIDhIMTdDMTcuMjc2MiA4IDE3LjUgOC4yMjM4NiAxNy41IDguNUMxNy41IDguNzc2MTQgMTcuMjc2MiA5IDE3IDlINy4wMDAwM0M2LjcyMzg5IDkgNi41MDAwMyA4Ljc3NjE0IDYuNTAwMDMgOC41WiIgZmlsbD0iI2I0YjRiNCI+PC9wYXRoPiA8L3N2Zz4="); }
|
||
|
||
/* ---- cube face colors (derived from --face-color, same logic
|
||
as website/styles/panes/explorer.css) ---- */
|
||
svg.cube {
|
||
--face-color: var(--orange);
|
||
--face-right: light-dark(
|
||
oklch(from var(--face-color) calc(l - var(--face-step) * 2) c h),
|
||
var(--face-color)
|
||
);
|
||
--face-left: light-dark(
|
||
oklch(from var(--face-color) calc(l - var(--face-step)) c h),
|
||
oklch(from var(--face-color) calc(l + var(--face-step)) c h)
|
||
);
|
||
--face-top: light-dark(
|
||
var(--face-color),
|
||
oklch(from var(--face-color) calc(l + var(--face-step) * 2) c h)
|
||
);
|
||
--face-bottom: oklch(from var(--face-color) calc(l - var(--face-step) * 3) c h);
|
||
color: light-dark(var(--black), var(--white));
|
||
}
|
||
|
||
/* Glass polygons: translucent. Liquid polygons: opaque. Rear-face
|
||
colors mirror demo.html (bottom → face-bottom, rear-left →
|
||
face-top, rear-right → face-left). */
|
||
svg.cube .glass { fill-opacity: var(--empty-alpha); }
|
||
|
||
svg.cube .glass-top, svg.cube .liquid-top { fill: var(--face-top); }
|
||
svg.cube .glass-right, svg.cube .liquid-right { fill: var(--face-right); }
|
||
svg.cube .glass-left, svg.cube .liquid-left { fill: var(--face-left); }
|
||
svg.cube .glass-bottom { fill: var(--face-bottom); }
|
||
svg.cube .glass-rear-left { fill: var(--face-top); }
|
||
svg.cube .glass-rear-right { fill: var(--face-left); }
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div class="wrap">
|
||
<!-- SVG shell. All polygons + text-face transforms are generated
|
||
in JS from the cube constants (ISO, OX, OY, CUBE), so the
|
||
geometry has a single source of truth. DOM order defines
|
||
z-order: rear polygons, liquid, front polygons, text. -->
|
||
<template id="logo-template">
|
||
<div class="logo-slot">
|
||
<svg class="cube"></svg>
|
||
</div>
|
||
</template>
|
||
|
||
<section>
|
||
<div class="row" id="row"></div>
|
||
</section>
|
||
<section>
|
||
<div class="row" id="fills"></div>
|
||
</section>
|
||
<section>
|
||
<div class="row" id="variants"></div>
|
||
</section>
|
||
<section>
|
||
<div class="row" id="with-text"></div>
|
||
</section>
|
||
</div>
|
||
|
||
<script>
|
||
// --- Cube geometry: everything derives from these 4 constants.
|
||
// Change ISO/OX/OY/CUBE and the entire cube reprojects. ---
|
||
const ISO = 0.866, OX = 0.3, OY = 0.6, CUBE = 100;
|
||
const W = 2 * ISO * CUBE, H = 2 * CUBE; // viewBox 173.2 × 200
|
||
|
||
// Hex vertices (iso projection of the 8 cube vertices; parallel
|
||
// pairs collapse into V.C, then these 7 outline the silhouette).
|
||
const V = {
|
||
T: [W/2, 0 ],
|
||
UR: [W, H/4 ], UL: [0, H/4 ],
|
||
C: [W/2, H/2 ],
|
||
LR: [W, 3*H/4 ], LL: [0, 3*H/4 ],
|
||
B: [W/2, H ],
|
||
};
|
||
const lerp = ([ax,ay], [bx,by], t) => [ax + (bx-ax)*t, ay + (by-ay)*t];
|
||
|
||
// Static glass polygons. DOM order sets z-order (rear polygons
|
||
// first, then liquid, then front). All share the .glass class so
|
||
// the single fill-opacity rule applies to both rear and front.
|
||
const GLASS_REAR = [
|
||
{ cls: 'glass glass-bottom', pts: [V.C, V.LR, V.B, V.LL] },
|
||
{ cls: 'glass glass-rear-left', pts: [V.C, V.LL, V.UL, V.T] },
|
||
{ cls: 'glass glass-rear-right', pts: [V.C, V.LR, V.UR, V.T] },
|
||
];
|
||
const GLASS_FRONT = [
|
||
{ cls: 'glass glass-top', pts: [V.UL, V.T, V.UR, V.C] },
|
||
{ cls: 'glass glass-right', pts: [V.UR, V.LR, V.B, V.C] },
|
||
{ cls: 'glass glass-left', pts: [V.UL, V.LL, V.B, V.C] },
|
||
];
|
||
|
||
// Liquid surface at fill f is a linear interp of the cube's
|
||
// bottom-face corners (f=0) toward its top-face corners (f=1).
|
||
// The 3 liquid sub-polygons clip the visible front faces at it.
|
||
const surface = (f) => ({
|
||
back: lerp(V.C, V.T, f),
|
||
tr: lerp(V.LR, V.UR, f),
|
||
front: lerp(V.B, V.C, f),
|
||
tl: lerp(V.LL, V.UL, f),
|
||
});
|
||
const liquidPolygons = (f) => {
|
||
if (f <= 0) return [];
|
||
const s = surface(f);
|
||
return [
|
||
{ cls: 'liquid-top', pts: [s.back, s.tr, s.front, s.tl] },
|
||
{ cls: 'liquid-right', pts: [s.tr, V.LR, V.B, s.front] },
|
||
{ cls: 'liquid-left', pts: [s.tl, V.LL, V.B, s.front] },
|
||
];
|
||
};
|
||
|
||
// Face-text transforms: outer translate re-anchors the cube
|
||
// origin (HTML demo's (0,0)) to the viewBox, then per-face
|
||
// `rotate skewX translate scaleY(ISO)` matches the HTML demo.
|
||
// Composed into a single transform per face and set directly on
|
||
// each <foreignObject> — no wrapping <g>.
|
||
const OUTER_TF =
|
||
`translate(${W/2 - ISO*(OX+1)*CUBE} ${H/2 - (0.5*(OX+1) + OY/ISO)*CUBE})`;
|
||
const tf = (rot, skew, tx, ty) =>
|
||
`${OUTER_TF} rotate(${rot}) skewX(${skew}) translate(${tx} ${ty}) scale(1 ${ISO})`;
|
||
const TEXT_FACES = [
|
||
['top', tf( 30, -30, (OX + OY/ISO) * CUBE, (OY - ISO) * CUBE)],
|
||
['right', tf(-30, -30, (OX + 1) * CUBE, ((OX + 1) * ISO + OY) * CUBE)],
|
||
['left', tf( 30, 30, OX * CUBE, OY * CUBE)],
|
||
];
|
||
|
||
const SVGNS = 'http://www.w3.org/2000/svg';
|
||
const XHTMLNS = 'http://www.w3.org/1999/xhtml';
|
||
const svgEl = (tag, attrs = {}) => {
|
||
const e = document.createElementNS(SVGNS, tag);
|
||
for (const [k, v] of Object.entries(attrs)) e.setAttribute(k, String(v));
|
||
return e;
|
||
};
|
||
const ptsAttr = (pts) => pts.map(p => p.join(',')).join(' ');
|
||
const addPoly = (parent, cls, pts) =>
|
||
parent.appendChild(svgEl('polygon', { class: cls, points: ptsAttr(pts) }));
|
||
|
||
const template = document.getElementById('logo-template');
|
||
|
||
const makeLogo = ({ fill = 0.5, faceColor, cubeScheme } = {}) => {
|
||
const slot = template.content.cloneNode(true).firstElementChild;
|
||
const svg = slot.querySelector('svg');
|
||
svg.setAttribute('viewBox', `0 0 ${W} ${H}`);
|
||
svg.style.setProperty('--fill', String(fill));
|
||
if (faceColor) svg.style.setProperty('--face-color', faceColor);
|
||
svg.style.setProperty('color-scheme', cubeScheme ?? 'light');
|
||
|
||
for (const f of GLASS_REAR) addPoly(svg, f.cls, f.pts);
|
||
for (const f of liquidPolygons(fill)) addPoly(svg, f.cls, f.pts);
|
||
for (const f of GLASS_FRONT) addPoly(svg, f.cls, f.pts);
|
||
|
||
for (const [face, transform] of TEXT_FACES) {
|
||
const fo = svgEl('foreignObject', { width: CUBE, height: CUBE, transform });
|
||
const div = document.createElementNS(XHTMLNS, 'div');
|
||
div.setAttribute('class', `face-text ${face}`);
|
||
fo.appendChild(div);
|
||
svg.appendChild(fo);
|
||
}
|
||
return slot;
|
||
};
|
||
|
||
const makeTile = (cls, label, content) => {
|
||
const tile = document.createElement('div');
|
||
tile.className = `tile ${cls}`;
|
||
tile.appendChild(content);
|
||
const lbl = document.createElement('span');
|
||
lbl.className = 'label';
|
||
lbl.textContent = label;
|
||
tile.appendChild(lbl);
|
||
return tile;
|
||
};
|
||
|
||
// Row 1: cube on each background.
|
||
const row = document.getElementById('row');
|
||
row.appendChild(makeTile('bg-auto scheme-light', 'light', makeLogo()));
|
||
row.appendChild(makeTile('bg-auto scheme-dark', 'dark', makeLogo()));
|
||
row.appendChild(makeTile('bg-paper scheme-light', 'paper', makeLogo()));
|
||
row.appendChild(makeTile('bg-gradient scheme-light', 'gradient', makeLogo()));
|
||
row.appendChild(makeTile('bg-image-1 scheme-light', 'img 1', makeLogo()));
|
||
row.appendChild(makeTile('bg-image-2 scheme-light', 'img 2', makeLogo()));
|
||
|
||
// Row 2: fill levels.
|
||
const fills = document.getElementById('fills');
|
||
for (const f of [0, 0.1, 0.25, 0.5, 0.75, 1])
|
||
fills.appendChild(makeTile('bg-auto scheme-light', `fill ${f}`, makeLogo({ fill: f })));
|
||
|
||
// Row 3: cube variants × bg theme (same matrix as demo.html).
|
||
const variants = document.getElementById('variants');
|
||
const neutLight = { faceColor: 'var(--border-color)', cubeScheme: 'light' };
|
||
const neutDark = { faceColor: 'var(--border-color)', cubeScheme: 'dark' };
|
||
const variantTiles = [
|
||
{ label: 'light / light', bg: 'scheme-light', opts: neutLight },
|
||
{ label: 'light / dark', bg: 'scheme-dark', opts: neutLight },
|
||
{ label: 'dark / light', bg: 'scheme-light', opts: neutDark },
|
||
{ label: 'dark / dark', bg: 'scheme-dark', opts: neutDark },
|
||
{ label: 'orange / light', bg: 'scheme-light', opts: {} },
|
||
{ label: 'orange / dark', bg: 'scheme-dark', opts: {} },
|
||
];
|
||
for (const v of variantTiles)
|
||
variants.appendChild(makeTile(`bg-auto ${v.bg}`, v.label, makeLogo(v.opts)));
|
||
|
||
// Row 4: text-in-cube — same variant matrix as row 3 with realistic
|
||
// block content (same as demo.html's `with-text` section).
|
||
const sampleBlocks = [
|
||
{ height: 912345, date: '2026-04-17', time: '12:00:00', miner: 'Foundry USA', mid: 12, min: 1, max: 64 },
|
||
{ height: 912346, date: '2026-04-17', time: '12:10:23', miner: 'AntPool', mid: 8, min: 2, max: 21 },
|
||
{ height: 912347, date: '2026-04-17', time: '12:22:51', miner: 'ViaBTC', mid: 45, min: 8, max: 180 },
|
||
{ height: 912348, date: '2026-04-17', time: '12:31:07', miner: 'F2Pool', mid: 3, min: 1, max: 9 },
|
||
{ height: 912349, date: '2026-04-17', time: '12:40:33', miner: 'MARA Pool', mid: 120, min: 40, max: 350 },
|
||
{ height: 912350, date: '2026-04-17', time: '12:48:59', miner: 'Unknown', mid: 5, min: 1, max: 15 },
|
||
];
|
||
const MONTHS = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'];
|
||
const shortDate = (iso) => {
|
||
const [, m, d] = iso.split('-').map(Number);
|
||
return `${MONTHS[m - 1]} ${d}`;
|
||
};
|
||
// Tiny DOM builders.
|
||
const el = (tag, cls, text) => {
|
||
const e = document.createElement(tag);
|
||
if (cls) e.className = cls;
|
||
if (text != null) e.textContent = text;
|
||
return e;
|
||
};
|
||
const p = (text, cls) => el('p', cls, text);
|
||
const span = (text, cls) => el('span', cls, text);
|
||
const slug = (s) => s.toLowerCase().replace(/\s+/g, '');
|
||
|
||
// Mirror of website/scripts/explorer/render.js createHeightElement:
|
||
// dimmed "#000…" prefix padding the height to 7 digits.
|
||
const heightSpan = (h) => {
|
||
const s = String(h);
|
||
const prefix = span('#' + '0'.repeat(Math.max(0, 7 - s.length)), 'dim');
|
||
prefix.style.userSelect = 'none';
|
||
const c = document.createElement('span');
|
||
c.append(prefix, span(s));
|
||
return c;
|
||
};
|
||
|
||
const makeBlockCube = (opts, block) => {
|
||
const slot = makeLogo(opts);
|
||
const q = (sel) => slot.querySelector(sel);
|
||
const [hh, mm] = block.time.slice(0, 5).split(':');
|
||
|
||
// Top: date / HH:MM (colon dimmed).
|
||
const timeP = p();
|
||
timeP.append(hh, span(':', 'dim'), mm);
|
||
q('.face-text.top').append(p(shortDate(block.date)), timeP);
|
||
|
||
// Right: height (sm) / raw pool-logo + miner name (ellipsis-clipped).
|
||
const heightP = p(null, 'height');
|
||
heightP.appendChild(heightSpan(block.height));
|
||
const poolDiv = el('div', 'pool');
|
||
const logo = el('img', slug(block.miner));
|
||
const nameSpan = span(block.miner.replace(/\s+(Pool|USA)$/i, '').trim());
|
||
poolDiv.append(logo, nameSpan);
|
||
q('.face-text.right').append(heightP, poolDiv);
|
||
|
||
// Left: ~median / min-max / sat/vB (dash + unit dimmed).
|
||
const range = p();
|
||
range.append(String(block.min), span('-', 'dim'), String(block.max));
|
||
const fees = el('div', 'fees');
|
||
fees.append(p(`~${block.mid}`), range, p('sat/vB', 'dim'));
|
||
q('.face-text.left').append(fees);
|
||
|
||
return slot;
|
||
};
|
||
const withText = document.getElementById('with-text');
|
||
variantTiles.forEach((v, i) =>
|
||
withText.appendChild(makeTile(`bg-auto ${v.bg}`, v.label, makeBlockCube(v.opts, sampleBlocks[i])))
|
||
);
|
||
|
||
</script>
|
||
</body>
|
||
</html>
|