@import "@fontsource/space-grotesk/500.css"; @import "@fontsource/space-grotesk/600.css"; @import "@fontsource/ibm-plex-sans/400.css"; @import "@fontsource/ibm-plex-sans/500.css"; @import "@fontsource/ibm-plex-mono/400.css"; @import "@fontsource/ibm-plex-mono/500.css"; :root { --bg-deep: #0b0e14; --bg-panel: #131822; --bg-panel-border: #232b38; --torus-glaze: #c97b56; --sun-gold: #ffb454; --orbit-trace: #6fd3c7; --bg-track: #1a2130; --text-primary: #e9e6df; --text-secondary: #8d94a3; --text-tertiary: #545e70; --font-display: "Space Grotesk", sans-serif; --font-body: "IBM Plex Sans", sans-serif; --font-mono: "IBM Plex Mono", monospace; --radius-md: 10px; --radius-sm: 6px; color-scheme: dark; } * { box-sizing: border-box; } html, body { height: 100%; } body { margin: 0; background: var(--bg-deep); color: var(--text-primary); font-family: var(--font-body); overflow: hidden; } #app { display: grid; grid-template-rows: auto 1fr auto; height: 100dvh; width: 100vw; } /* -- top bar -------------------------------------------------------- */ .topbar { display: flex; align-items: center; justify-content: space-between; gap: 1.5rem; padding: 0.85rem 1.5rem; border-bottom: 1px solid var(--bg-panel-border); background: var(--bg-panel); } .topbar__title { display: flex; align-items: baseline; gap: 0.65rem; min-width: 0; } .topbar__eyebrow { font-family: var(--font-display); font-size: 0.7rem; font-weight: 600; letter-spacing: 0.16em; text-transform: uppercase; color: var(--torus-glaze); white-space: nowrap; } .topbar__title h1 { font-family: var(--font-display); font-size: 1.05rem; font-weight: 500; margin: 0; color: var(--text-primary); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } /* -- viewport: the 3D panel --------------------------------------------- */ .viewport { display: grid; min-height: 0; } .panel { position: relative; background: var(--bg-deep); min-width: 0; min-height: 0; } .panel__canvas-host { position: absolute; inset: 0; width: 100%; height: 100%; display: block; } /* Two symmetric overlay affordances bookend the viewport: Physics (left) controls the world's parameters, Cutaway (right) controls how you see it. Same pill treatment, different accent color on press. */ .overlay-pill { position: absolute; top: 0.9rem; z-index: 2; display: flex; align-items: center; gap: 0.45rem; padding: 0.4rem 0.75rem 0.4rem 0.6rem; border-radius: 999px; border: 1px solid var(--bg-panel-border); background: rgba(19, 24, 34, 0.75); backdrop-filter: blur(6px); color: var(--text-secondary); font-family: var(--font-display); font-size: 0.72rem; font-weight: 500; letter-spacing: 0.02em; cursor: pointer; transition: background-color 120ms ease, border-color 120ms ease, color 120ms ease; } .overlay-pill--left { left: 1rem; } .overlay-pill--right { right: 1rem; } .overlay-pill:hover { border-color: #364155; color: var(--text-primary); } .overlay-pill:focus-visible { outline: 2px solid var(--sun-gold); outline-offset: 2px; } .overlay-pill svg { width: 16px; height: 16px; flex-shrink: 0; } .overlay-pill[aria-pressed="true"] { border-color: var(--orbit-trace); color: var(--orbit-trace); background: rgba(111, 211, 199, 0.1); } .overlay-pill--physics[aria-pressed="true"] { border-color: var(--sun-gold); color: var(--sun-gold); background: rgba(255, 180, 84, 0.1); } /* -- physics drawer ------------------------------------------------------ */ .physics-drawer { overflow: hidden; max-height: 0; transition: max-height 260ms cubic-bezier(0.4, 0, 0.2, 1); background: var(--bg-panel); border-top: 1px solid var(--bg-panel-border); } .physics-drawer.open { max-height: 10.5rem; } .physics-drawer__inner { padding: 1.1rem 1.5rem 1.3rem; display: grid; grid-template-columns: repeat(2, 1fr); gap: 1.6rem; } .slider-field { display: flex; flex-direction: column; gap: 0.55rem; } .slider-field__head { display: flex; align-items: baseline; justify-content: space-between; gap: 0.5rem; } .slider-field__label { font-family: var(--font-display); font-size: 0.68rem; font-weight: 600; letter-spacing: 0.08em; text-transform: uppercase; color: var(--text-secondary); display: flex; align-items: center; gap: 0.4rem; } .slider-field__label .swatch { width: 7px; height: 7px; border-radius: 50%; flex-shrink: 0; } .swatch--season { background: var(--torus-glaze); } .swatch--orbit { background: var(--orbit-trace); } .slider-field__value { font-family: var(--font-mono); font-size: 0.82rem; color: var(--text-primary); font-variant-numeric: tabular-nums; white-space: nowrap; } /* The orbit-size slider shows a live preview of the actual current orbit behind the track, and the season slider a schematic of the world's rotation against the sun's fixed plane -- both previews double as the control's own feedback rather than a separate readout. */ .slider-track { position: relative; height: 2.4rem; } .slider-track__preview { position: absolute; inset: 0; border-radius: 6px; background: var(--bg-track); overflow: hidden; border: 1px solid var(--bg-panel-border); } .slider-track__preview svg { width: 100%; height: 100%; display: block; } .slider-track input[type="range"] { -webkit-appearance: none; appearance: none; position: absolute; inset: 0; width: 100%; height: 100%; background: transparent; margin: 0; cursor: pointer; } .slider-track input[type="range"]::-webkit-slider-runnable-track { height: 100%; background: transparent; } .slider-track input[type="range"]::-moz-range-track { height: 100%; background: transparent; } input[type="range"]::-webkit-slider-thumb { -webkit-appearance: none; width: 14px; height: 14px; border-radius: 50%; cursor: grab; box-shadow: 0 0 0 3px var(--bg-deep), 0 0 10px 1px currentColor; border: none; } input[type="range"]::-moz-range-thumb { width: 14px; height: 14px; border-radius: 50%; cursor: grab; box-shadow: 0 0 0 3px var(--bg-deep), 0 0 10px 1px currentColor; border: none; } .thumb-season::-webkit-slider-thumb, .thumb-season::-moz-range-thumb { background: var(--torus-glaze); color: var(--torus-glaze); } .thumb-orbit::-webkit-slider-thumb, .thumb-orbit::-moz-range-thumb { background: var(--orbit-trace); color: var(--orbit-trace); } .slider-field__caption { font-family: var(--font-mono); font-size: 0.66rem; color: var(--text-tertiary); line-height: 1.4; } @media (max-width: 560px) { .physics-drawer__inner { grid-template-columns: 1fr; } } /* -- transport strip --------------------------------------------------- */ .transport { display: flex; align-items: center; gap: 1rem; padding: 0.7rem 1.5rem; border-top: 1px solid var(--bg-panel-border); background: var(--bg-panel); } .transport-btn { display: grid; place-items: center; width: 2.4rem; height: 2.4rem; flex-shrink: 0; border-radius: 50%; border: 1px solid var(--bg-panel-border); background: #1a2130; color: var(--text-primary); cursor: pointer; transition: background-color 120ms ease, border-color 120ms ease; } .transport-btn:hover { background: #212a3c; border-color: #364155; } .transport-btn:focus-visible { outline: 2px solid var(--sun-gold); outline-offset: 2px; } .transport-btn .icon { width: 18px; height: 18px; fill: currentColor; } .scrubber { position: relative; flex: 1 1 auto; height: 2.4rem; display: flex; align-items: center; cursor: pointer; touch-action: none; } .scrubber__track { position: absolute; left: 0; right: 0; height: 3px; border-radius: 2px; background: var(--bg-panel-border); } .scrubber__fill { position: absolute; left: 0; height: 3px; border-radius: 2px; background: var(--orbit-trace); width: 0%; pointer-events: none; } .scrubber__ticks { position: absolute; inset: 0; } /* 12 of these now (one every 4 hours of this world's 48-hour day), so each is smaller and plainer than the old 8 labeled critical-point ticks -- a quiet dotted ring, not individually called out. */ .scrubber__tick { position: absolute; top: 50%; transform: translate(-50%, -50%); width: 4px; height: 4px; border-radius: 50%; background: var(--text-tertiary); pointer-events: none; } .scrubber__playhead { position: absolute; top: 50%; left: 0%; width: 12px; height: 12px; border-radius: 50%; transform: translate(-50%, -50%) rotate(45deg); background: var(--sun-gold); box-shadow: 0 0 10px 1px rgba(255, 180, 84, 0.65); pointer-events: none; transition: background-color 120ms ease; } .readout { font-family: var(--font-mono); font-size: 0.82rem; color: var(--text-secondary); width: 3rem; flex-shrink: 0; font-variant-numeric: tabular-nums; } .speed-select { display: flex; align-items: center; gap: 0.5rem; flex-shrink: 0; } .speed-select__label { font-family: var(--font-display); font-size: 0.68rem; letter-spacing: 0.1em; text-transform: uppercase; color: var(--text-tertiary); } .speed-select select { font-family: var(--font-mono); font-size: 0.8rem; color: var(--text-primary); background: #1a2130; border: 1px solid var(--bg-panel-border); border-radius: var(--radius-sm); padding: 0.3rem 0.5rem; cursor: pointer; } .speed-select select:focus-visible { outline: 2px solid var(--sun-gold); outline-offset: 1px; } /* -- 3D panel fallback (e.g. WebGL unavailable) ------------------------ */ .panel-fallback { position: absolute; inset: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 0.5rem; padding: 2rem; text-align: center; font-family: var(--font-body); color: var(--text-secondary); } .panel-fallback p { margin: 0; } .panel-fallback__detail { font-family: var(--font-mono); font-size: 0.78rem; color: var(--text-tertiary); max-width: 32ch; } /* -- status / loading / error overlay --------------------------------- */ .status { position: fixed; inset: 0; display: none; align-items: center; justify-content: center; background: var(--bg-deep); font-family: var(--font-mono); font-size: 0.9rem; color: var(--text-secondary); text-align: center; padding: 2rem; z-index: 10; } .status.status--visible { display: flex; } .status.status--error { color: #e08a7a; } /* -- responsive: stack panels on narrow viewports ----------------------- */ @media (max-width: 860px) { .transport { flex-wrap: wrap; row-gap: 0.6rem; } .readout { order: 4; } .speed-select { order: 5; } } /* -- reduced motion ----------------------------------------------------- */ @media (prefers-reduced-motion: reduce) { .transport-btn, .scrubber__playhead { transition: none; } }