1142 lines
31 KiB
CSS
1142 lines
31 KiB
CSS
/*
|
|
* ASCII / console theme.
|
|
* Pure black background, white foreground, monospace everything,
|
|
* 1px white borders, animated ASCII spinners and block-progress bars.
|
|
*/
|
|
|
|
.theme-key-ascii {
|
|
color-scheme: dark;
|
|
--accent: #ffffff;
|
|
--accent-contrast: #000000;
|
|
--bg: #000000;
|
|
--panel: #000000;
|
|
--panel-2: #050505;
|
|
--panel-3: #0c0c0c;
|
|
--border: #ffffff;
|
|
--border-strong: #ffffff;
|
|
--text: #ffffff;
|
|
--muted: #b0b0b0;
|
|
--dim: #6a6a6a;
|
|
--danger: #ff5555;
|
|
--danger-text: #ff5555;
|
|
--danger-soft: #000000;
|
|
--danger-border: #ff5555;
|
|
--success: #ffffff;
|
|
--success-text: #ffffff;
|
|
--success-soft: #000000;
|
|
--success-border: #ffffff;
|
|
--warning: #ffffff;
|
|
--warning-text: #ffffff;
|
|
--warning-soft: #000000;
|
|
--warning-border: #ffffff;
|
|
--info: #ffffff;
|
|
--info-text: #ffffff;
|
|
--info-soft: #000000;
|
|
--info-border: #ffffff;
|
|
--blue: #ffffff;
|
|
--radius: 0px;
|
|
--font-sans: "JetBrains Mono", "Cascadia Code", "Fira Code", "Consolas",
|
|
"Source Code Pro", "Courier New", ui-monospace, monospace;
|
|
--font-logo: "JetBrains Mono", "Cascadia Code", "Consolas", "Courier New",
|
|
ui-monospace, monospace;
|
|
--font-mono: "JetBrains Mono", "Cascadia Code", "Consolas", "Courier New",
|
|
ui-monospace, monospace;
|
|
--surface-sheen: transparent;
|
|
--surface-sheen-soft: transparent;
|
|
--surface-hover: rgba(255, 255, 255, 0.08);
|
|
--surface-muted: #0a0a0a;
|
|
--surface-subtle-border: #ffffff;
|
|
--overlay-scrim: rgba(0, 0, 0, 0.85);
|
|
--nav-bg: #000000;
|
|
--rail-bg: #000000;
|
|
--shadow-soft: none;
|
|
--shadow-strong: none;
|
|
--shadow-popover: 0 0 0 1px #ffffff;
|
|
--inset-highlight: transparent;
|
|
--admin-bg: #000000;
|
|
--admin-surface: #000000;
|
|
--admin-surface-2: #050505;
|
|
--admin-elev: #0c0c0c;
|
|
--admin-border: #ffffff;
|
|
--admin-border-strong: #ffffff;
|
|
--admin-text: #ffffff;
|
|
--admin-muted: #b0b0b0;
|
|
--admin-dim: #6a6a6a;
|
|
}
|
|
|
|
/* ---------- Base typography ---------- */
|
|
|
|
.theme-key-ascii,
|
|
.theme-key-ascii body,
|
|
.theme-key-ascii button,
|
|
.theme-key-ascii input,
|
|
.theme-key-ascii textarea,
|
|
.theme-key-ascii select {
|
|
font-family: var(--font-sans);
|
|
letter-spacing: 0;
|
|
font-synthesis: none;
|
|
-webkit-font-smoothing: none;
|
|
font-smooth: never;
|
|
font-variant-ligatures: none;
|
|
}
|
|
|
|
.theme-key-ascii.app-shell {
|
|
background: var(--bg) !important;
|
|
background-image:
|
|
repeating-linear-gradient(
|
|
0deg,
|
|
rgba(255, 255, 255, 0.025) 0,
|
|
rgba(255, 255, 255, 0.025) 1px,
|
|
transparent 1px,
|
|
transparent 3px
|
|
) !important;
|
|
}
|
|
|
|
/* Slight CRT-like flicker on the shell. */
|
|
@keyframes ascii-flicker {
|
|
0%, 96%, 100% { opacity: 1; }
|
|
97% { opacity: 0.96; }
|
|
98% { opacity: 1; }
|
|
99% { opacity: 0.94; }
|
|
}
|
|
|
|
.theme-key-ascii.app-shell::before {
|
|
content: "";
|
|
position: fixed;
|
|
inset: 0;
|
|
pointer-events: none;
|
|
z-index: 9998;
|
|
background: repeating-linear-gradient(
|
|
180deg,
|
|
rgba(255, 255, 255, 0.02) 0,
|
|
rgba(255, 255, 255, 0.02) 1px,
|
|
transparent 1px,
|
|
transparent 2px
|
|
);
|
|
animation: ascii-flicker 5s infinite;
|
|
}
|
|
|
|
/* ---------- Panels / cards ---------- */
|
|
|
|
.theme-key-ascii .card,
|
|
.theme-key-ascii .period-card,
|
|
.theme-key-ascii .method-card,
|
|
.theme-key-ascii .settings-row,
|
|
.theme-key-ascii .option-row,
|
|
.theme-key-ascii .tariff-selected-card,
|
|
.theme-key-ascii .tariff-action-card,
|
|
.theme-key-ascii .tariff-warning-card,
|
|
.theme-key-ascii .topup-carryover-note,
|
|
.theme-key-ascii .subscription-purchase-description,
|
|
.theme-key-ascii .dialog-card,
|
|
.theme-key-ascii .language-select-content,
|
|
.theme-key-ascii .bottom-nav,
|
|
.theme-key-ascii .toast,
|
|
.theme-key-ascii .auth-card,
|
|
.theme-key-ascii .support-overview-card,
|
|
.theme-key-ascii .support-list-card,
|
|
.theme-key-ascii .support-ticket-card,
|
|
.theme-key-ascii .support-conversation-card,
|
|
.theme-key-ascii .support-new-ticket-button,
|
|
.theme-key-ascii .support-create-panel,
|
|
.theme-key-ascii .support-select-trigger,
|
|
.theme-key-ascii .support-select-content,
|
|
.theme-key-ascii .support-status-tabs-list,
|
|
.theme-key-ascii .support-user-ticket-skeleton,
|
|
.theme-key-ascii .ticket-card,
|
|
.theme-key-ascii .support-empty-state,
|
|
.theme-key-ascii .support-message-scroll,
|
|
.theme-key-ascii .ticket-message-avatar,
|
|
.theme-key-ascii .ticket-message-bubble,
|
|
.theme-key-ascii .ticket-composer,
|
|
.theme-key-ascii .admin-sidebar,
|
|
.theme-key-ascii .admin-header,
|
|
.theme-key-ascii .admin-card,
|
|
.theme-key-ascii .admin-stat-card,
|
|
.theme-key-ascii .admin-revenue-panel,
|
|
.theme-key-ascii .admin-empty,
|
|
.theme-key-ascii .admin-tariff-card,
|
|
.theme-key-ascii .admin-toolbar-card,
|
|
.theme-key-ascii .admin-table-card,
|
|
.theme-key-ascii .admin-panel-dash-card,
|
|
.theme-key-ascii .admin-select-trigger,
|
|
.theme-key-ascii .admin-select-content,
|
|
.theme-key-ascii .admin-cn-card[data-slot="card"],
|
|
.theme-key-ascii .admin-dialog .dialog-card,
|
|
.theme-key-ascii .admin-theme-editor-section {
|
|
border: 1px solid #ffffff;
|
|
border-radius: 0;
|
|
background: var(--panel);
|
|
box-shadow: none;
|
|
}
|
|
|
|
/* No ribbon/corner overlays: those caused dialog overflow scrollbars.
|
|
* The console feel comes from the crisp 1px borders, monospace text,
|
|
* and the animated marquees / glitches applied to interactive elements. */
|
|
|
|
/* ---------- Buttons ---------- */
|
|
|
|
.theme-key-ascii .btn,
|
|
.theme-key-ascii .language-select-trigger,
|
|
.theme-key-ascii .bottom-nav button,
|
|
.theme-key-ascii .link-button,
|
|
.theme-key-ascii .support-new-ticket-button,
|
|
.theme-key-ascii .support-select-trigger,
|
|
.theme-key-ascii .support-status-tabs-trigger,
|
|
.theme-key-ascii .admin-btn,
|
|
.theme-key-ascii .admin-chip,
|
|
.theme-key-ascii .admin-tabs-trigger,
|
|
.theme-key-ascii .admin-revenue-period-btn,
|
|
.theme-key-ascii .admin-mobile-toggle,
|
|
.theme-key-ascii .admin-nav-item {
|
|
border: 1px solid #ffffff;
|
|
border-radius: 0;
|
|
background: #000000;
|
|
color: #ffffff;
|
|
box-shadow: none;
|
|
text-transform: none;
|
|
font-family: var(--font-sans);
|
|
transform: none;
|
|
position: relative;
|
|
}
|
|
|
|
.theme-key-ascii .btn:hover:not(:disabled),
|
|
.theme-key-ascii .admin-btn:hover:not(:disabled),
|
|
.theme-key-ascii .admin-nav-item:hover,
|
|
.theme-key-ascii .admin-tabs-trigger:hover,
|
|
.theme-key-ascii .admin-revenue-period-btn:hover,
|
|
.theme-key-ascii .bottom-nav button:hover {
|
|
background: #ffffff;
|
|
color: #000000;
|
|
}
|
|
|
|
.theme-key-ascii .btn:active:not(:disabled),
|
|
.theme-key-ascii .bottom-nav button:active,
|
|
.theme-key-ascii .support-new-ticket-button:active,
|
|
.theme-key-ascii .support-status-tabs-trigger:active,
|
|
.theme-key-ascii .admin-btn:active:not(:disabled) {
|
|
background: #ffffff;
|
|
color: #000000;
|
|
transform: translate(1px, 1px);
|
|
}
|
|
|
|
.theme-key-ascii .btn-primary,
|
|
.theme-key-ascii .admin-btn-primary,
|
|
.theme-key-ascii .bottom-nav button.active,
|
|
.theme-key-ascii .period-card.active,
|
|
.theme-key-ascii .method-card.active,
|
|
.theme-key-ascii .option-row.active,
|
|
.theme-key-ascii .support-new-ticket-button.active,
|
|
.theme-key-ascii .support-status-tabs-trigger[data-state="active"],
|
|
.theme-key-ascii .support-select-item[data-highlighted],
|
|
.theme-key-ascii .support-select-item[data-selected],
|
|
.theme-key-ascii .admin-nav-item.active,
|
|
.theme-key-ascii .admin-tabs-trigger[data-state="active"],
|
|
.theme-key-ascii .admin-revenue-period-btn.is-active {
|
|
background: #ffffff;
|
|
color: #000000;
|
|
border-color: #ffffff;
|
|
}
|
|
|
|
.theme-key-ascii .btn-primary:hover:not(:disabled),
|
|
.theme-key-ascii .admin-btn-primary:hover:not(:disabled) {
|
|
background: #000000;
|
|
color: #ffffff;
|
|
outline: 1px solid #ffffff;
|
|
outline-offset: -2px;
|
|
}
|
|
|
|
/* Blinking caret-style focus ring. */
|
|
@keyframes ascii-caret {
|
|
0%, 49% { outline-color: #ffffff; }
|
|
50%, 100% { outline-color: transparent; }
|
|
}
|
|
|
|
.theme-key-ascii .btn:focus-visible,
|
|
.theme-key-ascii .admin-btn:focus-visible,
|
|
.theme-key-ascii .admin-nav-item:focus-visible,
|
|
.theme-key-ascii .admin-tabs-trigger:focus-visible,
|
|
.theme-key-ascii .admin-revenue-period-btn:focus-visible,
|
|
.theme-key-ascii .admin-mobile-toggle:focus-visible,
|
|
.theme-key-ascii .language-select-trigger:focus-visible,
|
|
.theme-key-ascii .bottom-nav button:focus-visible {
|
|
outline: 2px solid #ffffff;
|
|
outline-offset: 1px;
|
|
animation: ascii-caret 1s steps(1) infinite;
|
|
}
|
|
|
|
/* ---------- Inputs ---------- */
|
|
|
|
.theme-key-ascii .input,
|
|
.theme-key-ascii .textarea,
|
|
.theme-key-ascii .admin-input,
|
|
.theme-key-ascii .admin-textarea,
|
|
.theme-key-ascii .admin-screen-wrap textarea,
|
|
.theme-key-ascii .admin-dialog textarea {
|
|
border: 1px solid #ffffff;
|
|
border-radius: 0;
|
|
background: #000000;
|
|
color: #ffffff;
|
|
box-shadow: none;
|
|
font-family: var(--font-mono);
|
|
caret-color: #ffffff;
|
|
}
|
|
|
|
.theme-key-ascii .input::placeholder,
|
|
.theme-key-ascii .textarea::placeholder,
|
|
.theme-key-ascii .admin-input::placeholder,
|
|
.theme-key-ascii .admin-textarea::placeholder,
|
|
.theme-key-ascii .admin-screen-wrap textarea::placeholder,
|
|
.theme-key-ascii .admin-dialog textarea::placeholder {
|
|
color: var(--dim);
|
|
font-style: normal;
|
|
}
|
|
|
|
.theme-key-ascii .input:focus,
|
|
.theme-key-ascii .textarea:focus,
|
|
.theme-key-ascii .admin-input:focus,
|
|
.theme-key-ascii .admin-textarea:focus,
|
|
.theme-key-ascii .admin-screen-wrap textarea:focus,
|
|
.theme-key-ascii .admin-dialog textarea:focus {
|
|
outline: none;
|
|
border-color: #ffffff;
|
|
box-shadow: inset 0 0 0 1px #ffffff;
|
|
}
|
|
|
|
/* ---------- New webapp surfaces: support, purchase info, password login ---------- */
|
|
|
|
.theme-key-ascii .subscription-purchase-description,
|
|
.theme-key-ascii .support-create-panel,
|
|
.theme-key-ascii .ticket-composer {
|
|
background: #000000;
|
|
}
|
|
|
|
.theme-key-ascii .support-heading-icon,
|
|
.theme-key-ascii .support-new-ticket-icon,
|
|
.theme-key-ascii .support-empty-state svg,
|
|
.theme-key-ascii .ticket-card-title svg,
|
|
.theme-key-ascii .field-error-icon {
|
|
color: #ffffff;
|
|
}
|
|
|
|
.theme-key-ascii .password-switch-divider,
|
|
.theme-key-ascii .or-line span {
|
|
height: 1px;
|
|
background: #ffffff;
|
|
}
|
|
|
|
.theme-key-ascii .link-button {
|
|
min-height: 28px;
|
|
padding: 0 8px;
|
|
color: #ffffff;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.theme-key-ascii .link-button:hover:not(:disabled),
|
|
.theme-key-ascii .support-status-tabs-trigger:hover {
|
|
background: #ffffff;
|
|
color: #000000;
|
|
}
|
|
|
|
.theme-key-ascii .ticket-card::before {
|
|
inset: 0 auto 0 0;
|
|
width: 1px;
|
|
border-radius: 0;
|
|
background: #ffffff;
|
|
}
|
|
|
|
.theme-key-ascii .ticket-status-badge,
|
|
.theme-key-ascii .ticket-priority-badge,
|
|
.theme-key-ascii .ticket-message-role-badge {
|
|
border-color: #ffffff;
|
|
background: #000000;
|
|
color: #ffffff;
|
|
}
|
|
|
|
.theme-key-ascii .ticket-status-badge::before,
|
|
.theme-key-ascii .ticket-priority-badge::before,
|
|
.theme-key-ascii .support-status-tabs-trigger b::before {
|
|
content: "[";
|
|
}
|
|
|
|
.theme-key-ascii .ticket-status-badge::after,
|
|
.theme-key-ascii .ticket-priority-badge::after,
|
|
.theme-key-ascii .support-status-tabs-trigger b::after {
|
|
content: "]";
|
|
}
|
|
|
|
.theme-key-ascii .ticket-message-row,
|
|
.theme-key-ascii .ticket-message-row--admin,
|
|
.theme-key-ascii .ticket-message-row--user,
|
|
.theme-key-ascii .ticket-message-row--system,
|
|
.theme-key-ascii .ticket-message-row--internal {
|
|
--ticket-bubble-bg: #000000;
|
|
--ticket-bubble-border: #ffffff;
|
|
--ticket-bubble-text: #ffffff;
|
|
}
|
|
|
|
.theme-key-ascii .ticket-message-bubble,
|
|
.theme-key-ascii .ticket-message-row--outgoing .ticket-message-bubble {
|
|
border-radius: 0;
|
|
}
|
|
|
|
.theme-key-ascii .ticket-message-row--outgoing .ticket-message-bubble::after,
|
|
.theme-key-ascii .ticket-message-row--incoming .ticket-message-bubble::before {
|
|
color: #ffffff;
|
|
font-family: var(--font-mono);
|
|
}
|
|
|
|
.theme-key-ascii .ticket-message-row--outgoing .ticket-message-bubble::after {
|
|
content: " >";
|
|
}
|
|
|
|
.theme-key-ascii .ticket-message-row--incoming .ticket-message-bubble::before {
|
|
content: "< ";
|
|
}
|
|
|
|
.theme-key-ascii .ticket-composer:focus-within,
|
|
.theme-key-ascii .support-select-trigger:focus-visible,
|
|
.theme-key-ascii .ticket-card:focus-visible,
|
|
.theme-key-ascii .support-status-tabs-trigger:focus-visible {
|
|
border-color: #ffffff;
|
|
box-shadow: inset 0 0 0 1px #ffffff;
|
|
}
|
|
|
|
.theme-key-ascii .support-message-scroll,
|
|
.theme-key-ascii .scroll-area--mono::-webkit-scrollbar-thumb {
|
|
border-radius: 0;
|
|
}
|
|
|
|
.theme-key-ascii .auth-card {
|
|
transition: none;
|
|
}
|
|
|
|
body:has(.theme-key-ascii) .support-select-content,
|
|
body:has(.theme-key-ascii) .field-error-tooltip {
|
|
border: 1px solid #ffffff;
|
|
border-radius: 0;
|
|
background: #000000;
|
|
color: #ffffff;
|
|
box-shadow: 0 0 0 1px #ffffff;
|
|
}
|
|
|
|
body:has(.theme-key-ascii) .support-select-item {
|
|
border-radius: 0;
|
|
color: #ffffff;
|
|
}
|
|
|
|
body:has(.theme-key-ascii) .support-select-item[data-highlighted],
|
|
body:has(.theme-key-ascii) .support-select-item[data-selected] {
|
|
background: #ffffff;
|
|
color: #000000 !important;
|
|
}
|
|
|
|
body:has(.theme-key-ascii) .support-select-item[data-highlighted] svg,
|
|
body:has(.theme-key-ascii) .support-select-item[data-selected] svg {
|
|
color: #000000 !important;
|
|
stroke: #000000 !important;
|
|
}
|
|
|
|
/* ---------- Bottom nav (desktop rail) ---------- */
|
|
|
|
@media (min-width: 1024px) {
|
|
.theme-key-ascii .bottom-nav {
|
|
border-right: 1px solid #ffffff !important;
|
|
background: var(--rail-bg) !important;
|
|
backdrop-filter: none !important;
|
|
box-shadow: none !important;
|
|
}
|
|
|
|
.theme-key-ascii .bottom-nav button {
|
|
border: 1px solid #ffffff !important;
|
|
border-radius: 0 !important;
|
|
background: #000000 !important;
|
|
color: #ffffff !important;
|
|
box-shadow: none !important;
|
|
}
|
|
|
|
.theme-key-ascii .bottom-nav button.active {
|
|
background: #ffffff !important;
|
|
color: #000000 !important;
|
|
}
|
|
}
|
|
|
|
/* ---------- ASCII progress bar ---------- *
|
|
* Empty track: ░░░░░░░░░░░ (low-contrast dotted fill).
|
|
* Filled span: ██████ (solid white blocks).
|
|
*/
|
|
|
|
.theme-key-ascii .progress {
|
|
height: 14px;
|
|
border: 1px solid #ffffff;
|
|
border-radius: 0 !important;
|
|
background-color: #000000;
|
|
background-image: repeating-linear-gradient(
|
|
90deg,
|
|
rgba(255, 255, 255, 0.22) 0,
|
|
rgba(255, 255, 255, 0.22) 1px,
|
|
transparent 1px,
|
|
transparent 4px
|
|
);
|
|
position: relative;
|
|
overflow: hidden;
|
|
font-family: var(--font-mono);
|
|
}
|
|
|
|
.theme-key-ascii .progress span {
|
|
border-radius: 0 !important;
|
|
background: #ffffff !important;
|
|
background-image: repeating-linear-gradient(
|
|
90deg,
|
|
rgba(0, 0, 0, 0.0) 0,
|
|
rgba(0, 0, 0, 0.0) 5px,
|
|
rgba(0, 0, 0, 0.35) 5px,
|
|
rgba(0, 0, 0, 0.35) 6px
|
|
) !important;
|
|
box-shadow: none;
|
|
}
|
|
|
|
/* Indeterminate scanning effect for any progress lacking a width-set span. */
|
|
@keyframes ascii-scan {
|
|
0% { background-position: 0 0; }
|
|
100% { background-position: 12px 0; }
|
|
}
|
|
|
|
/* ---------- ASCII spinner replacement ---------- */
|
|
|
|
.theme-key-ascii .ui-spinner,
|
|
.theme-key-ascii .telegram-button-spinner,
|
|
.theme-key-ascii .brand-mark-spinner {
|
|
border: none !important;
|
|
border-radius: 0 !important;
|
|
width: 1ch !important;
|
|
height: 1em !important;
|
|
background: transparent !important;
|
|
position: relative;
|
|
animation: none !important;
|
|
color: currentColor;
|
|
font-family: var(--font-mono);
|
|
font-weight: 700;
|
|
text-align: center;
|
|
vertical-align: middle;
|
|
overflow: visible;
|
|
}
|
|
|
|
.theme-key-ascii .ui-spinner::before,
|
|
.theme-key-ascii .telegram-button-spinner::before,
|
|
.theme-key-ascii .brand-mark-spinner::before {
|
|
content: "|";
|
|
display: inline-block;
|
|
animation: ascii-spin 0.8s steps(1) infinite;
|
|
font-family: var(--font-mono);
|
|
line-height: 1;
|
|
}
|
|
|
|
@keyframes ascii-spin {
|
|
0% { content: "|"; }
|
|
25% { content: "/"; }
|
|
50% { content: "-"; }
|
|
75% { content: "\\"; }
|
|
100% { content: "|"; }
|
|
}
|
|
|
|
/* Some browsers don't animate content; fallback rotation of a glyph. */
|
|
@supports not (animation-name: ascii-spin) {
|
|
.theme-key-ascii .ui-spinner::before,
|
|
.theme-key-ascii .telegram-button-spinner::before,
|
|
.theme-key-ascii .brand-mark-spinner::before {
|
|
content: "+";
|
|
animation: ascii-spin-rotate 0.8s steps(4) infinite;
|
|
}
|
|
@keyframes ascii-spin-rotate {
|
|
to { transform: rotate(360deg); }
|
|
}
|
|
}
|
|
|
|
/* Blinking cursor appended to brand text. */
|
|
.theme-key-ascii .login-brand h1::after,
|
|
.theme-key-ascii .admin-sidebar-brand strong::after,
|
|
.theme-key-ascii .brand-row strong::after {
|
|
content: "_";
|
|
display: inline-block;
|
|
margin-left: 0.2ch;
|
|
color: #ffffff;
|
|
animation: ascii-blink 1s steps(1) infinite;
|
|
}
|
|
|
|
@keyframes ascii-blink {
|
|
0%, 49% { opacity: 1; }
|
|
50%, 100% { opacity: 0; }
|
|
}
|
|
|
|
/* Section heading prompt prefix. */
|
|
.theme-key-ascii .admin-card-head h2::before,
|
|
.theme-key-ascii .admin-card-head h3::before,
|
|
.theme-key-ascii .card > h2:first-child::before,
|
|
.theme-key-ascii .card > h3:first-child::before {
|
|
content: "> ";
|
|
color: #ffffff;
|
|
opacity: 0.85;
|
|
font-family: var(--font-mono);
|
|
}
|
|
|
|
/* ---------- Tables ---------- */
|
|
|
|
.theme-key-ascii .admin-table thead th {
|
|
background: #000000;
|
|
color: #ffffff;
|
|
border-bottom: 1px solid #ffffff;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.04em;
|
|
font-weight: 700;
|
|
}
|
|
|
|
.theme-key-ascii .admin-table tbody tr {
|
|
border-bottom: 1px dashed #ffffff;
|
|
}
|
|
|
|
.theme-key-ascii .admin-table tbody tr:hover {
|
|
background: rgba(255, 255, 255, 0.08);
|
|
}
|
|
|
|
/* ---------- Badges / chips ---------- */
|
|
|
|
.theme-key-ascii .admin-badge,
|
|
.theme-key-ascii .admin-cn-badge {
|
|
border: 1px solid #ffffff;
|
|
border-radius: 0;
|
|
background: #000000;
|
|
color: #ffffff;
|
|
font-weight: 700;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.04em;
|
|
}
|
|
|
|
.theme-key-ascii .admin-badge::before,
|
|
.theme-key-ascii .admin-cn-badge::before {
|
|
content: "[";
|
|
}
|
|
|
|
.theme-key-ascii .admin-badge::after,
|
|
.theme-key-ascii .admin-cn-badge::after {
|
|
content: "]";
|
|
}
|
|
|
|
/* ---------- Links ---------- */
|
|
|
|
.theme-key-ascii a:not(.btn):not(.bottom-nav button):not([class*="-trigger"]),
|
|
.theme-key-ascii .admin-screen-wrap a:not(.admin-btn):not(.admin-nav-item) {
|
|
color: #ffffff;
|
|
text-decoration: underline;
|
|
text-underline-offset: 2px;
|
|
}
|
|
|
|
.theme-key-ascii a:not(.btn):not(.bottom-nav button):not([class*="-trigger"]):hover,
|
|
.theme-key-ascii .admin-screen-wrap a:not(.admin-btn):not(.admin-nav-item):hover {
|
|
background: #ffffff;
|
|
color: #000000;
|
|
text-decoration: none;
|
|
}
|
|
|
|
/* ---------- Selection ---------- */
|
|
|
|
.theme-key-ascii ::selection {
|
|
background: #ffffff;
|
|
color: #000000;
|
|
}
|
|
|
|
/* ---------- Scrollbars ---------- */
|
|
|
|
.theme-key-ascii ::-webkit-scrollbar {
|
|
width: 12px;
|
|
height: 12px;
|
|
}
|
|
|
|
.theme-key-ascii ::-webkit-scrollbar-track {
|
|
background-color: #000000;
|
|
background-image: repeating-linear-gradient(
|
|
0deg,
|
|
#ffffff 0,
|
|
#ffffff 1px,
|
|
transparent 1px,
|
|
transparent 4px
|
|
);
|
|
}
|
|
|
|
.theme-key-ascii ::-webkit-scrollbar-thumb {
|
|
background: #ffffff;
|
|
border: 1px solid #000000;
|
|
}
|
|
|
|
.theme-key-ascii ::-webkit-scrollbar-thumb:active {
|
|
background: #b0b0b0;
|
|
}
|
|
|
|
.theme-key-ascii ::-webkit-scrollbar-corner {
|
|
background: #000000;
|
|
}
|
|
|
|
/* ---------- Lucide icons: render as crisp white outlines ---------- */
|
|
|
|
.theme-key-ascii svg.lucide,
|
|
.theme-key-ascii svg[class*="lucide-"] {
|
|
color: #ffffff !important;
|
|
stroke: #ffffff !important;
|
|
fill: none !important;
|
|
stroke-width: 1.75;
|
|
filter: none;
|
|
}
|
|
|
|
.theme-key-ascii .btn-primary svg.lucide,
|
|
.theme-key-ascii .bottom-nav button.active svg.lucide,
|
|
.theme-key-ascii .period-card.active svg.lucide,
|
|
.theme-key-ascii .method-card.active svg.lucide,
|
|
.theme-key-ascii .option-row.active svg.lucide,
|
|
.theme-key-ascii .admin-btn-primary svg.lucide,
|
|
.theme-key-ascii .admin-nav-item.active svg.lucide,
|
|
.theme-key-ascii .admin-tabs-trigger[data-state="active"] svg.lucide,
|
|
.theme-key-ascii .admin-revenue-period-btn.is-active svg.lucide {
|
|
color: #000000 !important;
|
|
stroke: #000000 !important;
|
|
}
|
|
|
|
/* ---------- Toast / language select polish ---------- */
|
|
|
|
.theme-key-ascii .toast {
|
|
background: #000000;
|
|
border: 1px solid #ffffff;
|
|
color: #ffffff;
|
|
}
|
|
|
|
.theme-key-ascii .language-select-item {
|
|
border-radius: 0;
|
|
}
|
|
|
|
.theme-key-ascii .language-select-item[data-highlighted],
|
|
.theme-key-ascii .language-select-item[data-selected] {
|
|
background: #ffffff;
|
|
color: #000000 !important;
|
|
}
|
|
|
|
/* ---------- Headings: stronger console feel ---------- */
|
|
|
|
.theme-key-ascii h1,
|
|
.theme-key-ascii h2,
|
|
.theme-key-ascii h3,
|
|
.theme-key-ascii h4 {
|
|
font-family: var(--font-mono);
|
|
letter-spacing: 0;
|
|
text-transform: none;
|
|
}
|
|
|
|
.theme-key-ascii .admin-header {
|
|
background: #000000;
|
|
border-bottom: 1px solid #ffffff;
|
|
color: #ffffff;
|
|
}
|
|
|
|
.theme-key-ascii .admin-header-title h2,
|
|
.theme-key-ascii .admin-header-title small {
|
|
color: #ffffff;
|
|
}
|
|
|
|
/* Make any element with role progressbar but no inner span show animated stripes. */
|
|
.theme-key-ascii [role="progressbar"]:not(.progress) {
|
|
background:
|
|
repeating-linear-gradient(
|
|
90deg,
|
|
#ffffff 0,
|
|
#ffffff 6px,
|
|
#000000 6px,
|
|
#000000 8px
|
|
);
|
|
animation: ascii-scan 0.6s linear infinite;
|
|
border: 1px solid #ffffff;
|
|
border-radius: 0;
|
|
color: #000000;
|
|
}
|
|
|
|
/* ============================================================
|
|
* Console-themed extras
|
|
* ============================================================ */
|
|
|
|
/* ---------- ASCII skeletons ---------- *
|
|
* Subtle dark shimmer with a single bright scan line moving across.
|
|
*/
|
|
|
|
@keyframes ascii-skeleton-scan {
|
|
0% { background-position: -120% 0; }
|
|
100% { background-position: 220% 0; }
|
|
}
|
|
|
|
.theme-key-ascii .ui-skeleton,
|
|
.theme-key-ascii .admin-skeleton,
|
|
.theme-key-ascii .skeleton-line,
|
|
.theme-key-ascii .skeleton-dot,
|
|
.theme-key-ascii .skeleton-pay-button,
|
|
.theme-key-ascii .ui-skeleton-line,
|
|
.theme-key-ascii .admin-skeleton-line,
|
|
.theme-key-ascii .admin-skeleton-line-strong,
|
|
.theme-key-ascii .admin-skeleton-line-soft,
|
|
.theme-key-ascii .admin-skeleton-line-short,
|
|
.theme-key-ascii .admin-skeleton-line-tiny,
|
|
.theme-key-ascii .ui-skeleton-title,
|
|
.theme-key-ascii .ui-skeleton-short,
|
|
.theme-key-ascii .ui-skeleton-tiny,
|
|
.theme-key-ascii .ui-skeleton-badge,
|
|
.theme-key-ascii .admin-skeleton-badge,
|
|
.theme-key-ascii .admin-skeleton-avatar,
|
|
.theme-key-ascii .admin-stat-skeleton-card,
|
|
.theme-key-ascii .admin-stat-skeleton-wide,
|
|
.theme-key-ascii .admin-cn-card-skeleton--tall {
|
|
border-radius: 0 !important;
|
|
border: 1px solid #ffffff !important;
|
|
background-color: #050505 !important;
|
|
background-image: linear-gradient(
|
|
90deg,
|
|
transparent 0%,
|
|
transparent 40%,
|
|
rgba(255, 255, 255, 0.18) 50%,
|
|
transparent 60%,
|
|
transparent 100%
|
|
) !important;
|
|
background-size: 200% 100% !important;
|
|
background-repeat: no-repeat !important;
|
|
color: #ffffff !important;
|
|
animation: ascii-skeleton-scan 1.6s linear infinite !important;
|
|
}
|
|
|
|
.theme-key-ascii .admin-skeleton-avatar {
|
|
width: 32px !important;
|
|
height: 32px !important;
|
|
}
|
|
|
|
/* ---------- Empty / loading state console message ---------- */
|
|
.theme-key-ascii .admin-empty {
|
|
position: relative;
|
|
}
|
|
|
|
.theme-key-ascii .admin-empty::before {
|
|
content: "$ tail -f /var/log/empty.log";
|
|
display: block;
|
|
font-family: var(--font-mono);
|
|
color: var(--muted);
|
|
margin-bottom: 8px;
|
|
letter-spacing: 0;
|
|
}
|
|
|
|
/* ---------- Buttons: glitch on hover ---------- */
|
|
|
|
@keyframes ascii-glitch {
|
|
0%, 100% { transform: translate(0, 0); clip-path: inset(0 0 0 0); }
|
|
20% { transform: translate(-1px, 0); clip-path: inset(20% 0 50% 0); }
|
|
40% { transform: translate(1px, 0); clip-path: inset(40% 0 30% 0); }
|
|
60% { transform: translate(-1px, 0); clip-path: inset(10% 0 70% 0); }
|
|
80% { transform: translate(1px, 0); clip-path: inset(60% 0 10% 0); }
|
|
}
|
|
|
|
.theme-key-ascii .btn:hover:not(:disabled)::after,
|
|
.theme-key-ascii .admin-btn:hover:not(:disabled)::after {
|
|
content: attr(data-label, "");
|
|
pointer-events: none;
|
|
}
|
|
|
|
/* Disable glitch text duplication if the button has no data-label.
|
|
* Apply a subtle scanline overlay instead, which is content-agnostic. */
|
|
.theme-key-ascii .btn,
|
|
.theme-key-ascii .admin-btn,
|
|
.theme-key-ascii .admin-nav-item,
|
|
.theme-key-ascii .bottom-nav button {
|
|
overflow: hidden;
|
|
}
|
|
|
|
.theme-key-ascii .btn:hover:not(:disabled)::before,
|
|
.theme-key-ascii .admin-btn:hover:not(:disabled)::before,
|
|
.theme-key-ascii .admin-nav-item:hover::before,
|
|
.theme-key-ascii .bottom-nav button:hover::before {
|
|
content: "";
|
|
position: absolute;
|
|
inset: 0;
|
|
pointer-events: none;
|
|
background: repeating-linear-gradient(
|
|
0deg,
|
|
rgba(0, 0, 0, 0.4) 0,
|
|
rgba(0, 0, 0, 0.4) 1px,
|
|
transparent 1px,
|
|
transparent 3px
|
|
);
|
|
animation: ascii-glitch 0.6s steps(1) infinite;
|
|
z-index: 1;
|
|
}
|
|
|
|
/* ---------- Bottom nav active markers "> item <" ---------- */
|
|
|
|
.theme-key-ascii .bottom-nav button.active::before,
|
|
.theme-key-ascii .admin-nav-item.active::before {
|
|
content: ">";
|
|
position: absolute;
|
|
left: 6px;
|
|
top: 50%;
|
|
transform: translateY(-50%);
|
|
font-family: var(--font-mono);
|
|
color: #000000;
|
|
animation: ascii-blink 1s steps(1) infinite;
|
|
z-index: 2;
|
|
}
|
|
|
|
.theme-key-ascii .bottom-nav button.active::after,
|
|
.theme-key-ascii .admin-nav-item.active::after {
|
|
content: "<";
|
|
position: absolute;
|
|
right: 6px;
|
|
top: 50%;
|
|
transform: translateY(-50%);
|
|
font-family: var(--font-mono);
|
|
color: #000000;
|
|
animation: ascii-blink 1s steps(1) infinite;
|
|
animation-delay: 0.5s;
|
|
z-index: 2;
|
|
}
|
|
|
|
.theme-key-ascii .bottom-nav button.active,
|
|
.theme-key-ascii .admin-nav-item.active {
|
|
position: relative;
|
|
}
|
|
|
|
/* On the mobile bottom-bar (compact) hide the markers to avoid overlap. */
|
|
@media (max-width: 1023px) {
|
|
.theme-key-ascii .bottom-nav button.active::before,
|
|
.theme-key-ascii .bottom-nav button.active::after {
|
|
content: none;
|
|
}
|
|
}
|
|
|
|
/* ---------- ASCII block progress fill ---------- *
|
|
* The actual fill renders as alternating █ blocks via the existing span
|
|
* gradient. We also overlay a slow scanning highlight to make it feel
|
|
* "live", and add a soft typed counter to the right edge.
|
|
*/
|
|
|
|
/* (duplicate progress fill rules removed — see definition above) */
|
|
|
|
/* ---------- Headings: subtle CRT glitch on hover ---------- */
|
|
|
|
@keyframes ascii-heading-jitter {
|
|
0%, 92%, 100% { transform: translate(0, 0); }
|
|
93% { transform: translate(-1px, 0); }
|
|
94% { transform: translate(1px, 0); }
|
|
95% { transform: translate(0, -1px); }
|
|
96% { transform: translate(0, 1px); }
|
|
}
|
|
|
|
.theme-key-ascii h1,
|
|
.theme-key-ascii h2,
|
|
.theme-key-ascii h3,
|
|
.theme-key-ascii .login-brand h1,
|
|
.theme-key-ascii .admin-sidebar-brand strong,
|
|
.theme-key-ascii .admin-card-head h2,
|
|
.theme-key-ascii .admin-card-head h3 {
|
|
display: inline-block;
|
|
animation: ascii-heading-jitter 7s steps(1) infinite;
|
|
}
|
|
|
|
/* ---------- App-shell boot banner ---------- *
|
|
* A non-blocking strip at the very top of the viewport that displays a
|
|
* typed "booting…" line, then settles. Pure CSS so it cannot interfere
|
|
* with any DOM. The animation runs once on mount.
|
|
*/
|
|
|
|
@keyframes ascii-boot-type {
|
|
0% { width: 0; }
|
|
85% { width: 28ch; }
|
|
100% { width: 28ch; }
|
|
}
|
|
|
|
@keyframes ascii-boot-fade {
|
|
0%, 70% { opacity: 1; }
|
|
100% { opacity: 0; visibility: hidden; }
|
|
}
|
|
|
|
.theme-key-ascii.app-shell::after {
|
|
content: "$ remnawave --start --tty=0";
|
|
position: fixed;
|
|
top: 0;
|
|
left: 0;
|
|
z-index: 9999;
|
|
display: block;
|
|
padding: 2px 8px;
|
|
max-width: 28ch;
|
|
overflow: hidden;
|
|
white-space: nowrap;
|
|
background: #000000;
|
|
color: #ffffff;
|
|
font-family: var(--font-mono);
|
|
font-size: 11px;
|
|
line-height: 1.5;
|
|
border-right: 1px solid #ffffff;
|
|
border-bottom: 1px solid #ffffff;
|
|
pointer-events: none;
|
|
animation:
|
|
ascii-boot-type 1.6s steps(28) 1 both,
|
|
ascii-boot-fade 3s linear 1.6s 1 forwards;
|
|
}
|
|
|
|
/* ---------- Toggle / checkbox squareification (best-effort) ---------- */
|
|
|
|
.theme-key-ascii input[type="checkbox"],
|
|
.theme-key-ascii input[type="radio"] {
|
|
appearance: none;
|
|
-webkit-appearance: none;
|
|
width: 1em;
|
|
height: 1em;
|
|
border: 1px solid #ffffff;
|
|
background: #000000;
|
|
border-radius: 0 !important;
|
|
position: relative;
|
|
vertical-align: middle;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.theme-key-ascii input[type="checkbox"]:checked::after,
|
|
.theme-key-ascii input[type="radio"]:checked::after {
|
|
content: "x";
|
|
position: absolute;
|
|
inset: 0;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
font-family: var(--font-mono);
|
|
font-weight: 700;
|
|
color: #ffffff;
|
|
line-height: 1;
|
|
}
|
|
|
|
/* ---------- Code-like "$ " prefix on toast messages ---------- */
|
|
|
|
.theme-key-ascii .toast::before {
|
|
content: "$ ";
|
|
color: #ffffff;
|
|
font-family: var(--font-mono);
|
|
font-weight: 700;
|
|
}
|
|
|
|
/* ---------- Disabled state — strikethrough hatching ---------- */
|
|
|
|
.theme-key-ascii .btn:disabled,
|
|
.theme-key-ascii .admin-btn:disabled,
|
|
.theme-key-ascii button:disabled {
|
|
background-image: repeating-linear-gradient(
|
|
-45deg,
|
|
transparent 0,
|
|
transparent 4px,
|
|
rgba(255, 255, 255, 0.18) 4px,
|
|
rgba(255, 255, 255, 0.18) 5px
|
|
);
|
|
color: var(--dim) !important;
|
|
border-color: var(--dim) !important;
|
|
cursor: not-allowed;
|
|
}
|
|
|
|
/* ============================================================
|
|
* Square everything: drop all rounded corners on touched surfaces.
|
|
* ============================================================ */
|
|
|
|
.theme-key-ascii :is(
|
|
.card, .dialog-card, .toast,
|
|
.btn, .input,
|
|
.period-card, .method-card, .settings-row, .option-row,
|
|
.tariff-selected-card, .tariff-action-card, .tariff-warning-card,
|
|
.topup-carryover-note, .subscription-purchase-description,
|
|
.language-select-content, .language-select-item,
|
|
.language-select-trigger, .bottom-nav, .bottom-nav button,
|
|
.link-button,
|
|
.support-overview-card, .support-list-card, .support-ticket-card,
|
|
.support-conversation-card, .support-new-ticket-button,
|
|
.support-create-panel, .support-select-trigger, .support-select-content,
|
|
.support-select-item, .support-status-tabs-list, .support-status-tabs-trigger,
|
|
.support-user-ticket-skeleton, .ticket-card, .support-empty-state,
|
|
.support-message-scroll, .ticket-message-avatar, .ticket-message-bubble,
|
|
.ticket-composer, .textarea,
|
|
.field-error-tooltip,
|
|
.admin-card, .admin-card-head, .admin-card-body,
|
|
.admin-stat-card, .admin-stat-skeleton-card, .admin-stat-skeleton-wide,
|
|
.admin-revenue-panel, .admin-empty,
|
|
.admin-tariff-card, .admin-toolbar-card, .admin-table-card,
|
|
.admin-panel-dash-card,
|
|
.admin-select-trigger, .admin-select-content, .admin-select-item,
|
|
.admin-cn-card, .admin-cn-badge, .admin-badge,
|
|
.admin-cn-card-skeleton--tall,
|
|
.admin-input, .admin-textarea, .admin-btn, .admin-chip,
|
|
.admin-tabs-trigger, .admin-tabs-list,
|
|
.admin-nav-item, .admin-revenue-period-btn, .admin-mobile-toggle,
|
|
.admin-header, .admin-sidebar, .admin-sidebar-brand,
|
|
.admin-dialog,
|
|
.admin-theme-editor-section,
|
|
[data-slot="card"], [data-slot="card-header"],
|
|
[data-slot="card-content"], [data-slot="card-footer"]
|
|
),
|
|
.theme-key-ascii :is(
|
|
.card, .dialog-card, .toast,
|
|
.btn, .input,
|
|
.admin-card, .admin-card-head, .admin-card-body,
|
|
.admin-stat-card, .admin-revenue-panel, .admin-empty,
|
|
.admin-tariff-card, .admin-toolbar-card, .admin-table-card,
|
|
.admin-panel-dash-card,
|
|
.admin-select-trigger, .admin-select-content,
|
|
.admin-cn-card,
|
|
.admin-input, .admin-textarea, .admin-btn,
|
|
.admin-nav-item, .admin-tabs-trigger
|
|
) * {
|
|
border-radius: 0 !important;
|
|
}
|
|
|
|
.theme-key-ascii img,
|
|
.theme-key-ascii .admin-avatar,
|
|
.theme-key-ascii .admin-skeleton-avatar {
|
|
border-radius: 0 !important;
|
|
}
|
|
|
|
/* ============================================================
|
|
* Console-style tables: cell borders, header underline,
|
|
* row separator using dashed line.
|
|
* ============================================================ */
|
|
|
|
.theme-key-ascii .admin-table,
|
|
.theme-key-ascii table {
|
|
border-collapse: collapse;
|
|
border: 1px solid #ffffff;
|
|
font-family: var(--font-mono);
|
|
}
|
|
|
|
.theme-key-ascii .admin-table th,
|
|
.theme-key-ascii .admin-table td,
|
|
.theme-key-ascii table th,
|
|
.theme-key-ascii table td {
|
|
border: 1px solid #ffffff;
|
|
border-radius: 0 !important;
|
|
padding: 6px 10px;
|
|
}
|
|
|
|
.theme-key-ascii .admin-table thead th,
|
|
.theme-key-ascii table thead th {
|
|
background: #000000;
|
|
border-bottom: 2px solid #ffffff;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.04em;
|
|
}
|
|
|
|
.theme-key-ascii .admin-table tbody tr,
|
|
.theme-key-ascii table tbody tr {
|
|
border-bottom: 1px solid #ffffff;
|
|
}
|
|
|
|
.theme-key-ascii .admin-table tbody tr:hover,
|
|
.theme-key-ascii table tbody tr:hover {
|
|
background: rgba(255, 255, 255, 0.07);
|
|
}
|
|
|
|
.theme-key-ascii .admin-table tbody tr:hover td,
|
|
.theme-key-ascii table tbody tr:hover td {
|
|
color: #ffffff;
|
|
}
|