/* Paleta w zmiennych, obie wersje zdefiniowane wprost — motyw ciemny nie może
   zależeć od tego, że coś "odziedziczy" tło. Ta sama zasada, co w theme.py. */
:root {
  --plan: #f4f2ee;   --panel: #fbfaf8;  --rule: #d8d3ca;  --hair: #ebe7e0;
  --ink900: #26221d; --ink700: #55504a; --ink500: #8b857c;
  --track: #34302a;  --accent: #2f7d4f; --red: #b03a2e;   --grid: #e6e1d8;
}
@media (prefers-color-scheme: dark) {
  :root {
    --plan: #1c1a17; --panel: #232019; --rule: #3d3830;  --hair: #2c2822;
    --ink900: #f0ece4; --ink700: #b8b1a6; --ink500: #857f75;
    --track: #e7e2d8; --accent: #6cc08a; --red: #e0705f; --grid: #262320;
  }
}

* { box-sizing: border-box; }
html, body { height: 100%; margin: 0; }
body {
  display: flex; flex-direction: column;
  font: 13px/1.45 -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif;
  color: var(--ink900); background: var(--panel);
}

header, footer {
  display: flex; align-items: center; gap: 12px;
  padding: 8px 14px; background: var(--panel); border-bottom: 1px solid var(--rule);
}
/* NAGŁÓWEK Z PASKIEM MENU: niższy i ciaśniejszy niż dawny rząd przycisków —
   menu ma wyglądać jak w programie, nie jak pasek narzędzi strony. */
header { padding: 0 10px 0 4px; gap: 8px; min-height: 36px; }
/* STOPKA NIE MOŻE ROSNĄĆ. `body` jest kolumną flex, więc długi komunikat
   zawijał się na kilkanaście wierszy, rozpychał stopkę i ZGNIATAŁ PLAN DO ZERA
   — z planszy znikało wszystko. Zgłoszone dwa razy, przy przycisku poprawki,
   który wypisywał w jednej linii wszystkie znalezione wady.
   Stopka ma odtąd stałą wysokość, a komunikat ucina się wielokropkiem. */
footer {
  border-bottom: 0; border-top: 1px solid var(--rule); color: var(--ink700);
  flex: 0 0 auto; min-height: 0; overflow: hidden;
}
#status {
  min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.grow { flex: 1; }

button.ghost {
  font: inherit; padding: 4px 12px; border-radius: 6px;
  border: 1px solid var(--rule); background: transparent; color: var(--ink900);
  cursor: pointer;
}
button:disabled { opacity: .45; cursor: default; }

/* Nazwa makiety siedzi w nagłówku obok obu przycisków wysyłki, bo dotyczy
   jednego i drugiego: pod nią plik trafi do EEP i pod nią się pobierze. */
#naming { display: flex; gap: 8px; align-items: center; color: var(--ink700); }
#sizing { display: flex; gap: 5px; align-items: center; color: var(--ink700); }
#sizing input {
  /* 8ch, bo „1000" plus strzałki pola liczbowego nie mieściły się w 6ch
     i nagłówek pokazywał „10C" × „60C". */
  font: inherit; width: 8ch; padding: 4px 6px; border-radius: 6px;
  border: 1px solid var(--rule); background: var(--plan); color: var(--ink900);
}
#naming input {
  font: inherit; width: 12ch; padding: 4px 8px; border-radius: 6px;
  border: 1px solid var(--rule); background: var(--plan); color: var(--ink900);
}

/* PASEK KOMUNIKATÓW UNOSI SIĘ NAD PLANEM. Dopóki był zwykłym elementem
   układu, jego pojawienie się spychało w dół plan i panel boczny, płótno
   zmieniało wysokość, a wraz z nim wszystkie przeliczenia pikseli — cała
   strona podskakiwała. Teraz nie zajmuje miejsca nikomu. */
#warn {
  position: absolute; left: 0; right: 0; top: 0; z-index: 8;
  padding: 8px 14px; background: color-mix(in srgb, var(--red) 12%, var(--panel));
  border-bottom: 1px solid var(--red); color: var(--ink900);
}

main { flex: 1; display: flex; min-height: 0; }

#plan { position: relative; flex: 1; background: var(--plan); overflow: hidden; }
#drawingControls {
  position: absolute; z-index: 4; bottom: 42px; left: 12px; right: 12px;
  display: flex; flex-wrap: wrap; align-items: center; gap: 8px;
  width: fit-content; max-width: calc(100% - 24px); padding: 8px 10px;
  border: 1px solid var(--rule); border-radius: 10px; background: var(--panel);
  box-shadow: 0 4px 14px rgba(0, 0, 0, .18);
}
#drawingControls[hidden] { display: none; }
/* Teren leży NAJNIŻEJ w rysunku planu i nie łapie myszy. */
#ground image { pointer-events: none; }
#canvas { width: 100%; height: 100%; display: block; cursor: grab; touch-action: none; }
/* NIEBO pod przezroczystym płótnem 3D: błękit u góry, mgiełka przy
   horyzoncie w barwie mgły powietrza (`BARWA_HORYZONTU` w widok3d.js). */
#widok3d { position: absolute; inset: 0; z-index: 6;
  background: linear-gradient(to bottom, #6f9fd2 0%, #a9c6e3 40%, #dde6ea 72%, #dde6ea 100%); }
#widok3d[hidden] { display: none; }
/* KURSOR W PODGLĄDZIE 3D JAK NA PLANIE, według narzędzia: Wskaźnik to
   strzałka zaznaczania, rysowanie i pędzel — krzyżyk, moduł i usuwanie jak
   na planie (`#canvas.module`, `#canvas.delete`). Zgłoszone: „cały czas mam
   łapkę w widoku 3D, a nie kursor zaznaczenia" — łapka była wszędzie, bo
   lewy przycisk obracał widok, a nad obiektem wisiała druga dłoń (pointer).
   To, co jest pod strzałką, pokazuje podświetlenie; strzałka przesuwania
   wisi tylko nad tym, co da się przeciągnąć, a zaciśnięta dłoń — w trakcie
   obracania widoku albo ciągnięcia obiektu. */
#widok3d canvas { width: 100%; height: 100%; display: block; cursor: default; }
#widok3d canvas.przesuwalny { cursor: move; }
.kamera-odtwarzana { fill: #d08b2c; stroke: #fff; stroke-width: 2; }
.kamera-odtwarzana-kierunek { fill: none; stroke: #d08b2c; stroke-width: 3; stroke-linecap: round; }
.kamera-plan { pointer-events: none; }
.kamera-plan[data-selected="true"] { pointer-events: auto; }
.kamera-plan circle { fill: #5a6b7a; stroke: #fff; stroke-width: 2; }
.kamera-plan path { fill: none; stroke: #5a6b7a; stroke-width: 3; stroke-linecap: round; }
.kamera-plan .kamera-cel { fill: #e77c32; stroke: #fff; stroke-width: 2; cursor: move; }
.kamera-plan .kamera-cel-linia { stroke: #e77c32; stroke-width: 1.5; stroke-dasharray: 5 4; }
#kameraUstawienia small { grid-column: 1 / -1; color: var(--ink700); }
body[data-tryb="draw"] #widok3d canvas, body[data-tryb="terrain"] #widok3d canvas { cursor: crosshair; }
body[data-tryb="module"] #widok3d canvas { cursor: copy; }
body[data-tryb="delete"] #widok3d canvas { cursor: not-allowed; }
html body #widok3d canvas.obraca, html body #widok3d canvas.ciagnie { cursor: grabbing; }
#flora { position: absolute; inset: 0; width: 100%; height: 100%;
  pointer-events: none; z-index: 1; }
#canvas { position: relative; z-index: 2; }
/* Legenda planu: co znaczy który kształt. Czyta się ją raz. Stoi OBOK
   przycisku dopasowania widoku (#fitView: 14 px od prawej krawędzi, 30 px
   szerokości, dalej 10 px odstępu), nie na nim — przy wodzie na makiecie
   zasłaniała go w całości. */
#legend { position: absolute; right: 54px; bottom: 12px; z-index: 3;
  display: flex; flex-wrap: wrap; gap: 4px 12px; max-width: 62%;
  justify-content: flex-end; padding: 6px 10px; border-radius: 8px;
  background: color-mix(in srgb, var(--panel) 88%, transparent);
  border: 1px solid var(--hair); color: var(--ink700); font-size: 11px; }
#legend[hidden] { display: none; }
#legend span { display: inline-flex; align-items: center; gap: 4px; white-space: nowrap; }
#legend i { width: 10px; height: 10px; border-radius: 50%; display: inline-block; }

/* KSZTAŁT MÓWI, CZYM RZECZ JEST. Zgłoszone: „pokazywać lepiej elementy, aby
   wiadomo było, czym są" — wszystko było szarym kwadracikiem 5 px. */
#items .dom { fill: #8d7a63; stroke: #5d4f3d; stroke-width: 1; opacity: .9; }
#items .peron { fill: #9aa0a6; stroke: #6b7075; stroke-width: 1; opacity: .9; }
#items .woda { fill: #4d8fb5; opacity: .45; }
#items .rozjazd { fill: none; stroke: #7a5c2e; stroke-width: 1.5; opacity: .95; }
#items .portal { fill: #6f6f6f; stroke: #3f3f3f; stroke-width: 1; }
#items .most { fill: #5a6b7a; stroke: #2f3a44; stroke-width: 1.2; opacity: .9; }
#items .filar { fill: #3f4a55; stroke: #1f262c; stroke-width: 1; }
#items .latarnia { stroke: #c9a227; stroke-width: 1.6; fill: #c9a227; }
#items .maszt { stroke: #4f7a8a; stroke-width: 1.6; fill: #4f7a8a; }
#items .znak, #items .sygnal { fill: #b2542a; }
#items .koziol { fill: #a03a3a; }
#items .plot { stroke: #7b8a6a; stroke-width: 2; fill: none; }
#items .inne { fill: var(--ink500); opacity: .55; }
#items .wybrany { fill: var(--accent); stroke: var(--accent); opacity: 1; }

#scale { position: absolute; left: 14px; bottom: 12px; z-index: 3; color: var(--ink500); }

/* Dopasowanie widoku: przy podziałce, bo obie rzeczy mówią o tym samym —
   o tym, na co się właśnie patrzy. */
#fitView {
  position: absolute; right: 14px; bottom: 12px; width: 30px; height: 30px;
  font-size: 15px; line-height: 1; padding: 0; cursor: pointer;
  border-radius: 8px; border: 1px solid var(--rule);
  background: var(--panel); color: var(--ink900);
}
#fitView:hover { background: var(--accent); border-color: var(--accent);
  color: var(--plan); }

/* ---- biblioteka makiet ---------------------------------------------------
   Leży NA planie i ma własne przewijanie: makiet bywa kilkadziesiąt, a lista
   nie ma prawa rozpychać strony. */
#library, #history {
  position: absolute; right: 14px; top: 14px; bottom: 14px; width: 380px;
  z-index: 5; display: flex; flex-direction: column; border-radius: 10px;
  background: var(--panel); border: 1px solid var(--rule);
  box-shadow: 0 10px 30px rgba(0, 0, 0, .28);
}
#library[hidden], #history[hidden] { display: none; }
#library > header, #history > header {
  display: flex; gap: 8px; align-items: center; padding: 10px 12px;
  border-bottom: 1px solid var(--rule);
}
#library > header strong, #history > header strong { flex: 0 0 auto; }
#history > header strong { flex: 1; }
#filter {
  font: inherit; flex: 1; min-width: 0; padding: 4px 8px; border-radius: 6px;
  border: 1px solid var(--rule); background: var(--plan); color: var(--ink900);
}
#layouts, #saved { list-style: none; margin: 0; padding: 6px; overflow-y: auto; flex: 1; }
#layouts li, #saved li {
  padding: 7px 9px; border-radius: 7px; cursor: pointer; line-height: 1.35;
}
#layouts li:hover, #saved li:hover { background: color-mix(in srgb, var(--accent) 12%, var(--panel)); }
#layouts li .why, #saved li .why { color: var(--ink500); font-size: .88em; }
/* MOJE MAKIETY: otwarta jest wyróżniona, a kosz stoi z prawej i nie otwiera
   wiersza — usunięcie pyta, otwarcie nie. */
#saved li { display: flex; align-items: center; gap: 8px; }
#saved li > div { flex: 1; min-width: 0; }
#saved li.current { background: color-mix(in srgb, var(--accent) 22%, var(--panel)); font-weight: 600; }
#saved li.current .why { font-weight: 400; }
#saved li .drop { flex: 0 0 auto; padding: 2px 8px; }
#saved li.blocked { cursor: default; opacity: .62; }
#saved li.blocked:hover { background: transparent; }
/* Makieta, której nie otworzymy, zostaje NA LIŚCIE z powodem — „nie ma jej"
   i „jest, ale ma kształty spoza modelu" to dwie różne wiadomości. */
#layouts li.blocked { cursor: default; opacity: .62; }
#layouts li.blocked:hover { background: transparent; }

/* IMPORT Z MAPY: ta sama karta co biblioteka, tylko szersza — w środku jest
   mapa do celowania ramką i musi być na niej co oglądać. */
#mapa {
  position: absolute; right: 14px; top: 14px; bottom: 14px; width: 520px;
  z-index: 5; display: flex; flex-direction: column; border-radius: 10px;
  background: var(--panel); border: 1px solid var(--rule);
  box-shadow: 0 10px 30px rgba(0, 0, 0, .28);
}
#mapa[hidden] { display: none; }
#mapa > header {
  display: flex; gap: 8px; align-items: center; padding: 10px 12px;
  border-bottom: 1px solid var(--rule);
}
#mapa > header strong { flex: 0 0 auto; }
#mapQuery {
  font: inherit; flex: 1; min-width: 0; padding: 4px 8px; border-radius: 6px;
  border: 1px solid var(--rule); background: var(--plan); color: var(--ink900);
}
/* Lista adresów wyrasta tylko wtedy, gdy jest z czego wybierać — mapa pod nią
   nie może się przez to kurczyć do zera. */
#mapPlaces { list-style: none; margin: 0; padding: 0 6px; overflow-y: auto;
             flex: 0 0 auto; max-height: 180px; }
#mapPlaces li { padding: 6px 9px; border-radius: 7px; cursor: pointer;
                line-height: 1.3; font-size: .92em; }
#mapPlaces li:hover { background: color-mix(in srgb, var(--accent) 12%, var(--panel)); }
#mapCanvas { flex: 1; min-height: 240px; background: var(--plan); }
#mapCanvas.rysowanie { cursor: crosshair; }
#mapDraw.armed { outline: 2px solid var(--accent); }
#mapRatio { color: var(--ink500); font-size: .9em; }
#mapa > footer {
  display: flex; gap: 12px; align-items: center; padding: 10px 12px;
  border-top: 1px solid var(--rule); flex-wrap: wrap;
}
#mapa > footer label { display: flex; gap: 6px; align-items: center; }
#mapa > footer input[type=number] {
  font: inherit; width: 5.2em; padding: 3px 6px; border-radius: 6px;
  border: 1px solid var(--rule); background: var(--plan); color: var(--ink900);
}
#mapa > footer select {
  font: inherit; padding: 3px 6px; border-radius: 6px;
  border: 1px solid var(--rule); background: var(--plan); color: var(--ink900);
}
#mapa > footer #mapGo { margin-left: auto; }

/* Tory: kreska rysowana w układzie świata, więc grubość skalujemy odwrotnie
   do przybliżenia (vector-effect), żeby przy oddaleniu nie znikała. */
#tracks path, #switches circle { vector-effect: non-scaling-stroke; }
#tracks path { fill: none; stroke: var(--track); stroke-width: 2.5; stroke-linecap: round; }
/* TOR JAK TOR po przybliżeniu (`rysujPodtorze`): podsypka, podkłady, szyny,
   jezdnia z osią. Grubości przychodzą w pikselach z JS — liczone z metrów.
   Kreska osi toru z `#tracks` znika wtedy pod spodem, a jej stany (najazd,
   zaznaczenie, wada) kładą się na torze półprzezroczystym pasem szerokości
   podsypki. */
#podtorze path { fill: none; stroke-linecap: butt; stroke-linejoin: round; pointer-events: none; }
#podtorze path.podsypka { stroke: #b3aa9c; }
#podtorze path.bruk { stroke: #9c9a96; }
#podtorze path.podklady { stroke: #6e5139; }
#podtorze path.szyna { stroke: #454a51; }
#podtorze path.jezdnia { stroke: #6d7076; stroke-linecap: round; }
#podtorze path.rzeka { stroke: #4d8fb5; stroke-opacity: 0.85; stroke-linecap: round; stroke-linejoin: round; }
#podtorze path.rzeka.lod { stroke: #c9dde8; }
#tracks path.rzeka { stroke: #4d8fb5; stroke-opacity: 0.85; stroke-linecap: round; stroke-linejoin: round; }
#tracks path.rzeka.lod { stroke: #c9dde8; }
#tracks path.szlak { stroke: #2f6f99; stroke-dasharray: 6 5; stroke-opacity: 0.9; }
#podtorze path.os-jezdni { stroke: #f2f0ea; }
#podtorze path.chodnik { stroke: #c8c2b6; }
#podtorze path.kraweznik { stroke: #eeeae1; }
#podtorze polygon.latka-jezdni { fill: #6d7076; stroke: none; pointer-events: none; }
#canvas.tor-szczegolowy #tracks path { stroke: transparent; stroke-width: var(--szer-podsypki); }
#canvas.tor-szczegolowy #tracks path.inne { stroke: #9a8f7a; stroke-width: 2; }
#canvas.tor-szczegolowy #tracks path.hover,
#canvas.tor-szczegolowy #tracks path.wskazany { stroke: var(--accent); opacity: .35; }
#canvas.tor-szczegolowy #tracks path.picked { stroke: var(--accent); opacity: .5; }
#canvas.tor-szczegolowy #tracks path.faulty { stroke: var(--red); opacity: .55; }
#canvas.tor-szczegolowy #tracks path.warned { stroke: #c9861f; opacity: .5; }

/* ---- bloki statyczne ------------------------------------------------------
   Tory o kształtach, których jeszcze nie modelujemy (przejściowe, sześcienne,
   śrubowe). Widoczne, żeby otwarta makieta nie wyglądała na dziurawą, i
   wyraźnie inne, żeby nie brać ich za tor do edycji. Przerywana kreska tam,
   gdzie kształt jest tylko przybliżony. */
#statics path { fill: none; stroke: var(--ink500); stroke-width: 2;
  stroke-linecap: round; vector-effect: non-scaling-stroke; opacity: .7; }
#statics path.rough { stroke-dasharray: 6 5; }
/* Reszta makiety, każde swoją barwą — żeby na pierwszy rzut oka było widać,
   co jest koleją do edycji, a co jeszcze nie. */
#statics path.droga   { stroke: #8a8f98; stroke-width: 3; opacity: .5; }
#statics path.tramwaj { stroke: #7f9bb5; stroke-width: 1.8; opacity: .6; }
#statics path.inne    { stroke: #9a8f7a; stroke-width: 1.6; opacity: .45; }
#statics path.wybrany { stroke: var(--accent); stroke-width: 4; opacity: 1; }

/* ---- obiekty makiety: budynki, mosty, drzewa, latarnie -------------------
   Kwadracik w miejscu, gdzie obiekt stoi. Nie da się ich jeszcze edytować,
   ale da się zobaczyć i zaznaczyć — a to pierwsze, czego się od planu chce. */
#items rect { fill: var(--ink500); opacity: .5; }
#items rect.wybrany { fill: var(--accent); opacity: 1; }
/* POJAZDY: kreska o długości składu wzdłuż toru — pociąg ciemny i gruby,
   samochód drobny, tramwaj pomiędzy. Grubość w pikselach, długość w świecie. */
/* Skład: kreska albo łamana po torze (`points`), zawsze bez wypełnienia. */
#items .pojazd { stroke: #3b3f46; stroke-width: 6; stroke-linecap: butt; stroke-linejoin: round;
                 fill: none; opacity: .85; }
#items .pojazd.s3 { stroke: #b2542a; stroke-width: 4; }
#items .pojazd.s2 { stroke: #4d6f93; stroke-width: 4; }
#items .pojazd.naped { stroke: #b03a2e; }          /* lokomotywa, zespół trakcyjny */
#items .pojazd.s4 { stroke: #f4f1ea; stroke-width: 7; }   /* statek na wodzie */
#items .pojazd.wybrany { stroke: var(--accent); opacity: 1; }
/* Wybór rodzaju i klocka: wciśnięta ikona wygląda jak wciśnięty tryb. */
#panels .segment button[aria-pressed="true"], #turnouts3d[aria-pressed="true"] {
  background: color-mix(in srgb, var(--accent) 18%, var(--panel));
  outline: 1px solid var(--accent);
}
/* Tory niekolejowe: rysowane tym samym narzędziem, ale w pliku trafiają do
   innego `Gleissystem` i z koleją się nie łączą — więc i wyglądać mają
   inaczej. Te same barwy co elementy wczytane z pliku. */
#tracks path.droga   { stroke: #8a8f98; stroke-width: 3.5; }
/* DROGI GŁÓWNE I POBOCZNE: jak na mapie — przelotowa gruba i ciemna, ulica
   osiedlowa zwykła, polna cienka i blada. Klasa bierze się ze STYLU jezdni,
   więc działa tak samo dla importu z mapy, generatora i rysowania ręcznego. */
#tracks path.droga.glowna { stroke: #6f747c; stroke-width: 5; }
#tracks path.droga.boczna { stroke: #a6abb2; stroke-width: 2.4; }
#tracks path.tramwaj { stroke: #7f9bb5; stroke-width: 2.2; }
#tracks path.inne    { stroke: #9a8f7a; stroke-width: 2; }

#tracks path.hover { stroke: var(--accent); stroke-width: 4; }
/* NAJAZD NA WIERSZ SPISU — ta sama barwa co najazd na planie, ale cieńsza:
   to podpowiedź „to jest ta trasa", a nie zaznaczenie. */
#tracks path.wskazany { stroke: var(--accent); stroke-width: 3.5; opacity: .9; }
#tracks path.picked { stroke: var(--accent); stroke-width: 4.5; }
#tracks path.faulty { stroke: var(--red); stroke-width: 5; stroke-dasharray: 9 6; }
/* OSTRZEŻENIE TO NIE BŁĄD. Czerwień zostaje dla tego, czego EEP nie zbuduje;
   prześwit poniżej normy da się zostawić, więc dostaje bursztyn i cieńszą
   kreskę. Zgłoszone: „niektóre tory połączone są na czerwono". */
#tracks path.warned { stroke: #c9861f; stroke-width: 4; stroke-dasharray: 6 5; }
#switches circle.halo { fill: var(--plan); }
#switches circle.dot { fill: var(--accent); }

/* SPIS MAKIETY TO KARTA NA PLANIE, jak „Moje makiety", a nie kolumna obok.
   Kolumna zabierała planowi 320 px i zwężała go przy każdym otwarciu — co
   w 3D znaczyło przebudowę całej sceny tylko po to, żeby pokazać listę.
   Zgłoszone: „nie potrzebuję mieć sidebara po prawej stronie". Stoi pod
   paskiem narzędzi (`--narzedzia-h` podaje strona) i nad przyciskami
   ⤢ / 3D w prawym dolnym rogu. Ustawienia zaznaczonego elementu są
   w dymku (`#dymek` niżej), więc spis ma już tylko jedno przewijanie. */
#spis {
  position: absolute; z-index: 7; right: 14px; width: 340px;
  top: calc(12px + var(--warn-h, 0px) + var(--narzedzia-h, 44px) + 8px);
  bottom: 100px;
  display: flex; flex-direction: column; min-height: 0; overflow: hidden;
  background: var(--panel); border: 1px solid var(--rule); border-radius: 10px;
  box-shadow: 0 10px 30px rgba(0, 0, 0, .28);
}
/* `display:flex` autora wygrywa z `[hidden]` przeglądarki — dawny przełącznik
   „Panel boczny" gasił znacznik w menu, a kolumna zostawała na miejscu. */
#spis[hidden] { display: none; }
.bok-glowka { flex: none; padding: 12px 14px 8px; }
.naglowek-spisu { display: flex; align-items: center; gap: 8px; margin: 0 0 6px; }
#spis h2 { flex: 1; font-size: 11px; letter-spacing: .08em; text-transform: uppercase;
  color: var(--ink500); margin: 0; }
button.zamknij {
  font: inherit; font-size: 16px; line-height: 1; border: 0; cursor: pointer;
  background: transparent; color: var(--ink500); padding: 2px 7px;
  border-radius: 5px; flex: none;
}
button.zamknij:hover { color: var(--ink900); background: var(--hair); }
/* STAN MAKIETY: liczby, do których wraca się co chwilę, więc czytelniejsze
   od podpisu sekcji, ale nie krzyczące. */
.stan { margin: 0 0 8px; color: var(--ink700); font-variant-numeric: tabular-nums; }
.stan .wady {
  color: var(--red); white-space: nowrap;
}
.hint { color: var(--ink500); margin: 0 0 12px; }
.hint .klawisz {
  display: inline-block; padding: 0 4px; border-radius: 4px;
  background: var(--hair); color: var(--ink700);
}
/* JEDNA LINIJKA ZAMIAST PIĘCIU. Instrukcja czytana raz zostawała na zawsze
   i zjadała pierwszy ekran panelu. */
.hint.jednolinijkowy { margin: 0 0 8px; font-size: 12px; line-height: 1.4; }

/* SZUKAJKA: przy dwudziestu pozycjach szybciej wpisać „most" niż przewijać. */
.szukajka {
  display: flex; align-items: center; gap: 6px; padding: 4px 8px;
  border: 1px solid var(--rule); border-radius: 8px; background: var(--plan);
}
.szukajka:focus-within { border-color: var(--accent); }
.szukajka .lupa { font-size: 11px; opacity: .6; }
.szukajka input {
  flex: 1; min-width: 0; font: inherit; border: 0; background: transparent;
  color: var(--ink900); outline: none; padding: 2px 0;
}
.szukajka input::-webkit-search-cancel-button { cursor: pointer; }

/* ---- SPIS MAKIETY -------------------------------------------------------
   Sekcje o stałej kolejności, w nich wiersze. Ramka wokół każdego wiersza
   robiła z panelu kratę; zostaje sam odstęp, a zaznaczenie i najechanie
   niesie tło. */
#stack {
  flex: 1 1 auto; min-height: 90px; overflow-y: auto;
  display: flex; flex-direction: column; gap: 2px; padding: 0 14px 12px;
}
#stack .pusto { margin: 8px 0 0; }

.sekcja { border-top: 1px solid var(--hair); }
.sekcja:first-child { border-top: 0; }
.sekcja > .naglowek {
  display: flex; align-items: center; gap: 8px; width: 100%;
  padding: 9px 6px 7px; margin: 0; border: 0; background: transparent;
  font: inherit; color: var(--ink500); cursor: pointer; text-align: left;
}
.sekcja > .naglowek:hover { color: var(--ink900); }
.sekcja > .naglowek .strzalka { font-size: 10px; width: 10px; transition: transform .12s; }
.sekcja.zwinieta > .naglowek .strzalka { transform: rotate(-90deg); }
.sekcja > .naglowek .tytul {
  flex: 1; font-size: 11px; letter-spacing: .08em; text-transform: uppercase;
}
.sekcja > .naglowek .licznik {
  font-size: 11px; padding: 1px 7px; border-radius: 9px;
  background: var(--hair); color: var(--ink500);
}
.sekcja.zwinieta .pozycje { display: none; }

.pozycje { list-style: none; margin: 0 0 8px; padding: 0;
  display: flex; flex-direction: column; gap: 1px; }
.pozycje li {
  display: flex; align-items: center; gap: 8px; padding: 4px 6px;
  border: 1px solid transparent; border-radius: 8px; cursor: pointer;
}
.pozycje li:hover { background: var(--hair); }
/* NAJAZD Z PLANU: kursor nad torem zapala jego wiersz w spisie, i odwrotnie.
   Dotąd jedyną drogą było kliknięcie, czyli zmiana zaznaczenia. */
.pozycje li.wskazany { background: var(--hair); box-shadow: inset 2px 0 0 var(--accent); }
.pozycje li[aria-selected="true"] { border-color: var(--accent);
  background: color-mix(in srgb, var(--accent) 12%, transparent); }
.pozycje li.off { opacity: .45; }
.pozycje li.off .name { text-decoration: line-through; }
.pozycje li .ikona {
  flex: 0 0 22px; width: 22px; height: 22px; border-radius: 6px;
  display: flex; align-items: center; justify-content: center;
  background: var(--hair); font-size: 12px; line-height: 1;
}
.pozycje li .name { flex: 1; min-width: 0; line-height: 1.35; }
.pozycje li .ile { color: var(--ink500); font-variant-numeric: tabular-nums; }
.pozycje li .sub { display: block; color: var(--ink500); font-size: .9em;
  line-height: 1.3;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* LICZBA POZYCJI DO PRAWEJ, cyframi tej samej szerokości — kolumna długości
   czyta się wtedy z góry na dół, a nie zdanie po zdaniu. */
.pozycje li .miara {
  flex: none; color: var(--ink500); font-variant-numeric: tabular-nums;
  font-size: .92em; white-space: nowrap;
}
.pozycje li .note { display: block; color: var(--red); font-size: .92em; }

/* AKCJE WIDAĆ ZAWSZE, tylko blado. Chowanie ich do najechania jest wygodne
   dla oka i niewidzialne dla kogoś, kto pierwszy raz szuka, jak coś usunąć —
   a na ekranie dotykowym nie ma czym najechać. */
.pozycje li .akcje { display: flex; gap: 2px; opacity: .38; }
.pozycje li:hover .akcje,
.pozycje li[aria-selected="true"] .akcje,
.pozycje li .akcje:focus-within { opacity: 1; }
#stack button.sekcjaOko { opacity: .55; }
.sekcja > .naglowek:hover button.sekcjaOko { opacity: 1; }
#stack li button, #stack button.sekcjaOko {
  font: inherit; border: 0; background: transparent; cursor: pointer;
  color: var(--ink500); padding: 2px 5px; border-radius: 5px; line-height: 1;
}
#stack li button:hover, #stack button.sekcjaOko:hover {
  color: var(--ink900); background: var(--panel);
  box-shadow: inset 0 0 0 1px var(--rule);
}

/* ---- pasek narzędzi na planie ------------------------------------------- */
/* Narzędzia schodzą paskowi z drogi — o tyle, ile naprawdę zajął. Wysokość
   podaje strona, bo komunikat bywa dwuwierszowy. Płynnie, żeby ruch był
   widoczny jako ustąpienie miejsca, a nie jako skok. */
/* ---- PASEK NARZĘDZI NAD PLANEM ------------------------------------------
   JEDNA KARTA, DWA WIERSZE: u góry narzędzia, pod spodem parametry tego, co
   wybrane. Trzy strefy paska mają TRZY RÓŻNE WYGLĄDY, bo robią trzy różne
   rzeczy — dawniej tryb pracy, otwieracz panelu i akcja natychmiastowa
   wyglądały identycznie i potrafiły zapalić się we dwa naraz.

   * tryb            — pełne, zielone wypełnienie (`aria-pressed`)
   * otwieracz panelu — sama obwódka i daszek (`aria-expanded`)
   * akcja            — bez stanu; „Wyczyść" czerwienieje przy najechaniu */
#tools {
  /* NAD WARSTWAMI PLANU: płótno roślin (`#flora`, z-index 1) i SVG (2)
     leżą pod paskiem, inaczej drzewa rysują się na przyciskach.
     NAD PODGLĄDEM 3D TEŻ (`#widok3d` ma z-index 6): pędzel działa również
     w widoku z boku, a schowany pasek znaczyłby, że nie da się w nim
     zmienić rodzaju pędzla ani promienia. */
  position: absolute; z-index: 7;
  left: 12px; right: 12px; top: calc(12px + var(--warn-h, 0px));
  transition: top .12s ease-out;
  display: flex; flex-direction: column; align-items: stretch;
  pointer-events: none;                  /* plan pod paskiem zostaje klikalny */
}
#toolbar, #panels {
  pointer-events: auto;
  display: flex; flex-wrap: wrap; align-items: center; gap: 6px;
  padding: 6px 8px; border-radius: 10px;
  background: var(--panel); border: 1px solid var(--rule);
  box-shadow: 0 4px 14px rgba(0, 0, 0, .18);
}
/* PASEK I JEGO PARAMETRY TO JEDNA RZECZ, więc i jedna karta: przy otwartym
   panelu górny wiersz traci dolne zaokrąglenie i szew między nimi znika. */
#tools:has(#panels:not([hidden])) #toolbar {
  border-radius: 10px 10px 0 0; border-bottom-color: var(--hair);
  box-shadow: 0 4px 14px rgba(0, 0, 0, .10);
}
#tools:has(#panels:not([hidden])) #panels {
  border-radius: 0 0 10px 10px; border-top: 0;
}
#panels[hidden] { display: none; }
#panels .panel[hidden] { display: none; }
#panels .panel { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; }
#panels .pod[hidden] { display: none; }
/* `hidden` MUSI WYGRAĆ z `display: inline-flex`. Segment z jedną możliwością
   chowa się atrybutem i bez tego dalej był widoczny. */
#panels .segment[hidden], #panels .grupa[hidden] { display: none; }
#panels .pod {
  display: flex; flex-wrap: wrap; align-items: center; gap: 10px;
}

/* STREFY PASKA. Cienka kreska między nimi mówi „to inna rodzina rzeczy" —
   bez niej dwanaście przycisków czytało się jako jeden ciąg. */
.strefa { display: inline-flex; align-items: center; gap: 2px; }
.strefa + .strefa {
  margin-left: 5px; padding-left: 9px; border-left: 1px solid var(--hair);
}

#toolbar .tool {
  display: inline-flex; align-items: center; gap: 7px; white-space: nowrap;
  font: inherit; height: 32px; padding: 0 10px;
  border-radius: 8px; border: 1px solid transparent; background: transparent;
  color: var(--ink900); cursor: pointer;
}
#toolbar .tool svg { display: block; flex: none; }
#toolbar .tool .daszek { font-size: 10px; color: var(--ink500); margin-left: -2px; }
#toolbar .tool:hover { background: var(--hair); }
/* TRYB PRACY — jeden na raz, więc jako jedyny dostaje pełny kolor. */
#toolbar .tool[aria-pressed="true"] {
  background: var(--accent); border-color: var(--accent); color: var(--plan);
}
#toolbar .tool[aria-pressed="true"] .daszek { color: var(--plan); }
/* PANEL OTWARTY — to nie tryb, więc i nie wygląda jak tryb. */
#toolbar .tool[aria-expanded="true"] {
  background: color-mix(in srgb, var(--accent) 14%, var(--panel));
  border-color: var(--accent); color: var(--ink900);
}
#toolbar .tool[aria-expanded="true"] .daszek { color: var(--accent); }
/* AKCJA, KTÓREJ NIE DA SIĘ COFNĄĆ JEDNYM KLIKNIĘCIEM, ma to po sobie widać. */
#toolbar .tool.grozny:hover {
  color: var(--red); background: color-mix(in srgb, var(--red) 12%, var(--panel));
  border-color: color-mix(in srgb, var(--red) 45%, var(--panel));
}

/* WIDOCZNY FOCUS. Pasek obsługuje się też z klawiatury (strzałki), a bez
   obwódki nie było widać, gdzie się stoi. */
#toolbar .tool:focus-visible, #panels button:focus-visible,
#panels select:focus-visible, #panels input:focus-visible,
#naming input:focus-visible {
  outline: 2px solid var(--accent); outline-offset: 2px;
}

/* NAZWA KONTEKSTU. Pierwsza rzecz w wierszu parametrów mówi, CZYJE to
   ustawienia — bez tego pasek pod spodem wisiał w powietrzu. */
#panels .ctx {
  font-size: 11px; font-weight: 600; letter-spacing: .08em;
  text-transform: uppercase; color: var(--ink500);
  padding-right: 8px; border-right: 1px solid var(--hair); align-self: stretch;
  display: inline-flex; align-items: center;
}

/* GRUPA = TYTUŁ PLUS TO, CO OPISUJE, w jednym kawałku. Dawniej podpis
   „Klimat" zawijał się do innego wiersza niż jego przyciski. */
#panels .grupa {
  display: inline-flex; align-items: center; gap: 6px; color: var(--ink700);
}
/* TYTUŁ GRUPY jest podpisem, nie kolejnym przyciskiem — mniejszy i bledszy,
   żeby wzrok wpadał najpierw na to, co się klika. */
#panels .grupa .tytul {
  color: var(--ink500); white-space: nowrap; font-size: 12px;
}
#panels .grupa.check { gap: 5px; }
#panels label { display: inline-flex; gap: 6px; align-items: center; color: var(--ink700); }
#panels output { color: var(--ink900); min-width: 46px; }
#panels select, #panels input[type="number"] {
  font: inherit; background: transparent; color: var(--ink900);
  border: 1px solid var(--rule); border-radius: 6px; padding: 3px 6px;
}
#panels input[type="number"] { width: 82px; }
#panels input[type="range"] { width: 120px; }
#panels button {
  font: inherit; padding: 4px 10px; border-radius: 7px;
  border: 1px solid var(--rule); background: transparent; color: var(--ink900);
  cursor: pointer; white-space: nowrap;
}
#panels button:hover { background: var(--hair); }
#panels button.primary {
  background: var(--accent); border-color: var(--accent); color: var(--plan);
}
#panels button.primary:hover { filter: brightness(1.1); background: var(--accent); }

/* Pierwszy pusty plan pokazuje trzy drogi startu w miejscu, w którym
   użytkownik patrzy na makietę. Karta znika po pierwszej operacji. */
.first-step {
  position: absolute; z-index: 5;
  left: 50%; top: 52%; transform: translate(-50%, -50%);
  width: min(410px, calc(100% - 32px)); padding: 22px;
  border: 1px solid var(--rule); border-radius: 16px;
  background: var(--panel); box-shadow: 0 20px 60px rgba(0, 0, 0, .2);
}
.first-step[hidden] { display: none; }
.first-step-eyebrow {
  color: var(--accent); font-size: 11px; font-weight: 700;
  letter-spacing: .1em;
}
.first-step h2 { margin: 5px 32px 5px 0; font-size: 21px; line-height: 1.2; }
.first-step p { margin: 0 0 16px; color: var(--ink700); }
.first-step-close {
  position: absolute; right: 14px; top: 12px; width: 30px; height: 30px;
  border: 0; border-radius: 7px; background: transparent;
  color: var(--ink700); font: inherit; font-size: 23px; cursor: pointer;
}
.first-step-close:hover { background: var(--hair); }
.first-step-actions { display: grid; gap: 8px; }
.first-step-actions button {
  display: flex; align-items: center; gap: 12px; width: 100%;
  padding: 11px 12px; text-align: left; font: inherit;
  color: var(--ink900); background: var(--plan);
  border: 1px solid var(--rule); border-radius: 10px; cursor: pointer;
}
.first-step-actions button:hover {
  border-color: var(--accent); background: color-mix(in srgb, var(--accent) 9%, var(--plan));
}
.first-step-actions button:first-child { border-color: var(--accent); }
.first-step-actions strong, .first-step-actions small { display: block; }
.first-step-actions small { margin-top: 2px; color: var(--ink700); font-size: 11px; }
.first-step-icon { width: 24px; flex: none; text-align: center; font-size: 20px; }
.first-step button:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
body.tryb-kafelki .first-step,
#plan:has(#library:not([hidden])) .first-step,
#plan:has(#history:not([hidden])) .first-step,
#plan:has(#mapa:not([hidden])) .first-step { display: none; }
@media (max-width: 560px) {
  .first-step {
    left: 12px; right: 12px; top: auto; bottom: 12px; transform: none;
    width: auto; max-height: calc(100% - 105px); overflow: auto; padding: 16px;
  }
}

/* SEGMENT — wybór jednego z kilku, jak przełącznik zakresów. Wspólne korytko
   pokazuje, że te przyciski wykluczają się nawzajem; osobno stojące, obwiedzione
   kwadraciki wyglądały jak osobne polecenia. */
#panels .segment {
  display: inline-flex; flex-wrap: wrap; gap: 2px; padding: 2px;
  border-radius: 9px; background: var(--hair);
}
#panels .segment button {
  border-color: transparent; background: transparent; border-radius: 7px;
  padding: 3px 9px;
}
#panels .segment button:hover { background: var(--panel); }

/* PANEL Z PODPISAMI. Akcje jednorazowe — dołożenie równoległej, zieleni,
   infrastruktury — czyta się tu SŁOWEM, a nie po ikonce: 🚉 🚏 🚋 stojące
   obok siebie w pasku były nie do rozróżnienia bez najechania. Ikona zostaje
   z przodu jako znak rozpoznawczy, nie jako jedyna treść. */
#panels .labelled { gap: 10px; }
#panels .labelled button { display: inline-flex; align-items: center; gap: 7px; }

.hintline { color: var(--ink700); font-size: 12px; }

/* PASEK NIE MA PRAWA ZŁAMAĆ SIĘ NA DWA WIERSZE — to on mówi, w jakim się jest
   trybie, a złamany zjada plan i skacze przy każdej zmianie narzędzia. Progu
   nie da się wpisać na sztywno, bo podpisy różnią się długością między językami.
   Szerokość MIERZY więc strona (`dopasujPasek`) i po kolei zdejmuje podpisy:
   najpierw trybom (zostaje ikona i podpowiedź ze skrótem), potem wszystkim. */
#toolbar { flex-wrap: nowrap; overflow: hidden; }
#toolbar.waski .tool:not(.rozwija) .etykieta { display: none; }
#toolbar.waski .tool:not(.rozwija) { padding: 0 8px; }
#toolbar.bardzo-waski .tool .etykieta { display: none; }
#toolbar.bardzo-waski .tool { padding: 0 8px; }

/* NAZWA NIE JEST TYM, CO USTĘPUJE PIERWSZE — a dokładnie to robiła.
   `flex: 0 1 auto` z `min-width: 0` znaczyło, że przy ciasnocie kurczy się
   TYLKO ona: przyciski mają `white-space: nowrap`, więc nie mają jak. Pasek
   nigdy więc nie wystawał, a `dopasujPasek` czeka właśnie na wystawanie —
   podpisy zostawały, a pole cichu znikało. Zmierzone w Chrome przy 1120 px:
   pole zjechało z 207 do 143 px, a „Generuj", „Modele" i „Ustawienia" wciąż
   miały podpisy; przy 820 px zostało z niego 11 px i obcięte „N”. Zgłoszone:
   „pole z nazwą makiety chowa się przy braku miejsca, a powinno być zawsze
   widoczne, a ikony powinny się zmienić na wersje bez treści".

   Teraz nic w pasku nie kurczy się samo. Pasek naprawdę wystaje, strona to
   widzi i po kolei zdejmuje podpisy — a nazwa ustępuje OSTATNIA, i tylko
   do ośmiu znaków. */
/* NARZĘDZIA SĄ TYM, CO USTĘPUJE — jedyny elastyczny element paska. Gdy
   zabraknie miejsca, kurczy się i obcina od prawej właśnie ten pojemnik,
   a `#naming` obok stoi nieruszone. Odwrotnie niż dotąd, kiedy jedynym,
   co mogło ustąpić, było pole nazwy. */
#narzedzia {
  display: flex; align-items: center; gap: 6px;
  flex: 1 1 auto; min-width: 0; overflow: hidden;
}
#naming { flex: none; }
#toolbar.ciasno #naming .etykieta { display: none; }
#toolbar.ciasno #naming input { width: 8ch; }
/* Na tym samym stopniu ściska się WSZYSTKO, co da się ścisnąć bez straty:
   odstępy między strefami, przerwy paska i wyściółka przycisków. Same ikony
   plus pole nazwy to przy 820 px wciąż było o 70 px za dużo, a tyle właśnie
   tu leży — dziesięć przycisków po 4 px i dwie kreski stref. Poniżej tej
   granicy nie ma już czego oddać: wtedy ustępują NARZĘDZIA, nie nazwa. */
#toolbar.ciasno { gap: 4px; }
#toolbar.ciasno .strefa + .strefa { margin-left: 3px; padding-left: 5px; }
#toolbar.ciasno .tool { padding: 0 6px; }

/* ---- ustawienia pędzla (prawy przycisk) ---------------------------------
   Suwaki z widoczną wartością, jak przy wyborze pędzla w programach
   graficznych. Panel staje tam, gdzie kliknięto. */
/* Rodzaje pędzla mają PODPISY i wspólne korytko segmentu — patrz `.segment`.
   Siedem kwadracików 38 px z samą ikoną (⛰ ⛏ 〰 ▬ 🛤 💧 🌲) czytało się
   wyłącznie po najechaniu, a przy siódmym i tak nikt nie pamiętał pierwszego. */

/* Pędzel terenu: widać zasięg, ZANIM się kliknie. */
#snap circle.brush-obrys { fill: none; stroke: rgba(15, 15, 15, .6); stroke-width: 5.5;
  vector-effect: non-scaling-stroke; }
#snap circle.brush { fill: rgba(255, 164, 28, .14); stroke: #ffa41c; stroke-width: 2.5;
  vector-effect: non-scaling-stroke; }
#snap circle.brush.lower { fill: rgba(56, 182, 255, .14); stroke: #38b6ff; }
#snap circle.brush:not(.raise):not(.lower) { fill: rgba(255, 255, 255, .14); stroke: #ffffff; }
#snap circle.brush-srodek { fill: #ffa41c; stroke: rgba(15, 15, 15, .6); stroke-width: 1.5;
  vector-effect: non-scaling-stroke; }
#snap circle.brush-srodek.lower { fill: #38b6ff; }
#snap circle.brush-srodek:not(.raise):not(.lower) { fill: #ffffff; }
/* Ślad pędzla drzew do chwili, aż silnik je posadzi — patrz `drawSladDrzew`. */
#snap .slad-drzew { opacity: .35; pointer-events: none; }
/* Barwa z grupy (`fill` klimatu) — ogólne `#snap circle` ma `fill: none`. */
#snap .slad-drzew circle { fill: inherit; stroke: none; }

/* ---- menu przy torze pod kursorem ---------------------------------------
   Zwykły element DOM, a nie rysunek na płótnie — dzięki temu najechanie NA
   MENU trzyma je otwarte samo z siebie. W poprzednim edytorze plakietka
   jechała za myszą i uciekała spod kursora, który do niej zmierzał. */
/* ---- podgląd prowadzonego toru ------------------------------------------
   Kreskowany, bo pokazuje coś, czego JESZCZE NIE MA. Linia ciągła
   obiecywałaby, że tor już stoi. */
#preview path { fill: none; stroke: var(--accent); stroke-width: 3;
  stroke-dasharray: 7 5; stroke-linecap: round; vector-effect: non-scaling-stroke; }
#preview path.joins { stroke-dasharray: none; stroke-width: 4; }
/* Celowanie w miejsce, w które toru poprowadzić się nie da. Cieńsze i gęściej
   kreskowane niż podgląd — bo to nie jest tor, tylko kierunek patrzenia. */
#preview path.blocked { stroke: var(--red); stroke-width: 2; stroke-dasharray: 4 4; }
#preview circle { fill: var(--accent); }

#canvas.draw { cursor: crosshair; }
#canvas.delete { cursor: not-allowed; }

button.primary {
  background: var(--accent); border: 1px solid var(--accent); color: var(--plan);
  font: inherit; padding: 4px 14px; border-radius: 6px; cursor: pointer;
}

/* ---- PANEL USTAWIEŃ ZAZNACZONEGO ELEMENTU ---------------------------------
   Zgłoszone: „każdy zaznaczony element powinien otwierać tooltip z ustawieniami",
   potem: „okna nie podążające za obiektem, tylko stałe z boku, widoczne, gdy
   obiekt jest aktywny". Karta jak „Moje makiety", przypięta do prawej krawędzi
   wolnego obszaru planu. Położenie daje strona przez `transform` (`ustawDymek`
   w app.js) — `left/top` zostają zerem. Z-index jak pasek narzędzi: nad
   podglądem 3D (6), pod podpowiedzią paska (8). */
#dymek {
  position: absolute; left: 0; top: 0; z-index: 7; width: 340px;
  max-height: calc(100% - 120px);
  display: flex; flex-direction: column; min-height: 0;
  background: var(--panel); border: 1px solid var(--rule); border-radius: 10px;
  box-shadow: 0 10px 30px rgba(0, 0, 0, .28);
}
#dymek[hidden] { display: none; }
/* Awaryjnie całość się przewija, gdy okno jest bardzo niskie. */
#dymek { overflow-y: auto; overscroll-behavior: contain; }
/* GŁÓWKA: co to jest i z której pozycji stosu — bez tego zmiana gęstości
   „przy jednym drzewie" przestawiała las i nikt nie wiedział czemu. */
.glowka-dymka {
  flex: none; display: flex; align-items: flex-start; gap: 9px;
  padding: 10px 10px 8px 12px;
}
.glowka-dymka .ikona {
  flex: 0 0 26px; width: 26px; height: 26px; border-radius: 7px;
  display: flex; align-items: center; justify-content: center;
  background: var(--hair); font-size: 14px; line-height: 1;
}
.glowka-dymka .teksty { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.glowka-dymka strong { font-size: 13px; color: var(--ink900); font-weight: 600;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
#dymekSkad { color: var(--ink500); font-size: 12px; line-height: 1.35; }
/* UWAGA: czego dotyczy zmiana (cała pozycja, wszystkie składy, cały film)
   i czerwona wada pozycji. Każde zdanie w swoim wierszu. */
#dymekUwaga { flex: none; padding: 0 12px 8px; font-size: 12px; line-height: 1.4;
  color: var(--ink700); }
#dymekUwaga[hidden] { display: none; }
#dymekUwaga > span { display: block; }
#dymekUwaga > span + span { margin-top: 3px; }
#dymekUwaga .note { color: var(--red); }
#dymekUwaga .kandydaci { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 5px; }
/* STOPKA: kamera zaznaczonego elementu i akcje pozycji. */
.stopka-dymka {
  flex: none; display: flex; flex-direction: column; align-items: stretch; gap: 8px;
  padding: 8px 10px 10px 12px; border-top: 1px solid var(--hair);
}
.stopka-dymka:not(:has(#dymekAkcje > *)):not(:has(#ujecieElementu:not([hidden]))) { display: none; }
#ujecieElementu[hidden] { display: none; }
.tworzenie-kamery {
  display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 6px;
  align-items: center; width: 100%;
}
.tworzenie-kamery label {
  grid-column: 1 / -1; font-size: 11px; font-weight: 700;
  color: var(--ink700);
}
.tworzenie-kamery select, .tworzenie-kamery button {
  min-width: 0; min-height: 32px; box-sizing: border-box; border-radius: 7px;
  font: inherit; font-size: 12px;
}
.tworzenie-kamery select {
  width: 100%; padding: 5px 8px; color: var(--ink900);
  border: 1px solid var(--rule); background: var(--panel);
}
.tworzenie-kamery button {
  padding: 5px 10px; border: 1px solid var(--track);
  background: var(--track); color: var(--panel); cursor: pointer;
}
.tworzenie-kamery button:disabled { opacity: .55; cursor: default; }
#dymekAkcje { display: flex; flex-wrap: wrap; gap: 6px; }
#dymekAkcje button, #dymekUwaga .kandydaci button {
  font: inherit; font-size: 12px; padding: 3px 9px; border-radius: 6px; cursor: pointer;
  border: 1px solid var(--rule); background: transparent; color: var(--ink900);
}
#dymekAkcje button:hover, #dymekUwaga .kandydaci button:hover { background: var(--hair); }
#dymekAkcje button.usun:hover { border-color: var(--red); color: var(--red); }
/* INSPEKTOR KAMERY: trzy zwarte grupy, a wspólne pola i suwaki używają
   tych samych wymiarów oraz kolorów co ustawienia pozostałych elementów. */
.kamera-wybor {
  display: grid; gap: 5px; padding: 10px 12px 8px;
  color: var(--ink700); font-size: 12px; font-weight: 600;
}
.kamera-wybor[hidden] { display: none; }
.kamera-wybor select {
  width: 100%; min-width: 0; height: 34px; padding: 5px 8px;
  border: 1px solid var(--rule); border-radius: 7px;
  background: var(--panel); color: var(--ink900); font: inherit;
}
.kamera-wybor select:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
#kameraUstawienia {
  flex: none; display: flex; flex-direction: column; gap: 8px;
  padding: 10px 12px 12px; border-top: 1px solid var(--hair);
}
#kameraUstawienia[hidden] { display: none; }
#kameraUstawienia .kamera-sekcja {
  display: flex; flex-direction: column; gap: 8px; min-width: 0;
  padding: 10px; border: 1px solid var(--rule); border-radius: 9px;
  background: color-mix(in srgb, var(--plan) 52%, var(--panel));
}
#kameraUstawienia .kamera-sekcja[hidden] { display: none; }
.kamera-cel-ustawienie { display: grid; gap: 5px; }
.kamera-cel-ustawienie[hidden] { display: none; }
.kamera-cel-ustawienie button {
  width: 100%; padding: 7px 10px; border: 1px solid var(--rule);
  border-radius: 7px; background: var(--panel); color: var(--ink900);
  font: inherit; font-size: 12px; cursor: pointer;
}
.kamera-cel-ustawienie button:hover, .kamera-cel-ustawienie button.aktywny {
  border-color: var(--accent); color: var(--accent);
  background: color-mix(in srgb, var(--accent) 9%, var(--panel));
}
.kamera-cel-ustawienie small { color: var(--ink500); font-size: 11px; }
#kameraUstawienia .kamera-sekcja h3 {
  margin: 0 0 1px; color: var(--ink500); font-size: 10px;
  font-weight: 700; letter-spacing: .08em; text-transform: uppercase;
}
#kameraUstawienia .kamera-wiersz {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(100px, 42%);
  gap: 8px; align-items: center; min-width: 0; color: var(--ink700);
  font-size: 12px;
}
#kameraUstawienia .kamera-wiersz[hidden] { display: none; }
#kameraUstawienia .kamera-suwak[hidden] { display: none; }
#kameraUstawienia .kamera-suwak { display: grid; grid-template-columns: 1fr; gap: 2px; min-width: 0; }
#kameraUstawienia .kamera-suwak > span {
  display: flex; justify-content: space-between; align-items: center;
  color: var(--ink700); font-size: 12px;
}
#kameraUstawienia .kamera-suwak output {
  color: var(--ink500); font-size: 11px; font-variant-numeric: tabular-nums;
}
#kameraUstawienia .kamera-liczba {
  display: flex; align-items: center; justify-content: flex-end; gap: 6px; min-width: 0;
}
#kameraUstawienia .kamera-parametr-lotu > span { gap: 8px; }
#kameraUstawienia .kamera-parametr-lotu .kamera-liczba input {
  width: 72px; min-width: 0; padding: 3px 6px; text-align: right;
  font-variant-numeric: tabular-nums;
}
#kameraUstawienia .kamera-parametr-lotu input[type="range"] {
  width: 100%; margin: 0; cursor: ew-resize; touch-action: pan-y;
}
#kameraUstawienia .kamera-liczba i { min-width: 12px; color: var(--ink500); font-size: 11px; font-style: normal; }
#kameraUstawienia input:disabled, #kameraUstawienia select:disabled { opacity: .52; }
#kameraUstawienia input[type="range"]:disabled { cursor: default; }
#kameraUstawienia #kameraCelPodpowiedz {
  display: block; margin: -3px 0 2px; padding-left: 8px;
  border-left: 2px solid var(--accent); color: var(--ink500);
  font-size: 11px; line-height: 1.4;
}
#kameraUstawienia #kameraCelPodpowiedz[hidden] { display: none; }
#kameraUstawienia .kamera-check input { accent-color: var(--accent); }
#kameraUstawienia .kamera-check output { min-width: 26px; text-align: right; }
/* KADR Z KAMERY nad suwakami: szerokość dymka, proporcje 16:9. */
/* Wysokość od okna, szerokość z proporcji — w niskim oknie kadr maleje,
   a suwaki i akcje zostają w dymku (dymek miał wystające przyciski). */
#kadrKamery { flex: none; display: block; align-self: center;
  height: min(178px, 26vh); width: auto; max-width: calc(100% - 24px);
  aspect-ratio: 16 / 9; margin: 0 12px 8px; border-radius: 6px;
  border: 1px solid var(--rule); background: #a9c6e3; }
#kadrKamery[hidden] { display: none; }
#kameraAkcje {
  display: flex; flex-wrap: wrap; gap: 7px;
  padding: 0 12px 11px;
}
#kameraAkcje[hidden] { display: none; }
#kameraAkcje button {
  flex: 1 1 calc(50% - 4px); min-width: 0; min-height: 36px;
  padding: 7px 10px; border: 1px solid var(--rule); border-radius: 8px;
  background: var(--panel); color: var(--ink900);
  font: inherit; font-size: 12px; font-weight: 600; cursor: pointer;
  transition: background .15s, border-color .15s;
}
#kameraAkcje button:hover { background: var(--hair); }
#kameraAkcje button:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
#kameraAkcje button.odtworz {
  flex-basis: 100%; border-color: var(--accent); background: var(--accent);
  color: white;
}
#kameraAkcje button.odtworz:hover { filter: brightness(.94); }
#kameraAkcje button.usun { color: var(--red); }
#kameraAkcje button.usun:hover {
  border-color: var(--red); background: color-mix(in srgb, var(--red) 9%, var(--panel));
}
/* ---- pola ustawień pozycji (tryb zaawansowany z §8) ----------------------
   Te same pola, co w dawnym inspektorze pod spisem, teraz w dymku. Przewija
   się tylko ta część — główka i akcje zostają na miejscu. */
#params {
  flex: 0 1 auto; min-height: 0; overflow-y: auto; overscroll-behavior: contain;
  padding: 10px 12px 4px; border-top: 1px solid var(--hair);
}
#params[hidden] { display: none; }
/* POLE USTAWIENIA: ikona, nazwa, wartość z jednostką, pod spodem suwak.
   Zgłoszone: „sekcje parametrów elementu także dostosuj, aby było ładniej,
   może suwaki, grafiki, ikonki". Rząd „nazwa — pole" nie mówił, w jakim
   zakresie liczba ma sens; suwak pokazuje to bez czytania. */
#params .num { display: flex; align-items: center; gap: 8px; margin-bottom: 6px; }
#params .num span { flex: 1; color: var(--ink700); }
#params .pole { margin-bottom: 10px; }
#params .glowka {
  display: flex; align-items: center; gap: 8px; margin-bottom: 4px;
  color: var(--ink700);
}
#params .glowka .ikona {
  flex: 0 0 22px; width: 22px; height: 22px; border-radius: 6px;
  display: flex; align-items: center; justify-content: center;
  background: var(--hair); font-size: 12px; line-height: 1;
}
#params .glowka .tytul { flex: 1; min-width: 0; }
#params .wartosc { display: flex; align-items: baseline; gap: 4px; }
#params .wartosc .jednostka { color: var(--ink500); font-size: .9em; }
#params input:not(.suwak), #params select,
#kameraUstawienia input[type="number"], #kameraUstawienia select {
  font: inherit; min-width: 0; height: 30px; padding: 4px 8px;
  border-radius: 7px; border: 1px solid var(--rule);
  background: var(--panel); color: var(--ink900);
  box-shadow: inset 0 1px 1px color-mix(in srgb, var(--ink900) 4%, transparent);
}
#params input:not(.suwak), #params select { width: 108px; }
#kameraUstawienia input[type="number"] { width: 100%; text-align: right;
  font-variant-numeric: tabular-nums; }
#kameraUstawienia select { width: 100%; }
#params input:not(.suwak):focus-visible, #params select:focus-visible,
#kameraUstawienia input:focus-visible, #kameraUstawienia select:focus-visible {
  outline: 2px solid var(--accent); outline-offset: 1px;
}
#params input.liczba { width: 66px; text-align: right;
  font-variant-numeric: tabular-nums; }
#params .pole.ziarno input.liczba { width: 84px; }
#params button.kostka {
  font: inherit; border: 0; background: transparent; cursor: pointer;
  color: var(--ink500); padding: 2px 6px; border-radius: 5px; line-height: 1;
}
#params button.kostka:hover { color: var(--ink900); background: var(--hair); }

/* SUWAK: cienki tor, wyraźny uchwyt. Zmienia liczbę w trakcie ciągnięcia,
   a makietę dopiero po puszczeniu — patrz `field()`. */
#params input.suwak, #kameraUstawienia input[type="range"] {
  -webkit-appearance: none; appearance: none; width: 100%; height: 18px;
  padding: 0; border: 0; background: transparent; cursor: pointer; accent-color: var(--accent);
}
#params input.suwak::-webkit-slider-runnable-track,
#kameraUstawienia input[type="range"]::-webkit-slider-runnable-track {
  height: 4px; border-radius: 3px; background: var(--hair);
}
#params input.suwak::-moz-range-track,
#kameraUstawienia input[type="range"]::-moz-range-track {
  height: 4px; border-radius: 3px; background: var(--hair);
}
#params input.suwak::-webkit-slider-thumb,
#kameraUstawienia input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none; margin-top: -5px;
  width: 14px; height: 14px; border-radius: 50%;
  background: var(--accent); border: 2px solid var(--panel);
  box-shadow: 0 0 0 1px var(--rule);
}
#params input.suwak::-moz-range-thumb,
#kameraUstawienia input[type="range"]::-moz-range-thumb {
  width: 14px; height: 14px; border-radius: 50%; border: 2px solid var(--panel);
  background: var(--accent); box-shadow: 0 0 0 1px var(--rule);
}
#params input.suwak:focus-visible, #kameraUstawienia input[type="range"]:focus-visible {
  outline: 2px solid var(--accent); outline-offset: 3px;
}

/* PIGUŁKI zamiast listy rozwijanej: do czterech możliwości widać naraz. */
#params .pigulki { display: flex; gap: 4px; flex-wrap: wrap; }
#params .pigulka {
  font: inherit; display: flex; align-items: center; gap: 5px;
  padding: 4px 10px; border-radius: 999px; cursor: pointer;
  border: 1px solid var(--rule); background: transparent; color: var(--ink700);
}
#params .pigulka:hover { background: var(--hair); color: var(--ink900); }
#params .pigulka.wybrana {
  border-color: var(--accent); color: var(--ink900);
  background: color-mix(in srgb, var(--accent) 16%, transparent);
}
#params .pigulka .znak { font-size: .95em; }

/* `display:flex` autora wygrywa z `[hidden]{display:none}` przeglądarki —
   pasek wad świecił pustym czerwonym paskiem nad planem, a wiersz gatunku
   nie dawał się schować. Każdy element z własnym `display` musi mieć to. */
#warn[hidden], #panels label[hidden] { display: none; }
/* Przyciski paska też są `display:flex` — schowany przycisk (flaga
   `LINIE_ROWNOLEGLE`) zostawał widoczny na produkcji. */
#tools button[hidden] { display: none; }
#warn { display: flex; align-items: center; gap: 12px; }
#warn button {
  font: inherit; padding: 3px 12px; border-radius: 6px; cursor: pointer;
  border: 1px solid var(--red); background: transparent; color: var(--ink900);
}
#warn button:hover { background: var(--red); color: var(--plan); }
.pozycje li.broken { border-color: var(--red); }

/* ---- magnes: gdzie zacznie się tor ---------------------------------------
   Widać go, ZANIM klikniesz, i leży dokładnie na osi toru. Kreska pokazuje
   stronę, w którą odejdzie odgałęzienie — bo to miejsce kursora względem osi
   o niej decyduje. */
#snap circle { fill: none; stroke: var(--accent); stroke-width: 2;
  vector-effect: non-scaling-stroke; }
#snap path.tick { stroke: var(--accent); stroke-width: 2; fill: none;
  vector-effect: non-scaling-stroke; }

/* ---- gdzie wepnie się ciągnięty koniec -----------------------------------
   Pełna obwódka jest OBIETNICĄ: puszczenie tutaj naprawdę zepnie tory, bo
   silnik wpięcie wykonał na próbę i przeszło. Przerywana czerwona mówi, że
   akurat w tym miejscu się nie da — powód idzie na pasek stanu. Bez tego
   odmowa niczym nie różniła się od upuszczenia w pustym polu. */
/* Wolny koniec pod kursorem: stąd tor przedłuża się BEZ zwrotnicy. Grubsza
   obwódka niż magnes na osi, bo to inne miejsce startu i inny skutek. */
#snap circle.start { fill: none; stroke: var(--accent); stroke-width: 3.5;
  vector-effect: non-scaling-stroke; }

#snap circle.join { fill: none; stroke: var(--accent); stroke-width: 3;
  vector-effect: non-scaling-stroke; }
#snap circle.join.no { stroke: var(--red); stroke-width: 2.5;
  stroke-dasharray: 5 4; }
#canvas.module { cursor: copy; }

/* Tory nie łapią wskaźnika: który tor jest pod kursorem, rozstrzyga
   `nearestTrack()` po współrzędnych. Kreska ma 2,5 px, więc trafianie w nią
   przez SVG wymagało celowania co do piksela. */
#tracks path, #switches circle, #preview path, #snap * { pointer-events: none; }

/* Kółko myszy przesuwa plan; lewy przycisk należy do rysowania. */
#canvas { cursor: crosshair; }
#canvas.panning { cursor: grabbing; }
#canvas.select, #canvas.terrain { cursor: default; }
#canvas.select { cursor: default; }

/* Wolny koniec toru: stąd przedłuża się BEZ zwrotnicy i to je łączy się ze
   sobą. Pusty krążek, żeby nie mylił się z pełną kropką zwrotnicy. */
#switches circle.loose { fill: var(--plan); stroke: var(--accent); stroke-width: 2;
  vector-effect: non-scaling-stroke; }

/* Ostrzeżenie, nie awaria: makieta zadziała, tylko wygląda nierealistycznie.
   Ta sama belka, spokojniejsza barwa — czerwień zostaje dla rzeczy, które
   naprawdę nie pojadą. */
#warn.note { background: color-mix(in srgb, var(--accent) 12%, var(--panel));
  border-bottom-color: var(--accent); }
#warn.note button { border-color: var(--accent); }
#warn.note button:hover { background: var(--accent); color: var(--plan); }

/* Uchwyt: punkt zaznaczonego toru, który da się chwycić i pociągnąć.
   Wypełniony, żeby odróżniał się od pustego krążka wolnego końca. */
#handles circle.handle { fill: var(--panel); stroke: var(--accent); stroke-width: 2.5;
  pointer-events: none; }

/* Zaczep odróżnia się od wierzchołka: jedzie tylko wzdłuż swojego toru. */
#handles circle.handle.anchor { fill: var(--accent); stroke: var(--plan); }

/* Uchwyt pod kursorem: większy i wypełniony akcentem, żeby było widać, co da
   się chwycić, zanim się chwyci. */
#handles circle.handle.hot { fill: var(--accent); stroke: var(--plan); stroke-width: 2; }

/* RAMIĘ ZAOKRĄGLENIA DROGI. Kreska sięga dokładnie tam, gdzie zaczyna się łuk,
   więc pokazuje, ile drogi zjada zakręt; kwadracik na jej końcu da się chwycić
   i wyciągnąć. Cieńsza i bledsza od samej drogi, żeby nie udawała jezdni. */
#handles line.arm { stroke: var(--accent); stroke-width: 1.5; stroke-dasharray: 5 4;
  opacity: 0.75; pointer-events: none; }
#handles line.arm.hot { opacity: 1; stroke-width: 2; stroke-dasharray: none; }
#handles rect.arm-grip { fill: var(--panel); stroke: var(--accent); stroke-width: 2;
  pointer-events: none; }
#handles rect.arm-grip.hot { fill: var(--accent); stroke: var(--plan); }

/* Ramię na PROSTEJ: zakrętu jeszcze nie ma, więc ramię jest zapasem na później
   — bledsze, żeby nikt nie wypatrywał łuku, którego nie ma. Chwycić się daje
   tak samo. */
#handles line.arm.idle { opacity: 0.35; }
#handles rect.arm-grip.idle { opacity: 0.55; }
#handles line.arm.idle.hot, #handles rect.arm-grip.idle.hot { opacity: 1; }
#canvas.grab { cursor: grab; }
#canvas.grab:active { cursor: grabbing; }

/* GRUPA GENERATORÓW. Trzy przyciski, które robią to samo dla różnych warstw
   makiety, mają wyglądać jak jedno narzędzie z trzema wyjściami — inaczej
   giną wśród kilkunastu innych i nie widać, że każdy działa NIEZALEŻNIE. */
.group {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 2px 6px 2px 8px; border: 1px solid var(--rule); border-radius: 8px;
}
.groupName { color: var(--ink700); font-size: 12px; }
.group select { font: inherit; }

/* ---- PODPOWIEDŹ POD KURSOREM -------------------------------------------
   `title` przeglądarki pokazuje się dopiero po około sekundzie. Przy pasku
   złożonym z samych ikon to sekunda zgadywania przy każdym przycisku, więc
   rysujemy własną — natychmiast. */
#tip {
  position: absolute; z-index: 8; max-width: 320px; padding: 6px 9px;
  border-radius: 7px; pointer-events: none;
  background: var(--ink900); color: var(--panel);
  font-size: 12px; line-height: 1.35;
  box-shadow: 0 6px 18px rgba(0, 0, 0, .3);
}
/* SKRÓT KLAWISZOWY W PODPOWIEDZI — jak klawisz na klawiaturze, żeby dało się
   go odróżnić od zdania obok. */
#tip .skrot {
  display: inline-block; margin-left: 2px; padding: 0 5px;
  border-radius: 4px; border: 1px solid var(--ink500);
  font-size: 11px; font-weight: 600; line-height: 16px;
}
#tip[hidden] { display: none; }


/* ============================================================ licencja */
/* `display: flex` przebija arkusz przeglądarki dla `[hidden]`, więc bez tej
   reguły nakładka NIE ZNIKA po zalogowaniu — „cały czas Sprawdzam…", choć
   logowanie przeszło (zmierzone: znaczek w nagłówku już pokazywał pakiet). */
.naklada[hidden] { display: none; }
.naklada {
  position: fixed; inset: 0; z-index: 50;
  display: flex; align-items: center; justify-content: center;
  background: rgba(20, 24, 32, 0.72); backdrop-filter: blur(3px);
}
.naklada form {
  background: #fff; color: #222; border-radius: 12px; padding: 24px 28px;
  width: min(440px, 92vw); box-shadow: 0 18px 50px rgba(0,0,0,0.35);
  display: flex; flex-direction: column; gap: 12px;
}
.naklada h2 { margin: 0; font-size: 20px; }
.naklada p { margin: 0; font-size: 13px; line-height: 1.45; color: #555; }
.naklada code { font-family: ui-monospace, Menlo, monospace; }
.naklada input {
  font: 18px/1.3 ui-monospace, Menlo, monospace; letter-spacing: 1px;
  text-transform: uppercase; padding: 10px 12px; border: 1px solid #bbb;
  border-radius: 8px; text-align: center;
}
.naklada .blad { color: #b3261e; min-height: 1.2em; }
.naklada .blad:empty { display: none; }
#licencjaZnaczek { font-variant-numeric: tabular-nums; }
#licencjaZnaczek.pusto { color: #b3261e; border-color: #b3261e; }


/* ============================================================ pasek menu */
#menu { display: flex; align-items: stretch; align-self: stretch; user-select: none; }
#menu .menu { position: relative; display: flex; }
#menu .menu > button {
  font: inherit; border: 0; background: transparent; color: var(--ink900);
  padding: 0 10px; cursor: default; border-radius: 4px; margin: 4px 0;
}
#menu .menu > button:hover, #menu .menu.otwarte > button {
  background: color-mix(in srgb, var(--ink900) 9%, transparent);
}
#menu .menu > button u { text-decoration: underline; text-underline-offset: 2px; }
#menu ul[role="menu"] {
  position: absolute; top: 100%; left: 0; z-index: 40; margin: 0; padding: 4px;
  min-width: 250px; list-style: none;
  background: var(--panel); border: 1px solid var(--rule); border-radius: 6px;
  box-shadow: 0 10px 28px rgba(0, 0, 0, .22);
}
/* Podmenu NIE DZIEDZICZY bieli z podświetlonego rodzica — bez tego pozycje
   w „Język" były białe na jasnym tle (zgłoszone: „teksty są niewidoczne"). */
#menu ul[role="menu"] ul[role="menu"] { top: -5px; left: 100%; color: var(--ink900); }
#menu li { position: relative; }
#menu li[role="separator"] { height: 1px; margin: 4px 8px; background: var(--rule); }
#menu li[role="menuitem"], #menu li[role="menuitemcheckbox"], #menu li[role="menuitemradio"] {
  display: grid; grid-template-columns: 20px 1fr auto; align-items: center; gap: 8px;
  padding: 5px 10px 5px 6px; border-radius: 4px; white-space: nowrap; cursor: default;
}
#menu li[role^="menuitem"]:hover, #menu li[role^="menuitem"].podmenu-otwarte {
  background: var(--accent); color: #fff;
}
#menu li[role^="menuitem"]:hover .skrot { color: inherit; }
#menu li[aria-disabled="true"] { opacity: .45; }
#menu li[aria-disabled="true"]:hover { background: transparent; color: inherit; }
#menu .znak { text-align: center; font-size: 12px; }
#menu .skrot { color: var(--ink500); font-size: 12px; margin-left: 24px; }
#menu .strzalka { color: var(--ink500); }
#menu li:hover > .strzalka { color: inherit; }
#menu li.pusto { color: var(--ink500); font-style: italic; padding: 5px 10px; }

/* Menu PPM ma ten sam język wizualny co pasek menu, ale jest przyklejone do
   punktu planszy, a nie do jego nagłówka. */
.menu-kontekst {
  position: fixed; z-index: 100; user-select: none;
}
.menu-kontekst ul[role="menu"] {
  position: absolute; top: 0; left: 0; margin: 0; padding: 4px;
  min-width: 260px; list-style: none; background: var(--panel);
  border: 1px solid var(--rule); border-radius: 6px;
  box-shadow: 0 10px 28px rgba(0, 0, 0, .22);
}
.menu-kontekst ul[role="menu"] ul[role="menu"] {
  top: -5px; left: 100%; color: var(--ink900);
}
.menu-kontekst li { position: relative; }
.menu-kontekst li[role="separator"] { height: 1px; margin: 4px 8px; background: var(--rule); }
.menu-kontekst li[role^="menuitem"] {
  display: grid; grid-template-columns: 20px 1fr auto; align-items: center;
  gap: 8px; padding: 5px 10px 5px 6px; border-radius: 4px;
  white-space: nowrap; cursor: default;
}
.menu-kontekst li[role^="menuitem"]:hover,
.menu-kontekst li[role^="menuitem"].podmenu-otwarte {
  background: var(--accent); color: #fff;
}
.menu-kontekst li[aria-disabled="true"] { opacity: .45; }
.menu-kontekst .znak { text-align: center; font-size: 12px; }
.menu-kontekst .skrot, .menu-kontekst .strzalka { color: var(--ink500); }
.menu-kontekst li:hover > .strzalka { color: inherit; }

/* ============================================================ dialogi */
dialog {
  border: 1px solid var(--rule); border-radius: 10px; padding: 0;
  background: var(--panel); color: var(--ink900); min-width: 360px; max-width: 560px;
  box-shadow: 0 18px 50px rgba(0, 0, 0, .35);
}
dialog::backdrop { background: rgba(20, 24, 32, .45); }
dialog form { display: flex; flex-direction: column; gap: 12px; padding: 20px 22px; }
dialog h2 { margin: 0; font-size: 17px; }
dialog p { margin: 0; color: var(--ink700); line-height: 1.45; }
dialog .drobne { font-size: 12px; color: var(--ink500); }
dialog menu { display: flex; justify-content: flex-end; gap: 8px; margin: 6px 0 0; padding: 0; }
dialog menu button { font: inherit; padding: 5px 14px; border-radius: 6px; cursor: pointer; }
dialog dl { display: grid; grid-template-columns: auto 1fr; gap: 6px 16px; margin: 0; }
dialog dt { color: var(--ink700); }
dialog dd { margin: 0; font-variant-numeric: tabular-nums; }
dialog table { border-collapse: collapse; }
dialog td { padding: 3px 12px 3px 0; }
dialog td:first-child { font-family: ui-monospace, Menlo, monospace; color: var(--ink700); white-space: nowrap; }

/* ============================================================ flagi języków */
#flagi { display: flex; gap: 2px; }
#flagi button {
  display: flex; align-items: center; padding: 4px 5px; border-radius: 6px;
  border: 1px solid transparent; background: transparent; cursor: pointer; opacity: .55;
}
#flagi svg { width: 21px; height: 14px; border-radius: 2px; box-shadow: 0 0 0 1px rgba(0,0,0,.18); display: block; }
#flagi button:hover { opacity: 1; }
#flagi button[aria-pressed="true"] { opacity: 1; border-color: var(--rule); background: var(--plan); }

/* ============================================================ okno pytań */
#dlgOkno .tresc {
  white-space: pre-wrap; line-height: 1.5; color: var(--ink700);
  max-height: 60vh; overflow: auto; font-size: 13.5px;
}
#dlgOkno .tresc b { color: var(--ink900); }
#dlgOkno menu button.danger {
  background: var(--red); border: 1px solid var(--red); color: #fff;
}
dialog { animation: okno-wejscie .16s ease-out; }
@keyframes okno-wejscie { from { opacity: 0; transform: translateY(6px) scale(.98); } to { opacity: 1; transform: none; } }
dialog::backdrop { backdrop-filter: blur(2px); }
#dlgOkno .tresc p { margin: 0 0 8px; }
#dlgOkno .tresc ul { margin: 0 0 8px; padding: 0; list-style: none; display: flex; flex-direction: column; gap: 6px; }
#dlgOkno .tresc li { padding: 6px 10px 6px 30px; border-radius: 6px; position: relative; background: color-mix(in srgb, var(--ink900) 5%, transparent); }
#dlgOkno .tresc li::before { position: absolute; left: 10px; top: 5px; font-size: 14px; }
#dlgOkno .tresc li.poprawie::before { content: "✓"; color: var(--accent); }
#dlgOkno .tresc li.obejrze::before { content: "👁"; }

/* ============================================================ ekran startowy */
/* CAŁY EKRAN, razem z miejscem nagłówka: przy kafelkach menu edytora nie ma
   czego obsługiwać (zgłoszone: „jak mam listę makiet, to widoczne jest
   menu"). Nagłówek chowa reguła niżej, ekran ma własne logo i flagi. */
.start {
  position: fixed; inset: 0; z-index: 45;
  background: var(--plan); overflow: auto;
}
body.tryb-kafelki header { display: none; }
.start[hidden] { display: none; }
.start-tresc { max-width: 1180px; margin: 0 auto; padding: 28px 32px 48px; }
.start-glowka { display: flex; align-items: center; gap: 8px; margin-bottom: 20px; }
.start-glowka h2 { margin: 0; font-size: 22px; }
.kafelki {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); gap: 18px;
}
.kafelek {
  position: relative; display: flex; flex-direction: column; text-align: left;
  font: inherit; color: var(--ink900); background: var(--panel);
  border: 1px solid var(--rule); border-radius: 12px; padding: 0; overflow: hidden;
  cursor: pointer; transition: transform .12s ease, box-shadow .12s ease;
}
.kafelek:hover { transform: translateY(-2px); box-shadow: 0 10px 26px rgba(0,0,0,.14); }
.kafelek.otwarta { border-color: var(--accent); box-shadow: 0 0 0 2px color-mix(in srgb, var(--accent) 35%, transparent); }
.kafelek .obraz {
  aspect-ratio: 16 / 10; background: color-mix(in srgb, var(--ink900) 6%, var(--plan));
  display: flex; align-items: center; justify-content: center; overflow: hidden;
}
.kafelek .obraz img { width: 100%; height: 100%; object-fit: cover; display: block; }
.kafelek .obraz .puste { font-size: 40px; opacity: .35; }
.kafelek .podpis { padding: 10px 12px 12px; display: flex; flex-direction: column; gap: 3px; }
.kafelek .nazwa { font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.kafelek .kiedy { font-size: 12px; color: var(--ink500); }
.kafelek .drop {
  position: absolute; top: 8px; right: 8px; opacity: .75; font: inherit; font-size: 13px;
  border-radius: 6px; border: 1px solid var(--rule); background: var(--panel); cursor: pointer; padding: 3px 8px;
  box-shadow: 0 1px 4px rgba(0,0,0,.15); transition: opacity .12s, transform .12s;
}
.kafelek:hover .drop, .kafelek:focus-within .drop { opacity: 1; }
.kafelek .drop:hover { transform: scale(1.08); border-color: var(--red); }
.kafelek:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.kafelek.nowa {
  border-style: dashed; justify-content: center; align-items: center; min-height: 190px;
  color: var(--accent); background: transparent; gap: 8px;
}
.kafelek.nowa .plus { font-size: 44px; line-height: 1; }
.kafelek.nowa .nazwa { font-weight: 600; }
.kafelek.nowa .kiedy { color: var(--ink700); text-align: center; }
.kafelek.mapa .obraz { background: #dfe9d3; }
.kafelek.mapa .obraz svg { width: 100%; height: 100%; display: block; }
.kafelek.mapa .nazwa { color: var(--accent); }
/* KLASA NA <body> NAZYWA SIĘ INACZEJ NIŻ SIATKA KAFELKÓW. `body.kafelki`
   łapało regułę `.kafelki { display: grid }` — nagłówek, plan i stopka
   stawały obok siebie w trzech kolumnach, plan miał zerową szerokość,
   skala widoku wychodziła ujemna i po wejściu z kafelków nie było terenu
   (zgłoszone). */
body.tryb-kafelki #naming, body.tryb-kafelki #export, body.tryb-kafelki #download { opacity: .4; pointer-events: none; }
/* DYMEK I SPIS LEŻĄ NA PLANIE, więc schodzą z drogi wszystkiemu, co go
   zakrywa: ekranowi startowemu i kartom bibliotek, historii i mapy. */
body.tryb-kafelki :is(#dymek, #spis) { display: none; }
/* WĄSKI EKRAN (telefon): dymek to arkusz od dołu na całą szerokość, bez
   dzióbka — przy 390 px nie ma obok czego kotwiczyć. Klasę `arkusz` nadaje
   `ustawDymek`, gdy plan ma mniej niż 560 px. Spis też na całą szerokość. */
#dymek.arkusz { left: 16px; right: 16px; bottom: 16px; top: auto; width: auto;
  max-height: 50% !important; transform: none !important; }
#dymek.arkusz .dziob { display: none !important; }
@media (max-width: 560px) { #spis { left: 16px; right: 16px; width: auto; } }
#plan:has(#library:not([hidden])) :is(#dymek, #spis),
#plan:has(#history:not([hidden])) :is(#dymek, #spis),
#plan:has(#mapa:not([hidden])) :is(#dymek, #spis) { display: none; }
.start-glowka { flex-wrap: wrap; }
.start-logo { display: flex; align-items: center; gap: 12px; }
.start-logo svg { width: 56px; height: 30px; }
.start-logo .tytuly { display: flex; flex-direction: column; line-height: 1.15; }
.start-logo .marka { font-size: 12px; letter-spacing: .6px; text-transform: uppercase; color: var(--ink500); }
#startFlagi { display: flex; gap: 2px; margin-right: 8px; }
#startFlagi button { display: flex; align-items: center; padding: 4px 5px; border-radius: 6px; border: 1px solid transparent; background: transparent; cursor: pointer; opacity: .55; }
#startFlagi button:hover { opacity: 1; }
#startFlagi button[aria-pressed="true"] { opacity: 1; border-color: var(--rule); background: var(--panel); }
#startFlagi svg { width: 24px; height: 16px; border-radius: 2px; box-shadow: 0 0 0 1px rgba(0,0,0,.18); display: block; }
/* Przy kafelkach język wybiera się na ekranie startowym — flagi w nagłówku
   byłyby drugim, identycznym przełącznikiem (zgłoszone). */
body.tryb-kafelki #flagi { display: none; }
#startExe { border-color: var(--accent); color: var(--accent); font-weight: 600; }
#dlgOkno .tresc li.punkt::before { content: "•"; color: var(--accent); }
#licencjaFlagi { display: flex; gap: 2px; justify-content: flex-end; margin-bottom: -6px; }
#licencjaFlagi button { display: flex; align-items: center; padding: 4px 5px; border-radius: 6px; border: 1px solid transparent; background: transparent; cursor: pointer; opacity: .55; }
#licencjaFlagi button:hover { opacity: 1; }
#licencjaFlagi button[aria-pressed="true"] { opacity: 1; border-color: #bbb; background: #f4f2ee; }
#licencjaFlagi svg { width: 22px; height: 15px; border-radius: 2px; box-shadow: 0 0 0 1px rgba(0,0,0,.18); display: block; }

/* PRZEŁĄCZNIK 3D obok dopasowania widoku — ten sam kształt, o krok dalej. */
#przelacz3d {
  /* NAD PODGLĄDEM 3D (#widok3d ma z-index 6): z niego też musi dać się
     wrócić jednym kliknięciem (zgłoszone: „z podglądu 3D powinien być
     przycisk powrotu do 2D"). */
  position: absolute; right: 14px; bottom: 58px; z-index: 7;
  min-width: 34px; height: 34px; padding: 0 8px; border-radius: 8px; display: flex; align-items: center; justify-content: center; gap: 6px;
  font: 600 12px/1 inherit;
  border: 1px solid var(--rule); background: var(--panel); color: var(--ink900); cursor: pointer;
  box-shadow: 0 1px 4px rgba(0,0,0,.12);
}
#przelacz3d:hover { background: var(--accent); border-color: var(--accent); color: #fff; }
#przelacz3d[aria-pressed="true"] { background: var(--accent); border-color: var(--accent); color: #fff; }

/* IKONY PASKA NARZĘDZI SĄ SVG, nie emoji: Windows nie ma części tych
   znaków w czcionkach (zgłoszone). Rysowane linią w kolorze tekstu, więc
   w podświetleniu i w trybie ciemnym przebarwiają się same. */
#przelacz3d .do2d, #przelacz3d .podpis2d { display: none; }
#przelacz3d[aria-pressed="true"] .do3d { display: none; }
#przelacz3d[aria-pressed="true"] .do2d, #przelacz3d[aria-pressed="true"] .podpis2d { display: block; }
#toolbar #naming { margin-left: auto; padding-left: 10px; border-left: 1px solid var(--hair); }
#toolbar #naming input { width: 18ch; }

#preview .pen-arm { stroke: #77bdfb; stroke-width: 1; stroke-dasharray: 4 3; fill: none; }
#preview .pen-guide { stroke: #77bdfb; stroke-width: 1.5; stroke-dasharray: 5 3; fill: none; }
#preview .pen-control { fill: #fff; stroke: #258ade; stroke-width: 1.5; }

/* MANAGER MODELI — OSOBNE OKNO, szerokie, bo lista bywa na 93 970 pozycji
   i w kolumnie na 280 px nie dało się jej czytać. */
#dlgModele form { width: min(760px, 92vw); }
.modele-paski { display: flex; gap: 10px; flex-wrap: wrap; }
.modele-paski .pole { display: flex; flex-direction: column; gap: 3px; flex: 1 1 180px; }
.modele-paski .pole.szeroko { flex: 2 1 240px; }
.modele-paski .pole > span { font-size: 12px; color: var(--ink700); }
#modeleLista { max-height: 46vh; overflow: auto; display: grid;
               grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
               gap: 2px; border: 1px solid var(--rule); padding: 4px; }
#modeleLista .model { text-align: left; padding: 4px 7px; font-size: 12px;
                      border: 1px solid transparent; background: none;
                      color: var(--ink900); cursor: pointer;
                      overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
#modeleLista .model:hover { border-color: var(--rule); background: var(--hair); }
/* CZEGO NIE MASZ, WIDAĆ OD RAZU: katalog pokazuje 93 970 modeli, a postawić
   da się tylko zainstalowane. */
#modeleLista .model.brak { opacity: .55; font-style: italic; }
/* „Wskaż bazę…" to <label> na ukrytym <input type=file>, więc musi wyglądać
   jak przycisk sama z siebie. */
.wskaz { margin-right: auto; }
.wskaz .przycisk { display: inline-block; padding: 6px 12px; cursor: pointer;
                   border: 1px solid var(--rule); border-radius: 6px; }
.wskaz .przycisk:hover { background: var(--hair); }
/* „albo wyślij plik bazy…" to droga awaryjna dla chmury, więc jest mniejsza
   od wskazania katalogu — jedno wyjście główne, jedno na wypadek. */
.wskaz.drobne .przycisk { font-size: 12px; border-style: dashed; }

/* TRYB NAGRANIA (`?nagranie=1`, filmy promocyjne): bez pasków pomocniczych. */
body.nagranie #status, body.nagranie #tip, body.nagranie #oknoPomiarow,
body.nagranie #przeliczanie { display: none !important; }

/* PRZELICZANIE, PROSZĘ CZEKAĆ — pigułka na dole planu, nad podglądem 3D
   (z-index 6) i pod dymkami. Nie łapie myszy: przeliczenie idzie w tle,
   a plan pod nią działa dalej. Patrz `przeliczanieStart` w app.js. */
#przeliczanie {
  position: absolute; left: 50%; bottom: 12px; z-index: 8;
  display: flex; align-items: center; gap: 10px;
  padding: 6px 16px 6px 10px; border-radius: 999px;
  background: var(--panel); color: var(--ink700); border: 1px solid var(--rule);
  box-shadow: 0 4px 14px rgba(0, 0, 0, .14);
  opacity: 0; transform: translate(-50%, 6px); pointer-events: none;
  transition: opacity .2s ease, transform .2s ease;
}
#przeliczanie.widoczne { opacity: 1; transform: translate(-50%, 0); }
#przeliczanie .lokomotywa { position: relative; flex: none; width: 46px; height: 22px; }
#przeliczanie svg { display: block; width: 46px; height: 22px;
  animation: przeliczanie-kolysanie 1.1s ease-in-out infinite; }
/* Dym z komina: komin stoi w 105/130 szerokości lokomotywy. */
#przeliczanie .dym { position: absolute; left: 35px; top: -1px; width: 5px; height: 5px;
  border-radius: 50%; background: var(--ink500); opacity: 0;
  animation: przeliczanie-dym 1.6s ease-out infinite; }
#przeliczanie .dym:nth-child(2) { animation-delay: .53s; }
#przeliczanie .dym:nth-child(3) { animation-delay: 1.06s; }
@keyframes przeliczanie-kolysanie { 0%, 100% { transform: none; } 50% { transform: translateY(-1px); } }
@keyframes przeliczanie-dym {
  0% { opacity: .75; transform: translate(0, 0) scale(.6); }
  100% { opacity: 0; transform: translate(9px, -14px) scale(2.2); }
}
@media (prefers-reduced-motion: reduce) {
  #przeliczanie svg, #przeliczanie .dym { animation: none; }
}

/* WARSTWA PRZELICZANIA — nad planem i nad podglądem 3D (z-index 7: nad 3D,
   pod pigułką). Piotr, 01.10.2026: „pasek świetlny przechodzący po
   powierzchni makiety” i „nie powinno to blokować działania na makiecie”.

   * PAS ŚWIATŁA (`::before`) jedzie po makiecie jak skaner: jasny rdzeń
     w kolorze akcentu, miękka poświata przed nim i dłuższa smuga za nim;
   * RAMKA (`::after`) pulsuje akcentem na krawędzi planu.

   TYLKO `transform` I `opacity` — te animacje przesuwa sama karta graficzna,
   bez przerysowywania planu i bez spowalniania 3D. Myszy nie łapie nic:
   plan i 3D działają dalej. Zapala ją `pokazPrzeliczanie` w app.js. */
#przeliczanieWarstwa {
  position: absolute; inset: 0; z-index: 7; pointer-events: none;
  overflow: hidden; opacity: 0; transition: opacity .35s ease;
}
#przeliczanieWarstwa.widoczne { opacity: 1; }
#przeliczanieWarstwa::before {
  content: ""; position: absolute; top: -10%; bottom: -10%; left: 0;
  width: 34%;
  background: linear-gradient(90deg,
    transparent 0%,
    color-mix(in srgb, var(--accent) 6%, transparent) 45%,
    color-mix(in srgb, var(--accent) 22%, transparent) 72%,
    color-mix(in srgb, #fff 70%, var(--accent)) 74%,
    color-mix(in srgb, var(--accent) 18%, transparent) 77%,
    transparent 100%);
  mix-blend-mode: screen;
  transform: translateX(-110%) skewX(-14deg);
  will-change: transform;
}
#przeliczanieWarstwa::after {
  content: ""; position: absolute; inset: 0;
  box-shadow: inset 0 0 0 2px color-mix(in srgb, var(--accent) 80%, transparent),
              inset 0 0 60px color-mix(in srgb, var(--accent) 30%, transparent);
  opacity: .5;
}
#przeliczanieWarstwa.widoczne::before { animation: przeliczanie-pas 2.4s cubic-bezier(.45, 0, .55, 1) infinite; }
#przeliczanieWarstwa.widoczne::after { animation: przeliczanie-puls 1.2s ease-in-out infinite alternate; }
@keyframes przeliczanie-pas {
  0%   { transform: translateX(-110%) skewX(-14deg); }
  100% { transform: translateX(320%) skewX(-14deg); }
}
@keyframes przeliczanie-puls { from { opacity: .35; } to { opacity: 1; } }
body.nagranie #przeliczanieWarstwa { display: none !important; }
/* W 3D PAS ŚWIECI NA SAMYM GRUNCIE (`dolozSkanTerenu` w widok3d.js) —
   nakładka zostawia tylko ramkę. */
#plan:has(#widok3d:not([hidden])) #przeliczanieWarstwa::before { display: none; }
@media (prefers-reduced-motion: reduce) {
  #przeliczanieWarstwa.widoczne::before { animation: none; display: none; }
  #przeliczanieWarstwa.widoczne::after { animation: none; opacity: .8; }
}
