﻿/* Platform shell konsumuje globalne tokeny z apps/shared/platform-header.css. */

* { box-sizing: border-box; }
html { scroll-behavior: smooth; }
body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
}
a { color: inherit; text-decoration: none; }
button { font: inherit; }

.app-shell {
  min-height: 100vh;
}

.platform-shell-header,
.platform-shell-header .platform-header__actions,
.section-head,
.module-card__header,
.status-card,
.copy-row {
  display: flex;
  align-items: center;
}

/* Ikona w wierszu tytułu (nie nad nim) — mniejsza, żeby wiersz był zwarty. */
.app-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 38px;
  height: 38px;
  border-radius: 9px;
}

.app-icon svg {
  width: 20px;
  height: 20px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* Eyebrows: kanon kitu .platform-eyebrow (shared) — lokalna receptura usunięta
   (etap 7 planu UI-Kit); markup używa klas kitu. */

/* Token --platform-content-mid = 1120px: 6 kart domyka się w równy prostokąt
   3x2 (~350px karty) zamiast rozlanych 460px na 1440 — gęstość produktu, nie
   poczekalni. */
.main {
  min-width: 0;
  width: 100%;
  max-width: var(--platform-content-mid, 1120px);
  margin: 0 auto;
  padding: 22px;
}

/* Header renderuje wspólny data-platform-header (konwersja wykonana `kit3-1`);
   akcent .nb-dot i linię meta wstrzykuje inline-skrypt w index.html. */
.platform-header.platform-shell-header {
  position: sticky;
  top: 0;
  z-index: 10;
  margin-bottom: 22px;
}

h1, h2, h3, p { margin-top: 0; }
h1 {
  margin-bottom: 0;
  font-size: 1.35rem;
}
h2 { margin-bottom: 0; font-size: 1.18rem; }
h3 { margin-bottom: 8px; }
p { line-height: 1.55; }

.platform-shell-header .platform-header__actions {
  gap: 8px;
  justify-content: flex-end;
}

/* DE-WYSPOWANIE (20260729-p5-1): karty/panele PŁASKIE — bez obrysu, promienia
   i cienia (elewacja tylko dla modali/dropdownów/toastów). Wiersze i sekcje
   rozdziela kreska --shell-rule (=--line; w glass --platform-hairline, bo
   --line to tam biel 0.1 — praktycznie niewidoczna). */
:root { --shell-rule: var(--line); }
:root[data-theme="glass"] { --shell-rule: var(--platform-hairline); }

.panel,
.app-card,
.daily-joke-card,
.deploy-map article {
  background: transparent;
  border: 0;
  border-top: 1px solid var(--shell-rule);
  border-radius: 0;
  box-shadow: none;
}

/* Glass-override shared (specyficzność [data-theme]+klasa) maluje na tych
   klasach mleczną taflę z blur+cieniem — po de-wyspowaniu kontrujemy ją
   lokalnie tą samą specyficznością (arkusz app ładuje się PO shared). */
[data-theme="glass"] .panel,
[data-theme="glass"] .app-card,
[data-theme="glass"] .daily-joke-card,
[data-theme="glass"] .status-card,
[data-theme="glass"] .deploy-map article {
  background: transparent;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  border-color: var(--shell-rule);
  box-shadow: none;
}

.admin-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 12px;
  margin-bottom: 18px;
}

.status-card {
  gap: 12px;
  padding: 14px 0;
  background: transparent;
  border: 0;
  border-top: 1px solid var(--shell-rule);
  border-radius: 0;
}
.status-card strong,
.status-card small { display: block; }
.status-card small { margin-top: 3px; color: var(--muted); }
/* Stany na tokenach semantycznych — --gold i --primary aliasują ten sam
   akcent, przez co ok/caution/pending były nierozróżnialne w 3 z 4 motywów. */
.status-dot {
  width: 12px;
  height: 12px;
  border-radius: 999px;
  background: var(--warn-fg);
  box-shadow: 0 0 0 4px var(--warn-bg);
}
.status-dot.pending {
  background: transparent;
  border: 2px dashed var(--muted);
  box-shadow: none;
}
.status-dot.ok {
  background: var(--pass-fg);
  box-shadow: 0 0 0 4px var(--pass-bg);
}
.status-dot.error {
  background: var(--fail-fg);
  box-shadow: 0 0 0 4px var(--fail-bg);
}

/* Kolumny oddziela światło, wiersze — kreska (border-top na komórkach). */
.app-grid,
.two-col,
.deploy-map {
  display: grid;
  gap: 0 var(--space-6);
}
.panel,
.app-card,
.daily-joke-card,
.deploy-map article {
  padding: 16px 0;
}
.app-card p,
.panel p,
.daily-joke-card__text,
.deploy-map small {
  color: var(--muted);
}

.section {
  margin-bottom: var(--space-6);
  scroll-margin-top: 88px;
}
.section-head {
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: var(--space-4);
}
.section-head.compact { margin-bottom: 12px; }

/* Równy prostokąt 3x2 — bez spanów featured/last-child (dziury i nierówny
   rytm); wyróżnikiem karty jest treść (feats), nie szerokość. */
.app-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 0 var(--space-5); }
.app-launcher { align-items: stretch; }
.app-card {
  display: flex;
  flex-direction: column;
  padding: 16px 12px 20px;
}

/* Etykieta sekcji launchera = kit .platform-eyebrow--muted (na h2 w markupie)
   — tytuły kart mają dominować. */
.section-head__label {
  display: flex;
  align-items: center;
  gap: 8px;
}
/* Licznik = kit .platform-chip--count; lokalnie tylko chowanie pustego spanu
   zanim JS wpisze liczbę. */
.section-count:empty { display: none; }

.app-card h3 {
  flex: 1 1 auto;
  min-width: 0;
  font-size: 1.02rem;
  line-height: 1.3;
  margin: 0;
}

/* Tag kategorii w wierszu tytułu — ŚWIADOMIE nie chip (.platform-chip):
   to cicha meta-etykieta kategorii (jak eyebrow), nie status; pigułka na
   każdej z 6 kart konkurowałaby z badge Beta. Bez klas .badge/.platform-chip
   (badge kart czytany po .app-card__badge/.badge)
   i nie może pomylić tagu z Beta. */
.app-card__tag {
  flex: 0 0 auto;
  font-size: 0.68rem;
  font-weight: 600;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--muted);
  white-space: nowrap;
}

.app-card p {
  flex: 1 1 auto;
  font-size: var(--text-base);
  line-height: 1.55;
  margin-bottom: 12px;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* Warstwa treści: ciche punkty z data-nb-features (generuje inline JS w
   index.html) — karta jest mini-dossier aplikacji, nie pustą wizytówką. */
.app-card__feats {
  list-style: none;
  margin: 0 0 14px;
  padding: 0;
  display: grid;
  gap: 6px;
  font-size: 0.82rem;
  line-height: 1.4;
  color: color-mix(in srgb, var(--text) 72%, var(--muted));
}
.app-card__feats li {
  display: flex;
  align-items: flex-start;
  gap: 9px;
}
.app-card__feats li::before {
  content: "";
  flex: 0 0 auto;
  width: 4px;
  height: 4px;
  margin-top: 0.5em;
  border-radius: 999px;
  background: var(--brand, var(--primary));
}

/* CTA jako cicha stopka karty — hairline domyka dossier, akcent oszczędny. */
.app-card .button.primary.app-card__link {
  margin-top: auto;
  align-self: stretch;
  justify-content: flex-start;
  min-height: 0;
  padding: 10px 0 0;
  background: transparent;
  border: 0;
  border-top: 1px solid var(--platform-hairline);
  border-radius: 0;
  color: var(--accent-ink, var(--accent));
  font-size: 0.88rem;
  font-weight: 600;
  gap: 6px;
}

.app-card .link-arrow {
  transition: transform 0.15s ease;
}

.app-card:hover .link-arrow {
  transform: translateX(3px);
}

@media (prefers-reduced-motion: reduce) {
  .app-card .link-arrow { transition: none; }
}
/* Wiersz tytułu: ikona | h3 | tag (+Beta) — bez martwego pola nad tytułem. */
.module-card__header {
  gap: 12px;
  margin-bottom: 12px;
}
.app-card[hidden] { display: none; }
.app-icon { color: var(--primary-strong); background: var(--teal-soft); }
.accent-purple .app-icon { color: var(--primary); background: color-mix(in srgb, var(--primary) 16%, var(--surface)); }
.accent-coral .app-icon { color: var(--coral); background: var(--coral-soft); }
.accent-gold .app-icon { color: var(--gold); background: var(--gold-soft); }

/* Cała karta klikalna: rozciągnięty link + widoczny focus-ring. */
.app-card { position: relative; }
.app-card__badge { align-self: center; }
.app-card__link::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
}
/* Hover = tint tonalny (nie lift) — płaska karta podświetla się tłem. */
.app-card {
  transition: background-color 0.15s ease;
}
.app-card:hover {
  background: color-mix(in srgb, var(--text) 4%, transparent);
}
@media (prefers-reduced-motion: reduce) {
  .app-card { transition: none; }
}
/* Miękki ring fokusa (reguła 10) zamiast twardego pełnego akcentu. */
.app-card:focus-within {
  outline: 2px solid color-mix(in srgb, var(--primary) 40%, transparent);
  outline-offset: 4px;
}
.app-card__link:focus-visible {
  outline: none;
}

/* Wyszukiwarka aplikacji. */
.app-search {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-width: min(260px, 100%);
}
/* Podpowiedź skrótu „/" w polu wyszukiwarki — znika przy fokusie, wpisanym
   zapytaniu i na urządzeniach dotykowych (skrót klawiaturowy nie dotyczy). */
.app-search__kbd {
  position: absolute;
  top: 9px;
  right: 10px;
  padding: 1px 7px;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--surface-2, var(--panel-soft));
  color: var(--muted);
  font-family: inherit;
  font-size: 0.72rem;
  font-weight: 600;
  line-height: 1.4;
  pointer-events: none;
}
.app-search:focus-within .app-search__kbd,
.app-search__input:not(:placeholder-shown) ~ .app-search__kbd {
  display: none;
}
@media (hover: none) {
  .app-search__kbd { display: none; }
}
.app-search__label {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}
.app-search__input {
  width: 100%;
  padding: 9px 12px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--surface);
  color: var(--text);
}
.app-search__input:focus-visible {
  outline: 2px solid color-mix(in srgb, var(--primary) 40%, transparent);
  outline-offset: 2px;
}
.app-search__status {
  min-height: 1em;
  margin: 0;
  font-size: 0.78rem;
  color: var(--muted);
}
.app-search__status:empty { display: none; }
/* Podświetlenie trafienia wyszukiwarki (JS owija fragment w <mark>) —
   pokazuje, DLACZEGO karta pasuje do zapytania. */
.app-card mark.app-card__mark {
  background: color-mix(in srgb, var(--primary) 24%, transparent);
  color: inherit;
  border-radius: 3px;
  padding: 0 1px;
}

/* Pasek sterowania: przełącznik widoku Notatnik|Lista USUNIĘTY z Platformą-notatnikiem
   (2026-07-29, decyzja usera: forma notatnika porzucona). Pulpit ma jeden widok —
   płaską siatkę/listę kart; szukajka siedzi w nagłówku sekcji „Aplikacje". */
.section-head .app-search {
  flex: 0 1 340px;
  margin-left: auto;
  min-width: min(260px, 100%);
}
/* Input tonalny wewnątrz paska-produktu; ramka dopiero przy fokusie. */
.section-head .app-search__input {
  border-color: transparent;
  background: var(--surface-2, var(--panel-soft));
}
.section-head .app-search__input:focus-visible {
  border-color: var(--brand, var(--primary));
}
/* Status wyszukiwarki w pasku tylko dla czytników (rola status zostaje) —
   pasek nie skacze wysokością; wynik i tak widać po przefiltrowanych kartach. */
.section-head .app-search__status {
  position: absolute;
  width: 1px;
  height: 1px;
  min-height: 0;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

.daily-joke-section {
  margin-top: 0;
}
/* Suchar jako cichy pasek (eyebrow + tekst w jednej linii) — nie konkuruje
   wysokością ani skalą typografii z kartami aplikacji. */
.daily-joke-card {
  display: flex;
  align-items: baseline;
  gap: 14px;
  padding: 14px 0;
}
.daily-joke-card__header {
  display: flex;
  align-items: baseline;
  gap: 14px;
}
.daily-joke-card .platform-eyebrow {
  margin: 0;
  white-space: nowrap;
}
/* Treść dowcipu to jedyna zawartość paska — pełny atrament, nie drugorzędny. */
.daily-joke-card__text {
  color: var(--text);
  max-width: 900px;
  margin: 0;
  font-size: 0.95rem;
  line-height: 1.45;
}
.daily-joke-card__text span {
  display: inline;
}
.daily-joke-card__text span + span {
  margin-left: 8px;
}
/* Klik w treść kopiuje suchar (handler w app.js) — kursor to sygnalizuje. */
.daily-joke-card__text[data-daily-joke] { cursor: copy; }
/* Etykieta dnia archiwum („wczoraj" / data) — cicha meta obok eyebrow. */
.daily-joke-card__day {
  font-size: 0.78rem;
  color: var(--muted);
  white-space: nowrap;
}
.daily-joke-card__day:empty { display: none; }
/* Akcje suchara: strzałki archiwum + kopiowanie; align-self zamiast baseline
   (przyciski bez tekstu w baseline-flex wisiałyby krzywo). */
.daily-joke-card__actions {
  display: inline-flex;
  align-items: center;
  align-self: center;
  gap: 6px;
  margin-left: auto;
  flex: 0 0 auto;
}
.daily-joke-card__btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  padding: 0;
  border: 1px solid transparent;
  border-radius: 8px;
  background: transparent;
  color: var(--muted);
  cursor: pointer;
  transition: border-color 0.15s ease, background-color 0.15s ease, color 0.15s ease;
}
.daily-joke-card__btn:hover {
  color: var(--text);
  background: var(--surface-2, var(--panel-soft));
  border-color: var(--border);
}
.daily-joke-card__btn:disabled {
  opacity: 0.45;
  cursor: default;
}
.daily-joke-card__btn:disabled:hover {
  color: var(--muted);
  background: transparent;
  border-color: transparent;
}
.daily-joke-card__btn:focus-visible {
  outline: 2px solid color-mix(in srgb, var(--primary) 40%, transparent);
  outline-offset: 2px;
}
.daily-joke-card__btn[hidden] { display: none; }
.daily-joke-card__btn svg {
  width: 15px;
  height: 15px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* Wiersze danych bez drabiny kresek: separator tylko MIĘDZY wierszami,
   zmiękczony hairline'em (reguła 1); etykiety zdaniowe (reguła 3). */
dl {
  display: grid;
  gap: 0;
  margin: 4px 0 0;
}
dl div {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  padding: 8px 0;
  border-bottom: 0;
}
dl div + div {
  border-top: 1px solid var(--platform-hairline);
}
dt {
  color: color-mix(in srgb, var(--text) 62%, var(--muted));
  font-size: 0.8rem;
  text-transform: none;
  letter-spacing: 0;
}
/* Wyższa specyficzność niż grupa wag w shared (goły dt). */
dl dt {
  font-weight: 600;
}
dd {
  margin: 0;
  min-width: 0;
  text-align: right;
  word-break: normal;
  overflow-wrap: anywhere;
  font-variant-numeric: tabular-nums;
}

.button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  margin-top: auto;
}
/* Chipy statusów = kanon kitu .platform-chip (pill; dawny lokalny span.badge
   radius 7px usunięty — etap 7 planu UI-Kit); lokalnie tylko barwa stanu
   przez --chip-hue na tokenach semantycznych pass/warn. */
.platform-chip.good {
  --chip-hue: var(--pass-fg);
  color: var(--pass-fg);
}
.platform-chip.warn {
  --chip-hue: var(--warn-fg);
  color: var(--warn-fg);
}

.two-col { grid-template-columns: repeat(2, minmax(0, 1fr)); }
/* Zaplecze techniczne oddzielone kreską od części publicznej. */
.admin-section {
  margin-top: var(--space-6, 32px);
  padding-top: var(--space-6, 32px);
  border-top: 1px solid var(--shell-rule);
}
/* Świeżość statusu + ręczne odświeżenie (bez przeładowania strony). */
.admin-status-tools {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
}
.admin-status-checked {
  font-size: 0.78rem;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.admin-refresh {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 14px;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: var(--surface);
  color: var(--text);
  font-size: 0.82rem;
  font-weight: 600;
  cursor: pointer;
  transition: border-color 0.15s ease, background-color 0.15s ease;
}
.admin-refresh:hover {
  border-color: color-mix(in srgb, var(--primary) 36%, var(--border));
}
.admin-refresh:disabled {
  opacity: 0.55;
  cursor: default;
}
.admin-refresh:focus-visible {
  outline: 2px solid color-mix(in srgb, var(--primary) 40%, transparent);
  outline-offset: 2px;
}
[data-admin-only][hidden] {
  display: none !important;
}
.check-list,
.guard-panel ul {
  margin: 0;
  padding: 0;
  list-style: none;
}
/* Separator tylko między wpisami, zmiękczony — koniec z drabiną kresek. */
.check-list li,
.guard-panel li {
  display: flex;
  gap: 10px;
  padding: 10px 0;
  border-bottom: 1px solid var(--platform-hairline);
  line-height: 1.45;
}
.check-list li:last-child,
.guard-panel li:last-child {
  border-bottom: 0;
}
/* Punktor 4px w kolorze semantyki panelu (reguła 8). */
.guard-panel li::before {
  content: "";
  flex: 0 0 auto;
  width: 4px;
  height: 4px;
  margin-top: 0.62em;
  border-radius: 999px;
  background: var(--danger);
}
.check {
  flex: 0 0 auto;
  width: 18px;
  height: 18px;
  margin-top: 2px;
  border-radius: 999px;
  background: var(--warn-fg);
}
.check.ok { background: var(--pass-fg); }
.check.caution { background: var(--warn-fg); }

.command-list { display: grid; gap: 10px; }
/* Wiersz komendy = tonalny, z żywym hover/fokusem (to przycisk "skopiuj"). */
.copy-row {
  width: 100%;
  justify-content: space-between;
  gap: 12px;
  padding: 12px;
  border: 1px solid transparent;
  border-radius: 8px;
  background: color-mix(in srgb, var(--primary) 6%, var(--surface-2));
  color: var(--text);
  cursor: pointer;
  text-align: left;
  transition: border-color 0.15s ease, background-color 0.15s ease;
}
.copy-row:hover {
  border-color: color-mix(in srgb, var(--primary) 36%, var(--border));
  background: var(--surface);
}
.copy-row:active {
  transform: translateY(1px);
}
.copy-row:focus-visible {
  outline: 2px solid color-mix(in srgb, var(--primary) 40%, transparent);
  outline-offset: 2px;
}
code {
  color: var(--primary-strong);
  font-family: "SFMono-Regular", Consolas, monospace;
  font-size: 0.82rem;
}

/* Semantyka paneli w krótkim akcencie pod etykietą (klasa platform-label-accent
   w HTML), nie w tintowanej ramie całego panelu (reguła 1). */
.data-panel { border-color: var(--border); }
.guard-panel { border-color: var(--border); }
.data-panel .platform-label-accent::after { background: var(--primary); }
.guard-panel .platform-label-accent::after { background: var(--danger); }
.deploy-map { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.deploy-map strong {
  display: block;
  margin: 8px 0 5px;
}

/* Toast = kanoniczny .platform-toast ze shared (reguła 12); lokalnie tylko
   clamp szerokości pod wąskie ekrany — bez drugiej, konkurującej receptury. */
.toast.platform-toast {
  max-width: min(320px, calc(100vw - 36px));
  border: 0;
  box-shadow: none;
}

@media (max-width: 1080px) {
  .admin-grid,
  .two-col,
  .deploy-map {
    grid-template-columns: 1fr;
  }
  .app-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 720px) {
  .app-grid {
    grid-template-columns: 1fr;
  }
  .daily-joke-card {
    flex-direction: column;
    gap: 6px;
  }
}
