diff --git a/README.md b/README.md
index f77b4ab..1cb36db 100644
--- a/README.md
+++ b/README.md
@@ -46,15 +46,16 @@ server.
### Features
-- Service tabs with a clean card-based layout
-- Live service dashboard with online count, last check time, and latency labels
-- Browser-local recent status history with mini timelines and average latency
+- Responsive service tabs with a compact status overview and one focused detail card
+- Live dashboard showing every service's status and latency as measured by this browser
+- Collapsed browser-local history of the last 24 measurements with mini timelines and averages
- Health checks for all configured services
+- Explicit `Checking`, `Online`, `Unreachable`, and `Unknown` service states
- Local Muse readiness probe with Discord gateway connectivity check
- Polling with warm-up measurement and failure backoff
- EN/PL language switcher
- Dark / Light / OLED themes
-- Client info badge with OS, browser, and device detection
+- Always-visible client context in the header with OS, browser, and device detection
- Keyboard-accessible tabs and visible focus states
### Project Structure
@@ -210,15 +211,16 @@ albo dowolnym serwerze statycznym.
### Funkcje
-- Zakładki usług z czytelnym układem kart
-- Dashboard statusów z liczbą usług online, czasem ostatniego sprawdzenia i opóźnieniami
-- Lokalna historia ostatnich statusów z mini-timeline i średnim opóźnieniem
+- Responsywne zakładki usług z kompaktowym podsumowaniem i jednym aktywnym panelem szczegółów
+- Dashboard pokazujący status i opóźnienie każdej usługi, mierzone z tej przeglądarki
+- Zwijana lokalna historia ostatnich 24 pomiarów z mini-timeline i średnim opóźnieniem
- Health checki dla wszystkich skonfigurowanych usług
+- Jawne stany usług: `Checking`, `Online`, `Unreachable` i `Unknown`
- Lokalna sonda gotowości Muse ze sprawdzeniem połączenia z gateway Discorda
- Odpytywanie z pomiarem rozgrzewkowym i backoffem przy błędach
- Przełącznik języka EN/PL
- Motywy Dark / Light / OLED
-- Etykieta z wykrytym OS, przeglądarką i typem urządzenia
+- Zawsze widoczne w nagłówku informacje o kliencie: OS, przeglądarka i typ urządzenia
- Zakładki dostępne z klawiatury i czytelne stany focus
### Struktura projektu
diff --git a/css/styles.css b/css/styles.css
index 4689ca5..9f54ac6 100644
--- a/css/styles.css
+++ b/css/styles.css
@@ -1,163 +1,269 @@
:root {
- --bg: #0b0f14;
- --fg: #e6eef6;
- --mut: #9fb3c8;
- --line: #1b2530;
- --card: #0f1620;
- --acc: #7cc4ff;
- --br: 16px;
- --shadow: 0 12px 30px rgba(0, 0, 0, .35);
- --ring: 0 0 0 2px #0ea5e955;
- --good: #22c55e;
- --bad: #ef4444;
+ --bg: #080d14;
+ --fg: #edf5ff;
+ --mut: #93a8bc;
+ --line: rgba(148, 177, 204, .16);
+ --card: #0e1621;
+ --surface: #121c28;
+ --surface-strong: #172434;
+ --acc: #67bdff;
+ --acc-strong: #169bf5;
+ --good: #31d477;
+ --bad: #ff5e68;
+ --warn: #f6b73c;
+ --br: 20px;
+ --shadow: 0 22px 60px rgba(0, 0, 0, .32);
+ --ring: 0 0 0 3px rgba(22, 155, 245, .28);
}
* {
- box-sizing: border-box
+ box-sizing: border-box;
}
-html,
-body {
- height: 100%
+html {
+ min-height: 100%;
+ color-scheme: dark;
}
body {
+ min-height: 100%;
margin: 0;
- font: 16px/1.55 system-ui, Segoe UI, Roboto, Ubuntu, Arial;
- background: radial-gradient(1400px 800px at 10% -10%, #0e1622 0, #0b0f14 45%) fixed;
+ font: 16px/1.55 Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
color: var(--fg);
+ background:
+ radial-gradient(circle at 12% -8%, rgba(14, 165, 233, .16), transparent 34rem),
+ radial-gradient(circle at 92% 18%, rgba(99, 102, 241, .1), transparent 28rem),
+ linear-gradient(180deg, #0a1018 0, var(--bg) 42rem) fixed;
-webkit-font-smoothing: antialiased;
text-rendering: optimizeLegibility;
- transition: background .3s ease, color .3s ease;
+ transition: background .25s ease, color .25s ease;
+}
+
+button,
+a,
+summary {
+ -webkit-tap-highlight-color: transparent;
}
.skip-link {
- position: absolute;
+ position: fixed;
+ top: 12px;
left: 12px;
- top: -48px;
z-index: 100;
- padding: 10px 12px;
- border-radius: 10px;
+ padding: 10px 14px;
border: 1px solid var(--line);
- background: var(--card);
+ border-radius: 12px;
color: var(--fg);
- font-weight: 700;
- transition: top .2s ease;
+ background: var(--surface-strong);
+ box-shadow: var(--shadow);
+ font-weight: 750;
+ transform: translateY(-180%);
+ transition: transform .18s ease;
}
.skip-link:focus {
- top: 12px;
+ transform: translateY(0);
}
.wrap {
- max-width: 980px;
- margin: 0 auto;
- padding: 28px
+ width: min(100%, 1080px);
+ margin-inline: auto;
+}
+
+.topbar-inner {
+ width: min(100%, 1200px);
+ margin-inline: auto;
+}
+
+.wrap {
+ padding: 26px 28px 10px;
}
.topbar {
position: sticky;
top: 0;
z-index: 10;
- backdrop-filter: saturate(140%) blur(6px);
- background: rgba(11, 15, 20, .75);
border-bottom: 1px solid var(--line);
- overflow: visible;
- /* ensure nothing clips */
+ background: rgba(8, 13, 20, .82);
+ backdrop-filter: saturate(145%) blur(18px);
}
.topbar-inner {
- max-width: 980px;
- margin: 0 auto;
- padding: 12px 28px;
+ display: grid;
+ gap: 12px;
+ padding: 14px 28px;
+}
+
+.topbar-primary,
+.topbar-lower {
display: flex;
align-items: center;
justify-content: space-between;
- gap: 18px;
- overflow: visible;
- /* ensure nothing clips */
- flex-wrap: wrap;
- /* allow wrapping on narrower widths so subtitle never disappears */
+ gap: 16px;
+ min-width: 0;
}
.brand {
display: flex;
- gap: 14px;
align-items: center;
- flex: 1 1 320px;
- min-width: 280px;
+ gap: 14px;
+ min-width: 0;
}
.logo {
- width: 42px;
- height: 42px;
- border-radius: 12px;
- background: radial-gradient(70% 70% at 30% 30%, #0ea5e9, #1f2937);
- box-shadow: 0 0 0 1px var(--line) inset;
+ position: relative;
+ flex: 0 0 auto;
+ width: 48px;
+ height: 48px;
+ border: 1px solid rgba(125, 211, 252, .22);
+ border-radius: 15px;
+ background:
+ radial-gradient(circle at 30% 25%, #38bdf8 0, #1679b8 38%, transparent 39%),
+ linear-gradient(145deg, #17344b, #0c1722);
+ box-shadow: 0 12px 28px rgba(14, 165, 233, .2), inset 0 1px rgba(255, 255, 255, .08);
+}
+
+.logo::after {
+ content: "";
+ position: absolute;
+ right: 9px;
+ bottom: 9px;
+ width: 0;
+ height: 0;
+ border-top: 6px solid transparent;
+ border-bottom: 6px solid transparent;
+ border-left: 10px solid #bce7ff;
+ filter: drop-shadow(0 2px 5px rgba(0, 0, 0, .35));
+}
+
+h1,
+h2,
+p {
+ margin-top: 0;
}
h1 {
- margin: 0;
+ margin-bottom: 0;
+ font-size: 1.35rem;
+ font-weight: 800;
+ letter-spacing: -.025em;
+}
+
+h2 {
+ margin: 0 0 5px;
font-size: 1.25rem;
- font-weight: 700
+ line-height: 1.25;
+ letter-spacing: -.02em;
}
.tag {
- color: var(--mut)
+ color: var(--mut);
}
-.pc-status {
- margin-top: 0;
- display: inline-flex;
+#subtitle {
+ display: inline;
+ font-size: .88rem;
+}
+
+#availability {
+ display: flex;
align-items: center;
- gap: 8px;
- white-space: nowrap;
- padding: 6px 10px;
- border-radius: 999px;
- border: 1px solid var(--line);
- background: linear-gradient(180deg, #111b26, #0b111a);
- font-weight: 600;
- font-size: .92rem;
+ gap: 7px;
+ margin-top: 2px;
+ font-size: .76rem;
}
-.pc-status .pc-main {
- font-weight: 700;
+#availability::before {
+ content: "";
+ width: 7px;
+ height: 7px;
+ border-radius: 50%;
+ background: var(--good);
+ box-shadow: 0 0 0 4px rgba(49, 212, 119, .1);
}
-.pc-status .pc-os {
- display: inline-flex;
+.controls {
+ display: flex;
align-items: center;
- padding: 2px 8px;
- border-radius: 999px;
+ gap: 8px;
+ flex: 0 0 auto;
+}
+
+.chip,
+.tab {
border: 1px solid var(--line);
- background: color-mix(in srgb, var(--card) 88%, transparent);
- color: var(--mut);
- font-size: .8rem;
- line-height: 1.2;
+ color: var(--fg);
+ font: inherit;
+ font-weight: 700;
+ cursor: pointer;
}
-.pc-status.is-on .pc-main {
- color: var(--good);
+.chip {
+ min-height: 38px;
+ padding: 8px 12px;
+ border-radius: 12px;
+ background: rgba(18, 28, 40, .82);
+ transition: border-color .16s ease, background .16s ease, transform .16s ease;
}
-.pc-status.is-off .pc-main {
- color: var(--bad);
+.chip:hover {
+ border-color: rgba(103, 189, 255, .35);
+ background: var(--surface-strong);
+}
+
+.language-control {
+ padding: 3px;
+}
+
+.lang-switch {
+ position: relative;
+ display: grid;
+ grid-template-columns: repeat(2, 1fr);
+}
+
+.lang-switch::before {
+ content: "";
+ position: absolute;
+ inset: 0 50% 0 0;
+ border-radius: 9px;
+ background: linear-gradient(135deg, rgba(103, 189, 255, .32), rgba(22, 155, 245, .17));
+ box-shadow: inset 0 0 0 1px rgba(103, 189, 255, .26);
+ transition: transform .22s cubic-bezier(.4, 0, .2, 1);
+}
+
+.lang-switch:has(#lang-pl[aria-pressed="true"])::before,
+.lang-switch.is-pl::before {
+ transform: translateX(100%);
+}
+
+.lang-switch:has(#lang-en[aria-pressed="true"])::before,
+.lang-switch.is-en::before {
+ transform: translateX(0);
+}
+
+#lang-en,
+#lang-pl {
+ position: relative;
+ z-index: 1;
+ min-width: 40px;
+ min-height: 32px;
+ padding: 5px 9px;
+ border: 0;
+ border-radius: 9px;
+ background: transparent;
+ box-shadow: none;
}
nav.tabs {
display: flex;
- gap: 8px;
- flex-wrap: nowrap;
- overflow: visible;
- /* no scroll gutter, no clipping */
+ gap: 3px;
+ min-width: 0;
+ padding: 4px;
+ overflow-x: auto;
+ border: 1px solid var(--line);
+ border-radius: 14px;
+ background: rgba(9, 15, 23, .62);
scrollbar-width: none;
- /* FF: hide scrollbar */
- flex: 0 1 auto;
- /* don't steal width from brand */
-}
-
-nav.tabs::-webkit-scrollbar {
- display: none;
}
nav.tabs::-webkit-scrollbar {
@@ -165,202 +271,305 @@ nav.tabs::-webkit-scrollbar {
}
.tab {
- padding: 8px 16px;
- border: 1px solid var(--line);
- border-radius: 9999px;
- background: var(--card);
- color: var(--fg);
- font-weight: 600;
- cursor: pointer;
+ flex: 0 0 auto;
+ min-height: 36px;
+ padding: 7px 12px;
+ border-color: transparent;
+ border-radius: 10px;
+ color: var(--mut);
+ background: transparent;
white-space: nowrap;
- transition: transform .2s ease, background .2s ease;
- position: relative;
- /* for ::after ring */
- isolation: isolate;
- /* create its own stacking context so ring isn't hidden */
+ transition: color .16s ease, background .16s ease, transform .16s ease;
+}
+
+.tab-label-compact {
+ display: none;
}
.tab:hover {
- transform: translateY(-2px);
- background: linear-gradient(180deg, #111b26, #0b111a)
+ color: var(--fg);
+ background: rgba(103, 189, 255, .08);
}
-/* Nice, always-visible ring for active tab */
.tab[aria-selected="true"] {
- outline: none
+ color: #f5fbff;
+ background: linear-gradient(135deg, rgba(22, 155, 245, .34), rgba(74, 121, 255, .18));
+ box-shadow: inset 0 0 0 1px rgba(103, 189, 255, .28), 0 8px 20px rgba(0, 0, 0, .15);
}
-.tab[aria-selected="true"]::after {
- content: "";
- position: absolute;
- top: -4px;
- right: -4px;
- bottom: -4px;
- left: -4px;
- /* extends evenly around */
- border-radius: 9999px;
- border: 2px solid var(--acc);
- pointer-events: none;
+.client-info {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ min-width: 0;
+ padding: 4px;
+ border: 1px solid var(--line);
+ border-radius: 14px;
+ background: rgba(9, 15, 23, .62);
}
-.controls {
+.client-heading {
+ display: inline-flex;
+ align-items: center;
+ gap: 7px;
+ padding: 0 7px;
+ color: var(--mut);
+ font-size: .72rem;
+ font-weight: 800;
+ letter-spacing: .02em;
+ white-space: nowrap;
+}
+
+.client-indicator {
+ width: 7px;
+ height: 7px;
+ border-radius: 50%;
+ background: var(--acc);
+ box-shadow: 0 0 0 4px rgba(103, 189, 255, .1);
+}
+
+.pc-status {
display: flex;
- gap: 8px;
align-items: center;
- flex-wrap: wrap;
- flex: 0 0 auto;
+ gap: 4px;
+ min-width: 0;
}
-.chip {
- padding: 8px 12px;
- border: 1px solid var(--line);
- border-radius: 999px;
- background: linear-gradient(180deg, #111b26, #0b111a);
- color: var(--fg);
- cursor: pointer
+.client-metric {
+ display: inline-flex;
+ align-items: baseline;
+ gap: 5px;
+ min-width: 0;
+ padding: 6px 8px;
+ border: 1px solid transparent;
+ border-radius: 9px;
+ background: rgba(18, 28, 40, .8);
+ white-space: nowrap;
+}
+
+.client-key {
+ color: var(--mut);
+ font-size: .64rem;
+ font-weight: 750;
+ letter-spacing: .04em;
+ text-transform: uppercase;
}
-.chip[aria-pressed="true"],
-.chip.active {
- outline: 2px solid var(--acc)
+.client-value {
+ color: var(--fg);
+ font-size: .72rem;
+ font-weight: 800;
+ white-space: nowrap;
}
.tab:focus-visible,
.chip:focus-visible,
-a:focus-visible {
+a:focus-visible,
+summary:focus-visible {
outline: 2px solid var(--acc);
- outline-offset: 2px;
+ outline-offset: 3px;
}
main {
- padding-top: 18px
+ padding-top: 2px;
}
.card {
- background: var(--card);
+ margin-bottom: 16px;
+ padding: 24px;
+ overflow: hidden;
border: 1px solid var(--line);
border-radius: var(--br);
- padding: 22px;
- box-shadow: var(--shadow);
- margin-bottom: 18px;
- transition: transform .18s ease, box-shadow .18s ease;
+ background: linear-gradient(145deg, rgba(18, 28, 40, .94), rgba(12, 20, 30, .96));
+ box-shadow: var(--shadow), inset 0 1px rgba(255, 255, 255, .025);
}
-.card:hover {
- transform: translateY(-2px);
- box-shadow: 0 16px 36px rgba(0, 0, 0, .45)
+.dashboard-card {
+ padding: 22px;
}
-h2 {
- margin: .2rem 0 .6rem;
- font-size: 1.2rem
+.dashboard-top {
+ display: flex;
+ align-items: flex-start;
+ justify-content: space-between;
+ gap: 20px;
}
-a {
- color: var(--acc);
- text-decoration: none;
- font-weight: 600
+.dashboard-copy .tag {
+ margin: 0;
+ font-size: .86rem;
}
-a:hover {
- text-decoration: underline
+.dashboard-grid {
+ display: flex;
+ align-items: center;
+ justify-content: flex-end;
+ gap: 7px;
+ flex-wrap: wrap;
}
-.btn {
+.pill {
display: inline-flex;
align-items: center;
- gap: 10px;
- padding: 12px 16px;
- border-radius: 999px;
+ gap: 7px;
+ min-height: 32px;
+ padding: 6px 10px;
border: 1px solid var(--line);
- background: linear-gradient(180deg, #111b26, #0b111a);
+ border-radius: 10px;
color: var(--fg);
- text-decoration: none;
+ background: rgba(18, 28, 40, .78);
+ font-size: .86rem;
font-weight: 700;
- box-shadow: var(--shadow);
- transition: transform .15s ease, filter .15s ease;
}
-.btn:hover {
- filter: brightness(1.12);
- transform: translateY(-1px)
+.dashboard-grid .pill {
+ color: var(--mut);
+ font-size: .78rem;
}
-.btn:focus-visible {
- outline: none;
- box-shadow: var(--ring)
+.dashboard-grid #dash-overall {
+ color: var(--fg);
}
-.j-wrap {
- display: flex;
- gap: 18px;
- align-items: center;
- justify-content: space-between;
- flex-wrap: wrap
+.dashboard-grid #dash-overall.is-checking {
+ color: var(--mut);
}
-.j-left {
- display: flex;
- gap: 16px;
- align-items: center
+.dashboard-grid #dash-overall.is-unreachable {
+ color: var(--bad);
}
-.j-icon {
- display: flex;
+.dashboard-services {
+ display: grid;
+ grid-template-columns: repeat(5, minmax(0, 1fr));
+ gap: 8px;
+ margin-top: 18px;
+}
+
+.dashboard-service {
+ display: grid;
+ grid-template-columns: auto minmax(0, 1fr) auto;
+ grid-template-areas:
+ "dot name name"
+ "state state latency";
align-items: center;
- justify-content: center;
+ gap: 8px 7px;
+ min-width: 0;
+ padding: 12px;
+ border: 1px solid var(--line);
+ border-radius: 14px;
+ background: linear-gradient(145deg, rgba(23, 36, 52, .72), rgba(13, 22, 33, .76));
+ transition: border-color .18s ease, background .18s ease, transform .18s ease;
}
-.j-icon svg,
-.j-icon img {
- display: block;
- width: 70px;
- height: 70px;
+.dashboard-service:hover {
+ transform: translateY(-1px);
+ border-color: rgba(103, 189, 255, .26);
}
-.pill {
- display: inline-flex;
- align-items: center;
- gap: 8px;
- padding: 6px 10px;
- border: 1px solid var(--line);
- border-radius: 999px;
- background: linear-gradient(180deg, #111b26, #0b111a);
- color: var(--fg)
+.dashboard-service > .dot {
+ grid-area: dot;
}
-.dashboard-grid {
- display: flex;
- flex-wrap: wrap;
- gap: 8px;
+.dashboard-service-name {
+ grid-area: name;
+ min-width: 0;
+ overflow: hidden;
+ font-size: .86rem;
+ font-weight: 800;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.dashboard-service-state {
+ grid-area: state;
+}
+
+.dashboard-service-latency {
+ grid-area: latency;
+ justify-self: end;
+}
+
+.dashboard-service-state,
+.dashboard-service-latency {
+ color: var(--mut);
+ font-size: .72rem;
+ font-weight: 750;
+ white-space: nowrap;
+}
+
+.dot {
+ width: 8px;
+ height: 8px;
+ border-radius: 50%;
+ background: var(--mut);
+}
+
+.dashboard-service.status-online .dot,
+.service-status.status-online .dot {
+ background: var(--good);
+ box-shadow: 0 0 0 4px rgba(49, 212, 119, .1);
+}
+
+.dashboard-service.status-checking .dot,
+.dashboard-service.status-unknown .dot,
+.service-status.status-checking .dot,
+.service-status.status-unknown .dot {
+ background: var(--mut);
+}
+
+.dashboard-service.status-unreachable .dot,
+.service-status.status-unreachable .dot {
+ background: var(--bad);
+ box-shadow: 0 0 0 4px rgba(255, 94, 104, .1);
+}
+
+.dashboard-service.status-online .dashboard-service-state {
+ color: var(--good);
+}
+
+.dashboard-service.status-unreachable .dashboard-service-state {
+ color: var(--bad);
}
.status-history {
- margin-top: 16px;
+ margin-top: 18px;
+ padding-top: 14px;
+ border-top: 1px solid var(--line);
}
-.status-history h3 {
- margin: 0 0 10px;
+.status-history > summary {
+ width: fit-content;
color: var(--mut);
- font-size: .95rem;
- font-weight: 700;
+ cursor: pointer;
+ font-size: .8rem;
+ font-weight: 750;
+}
+
+.status-history > summary:hover {
+ color: var(--fg);
+}
+
+.status-history[open] > summary {
+ margin-bottom: 14px;
}
.history-grid {
display: grid;
- grid-template-columns: repeat(auto-fit, minmax(min(100%, 360px), 1fr));
- gap: 10px;
+ grid-template-columns: repeat(2, minmax(0, 1fr));
+ gap: 8px;
}
.history-row {
display: grid;
- grid-template-columns: minmax(130px, 1fr) minmax(150px, 1.2fr) auto;
- gap: 10px;
+ grid-template-columns: minmax(110px, 1fr) minmax(130px, 1.35fr) auto;
align-items: center;
- padding: 10px;
+ gap: 10px;
+ min-width: 0;
+ padding: 10px 11px;
border: 1px solid var(--line);
border-radius: 12px;
- background: color-mix(in srgb, var(--card) 88%, transparent);
+ background: rgba(9, 15, 23, .42);
}
.history-meta {
@@ -371,7 +580,8 @@ a:hover {
.history-name {
overflow: hidden;
color: var(--fg);
- font-weight: 700;
+ font-size: .82rem;
+ font-weight: 800;
text-overflow: ellipsis;
white-space: nowrap;
}
@@ -379,8 +589,8 @@ a:hover {
.history-summary,
.history-avg {
color: var(--mut);
- font-size: .82rem;
- font-weight: 600;
+ font-size: .7rem;
+ font-weight: 700;
}
.history-summary.is-stable {
@@ -388,7 +598,7 @@ a:hover {
}
.history-summary.is-recovering {
- color: #f59e0b;
+ color: var(--warn);
}
.history-summary.is-issues {
@@ -397,15 +607,15 @@ a:hover {
.history-line {
display: grid;
- grid-template-columns: repeat(24, minmax(3px, 1fr));
- gap: 3px;
+ grid-template-columns: repeat(24, minmax(2px, 1fr));
+ gap: 2px;
min-width: 0;
}
.history-segment {
display: block;
- height: 18px;
- min-width: 3px;
+ min-width: 2px;
+ height: 16px;
border-radius: 999px;
background: var(--line);
cursor: default;
@@ -413,7 +623,7 @@ a:hover {
}
.history-segment.is-online:hover,
-.history-segment.is-offline:hover {
+.history-segment.is-unreachable:hover {
transform: scaleY(1.3);
}
@@ -421,7 +631,7 @@ a:hover {
background: var(--good);
}
-.history-segment.is-offline {
+.history-segment.is-unreachable {
background: var(--bad);
}
@@ -429,361 +639,491 @@ a:hover {
opacity: .55;
}
-.dot {
- width: 8px;
- height: 8px;
- border-radius: 50%
+.service-section {
+ position: relative;
+ isolation: isolate;
+ min-height: 176px;
+ padding: 28px;
+ --service-accent: var(--acc-strong);
}
-footer {
- margin: 26px 0;
+.service-section::before {
+ content: "";
+ position: absolute;
+ inset: 0 auto 0 0;
+ width: 4px;
+ background: linear-gradient(180deg, transparent, var(--service-accent), transparent);
+ opacity: .9;
+}
+
+.service-section::after {
+ content: "";
+ position: absolute;
+ z-index: -1;
+ top: -120px;
+ left: -80px;
+ width: 360px;
+ height: 300px;
+ border-radius: 50%;
+ background: color-mix(in srgb, var(--service-accent) 12%, transparent);
+ filter: blur(48px);
+ pointer-events: none;
+}
+
+#section-jf {
+ --service-accent: #8b5cf6;
+}
+
+#section-fb {
+ --service-accent: #14b8a6;
+}
+
+#section-ab {
+ --service-accent: #f59e0b;
+}
+
+#section-st {
+ --service-accent: #3b82f6;
+}
+
+#section-muse {
+ --service-accent: #ec4899;
+}
+
+.j-wrap {
display: flex;
- justify-content: center;
align-items: center;
- gap: 8px;
- color: var(--mut);
- font-size: .92rem;
+ justify-content: space-between;
+ gap: 24px;
+ min-height: 118px;
}
-@media (prefers-reduced-motion: reduce) {
+.j-left {
+ display: flex;
+ align-items: center;
+ gap: 22px;
+ min-width: 0;
+}
- .card,
- .btn {
- transition: none
- }
+.j-left > div:last-child {
+ min-width: 0;
}
-/* Light theme */
-.theme-light {
- --bg: #f7f9fc;
- --fg: #0b1220;
- --mut: #4b5563;
- --line: #d9e1ec;
- --card: #ffffff;
- --acc: #0e88da;
- --ring: 0 0 0 2px #0ea5e955;
- --good: #16a34a;
- --bad: #dc2626;
+.j-icon {
+ display: grid;
+ place-items: center;
+ flex: 0 0 auto;
+ width: 88px;
+ height: 88px;
+ padding: 13px;
+ border: 1px solid color-mix(in srgb, var(--service-accent) 26%, var(--line));
+ border-radius: 24px;
+ background: color-mix(in srgb, var(--service-accent) 10%, rgba(9, 15, 23, .76));
+ box-shadow: inset 0 1px rgba(255, 255, 255, .05), 0 16px 36px rgba(0, 0, 0, .18);
}
-.theme-light body {
- background: radial-gradient(1400px 800px at 10% -10%, #eef3f9 0, #f7f9fc 45%) fixed
+.j-icon img,
+.j-icon svg {
+ display: block;
+ width: 62px;
+ height: 62px;
+ object-fit: contain;
}
-.theme-light .btn {
- background: linear-gradient(180deg, #ffffff, #eef3f9);
- border-color: #d9e1ec;
- color: #0b1220
+.service-section h2 {
+ margin-bottom: 5px;
+ font-size: 1.55rem;
}
-.theme-light .tab,
-.theme-light .chip,
-.theme-light .pill,
-.theme-light .pc-status {
- background: linear-gradient(180deg, #ffffff, #eef3f9);
- border-color: #d9e1ec;
- color: #0b1220
+.service-section .tag {
+ font-size: .92rem;
}
-.theme-light body {
- background: radial-gradient(1400px 800px at 10% -10%, #ffffff 0, #f2f5fa 60%) fixed
+.service-meta {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 7px;
+ margin-top: 13px !important;
}
-.theme-light .tab,
-.theme-light .chip,
-.theme-light .btn,
-.theme-light .pill,
-.theme-light .pc-status {
- background: linear-gradient(180deg, #f9fafb, #f3f4f6);
- color: var(--fg)
+.service-status.status-online {
+ border-color: rgba(49, 212, 119, .2);
+ color: var(--good);
+ background: rgba(49, 212, 119, .07);
}
-.theme-light .card {
- background: var(--card)
+.service-status.status-unreachable {
+ border-color: rgba(255, 94, 104, .22);
+ color: var(--bad);
+ background: rgba(255, 94, 104, .07);
}
-.theme-light .history-row {
- background: #f9fafb;
+.service-latency {
+ color: var(--mut);
}
-.theme-light .history-summary.is-recovering {
- color: #d97706;
+.service-source,
+.service-note {
+ margin: 8px 0 0;
+ color: var(--mut);
+ font-size: .72rem;
}
-.toast {
- position: fixed;
- left: 50%;
- bottom: 20px;
- transform: translate(-50%, 10px);
- background: var(--card);
- color: var(--fg);
- border: 1px solid var(--line);
- border-radius: 12px;
- padding: 10px 14px;
- box-shadow: var(--shadow);
- opacity: 0;
- pointer-events: none;
- transition: opacity .2s ease, transform .2s ease;
- z-index: 50;
+.service-note {
+ color: color-mix(in srgb, var(--service-accent) 55%, var(--mut));
+ font-weight: 700;
}
-.toast.show {
- opacity: 1;
- transform: translate(-50%, 0)
+.service-actions {
+ flex: 0 0 auto;
}
-.theme-light .topbar {
- background: rgba(255, 255, 255, 0.86);
- border-bottom: 1px solid var(--line);
- backdrop-filter: saturate(140%) blur(6px);
+a {
+ color: var(--acc);
+ text-decoration: none;
+ font-weight: 650;
}
-.theme-light .tag {
- color: #374151;
+a:hover {
+ text-decoration: underline;
}
-/* OLED theme */
-.theme-oled {
- --bg: #000000;
- --fg: #f4f7ff;
- --mut: #9aa7ba;
- --line: #121212;
- --card: #000000;
- --acc: #6db5ff;
- --ring: 0 0 0 2px #6db5ff55;
- --good: #22c55e;
- --bad: #ef4444;
- --shadow: 0 12px 30px rgba(0, 0, 0, .6);
+.btn {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ gap: 9px;
+ min-height: 46px;
+ padding: 11px 17px;
+ border: 1px solid color-mix(in srgb, var(--service-accent) 50%, transparent);
+ border-radius: 14px;
+ color: #fff;
+ background: linear-gradient(135deg, color-mix(in srgb, var(--service-accent) 82%, #0a2237), var(--service-accent));
+ box-shadow: 0 12px 28px color-mix(in srgb, var(--service-accent) 18%, transparent);
+ font-weight: 800;
+ text-decoration: none;
+ transition: transform .16s ease, filter .16s ease, box-shadow .16s ease;
}
-.theme-oled body {
- background: #000 fixed;
+.btn svg path {
+ stroke: currentColor;
}
-.theme-oled .topbar {
- background: rgba(0, 0, 0, 0.92);
- border-bottom: 1px solid var(--line);
+.btn:hover {
+ filter: brightness(1.08);
+ text-decoration: none;
+ transform: translateY(-2px);
}
-.theme-oled .card,
-.theme-oled .btn,
-.theme-oled .tab,
-.theme-oled .chip,
-.theme-oled .pill,
-.theme-oled .pc-status,
-.theme-oled .toast {
- background: #000;
- border-color: var(--line);
- color: var(--fg);
+.btn:focus-visible {
+ outline: 0;
+ box-shadow: var(--ring), 0 12px 28px color-mix(in srgb, var(--service-accent) 18%, transparent);
}
-.theme-oled .tab:hover,
-.theme-oled .btn:hover,
-.theme-oled .chip:hover {
- background: #050505;
+.card.active-card {
+ border-color: color-mix(in srgb, var(--service-accent) 32%, var(--line));
}
-.theme-oled .history-row {
- background: #050505;
+footer {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ gap: 8px;
+ margin: 26px 0;
+ color: var(--mut);
+ font-size: .82rem;
}
-/* ---- Theme toggle animations ---- */
+.github-link {
+ display: inline-flex;
+ align-items: center;
+ gap: 6px;
+ vertical-align: middle;
+}
-#theme-toggle .emoji {
- display: inline-block;
- transition: transform .3s ease;
+/* Light theme */
+.theme-light {
+ color-scheme: light;
+ --bg: #f3f7fb;
+ --fg: #132033;
+ --mut: #5c6f84;
+ --line: rgba(77, 106, 133, .18);
+ --card: #fff;
+ --surface: #f6f9fc;
+ --surface-strong: #eef4f9;
+ --acc: #087ec5;
+ --acc-strong: #087ec5;
+ --good: #158f4b;
+ --bad: #d33c48;
+ --shadow: 0 18px 48px rgba(49, 73, 97, .12);
}
-#theme-toggle .emoji.flip {
- transform: rotateY(180deg) scale(1.08);
+.theme-light body {
+ background:
+ radial-gradient(circle at 12% -8%, rgba(14, 165, 233, .14), transparent 34rem),
+ radial-gradient(circle at 92% 18%, rgba(99, 102, 241, .07), transparent 28rem),
+ linear-gradient(180deg, #fbfdff 0, var(--bg) 42rem) fixed;
}
-#theme-toggle {
- transition: transform 0.6s ease;
+.theme-light .topbar {
+ background: rgba(250, 252, 255, .86);
}
-#theme-toggle:active {
- transform: rotate(360deg);
+.theme-light nav.tabs,
+.theme-light .client-info {
+ background: rgba(255, 255, 255, .72);
}
-html.theme-light #theme-toggle {
- border: none !important;
- outline: none !important;
- box-shadow: none !important;
+.theme-light .card {
+ background: linear-gradient(145deg, rgba(255, 255, 255, .98), rgba(246, 249, 252, .98));
}
-/* ---- Language switcher ---- */
-.lang-switch {
- position: relative;
- display: inline-flex;
- gap: 8px;
+.theme-light .chip,
+.theme-light .pill,
+.theme-light .client-metric {
+ background: rgba(246, 249, 252, .94);
}
-#lang-en,
-#lang-pl {
- position: relative;
- z-index: 1;
+.theme-light .tab[aria-selected="true"] {
+ color: #075985;
+ background: linear-gradient(135deg, rgba(14, 165, 233, .18), rgba(59, 130, 246, .1));
}
-.lang-switch::before {
- content: '';
- position: absolute;
- top: 0;
- left: 0;
- bottom: 0;
- width: calc(50% - 4px);
- border-radius: 999px;
- border: 2px solid var(--acc);
- pointer-events: none;
- transition: left 0.3s cubic-bezier(.4, 0, .2, 1);
- box-sizing: border-box;
+.theme-light .dashboard-service,
+.theme-light .history-row {
+ background: rgba(246, 249, 252, .88);
}
-.lang-switch:has(#lang-pl[aria-pressed="true"])::before {
- left: calc(50% + 4px);
+/* OLED theme */
+.theme-oled {
+ --bg: #000;
+ --fg: #f4f7ff;
+ --mut: #94a1b2;
+ --line: rgba(255, 255, 255, .1);
+ --card: #000;
+ --surface: #050505;
+ --surface-strong: #090909;
+ --acc: #6db5ff;
+ --acc-strong: #258ee8;
+ --shadow: 0 18px 48px rgba(0, 0, 0, .72);
}
-.lang-switch:has(#lang-en[aria-pressed="true"])::before {
- left: 0;
+.theme-oled body {
+ background: #000 fixed;
}
-/* Fallback for browsers without :has() support */
-.lang-switch.is-pl::before {
- left: calc(50% + 4px);
+.theme-oled .topbar,
+.theme-oled nav.tabs,
+.theme-oled .client-info,
+.theme-oled .card,
+.theme-oled .chip,
+.theme-oled .pill,
+.theme-oled .client-metric,
+.theme-oled .dashboard-service,
+.theme-oled .history-row {
+ background: #000;
}
-.lang-switch.is-en::before {
- left: 0;
+/* Toggle animation */
+#theme-toggle .emoji {
+ display: inline-block;
+ transition: transform .3s ease;
}
-.card.active-card {
- outline: 3px solid var(--acc);
- outline-offset: 4px;
- border-radius: 1rem
+#theme-toggle .emoji.flip {
+ transform: rotateY(180deg) scale(1.08);
}
-.github-link {
- display: inline-flex;
- align-items: center;
- gap: 6px;
- color: var(--acc);
- font-weight: 600;
- vertical-align: middle;
+@media (max-width: 1120px) {
+ .topbar-lower {
+ align-items: stretch;
+ flex-direction: column;
+ }
+
+ .client-info {
+ justify-content: space-between;
+ }
}
-.github-link:hover {
- text-decoration: underline;
+@media (max-width: 980px) {
+ .dashboard-services {
+ grid-template-columns: repeat(3, minmax(0, 1fr));
+ }
}
-@media (max-width: 900px) {
+@media (max-width: 720px) {
+ .topbar {
+ position: relative;
+ }
+
+ .topbar-inner,
+ .wrap {
+ padding-inline: 16px;
+ }
+
+ .topbar-inner {
+ padding-block: 12px;
+ }
+
+ .topbar-primary {
+ align-items: flex-start;
+ flex-direction: column;
+ gap: 12px;
+ }
+
.controls {
- flex: 1 1 100%;
width: 100%;
}
+ #theme-toggle {
+ flex: 1 1 auto;
+ }
+
+ .client-info {
+ display: grid;
+ justify-content: stretch;
+ gap: 7px;
+ width: 100%;
+ padding: 8px;
+ }
+
+ .client-heading {
+ padding: 0 3px;
+ }
+
.pc-status {
+ display: grid;
+ grid-template-columns: repeat(3, minmax(0, 1fr));
width: 100%;
- white-space: normal;
- flex-wrap: wrap;
- row-gap: 6px;
}
- .pc-status .pc-os,
- .pc-status .pc-main {
- max-width: 100%;
- overflow-wrap: anywhere;
+ .client-metric {
+ display: grid;
+ gap: 1px;
+ padding: 7px 8px;
}
-}
-/* ---- Mobile-only layout fixes (desktop stays unchanged) ---- */
-@media (max-width: 768px) {
- .wrap {
- padding: 16px;
+ .client-value {
+ font-size: .76rem;
}
- .topbar-inner {
- padding: 10px 16px;
- gap: 12px;
- align-items: stretch;
+ nav.tabs {
+ display: grid;
+ grid-template-columns: repeat(5, minmax(0, 1fr));
+ width: 100%;
+ overflow: visible;
}
- .brand {
+ .tab {
min-width: 0;
- flex: 1 1 100%;
- align-items: flex-start;
+ padding-inline: 3px;
+ font-size: .69rem;
+ text-align: center;
}
- nav.tabs {
- flex: 1 1 100%;
- overflow-x: auto;
- -webkit-overflow-scrolling: touch;
- padding: 4px;
+ .tab-label-full {
+ display: none;
}
- .tab[aria-selected="true"]::after {
- top: 0;
- right: 0;
- bottom: 0;
- left: 0;
+ .tab-label-compact {
+ display: inline;
}
- .controls {
- gap: 10px;
+ .tab,
+ .chip {
+ min-height: 42px;
}
- .chip,
- .tab {
- padding: 10px 12px;
- min-height: 44px;
+ .dashboard-top {
+ flex-direction: column;
+ gap: 13px;
+ }
+
+ .dashboard-grid {
+ justify-content: flex-start;
+ width: 100%;
+ }
+
+ .dashboard-services {
+ grid-template-columns: repeat(2, minmax(0, 1fr));
+ }
+
+ .dashboard-service {
+ padding: 11px;
+ }
+
+ .history-grid {
+ grid-template-columns: 1fr;
+ }
+
+ .history-row {
+ grid-template-columns: 1fr;
+ }
+
+ .history-avg {
+ justify-self: start;
}
- .card {
- padding: 16px;
+ .card,
+ .dashboard-card,
+ .service-section {
+ padding: 18px;
+ border-radius: 18px;
}
.j-wrap {
- flex-direction: column;
align-items: stretch;
- gap: 14px;
+ flex-direction: column;
+ gap: 20px;
}
.j-left {
align-items: flex-start;
+ gap: 15px;
+ }
+
+ .j-icon {
+ width: 68px;
+ height: 68px;
+ padding: 10px;
+ border-radius: 19px;
+ }
+
+ .j-icon img,
+ .j-icon svg {
+ width: 48px;
+ height: 48px;
}
- .j-icon svg,
- .j-icon img {
- width: 56px;
- height: 56px;
+ .service-section h2 {
+ font-size: 1.3rem;
}
+ .service-actions,
.btn {
width: 100%;
- justify-content: center;
- min-height: 44px;
}
footer {
flex-wrap: wrap;
- text-align: center;
row-gap: 4px;
+ text-align: center;
}
+}
- .dashboard-grid .pill {
- width: 100%;
- justify-content: center;
- }
-
- .history-grid {
- grid-template-columns: 1fr;
+@media (max-width: 390px) {
+ .client-key {
+ font-size: .54rem;
+ letter-spacing: .02em;
}
- .history-row {
- grid-template-columns: 1fr;
+ .client-value {
+ font-size: .7rem;
}
- .history-avg {
- justify-self: start;
+ .tab {
+ font-size: .64rem;
+ letter-spacing: -.01em;
}
}
@@ -791,8 +1131,7 @@ html.theme-light #theme-toggle {
*,
*::before,
*::after {
- animation: none !important;
- transition: none !important;
scroll-behavior: auto !important;
+ transition: none !important;
}
}
diff --git a/index.html b/index.html
index 531f991..b4a3bec 100644
--- a/index.html
+++ b/index.html
@@ -7,7 +7,7 @@
adiker.eu — Homepage
-
+
@@ -20,58 +20,103 @@
- Skip to main content
+ Skip to main content
-
-
-
-
adiker.eu
-
My Playground
-
Usually available: 9:00 AM – 1:00 AM CEST
+
+
+
+
+
adiker.eu
+
My Playground
+
Usually available: 9:00 AM – 1:00 AM CEST
+
+
+
-
-
-
-
-
-
-
+
+
+
+
+
+ This device
+
Detecting client…
-
My PC is off :(
-
- 📊 Service dashboard
- Live status overview
-
-
0/5 online
-
Last check: --
-
Jellyfin: -- ms
-
FileBrowser: -- ms
-
autobrr: -- ms
-
OpenSpeedTest: -- ms
-
Muse: -- ms
+
+
+
+
Service status
+
Live measurements from this browser
+
+
+ 0/5 online
+ Last update: --
+
-
-
Recent checks
+
+
+
+ Jellyfin
+ Checking…
+ -- ms
+
+
+
+ FileBrowser
+ Checking…
+ -- ms
+
+
+
+ autobrr
+ Checking…
+ -- ms
+
+
+
+ OpenSpeedTest
+ Checking…
+ -- ms
+
+
+
+ Muse
+ Checking…
+ -- ms
+
+
+
+ Recent measurements
@@ -119,7 +164,7 @@
Recent checks
Avg: -- ms
-
+
@@ -130,15 +175,18 @@ Recent checks
src="https://upload.wikimedia.org/wikipedia/commons/4/41/Jellyfin_-_icon-transparent.svg" />
-
🎬 Jellyfin
+
Jellyfin
Your media server
-
-
Offline
+
+
+ Checking…
+
+ Latency: -- ms
+
Measured from this browser
-
+
-
📁 FileBrowser Quantum
+
FileBrowser Quantum
Your file manager
-
-
Offline
+
+
+ Checking…
+
+ Latency: -- ms
+
Measured from this browser
-
-
⚡ autobrr
+
autobrr
Automated torrent management
-
-
-
- Offline
+
+
+ Checking…
+ Latency: -- ms
+ Measured from this browser
-
+
-
🚀 OpenSpeedTest
+
OpenSpeedTest
Network speed test
-
-
-
- Offline
+
+
+ Checking…
+ Latency: -- ms
+ Measured from this browser
-
+
-
🎧 Muse
+
Muse
Discord music bot
-
-
-
- Offline
+
+
+ Checking…
+ Latency: -- ms
+ Measured from this browser
+ Status only · no web interface
@@ -268,12 +323,14 @@
🎧 Muse
GitHub
+
•
+
+ Keep Android Open
+
-
-
-
-
+
+