/* ==========================================================================
   Sunny Days — app styling (Rookie A)

   Day-sky style, per "SunDome Skies Design/design_handoff_sundome_day_sky": a
   bright pale-blue sky, one yellow accent, navy ink, and a Stockholm waterfront
   horizon.

   One palette, defined once here, used everywhere. The slider (this file), the
   panel and the location screens (styled at runtime inside panel.js / geo.js)
   all pull from these tokens so the app reads as one thing. The sizes below are
   the handoff's px values, not rem: they are type and touch sizes for a phone
   screen and are not meant to grow with the column.
   ========================================================================== */

:root {
  /* Sky — the screen, then the graphic block inside it */
  --sky-top:    #fbfcfd;
  --sky-mid:    #e9f0f4;
  --sky-bot:    #f7f2e6;
  --stage-top:  #a4cde9;
  --stage-bot:  #dcecf2;

  --ink:       #21324f;  /* primary text, wordmark, date            */
  --ink-mark:  #274063;  /* the needle, and the mark's horizon line  */
  --ink-2:     #3f5570;  /* hour labels, quiet compass cardinals     */
  --ink-3:     #5d7085;  /* polar note, today's tick                 */
  --ink-4:     #6d7d95;  /* card labels                              */
  --ink-5:     #8395aa;  /* month scale                              */
  --ink-6:     #a7b6c6;  /* altitude rungs and their labels          */

  /* The one accent, in its six jobs. Fills and active states carry --sun;
     strokes go a step darker so a 2.8px arc still reads on pale blue. */
  --sun:        #e8b923;
  --sun-stroke: #d9a30a;
  --sun-halo:   #f7c948;  /* now-sun glow                            */
  --sun-arc:    #f2c94c;  /* gradient under the sun path             */
  --sun-text:   #a8860a;  /* accent as text/label on a light ground   */
  --sun-ink:    #2b2205;  /* text sitting on top of a --sun fill      */
  --sun-edge:   #fff8e2;  /* the warm white rim around the now-sun    */

  --card:      #ffffff;
  --chip:      #e8eff4;  /* unselected preset                        */
  --trough:    #d5dfe7;  /* slider track past the thumb              */

  /* The horizon art and the compass dial. These and the sun values above are
     the whole palette of the SVG graphics, and they are spelled out again as
     literals in panorama.js and dome.js: an SVG presentation attribute can't
     read a custom property. The record lives here; change both together. */
  --sky-far:    #a8c0d4;
  --sky-near:   #88a6c1;
  --water-top:  #8fb8dc;
  --water-bot:  #6a97c3;
  --refl:       #5b81a4;
  --land:       #33566c;
  --detail:     #26424f;
  --boat:       #2c4657;
  --dial:       #b6d5ea;
  --dial-rim:   #7f9fbb;
  --tick-far:   #a9bccb;  /* winter-solstice mark on the date slider  */

  --hairline: rgb(33 50 79 / 0.1);
  --card-shadow:  0 2px 10px rgb(33 50 79 / 0.07);
  --pill-shadow:  0 2px 6px rgb(33 50 79 / 0.1);
  --thumb-shadow: 0 2px 6px rgb(33 50 79 / 0.25);
  --card-radius:  16px;
  --stage-radius: 22px;
  /* The design's 400px screen with 14px margins, which is what makes the
     graphic block exactly 372 wide — the width its viewBox is drawn for. */
  --column: 400px;
  --gutter: 14px;

  --font-sans: 'DM Sans', system-ui, -apple-system, sans-serif;
  --font-mono: 'DM Mono', ui-monospace, monospace;
}

* { box-sizing: border-box; margin: 0; padding: 0; }

body {
  font-family: var(--font-sans);
  color: var(--ink);
  /* The day sky: near-white overhead, warming to a sunlit haze at the bottom.
     Fixed so it doesn't scroll away on a tall page. */
  background: linear-gradient(var(--sky-top) 0%, var(--sky-mid) 58%, var(--sky-bot) 100%)
    var(--sky-mid) fixed;
  min-height: 100dvh;
  padding:
    max(20px, env(safe-area-inset-top))
    env(safe-area-inset-right)
    max(24px, env(safe-area-inset-bottom))
    env(safe-area-inset-left);
  display: flex;
  flex-direction: column;
  align-items: center;
  -webkit-font-smoothing: antialiased;
}

/* ------------------------------------------------------------ app header */

/* Rising-sun mark, wordmark, view switch — one centred row. */
.app-header {
  display: flex;
  align-items: center;
  gap: 9px;
  width: 100%;
  max-width: var(--column);
  padding: 0 18px;
}

/* A half disc rising over a horizon line: the app's subject in 18px. */
.app-mark {
  width: 18px;
  height: 18px;
  flex: none;
  display: block;
}

h1 {
  font: 700 15px/1 var(--font-sans);
  letter-spacing: 0.17em;
  text-transform: uppercase;
  color: var(--ink);
}

/* ------------------------------------------------ view switch (app.js)

   One pill, right of the wordmark, labelled with the view you are NOT looking
   at — so it reads as the way through rather than as a state read-out. */

#viewtoggle { margin-left: auto; }

.view-switch {
  min-height: 40px;
  padding: 0 20px;
  border: 1.5px solid var(--sun);
  border-radius: 999px;
  background: var(--card);
  color: var(--ink);
  font: 500 13px var(--font-sans);
  letter-spacing: 0.02em;
  box-shadow: var(--pill-shadow);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

.view-switch:hover { background: #fffdf2; }
.view-switch:active { transform: scale(0.98); }
.view-switch:focus-visible { outline: 2px solid var(--sun-stroke); outline-offset: 2px; }

/* Every block shares one column and one gutter, so the app lines up top to
   bottom. The switch is not in this list — it lives inside the header row. */
#panel,
#slider,
#geo {
  width: 100%;
  max-width: var(--column);
  padding: 0 var(--gutter);
}

/* The date controls ride the bottom of the screen, as in the design: on a tall
   phone the spare room falls above them, where a thumb isn't. */
#slider { margin-top: auto; }

/* ---------------------------------------------------- v2 view shell (app.js)

   #panorama and #orient are stacked in one grid cell; App.setView() toggles
   .is-active and the inactive view fades + slides out. Panorama parks left and
   orient parks right, so orient reads as "forward" and back slides back. */

.views {
  position: relative;
  width: 100%;
  max-width: var(--column);
  margin-top: 18px;
  padding: 0 var(--gutter);
  display: grid;
  /* The parked view waits 24px off-column, which is enough to raise a sideways
     scrollbar on a phone. clip (not hidden) keeps this from becoming a scroll
     container. */
  overflow-x: clip;
  overflow-clip-margin: 6px;
}

.view {
  grid-area: 1 / 1;
  opacity: 0;
  transform: translateX(24px);
  pointer-events: none;
  transition: opacity 260ms ease, transform 260ms ease;
}

/* :not(.is-active) is load-bearing: a bare #panorama would outrank
   .view.is-active on specificity and leave the active view parked off-column. */
#panorama:not(.is-active) { transform: translateX(-24px); }

.view.is-active {
  opacity: 1;
  transform: none;
  pointer-events: auto;
}

@media (prefers-reduced-motion: reduce) {
  .view { transition: none; }
  .sd-sunpulse { animation: none; }
  .dome-stage > svg { transition: none; }
}

/* Placeholder so the shell is testable while the views are empty. :empty stops
   matching the moment a view gets real content — nothing to clean up. */
.view:empty {
  display: grid;
  place-items: center;
  min-height: 110px;
  border: 1px dashed var(--hairline);
  border-radius: var(--stage-radius);
  background: var(--card);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

.view:empty::before {
  content: attr(data-label) " — tap to switch view";
  font-size: 0.8rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-4);
}

/* Which day the whole stage is showing. Written by panorama.js; sits inside the
   block's top-left corner, so it is offset by the gutter as well as its own
   18px inset. */
.stage-stamp {
  position: absolute;
  z-index: 2;
  top: 18px;
  left: calc(var(--gutter) + 18px);
  font: 500 13px/1 var(--font-sans);
  letter-spacing: 0.03em;
  text-transform: uppercase;
  color: var(--ink);
}

/* -------------------------------------------- graphic block (both views)

   One box, two graphics: the panorama's horizon strip and the compass dial. The
   aspect ratio is the design's 372 × 430 block, and it matches the panorama sky
   viewBox exactly, so that SVG fills it with no stretch, the sun renders as a
   true circle, and switching views never shifts the layout below. Change the
   two together: SW and SH in panorama.js are the same numbers. */

.pano-strip,
.dome-stage {
  position: relative;
  aspect-ratio: 372 / 430;
  border-radius: var(--stage-radius);
  overflow: hidden;
  background: linear-gradient(var(--stage-top), var(--stage-bot));
}

/* Containing block for compass.js's hint, which floats over the foot of the
   dial rather than pushing the chrome below it down. */
#orient { position: relative; }

.dome-stage {
  display: grid;
  place-items: center;
}

/* The design's 352px dial inside the 372px block. Squared off the width so the
   viewBox never stretches — the dial has to stay a circle. overflow:visible per
   the design: nothing spills today (the outermost glyph, N, reaches y≈0.5 of the
   100-unit box) but the cardinals sit close enough to the edge that a browser
   with its own idea of dominant-baseline would clip them. */
.dome-stage > svg {
  width: 94.62%;
  aspect-ratio: 1;
  display: block;
  overflow: visible;
  transition: filter 320ms ease, opacity 320ms ease;
}

/* Until the compass is live — waiting on the permission tap, or on the first
   press where there is no sensor — the dial greys out behind compass.js's cue,
   so a sky that isn't oriented to you yet doesn't look like one that is.
   compass.js owns the switch; the paint belongs here with the rest of the
   stage. */
#orient.is-idle .dome-stage > svg {
  filter: grayscale(0.9);
  opacity: 0.55;
}

/* ------------------------------------------------ date slider (slider.js) */

.sd-slider {
  --sd-thumb: 30px;
  --sd-track: 10px;

  margin-top: 24px;
  -webkit-user-select: none;
  user-select: none;
  -webkit-tap-highlight-color: transparent;
}

/* Redundant now — the preset buttons light up when their date is selected, so
   the name is just repeating that. Hidden rather than deleted: slider.js still
   sets its text (harmless). If this sticks, drop the element in slider.js too. */
.sd-preset-name { display: none; }

/* Three marks over the groove: the two solstices and today. 4px sides, per the
   design — the same inset the month letters use, so the two scales agree. */
.sd-marks {
  position: relative;
  height: 9px;
  margin: 0 4px;
  pointer-events: none;
}

.sd-mark {
  position: absolute;
  bottom: 0;
  width: 2px;
  height: 7px;
  border-radius: 1px;
  background: var(--ink-3);
  transform: translateX(-50%);
}

.sd-mark--summer-solstice { background: var(--sun); }
.sd-mark--winter-solstice { background: var(--tick-far); }

.sd-range {
  display: block;
  width: 100%;
  height: 34px;
  background: transparent;
  -webkit-appearance: none;
  appearance: none;
  /* Keeps the page from scrolling out from under your thumb mid-drag. */
  touch-action: none;
}

.sd-range:focus { outline: none; }
.sd-range:focus-visible { outline: 2px solid var(--sun-stroke); outline-offset: 4px; }

.sd-range::-webkit-slider-runnable-track {
  height: var(--sd-track);
  border-radius: 999px;
  background: linear-gradient(
    to right,
    var(--sun) 0 var(--sd-fill, 0%),
    var(--trough) var(--sd-fill, 0%) 100%
  );
}

.sd-range::-webkit-slider-thumb {
  width: var(--sd-thumb);
  height: var(--sd-thumb);
  margin-top: calc((var(--sd-track) - var(--sd-thumb)) / 2);
  border: 4px solid var(--sun);
  border-radius: 50%;
  background: var(--card);
  box-shadow: var(--thumb-shadow);
  -webkit-appearance: none;
  appearance: none;
}

.sd-range::-moz-range-track {
  height: var(--sd-track);
  border-radius: 999px;
  background: var(--trough);
}

.sd-range::-moz-range-progress {
  height: var(--sd-track);
  border-radius: 999px;
  background: var(--sun);
}

.sd-range::-moz-range-thumb {
  width: var(--sd-thumb);
  height: var(--sd-thumb);
  border: 4px solid var(--sun);
  border-radius: 50%;
  background: var(--card);
  box-shadow: var(--thumb-shadow);
}

/* Presets sit above the track, as in the design. */
.sd-presets {
  display: flex;
  gap: 9px;
  margin-bottom: 14px;
}

.sd-preset {
  flex: 1;
  min-height: 36px;
  border: none;
  border-radius: 10px;
  background: var(--chip);
  color: var(--ink);
  font: 500 11.5px var(--font-sans);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

.sd-preset:active { transform: scale(0.97); }
.sd-preset:focus-visible { outline: 2px solid var(--sun-stroke); outline-offset: 2px; }

.sd-preset[aria-pressed='true'] {
  background: var(--sun);
  color: var(--sun-ink);
}

/* Month letters under the track, spread across it. */
.sd-months {
  display: flex;
  justify-content: space-between;
  margin: 2px 4px 0;
  font: 500 8px/1 var(--font-mono);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-5);
  pointer-events: none;
}
/* The year's turning point, in the accent — the one month the app is about. */
.sd-month--jun { color: var(--sun-text); }

/* ------------------------------------------------- info panel (panel.js) */

/* The panel is built and styled at runtime inside panel.js. This block restyles
   it from the outside — palette AND layout — using #panel to win on specificity
   regardless of load order.
   HEAVY COUPLING: these rules assume panel.js's exact markup (.panel-card >
   .panel-row > .panel-label + .panel-value, plus .panel-date / .panel-note) —
   including that the rows are the only <div>s in the card, which is what the
   :nth-of-type alignment below counts on. If Rookie B changes that structure,
   this layout breaks silently. The clean end state is to fold this into
   panel.js; keep it here only with their sign-off. */

/* Sunrise · Sunset · Day length become three columns in one white card, echoing
   the three preset buttons below and freeing vertical room for the stage. */
#panel .panel-card {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  margin-top: 12px;
  padding: 12px 18px;
  border: none;
  border-radius: var(--card-radius);
  background: var(--card);
  box-shadow: var(--card-shadow);
}

/* The stage already shows the date — no need to repeat it here. */
#panel .panel-date { display: none; }

/* Outer columns lean on the card's edges, the middle one centres. */
#panel .panel-row:first-of-type { text-align: left; }
#panel .panel-row:nth-of-type(2) { text-align: center; }
#panel .panel-row:last-of-type { text-align: right; }

#panel .panel-label {
  display: block;
  font: 500 8.5px/1 var(--font-sans);
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--ink-4);
}

#panel .panel-value {
  display: block;
  margin-top: 6px;
  font: 500 17px/1 var(--font-mono);
  font-variant-numeric: tabular-nums;
  color: var(--ink);
}

/* Polar-day / polar-night note spans full width beneath the three columns. */
#panel .panel-note {
  grid-column: 1 / -1;
  margin-top: 8px;
  text-align: center;
  font: 400 11px/1.4 var(--font-sans);
  color: var(--ink-3);
}

/* -------------------------------------------- panorama view (panorama.js)

   Component styles for the eye-level horizon strip. It renders inside the
   #panorama view section (see the graphic block above), hour labels and
   cardinals and all — so the whole thing comes and goes with the view. */

.pano-sky {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
}

/* The Stockholm waterfront, pinned to the bottom of the block. 118px of the
   430px block; as a percentage it keeps that share at any width. */
.pano-horizon {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  width: 100%;
  height: 27.44%;
  display: block;
}

/* Now-sun pulse — a soft breathing glow. Used by both graphics. */
@keyframes sd-sunpulse {
  0%, 100% { opacity: 0.3;  transform: scale(1); }
  50%      { opacity: 0.52; transform: scale(1.12); }
}
.sd-sunpulse {
  transform-box: fill-box;
  transform-origin: center;
  animation: sd-sunpulse 2.8s ease-in-out infinite;
}

/* Hour numbers, cardinals and altitude labels are HTML over the SVG rather than
   <text> inside it: each is offset from its anchor in px, and px only stays px
   outside a viewBox that scales with the column. panorama.js sets each
   `left`/`top` as a share of the stage, and the translate below carries the
   design's offset. */

.pano-hours,
.pano-cardinals,
.pano-altitudes {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

.pano-hours span {
  position: absolute;
  font: 500 10px/1 var(--font-mono);
  color: var(--ink-2);
  /* 15px right and 9px above the dot, off the arc it labels. */
  transform: translate(calc(-50% + 15px), calc(-50% - 9px));
}

/* Only the quarters the sun actually crosses, standing on the dark quay — where
   white is the one ink that reads. Placed at the azimuth crossing, so the row
   lines up exactly with the arc above. */
.pano-cardinals span {
  position: absolute;
  bottom: 13px;
  transform: translateX(-50%);
  font: 500 8.5px/1 var(--font-mono);
  letter-spacing: 0.08em;
  color: #ffffff;
}

/* Altitude read-off, in the empty air the arc has already come down from. The
   lightest ink there is: a scale to glance at, never something to read before
   the arc itself. */
.pano-altitudes span {
  position: absolute;
  font: 500 8px/1 var(--font-mono);
  color: var(--ink-6);
  /* right-aligned on its anchor, centred on the rung it names */
  transform: translate(-100%, -50%);
}

/* ------------------------------------------------------- not found (404.html)

   The only rules here that the app itself never uses. 404.html borrows the
   header and the sky, so a mistyped URL still reads as this app rather than as
   the host's error page. */

/* auto margins, not a wrapper: body is already a centred flex column, so this
   takes the leftover height and lands the block on the optical centre. */
.notfound {
  width: 100%;
  max-width: var(--column);
  margin: auto;
  padding: 0 18px;
  text-align: center;
}

.notfound-code {
  font: 500 13px var(--font-mono);
  letter-spacing: 0.18em;
  color: var(--sun-text);
}

.notfound-title {
  margin-top: 10px;
  font: 700 22px/1.25 var(--font-sans);
  color: var(--ink);
}

.notfound-note {
  margin-top: 8px;
  font: 400 15px/1.5 var(--font-sans);
  color: var(--ink-4);
}

/* The view switch's pill, as a link. */
.notfound-link {
  display: inline-block;
  margin-top: 22px;
  padding: 12px 20px;
  border: 1.5px solid var(--sun);
  border-radius: 999px;
  background: var(--card);
  color: var(--ink);
  font: 500 13px var(--font-sans);
  letter-spacing: 0.02em;
  text-decoration: none;
  box-shadow: var(--pill-shadow);
  -webkit-tap-highlight-color: transparent;
}

.notfound-link:hover { background: #fffdf2; }
.notfound-link:active { transform: scale(0.98); }
.notfound-link:focus-visible { outline: 2px solid var(--sun-stroke); outline-offset: 2px; }
