Files
beacon-web/src/index.css
T

154 lines
5.6 KiB
CSS

@import "tailwindcss";
/* theme tokens from palette CSS vars */
@theme {
--font-mono: "JetBrains Mono", monospace;
--font-sans: "Inter", system-ui, sans-serif;
--color-bg-base: var(--palette-bg-base, #09090B);
--color-bg-surface: var(--palette-bg-surface, #111114);
--color-bg-raised: var(--palette-bg-raised, #1A1A1F);
--color-border: var(--palette-border, #27272A);
--color-border-subtle: var(--palette-border-subtle, #1E1E22);
--color-primary: var(--palette-primary, #3B82F6);
--color-primary-dim: var(--palette-primary-dim, #1D4ED8);
--color-secondary: var(--palette-secondary, #A78BFA);
--color-green: var(--palette-green, #22C55E);
--color-danger: var(--palette-danger, #EF4444);
--color-warn: var(--palette-warn, #EAB308);
--color-text-bright: var(--palette-text-bright, #FAFAFA);
--color-text-normal: var(--palette-text-normal, #A1A1AA);
--color-text-muted: var(--palette-text-muted, #73737B);
--color-text-dim: var(--palette-text-dim, #5F5F65);
}
/* base resets */
@layer base {
html, body, #root {
@apply h-full;
}
body {
@apply bg-bg-base text-text-normal font-sans text-[13px] leading-relaxed m-0;
}
* {
scrollbar-width: thin;
scrollbar-color: var(--color-border) transparent;
}
/* one consistent keyboard-focus indicator for every interactive element. Inset so it isn't clipped
by scroll/overflow containers (table rows, panels) and matches the prior ring-inset look. */
:focus-visible {
outline: 2px solid var(--color-primary);
outline-offset: -1px;
}
}
/* animations and utilities */
@keyframes packet-pulse {
0% { border-color: var(--color-secondary); box-shadow: 0 0 12px color-mix(in srgb, var(--color-secondary) 15%, transparent); }
100% { border-color: var(--color-border); box-shadow: none; }
}
.packet-fresh {
animation: packet-pulse 1s ease-out forwards;
}
/* RF beacon: each ring rests at its natural opacity and, as the wave passes,
brightens and swells before easing back — staggered outward so the signal
radiates from the core. The resting state (0%/100%) matches the static logo,
so the loop starts and repeats seamlessly with no pop. */
@keyframes beacon-core-ping {
0%, 100% { transform: scale(1); opacity: 1; }
16% { transform: scale(1.25); opacity: 1; }
45% { transform: scale(0.95); opacity: 0.85; }
}
@keyframes beacon-ring-ping {
0%, 100% { opacity: var(--ring-base); transform: scale(1); }
30% { opacity: 1; transform: scale(1.06); }
60% { opacity: var(--ring-base); transform: scale(1); }
}
.beacon-core-pulse {
transform-box: fill-box;
transform-origin: center;
animation: beacon-core-ping 1.8s ease-in-out infinite both;
}
.beacon-ring {
transform-box: fill-box;
transform-origin: center;
animation: beacon-ring-ping 1.8s ease-in-out infinite both;
}
.beacon-ring-1 { --ring-base: 0.95; animation-delay: 0.08s; }
.beacon-ring-2 { --ring-base: 0.6; animation-delay: 0.30s; }
.beacon-ring-3 { --ring-base: 0.3; animation-delay: 0.52s; }
@media (prefers-reduced-motion: reduce) {
.beacon-core-pulse,
.beacon-ring { animation: none; }
}
.writing-vertical {
writing-mode: vertical-rl;
text-orientation: mixed;
}
@keyframes fade-in {
from { opacity: 0; }
to { opacity: 1; }
}
.fade-in {
animation: fade-in 150ms ease-out;
}
/* MapLibre controls ship light chrome; re-skin to the app's dark tokens when the active basemap
is dark (data-dark set on each map container — MapView and the packet-path mini-map). Glyphs are baked-in dark SVGs, so they
are inverted rather than recolored. Light basemaps (Liberty/Light) keep the default chrome. */
[data-dark="true"] .maplibregl-ctrl-group {
background: var(--color-bg-raised);
border: 1px solid var(--color-border);
box-shadow: none;
}
[data-dark="true"] .maplibregl-ctrl-group button + button {
border-top-color: var(--color-border);
}
[data-dark="true"] .maplibregl-ctrl-group button:hover {
background: color-mix(in srgb, var(--color-text-normal) 10%, transparent);
}
[data-dark="true"] .maplibregl-ctrl-icon {
filter: invert(1) brightness(1.6);
}
[data-dark="true"] .maplibregl-ctrl-scale {
background: color-mix(in srgb, var(--color-bg-raised) 78%, transparent);
border-color: var(--color-border);
color: var(--color-text-normal);
}
[data-dark="true"] .maplibregl-ctrl-attrib {
background: color-mix(in srgb, var(--color-bg-raised) 78%, transparent);
}
[data-dark="true"] .maplibregl-ctrl-attrib a {
color: var(--color-text-muted);
}
/* Path-node popup: dark chrome to match the controls, plus name/coords typography. */
[data-dark="true"] .maplibregl-popup-content {
background: var(--color-bg-raised);
color: var(--color-text-normal);
border: 1px solid var(--color-border);
box-shadow: none;
}
[data-dark="true"] .maplibregl-popup-anchor-top .maplibregl-popup-tip,
[data-dark="true"] .maplibregl-popup-anchor-top-left .maplibregl-popup-tip,
[data-dark="true"] .maplibregl-popup-anchor-top-right .maplibregl-popup-tip { border-bottom-color: var(--color-bg-raised); }
[data-dark="true"] .maplibregl-popup-anchor-bottom .maplibregl-popup-tip,
[data-dark="true"] .maplibregl-popup-anchor-bottom-left .maplibregl-popup-tip,
[data-dark="true"] .maplibregl-popup-anchor-bottom-right .maplibregl-popup-tip { border-top-color: var(--color-bg-raised); }
[data-dark="true"] .maplibregl-popup-anchor-left .maplibregl-popup-tip { border-right-color: var(--color-bg-raised); }
[data-dark="true"] .maplibregl-popup-anchor-right .maplibregl-popup-tip { border-left-color: var(--color-bg-raised); }
.pp-popup-name { font-weight: 600; }
.pp-popup-coords { font-family: ui-monospace, monospace; font-size: 11px; color: var(--color-text-muted); margin-top: 2px; }