Create user account
diff --git a/html/css/base.css b/html/css/base.css
index 43f1c7f..7985635 100644
--- a/html/css/base.css
+++ b/html/css/base.css
@@ -1,32 +1,14 @@
-:root {
- --bg-0: #07111d;
- --bg-1: #0c1a2b;
- --bg-2: #12233a;
- --panel: #102238;
- --panel-soft: #0f1f33;
- --line: #274462;
- --line-soft: #1b334d;
- --text: #e9f5ff;
- --text-muted: #b7cee1;
- --accent: #35d2ff;
- --accent-strong: #12b9ff;
- --accent-soft: rgba(53, 210, 255, 0.2);
- --ok: #2fd18a;
- --warn: #ffc15a;
- --error: #ff6f6f;
- --radius-s: 10px;
- --radius-m: 14px;
- --radius-l: 18px;
- --shadow-1: 0 20px 45px rgba(0, 0, 0, 0.32);
- --shadow-2: 0 12px 30px rgba(0, 0, 0, 0.28);
-}
+/*
+ * base.css - reset, typography, links, focus styles, skip link, generic
+ * form elements and small utility classes. Loaded after tokens.css.
+ */
* {
-webkit-appearance: none;
-moz-appearance: none;
-ms-appearance: none;
box-sizing: border-box;
- font-family: "Space Grotesk", "Avenir Next", "Trebuchet MS", sans-serif;
+ font-family: var(--font-sans);
letter-spacing: 0.02em;
}
@@ -37,17 +19,17 @@
::-webkit-scrollbar-track {
border-radius: 999px;
- background: rgba(7, 17, 29, 0.65);
+ background: var(--scroll-track);
}
::-webkit-scrollbar-thumb {
border-radius: 999px;
- border: 2px solid rgba(7, 17, 29, 0.6);
- background: linear-gradient(180deg, #2d597f, #1e4060);
+ border: 2px solid var(--scroll-track);
+ background: linear-gradient(180deg, var(--scroll-thumb-a), var(--scroll-thumb-b));
}
::-webkit-scrollbar-thumb:hover {
- background: linear-gradient(180deg, #3678ac, #20537c);
+ background: linear-gradient(180deg, var(--scroll-thumb-hover-a), var(--scroll-thumb-hover-b));
}
::-webkit-scrollbar-corner {
@@ -61,9 +43,9 @@ body {
color: var(--text);
font-size: 14px;
background:
- radial-gradient(circle at 15% 12%, rgba(64, 132, 183, 0.22), transparent 32%),
- radial-gradient(circle at 88% 2%, rgba(18, 185, 255, 0.16), transparent 30%),
- linear-gradient(180deg, var(--bg-1) 0%, var(--bg-0) 56%, #060d17 100%);
+ radial-gradient(circle at 15% 12%, var(--bg-glow-1), transparent 32%),
+ radial-gradient(circle at 88% 2%, var(--bg-glow-2), transparent 30%),
+ linear-gradient(180deg, var(--bg-1) 0%, var(--bg-0) 56%, var(--bg-deep) 100%);
}
body {
@@ -75,7 +57,7 @@ a {
}
a:hover {
- color: #8de7ff;
+ color: var(--accent-hover);
}
h1,
@@ -122,7 +104,7 @@ pre {
white-space: pre-wrap;
line-height: 1.55;
letter-spacing: 0.015em;
- font-family: "IBM Plex Mono", "SFMono-Regular", "Consolas", monospace;
+ font-family: var(--font-mono);
}
hr {
@@ -153,7 +135,7 @@ button {
}
:focus-visible {
- outline: 2px solid #91eaff;
+ outline: 2px solid var(--focus-ring-soft);
outline-offset: 2px;
}
@@ -171,7 +153,7 @@ textarea {
width: 100%;
border-radius: var(--radius-s);
border: 1px solid var(--line);
- background-color: rgba(10, 22, 36, 0.78);
+ background-color: var(--surface-input);
color: var(--text);
padding: 10px 11px;
transition: border-color 0.2s ease, box-shadow 0.2s ease, background-color 0.2s ease;
@@ -184,45 +166,15 @@ input[type=number]:focus,
select:focus,
textarea:focus {
border-color: var(--accent);
- box-shadow: 0 0 0 3px rgba(53, 210, 255, 0.17);
- background-color: rgba(9, 25, 40, 0.95);
+ box-shadow: 0 0 0 3px var(--accent-ring);
+ background-color: var(--surface-input-focus);
}
input[type=text]::placeholder,
input[type=search]::placeholder,
input[type=password]::placeholder,
textarea::placeholder {
- color: #7e9ab4;
-}
-
-input[type=button],
-input[type=submit],
-button {
- cursor: pointer;
- border: 1px solid transparent;
- border-radius: 999px;
- color: #03101a;
- padding: 10px 18px;
- margin: 8px 8px 8px 0;
- font-weight: 700;
- letter-spacing: 0.03em;
- background: linear-gradient(135deg, #67e8ff 0%, #12b9ff 100%);
- box-shadow: 0 10px 22px rgba(18, 185, 255, 0.3);
- transition: transform 0.15s ease, box-shadow 0.2s ease, filter 0.2s ease;
-}
-
-input[type=button]:hover,
-input[type=submit]:hover,
-button:hover {
- transform: translateY(-1px);
- filter: brightness(1.05);
- box-shadow: 0 12px 24px rgba(18, 185, 255, 0.36);
-}
-
-input[type=button]:active,
-input[type=submit]:active,
-button:active {
- transform: translateY(0);
+ color: var(--text-placeholder);
}
input[type=button]:focus-visible,
@@ -236,80 +188,43 @@ input[type=text]:focus-visible,
input[type=search]:focus-visible,
input[type=password]:focus-visible,
input[type=number]:focus-visible {
- outline: 2px solid #7de5ff;
+ outline: 2px solid var(--focus-ring);
outline-offset: 2px;
}
-input[type=button].delete {
- color: #fff;
- background: linear-gradient(135deg, #ff7f7f 0%, #e94343 100%);
- box-shadow: 0 10px 20px rgba(233, 67, 67, 0.35);
-}
-
-input[type=button].cancel {
- color: #ffd8d8;
- border-color: rgba(255, 111, 111, 0.45);
- background: rgba(87, 22, 22, 0.45);
- box-shadow: none;
-}
-
-input[type=button].black,
-input[type=submit].black {
- color: #d8ecff;
- border-color: var(--line);
- background: rgba(14, 32, 50, 0.85);
- box-shadow: none;
-}
-
-input[type=button].center {
- margin-right: auto;
- margin-left: auto;
-}
-
-input[type=button].save {
- margin-left: auto;
-}
-
-input[type=checkbox] {
- width: 20px;
- height: 20px;
- border: 1px solid var(--line);
- border-radius: 6px;
- background-color: rgba(10, 22, 36, 0.86);
- cursor: pointer;
- position: relative;
-}
-
-input[type=checkbox]:checked {
- border-color: #89ebff;
- background-color: #39d6ff;
-}
-
-input[type=checkbox]:before {
- content: "";
-}
-
-input[type=checkbox]:checked:before {
- content: "\2713";
- color: #032033;
- font-size: 14px;
- font-weight: 800;
+.skip-link {
position: absolute;
- top: -1px;
- left: 3px;
+ top: 10px;
+ left: 10px;
+ z-index: 2600;
+ border-radius: 999px;
+ padding: 8px 12px;
+ font-size: 12px;
+ font-weight: 700;
+ color: var(--text-on-accent);
+ background: var(--accent-gradient);
+ transform: translateY(-180%);
+ transition: transform 0.2s ease;
}
-.changed {
- border-color: #8de7ff !important;
- box-shadow: 0 0 0 3px rgba(53, 210, 255, 0.2) !important;
+.skip-link:focus-visible {
+ transform: translateY(0);
}
-.notAvailable {
- opacity: 0.58;
- cursor: not-allowed;
- border-color: rgba(255, 111, 111, 0.45) !important;
+.sr-only {
+ border: 0 !important;
+ clip: rect(0 0 0 0) !important;
+ height: 1px !important;
+ margin: -1px !important;
+ overflow: hidden !important;
+ padding: 0 !important;
+ position: absolute !important;
+ white-space: nowrap !important;
+ width: 1px !important;
}
+/* Utility classes */
+
.pointer {
cursor: pointer;
}
@@ -364,37 +279,6 @@ input[type=checkbox]:checked:before {
text-align: center;
}
-.skip-link {
- position: absolute;
- top: 10px;
- left: 10px;
- z-index: 2600;
- border-radius: 999px;
- padding: 8px 12px;
- font-size: 12px;
- font-weight: 700;
- color: #03131f;
- background: linear-gradient(135deg, #7be8ff 0%, #19c1ff 100%);
- transform: translateY(-180%);
- transition: transform 0.2s ease;
-}
-
-.skip-link:focus-visible {
- transform: translateY(0);
-}
-
-.sr-only {
- border: 0 !important;
- clip: rect(0 0 0 0) !important;
- height: 1px !important;
- margin: -1px !important;
- overflow: hidden !important;
- padding: 0 !important;
- position: absolute !important;
- white-space: nowrap !important;
- width: 1px !important;
-}
-
.floatRight {
float: right;
}
@@ -423,9 +307,6 @@ input[type=checkbox]:checked:before {
display: none;
}
-.noBulk {
-}
-
.notVisible {
display: none;
opacity: 0;
@@ -437,259 +318,10 @@ input[type=checkbox]:checked:before {
opacity: 1;
}
-.menu-active {
- color: #011019;
-}
-
-.menu-notActive {
-}
-
-.menu {
- border: 1px solid var(--accent);
-}
-
.half {
width: 45%;
}
-.screenLogHidden {
- transform: translate(0, -110px);
-}
-
-.infoMsg {
- color: #87b0d1;
-}
-
-.errorMsg {
- color: #ff8d8d;
-}
-
-.warningMsg {
- color: var(--warn);
-}
-
-.debugMsg {
- color: #d687ff;
-}
-
-.News,
-.Movie,
-.Series,
-.Sports,
-.Kids {
- border-left: 3px solid transparent;
- padding-left: 8px;
-}
-
-.News {
- border-color: #ff8f6e;
-}
-
-.Movie {
- border-color: #46a4ff;
-}
-
-.Series {
- border-color: #ffd267;
-}
-
-.Sports {
- border-color: #5ee495;
-}
-
-.Kids {
- border-color: #f6a8ff;
-}
-
-#loading {
- position: fixed;
- inset: 0;
- z-index: 2000;
- background-color: rgba(5, 12, 20, 0.72);
- backdrop-filter: blur(1.5px);
-}
-
-.loader {
- width: 52px;
- height: 52px;
- border-radius: 50%;
- border: 4px solid transparent;
- border-top-color: #58ddff;
- border-right-color: #12b9ff;
- animation: spin 0.9s linear infinite;
- position: fixed;
- top: 0;
- right: 0;
- bottom: 0;
- left: 0;
- margin: auto;
-}
-
-#popup {
- position: fixed;
- inset: 0;
- background-color: rgba(3, 9, 16, 0.72);
- backdrop-filter: blur(2px);
- z-index: 1500;
- padding: 16px;
-}
-
-#popup-custom,
-#mapping-detail,
-#user-detail,
-#file-detail {
- margin: 0 auto;
- max-width: 760px;
- max-height: calc(100vh - 36px);
- overflow: auto;
- border-radius: var(--radius-l);
- border: 1px solid var(--line);
- background: linear-gradient(180deg, rgba(17, 34, 56, 0.97) 0%, rgba(12, 27, 44, 0.97) 100%);
- box-shadow: var(--shadow-1);
- padding: 16px;
- animation: popupIn 0.2s ease;
-}
-
-#popup-custom h3 {
- margin-bottom: 8px;
- text-align: center;
- color: #d5efff;
-}
-
-.popup-title {
- display: flex;
- align-items: center;
- justify-content: space-between;
- gap: 10px;
- margin-bottom: 10px;
-}
-
-.popup-title h3 {
- margin: 0;
- text-align: left;
-}
-
-#popup-custom .popup-title h3 {
- margin: 0;
- text-align: left;
-}
-
-.popup-close {
- min-width: 40px;
- min-height: 40px;
- margin: 0;
- padding: 0;
- border-radius: 999px;
- border: 1px solid var(--line);
- color: #d9f0ff;
- background: rgba(14, 32, 50, 0.9);
- box-shadow: none;
- font-size: 20px;
- line-height: 1;
-}
-
-.popup-close:hover {
- color: #ffffff;
- border-color: #5bc8ed;
-}
-
-#popup-custom table,
-#content_settings table,
-#mapping-detail-table,
-#user-detail-table {
- width: 100%;
- table-layout: fixed;
- border-collapse: separate;
- border-spacing: 0 8px;
-}
-
-#popup-custom td,
-#content_settings td,
-#mapping-detail-table td,
-#user-detail-table td {
- padding: 2px 6px;
- vertical-align: middle;
-}
-
-#popup-custom td.left,
-#mapping-detail-table td.left,
-#user-detail-table td.left {
- width: 38%;
- color: var(--text-muted);
-}
-
-#popup-custom input[type=text],
-#popup-custom input[type=password],
-#mapping-detail input[type=text],
-#content_settings input[type=text],
-#content_settings input[type=password] {
- width: 100%;
-}
-
-#mapping-detail img {
- display: block;
- max-height: 44px;
- margin: 8px auto 12px;
-}
-
-#file-detail input[type=text] {
- width: 100%;
-}
-
-.interaction,
-#interaction {
- margin-top: 16px;
- display: flex;
- flex-wrap: wrap;
- align-items: center;
- gap: 8px;
- float: right;
-}
-
-.interaction input[type=button],
-.interaction input[type=submit] {
- margin: 0;
- min-width: 110px;
-}
-
-#popup-interaction {
- margin-top: 14px;
- display: flex;
- flex-wrap: wrap;
- justify-content: flex-end;
- gap: 8px;
-}
-
-#notification {
- position: fixed;
- right: 12px;
- top: 12px;
- width: 260px;
- max-height: calc(100vh - 24px);
- overflow: auto;
- border-radius: var(--radius-m);
- border: 1px solid var(--line);
- background: rgba(10, 22, 36, 0.92);
- box-shadow: var(--shadow-2);
-}
-
-#notification .element {
- margin: 8px;
- border-radius: 10px;
- border-left: 4px solid var(--ok);
- background: rgba(17, 35, 56, 0.84);
- padding: 8px;
-}
-
-#notification h5 {
- padding: 0;
- margin-bottom: 6px;
-}
-
-#notification p {
- font-size: 11px;
-}
-
.tableEllipsis {
width: 150px;
overflow: hidden;
@@ -718,81 +350,3 @@ input[type=checkbox]:checked:before {
transform: translateY(0) scale(1);
}
}
-
-@media only screen and (max-width: 619px) {
- h1 {
- font-size: 1.46rem;
- }
-
- #popup {
- padding: 0;
- }
-
- #popup-custom,
- #mapping-detail,
- #user-detail,
- #file-detail {
- max-width: none;
- width: 100%;
- height: 100%;
- max-height: 100%;
- border-radius: 0;
- border: 0;
- padding: 10px 10px calc(14px + env(safe-area-inset-bottom));
- }
-
- #popup-custom table {
- border-spacing: 0 10px;
- }
-
- #popup-custom tr {
- display: block;
- border: 1px solid var(--line-soft);
- border-radius: 10px;
- padding: 8px 8px 10px;
- background: rgba(12, 26, 42, 0.8);
- }
-
- #popup-custom td {
- display: block;
- width: 100%;
- padding: 4px 2px;
- }
-
- #popup-custom td.left {
- width: 100%;
- font-size: 11px;
- text-transform: uppercase;
- letter-spacing: 0.06em;
- }
-
- #popup-interaction {
- position: sticky;
- bottom: 0;
- z-index: 5;
- margin-top: 10px;
- padding-top: 10px;
- background: linear-gradient(180deg, rgba(12, 27, 44, 0.1) 0%, rgba(12, 27, 44, 0.96) 30%);
- }
-
- .interaction,
- #interaction {
- justify-content: stretch;
- }
-
- .interaction input[type=button],
- .interaction input[type=submit],
- #popup-interaction input[type=button] {
- width: 100%;
- min-height: 44px;
- }
-
- .popup-title h3 {
- font-size: 1.02rem;
- }
-
- .popup-close {
- min-width: 44px;
- min-height: 44px;
- }
-}
diff --git a/html/css/components.css b/html/css/components.css
new file mode 100644
index 0000000..b65e0bb
--- /dev/null
+++ b/html/css/components.css
@@ -0,0 +1,775 @@
+/*
+ * components.css - buttons, inputs, tables, status cards, connection
+ * indicator, popups, menu, log lines and badges. Loaded after base.css.
+ * Responsive overrides for these components live in layout.css.
+ */
+
+/* Buttons */
+
+input[type=button],
+input[type=submit],
+button {
+ cursor: pointer;
+ border: 1px solid transparent;
+ border-radius: 999px;
+ color: var(--text-on-accent);
+ padding: 10px 18px;
+ margin: 8px 8px 8px 0;
+ font-weight: 700;
+ letter-spacing: 0.03em;
+ background: var(--accent-gradient);
+ box-shadow: 0 10px 22px var(--accent-shadow);
+ transition: transform 0.15s ease, box-shadow 0.2s ease, filter 0.2s ease;
+}
+
+input[type=button]:hover,
+input[type=submit]:hover,
+button:hover {
+ transform: translateY(-1px);
+ filter: brightness(1.05);
+ box-shadow: 0 12px 24px var(--accent-shadow-strong);
+}
+
+input[type=button]:active,
+input[type=submit]:active,
+button:active {
+ transform: translateY(0);
+}
+
+input[type=button].delete {
+ color: var(--text-on-error);
+ background: linear-gradient(135deg, var(--error-bright) 0%, var(--error-strong) 100%);
+ box-shadow: 0 10px 20px var(--error-shadow);
+}
+
+input[type=button].cancel {
+ color: var(--error-text-soft);
+ border-color: var(--error-soft);
+ background: var(--error-surface);
+ box-shadow: none;
+}
+
+input[type=button].black,
+input[type=submit].black {
+ color: var(--text-heading);
+ border-color: var(--line);
+ background: var(--surface-raised);
+ box-shadow: none;
+}
+
+input[type=button].center {
+ margin-right: auto;
+ margin-left: auto;
+}
+
+input[type=button].save {
+ margin-left: auto;
+}
+
+/* Checkbox */
+
+input[type=checkbox] {
+ width: 20px;
+ height: 20px;
+ border: 1px solid var(--line);
+ border-radius: 6px;
+ background-color: var(--surface-input);
+ cursor: pointer;
+ position: relative;
+}
+
+input[type=checkbox]:checked {
+ border-color: var(--checkbox-checked-border);
+ background-color: var(--checkbox-checked);
+}
+
+input[type=checkbox]:before {
+ content: "";
+}
+
+input[type=checkbox]:checked:before {
+ content: "\2713";
+ color: var(--text-on-accent);
+ font-size: 14px;
+ font-weight: 800;
+ position: absolute;
+ top: -1px;
+ left: 3px;
+}
+
+/* Input states */
+
+.changed {
+ border-color: var(--accent-hover) !important;
+ box-shadow: 0 0 0 3px var(--accent-soft) !important;
+}
+
+.notAvailable {
+ opacity: 0.58;
+ cursor: not-allowed;
+ border-color: var(--error-soft) !important;
+}
+
+.wizard {
+ margin: 10px 0;
+}
+
+/* Sidebar menu */
+
+#branch {
+ min-height: 18px;
+ margin: 2px 0 6px;
+ text-align: center;
+ font-size: 11px;
+ color: var(--error-text);
+ letter-spacing: 0.08em;
+ text-transform: uppercase;
+}
+
+#main-menu {
+ display: flex;
+ flex-direction: column;
+ gap: 7px;
+ overflow: auto;
+ padding-right: 4px;
+}
+
+#main-menu li {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ min-height: 42px;
+ padding: 8px 11px;
+ border-radius: 12px;
+ border: 1px solid transparent;
+ background: var(--surface-1);
+}
+
+#main-menu li:hover {
+ border-color: var(--accent-soft);
+ transform: translateX(2px);
+}
+
+#main-menu li:focus-visible {
+ border-color: var(--accent-border);
+ transform: translateX(2px);
+ box-shadow: 0 0 0 3px var(--accent-soft);
+}
+
+#main-menu li.menu-active {
+ border-color: var(--accent-border);
+ background: var(--accent-gradient);
+ box-shadow: 0 10px 18px var(--accent-shadow);
+}
+
+#main-menu li.menu-active p {
+ color: var(--text-on-accent);
+}
+
+#main-menu li.menu-active img {
+ filter: brightness(0.04) saturate(120%);
+}
+
+nav img {
+ display: block;
+ width: 18px;
+ height: 18px;
+ max-width: 18px;
+ max-height: 18px;
+ flex: 0 0 auto;
+}
+
+nav p {
+ margin: 0;
+ padding: 0;
+ text-align: left;
+ font-size: 12px;
+ font-weight: 600;
+ color: var(--text-heading);
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+.menu-active {
+ color: var(--text-on-accent);
+}
+
+.menu {
+ border: 1px solid var(--accent);
+}
+
+/* Connection indicator */
+
+#connection-indicator {
+ margin-left: auto;
+ padding: 5px 11px;
+ border-radius: 999px;
+ font-size: 11px;
+ font-weight: 700;
+ letter-spacing: 0.05em;
+ text-transform: uppercase;
+}
+
+#connection-indicator.status-idle {
+ color: var(--text-heading);
+ border: 1px solid var(--line-strong);
+ background: var(--surface-raised);
+}
+
+#connection-indicator.status-busy {
+ color: var(--text-on-accent);
+ border: 1px solid var(--accent-bright);
+ background: var(--accent-gradient);
+}
+
+#connection-indicator.status-online {
+ color: var(--text-on-ok);
+ border: 1px solid var(--ok-border);
+ background: linear-gradient(135deg, var(--ok-bright) 0%, var(--ok-mid) 100%);
+}
+
+#connection-indicator.status-offline {
+ color: var(--text-on-error);
+ border: 1px solid var(--error-border);
+ background: linear-gradient(135deg, var(--error-bright) 0%, var(--error-strong) 100%);
+}
+
+/* Server info and stream tables */
+
+#clientInfo,
+#activeStreams,
+#inactiveStreams {
+ width: 100%;
+ border-collapse: separate;
+ border-spacing: 7px;
+ background: var(--surface-0);
+}
+
+#clientInfo {
+ padding: 7px 10px 6px;
+ border-bottom: 1px solid var(--line-soft);
+}
+
+#clientInfo tr {
+ vertical-align: top;
+}
+
+#clientInfo .tdKey,
+#clientInfo .tdVal,
+#activeStreams .tdKey,
+#inactiveStreams .tdKey,
+#activeStreams .tdVal,
+#inactiveStreams .tdVal,
+#logInfo .tdVal,
+#mappingInfo .tdVal {
+ border: 1px solid var(--line-soft);
+ border-radius: 8px;
+ padding: 7px 8px;
+ vertical-align: middle;
+ font-family: var(--font-mono);
+}
+
+#clientInfo .tdKey,
+#activeStreams .tdKey,
+#inactiveStreams .tdKey {
+ color: var(--accent-text);
+ font-size: 10px;
+ text-transform: uppercase;
+}
+
+#clientInfo .tdVal,
+#activeStreams .tdVal,
+#inactiveStreams .tdVal {
+ color: var(--text-muted);
+ font-size: 11px;
+ word-break: break-word;
+}
+
+#clientInfo .tdVal a {
+ color: var(--accent-text);
+ text-decoration: none;
+ border-bottom: 1px dotted var(--link-underline);
+ word-break: break-all;
+}
+
+#clientInfo .tdVal a:hover,
+#clientInfo .tdVal a:focus {
+ color: var(--accent-text-hover);
+ border-bottom-color: var(--accent-text-hover);
+ text-decoration: none;
+}
+
+#myStreamsBox {
+ border-bottom: 1px solid var(--line-soft);
+ background: var(--surface-1);
+ transition: all 0.2s ease;
+}
+
+#allStreams {
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ gap: 8px;
+ padding: 8px;
+}
+
+#activeStreams,
+#inactiveStreams {
+ max-height: 120px;
+ overflow-y: auto;
+}
+
+#inactiveStreams .tdKey {
+ color: var(--error-text);
+}
+
+/* Status cards */
+
+.dashboard-cards {
+ display: grid;
+ grid-template-columns: repeat(6, minmax(130px, 1fr));
+ gap: 9px;
+ padding: 10px 14px;
+ border-bottom: 1px solid var(--line-soft);
+ background: var(--surface-0);
+}
+
+.status-card {
+ border: 1px solid var(--line-soft);
+ border-radius: 12px;
+ background: var(--surface-2);
+ padding: 10px;
+ min-height: 74px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ gap: 4px;
+}
+
+.status-card-label {
+ color: var(--text-soft);
+ font-size: 10px;
+ text-transform: uppercase;
+ letter-spacing: 0.07em;
+}
+
+.status-card-value {
+ color: var(--text);
+ font-size: 14px;
+ font-weight: 700;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+.status-card.status-card-ok {
+ border-color: var(--ok-soft);
+ background: linear-gradient(180deg, var(--ok-surface-top) 0%, var(--ok-surface-bottom) 100%);
+}
+
+.status-card.status-card-warn {
+ border-color: var(--warn-soft);
+ background: linear-gradient(180deg, var(--warn-surface-top) 0%, var(--warn-surface-bottom) 100%);
+}
+
+.status-card.status-card-error {
+ border-color: var(--error-soft);
+ background: linear-gradient(180deg, var(--error-surface-top) 0%, var(--error-surface-bottom) 100%);
+}
+
+/* Content table */
+
+#box-wrapper {
+ width: 100%;
+ overflow: auto;
+ border: 1px solid var(--line-soft);
+ border-radius: 12px;
+ background: var(--surface-1);
+}
+
+#content_table {
+ width: 100%;
+ border-collapse: collapse;
+}
+
+#content_table .content_table_header {
+ position: sticky;
+ top: 0;
+ z-index: 2;
+ background: linear-gradient(180deg, var(--table-head-top), var(--table-head-bottom));
+ border-bottom: 1px solid var(--line);
+}
+
+#content_table .content_table_header td {
+ color: var(--accent-text);
+ font-size: 11px;
+ text-transform: uppercase;
+ letter-spacing: 0.07em;
+ padding: 10px 8px;
+}
+
+#content_table tr {
+ border-left: 3px solid transparent;
+ border-bottom: 1px solid var(--row-line);
+ transition: background-color 0.2s ease;
+}
+
+#content_table tr:hover {
+ background-color: var(--row-hover);
+}
+
+#content_table tr[tabindex],
+#content_table td[tabindex] {
+ cursor: pointer;
+}
+
+#content_table tr[tabindex]:focus-visible,
+#content_table td[tabindex]:focus-visible,
+.keyboard-clickable:focus-visible {
+ outline: 2px solid var(--focus-ring);
+ outline-offset: -2px;
+ background-color: var(--row-focus);
+}
+
+#content_table td {
+ padding: 7px 8px;
+ vertical-align: middle;
+}
+
+#content_table img {
+ display: block;
+ width: auto;
+ max-width: 34px;
+ max-height: 30px;
+ margin: 0 auto;
+}
+
+#content_table input[type=text] {
+ min-width: 48px;
+ max-width: 76px;
+ margin: 0;
+ padding: 6px 7px;
+ border-radius: 8px;
+ text-align: left;
+}
+
+#content_table input[type=checkbox] {
+ margin: 0 auto;
+}
+
+#content_table .mapping-edit-button {
+ min-height: 32px;
+ min-width: 64px;
+ margin: 0;
+ padding: 5px 10px;
+ font-size: 11px;
+ line-height: 1;
+}
+
+#content_table tr.activeEPG {
+ border-left-color: var(--ok);
+}
+
+#content_table tr.notActiveEPG {
+ border-left-color: var(--error);
+}
+
+/* Settings */
+
+#settings {
+ padding: 10px;
+}
+
+#content_settings h4 {
+ margin: 15px 0 8px;
+ color: var(--text-heading);
+}
+
+#content_settings table {
+ border: 1px solid var(--line-soft);
+ border-radius: 12px;
+ background: var(--surface-1);
+ overflow: hidden;
+}
+
+#content_settings td {
+ border-bottom: 1px solid var(--row-line);
+}
+
+#content_settings tr:last-child td {
+ border-bottom: 0;
+}
+
+#content_settings pre {
+ color: var(--text-soft);
+ font-size: 11px;
+}
+
+/* Popup and detail tables */
+
+#popup-custom table,
+#content_settings table,
+#mapping-detail-table,
+#user-detail-table {
+ width: 100%;
+ table-layout: fixed;
+ border-collapse: separate;
+ border-spacing: 0 8px;
+}
+
+#popup-custom td,
+#content_settings td,
+#mapping-detail-table td,
+#user-detail-table td {
+ padding: 2px 6px;
+ vertical-align: middle;
+}
+
+#popup-custom td.left,
+#mapping-detail-table td.left,
+#user-detail-table td.left {
+ width: 38%;
+ color: var(--text-muted);
+}
+
+#popup-custom input[type=text],
+#popup-custom input[type=password],
+#mapping-detail input[type=text],
+#content_settings input[type=text],
+#content_settings input[type=password] {
+ width: 100%;
+}
+
+#mapping-detail img {
+ display: block;
+ max-height: 44px;
+ margin: 8px auto 12px;
+}
+
+#file-detail input[type=text] {
+ width: 100%;
+}
+
+/* Loading and popups */
+
+#loading {
+ position: fixed;
+ inset: 0;
+ z-index: 2000;
+ background-color: var(--overlay);
+ backdrop-filter: blur(1.5px);
+}
+
+.loader {
+ width: 52px;
+ height: 52px;
+ border-radius: 50%;
+ border: 4px solid transparent;
+ border-top-color: var(--loader);
+ border-right-color: var(--accent-strong);
+ animation: spin 0.9s linear infinite;
+ position: fixed;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ left: 0;
+ margin: auto;
+}
+
+#popup {
+ position: fixed;
+ inset: 0;
+ background-color: var(--overlay);
+ backdrop-filter: blur(2px);
+ z-index: 1500;
+ padding: 16px;
+}
+
+#popup-custom,
+#mapping-detail,
+#user-detail,
+#file-detail {
+ margin: 0 auto;
+ max-width: 760px;
+ max-height: calc(100vh - 36px);
+ overflow: auto;
+ border-radius: var(--radius-l);
+ border: 1px solid var(--line);
+ background: linear-gradient(180deg, var(--panel-top) 0%, var(--panel-bottom) 100%);
+ box-shadow: var(--shadow-1);
+ padding: 16px;
+ animation: popupIn 0.2s ease;
+}
+
+#popup-custom h3 {
+ margin-bottom: 8px;
+ text-align: center;
+ color: var(--text-heading);
+}
+
+.popup-title {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 10px;
+ margin-bottom: 10px;
+}
+
+.popup-title h3 {
+ margin: 0;
+ text-align: left;
+}
+
+#popup-custom .popup-title h3 {
+ margin: 0;
+ text-align: left;
+}
+
+.popup-close {
+ min-width: 40px;
+ min-height: 40px;
+ margin: 0;
+ padding: 0;
+ border-radius: 999px;
+ border: 1px solid var(--line);
+ color: var(--text-heading);
+ background: var(--surface-raised);
+ box-shadow: none;
+ font-size: 20px;
+ line-height: 1;
+}
+
+.popup-close:hover {
+ color: var(--text);
+ border-color: var(--accent);
+}
+
+.interaction,
+#interaction {
+ margin-top: 16px;
+ display: flex;
+ flex-wrap: wrap;
+ align-items: center;
+ gap: 8px;
+ float: right;
+}
+
+.interaction input[type=button],
+.interaction input[type=submit] {
+ margin: 0;
+ min-width: 110px;
+}
+
+#popup-interaction {
+ margin-top: 14px;
+ display: flex;
+ flex-wrap: wrap;
+ justify-content: flex-end;
+ gap: 8px;
+}
+
+/* Notifications */
+
+#notification {
+ position: fixed;
+ right: 12px;
+ top: 12px;
+ width: 260px;
+ max-height: calc(100vh - 24px);
+ overflow: auto;
+ border-radius: var(--radius-m);
+ border: 1px solid var(--line);
+ background: var(--surface-solid);
+ box-shadow: var(--shadow-2);
+}
+
+#notification .element {
+ margin: 8px;
+ border-radius: 10px;
+ border-left: 4px solid var(--ok);
+ background: var(--surface-3);
+ padding: 8px;
+}
+
+#notification h5 {
+ padding: 0;
+ margin-bottom: 6px;
+}
+
+#notification p {
+ font-size: 11px;
+}
+
+/* Log lines */
+
+#content_log {
+ padding: 8px;
+}
+
+#content_log pre {
+ margin-bottom: 5px;
+ padding: 8px;
+ border-radius: 8px;
+ background: var(--surface-1);
+ white-space: pre-wrap;
+ overflow-wrap: anywhere;
+ word-break: break-word;
+ line-height: 1.45;
+}
+
+#logScreen p {
+ white-space: pre;
+ font-family: var(--font-mono);
+ font-size: 12px;
+ line-height: 1.55;
+}
+
+.screenLogHidden {
+ transform: translate(0, -110px);
+}
+
+.infoMsg {
+ color: var(--info);
+}
+
+.errorMsg {
+ color: var(--error-text);
+}
+
+.warningMsg {
+ color: var(--warn);
+}
+
+.debugMsg {
+ color: var(--debug);
+}
+
+/* Category badges */
+
+.News,
+.Movie,
+.Series,
+.Sports,
+.Kids {
+ border-left: 3px solid transparent;
+ padding-left: 8px;
+}
+
+.News {
+ border-color: #ff8f6e;
+}
+
+.Movie {
+ border-color: #46a4ff;
+}
+
+.Series {
+ border-color: #ffd267;
+}
+
+.Sports {
+ border-color: #5ee495;
+}
+
+.Kids {
+ border-color: #f6a8ff;
+}
diff --git a/html/css/screen.css b/html/css/layout.css
similarity index 52%
rename from html/css/screen.css
rename to html/css/layout.css
index 1f26d0b..efd5a56 100644
--- a/html/css/screen.css
+++ b/html/css/layout.css
@@ -1,3 +1,10 @@
+/*
+ * layout.css - shell layout (sidebar, header, content wrapper), the auth /
+ * wizard box pages and every responsive breakpoint. Loaded last.
+ */
+
+/* Application shell */
+
#layout {
display: grid;
grid-template-columns: 290px minmax(0, 1fr);
@@ -15,8 +22,8 @@
border-radius: var(--radius-l);
border: 1px solid var(--line);
background:
- linear-gradient(180deg, rgba(18, 36, 58, 0.95) 0%, rgba(10, 23, 38, 0.95) 100%),
- radial-gradient(circle at 20% 0%, rgba(53, 210, 255, 0.12), transparent 48%);
+ linear-gradient(180deg, var(--panel-top) 0%, var(--panel-bottom) 100%),
+ radial-gradient(circle at 20% 0%, var(--panel-glow), transparent 48%);
box-shadow: var(--shadow-2);
overflow: hidden;
}
@@ -28,100 +35,25 @@
padding: 14px;
}
-#branch {
- min-height: 18px;
- margin: 2px 0 6px;
- text-align: center;
- font-size: 11px;
- color: #ff9f8d;
- letter-spacing: 0.08em;
- text-transform: uppercase;
-}
-
#logo {
width: 100%;
height: 76px;
border-radius: 12px;
border: 1px solid var(--line-soft);
background:
- linear-gradient(180deg, rgba(26, 49, 73, 0.55), rgba(13, 28, 45, 0.6)),
+ linear-gradient(180deg, var(--logo-tint-top), var(--logo-tint-bottom)),
url("../img/logo_w_600x200.png") center no-repeat;
background-size: contain;
margin-bottom: 12px;
}
-#main-menu {
- display: flex;
- flex-direction: column;
- gap: 7px;
- overflow: auto;
- padding-right: 4px;
-}
-
-#main-menu li {
- display: flex;
- align-items: center;
- gap: 10px;
- min-height: 42px;
- padding: 8px 11px;
- border-radius: 12px;
- border: 1px solid transparent;
- background: rgba(11, 25, 40, 0.58);
-}
-
-#main-menu li:hover {
- border-color: var(--accent-soft);
- transform: translateX(2px);
-}
-
-#main-menu li:focus-visible {
- border-color: rgba(103, 232, 255, 0.62);
- transform: translateX(2px);
- box-shadow: 0 0 0 3px rgba(53, 210, 255, 0.23);
-}
-
-#main-menu li.menu-active {
- border-color: rgba(103, 232, 255, 0.55);
- background: linear-gradient(135deg, #6fe6ff 0%, #1cc5ff 100%);
- box-shadow: 0 10px 18px rgba(28, 197, 255, 0.3);
-}
-
-#main-menu li.menu-active p {
- color: #03111a;
-}
-
-#main-menu li.menu-active img {
- filter: brightness(0.04) saturate(120%);
-}
-
-nav img {
- display: block;
- width: 18px;
- height: 18px;
- max-width: 18px;
- max-height: 18px;
- flex: 0 0 auto;
-}
-
-nav p {
- margin: 0;
- padding: 0;
- text-align: left;
- font-size: 12px;
- font-weight: 600;
- color: #d7eefe;
- white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
-}
-
.layout-right {
min-width: 0;
border-radius: var(--radius-l);
border: 1px solid var(--line);
background:
- linear-gradient(180deg, rgba(17, 34, 54, 0.94) 0%, rgba(10, 20, 34, 0.96) 100%),
- radial-gradient(circle at 100% 0%, rgba(53, 210, 255, 0.08), transparent 34%);
+ linear-gradient(180deg, var(--panel-top) 0%, var(--panel-bottom) 100%),
+ radial-gradient(circle at 100% 0%, var(--panel-glow), transparent 34%);
box-shadow: var(--shadow-2);
display: flex;
flex-direction: column;
@@ -134,14 +66,14 @@ nav p {
gap: 12px;
padding: 12px 14px;
border-bottom: 1px solid var(--line-soft);
- background: rgba(10, 22, 36, 0.52);
+ background: var(--surface-0);
}
#shell-title {
margin: 0;
font-size: 1.08rem;
font-weight: 700;
- color: #d8f1ff;
+ color: var(--text-heading);
letter-spacing: 0.04em;
}
@@ -153,176 +85,7 @@ nav p {
font-size: 12px;
}
-#connection-indicator {
- margin-left: auto;
- padding: 5px 11px;
- border-radius: 999px;
- font-size: 11px;
- font-weight: 700;
- letter-spacing: 0.05em;
- text-transform: uppercase;
-}
-
-#connection-indicator.status-idle {
- color: #d8edff;
- border: 1px solid #3a5877;
- background: rgba(20, 42, 66, 0.65);
-}
-
-#connection-indicator.status-busy {
- color: #072031;
- border: 1px solid #7ee8ff;
- background: linear-gradient(135deg, #7be8ff 0%, #33cdff 100%);
-}
-
-#connection-indicator.status-online {
- color: #052219;
- border: 1px solid #9ff0c8;
- background: linear-gradient(135deg, #92f0c0 0%, #4fce93 100%);
-}
-
-#connection-indicator.status-offline {
- color: #ffe5e5;
- border: 1px solid #ff9e9e;
- background: linear-gradient(135deg, #ff7e7e 0%, #d34d4d 100%);
-}
-
-#clientInfo,
-#activeStreams,
-#inactiveStreams {
- width: 100%;
- border-collapse: separate;
- border-spacing: 7px;
- background: rgba(8, 20, 33, 0.54);
-}
-
-#clientInfo {
- padding: 7px 10px 6px;
- border-bottom: 1px solid var(--line-soft);
-}
-
-#clientInfo tr {
- vertical-align: top;
-}
-
-#clientInfo .tdKey,
-#clientInfo .tdVal,
-#activeStreams .tdKey,
-#inactiveStreams .tdKey,
-#activeStreams .tdVal,
-#inactiveStreams .tdVal,
-#logInfo .tdVal,
-#mappingInfo .tdVal {
- border: 1px solid var(--line-soft);
- border-radius: 8px;
- padding: 7px 8px;
- vertical-align: middle;
- font-family: "IBM Plex Mono", "SFMono-Regular", "Consolas", monospace;
-}
-
-#clientInfo .tdKey,
-#activeStreams .tdKey,
-#inactiveStreams .tdKey {
- color: #53d9ff;
- font-size: 10px;
- text-transform: uppercase;
-}
-
-#clientInfo .tdVal,
-#activeStreams .tdVal,
-#inactiveStreams .tdVal {
- color: var(--text-muted);
- font-size: 11px;
- word-break: break-word;
-}
-
-#clientInfo .tdVal a {
- color: #8fdcff;
- text-decoration: none;
- border-bottom: 1px dotted rgba(143, 220, 255, 0.6);
- word-break: break-all;
-}
-
-#clientInfo .tdVal a:hover,
-#clientInfo .tdVal a:focus {
- color: #d7f4ff;
- border-bottom-color: #d7f4ff;
- text-decoration: none;
-}
-
-.dashboard-cards {
- display: grid;
- grid-template-columns: repeat(6, minmax(130px, 1fr));
- gap: 9px;
- padding: 10px 14px;
- border-bottom: 1px solid var(--line-soft);
- background: rgba(8, 18, 30, 0.45);
-}
-
-.status-card {
- border: 1px solid var(--line-soft);
- border-radius: 12px;
- background: rgba(13, 31, 49, 0.8);
- padding: 10px;
- min-height: 74px;
- display: flex;
- flex-direction: column;
- justify-content: center;
- gap: 4px;
-}
-
-.status-card-label {
- color: #8fb3cf;
- font-size: 10px;
- text-transform: uppercase;
- letter-spacing: 0.07em;
-}
-
-.status-card-value {
- color: #e8f5ff;
- font-size: 14px;
- font-weight: 700;
- overflow: hidden;
- text-overflow: ellipsis;
-}
-
-.status-card.status-card-ok {
- border-color: rgba(67, 191, 130, 0.48);
- background: linear-gradient(180deg, rgba(20, 54, 44, 0.9) 0%, rgba(12, 38, 31, 0.95) 100%);
-}
-
-.status-card.status-card-warn {
- border-color: rgba(255, 193, 90, 0.5);
- background: linear-gradient(180deg, rgba(68, 50, 20, 0.86) 0%, rgba(44, 32, 14, 0.96) 100%);
-}
-
-.status-card.status-card-error {
- border-color: rgba(255, 111, 111, 0.5);
- background: linear-gradient(180deg, rgba(73, 26, 26, 0.84) 0%, rgba(47, 19, 19, 0.96) 100%);
-}
-
-#myStreamsBox {
- border-bottom: 1px solid var(--line-soft);
- background: rgba(10, 22, 36, 0.62);
- transition: all 0.2s ease;
-}
-
-#allStreams {
- display: grid;
- grid-template-columns: 1fr 1fr;
- gap: 8px;
- padding: 8px;
-}
-
-#activeStreams,
-#inactiveStreams {
- max-height: 120px;
- overflow-y: auto;
-}
-
-#inactiveStreams .tdKey {
- color: #ff8f8f;
-}
+/* Content wrapper */
#content {
display: block;
@@ -332,7 +95,7 @@ nav p {
#content h3 {
margin-bottom: 6px;
- color: #d4edff;
+ color: var(--text-heading);
}
#content-interaction {
@@ -353,162 +116,14 @@ nav p {
display: none;
}
-#box-wrapper {
- width: 100%;
- overflow: auto;
- border: 1px solid var(--line-soft);
- border-radius: 12px;
- background: rgba(10, 21, 34, 0.72);
-}
-
-#content_table,
-#mapping-detail-table {
- width: 100%;
- border-collapse: collapse;
-}
-
-#content_table .content_table_header {
- position: sticky;
- top: 0;
- z-index: 2;
- background: linear-gradient(180deg, rgba(23, 46, 72, 0.98), rgba(16, 32, 50, 0.98));
- border-bottom: 1px solid var(--line);
-}
-
-#content_table .content_table_header td {
- color: #8fd8ff;
- font-size: 11px;
- text-transform: uppercase;
- letter-spacing: 0.07em;
- padding: 10px 8px;
-}
-
-#content_table tr {
- border-left: 3px solid transparent;
- border-bottom: 1px solid rgba(29, 55, 80, 0.72);
- transition: background-color 0.2s ease;
-}
-
-#content_table tr:hover {
- background-color: rgba(28, 53, 79, 0.5);
-}
-
-#content_table tr[tabindex],
-#content_table td[tabindex] {
- cursor: pointer;
-}
-
-#content_table tr[tabindex]:focus-visible,
-#content_table td[tabindex]:focus-visible,
-.keyboard-clickable:focus-visible {
- outline: 2px solid #7de5ff;
- outline-offset: -2px;
- background-color: rgba(39, 73, 106, 0.56);
-}
-
-#content_table td {
- padding: 7px 8px;
- vertical-align: middle;
-}
-
-#content_table img {
- display: block;
- width: auto;
- max-width: 34px;
- max-height: 30px;
- margin: 0 auto;
-}
-
-#content_table input[type=text] {
- min-width: 48px;
- max-width: 76px;
- margin: 0;
- padding: 6px 7px;
- border-radius: 8px;
- text-align: left;
-}
-
-#content_table input[type=checkbox] {
- margin: 0 auto;
-}
-
-#content_table .mapping-edit-button {
- min-height: 32px;
- min-width: 64px;
- margin: 0;
- padding: 5px 10px;
- font-size: 11px;
- line-height: 1;
-}
-
-#content_table tr.activeEPG {
- border-left-color: #2ed486;
-}
-
-#content_table tr.notActiveEPG {
- border-left-color: #ff6868;
-}
-
-#settings {
- padding: 10px;
-}
-
-#content_settings h4 {
- margin: 15px 0 8px;
- color: #d6efff;
-}
-
-#content_settings table {
- border: 1px solid var(--line-soft);
- border-radius: 12px;
- background: rgba(10, 22, 35, 0.62);
- border-collapse: separate;
- border-spacing: 0;
- overflow: hidden;
-}
-
-#content_settings td {
- padding: 9px 8px;
- border-bottom: 1px solid rgba(31, 57, 82, 0.62);
-}
-
-#content_settings tr:last-child td {
- border-bottom: 0;
-}
-
-#content_settings pre {
- color: #9ab7d0;
- font-size: 11px;
-}
-
-#content_log {
- padding: 8px;
-}
-
-#content_log pre {
- margin-bottom: 5px;
- padding: 8px;
- border-radius: 8px;
- background: rgba(13, 31, 49, 0.72);
- white-space: pre-wrap;
- overflow-wrap: anywhere;
- word-break: break-word;
- line-height: 1.45;
-}
-
-#logScreen p {
- white-space: pre;
- font-family: "IBM Plex Mono", "SFMono-Regular", "Consolas", monospace;
- font-size: 12px;
- line-height: 1.55;
-}
+/* Login, first-user, wizard and maintenance box */
#box {
width: min(680px, calc(100% - 24px));
margin: 14px auto;
border-radius: var(--radius-l);
border: 1px solid var(--line);
- background: linear-gradient(180deg, rgba(16, 35, 56, 0.95) 0%, rgba(11, 24, 38, 0.96) 100%);
+ background: linear-gradient(180deg, var(--panel-top) 0%, var(--panel-bottom) 100%);
box-shadow: var(--shadow-2);
min-height: 430px;
display: flex;
@@ -523,14 +138,14 @@ nav p {
border-radius: 12px;
border: 1px solid var(--line);
background:
- linear-gradient(180deg, rgba(16, 35, 56, 0.84), rgba(11, 24, 38, 0.9)),
+ linear-gradient(180deg, var(--logo-tint-top), var(--logo-tint-bottom)),
url("../img/logo_w_600x200.png") center no-repeat;
background-size: 300px auto;
}
#headline {
border-bottom: 1px solid var(--line);
- background: rgba(10, 22, 37, 0.55);
+ background: var(--surface-0);
padding: 14px;
}
@@ -560,10 +175,6 @@ nav p {
min-width: 120px;
}
-.wizard {
- margin: 10px 0;
-}
-
.auth-screen {
display: flex;
flex-direction: column;
@@ -578,6 +189,8 @@ nav p {
display: table-cell;
}
+/* Breakpoints */
+
@media only screen and (max-width: 1300px) {
.dashboard-cards {
grid-template-columns: repeat(3, minmax(130px, 1fr));
@@ -622,7 +235,7 @@ nav p {
inset: 0;
z-index: 1000;
pointer-events: none;
- background: rgba(3, 9, 15, 0.48);
+ background: var(--overlay-soft);
opacity: 0;
transition: opacity 0.2s ease;
}
@@ -698,7 +311,7 @@ nav p {
padding: 8px;
border: 1px solid var(--line-soft);
border-radius: 12px;
- background: rgba(9, 22, 36, 0.92);
+ background: var(--surface-solid);
backdrop-filter: blur(6px);
}
@@ -771,7 +384,7 @@ nav p {
gap: 8px;
border-spacing: 0;
white-space: normal;
- background: rgba(8, 20, 33, 0.44);
+ background: var(--surface-0);
}
#clientInfo tr {
@@ -791,16 +404,16 @@ nav p {
justify-content: center;
gap: 4px;
padding: 10px 9px;
- background: rgba(17, 34, 53, 0.5);
+ background: var(--surface-2);
}
#clientInfo .tdVal::before {
content: attr(data-label);
- color: #8bb9d7;
+ color: var(--text-soft);
font-size: 9px;
letter-spacing: 0.07em;
text-transform: uppercase;
- font-family: "Space Grotesk", "Avenir Next", "Trebuchet MS", sans-serif;
+ font-family: var(--font-sans);
line-height: 1.2;
}
@@ -829,7 +442,7 @@ nav p {
border-radius: 12px;
margin-bottom: 10px;
padding: 6px;
- background: rgba(11, 24, 39, 0.86);
+ background: var(--surface-3);
}
#content_table td {
@@ -841,12 +454,12 @@ nav p {
grid-template-columns: minmax(92px, 36%) 1fr;
align-items: center;
gap: 8px;
- background: rgba(17, 34, 53, 0.5);
+ background: var(--surface-2);
}
#content_table td::before {
content: attr(data-label);
- color: #8bb9d7;
+ color: var(--text-soft);
font-size: 10px;
letter-spacing: 0.06em;
text-transform: uppercase;
@@ -967,6 +580,84 @@ nav p {
}
}
+@media only screen and (max-width: 619px) {
+ h1 {
+ font-size: 1.46rem;
+ }
+
+ #popup {
+ padding: 0;
+ }
+
+ #popup-custom,
+ #mapping-detail,
+ #user-detail,
+ #file-detail {
+ max-width: none;
+ width: 100%;
+ height: 100%;
+ max-height: 100%;
+ border-radius: 0;
+ border: 0;
+ padding: 10px 10px calc(14px + env(safe-area-inset-bottom));
+ }
+
+ #popup-custom table {
+ border-spacing: 0 10px;
+ }
+
+ #popup-custom tr {
+ display: block;
+ border: 1px solid var(--line-soft);
+ border-radius: 10px;
+ padding: 8px 8px 10px;
+ background: var(--surface-2);
+ }
+
+ #popup-custom td {
+ display: block;
+ width: 100%;
+ padding: 4px 2px;
+ }
+
+ #popup-custom td.left {
+ width: 100%;
+ font-size: 11px;
+ text-transform: uppercase;
+ letter-spacing: 0.06em;
+ }
+
+ #popup-interaction {
+ position: sticky;
+ bottom: 0;
+ z-index: 5;
+ margin-top: 10px;
+ padding-top: 10px;
+ background: linear-gradient(180deg, var(--sticky-fade-from) 0%, var(--sticky-fade-to) 30%);
+ }
+
+ .interaction,
+ #interaction {
+ justify-content: stretch;
+ }
+
+ .interaction input[type=button],
+ .interaction input[type=submit],
+ #popup-interaction input[type=button] {
+ width: 100%;
+ min-height: 44px;
+ }
+
+ .popup-title h3 {
+ font-size: 1.02rem;
+ }
+
+ .popup-close {
+ min-width: 44px;
+ min-height: 44px;
+ }
+}
+
@media only screen and (max-width: 430px) {
#clientInfo {
grid-template-columns: 1fr;
diff --git a/html/css/tokens.css b/html/css/tokens.css
new file mode 100644
index 0000000..a68ca39
--- /dev/null
+++ b/html/css/tokens.css
@@ -0,0 +1,313 @@
+/*
+ * tokens.css - design tokens (colours, spacing, radii, fonts, shadows).
+ *
+ * Load order: tokens.css, base.css, components.css, layout.css.
+ *
+ * The dark palette is the default. A light palette is applied when the user
+ * agent prefers a light colour scheme, and either palette can be forced with
+ * or , which always wins
+ * over the media query. Only colour tokens change between themes.
+ */
+
+:root {
+ color-scheme: dark;
+
+ /* Fonts */
+ --font-sans: "Space Grotesk", "Avenir Next", "Trebuchet MS", sans-serif;
+ --font-mono: "IBM Plex Mono", "SFMono-Regular", "Consolas", monospace;
+
+ /* Radii and shadows */
+ --radius-s: 10px;
+ --radius-m: 14px;
+ --radius-l: 18px;
+ --shadow-1: 0 20px 45px rgba(0, 0, 0, 0.32);
+ --shadow-2: 0 12px 30px rgba(0, 0, 0, 0.28);
+
+ /* Page background */
+ --bg-0: #07111d;
+ --bg-1: #0c1a2b;
+ --bg-2: #12233a;
+ --bg-deep: #060d17;
+ --bg-glow-1: rgba(64, 132, 183, 0.22);
+ --bg-glow-2: rgba(18, 185, 255, 0.16);
+
+ /* Panels and surfaces (translucent tints layered over the page) */
+ --panel-top: rgba(17, 34, 56, 0.97);
+ --panel-bottom: rgba(12, 27, 44, 0.97);
+ --panel-glow: rgba(53, 210, 255, 0.12);
+ --surface-0: rgba(8, 20, 33, 0.54);
+ --surface-1: rgba(10, 22, 36, 0.72);
+ --surface-2: rgba(13, 31, 49, 0.8);
+ --surface-3: rgba(17, 35, 56, 0.84);
+ --surface-solid: rgba(10, 22, 36, 0.92);
+ --surface-raised: rgba(14, 32, 50, 0.85);
+ --surface-input: rgba(10, 22, 36, 0.78);
+ --surface-input-focus: rgba(9, 25, 40, 0.95);
+ --logo-tint-top: rgba(26, 49, 73, 0.55);
+ --logo-tint-bottom: rgba(13, 28, 45, 0.6);
+ --table-head-top: rgba(23, 46, 72, 0.98);
+ --table-head-bottom: rgba(16, 32, 50, 0.98);
+ --row-line: rgba(29, 55, 80, 0.72);
+ --row-hover: rgba(28, 53, 79, 0.5);
+ --row-focus: rgba(39, 73, 106, 0.56);
+ --overlay: rgba(3, 9, 16, 0.72);
+ --overlay-soft: rgba(3, 9, 15, 0.48);
+ --sticky-fade-from: rgba(12, 27, 44, 0.1);
+ --sticky-fade-to: rgba(12, 27, 44, 0.96);
+ --scroll-track: rgba(7, 17, 29, 0.65);
+ --scroll-thumb-a: #2d597f;
+ --scroll-thumb-b: #1e4060;
+ --scroll-thumb-hover-a: #3678ac;
+ --scroll-thumb-hover-b: #20537c;
+
+ /* Lines */
+ --line: #274462;
+ --line-soft: #1b334d;
+ --line-strong: #3a5877;
+
+ /* Text */
+ --text: #e9f5ff;
+ --text-heading: #d6efff;
+ --text-muted: #b7cee1;
+ --text-soft: #8fb3cf;
+ --text-placeholder: #7e9ab4;
+ --text-on-accent: #03101a;
+ --text-on-ok: #052219;
+ --text-on-error: #ffe5e5;
+
+ /* Accent */
+ --accent: #35d2ff;
+ --accent-strong: #12b9ff;
+ --accent-bright: #67e8ff;
+ --accent-hover: #8de7ff;
+ --accent-text: #8fd8ff;
+ --accent-text-hover: #d7f4ff;
+ --accent-soft: rgba(53, 210, 255, 0.2);
+ --accent-ring: rgba(53, 210, 255, 0.17);
+ --accent-border: rgba(103, 232, 255, 0.55);
+ --accent-shadow: rgba(18, 185, 255, 0.3);
+ --accent-shadow-strong: rgba(18, 185, 255, 0.36);
+ --accent-gradient: linear-gradient(135deg, var(--accent-bright) 0%, var(--accent-strong) 100%);
+ --link-underline: rgba(143, 220, 255, 0.6);
+ --focus-ring: #7de5ff;
+ --focus-ring-soft: #91eaff;
+ --checkbox-checked: #39d6ff;
+ --checkbox-checked-border: #89ebff;
+ --loader: #58ddff;
+
+ /* Status */
+ --ok: #2fd18a;
+ --ok-bright: #92f0c0;
+ --ok-mid: #4fce93;
+ --ok-border: #9ff0c8;
+ --ok-soft: rgba(67, 191, 130, 0.48);
+ --ok-surface-top: rgba(20, 54, 44, 0.9);
+ --ok-surface-bottom: rgba(12, 38, 31, 0.95);
+ --warn: #ffc15a;
+ --warn-soft: rgba(255, 193, 90, 0.5);
+ --warn-surface-top: rgba(68, 50, 20, 0.86);
+ --warn-surface-bottom: rgba(44, 32, 14, 0.96);
+ --error: #ff6f6f;
+ --error-text: #ff8d8d;
+ --error-text-soft: #ffd8d8;
+ --error-bright: #ff7f7f;
+ --error-strong: #e94343;
+ --error-border: #ff9e9e;
+ --error-soft: rgba(255, 111, 111, 0.45);
+ --error-surface: rgba(87, 22, 22, 0.45);
+ --error-surface-top: rgba(73, 26, 26, 0.84);
+ --error-surface-bottom: rgba(47, 19, 19, 0.96);
+ --error-shadow: rgba(233, 67, 67, 0.35);
+ --info: #87b0d1;
+ --debug: #d687ff;
+}
+
+/*
+ * Light palette. Only tokens that differ from the dark palette are listed.
+ * The same block appears twice on purpose: once for the media query (skipped
+ * when dark is forced with data-theme="dark") and once for the explicit
+ * data-theme="light" override. Keep the two copies identical.
+ */
+@media (prefers-color-scheme: light) {
+ :root:not([data-theme="dark"]) {
+ color-scheme: light;
+
+ --bg-0: #e9eff5;
+ --bg-1: #f5f8fb;
+ --bg-2: #dfe7ef;
+ --bg-deep: #dfe7ef;
+ --bg-glow-1: rgba(64, 132, 183, 0.14);
+ --bg-glow-2: rgba(18, 185, 255, 0.12);
+
+ --panel-top: rgba(255, 255, 255, 0.97);
+ --panel-bottom: rgba(246, 249, 252, 0.97);
+ --panel-glow: rgba(18, 185, 255, 0.08);
+ --surface-0: rgba(255, 255, 255, 0.55);
+ --surface-1: rgba(255, 255, 255, 0.75);
+ --surface-2: rgba(236, 243, 249, 0.85);
+ --surface-3: rgba(232, 240, 247, 0.9);
+ --surface-solid: rgba(255, 255, 255, 0.94);
+ --surface-raised: rgba(228, 236, 244, 0.9);
+ --surface-input: rgba(255, 255, 255, 0.85);
+ --surface-input-focus: rgba(255, 255, 255, 1);
+ --logo-tint-top: rgba(15, 31, 48, 0.96);
+ --logo-tint-bottom: rgba(11, 23, 39, 0.98);
+ --table-head-top: rgba(232, 240, 248, 0.98);
+ --table-head-bottom: rgba(222, 232, 243, 0.98);
+ --row-line: rgba(100, 130, 160, 0.3);
+ --row-hover: rgba(0, 90, 150, 0.07);
+ --row-focus: rgba(0, 90, 150, 0.14);
+ --overlay: rgba(20, 35, 52, 0.5);
+ --overlay-soft: rgba(20, 35, 52, 0.35);
+ --sticky-fade-from: rgba(246, 249, 252, 0.1);
+ --sticky-fade-to: rgba(246, 249, 252, 0.96);
+ --scroll-track: rgba(200, 214, 228, 0.6);
+ --scroll-thumb-a: #9fb6cb;
+ --scroll-thumb-b: #7f9bb3;
+ --scroll-thumb-hover-a: #7f9bb3;
+ --scroll-thumb-hover-b: #61819c;
+
+ --line: #b9cadb;
+ --line-soft: #d3dfea;
+ --line-strong: #9fb4c8;
+
+ --text: #142434;
+ --text-heading: #0f2033;
+ --text-muted: #4a6379;
+ --text-soft: #526a80;
+ --text-placeholder: #58708a;
+ --text-on-error: #4a0c0c;
+
+ --accent: #0069a8;
+ --accent-hover: #00517f;
+ --accent-text: #0b6a95;
+ --accent-text-hover: #003a5c;
+ --accent-soft: rgba(0, 105, 168, 0.2);
+ --accent-ring: rgba(0, 105, 168, 0.18);
+ --accent-border: rgba(0, 105, 168, 0.5);
+ --accent-shadow: rgba(0, 105, 168, 0.22);
+ --accent-shadow-strong: rgba(0, 105, 168, 0.3);
+ --link-underline: rgba(11, 106, 149, 0.5);
+ --focus-ring: #0a7fc0;
+ --focus-ring-soft: #0a7fc0;
+ --checkbox-checked: #12b9ff;
+ --checkbox-checked-border: #0a7fc0;
+ --loader: #0a7fc0;
+
+ --ok: #12734a;
+ --ok-bright: #a9efcc;
+ --ok-mid: #5fd39b;
+ --ok-border: #4fb884;
+ --ok-soft: rgba(18, 115, 74, 0.45);
+ --ok-surface-top: rgba(226, 246, 235, 0.95);
+ --ok-surface-bottom: rgba(208, 238, 222, 0.98);
+ --warn: #7f5300;
+ --warn-soft: rgba(183, 121, 31, 0.5);
+ --warn-surface-top: rgba(253, 243, 224, 0.95);
+ --warn-surface-bottom: rgba(248, 232, 200, 0.98);
+ --error: #c62828;
+ --error-text: #b02020;
+ --error-text-soft: #8a1a1a;
+ --error-bright: #f6a5a5;
+ --error-strong: #e07575;
+ --error-border: #d95c5c;
+ --error-soft: rgba(198, 40, 40, 0.45);
+ --error-surface: rgba(255, 220, 220, 0.6);
+ --error-surface-top: rgba(253, 232, 232, 0.95);
+ --error-surface-bottom: rgba(248, 214, 214, 0.98);
+ --error-shadow: rgba(198, 40, 40, 0.25);
+ --info: #3f6785;
+ --debug: #7a35b5;
+ }
+}
+
+:root[data-theme="light"] {
+ color-scheme: light;
+
+ --bg-0: #e9eff5;
+ --bg-1: #f5f8fb;
+ --bg-2: #dfe7ef;
+ --bg-deep: #dfe7ef;
+ --bg-glow-1: rgba(64, 132, 183, 0.14);
+ --bg-glow-2: rgba(18, 185, 255, 0.12);
+
+ --panel-top: rgba(255, 255, 255, 0.97);
+ --panel-bottom: rgba(246, 249, 252, 0.97);
+ --panel-glow: rgba(18, 185, 255, 0.08);
+ --surface-0: rgba(255, 255, 255, 0.55);
+ --surface-1: rgba(255, 255, 255, 0.75);
+ --surface-2: rgba(236, 243, 249, 0.85);
+ --surface-3: rgba(232, 240, 247, 0.9);
+ --surface-solid: rgba(255, 255, 255, 0.94);
+ --surface-raised: rgba(228, 236, 244, 0.9);
+ --surface-input: rgba(255, 255, 255, 0.85);
+ --surface-input-focus: rgba(255, 255, 255, 1);
+ --logo-tint-top: rgba(15, 31, 48, 0.96);
+ --logo-tint-bottom: rgba(11, 23, 39, 0.98);
+ --table-head-top: rgba(232, 240, 248, 0.98);
+ --table-head-bottom: rgba(222, 232, 243, 0.98);
+ --row-line: rgba(100, 130, 160, 0.3);
+ --row-hover: rgba(0, 90, 150, 0.07);
+ --row-focus: rgba(0, 90, 150, 0.14);
+ --overlay: rgba(20, 35, 52, 0.5);
+ --overlay-soft: rgba(20, 35, 52, 0.35);
+ --sticky-fade-from: rgba(246, 249, 252, 0.1);
+ --sticky-fade-to: rgba(246, 249, 252, 0.96);
+ --scroll-track: rgba(200, 214, 228, 0.6);
+ --scroll-thumb-a: #9fb6cb;
+ --scroll-thumb-b: #7f9bb3;
+ --scroll-thumb-hover-a: #7f9bb3;
+ --scroll-thumb-hover-b: #61819c;
+
+ --line: #b9cadb;
+ --line-soft: #d3dfea;
+ --line-strong: #9fb4c8;
+
+ --text: #142434;
+ --text-heading: #0f2033;
+ --text-muted: #4a6379;
+ --text-soft: #526a80;
+ --text-placeholder: #58708a;
+ --text-on-error: #4a0c0c;
+
+ --accent: #0069a8;
+ --accent-hover: #00517f;
+ --accent-text: #0b6a95;
+ --accent-text-hover: #003a5c;
+ --accent-soft: rgba(0, 105, 168, 0.2);
+ --accent-ring: rgba(0, 105, 168, 0.18);
+ --accent-border: rgba(0, 105, 168, 0.5);
+ --accent-shadow: rgba(0, 105, 168, 0.22);
+ --accent-shadow-strong: rgba(0, 105, 168, 0.3);
+ --link-underline: rgba(11, 106, 149, 0.5);
+ --focus-ring: #0a7fc0;
+ --focus-ring-soft: #0a7fc0;
+ --checkbox-checked: #12b9ff;
+ --checkbox-checked-border: #0a7fc0;
+ --loader: #0a7fc0;
+
+ --ok: #12734a;
+ --ok-bright: #a9efcc;
+ --ok-mid: #5fd39b;
+ --ok-border: #4fb884;
+ --ok-soft: rgba(18, 115, 74, 0.45);
+ --ok-surface-top: rgba(226, 246, 235, 0.95);
+ --ok-surface-bottom: rgba(208, 238, 222, 0.98);
+ --warn: #7f5300;
+ --warn-soft: rgba(183, 121, 31, 0.5);
+ --warn-surface-top: rgba(253, 243, 224, 0.95);
+ --warn-surface-bottom: rgba(248, 232, 200, 0.98);
+ --error: #c62828;
+ --error-text: #b02020;
+ --error-text-soft: #8a1a1a;
+ --error-bright: #f6a5a5;
+ --error-strong: #e07575;
+ --error-border: #d95c5c;
+ --error-soft: rgba(198, 40, 40, 0.45);
+ --error-surface: rgba(255, 220, 220, 0.6);
+ --error-surface-top: rgba(253, 232, 232, 0.95);
+ --error-surface-bottom: rgba(248, 214, 214, 0.98);
+ --error-shadow: rgba(198, 40, 40, 0.25);
+ --info: #3f6785;
+ --debug: #7a35b5;
+}
diff --git a/html/index.html b/html/index.html
index e1facf4..819856a 100644
--- a/html/index.html
+++ b/html/index.html
@@ -1,11 +1,13 @@
-
+
xTeVe
-
-
+
+
+
+
@@ -37,7 +39,7 @@
-->
@@ -45,7 +47,7 @@
diff --git a/html/login.html b/html/login.html
index c0adae0..28adfd6 100644
--- a/html/login.html
+++ b/html/login.html
@@ -1,11 +1,13 @@
-
+
xTeVe
-
-
+
+
+
+
@@ -13,7 +15,7 @@
-
+
Login
diff --git a/html/maintenance.html b/html/maintenance.html
index d38f47d..e6512bd 100644
--- a/html/maintenance.html
+++ b/html/maintenance.html
@@ -1,18 +1,20 @@
-
+
xTeVe
-
-
+
+
+
+
-
+
Maintenance
@@ -24,7 +26,7 @@
-
+
diff --git a/ts/authentication_ts.ts b/ts/authentication.ts
similarity index 100%
rename from ts/authentication_ts.ts
rename to ts/authentication.ts
diff --git a/ts/base_ts.ts b/ts/base.ts
similarity index 100%
rename from ts/base_ts.ts
rename to ts/base.ts
diff --git a/ts/configuration_ts.ts b/ts/configuration.ts
similarity index 100%
rename from ts/configuration_ts.ts
rename to ts/configuration.ts
diff --git a/ts/logs_ts.ts b/ts/logs.ts
similarity index 100%
rename from ts/logs_ts.ts
rename to ts/logs.ts
diff --git a/ts/network_ts.ts b/ts/network.ts
similarity index 100%
rename from ts/network_ts.ts
rename to ts/network.ts
diff --git a/ts/settings_ts.ts b/ts/settings.ts
similarity index 100%
rename from ts/settings_ts.ts
rename to ts/settings.ts