Files
gods-eye-view/src/ui/styles/street-level.css
T

619 lines
13 KiB
CSS
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* ── Street Level panel ─────────────────────────────────────────
The rail owns position and width (layers.css). */
#street-level-panel {
--sl-green: #05cb63;
/* KartaView's purple for lines; a lighter one where it is text (WCAG AA). */
--sl-kartaview: #635bff;
--sl-kartaview-text: #8f8aff;
/* Panoramax's orange; the darker one sits behind white text. */
--sl-panoramax: #ff6f00;
--sl-panoramax-fill: #b84e00;
--sl-text: 0.6rem;
}
#street-level-panel .panel-glow {
position: absolute;
inset: -18px;
background: radial-gradient(
ellipse at center,
rgba(5, 203, 99, 0.16) 0%,
transparent 65%
);
filter: blur(16px);
opacity: 0.25;
pointer-events: none;
}
.street-level-panel-inner {
position: relative;
background: var(--glass-bg);
border: 1px solid var(--glass-border);
border-radius: var(--panel-radius);
padding: 14px;
display: flex;
flex-direction: column;
gap: 8px;
backdrop-filter: blur(24px) saturate(1.4);
-webkit-backdrop-filter: blur(24px) saturate(1.4);
box-shadow:
0 8px 32px rgba(0, 0, 0, 0.5),
0 0 0 1px rgba(255, 255, 255, 0.03) inset,
0 1px 0 rgba(255, 255, 255, 0.06) inset;
scrollbar-width: thin;
scrollbar-color: rgba(0, 212, 255, 0.46) rgba(255, 255, 255, 0.06);
}
/* Class-qualified, not id-qualified, so a theme's header rule still wins. */
.street-level-panel-inner > .panel-header {
gap: 8px;
}
.sl-status {
background: transparent;
font: inherit;
font-family: var(--font-mono);
font-size: var(--sl-text);
letter-spacing: 0.1em;
padding: 2px 7px;
border-radius: 999px;
border: 1px solid var(--glass-border-hover);
color: var(--text-secondary);
white-space: nowrap;
cursor: pointer;
transition:
border-color var(--transition-fast),
color var(--transition-fast);
}
.sl-status:hover,
.sl-status:focus-visible {
color: var(--text-primary);
border-color: var(--accent);
outline: none;
}
.sl-status.is-on {
color: var(--sl-green);
border-color: rgba(5, 203, 99, 0.55);
}
.sl-status.is-busy {
color: var(--accent);
border-color: rgba(0, 212, 255, 0.55);
}
.sl-status.is-warn {
color: #ffb300;
border-color: rgba(255, 179, 0, 0.55);
}
/* Collapsed strips hide the body entirely: nothing to paint or tab into. */
#street-level-panel.collapsed .sl-body,
#street-level-panel.collapsed .sl-status {
display: none;
}
.sl-body,
.sl-controls {
display: flex;
flex-direction: column;
gap: 8px;
}
.sl-body {
min-height: 0;
}
.sl-controls {
min-width: 0;
margin: 0;
padding: 0;
border: 0;
}
.sl-controls:disabled {
opacity: 0.45;
pointer-events: none;
}
/* ── Providers ───────────────────────────────────────────────────────────── */
.sl-providers {
display: flex;
align-items: center;
gap: 8px;
flex-wrap: wrap;
}
.sl-chips {
display: flex;
flex-wrap: wrap;
gap: 4px;
}
/* `--chip-color` comes from the provider. */
.sl-chips .data-toggle-chip {
display: inline-flex;
align-items: center;
gap: 5px;
}
.sl-chips .data-toggle-chip::before {
content: '';
width: 7px;
height: 7px;
border-radius: 50%;
background: var(--chip-color, currentColor);
opacity: 0.45;
flex: none;
}
.sl-chips .data-toggle-chip.active {
color: var(--chip-color, var(--accent));
border-color: var(--chip-color, var(--accent));
background: color-mix(
in srgb,
var(--chip-color, var(--accent)) 14%,
transparent
);
}
/* #635bff text on its own tint is 3.7:1 at this size; the lighter one is ~6:1. */
.sl-chips .data-toggle-chip.active[data-chip-id='kartaview'] {
color: var(--sl-kartaview-text);
}
.sl-chips .data-toggle-chip.active::before {
opacity: 1;
}
.sl-chips .data-toggle-chip.chip-error {
color: #ffb300;
border-color: rgba(255, 179, 0, 0.55);
}
/* The coverage hint and OPEN STREET VIEW share a line; the hint wraps. */
.sl-meta-row {
display: flex;
align-items: center;
gap: 8px;
}
.sl-meta-row .sl-meta {
flex: 1 1 auto;
min-width: 0;
}
/* Scoped to outrank .scene-btn's flex: 1, which squeezed the button to its
min-width beside a long coverage line and clipped its one-line label. */
.sl-meta-row .sl-nearest-btn {
flex: 0 0 auto;
}
.sl-nearest-btn[hidden] {
display: none;
}
/* When the hint and the button do not both fit, the button takes its own line. */
html:not([lang='en']) .sl-meta-row {
flex-wrap: wrap;
}
html:not([lang='en']) .sl-meta-row .sl-meta {
flex: 1 1 14em;
}
html:not([lang='en']) .sl-meta-row .sl-nearest-btn {
flex: 1 0 auto;
}
/* ── Errors ──────────────────────────────────────────────────────────────── */
.sl-error {
font-family: var(--font-sans);
font-size: 0.72rem;
line-height: 1.4;
color: #ff8a80;
}
/* ── Filters ──────────────────────────────────────────────────── */
.sl-filters {
display: flex;
align-items: center;
gap: 8px;
flex-wrap: wrap;
}
.sl-seg[hidden],
.sl-controls[hidden],
.sl-filters[hidden],
.sl-since[hidden] {
display: none;
}
.sl-since {
display: grid;
grid-template-columns: auto 1fr;
align-items: center;
gap: 4px 10px;
}
.sl-range {
width: 100%;
min-width: 0;
margin: 0;
accent-color: var(--sl-green);
cursor: pointer;
}
.sl-range:focus-visible {
outline: 1px solid var(--accent);
outline-offset: 3px;
}
/* The value and its note share a line: ANY DATE (by upload date). */
.sl-since-value {
grid-column: 2;
display: flex;
flex-wrap: wrap;
align-items: baseline;
gap: 0 6px;
min-width: 0;
}
.sl-since-note {
font-family: var(--font-mono);
font-size: 0.5rem;
letter-spacing: 0.08em;
color: var(--text-secondary);
}
.sl-since-note[hidden] {
display: none;
}
.sl-since-label {
font-family: var(--font-mono);
font-size: var(--sl-text);
letter-spacing: 0.08em;
color: var(--text-primary);
}
/* ── Embedded viewer ─────────────────────────────────────────────────────── */
.sl-viewer-wrap {
position: relative;
container-type: inline-size;
display: flex;
flex-direction: column;
flex: 0 0 auto;
border-radius: 12px;
overflow: hidden;
border: 1px solid var(--glass-border-hover);
background: #000;
}
.sl-viewer-wrap[hidden] {
display: none;
}
/* Nothing sits over the image, so the provider's own controls stay clear. */
.sl-viewer-stage {
position: relative;
display: flex;
flex-direction: column;
flex: 0 0 auto;
}
.sl-viewer {
width: 100%;
aspect-ratio: 16 / 10;
min-height: 180px;
}
.sl-viewer-placeholder {
position: absolute;
inset: 0;
display: grid;
place-items: center;
z-index: 3;
background: rgba(0, 0, 0, 0.35);
}
.sl-viewer-placeholder[hidden] {
display: none;
}
.sl-viewer-placeholder::after {
content: '';
width: 28px;
height: 28px;
border-radius: 50%;
border: 2px solid rgba(255, 255, 255, 0.2);
border-top-color: var(--sl-green);
animation: sl-spin 0.9s linear infinite;
}
@keyframes sl-spin {
to {
transform: rotate(360deg);
}
}
.sl-viewer-bar {
display: flex;
align-items: center;
justify-content: space-between;
gap: 6px;
padding: 5px 6px;
background: rgba(10, 10, 15, 0.85);
border-bottom: 1px solid var(--glass-border);
}
.sl-viewer-tools {
display: flex;
align-items: center;
gap: 4px;
min-width: 0;
flex-wrap: wrap;
}
.sl-viewer-tools .scene-btn {
padding: 4px 8px;
font-size: var(--sl-text);
background: rgba(10, 10, 15, 0.75);
flex: none;
min-width: 0;
display: inline-flex;
align-items: center;
gap: 4px;
}
.sl-viewer-tools .scene-btn[hidden] {
display: none;
}
.sl-viewer-tools .sl-seg {
background: rgba(10, 10, 15, 0.75);
}
@container (max-width: 380px) {
.sl-viewer-tools .sl-btn-text {
display: none;
}
}
.sl-viewer-x {
flex: none;
width: 26px;
height: 26px;
border-radius: 50%;
border: 1px solid rgba(255, 255, 255, 0.25);
background: rgba(10, 10, 15, 0.8);
color: var(--text-primary);
font-family: var(--font-mono);
font-size: 1.1rem;
line-height: 1;
cursor: pointer;
display: grid;
place-items: center;
transition: all var(--transition-fast);
}
.sl-viewer-x:hover {
color: #0a0a0f;
background: #fff;
border-color: #fff;
}
.sl-image-meta {
flex: 0 0 auto;
padding: 6px 10px;
font-family: var(--font-mono);
font-size: var(--sl-text);
letter-spacing: 0.06em;
color: var(--text-secondary);
background: rgba(0, 0, 0, 0.7);
display: flex;
flex-wrap: wrap;
justify-content: space-between;
align-items: center;
gap: 2px 10px;
min-height: 26px;
}
.sl-image-by {
color: var(--text-primary);
overflow-wrap: anywhere;
min-width: 0;
}
.sl-image-by:empty {
display: none;
}
.sl-image-right {
display: inline-flex;
align-items: center;
gap: 10px;
margin-left: auto;
white-space: nowrap;
}
.sl-image-link {
color: var(--sl-green);
text-decoration: none;
letter-spacing: 0.1em;
}
.sl-image-link[hidden] {
display: none;
}
.sl-image-link:hover {
text-decoration: underline;
}
.sl-meta {
font-family: var(--font-mono);
font-size: var(--sl-text);
letter-spacing: 0.06em;
color: var(--text-secondary);
}
.sl-meta:empty {
display: none;
}
/* ── Full screen (EXPAND) ────────────────────────────────────────────────── */
/* The browser lifts the viewer into the top layer; the photo takes the rest.
iPhone Safari has no element fullscreen, so there the viewer is a popover
sized to the viewport instead. */
.sl-viewer-wrap:fullscreen {
border: 0;
border-radius: 0;
}
.sl-viewer-wrap:popover-open {
position: fixed;
inset: 0;
width: 100vw;
height: 100dvh;
max-width: none;
max-height: none;
margin: 0;
padding: 0;
border: 0;
border-radius: 0;
}
.sl-viewer-wrap:is(:fullscreen, :popover-open) .sl-viewer-stage,
.sl-viewer-wrap:is(:fullscreen, :popover-open) .sl-viewer {
flex: 1 1 auto;
height: auto;
min-height: 0;
aspect-ratio: auto;
}
/* ── Photo viewer (KartaView, Panoramax) ─────────────────────────────────── */
.sl-photo-viewer {
/* The lit source's colour: a focus ring, and behind the white ‹ › glyphs. */
--sl-photo-ring: var(--sl-kartaview-text);
--sl-photo-fill: color-mix(in srgb, var(--sl-kartaview) 85%, transparent);
position: absolute;
inset: 0;
background: #000;
outline: none;
overflow: hidden;
}
.sl-photo-viewer:focus-visible {
outline: none;
}
/* The photo and canvas fill the viewer and would cover a ring drawn on it:
draw the ring on a layer above them (clicks pass through). */
.sl-photo-viewer:focus-visible::after {
content: '';
position: absolute;
inset: 0;
z-index: 3;
border: 2px solid var(--sl-photo-ring);
pointer-events: none;
}
/* White on #ff6f00 is 2.8:1; on the darker orange behind ‹ › it is 5.1:1. */
.sl-photo-viewer[data-provider='panoramax'] {
--sl-photo-ring: var(--sl-panoramax);
--sl-photo-fill: var(--sl-panoramax-fill);
}
.sl-photo-flat,
.sl-photo-pano {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
user-select: none;
}
.sl-photo-flat {
object-fit: contain;
}
.sl-photo-pano {
cursor: grab;
touch-action: none;
}
.sl-photo-pano.sl-photo-dragging {
cursor: grabbing;
}
.sl-photo-flat[hidden],
.sl-photo-pano[hidden] {
display: none;
}
.sl-photo-step {
position: absolute;
top: 50%;
z-index: 2;
width: 34px;
height: 44px;
margin-top: -22px;
border: 1px solid rgba(255, 255, 255, 0.18);
border-radius: 8px;
background: rgba(10, 10, 15, 0.62);
color: #fff;
font-size: 1.5rem;
line-height: 1;
cursor: pointer;
}
.sl-photo-step-prev {
left: 6px;
}
.sl-photo-step-next {
right: 6px;
}
.sl-photo-step:hover:not(:disabled),
.sl-photo-step:focus-visible {
background: var(--sl-photo-fill);
outline: none;
}
.sl-photo-step:disabled {
opacity: 0.3;
cursor: default;
}
/* Nothing to step through until a photo shows. */
.sl-photo-viewer:not([data-kind='flat']):not([data-kind='pano'])
.sl-photo-step {
display: none;
}
/* ── Short viewports ─────────────────────────────────────────────────────── */
@media (max-height: 640px) {
.street-level-panel-inner {
padding: 10px;
gap: 6px;
}
.sl-viewer {
min-height: 150px;
}
}
/* ── Phones ──────────────────────────────────────────────────────────────── */
/* The phone rail spans 50vh + 8px to 2vh + 7.5rem from the bottom
(responsive.css). Size the photo to that band, less ~150px of panel chrome,
so it shows without scrolling. */
@media (max-width: 720px) {
.sl-viewer {
aspect-ratio: auto;
height: clamp(110px, calc(48vh - 8px - 7.5rem - 150px), 320px);
min-height: 0;
}
}