diff --git a/ui/index.html b/ui/index.html index de3818b..26cf663 100644 --- a/ui/index.html +++ b/ui/index.html @@ -7,7 +7,7 @@ diff --git a/ui/src/App.css b/ui/src/App.css index 6e100e9..a505525 100644 --- a/ui/src/App.css +++ b/ui/src/App.css @@ -1,378 +1,526 @@ -/* Design tokens and layout ported from design/Iceberg.dc.html (Claude Design). */ +/* Deep-water terminal: the whole page is submerged. The public record sits in + cold light near the surface; your decoded plan glows warm in the depths. + Cold = anyone can see it. Warm = only you can. */ :root { - --bg: #eceef0; - --panel: #fbfcfc; - --fill: #f4f5f6; - --border: #d7dbde; - --border-soft: #e4e7e9; - --ink: #14171a; - --ink-2: #3a4247; - --ink-3: #6b7378; - /* Darkened from #7d878d / #9aa3a8: at 10px uppercase those measured 3.6:1 and - 2.5:1 against the panels, under the 4.5:1 floor. These clear it. */ - --muted: #656e74; - --muted-2: #737c82; - - --dark-bg: #0d1114; - --dark-panel: #131a1f; - --dark-border: #232d34; - --dark-border-2: #2c3841; - --dark-border-3: #56656e; - --dark-ink: #eef1f2; - --dark-ink-2: #f6f8f8; - --dark-muted: #8b979e; - --dark-muted-2: #cfd6da; - --dark-muted-3: #6f7c84; - --dark-locked: #3b464d; - - --accent: #e8a33d; - --accent-hover: #f2b558; - - /* Large solid fills sit a step softer than text black: at bar-and-block size - full #14171a on a light surface glares. */ - --ink-fill: #1e242a; - - --pad-x: clamp(16px, 4vw, 44px); + --abyss: #04070a; + --deep: #070c12; + --surface: #0b131b; + --surface-2: #101c26; + --raised: #142330; + + --border: #1b2a36; + --border-2: #263a48; + --border-lit: #33566a; + + --text: #e9f3f8; + --text-2: #b3c6d2; + --muted: #8ba3b2; + --muted-2: #6d8595; + + /* Cold: the public record. */ + --ice: #5ee0ff; + --ice-2: #a8f0ff; + --ice-glow: rgba(94, 224, 255, 0.35); + + /* Warm: your own data, the only warm light down here. */ + --warm: #ffb547; + --warm-2: #ffd18a; + --warm-glow: rgba(255, 181, 71, 0.3); + + --pad-x: clamp(18px, 5vw, 72px); --ease-out: cubic-bezier(0.16, 1, 0.3, 1); + --ease-spring: cubic-bezier(0.34, 1.4, 0.64, 1); + + /* Three voices, strictly assigned: + serif = what we say (headline, section titles, the thesis) + sans = how we explain (prose, labels, controls) + mono = what the chain says (every amount, hash, interval) + Nothing borrows another's job — that mixing is what read as sloppy. */ + --font-display: "Instrument Serif", Georgia, serif; + --font-text: "Libre Franklin", -apple-system, BlinkMacSystemFont, sans-serif; + --font-mono: "JetBrains Mono", ui-monospace, SFMono-Regular, monospace; + + /* One scale. Every size below comes from here, nothing ad hoc. */ + --fs-hero: clamp(52px, 8.4vw, 92px); + --fs-h2: clamp(28px, 3.8vw, 44px); + --fs-lead: clamp(18px, 1.95vw, 24px); + --fs-data-xl: clamp(34px, 4.2vw, 52px); + --fs-data-lg: clamp(25px, 2.7vw, 33px); + /* Plan values: five of them in one card, and mono runs much wider than the + serif this replaced — a step down keeps them inside their tracks. */ + --fs-data-md: clamp(20px, 2.1vw, 26px); + --fs-body: 14px; + --fs-sm: 13px; + --fs-label: 11px; + --fs-micro: 11px; + + --lh-hero: 0.92; + --lh-h2: 1.06; + --lh-lead: 1.45; + --lh-body: 1.62; + + /* Caps need air, but 0.2em+ turns every label into noise. */ + --tr-caps: 0.09em; + --tr-display: -0.025em; } * { box-sizing: border-box; } -html, body { - margin: 0; - padding: 0; - background: var(--bg); -} +html, body { margin: 0; padding: 0; background: var(--abyss); } body { - color: var(--ink); - font-family: "IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, monospace; - font-variant-numeric: tabular-nums; + color: var(--text); + font-family: var(--font-text); + font-size: var(--fs-body); + line-height: var(--lh-body); -webkit-font-smoothing: antialiased; text-rendering: optimizeLegibility; - /* Very slight light-from-above wash so the page isn't a dead flat fill. */ - background: - radial-gradient(1100px 520px at 12% -12%, #f5f7f8 0%, transparent 62%), - radial-gradient(900px 460px at 88% -6%, #f1f3f5 0%, transparent 58%), - var(--bg); - background-attachment: fixed; +} + +/* Data only. Tabular figures so columns of numbers line up. */ +.metric-value, +.metric-unit, +.metric-rpc, +.agg-value, +.agg-pair, +.plan-value, +.feed-row, +.tx, +.unit, +.timeline-val, +.timeline-tick, +.commitment-value, +.chunk-row .amount, +.badge { + font-family: var(--font-mono); + font-variant-numeric: tabular-nums; } input { font: inherit; } -::selection { background: var(--accent); color: #0d1114; } +::selection { background: var(--ice); color: var(--abyss); } +:focus-visible { outline: 2px solid var(--ice); outline-offset: 3px; } -:focus-visible { - outline: 2px solid var(--accent); - outline-offset: 2px; +@keyframes ib-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.2; } } +@keyframes ib-rise { from { opacity: 0; transform: translateY(22px); } to { opacity: 1; transform: none; } } +@keyframes ib-drift { + 0%, 100% { transform: translate(0, 0) scale(1); opacity: 0.55; } + 50% { transform: translate(2%, -3%) scale(1.06); opacity: 0.8; } } -@keyframes ib-pulse { - 0%, 100% { opacity: 1; } - 50% { opacity: 0.25; } -} +.rise { animation: ib-rise 780ms var(--ease-out) both; } +.rise-1 { animation-delay: 90ms; } +.rise-2 { animation-delay: 190ms; } +.rise-3 { animation-delay: 300ms; } -@keyframes ib-rise { - from { opacity: 0; transform: translateY(14px); } - to { opacity: 1; transform: none; } +@media (prefers-reduced-motion: reduce) { + *, *::before, *::after { + animation-duration: 0.01ms !important; + animation-iteration-count: 1 !important; + transition-duration: 0.01ms !important; + } } -.page { min-height: 100vh; position: relative; } - -/* Grain: kills gradient banding and takes the plastic sheen off flat panels. */ +/* Sonar grid + grain, fixed so the page feels like a window into water. */ +.page { + position: relative; + min-height: 100vh; + background: + linear-gradient(180deg, rgba(94, 224, 255, 0.05) 0%, transparent 24%), + var(--abyss); +} +.page::before { + content: ""; + position: fixed; + inset: 0; + pointer-events: none; + z-index: 0; + background-image: + linear-gradient(rgba(94, 224, 255, 0.055) 1px, transparent 1px), + linear-gradient(90deg, rgba(94, 224, 255, 0.055) 1px, transparent 1px); + background-size: 64px 64px; + mask-image: radial-gradient(ellipse 80% 55% at 50% 0%, #000 0%, transparent 78%); +} .page::after { content: ""; position: fixed; inset: 0; pointer-events: none; z-index: 9999; - opacity: 0.028; + opacity: 0.03; background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)'/%3E%3C/svg%3E"); } +.page > * { position: relative; z-index: 1; } -.rise { animation: ib-rise 640ms var(--ease-out) both; } -.rise-1 { animation-delay: 60ms; } -.rise-2 { animation-delay: 130ms; } -.rise-3 { animation-delay: 210ms; } +.serif { font-family: var(--font-display); font-weight: 400; letter-spacing: var(--tr-display); } -@media (prefers-reduced-motion: reduce) { - *, *::before, *::after { - animation-duration: 0.01ms !important; - animation-iteration-count: 1 !important; - transition-duration: 0.01ms !important; - } -} - -.serif { - font-family: Newsreader, Georgia, serif; - font-weight: 400; - letter-spacing: -0.01em; -} - -/* Small uppercase monospace label — the workhorse of this design. */ .lbl { - font-size: 10px; - letter-spacing: 0.16em; + font-family: var(--font-text); + font-size: var(--fs-label); + font-weight: 500; + letter-spacing: var(--tr-caps); text-transform: uppercase; + line-height: 1.3; color: var(--muted); } -.lbl-wide { letter-spacing: 0.2em; } +.lbl-wide { letter-spacing: 0.14em; } +/* Header — light shafts entering the water. */ .header { + position: relative; display: flex; flex-wrap: wrap; - gap: 24px; + gap: 28px; align-items: flex-end; justify-content: space-between; - padding: 26px var(--pad-x) 24px; - border-bottom: 1px solid var(--border); - background: var(--panel); - min-height: 120px; -} -.header-left { max-width: 640px; display: flex; flex-direction: column; gap: 10px; } -.title-row { display: flex; align-items: baseline; gap: 14px; flex-wrap: wrap; } -.title { margin: 0; font-size: clamp(34px, 4.4vw, 52px); letter-spacing: -0.02em; line-height: 0.95; } -.badge { font-size: 10px; letter-spacing: 0.16em; text-transform: uppercase; color: var(--muted); border: 1px solid var(--border); padding: 4px 7px; } -.thesis { margin: 0; font-size: clamp(16px, 1.5vw, 20px); line-height: 1.35; color: var(--ink-2); } -.header-right { display: flex; align-items: center; gap: 18px; } -.waterline-key { display: flex; flex-direction: column; gap: 4px; text-align: right; } -.waterline-key .on { color: var(--ink); } -.waterline-key .spaced { margin-top: 6px; } + padding: clamp(38px, 7vw, 76px) var(--pad-x) clamp(30px, 4vw, 44px); + overflow: hidden; +} +.header::before { + content: ""; + position: absolute; + inset: -40% -10% auto -10%; + height: 150%; + background: + radial-gradient(ellipse 46% 60% at 22% 0%, rgba(94, 224, 255, 0.16) 0%, transparent 62%), + radial-gradient(ellipse 38% 52% at 72% -6%, rgba(94, 224, 255, 0.1) 0%, transparent 60%); + animation: ib-drift 16s ease-in-out infinite; + pointer-events: none; +} +.header > * { position: relative; } +.header-left { max-width: 700px; display: flex; flex-direction: column; gap: 16px; } +.title-row { display: flex; align-items: baseline; gap: 18px; flex-wrap: wrap; } +.title { + margin: 0; + font-size: var(--fs-hero); + line-height: var(--lh-hero); + letter-spacing: var(--tr-display); + background: linear-gradient(170deg, var(--ice-2) 0%, var(--text) 42%, #7f97a6 100%); + -webkit-background-clip: text; + background-clip: text; + color: transparent; +} +.badge { + font-size: 10px; + letter-spacing: 0.12em; + text-transform: uppercase; + color: var(--ice); + border: 1px solid rgba(94, 224, 255, 0.32); + background: rgba(94, 224, 255, 0.06); + padding: 6px 10px; + border-radius: 2px; +} +.thesis { + margin: 0; + font-family: var(--font-display); + font-size: var(--fs-lead); + line-height: var(--lh-lead); + letter-spacing: -0.005em; + color: var(--text-2); + max-width: 46ch; +} +/* The two phrases that carry the whole idea. Italic serif lifts them without + another colour or weight — the eye lands on them first. */ +.thesis em { font-style: italic; color: var(--text); } + +.header-right { display: flex; align-items: center; gap: 22px; } +.waterline-key { display: flex; flex-direction: column; gap: 6px; text-align: right; } +.waterline-key .on { color: var(--ice); } +.waterline-key .spaced { margin-top: 8px; } .btn-ghost { - background: var(--panel); - border: 1px solid var(--border); - color: var(--ink); - font: inherit; - font-size: 10px; - letter-spacing: 0.16em; + background: rgba(94, 224, 255, 0.04); + border: 1px solid var(--border-2); + color: var(--text); + font-family: var(--font-text); + font-size: var(--fs-label); + font-weight: 500; + letter-spacing: var(--tr-caps); text-transform: uppercase; - padding: 11px 13px; + padding: 13px 17px; + border-radius: 2px; cursor: pointer; - transition: background 160ms ease, color 160ms ease, border-color 160ms ease; + transition: all 240ms var(--ease-out); +} +.btn-ghost:hover:not(:disabled) { + border-color: var(--ice); + color: var(--ice); + box-shadow: 0 0 0 1px rgba(94, 224, 255, 0.18), 0 0 26px -6px var(--ice-glow); + transform: translateY(-1px); } -.btn-ghost:hover:not(:disabled) { background: var(--ink); color: var(--panel); border-color: var(--ink); } -.btn-ghost:disabled { opacity: 0.45; cursor: default; } +.btn-ghost:disabled { opacity: 0.4; cursor: default; } +/* Metrics — instrument readout. */ .metrics { display: grid; - grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); + grid-template-columns: repeat(auto-fit, minmax(215px, 1fr)); + border-top: 1px solid var(--border); border-bottom: 1px solid var(--border); - background: var(--fill); + background: linear-gradient(180deg, rgba(94, 224, 255, 0.035), transparent); +} +.metric { + padding: 22px var(--pad-x); + border-right: 1px solid var(--border); + display: flex; + flex-direction: column; + gap: 10px; } -.metric { padding: 16px var(--pad-x); border-right: 1px solid var(--border); display: flex; flex-direction: column; gap: 6px; } .metric:last-child { border-right: 0; } -.metric-value { font-size: 26px; letter-spacing: -0.01em; } -.metric-unit { font-size: 12px; color: var(--muted); margin-left: 8px; } -.metric-rpc { font-size: 12px; display: flex; align-items: center; gap: 8px; color: var(--ink-2); padding-top: 8px; } +/* Reserve two lines for every metric label so a wrapping one doesn't push its + number off the baseline its neighbours sit on. */ +.metric .lbl { min-height: 2.6em; } +.metric-value { + font-size: var(--fs-data-lg); + font-weight: 400; + line-height: 1; + letter-spacing: -0.015em; + color: var(--text); +} +.metric-unit { font-size: var(--fs-micro); color: var(--muted); margin-left: 9px; letter-spacing: 0.04em; } +.metric-rpc { font-size: var(--fs-micro); display: flex; align-items: center; gap: 10px; color: var(--text-2); letter-spacing: 0.02em; } .pulse { - width: 6px; height: 6px; border-radius: 50%; - background: var(--accent); - box-shadow: 0 0 0 3px rgba(232, 163, 61, 0.18); - animation: ib-pulse 2s ease-in-out infinite; + width: 7px; height: 7px; border-radius: 50%; + background: var(--ice); + box-shadow: 0 0 0 4px rgba(94, 224, 255, 0.12), 0 0 14px var(--ice-glow); + animation: ib-pulse 2.4s ease-in-out infinite; display: inline-block; } -.section { padding: 34px var(--pad-x) 30px; } -.section-tight { padding: 0 var(--pad-x) 40px; } +.section { padding: clamp(46px, 6vw, 78px) var(--pad-x) clamp(30px, 4vw, 42px); } +.section-tight { padding: 0 var(--pad-x) clamp(48px, 6vw, 76px); } .section-head { - display: flex; flex-wrap: wrap; gap: 12px; - align-items: baseline; justify-content: space-between; margin-bottom: 20px; + display: flex; flex-wrap: wrap; gap: 20px; + align-items: flex-end; justify-content: space-between; margin-bottom: 30px; } -.section-head h2 { margin: 0; font-size: clamp(22px, 2.4vw, 30px); } -.section-head-left { display: flex; flex-direction: column; gap: 8px; } -.section-note { margin: 0; max-width: 420px; font-size: 12px; line-height: 1.75; color: var(--ink-3); } +.section-head h2 { margin: 0; font-size: var(--fs-h2); line-height: var(--lh-h2); } +.section-head-left { display: flex; flex-direction: column; gap: 14px; } +.section-note { margin: 0; max-width: 42ch; font-size: var(--fs-sm); line-height: var(--lh-body); color: var(--muted); } .card { border: 1px solid var(--border); - background: var(--panel); - box-shadow: 0 1px 2px rgba(20, 23, 26, 0.03), 0 10px 28px -20px rgba(20, 23, 26, 0.22); + background: linear-gradient(180deg, var(--surface) 0%, var(--deep) 100%); + border-radius: 3px; + box-shadow: 0 30px 70px -50px rgba(0, 0, 0, 0.9), inset 0 1px 0 rgba(255, 255, 255, 0.026); } -.timeline { padding: 18px 20px 14px; margin-bottom: 18px; } +.timeline { padding: 24px 26px 18px; margin-bottom: 22px; } .timeline-bars { - display: flex; align-items: flex-end; gap: clamp(6px, 1.4vw, 18px); - height: 92px; margin-top: 14px; border-bottom: 1px solid var(--border); + display: flex; align-items: flex-end; gap: clamp(6px, 1.4vw, 20px); + height: 116px; margin-top: 20px; border-bottom: 1px solid var(--border); } -.timeline-col { flex: 1; display: flex; flex-direction: column; justify-content: flex-end; align-items: center; gap: 6px; height: 100%; } -.timeline-val { font-size: 10px; color: var(--ink-3); } +.timeline-col { flex: 1; display: flex; flex-direction: column; justify-content: flex-end; align-items: center; gap: 8px; height: 100%; } +.timeline-val { font-size: var(--fs-micro); color: var(--ice); } .timeline-bar { width: 100%; - background: linear-gradient(180deg, #2b333a 0%, var(--ink-fill) 100%); + background: linear-gradient(180deg, var(--ice) 0%, rgba(94, 224, 255, 0.18) 100%); border-radius: 2px 2px 0 0; - transition: height 520ms var(--ease-out), opacity 200ms ease; + box-shadow: 0 0 18px -4px var(--ice-glow); + transition: height 620ms var(--ease-out), filter 220ms ease; } -.timeline-col:hover .timeline-bar { opacity: 0.82; } -.timeline-bar.empty { background: var(--border); border-radius: 1px; } -.timeline-ticks { display: flex; gap: clamp(6px, 1.4vw, 18px); margin-top: 7px; } -.timeline-tick { flex: 1; text-align: center; font-size: 10px; letter-spacing: 0.08em; color: var(--muted-2); } +.timeline-col:hover .timeline-bar { filter: brightness(1.25); } +.timeline-bar.empty { background: var(--border-2); box-shadow: none; } +.timeline-ticks { display: flex; gap: clamp(6px, 1.4vw, 20px); margin-top: 10px; } +.timeline-tick { flex: 1; text-align: center; font-size: var(--fs-micro); color: var(--muted-2); } -/* Five columns need ~600px; below that the table scrolls inside its own box - rather than dragging the whole page sideways. */ .feed-scroll { overflow-x: auto; } - .feed-cols { display: grid; - grid-template-columns: 84px minmax(110px, 1fr) minmax(110px, 1fr) minmax(140px, 1fr) minmax(110px, 0.9fr); - gap: 12px; - min-width: 620px; + grid-template-columns: 86px minmax(120px, 1fr) minmax(120px, 1fr) minmax(150px, 1fr) minmax(115px, 0.9fr); + gap: 14px; + min-width: 640px; } -.feed-head { padding: 11px 20px; border-bottom: 1px solid var(--border); background: var(--fill); } +.feed-head { padding: 15px 26px; border-bottom: 1px solid var(--border); } .feed-row { - padding: 15px 20px; - border-bottom: 1px solid var(--border-soft); + padding: 19px 26px; + border-bottom: 1px solid rgba(27, 42, 54, 0.6); align-items: center; - font-size: 14px; - transition: background 180ms ease, box-shadow 180ms ease; + font-size: var(--fs-body); + transition: background 200ms ease, box-shadow 200ms ease; } -.feed-row:hover { background: var(--fill); box-shadow: inset 2px 0 0 var(--accent); } -.feed-interval { color: var(--ink-3); } -.unit { font-size: 10px; color: var(--muted-2); margin-left: 6px; } -.counterparty { display: flex; align-items: center; gap: 9px; } +.feed-row:hover { background: rgba(94, 224, 255, 0.035); box-shadow: inset 2px 0 0 var(--ice); } +.feed-interval { color: var(--ice); } +.unit { font-size: var(--fs-micro); color: var(--muted-2); margin-left: 7px; } +.counterparty { display: flex; align-items: center; gap: 11px; } .redact { - display: inline-block; - width: 58px; - height: 10px; - border-radius: 1px; - background: repeating-linear-gradient( - 90deg, - var(--ink-fill) 0 11px, - #2a3238 11px 13px - ); -} -.tx { font-size: 12px; color: var(--ink-3); } -.feed-end { padding: 13px 20px; font-size: 11px; color: var(--muted-2); letter-spacing: 0.06em; } - -.assembly { padding: 20px; } -.assembly-head { display: flex; flex-wrap: wrap; gap: 14px; align-items: baseline; justify-content: space-between; margin-bottom: 22px; } -.assembly-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 26px; align-items: center; } -.assembly-chunks { display: flex; flex-direction: column; gap: 10px; } + display: inline-block; width: 62px; height: 11px; border-radius: 1px; + background: repeating-linear-gradient(90deg, var(--border-lit) 0 12px, var(--surface-2) 12px 14px); +} +.tx { font-size: var(--fs-micro); color: var(--muted-2); } +.feed-end { padding: 17px 26px; font-size: var(--fs-sm); color: var(--muted-2); } +.empty-note { padding: 20px 26px; font-size: var(--fs-sm); color: var(--muted-2); } + +.assembly { padding: 28px; } +.assembly-head { display: flex; flex-wrap: wrap; gap: 16px; align-items: center; justify-content: space-between; margin-bottom: 28px; } +.assembly-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(290px, 1fr)); gap: 32px; align-items: center; } +.assembly-chunks { display: flex; flex-direction: column; gap: 12px; } +.chunk-row .amount { font-size: 17px; letter-spacing: -0.01em; } .chunk-row { - display: flex; align-items: center; justify-content: space-between; gap: 14px; - border: 1px solid var(--border); background: var(--fill); padding: 13px 15px; + display: flex; align-items: center; justify-content: space-between; gap: 16px; + border: 1px solid var(--border-2); background: var(--surface-2); padding: 16px 18px; border-radius: 2px; transition: transform 900ms var(--ease-out), opacity 700ms ease; } -.assembly-agg { display: flex; flex-direction: column; gap: 12px; align-items: flex-start; } +.assembly-agg { display: flex; flex-direction: column; gap: 16px; align-items: flex-start; } .agg-card { - background: var(--panel); padding: 18px 20px; width: 100%; - transition: opacity 600ms ease, transform 600ms cubic-bezier(.4, 0, .2, 1), border-color 600ms ease; + background: linear-gradient(180deg, var(--raised) 0%, var(--surface) 100%); + padding: 24px 26px; width: 100%; border-radius: 3px; + transition: opacity 600ms ease, transform 600ms var(--ease-out), box-shadow 600ms ease; +} +.agg-amounts { display: flex; align-items: baseline; gap: 14px; margin-top: 12px; flex-wrap: wrap; } +.agg-value { + font-size: var(--fs-data-xl); line-height: 1; letter-spacing: -0.03em; font-weight: 400; + color: var(--ice-2); + text-shadow: 0 0 34px var(--ice-glow); } -.agg-amounts { display: flex; align-items: baseline; gap: 12px; margin-top: 8px; flex-wrap: wrap; } -.agg-value { font-size: clamp(26px, 3vw, 38px); letter-spacing: -0.02em; } -.agg-pair { font-size: 12px; color: var(--ink-3); } -.agg-identity { display: flex; align-items: center; gap: 9px; margin-top: 12px; padding-top: 12px; border-top: 1px solid var(--border-soft); } -.assembly-caption { margin: 0; font-size: 12px; line-height: 1.75; color: var(--ink-3); max-width: 380px; } +.agg-pair { font-size: var(--fs-sm); color: var(--muted); } +.agg-identity { display: flex; align-items: center; gap: 11px; margin-top: 18px; padding-top: 18px; border-top: 1px solid var(--border); } +.assembly-caption { margin: 0; font-size: var(--fs-sm); line-height: var(--lh-body); color: var(--muted); max-width: 40ch; } +/* The waterline: a lit horizon with shafts, then descent into the dark. */ .waterline { - position: relative; height: 132px; - background: linear-gradient(180deg, #eceef0 0%, #c9d2d7 34%, #4a5a63 62%, #0d1114 100%); + position: relative; height: 190px; overflow: hidden; + background: linear-gradient(180deg, var(--deep) 0%, #071119 30%, #050a0f 70%, var(--abyss) 100%); +} +.waterline::before { + content: ""; + position: absolute; inset: 0; + background: + radial-gradient(ellipse 55% 74% at 30% 0%, rgba(94, 224, 255, 0.16) 0%, transparent 66%), + radial-gradient(ellipse 40% 60% at 76% 4%, rgba(94, 224, 255, 0.1) 0%, transparent 62%); + animation: ib-drift 18s ease-in-out infinite reverse; +} +.waterline-line { + position: absolute; left: 0; right: 0; top: 30%; height: 1px; + background: linear-gradient(90deg, transparent, var(--ice), transparent); + opacity: 0.75; + box-shadow: 0 0 24px var(--ice-glow); +} +.waterline-tag { + position: absolute; left: var(--pad-x); top: 30%; transform: translateY(-190%); + font-family: var(--font-text); font-size: var(--fs-label); font-weight: 500; + letter-spacing: 0.14em; text-transform: uppercase; color: var(--ice); +} +.waterline-tip { + position: absolute; right: var(--pad-x); top: 30%; transform: translateY(70%); + font-family: var(--font-text); font-size: var(--fs-label); font-weight: 500; + letter-spacing: 0.14em; text-transform: uppercase; color: var(--muted-2); } -.waterline-line { position: absolute; left: 0; right: 0; top: 33%; height: 1px; background: #fff; opacity: 0.85; } -.waterline-tag { position: absolute; left: var(--pad-x); top: 33%; transform: translateY(-160%); font-size: 10px; letter-spacing: 0.24em; text-transform: uppercase; color: var(--ink-2); } -.waterline-tip { position: absolute; right: var(--pad-x); top: 33%; transform: translateY(60%); font-size: 10px; letter-spacing: 0.24em; text-transform: uppercase; color: var(--dark-muted-2); } +/* Below: the depths. Warm light only — because it's yours. */ .deep { - color: var(--dark-ink); - padding: 38px var(--pad-x) 46px; - /* Faint depth wash so the dark half reads as water, not a black rectangle. */ + padding: clamp(44px, 6vw, 74px) var(--pad-x) clamp(56px, 7vw, 92px); background: - radial-gradient(1000px 520px at 78% -8%, #161e25 0%, transparent 62%), - radial-gradient(700px 420px at 8% 12%, #121a20 0%, transparent 58%), - var(--dark-bg); -} -.deep h2 { color: var(--dark-ink-2); } -.deep .lbl { color: var(--dark-muted); } -.deep .section-note { color: var(--dark-muted); } -.deep-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); gap: 22px; align-items: start; } -.deep-grid + .deep-grid { margin-top: 22px; } + radial-gradient(ellipse 60% 44% at 74% 8%, rgba(255, 181, 71, 0.055) 0%, transparent 62%), + var(--abyss); +} +.deep h2 { color: var(--warm-2); } +.deep .section-note { color: var(--muted); } +.deep-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(330px, 1fr)); gap: 24px; align-items: start; } +.deep-grid + .deep-grid { margin-top: 24px; } .deep-card { - border: 1px solid var(--dark-border); - background: var(--dark-panel); - padding: 22px; - border-radius: 2px; - box-shadow: 0 18px 42px -30px rgba(0, 0, 0, 0.9); + border: 1px solid var(--border); + background: linear-gradient(180deg, var(--surface) 0%, var(--deep) 100%); + padding: 26px; border-radius: 3px; + box-shadow: 0 34px 74px -54px #000, inset 0 1px 0 rgba(255, 255, 255, 0.028); } -.field-row { display: flex; gap: 10px; margin-top: 12px; flex-wrap: wrap; } -.deep input { - background: var(--dark-bg); border: 1px solid var(--dark-border-2); color: var(--dark-ink); - padding: 12px 13px; font-size: 13px; outline: none; +.field-row { display: flex; gap: 12px; margin-top: 16px; flex-wrap: wrap; } +.deep input, .drawer-fields input { + background: var(--abyss); border: 1px solid var(--border-2); color: var(--text); + padding: 14px 15px; font-family: var(--font-mono); font-size: var(--fs-sm); outline: none; border-radius: 2px; + transition: border-color 200ms ease, box-shadow 200ms ease; +} +.deep input:focus, .drawer-fields input:focus { + border-color: var(--warm); + box-shadow: 0 0 0 3px rgba(255, 181, 71, 0.1); } -.deep input:focus { border-color: var(--accent); } -.secret-input { flex: 1; min-width: 180px; } +.secret-input { flex: 1; min-width: 190px; } .btn-accent { - background: var(--accent); border: 1px solid var(--accent); color: var(--dark-bg); - font: inherit; font-size: 10px; letter-spacing: 0.16em; text-transform: uppercase; - padding: 12px 16px; cursor: pointer; transition: background 200ms ease, color 200ms ease; + background: var(--warm); border: 1px solid var(--warm); color: #1a1206; + font-family: var(--font-text); font-size: var(--fs-label); font-weight: 600; + letter-spacing: var(--tr-caps); text-transform: uppercase; padding: 14px 20px; cursor: pointer; border-radius: 2px; + transition: all 240ms var(--ease-out); } -.btn-accent:hover:not(:disabled) { background: var(--accent-hover); border-color: var(--accent-hover); } -.btn-accent:disabled { background: transparent; border-color: var(--dark-border-2); color: var(--dark-border-3); cursor: default; } +.btn-accent:hover:not(:disabled) { + background: var(--warm-2); border-color: var(--warm-2); + box-shadow: 0 0 30px -6px var(--warm-glow); transform: translateY(-1px); +} +.btn-accent:disabled { background: transparent; border-color: var(--border-2); color: var(--muted-2); cursor: default; } .btn-dark { - background: transparent; border: 1px solid var(--dark-border-2); color: var(--dark-muted); - font: inherit; font-size: 10px; letter-spacing: 0.16em; text-transform: uppercase; - padding: 8px 11px; cursor: pointer; transition: color 160ms ease, border-color 160ms ease; -} -.btn-dark:hover:not(:disabled) { color: var(--dark-ink); border-color: var(--dark-border-3); } -.btn-dark:disabled { opacity: 0.4; cursor: default; } -.btn-dark.strong { border-color: var(--dark-border-3); color: var(--dark-ink); padding: 11px 15px; } -.btn-dark.strong:hover:not(:disabled) { background: #1c262c; } - -.btn-row { display: flex; gap: 12px; margin-top: 12px; align-items: center; flex-wrap: wrap; } -.commitment-block { margin-top: 18px; padding-top: 16px; border-top: 1px solid var(--dark-border); display: flex; flex-direction: column; gap: 6px; } -.commitment-value { font-size: 12px; color: var(--dark-muted-2); word-break: break-all; } - -.plan-card { display: flex; flex-direction: column; gap: 20px; } -.plan-head { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; } -.state-badge { font-size: 10px; letter-spacing: 0.14em; text-transform: uppercase; padding: 5px 8px; border: 1px solid var(--dark-border-2); color: var(--dark-muted); } -.state-badge.open { border-color: var(--accent); color: var(--accent); } -.plan-values { display: grid; grid-template-columns: repeat(auto-fit, minmax(132px, 1fr)); gap: 20px 24px; } -.plan-field { display: flex; flex-direction: column; gap: 7px; } -.plan-value { font-size: clamp(19px, 2vw, 24px); letter-spacing: -0.01em; color: var(--dark-ink-2); transition: color 300ms ease; } -.plan-value.locked { color: var(--dark-locked); } -.plan-value.accrued-open { color: var(--accent); } -.plan-progress { height: 3px; background: var(--dark-border); } -.plan-progress-fill { height: 100%; background: var(--accent); transition: width 700ms ease; } - -.act-card { display: flex; flex-direction: column; gap: 18px; } -.act-inputs { display: flex; gap: 12px; flex-wrap: wrap; align-items: flex-end; } -.act-inputs label { display: flex; flex-direction: column; gap: 7px; flex: 1; min-width: 104px; } -.act-inputs input { width: 100%; padding: 11px 12px; } -.act-buttons { display: flex; gap: 12px; flex-wrap: wrap; } -.act-line { font-size: 11px; line-height: 1.75; color: var(--dark-muted); word-break: break-word; } - -.privacy-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); gap: 20px; margin-top: 16px; } -.privacy-col { display: flex; flex-direction: column; gap: 9px; } -.privacy-col .lbl.hidden-lbl { color: var(--accent); } -.privacy-text { font-size: 12px; line-height: 1.7; color: var(--dark-muted-2); } -.privacy-text.dim { color: var(--dark-muted); } -.privacy-foot { margin: 16px 0 0; padding-top: 16px; border-top: 1px solid var(--dark-border); font-size: 11px; line-height: 1.7; color: var(--dark-muted-3); } + background: transparent; border: 1px solid var(--border-2); color: var(--muted); + font-family: var(--font-text); font-size: var(--fs-label); font-weight: 500; + letter-spacing: var(--tr-caps); text-transform: uppercase; padding: 11px 15px; cursor: pointer; border-radius: 2px; + transition: all 200ms var(--ease-out); +} +.btn-dark:hover:not(:disabled) { color: var(--text); border-color: var(--border-lit); } +.btn-dark:disabled { opacity: 0.35; cursor: default; } +.btn-dark.strong { border-color: var(--border-lit); color: var(--text); padding: 14px 18px; } +.btn-dark.strong:hover:not(:disabled) { background: rgba(94, 224, 255, 0.05); border-color: var(--ice); color: var(--ice); } + +.btn-row { display: flex; gap: 14px; margin-top: 16px; align-items: center; flex-wrap: wrap; } +.commitment-block { margin-top: 24px; padding-top: 20px; border-top: 1px solid var(--border); display: flex; flex-direction: column; gap: 9px; } +.commitment-value { font-size: var(--fs-micro); color: var(--muted); word-break: break-all; line-height: 1.75; } + +.plan-card { display: flex; flex-direction: column; gap: 26px; } +.plan-head { display: flex; align-items: center; justify-content: space-between; gap: 14px; } +.state-badge { + font-family: var(--font-text); font-size: 10px; font-weight: 600; letter-spacing: var(--tr-caps); + text-transform: uppercase; padding: 6px 10px; border: 1px solid var(--border-2); color: var(--muted-2); border-radius: 2px; +} +.state-badge.open { + border-color: var(--warm); color: var(--warm); + box-shadow: 0 0 22px -8px var(--warm-glow); +} +.plan-values { display: grid; grid-template-columns: repeat(auto-fit, minmax(152px, 1fr)); gap: 26px 30px; } +.plan-field { display: flex; flex-direction: column; gap: 10px; } +.plan-value { + font-size: var(--fs-data-md); line-height: 1.08; letter-spacing: -0.015em; + color: var(--text); transition: color 320ms ease; white-space: nowrap; +} +.plan-value.locked { color: #2f4250; } +.plan-value.accrued-open { color: var(--warm); text-shadow: 0 0 30px var(--warm-glow); } +.plan-progress { height: 2px; background: var(--border); border-radius: 2px; overflow: hidden; } +.plan-progress-fill { + height: 100%; background: linear-gradient(90deg, var(--warm), var(--warm-2)); + box-shadow: 0 0 14px var(--warm-glow); + transition: width 900ms var(--ease-out); +} + +.act-card { display: flex; flex-direction: column; gap: 22px; } +.act-inputs { display: flex; gap: 14px; flex-wrap: wrap; align-items: flex-end; } +.act-inputs label { display: flex; flex-direction: column; gap: 10px; flex: 1; min-width: 112px; } +.act-inputs input { width: 100%; } +.act-buttons { display: flex; gap: 14px; flex-wrap: wrap; } +.act-line { font-size: var(--fs-sm); line-height: var(--lh-body); color: var(--muted); word-break: break-word; } + +.privacy-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 26px; margin-top: 20px; } +.privacy-col { display: flex; flex-direction: column; gap: 12px; } +.privacy-col .lbl.hidden-lbl { color: var(--warm); } +.privacy-text { font-size: var(--fs-sm); line-height: var(--lh-body); color: var(--text-2); } +.privacy-text.dim { color: var(--muted); } +.privacy-foot { margin: 22px 0 0; padding-top: 20px; border-top: 1px solid var(--border); font-size: var(--fs-sm); line-height: var(--lh-body); color: var(--muted-2); } .drawer { - position: fixed; top: 0; right: 0; bottom: 0; width: min(380px, 88vw); - background: var(--panel); border-left: 1px solid var(--border); - padding: 26px 24px; overflow: auto; z-index: 20; - transition: transform 340ms cubic-bezier(.4, 0, .2, 1); -} -.drawer-head { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; margin-bottom: 22px; } -.drawer-fields { display: flex; flex-direction: column; gap: 16px; } -.drawer-fields label { display: flex; flex-direction: column; gap: 7px; } -.drawer-fields input { - background: var(--fill); border: 1px solid var(--border); color: var(--ink); - padding: 11px 12px; font-size: 13px; outline: none; -} -.drawer-fields input:focus { border-color: var(--ink); } -.drawer-pair { display: flex; gap: 12px; } + position: fixed; top: 0; right: 0; bottom: 0; width: min(400px, 90vw); + background: linear-gradient(180deg, var(--surface) 0%, var(--abyss) 100%); + border-left: 1px solid var(--border-2); + padding: 30px 26px; overflow: auto; z-index: 20; + box-shadow: -40px 0 90px -50px #000; + transition: transform 380ms var(--ease-out); +} +.drawer-head { display: flex; align-items: center; justify-content: space-between; gap: 14px; margin-bottom: 28px; } +.drawer-fields { display: flex; flex-direction: column; gap: 20px; } +.drawer-fields label { display: flex; flex-direction: column; gap: 10px; } +.drawer-pair { display: flex; gap: 14px; } .drawer-pair label { flex: 1; } -.drawer-note { margin: 4px 0 0; font-size: 11px; line-height: 1.7; color: var(--ink-3); } +.drawer-note { margin: 6px 0 0; font-size: var(--fs-sm); line-height: var(--lh-body); color: var(--muted-2); } .error { - margin: 0 var(--pad-x) 16px; - background: #f6e7ea; border: 1px solid #d9a3ae; color: #6d2233; - padding: 10px 14px; font-size: 12px; + font-family: var(--font-text); + margin: 0 var(--pad-x) 20px; + background: rgba(255, 92, 92, 0.07); border: 1px solid rgba(255, 92, 92, 0.32); + color: #ff9a9a; padding: 13px 16px; font-size: 12px; border-radius: 2px; } - -.empty-note { padding: 15px 20px; font-size: 12px; color: var(--muted-2); } diff --git a/ui/src/App.jsx b/ui/src/App.jsx index 323018d..82e6444 100644 --- a/ui/src/App.jsx +++ b/ui/src/App.jsx @@ -207,8 +207,8 @@ export default function App() { const totalChunks = plan.endInterval - plan.startInterval + 1n; return { chunk: formatAmount(plan.chunkAmount, Number(inDecimals)), - window: `intervals ${plan.startInterval}–${plan.endInterval}`, - progress: `${executedChunks(plan)} / ${totalChunks} chunks`, + window: `${plan.startInterval}–${plan.endInterval}`, + progress: `${executedChunks(plan)} / ${totalChunks}`, accrued: formatAmount(plan.accruedOut, Number(outDecimals)), claimed: formatAmount(plan.claimedOut, Number(outDecimals)), fraction: totalChunks > 0n ? Number(executedChunks(plan)) / Number(totalChunks) : 0, @@ -313,8 +313,9 @@ export default function App() { STRK20 private sprint

- Private scheduled trading on Starknet. The chain records one anonymous swap per interval - — only you can decode your own schedule out of it. + Private scheduled trading on Starknet. The chain records{" "} + one anonymous swap per interval — only you can decode{" "} + your own schedule out of it.

@@ -340,7 +341,7 @@ export default function App() { {status ? String(status.nextInterval) : "—"}
- active batch size / interval + batch size per interval {status ? formatAmount(status.chunkRate, Number(inDecimals)) : "—"} {inSymbol} @@ -461,7 +462,7 @@ export default function App() { ) : ( {chunk.label} )} - {chunk.amount} + {chunk.amount}
))} @@ -569,13 +570,13 @@ export default function App() {
- window + interval window {showField("window")}
- progress + chunks executed {showField("progress")}