Files
python-tdd/src/static_src/scss/_sky.scss
2026-05-08 15:41:24 -04:00

1122 lines
36 KiB
SCSS
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.

// ─── Sky (Pick Sky) overlay ────────────────────────────────────────────────
// Gaussian backdrop + centred modal, matching the gate/sig overlay pattern.
// Open state: html.sky-open (added by JS on PICK SKY click).
//
// Layout: header / two-column body (form | wheel) / footer
// Collapses to stacked single-column below 600 px.
// ── Scroll-lock ───────────────────────────────────────────────────────────────
html.sky-open {
overflow: hidden;
#id_aperture_fill { opacity: 1; }
}
// ── Backdrop ──────────────────────────────────────────────────────────────────
.sky-backdrop {
position: fixed;
inset: 0;
background: rgba(0, 0, 0, 0.75);
backdrop-filter: blur(5px);
z-index: 100;
pointer-events: none;
// Hidden until html.sky-open
opacity: 0;
transition: opacity 0.15s ease;
}
html.sky-open .sky-backdrop {
opacity: 1;
}
// ── Overlay shell (positions + scrolls the modal) ─────────────────────────────
.sky-overlay {
position: fixed;
inset: 0;
display: flex;
align-items: center;
justify-content: center;
z-index: 120;
overflow-y: auto;
overscroll-behavior: contain;
pointer-events: none;
// Hidden until html.sky-open
visibility: hidden;
@media (orientation: landscape) {
$sidebar-w: 4rem;
left: $sidebar-w;
right: $sidebar-w;
}
}
html.sky-open .sky-overlay {
visibility: visible;
pointer-events: none; // modal itself is pointer-events: auto
}
// ── Modal panel ───────────────────────────────────────────────────────────────
// Thin wrapper: position:relative so the NVM circle can sit on the corner
// without being clipped by the modal's overflow:hidden.
.sky-modal-wrap {
position: relative;
pointer-events: none; // overlay handles pointer-events; children re-enable
width: 92vw;
max-width: 920px;
// Fade + slide in — wraps modal AND NVM btn so both animate together
opacity: 0;
transform: translateY(1rem);
transition: opacity 0.2s ease, transform 0.2s ease;
}
html.sky-open .sky-modal-wrap {
opacity: 1;
transform: translateY(0);
}
.sky-modal {
pointer-events: auto;
display: flex;
flex-direction: column;
width: 100%; // fills .sky-modal-wrap
max-height: 96vh;
border: 0.1rem solid rgba(var(--terUser), 0.25);
border-radius: 0.5rem;
overflow: hidden;
}
// ── Header ────────────────────────────────────────────────────────────────────
.sky-modal-header {
flex-shrink: 0;
padding: 0.6rem 1rem;
background: rgba(var(--priUser), 1);
border-bottom: 0.1rem solid rgba(var(--terUser), 0.15);
display: flex;
flex-direction: row;
align-items: baseline;
gap: 0.75rem;
h2 {
margin: 0;
font-size: 1.1rem;
letter-spacing: 0.06em;
span { color: rgba(var(--secUser), 1); }
}
p {
margin: 0;
font-size: 0.7rem;
opacity: 0.55;
}
}
// ── Body: two columns ─────────────────────────────────────────────────────────
.sky-modal-body {
flex: 1;
min-height: 0;
display: flex;
flex-direction: row;
overflow: hidden;
}
// Form column — fixed width; form-main scrolls, confirm btn pinned at bottom
.sky-form-col {
flex: 0 0 240px;
overflow: hidden;
padding: 0.9rem 1rem;
background: rgba(var(--priUser), 1);
border-right: 0.1rem solid rgba(var(--terUser), 0.12);
display: flex;
flex-direction: column;
gap: 0.65rem;
}
// Scrollable inner container (form fields + status)
.sky-form-main {
flex: 1;
min-height: 0;
overflow-y: auto;
display: flex;
flex-direction: column;
gap: 0.65rem;
}
// Confirm btn inside form-col — full width, pinned at column bottom
.sky-form-col > #id_sky_confirm {
flex-shrink: 0;
}
// Wheel column — fills remaining space
.sky-wheel-col {
flex: 1;
min-width: 0;
display: flex;
align-items: center;
justify-content: center;
padding: 0.75rem;
// background: rgba(var(--duoUser), 1);
position: relative;
}
.sky-svg {
display: block;
width: 100%;
height: 100%;
aspect-ratio: 1 / 1;
max-width: 480px;
max-height: 480px;
}
// ── Form fields ───────────────────────────────────────────────────────────────
.sky-field {
display: flex;
flex-direction: column;
gap: 0;
& + & {
margin-top: 0.4rem;
}
label {
font-size: 0.6rem;
text-transform: uppercase;
letter-spacing: 0.1em;
color: rgba(var(--quaUser), 0.8);
}
// Match the .form-control look used by the login email input —
// priUser fill, secUser gold border + text, pill rounding, terUser focus glow.
input {
width: 100%;
// min-width:0 lets the input shrink below its native content-width on
// iOS Firefox, which gives <input type="date|time"> widgets a fixed
// minimum that would otherwise spill past .sky-form-main on narrow
// phones & trigger horizontal page scroll. max-width:100% is belt &
// suspenders for iOS WebKit, which treats date/time as a native
// widget that ignores min-width:0 alone.
min-width: 0;
max-width: 100%;
background-color: rgba(var(--priUser), 1);
color: rgba(var(--secUser), 1);
font-weight: 700;
border: 0.1rem solid rgba(var(--secUser), 0.5);
--_pad-v: 0.5rem;
padding: var(--_pad-v) 0.75rem;
border-radius: calc((var(--_pad-v) * 2 + 1em) / 3);
font-family: inherit;
// iOS Firefox renders <input type="date|time"> as a native widget
// whose intrinsic width exceeds .sky-form-main on narrow phones.
// appearance:none drops the native chrome so width/padding/border
// are honored uniformly; the date/time picker still opens on tap.
&[type="date"],
&[type="time"] {
-webkit-appearance: none;
appearance: none;
}
&:focus {
outline: none;
border-color: rgba(var(--terUser), 0.75);
box-shadow: 0 0 0.75rem rgba(var(--terUser), 0.5);
color: rgba(var(--terUser), 1);
}
&[readonly] {
// Match the birth-place placeholder's effective opacity. The
// browser's default ::placeholder pseudo-element is ~0.54; the
// lat/lon/tz fields used to sit at the input-element-level
// opacity:0.6, which compounded with that to ~0.32 — making
// placeholders almost invisible. Bumping to 0.85 keeps the
// readonly fields visually de-emphasized vs. the editable ones
// while leaving the placeholder copy clearly readable
// (0.85 × 0.54 ≈ 0.46, parity w. birth-place's ~0.54).
opacity: 0.85;
&:focus {
border-color: rgba(var(--secUser), 0.75);
box-shadow: 0 0 0.75rem rgba(var(--secUser), 0.5);
color: inherit;
}
cursor: default;
}
}
small {
font-size: 0.58rem;
opacity: 0.45;
line-height: 1.3;
margin-top: 0.2rem;
}
}
// Place search field wrapper: text input + geo button inline
.sky-place-field { position: relative; }
.sky-place-wrap {
display: flex;
gap: 0.4rem;
align-items: center;
input { flex: 1; min-width: 0; }
.btn-sm { flex-shrink: 0; margin-top: 0; margin-bottom: 0; }
}
// Nominatim suggestion dropdown
.sky-suggestions {
position: absolute;
left: 0;
right: 0;
top: calc(100% + 2px);
z-index: 10;
background: rgba(var(--priUser), 1);
border: 0.1rem solid rgba(var(--terUser), 0.3);
border-radius: 0.3rem;
overflow-y: auto;
max-height: 10rem;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.4);
}
.sky-suggestion-item {
display: block;
width: 100%;
padding: 0.4rem 0.6rem;
text-align: left;
background: none;
border: none;
border-bottom: 0.05rem solid rgba(var(--terUser), 0.1);
font-size: 0.65rem;
color: rgba(var(--ninUser), 0.85);
cursor: pointer;
line-height: 1.35;
&:last-child { border-bottom: none; }
&:hover, &:focus {
background: rgba(var(--terUser), 0.12);
color: rgba(var(--ninUser), 1);
outline: none;
}
}
// Coords row: lat | lon (read-only, populated by place selection)
.sky-coords {
flex-direction: row;
align-items: flex-end;
gap: 0.4rem;
> div {
flex: 1;
min-width: 0;
display: flex;
flex-direction: column;
gap: 0;
label {
font-size: 0.6rem;
text-transform: uppercase;
letter-spacing: 0.1em;
color: rgba(var(--quaUser), 0.8);
}
input {
width: 100%;
// opacity is inherited from the .sky-field input[readonly] rule
// above (0.85) — keep this block lean so the readonly-styling
// single source of truth doesn't drift.
}
}
}
// ── Status line ───────────────────────────────────────────────────────────────
.sky-status {
font-size: 0.65rem;
opacity: 0.6;
min-height: 1rem;
text-align: center;
&--error {
opacity: 1;
color: rgba(var(--priRd), 1);
}
}
// ── NVM corner btn ────────────────────────────────────────────────────────────
// Absolutely pinned to top-right corner of .sky-modal-wrap.
// transform: translate(50%,-50%) centres the circle on the corner point.
// Lives outside .sky-modal so overflow:hidden doesn't clip it.
#id_sky_cancel {
position: absolute;
top: 0;
right: 0;
transform: translate(50%, -50%);
z-index: 10;
margin: 0;
pointer-events: auto;
}
// ── Narrow / portrait ─────────────────────────────────────────────────────────
@media (max-width: 600px) {
.sky-modal-wrap {
width: 92vw;
}
.sky-modal {
max-height: 96vh;
}
.sky-modal-body {
flex-direction: column;
overflow-y: auto;
}
// Form col stacks above wheel; internally becomes a flex-row so
// form-main gets most of the width and confirm btn sits to its right.
.sky-form-col {
flex: 0 0 auto;
flex-direction: row;
align-items: flex-end;
border-right: none;
border-bottom: 0.1rem solid rgba(var(--terUser), 0.12);
overflow: visible; // form-main handles its own scroll
gap: 0.5rem;
}
.sky-form-main {
flex: 1;
min-width: 0;
overflow-y: auto;
max-height: 40vh;
}
.sky-form-col > #id_sky_confirm {
flex-shrink: 0;
align-self: flex-end;
}
.sky-wheel-col {
flex: 0 0 280px;
}
}
// ── SVG wheel element styles ──────────────────────────────────────────────────
// Colors and opacity live here; geometry (cx/cy/r/font-size) stays in JS.
.nw-outer-ring {
fill: none;
stroke: rgba(var(--terUser), 1);
stroke-width: 1.5px;
}
.nw-inner-disc {
fill: rgba(var(--quaUser), 0.6);
stroke: rgba(var(--terUser), 1);
stroke-width: 0.75px;
}
// Axes (ASC / DSC / MC / IC)
.nw-axis-line { stroke: rgba(var(--secUser), 1); stroke-width: 1.5px; }
.nw-axis-label { fill: rgba(var(--secUser), 1); }
// Sign ring — uniform --priYl bg at half opacity
.nw-sign--fire,
.nw-sign--stone,
.nw-sign--air,
.nw-sign--water {
fill: rgba(var(--priYl), 0.25);
stroke: rgba(var(--terUser), 1);
stroke-width: 0.75px;
}
// Icon bg circles — element fill + matching border
.nw-sign-icon-bg--fire { fill: rgba(var(--quaRd), 0.92); stroke: rgba(var(--priOr), 1); stroke-width: 1px; }
.nw-sign-icon-bg--stone { fill: rgba(var(--quaFs), 0.92); stroke: rgba(var(--priMe), 1); stroke-width: 1px; }
.nw-sign-icon-bg--air { fill: rgba(var(--quiCy), 0.92); stroke: rgba(var(--priBl), 1); stroke-width: 1px; }
.nw-sign-icon-bg--water { fill: rgba(var(--sixId), 0.92); stroke: rgba(var(--priVt), 1); stroke-width: 1px; }
// Inline SVG path icons — per-element colors
.nw-sign-icon--fire { fill: rgba(var(--priOr), 1); }
.nw-sign-icon--stone { fill: rgba(var(--priMe), 1); }
.nw-sign-icon--air { fill: rgba(var(--priBl), 1); }
.nw-sign-icon--water { fill: rgba(var(--priVt), 1); }
// House ring — uniform --priGn bg
.nw-house-cusp { stroke: rgba(var(--terUser), 1); stroke-width: 1.2px; }
.nw-house-num { fill: rgba(var(--ninUser), 1); }
.nw-house-fill--even { fill: rgba(var(--secGn), 0.25); stroke: rgba(var(--terUser), 1); stroke-width: 0.75px; }
.nw-house-fill--odd { fill: rgba(var(--quiGn), 0.25); stroke: rgba(var(--terUser), 1); stroke-width: 0.75px; }
// Planets — base geometry
.nw-planet-circle,
.nw-planet-circle--rx { stroke-width: 1px; }
.nw-planet-label { stroke-width: 0.4px; paint-order: stroke fill; }
// Per-planet circle: fill = ternary, border = senary
.nw-planet--au { fill: rgba(var(--terAu), 1); stroke: rgba(var(--sixAu), 1); } // Sun
.nw-planet--ag { fill: rgba(var(--terAg), 1); stroke: rgba(var(--sixAg), 1); } // Moon
.nw-planet--hg { fill: rgba(var(--terHg), 1); stroke: rgba(var(--sixHg), 1); } // Mercury
.nw-planet--cu { fill: rgba(var(--terCu), 1); stroke: rgba(var(--sixCu), 1); } // Venus
.nw-planet--fe { fill: rgba(var(--terFe), 1); stroke: rgba(var(--sixFe), 1); } // Mars
.nw-planet--sn { fill: rgba(var(--terSn), 1); stroke: rgba(var(--sixSn), 1); } // Jupiter
.nw-planet--pb { fill: rgba(var(--terPb), 1); stroke: rgba(var(--sixPb), 1); } // Saturn
.nw-planet--u { fill: rgba(var(--terU), 1); stroke: rgba(var(--sixU), 1); } // Uranus
.nw-planet--np { fill: rgba(var(--terNp), 1); stroke: rgba(var(--sixNp), 1); } // Neptune
.nw-planet--pu { fill: rgba(var(--terPu), 1); stroke: rgba(var(--sixPu), 1); } // Pluto
// Per-planet label: fill + stroke halo = senary
.nw-planet-label--au { fill: rgba(var(--sixAu), 1); stroke: rgba(var(--sixAu), 0.6); }
.nw-planet-label--ag { fill: rgba(var(--sixAg), 1); stroke: rgba(var(--sixAg), 0.6); }
.nw-planet-label--hg { fill: rgba(var(--sixHg), 1); stroke: rgba(var(--sixHg), 0.6); }
.nw-planet-label--cu { fill: rgba(var(--sixCu), 1); stroke: rgba(var(--sixCu), 0.6); }
.nw-planet-label--fe { fill: rgba(var(--sixFe), 1); stroke: rgba(var(--sixFe), 0.6); }
.nw-planet-label--sn { fill: rgba(var(--sixSn), 1); stroke: rgba(var(--sixSn), 0.6); }
.nw-planet-label--pb { fill: rgba(var(--sixPb), 1); stroke: rgba(var(--sixPb), 0.6); }
.nw-planet-label--u { fill: rgba(var(--sixU), 1); stroke: rgba(var(--sixU), 0.6); }
.nw-planet-label--np { fill: rgba(var(--sixNp), 1); stroke: rgba(var(--sixNp), 0.6); }
.nw-planet-label--pu { fill: rgba(var(--sixPu), 1); stroke: rgba(var(--sixPu), 0.6); }
.nw-rx { fill: rgba(var(--terUser), 1); }
// Hover and active-lock glow — planet, element, sign, house groups
.nw-planet-group,
.nw-element-group,
.nw-sign-group,
.nw-house-group { cursor: pointer; }
.nw-planet-group:hover,
.nw-planet-group.nw-planet--active,
.nw-planet-group.nw-planet--asp-active,
.nw-element-group:hover,
.nw-element-group.nw-element--active,
.nw-sign-group:hover,
.nw-sign-group.nw-sign--active,
.nw-house-group:hover,
.nw-house-group.nw-house--active {
filter: drop-shadow(0 0 5px rgba(var(--ninUser), 0.9));
}
// Zodiac icon circles — muted by default, full opacity on hover/active
.nw-sign-icon-bg { opacity: 0.5; }
.nw-sign-group:hover .nw-sign-icon-bg,
.nw-sign-group.nw-sign--active .nw-sign-icon-bg { opacity: 1; }
// House numbers — muted by default, full opacity on hover/active
.nw-house-num { opacity: 0.75; }
.nw-house-group:hover .nw-house-num,
.nw-house-group.nw-house--active .nw-house-num { opacity: 1; }
// ── Planet tick lines — hidden until parent group is active ──────────────────
.nw-planet-tick {
fill: none;
stroke-width: 1px;
stroke-opacity: 0;
stroke-linecap: round;
transition: stroke-opacity 0.15s ease;
}
.nw-planet-group.nw-planet--active .nw-planet-tick,
.nw-planet-group.nw-planet--asp-active .nw-planet-tick {
stroke: rgba(var(--terUser), 1);
stroke-opacity: 0.7;
filter: drop-shadow(0 0 3px rgba(var(--terUser), 0.8))
drop-shadow(0 0 6px rgba(var(--terUser), 0.4));
}
.nw-planet-tick--au { stroke: rgba(var(--priAu), 1); }
.nw-planet-tick--ag { stroke: rgba(var(--priAg), 1); }
.nw-planet-tick--hg { stroke: rgba(var(--priHg), 1); }
.nw-planet-tick--cu { stroke: rgba(var(--priCu), 1); }
.nw-planet-tick--fe { stroke: rgba(var(--priFe), 1); }
.nw-planet-tick--sn { stroke: rgba(var(--priSn), 1); }
.nw-planet-tick--pb { stroke: rgba(var(--priPb), 1); }
.nw-planet-tick--u { stroke: rgba(var(--priU), 1); }
.nw-planet-tick--np { stroke: rgba(var(--priNp), 1); }
.nw-planet-tick--pu { stroke: rgba(var(--priPu), 1); }
// Aspects — per-planet color tokens (light shades on dark palettes; mid on light)
:root {
--asp-Au: var(--sixAu); --asp-Ag: var(--sixAg);
--asp-Hg: var(--sixHg); --asp-Cu: var(--sixCu);
--asp-Fe: var(--sixFe); --asp-Sn: var(--sixSn);
--asp-Pb: var(--sixPb); --asp-U: var(--sixU);
--asp-Np: var(--sixNp); --asp-Pu: var(--sixPu);
}
body[class*="-light"] {
--asp-Au: var(--terAu); --asp-Ag: var(--terAg);
--asp-Hg: var(--terHg); --asp-Cu: var(--terCu);
--asp-Fe: var(--terFe); --asp-Sn: var(--terSn);
--asp-Pb: var(--terPb); --asp-U: var(--terU);
--asp-Np: var(--terNp); --asp-Pu: var(--terPu);
}
.nw-aspects { opacity: 0.8; }
// Element pie — deasil order: Fire → Stone → Time → Space → Air → Water
.nw-element--fire { fill: rgba(var(--priRd, 192, 64, 64), 0.92); stroke: rgba(var(--quaUser), 1); stroke-width: 0.5px; }
.nw-element--stone { fill: rgba(var(--priFs, 122, 96, 64), 0.92); stroke: rgba(var(--quaUser), 1); stroke-width: 0.5px; }
.nw-element--time { fill: rgba(var(--priYl, 192, 160, 48), 0.92); stroke: rgba(var(--quaUser), 1); stroke-width: 0.5px; }
.nw-element--space { fill: rgba(var(--priGn, 64, 96, 64), 0.92); stroke: rgba(var(--quaUser), 1); stroke-width: 0.5px; }
.nw-element--air { fill: rgba(var(--priCy, 64, 144, 176), 0.92); stroke: rgba(var(--quaUser), 1); stroke-width: 0.5px; }
.nw-element--water { fill: rgba(var(--priId, 80, 80, 160), 0.92); stroke: rgba(var(--quaUser), 1); stroke-width: 0.5px; }
// ── Planet hover tooltip — must live outside any ancestor with transform or
// container-type (both break position:fixed). Placed as a direct sibling of
// .sky-overlay in room.html; alongside #id_tooltip_portal in home.html. ──
#id_sky_tooltip,
#id_sky_tooltip_2 {
position: fixed;
z-index: 200;
pointer-events: auto;
padding: 0.75rem 0.75rem 0.75rem 1.5rem;
min-width: 14rem;
.tt-title { font-size: 1.25rem; font-weight: 700; margin-bottom: 0; }
.tt-description { font-size: 0.75rem; }
.tt-sign-icon { fill: currentColor; vertical-align: middle; margin-bottom: 0.1em; }
// Planet tooltip — flex row: name | symbol; location row: @deg° Sign | sign icon
.tt-planet-header {
display: flex;
align-items: baseline;
justify-content: space-between;
gap: 0.5rem;
margin-bottom: 0.2rem;
}
.tt-planet-sym {
font-size: 1.8rem;
opacity: 0.85;
}
.tt-angle-sym {
font-variant-caps: all-small-caps;
font-size: 1.1rem;
opacity: 0.85;
}
.tt-angle-house .tt-ord {
margin-left: 0;
}
.tt-planet-loc {
display: flex;
align-items: center;
justify-content: space-between;
gap: 0.5rem;
font-size: 0.8rem;
margin-bottom: 0.3rem;
}
.tt-planet-sign-icon { font-size: 1.2rem; line-height: 1; }
// Sign tooltip — name in element color | SVG icon; modality | vector; planets
.tt-sign-header {
display: flex;
align-items: center;
justify-content: space-between;
gap: 0.5rem;
margin-bottom: 0.2rem;
}
.tt-sign-icon-wrap {
font-size: 1.5rem;
line-height: 1;
flex-shrink: 0;
.tt-sign-icon { fill: currentColor; }
}
.tt-sign-meta {
display: flex;
align-items: center;
justify-content: space-between;
font-size: 0.75rem;
opacity: 0.85;
margin-bottom: 0.3rem;
}
.tt-sign-planets {
display: flex;
flex-direction: column;
gap: 0.15rem;
margin-top: 0.1rem;
font-size: 0.85rem;
}
.tt-sign-section-header {
font-size: 0.65rem;
font-weight: 600;
opacity: 0.55;
letter-spacing: 0.04em;
margin-bottom: 0.15rem;
}
.tt-sign-cusps {
display: flex;
flex-direction: column;
gap: 0.15rem;
font-size: 0.85rem;
}
// House tooltip — "House of X" | number; planets in house
.tt-house-header {
display: flex;
align-items: flex-start;
justify-content: space-between;
gap: 0.5rem;
margin-bottom: 0.3rem;
}
.tt-house-of {
font-size: 0.7rem;
font-weight: 700;
margin-right: 0.15em;
opacity: 0.9;
}
.tt-house-num {
font-size: 1.4rem;
font-weight: 700;
opacity: 1;
flex-shrink: 0;
}
.tt-element-type,
.tt-house-type,
.tt-sign-type {
display: block;
font-size: 0.7rem;
font-weight: 400;
opacity: 0.7;
margin-top: 0.1em;
font-style: italic;
}
.tt-house-planets {
display: flex;
flex-direction: column;
gap: 0.15rem;
font-size: 0.85rem;
}
.tt-house-planet-row {
display: flex;
align-items: center;
gap: 0.3rem;
}
// DON|DOFF aspect line toggle — stacked at top-left outside the tooltip box,
// matching the PRV/NXT pattern at the bottom corners.
.nw-asp-don,
.nw-asp-doff {
position: absolute;
left: -1rem;
margin: 0;
pointer-events: auto; // override btn-disabled; click must land here, not pass through to SVG
}
.nw-asp-don { top: -1rem; }
.nw-asp-doff { top: 1.2rem; }
.nw-tt-prv,
.nw-tt-nxt {
position: absolute;
bottom: -1rem;
margin: 0;
}
.nw-tt-prv { left: -1rem; }
.nw-tt-nxt { right: -1rem; }
// Aspect list — always visible below planet description
.tt-aspects {
display: block;
margin-top: 0.6rem;
font-size: 0.94rem;
font-weight: 600;
opacity: 0.85;
line-height: 1.3;
}
.tt-asp-row {
display: flex;
align-items: center;
gap: 0.3rem;
white-space: nowrap;
}
.tt-asp-line { flex-shrink: 0; vertical-align: middle; }
.tt-asp-orb {
margin-left: auto;
opacity: 0.6;
font-size: 0.65rem;
padding-left: 0.5rem;
white-space: nowrap;
}
.tt-asp-in {
opacity: 0.6;
font-size: 0.65rem;
padding-left: 0.25rem;
}
.tt-dim {
opacity: 0.6;
font-size: 0.65rem;
}
.tt-ord {
font-size: 0.6rem;
vertical-align: 0.25rem;
line-height: 0;
opacity: 1;
margin-left: -0.25rem;
letter-spacing: 0;
}
// Element tooltip — title + square badge
.tt-el-header {
margin-bottom: 0.3rem;
}
.tt-el-badge-col {
float: right;
display: flex;
flex-direction: column;
align-items: center;
gap: 0.2rem;
margin-left: 0.5rem;
}
.tt-el-square {
display: block;
}
.tt-el-score {
font-size: 0.7rem;
text-align: center;
}
.tt-el-vec {
display: inline;
vertical-align: middle;
margin: 0 0.1em;
}
.tt-el-body-line {
font-size: 0.75rem;
opacity: 0.9;
margin-bottom: 0.25rem;
}
.tt-el-contribs {
display: flex;
flex-direction: column;
gap: 0.2rem;
margin-top: 0.3rem;
}
.tt-el-planet-row {
opacity: 0.75;
margin-left: 0.5rem;
margin-top: -0.1rem;
}
.tt-el-formation-header {
font-size: 0.85rem;
font-weight: 700;
margin-top: 0.35rem;
.tt-el-formation-label {
font-size: 0.65rem;
font-weight: 600;
opacity: 0.55;
letter-spacing: 0.04em;
}
}
.tt-el-formation {
font-size: 0.75rem;
opacity: 0.7;
margin-top: 0.2rem;
font-style: italic;
}
// Planet title colors — senary (brightest) tier on dark palettes
.tt-title--au { color: rgba(var(--sixAu), 1); } // Sun
.tt-title--ag { color: rgba(var(--sixAg), 1); } // Moon
.tt-title--hg { color: rgba(var(--sixHg), 1); } // Mercury
.tt-title--cu { color: rgba(var(--sixCu), 1); } // Venus
.tt-title--fe { color: rgba(var(--sixFe), 1); } // Mars
.tt-title--sn { color: rgba(var(--sixSn), 1); } // Jupiter
.tt-title--pb { color: rgba(var(--sixPb), 1); } // Saturn
.tt-title--u { color: rgba(var(--sixU), 1); } // Uranus
.tt-title--np { color: rgba(var(--sixNp), 1); } // Neptune
.tt-title--pu { color: rgba(var(--sixPu), 1); } // Pluto
}
// Element title colors — primary tier on dark palettes
#id_sky_tooltip,
#id_sky_tooltip_2 {
.tt-title--el-fire { color: rgba(var(--priRd), 1); }
.tt-title--el-stone { color: rgba(var(--priFs), 1); }
.tt-title--el-time { color: rgba(var(--priYl), 1); }
.tt-title--el-space { color: rgba(var(--priGn), 1); }
.tt-title--el-air { color: rgba(var(--priCy), 1); }
.tt-title--el-water { color: rgba(var(--priId), 1); }
}
// Sign tooltip title + sign icon SVG — element border colors (Stone/Air/Fire/Water schema)
#id_sky_tooltip,
#id_sky_tooltip_2 {
.tt-title--sign-fire { color: rgba(var(--priOr), 1); }
.tt-title--sign-stone { color: rgba(var(--priMe), 1); }
.tt-title--sign-air { color: rgba(var(--priBl), 1); }
.tt-title--sign-water { color: rgba(var(--priVt), 1); }
.tt-sign-icon-wrap--fire .tt-sign-icon,
.tt-planet-sign-icon--fire .tt-sign-icon { fill: rgba(var(--priOr), 1); }
.tt-sign-icon-wrap--stone .tt-sign-icon,
.tt-planet-sign-icon--stone .tt-sign-icon { fill: rgba(var(--priMe), 1); }
.tt-sign-icon-wrap--air .tt-sign-icon,
.tt-planet-sign-icon--air .tt-sign-icon { fill: rgba(var(--priBl), 1); }
.tt-sign-icon-wrap--water .tt-sign-icon,
.tt-planet-sign-icon--water .tt-sign-icon { fill: rgba(var(--priVt), 1); }
}
// On light palettes — switch to tertiary tier for legibility
body[class*="-light"] #id_sky_tooltip,
body[class*="-light"] #id_sky_tooltip_2 {
.tt-title--el-fire { color: rgba(var(--terRd), 1); }
.tt-title--el-stone { color: rgba(var(--terFs), 1); }
.tt-title--el-time { color: rgba(var(--terYl), 1); }
.tt-title--el-space { color: rgba(var(--terGn), 1); }
.tt-title--el-air { color: rgba(var(--terCy), 1); }
.tt-title--el-water { color: rgba(var(--terId), 1); }
}
// On light palettes — switch to primary (darkest) tier for legibility
body[class*="-light"] #id_sky_tooltip,
body[class*="-light"] #id_sky_tooltip_2 {
.tt-title--au { color: rgba(var(--priAu), 1); }
.tt-title--ag { color: rgba(var(--priAg), 1); }
.tt-title--hg { color: rgba(var(--priHg), 1); }
.tt-title--cu { color: rgba(var(--priCu), 1); }
.tt-title--fe { color: rgba(var(--priFe), 1); }
.tt-title--sn { color: rgba(var(--priSn), 1); }
.tt-title--pb { color: rgba(var(--priPb), 1); }
.tt-title--u { color: rgba(var(--priU), 1); }
.tt-title--np { color: rgba(var(--priNp), 1); }
.tt-title--pu { color: rgba(var(--priPu), 1); }
}
// ── My Sky dashboard applet ───────────────────────────────────────────────────
#id_applet_my_sky {
display: flex;
flex-direction: column;
// Anchor for #id_applet_sky_delete_btn's absolute centering.
position: relative;
h2 { flex-shrink: 0; }
.sky-svg {
flex: 1;
min-height: 0;
max-width: none;
max-height: none;
align-self: center;
}
#id_applet_sky_form_wrap {
flex: 1;
min-height: 0;
overflow-y: auto;
padding: 0.5rem 0.25rem;
display: flex;
flex-direction: column;
gap: 0.5rem;
#id_sky_confirm {
margin-top: -1.5rem;
align-self: center;
position: relative;
z-index: 1;
}
}
}
// ── Sky full page (aperture + column layout) ──────────────────────────────────
html:has(body.page-sky) {
overflow: hidden;
}
body.page-sky {
overflow: hidden;
.container {
overflow: hidden;
display: flex;
flex-direction: column;
flex: 1;
min-height: 0;
}
.row {
flex-shrink: 0;
}
}
// Sky page fills the aperture; its content can scroll past the bottom edge.
// overflow-x: hidden clips any horizontal overflow that would otherwise create
// page-level horizontal scroll on iOS Firefox — html/body overflow:hidden on
// page-sky doesn't always catch native <input type="date|time"> widgets whose
// minimum content width exceeds the form column on narrow phones.
.sky-page {
position: relative;
flex: 1;
min-height: 0;
display: flex;
flex-direction: column;
overflow-y: auto;
overflow-x: hidden;
}
// DEL btn pinned at the wheel center — appears wherever a wheel is shown
// (Dashsky form#id_sky_delete_form, PICK SKY overlay #id_sky_delete_btn,
// My Sky applet #id_applet_sky_delete_btn). Anchored to .sky-wheel-col /
// the applet section (both position:relative) so the btn sits over the SVG's
// geometric center regardless of the surrounding layout.
#id_sky_delete_form,
#id_sky_delete_btn,
#id_applet_sky_delete_btn {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
z-index: 5;
margin: 0;
}
// The applet's padding is asymmetric — 2.5rem left (rotated h2 gutter) and
// 0.75rem right — so the SVG's geometric center sits 0.875rem right of the
// applet's padding-box center. Shift the DEL btn by half the asymmetry so it
// re-aligns with the SVG's actual center instead of the applet's box center.
#id_applet_sky_delete_btn {
left: calc(50% + 0.875rem);
}
// Stack wheel above form; allow body to grow past viewport (page scrolls, not body)
.sky-page .sky-modal-body {
flex-direction: column;
flex-shrink: 0;
}
// Wheel takes its natural square size from its width — never shrinks for the form
.sky-page .sky-wheel-col {
order: -1;
flex: 0 0 auto;
width: 100%;
aspect-ratio: 1 / 1;
max-width: 480px;
max-height: 480px;
align-self: center;
}
// Form col is a vertical stack — fields on top, SAVE SKY beneath, both
// centered horizontally. Pre-save the wheel-col is hidden so this column
// fills the aperture & sits visually centered. Post-save the snap layout
// (body.sky-saved) keeps the same internal stacking but pins each col to
// the aperture height.
.sky-page .sky-form-col {
flex: 1 0 auto;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 1rem;
min-height: 100%;
border-right: none;
border-top: 0.1rem solid rgba(var(--terUser), 0.12);
}
.sky-page .sky-form-main {
flex: 0 0 auto;
width: 100%;
max-width: 22rem;
min-width: 0;
max-height: none;
overflow-y: visible;
}
// The (max-width:600px) block (written for the in-room PICK SKY modal where
// form-col is flex-row) sets align-self:flex-end on the btn — that's "right"
// once we flip to flex-column. Reset.
.sky-page .sky-form-col > #id_sky_confirm {
align-self: auto;
}
// Pre-save the wheel section is hidden — no preview wheel shunts the form
// downward & the user clearly sees SAVE SKY. The DEL btn rides along so
// async SAVE SKY can reveal it without a template re-render.
body:not(.sky-saved) .sky-page .sky-wheel-col {
display: none;
}
// On the same media envelopes where .btn-primary shrinks to 2.75rem, narrow
// the form-col's vertical gap so SAVE SKY tucks closer to #id_sky_status &
// the form fits a short landscape / portrait phone aperture without clipping.
@media (orientation: landscape) and (max-width: 1100px),
(orientation: portrait) {
.sky-page .sky-form-col {
gap: 0.4rem;
}
}
// ── Snap-binary aperture (post-save) ──────────────────────────────────────────
// Once a sky is saved, the .sky-page aperture flips into scroll-snap mode:
// the wheel section + form section each fill the aperture, so scrolling toggles
// between them rather than free-flowing. SAVE SKY (in sky.html's click handler)
// animates the aperture back to the top after a successful save.
//
// modal-body keeps height:100% (= aperture height), so its two flex children
// using min-height:100% each resolve to a full aperture each → modal-body's
// content overflows itself → .sky-page (overflow-y:auto) becomes the scroller.
body.sky-saved {
.sky-page {
scroll-snap-type: y mandatory;
}
// modal-body acts as a layout pass-through so the wheel & form cols become
// direct flex children of .sky-page, where `min-height: 100%` resolves
// against the aperture height (.sky-page has flex:1 + min-height:0 so its
// height is explicit in the parent flex column).
.sky-page .sky-modal-body {
display: contents;
}
.sky-page .sky-wheel-col,
.sky-page .sky-form-col {
scroll-snap-align: start;
scroll-snap-stop: always;
min-height: 100%;
flex: 0 0 auto;
}
// Release the wheel-col aspect-ratio cap so the section fills the aperture;
// .sky-svg inside still renders square (its own aspect-ratio:1/1) and stays
// centered via the col's align-items:center.
.sky-page .sky-wheel-col {
aspect-ratio: auto;
max-width: none;
max-height: none;
width: 100%;
}
// form-col loses its grow/min-height fill so the snap basis (min-height:100%
// above) wins instead — without this, two `flex: 1 0 auto` sections compete
// for the aperture height and the snap stops landing at the col boundaries.
.sky-page .sky-form-col {
flex: 0 0 auto;
}
}
// ── Sidebar z-index sink (landscape sidebars must go below backdrop) ───────────
@media (orientation: landscape) {
html.sky-open body .container .navbar,
html.sky-open body #id_footer {
z-index: 90;
}
}