@charset "utf-8";
/*
 * karte.css - styles of the 3D map in the CSS 3D variant: the map is made of HTML elements that CSS
 * turns in 3D.                                                                            [V2]
 *
 * Everything in this file belongs to the interactive map that js/karte.js builds from
 * js/data/karte-daten.js. Version 1 shows the static image img/karte-statisch.png instead and does not
 * need this file.
 *
 * How the 3D view works (course topics: perspective, transform, transform-style, transition):
 *   .map-stage   the "stage", 1600 x 1066 px, the same size as the reference image 03. It has a perspective
 *                (distance of the eye) and is scaled as a whole to the width of the page.
 *   .map-plane   the ground plate with the ground texture img/boden-<mood>.svg. rotateX() tilts it away from us,
 *                so that the Schloss is in front and the north of the city is at the back.
 *   .map-block   one Quadrat. Its walls are divs that stand up with rotateX(-90deg); its roof is a div
 *                lifted with translateZ(). transform-style: preserve-3d keeps all of them in one 3D space,
 *                so the browser itself decides what is in front.
 *   Numbers that depend on the map (sizes, angles) come from karte-daten.js; karte.js puts them into the
 *   custom properties (--...) used below.
 * Units: the map is one fixed 1600 px drawing that is scaled as a whole, so sizes (also font sizes) are in px on
 * purpose: they must fit the geometry exactly. The rest of the site uses rem (css/style.css).
 */

/* ---------- design values of the map ----------
   These are the values of the day (mood "tag"). The other moods (sunrise, sunset, night) change them in the
   section "time-of-day moods" at the end of this file. */
.map-root {
  --map-ground: #e6e4df;          /* ground */
  --map-roof: #fbfbf9;            /* roofs: almost white by day */
  --map-wall: #dad7d0;            /* walls, a little darker than the roofs */
  --map-roof-edge: #c8c4bc;       /* thin edge around every roof */
  --map-roof-text: #3a3d43;       /* codes on roofs without a category colour */
  --map-text-light: #ffffff;      /* codes on dark category colours */
  --map-text-dark: #2b2d31;       /* codes on open squares and on light category colours */
  --map-ground-image: url("../img/boden-tag.svg");
  --sun-rgb: 255, 248, 235;       /* colour of the sunlight on the walls (r, g, b) */
  --sun-strength: 0.15;           /* how strongly sunlit walls take that colour (0 = not at all) */
  --map-selected: #ffcf3f;        /* yellow edges of the selected block */
  --map-light: 255, 214, 102;     /* warm light from below (r, g, b, used with an alpha value) */
  --map-focus: #ffffff;           /* keyboard focus frame */
  /* grow / shrink animation: --duration-grow comes from css/style.css (0 ms for less motion) */
  --map-duration: var(--duration-grow, 450ms);
  --map-easing: cubic-bezier(0.2, 0.8, 0.3, 1);   /* an ease-out curve: fast start, soft landing */
  --grow-factor: 2.4;             /* selected block: roof height x 2.4 (clearly visible from the steep camera) */
  /* change of the time-of-day mood (Version 6: the picture of the old mood fades out, see the end of the section
     on moods): 0.9 s as in Version 4, long enough to look soft, short enough that nobody waits for it.
     Keep it equal to FADE_MS in js/karte.js. */
  --mood-duration: 0.9s;
  --mood-easing: ease-in-out;     /* starts and ends softly */
}

/* ---------- frame, stage and plane ---------- */

/* The frame takes the width of the page. On very narrow screens the map keeps a minimum size
   and the frame scrolls sideways instead of making the codes unreadably small. */
.map-scroll {
  position: relative;
  width: 100%;
  overflow-x: auto;
  overflow-y: hidden;
  background: var(--map-ground);
}

/* Has the size of the scaled stage (set by karte.js), so the page reserves the right height. */
.map-sizer {
  position: relative;
  overflow: hidden;
}

.map-stage {
  position: absolute;
  left: 0;
  top: 0;
  width: var(--stage-width);
  height: var(--stage-height);
  overflow: hidden;
  background: var(--map-ground);
  /* the eye is --perspective pixels in front of the stage, above the point --origin-x / --origin-y */
  perspective: var(--perspective);
  perspective-origin: var(--origin-x) var(--origin-y);
  /* scale the finished picture to the page width (karte.js sets --scale) */
  transform: scale(var(--scale, 1));
  transform-origin: 0 0;
  font-family: Helvetica, Arial, sans-serif;
}

.map-plane {
  position: absolute;
  left: var(--plane-left);
  top: var(--plane-top);
  width: var(--plane-width);
  height: var(--plane-height);
  background: var(--map-ground) var(--map-ground-image) 0 0 / 100% 100% no-repeat;   /* one ground picture per mood (Version 6, as in Version 4) */
  /* tilt the plate around the point the camera looks at */
  transform-origin: var(--pivot-x) var(--pivot-y);
  transform: rotateX(var(--tilt));
  /* children keep their own 3D position instead of being flattened into the plate */
  transform-style: preserve-3d;
  /* only the Quadrate react to the mouse, not the ground, trees or landmarks */
  pointer-events: none;
}

/* ---------- one Quadrat ---------- */

/* The element sits in the top-left corner of the plate; all its parts use plate coordinates. */
.map-block {
  position: absolute;
  left: 0;
  top: 0;
  transform-style: preserve-3d;
  pointer-events: auto;
  cursor: pointer;
  outline: none;                      /* focus is shown on the roof instead, see below */
  --block-roof: var(--map-roof);
  --block-wall: var(--map-wall);
  --block-edge: var(--map-roof-edge);
  --height-factor: 1;                 /* 1 normally, --grow-factor when selected */
  --label-scale: 1;                   /* size of the code label */
  --wall-height: var(--block-height);
  --roof-height: var(--block-height);
}

.map-block--open {
  --roof-height: 0.5px;               /* open squares are flat */
}

/* A building part. When selected it is scaled around its centre (set per part by karte.js) so that it
   spreads a little into the streets. scale() only changes the width and depth, the height is done by
   --height-factor. */
.map-part {
  position: absolute;
  left: 0;
  top: 0;
  transform-style: preserve-3d;
  transform: scale(1, 1);
  transition: transform var(--map-duration) var(--map-easing);
}

/* A wall: its bottom edge is one edge of the footprint. rotateZ turns it along the edge, rotateX(-90deg) stands
   it up (the bottom edge stays on the ground, because transform-origin is the bottom-left corner) and scaleY
   makes it taller when the block is selected. Walls that face away from the camera are not exported at all. */
.map-wall {
  position: absolute;
  height: var(--wall-height);
  transform-origin: 0 100%;
  transform: rotateZ(var(--angle)) rotateX(-90deg) scaleY(var(--height-factor));
  backface-visibility: hidden;
  background-color: var(--block-wall);
  /* The darkening by orientation is a transparent black layer on top of the colour, and walls facing the sun
     get a layer of sun colour, so the same walls also work with the category colours. Both layers are inset
     shadows that fill the whole wall (spread 2000px): unlike a gradient, a shadow can glide to a new colour
     when the mood changes. The first two shadows stay invisible here; a selected wall uses them (see below). */
  box-shadow:
    inset 0 0 0 0 transparent,
    inset 0 0 0 0 transparent,
    inset 0 0 0 2000px rgba(0, 0, 0, var(--shade)),
    inset 0 0 0 2000px rgba(var(--sun-rgb), calc(var(--sun, 0) * var(--sun-strength)));
  /* Only the movement glides (since 2026-10-14). The colour and the light change in small steps with the time:
     a glide of 368 walls would make the browser check them again in every picture, and the map would stutter. */
  transition: transform var(--map-duration) var(--map-easing);
}

/* Lit windows at night: the picture img/fenster.svg (one row of windows) repeated over the whole wall, in two
   layers with different offsets so the windows look irregular. Every wall starts at its own offset (--win-x, set
   by karte.js), so the buildings do not all look the same. Invisible by day; .mood-nacht shows them. */
.map-wall::before {
  content: "";
  position: absolute;
  inset: 0;
  background-image: url("../img/fenster.svg"), url("../img/fenster.svg");
  background-size: 34px 5.5px;
  background-position: var(--win-x, 0) 0, calc(var(--win-x, 0) * 2 + 15px) 0;
  opacity: 0;
}

/* warm light that shines on the wall from below; invisible until the block is selected */
.map-wall::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(to top, rgba(var(--map-light), 0.95), rgba(var(--map-light), 0.35) 45%, rgba(var(--map-light), 0) 80%);
  opacity: 0;
  transition: opacity var(--map-duration) ease;
}

/* The roof: a flat element lifted to the wall height. Inside: the edge colour clipped to the footprint,
   the roof colour clipped to a slightly smaller footprint (so a thin edge stays visible) and the code.
   The footprints --outline-outer, --outline-inner and --outline-selected are polygon() values set by karte.js. */
.map-roof {
  position: absolute;
  transform: translateZ(calc(var(--roof-height) * var(--height-factor)));
  transition: transform var(--map-duration) var(--map-easing);
  /* the box is a rectangle around the footprint; only the clipped roof itself reacts to the mouse */
  pointer-events: none;
}

/* clip-path is supported without prefix by every current browser (Safari since 13.1) */
.map-roof-edge,
.map-roof-surface,
.map-square-edge,
.map-square-inner {
  position: absolute;
  inset: 0;
  clip-path: var(--outline-outer);
}

.map-roof-edge {
  background-color: var(--block-edge);
  pointer-events: auto;               /* clip-path also clips the clickable area */
}

.map-roof-surface,
.map-square-inner {
  clip-path: var(--outline-inner);
}

.map-roof-surface {
  background-color: var(--block-roof);
  transition: clip-path var(--map-duration) var(--map-easing);
}

/* The code label. Its size is given in stage pixels; the matrix --label-matrix (from karte-daten.js) undoes the
   tilt and the perspective at this spot, so the text looks upright and unstretched like in the reference image. */
.map-code {
  position: absolute;
  transform-origin: 0 0;
  transform: var(--label-matrix) scale(var(--label-scale)) translate(-50%, -50%);
  font-weight: 700;
  line-height: 1;
  white-space: nowrap;
  color: var(--map-roof-text);
  transition: transform var(--map-duration) var(--map-easing);
}

/* ---------- open squares (G1, O1, B3, H6, M4a): flat, their look is part of the ground texture ---------- */

/* No transform: the outline is painted together with the ground plate (a separate layer lying exactly on the
   ground would make the browser's depth sorting flicker). */
.map-square {
  position: absolute;
  pointer-events: none;               /* only the clipped parts below react to the mouse */
}

.map-square-edge,
.map-square-inner {
  background-color: transparent;
  pointer-events: auto;
}

/* The sign with code and name stands upright on the ground (rotateX(-90deg), like a wall facing the camera), so
   the block behind the square cannot cover it. Its bottom middle is the foot point (the negative margins move the
   box there). --sign-scale undoes the perspective enlargement at this spot and scaleY(--stretch) makes up for the
   camera looking down on it, so the text has the same size and shape as in image 03. */
.map-sign {
  position: absolute;
  width: 160px;
  height: 40px;
  margin-left: -80px;
  margin-top: -40px;
  transform-origin: 50% 100%;
  transform: rotateX(-90deg) scale(var(--sign-scale)) scaleY(var(--stretch));
  pointer-events: none;               /* the empty part of the box must not catch clicks for neighbours */
}

.map-sign-text {
  position: absolute;
  left: 50%;
  bottom: 0;
  transform: translateX(-50%);        /* centred above the foot point */
  text-align: center;
  white-space: nowrap;
  color: var(--map-text-dark);
  pointer-events: auto;               /* the text itself selects the square */
  /* a halo in the colour of the square keeps the text readable on paving and grass */
  text-shadow: 0 0 2px var(--halo), 0 0 2px var(--halo), 0 0 3px var(--halo), 0 0 4px var(--halo);
}

.map-sign-code {
  display: block;
  font-size: 16px;
  font-weight: 700;
  line-height: 16px;
}

.map-sign-name {
  display: block;
  font-weight: 600;
  line-height: 1.2;
  color: #46433c;
}

/* ---------- glow on the ground under the selected Quadrat ---------- */

/* All glows sit in one layer, the first child of the plate (js/karte.js), so they are painted with the ground
   under every building. Inside the blocks, Safari sorted the glow of A4 wrongly and drew A4 behind B4 and B5. */
.map-pools {
  position: absolute;
  left: 0;
  top: 0;
  pointer-events: none;
}

/* No transform, like .map-square: painted together with the ground plate. */
.map-pool {
  position: absolute;
  background: radial-gradient(closest-side, rgba(var(--map-light), 1), rgba(var(--map-light), 0.7) 55%, rgba(var(--map-light), 0));
  opacity: 0;
  transition: opacity var(--map-duration) ease;
  pointer-events: none;
}

/* ---------- category colours (Karte.faerben): the whole building takes the colour ---------- */
.map-block.is-tinted {
  --block-roof: var(--tint);
  --block-wall: var(--tint);
}

.map-block.is-tinted .map-roof-edge {
  background-color: var(--tint);
  background-image: linear-gradient(rgba(0, 0, 0, 0.3), rgba(0, 0, 0, 0.3));   /* slightly darker edge */
}

/* On dark category colours the code is white ... */
.map-block.is-tinted .map-code {
  color: var(--map-text-light);
}

/* ... on light category colours (class set by karte.js) the white code would be hard to read: dark text instead. */
.map-block.is-tinted-light .map-code {
  color: var(--map-text-dark);
}

.map-block--open.is-tinted .map-square-inner {
  background-color: var(--tint);
  opacity: 0.5;                       /* the square stays recognisable under the colour */
}

/* ---------- mouse over a Quadrat ---------- */
.map-block:hover .map-roof-surface {
  background-image: linear-gradient(rgba(255, 255, 255, 0.16), rgba(255, 255, 255, 0.16));
}

.map-block:hover .map-roof-edge,
.map-block:hover .map-square-edge {
  background: #f4efe2;
}

/* ---------- selected Quadrat (Karte.waehlen): taller, a little wider, yellow edges, lit from below ---------- */
.map-block.is-selected {
  --height-factor: var(--grow-factor);
  --label-scale: 1.2;
}

.map-block.is-selected .map-part {
  transform: scale(var(--sx), var(--sy));
}

/* thicker yellow roof edge: the roof surface shrinks to a smaller footprint with the same corners */
.map-block.is-selected .map-roof-surface {
  clip-path: var(--outline-selected);
}

.map-block.is-selected .map-wall {
  /* first inset shadow = yellow frame along all four edges of the wall, second = soft glow inside the edges.
     Only inset shadows: a shadow outside the wall would make the browser sort the 3D pieces wrongly. */
  box-shadow:
    inset 0 0 0 1.5px var(--map-selected),
    inset 0 0 8px 2px rgba(var(--map-light), 0.6),
    inset 0 0 0 2000px rgba(0, 0, 0, var(--shade)),
    inset 0 0 0 2000px rgba(var(--sun-rgb), calc(var(--sun, 0) * var(--sun-strength)));
  /* the yellow frame glides in; only the few walls of the selected Quadrat have this transition */
  transition: transform var(--map-duration) var(--map-easing), box-shadow var(--map-duration) ease;
}

.map-block.is-selected .map-wall::after,
.map-pool.is-lit {
  opacity: 1;
}

.map-block.is-selected .map-roof-edge,
.map-block.is-selected .map-square-edge {
  background: var(--map-selected);
}

/* ---------- keyboard focus: white frame around the code and a white roof edge ---------- */
.map-block:focus-visible .map-code,
.map-block:focus-visible .map-sign-code {
  outline: 2px solid var(--map-focus);
  outline-offset: 3px;
  border-radius: 2px;
}

.map-block--open:focus-visible .map-sign-code,
.map-block.is-tinted-light:focus-visible .map-code {
  outline-color: var(--map-text-dark);   /* a white frame would vanish on a light roof */
}

/* (a selected block keeps its yellow edge; the frame around the code still shows the focus) */
.map-block:focus-visible:not(.is-selected) .map-roof-edge,
.map-block:focus-visible:not(.is-selected) .map-square-edge {
  background: var(--map-focus);
}

/* ---------- pin for Quadrate with saved places (Karte.markieren, used by js/steckbrief.js with js/konto.js) ---------- */

/* Stands upright on the roof, facing the camera (rotateX(-90deg)); scaleY(--stretch) makes up for the camera
   looking down on it. Everything is drawn inside the 24 x 23 px box (nothing sticks out), which keeps the
   browser's 3D sorting clean. */
.map-pin {
  position: absolute;
  width: 24px;
  height: 23px;
  transform-origin: 50% 100%;
  /* scale(var(--pin-size)): 1.75 times as big since 2026-10-13; transform-origin 50% 100% keeps the tip in place */
  transform: translateZ(calc(var(--roof-height) * var(--height-factor) + var(--pin-z, 0px) + 1px)) rotateX(-90deg) scaleY(var(--stretch)) scale(var(--pin-size, 1.75));
  transition: transform var(--map-duration) var(--map-easing);
  pointer-events: none;
}

/* the pin head: a square with three round corners, turned so that the sharp corner points down to the tip */
.map-pin::before {
  content: "";
  position: absolute;
  left: 4px;
  top: 3.5px;
  width: 12px;
  height: 12px;
  border: 2px solid #ffffff;
  border-radius: 50% 50% 50% 0;
  background: #c0392b;
  transform: rotate(-45deg);
}

/* Pin in the colour of the category of the saved places (Karte.markieren with categories, 2026-10-13).
   The classes cat-essen ... of css/style.css set --cat-3; listed one by one, because the map itself may
   carry a cat- class of the filter, which a general rule would pass on to every pin. */
.map-pin.cat-essen::before,
.map-pin.cat-trinken::before,
.map-pin.cat-kultur::before,
.map-pin.cat-shoppen::before {
  background: var(--cat-3);
}

/* white dot in the head */
.map-pin::after {
  content: "";
  position: absolute;
  left: 10px;
  top: 9.5px;
  width: 4px;
  height: 4px;
  border-radius: 50%;
  background: #ffffff;
}

/* ---------- Schloss, trees and landmarks (not clickable) ---------- */
.map-palace {
  position: absolute;
  left: 0;
  top: 0;
  transform-style: preserve-3d;
  --height-factor: 1;                 /* the Schloss never grows */
  --block-wall: var(--palace-wall);   /* sandstone walls (colour from karte-daten.js) */
  --wall-height: var(--palace-height);
}

.map-palace-roof {
  position: absolute;
  background: url("../img/karte/schloss-dach.svg") 0 0 / 100% 100% no-repeat;
  transform: translateZ(var(--palace-height));
}

/* Trees and the Wasserturm are pictures facing the camera ("billboards"), turned about their bottom edge.
   A tree stands straight up (like a wall), so a building close behind it cannot cut its crown; scaleY gives
   it back the height the camera takes away. The Wasserturm picture is turned exactly parallel to the screen
   (it undoes the tilt of the plate), so it looks precisely like the drawing in image 03. */
.map-tree,
.map-landmark {
  position: absolute;
  transform-origin: 50% 100%;
  pointer-events: none;
}

.map-landmark {
  transform: rotateX(var(--untilt));
}

.map-tree {
  transform: rotateX(-90deg) scaleY(var(--stretch));
  width: var(--tree-width);
  height: var(--tree-height);
  margin-left: calc(var(--tree-width) / -2);   /* left/top name the foot of the tree */
  margin-top: calc(var(--tree-height) * -1);
  background: url("../img/karte/baum.svg") 50% 100% / 100% 100% no-repeat;
}

/* ---------- time-of-day moods (Karte.stimmung): sky, sun, moon and the colours of the city ----------
   js/filter.js chooses the mood from the time set in the filter (night 21-6, sunrise 6-8, day 8-19, sunset 19-21)
   and js/karte.js sets one of the classes mood-tag, mood-aufgang, mood-untergang, mood-nacht on the frame of the
   map (div.map-scroll). Version 6: on the frame, not on #karte, so the fading picture of the old mood (div.map-ghost,
   see the end of this section) can keep its own mood next to the live map. Each class only changes custom
   properties; the rules above use them. On the map east is on the right and west on the left: the sun rises on the
   right and sets on the left. karte.js also recomputes per wall how much it faces the sun or the moon (--sun 0..1)
   and how dark it is (--shade).
   The soft change (0.9 s, as in Version 4) is a picture of the old mood that fades out over the new map: see the
   rules at the end of this section. */

/* The sky: a band at the top of the map over the far end of the city, plus the sun or the moon in it.
   It lies above the 3D stage (later in the HTML, in div.map-sizer) and never catches the mouse. */
.map-sky,
.map-light {
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  pointer-events: none;
}

.map-sky {
  /* Outside the 3D stage (since Version 5), so the tilted plate cannot cut it at a hard edge. It has the size of
     the unscaled stage and is scaled like it (--scale on div.map-sizer), so sun and moon keep their place. */
  width: var(--stage-width);
  height: calc(var(--stage-height) * 0.14);   /* only the strip above the ring road, so no building is covered */
  transform: scale(var(--scale, 1));
  transform-origin: 0 0;
  /* the band fades out downwards into the city (mask: opaque at the top, transparent at the bottom) */
  -webkit-mask-image: linear-gradient(#000 45%, transparent);
  mask-image: linear-gradient(#000 45%, transparent);
}

/* Light over the whole map: a soft glow from the side of the sun (sunrise, sunset) or a dark veil (night). */
.map-light {
  height: 100%;
}

/* Sky and light have one layer per mood (div.mood-layer--tag, --aufgang ..., built by karte.js); only the layer
   of the current mood is visible. */
.mood-layer {
  position: absolute;
  inset: 0;
  opacity: 0;
}

.map-scroll.mood-tag .mood-layer--tag,
.map-scroll.mood-aufgang .mood-layer--aufgang,
.map-scroll.mood-untergang .mood-layer--untergang,
.map-scroll.mood-nacht .mood-layer--nacht {
  opacity: 1;
}

.map-sky .mood-layer--tag { background: linear-gradient(#cfe2f2, #e2ebf1); }
.map-sky .mood-layer--aufgang { background: linear-gradient(to left, #ffc48c, #d6c4de 55%, #aab0d6); }
.map-sky .mood-layer--untergang { background: linear-gradient(to right, #ff965a, #ec8c96 50%, #8c78b4); }
.map-sky .mood-layer--nacht { background: linear-gradient(#05070f, #0e1220); }

/* by day there is no light layer */
.map-light .mood-layer--aufgang { background: radial-gradient(ellipse 60% 70% at 100% 25%, rgba(255, 186, 110, 0.32), rgba(255, 186, 110, 0) 70%); }
.map-light .mood-layer--untergang { background: radial-gradient(ellipse 60% 70% at 0% 25%, rgba(255, 140, 80, 0.34), rgba(255, 140, 80, 0) 70%); }
.map-light .mood-layer--nacht { background: radial-gradient(ellipse 75% 70% at 50% 58%, rgba(8, 9, 14, 0) 55%, rgba(8, 9, 14, 0.55) 100%); }

.map-sun,
.map-moon {
  position: absolute;
  border-radius: 50%;
  opacity: 0;
}

.map-sun {
  top: 1%;
  width: 90px;
  height: 90px;
  background: radial-gradient(circle, #fff6d8 0%, #ffd27a 35%, rgba(255, 190, 110, 0.45) 55%, rgba(255, 170, 90, 0) 72%);
}

/* Two suns with fixed places, east for the sunrise and west for the sunset (karte.js builds both). */
.map-sun--aufgang {
  right: 4%;                          /* sunrise: east, on the right */
}

.map-sun--untergang {
  left: 4%;                           /* sunset: west, on the left, a little redder */
  background: radial-gradient(circle, #fff0d0 0%, #ffb35c 35%, rgba(255, 130, 70, 0.5) 55%, rgba(255, 110, 60, 0) 72%);
}

.map-moon {
  left: 7%;
  top: 1.5%;
  width: 46px;
  height: 46px;
  /* a full moon with two darker "seas" and a cool glow around it */
  background:
    radial-gradient(circle at 38% 40%, rgba(150, 160, 180, 0.55) 0 14%, transparent 15%),
    radial-gradient(circle at 62% 64%, rgba(150, 160, 180, 0.45) 0 10%, transparent 11%),
    radial-gradient(circle, #f4f1e6 0 62%, #dcd8cb 70%, transparent 71%);
  box-shadow: 0 0 24px 8px rgba(200, 215, 255, 0.35), 0 0 80px 30px rgba(140, 165, 230, 0.18);
}

/* Stars: one element, many small light dots drawn as shadows of a 2 px point. */
.map-stars {
  position: absolute;
  left: 0;
  top: 0;
  width: 2px;
  height: 2px;
  border-radius: 50%;
  background: transparent;
  opacity: 0;
  box-shadow:
    120px 18px #fff, 260px 44px rgba(255, 255, 255, 0.7), 340px 12px #fff, 470px 60px rgba(255, 255, 255, 0.6),
    560px 26px #fff, 690px 8px rgba(255, 255, 255, 0.8), 780px 52px #fff, 860px 20px rgba(255, 255, 255, 0.6),
    960px 40px #fff, 1040px 10px rgba(255, 255, 255, 0.7), 1130px 64px #fff, 1220px 30px rgba(255, 255, 255, 0.8),
    1310px 14px #fff, 1400px 50px rgba(255, 255, 255, 0.6), 1490px 24px #fff, 1560px 70px rgba(255, 255, 255, 0.7),
    200px 80px rgba(255, 255, 255, 0.5), 620px 90px rgba(255, 255, 255, 0.5), 1000px 86px rgba(255, 255, 255, 0.5),
    1350px 92px rgba(255, 255, 255, 0.5), 40px 54px rgba(255, 255, 255, 0.7);
}

/* --- day (8-19 h): white city under a light sky: the design values at the top of this file --- */

/* --- sunrise (6-8 h): the sun on the right (east), warm light on the east walls, cool shade on the west --- */
.map-scroll.mood-aufgang {
  --map-ground: #e4dde3;
  --map-roof: #f6f1f2;
  --map-wall: #d9ccd3;
  --map-roof-edge: #c8bcc6;
  --map-roof-text: #4a4558;
  --map-ground-image: url("../img/boden-aufgang.svg");
  --sun-rgb: 255, 176, 102;
  --sun-strength: 0.55;
}

.map-scroll.mood-aufgang .map-sun--aufgang {
  opacity: 1;
}

/* --- sunset (19-21 h): the sun on the left (west), mirrored --- */
.map-scroll.mood-untergang {
  --map-ground: #ead7cf;
  --map-roof: #f5e9e2;
  --map-wall: #d8c0b4;
  --map-roof-edge: #ccb2a6;
  --map-roof-text: #5b4540;
  --map-ground-image: url("../img/boden-untergang.svg");
  --sun-rgb: 255, 140, 80;
  --sun-strength: 0.6;
}

.map-scroll.mood-untergang .map-sun--untergang {
  opacity: 1;
}

/* --- night (21-6 h), after the user's reference pictures of night cities (data/userBilder, 2026-10-07) ---
   The light comes from below: the streets are lit warm by the street lamps (ground picture boden-nacht.svg), the
   buildings stand on it as dark shapes with many lit windows, the bottom of every facade catches the warm light,
   and the roof edges catch a little of it. Around the city the night gets darker (a veil towards the edges). */
.map-scroll.mood-nacht {
  --map-ground: #7d7466;
  --map-roof: #33353c;
  --map-wall: #575a63;
  --map-roof-edge: #8c8e95;           /* light edge: the roofs catch the light of the streets */
  --map-roof-text: #eceae4;
  --map-text-dark: #2b2d31;
  --map-ground-image: url("../img/boden-nacht.svg");
  --sun-rgb: 190, 205, 240;           /* cool moonlight on the walls that face the moon (west) */
  --sun-strength: 0.12;
}

.map-scroll.mood-nacht .map-moon,
.map-scroll.mood-nacht .map-stars {
  opacity: 1;
}

/* the lit windows (.map-wall::before) */
.map-scroll.mood-nacht .map-wall::before {
  opacity: 1;
}

/* The street lamps light the bottom of every facade; Quadrate with a category colour glow more. */
.map-scroll.mood-nacht .map-wall::after {
  opacity: 0.4;
}

.map-scroll.mood-nacht .map-block.is-tinted .map-wall::after {
  opacity: 0.6;
}

/* Category colours: a little stronger, so they still stand out on the warm streets. */
.map-scroll.mood-nacht .map-block.is-tinted .map-wall,
.map-scroll.mood-nacht .map-block.is-tinted .map-roof-surface {
  filter: saturate(1.35);
}

/* Names of the open squares: dark text with a light halo, like by day, on the lit squares. */
.map-scroll.mood-nacht .map-sign-text {
  text-shadow: 0 0 2px #e9dcc0, 0 0 2px #e9dcc0, 0 0 3px #e9dcc0, 0 0 4px #e9dcc0;
}

/* Trees a little darker (a darker picture of the same tree); the Schloss and the Wasserturm are floodlit. */
.map-scroll.mood-nacht .map-tree {
  background-image: url("../img/karte/baum-nacht.svg");   /* already darker: no filter needed (faster) */
}

.map-scroll.mood-nacht .map-palace {
  --block-wall: #8a7a62;
}

.map-scroll.mood-nacht .map-palace-roof {
  filter: brightness(0.6);
}

.map-scroll.mood-nacht .map-landmark {
  filter: drop-shadow(0 0 6px rgba(255, 210, 140, 0.8));
}

/* --- soft change of the mood (0.9 s), Version 6 (js/karte.js, stimmung() and fadeOut()) ---
   Version 4 did this with the View Transitions API: the browser took a picture of the map and faded it out over the
   new map. The look was soft, but for the moment of the fade some browsers drew the map without its tilt (it stood
   upright for a short moment). Version 6 does the same by hand: karte.js copies the frame of the map with everything
   in it (cloneNode), still in the old mood, lays the copy exactly over the map (div.map-ghost), switches the map
   itself to the new mood at once and lets the copy fade out. The copy is an ordinary 3D map like the real one, so it
   keeps its tilt. It does not react to the mouse or the keyboard (pointer-events: none, inert in karte.js).
   Only opacity changes: the browser blends the finished picture on the graphics card. */
.map-scroll.map-ghost {
  position: absolute;
  top: 0;
  z-index: 1;                         /* over the live map; the profile (z-index 10) stays above it */
  pointer-events: none;
  will-change: opacity;
  animation: map-ghost-fade var(--mood-duration) var(--mood-easing) forwards;
}

@keyframes map-ghost-fade {
  from {
    opacity: 1;
  }
  to {
    opacity: 0;
  }
}

/* ---------- less motion ---------- */

/* People who switch off animations in their system get the same states without the movement. */
@media (prefers-reduced-motion: reduce) {
  .map-root *,
  .map-root *::before,
  .map-root *::after {
    transition-duration: 0.01ms !important;
  }
}

