diff --git a/src/lib/assets/css/background-3d.css b/src/lib/assets/css/background-3d.css
new file mode 100644
index 0000000..c8b4ad8
--- /dev/null
+++ b/src/lib/assets/css/background-3d.css
@@ -0,0 +1,13 @@
+.scene-container {
+ position: fixed;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ z-index: -1;
+ pointer-events: none;
+}
+
+.scene-container :global(canvas) {
+ display: block;
+}
diff --git a/src/lib/assets/css/index.css b/src/lib/assets/css/index.css
new file mode 100644
index 0000000..0f2b2a9
--- /dev/null
+++ b/src/lib/assets/css/index.css
@@ -0,0 +1,34 @@
+/* TUI Components CSS Index */
+/* This file can be imported to get all TUI component styles at once */
+
+/* TUI Core Components */
+@import './tui-header.css';
+@import './tui-footer.css';
+@import './tui-body.css';
+
+/* TUI Display Components */
+@import './tui-button.css';
+@import './tui-link.css';
+@import './tui-card.css';
+@import './tui-card-grid.css';
+@import './tui-progress.css';
+@import './tui-accordion.css';
+@import './tui-table.css';
+@import './tui-tooltip.css';
+
+/* TUI Form Components */
+@import './tui-input.css';
+@import './tui-textarea.css';
+@import './tui-checkbox.css';
+@import './tui-radio.css';
+@import './tui-select.css';
+@import './tui-toggle.css';
+
+/* Main Components */
+@import './terminal.css';
+@import './terminal-tui.css';
+@import './terminal-page.css';
+@import './model-viewer.css';
+@import './navbar.css';
+@import './navbar-waybar.css';
+@import './background-3d.css';
diff --git a/src/lib/assets/css/model-viewer.css b/src/lib/assets/css/model-viewer.css
new file mode 100644
index 0000000..cb2dc9a
--- /dev/null
+++ b/src/lib/assets/css/model-viewer.css
@@ -0,0 +1,172 @@
+.model-viewer {
+ display: flex;
+ flex-direction: column;
+ background: var(--viewer-bg);
+ border: 1px solid var(--viewer-border);
+ border-radius: 8px;
+ overflow: hidden;
+ transition: all 0.3s ease;
+}
+
+.model-viewer.fullscreen {
+ position: fixed;
+ inset: 60px 0 0 0;
+ z-index: 100;
+ border-radius: 0;
+ border: none;
+}
+
+.viewer-header {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding: 0.5rem 0.75rem;
+ background: color-mix(in srgb, var(--viewer-bg) 80%, black);
+ border-bottom: 1px solid var(--viewer-border);
+}
+
+.header-left {
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
+ color: var(--viewer-primary);
+ font-size: 0.85rem;
+ font-weight: 500;
+}
+
+.header-controls {
+ display: flex;
+ gap: 0.25rem;
+}
+
+.control-btn {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ width: 28px;
+ height: 28px;
+ background: transparent;
+ border: 1px solid transparent;
+ border-radius: 4px;
+ color: var(--viewer-muted);
+ cursor: pointer;
+ transition: all 0.2s ease;
+}
+
+.control-btn:hover {
+ background: var(--viewer-border);
+ color: var(--viewer-text);
+ border-color: var(--viewer-border);
+}
+
+.control-btn.active {
+ background: var(--viewer-primary);
+ color: var(--viewer-bg);
+ border-color: var(--viewer-primary);
+}
+
+.control-btn.small {
+ width: 24px;
+ height: 24px;
+}
+
+/* Extended controls panel */
+.controls-panel {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 1rem;
+ padding: 0.5rem 0.75rem;
+ background: color-mix(in srgb, var(--viewer-bg) 90%, black);
+ border-bottom: 1px solid var(--viewer-border);
+}
+
+.control-group {
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
+}
+
+.control-label {
+ font-size: 0.7rem;
+ color: var(--viewer-muted);
+ text-transform: uppercase;
+ letter-spacing: 0.05em;
+}
+
+.control-buttons {
+ display: flex;
+ align-items: center;
+ gap: 0.25rem;
+}
+
+.control-value {
+ font-size: 0.7rem;
+ color: var(--viewer-text);
+ min-width: 2.5rem;
+ text-align: center;
+ font-family: 'JetBrains Mono', monospace;
+}
+
+.canvas-container {
+ flex: 1;
+ min-height: 300px;
+ position: relative;
+ background: radial-gradient(
+ circle at center,
+ color-mix(in srgb, var(--viewer-primary) 5%, transparent),
+ transparent 70%
+ );
+ outline: none;
+}
+
+.canvas-container:focus {
+ box-shadow: inset 0 0 0 2px var(--viewer-primary);
+}
+
+.canvas-container :global(canvas) {
+ display: block;
+}
+
+.loading-overlay,
+.error-overlay {
+ position: absolute;
+ inset: 0;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ gap: 0.75rem;
+ color: var(--viewer-muted);
+ font-size: 0.9rem;
+}
+
+.error-overlay {
+ color: #f38ba8;
+}
+
+:global(.spin) {
+ animation: spin 1s linear infinite;
+}
+
+@keyframes spin {
+ from { transform: rotate(0deg); }
+ to { transform: rotate(360deg); }
+}
+
+.viewer-footer {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ gap: 1.5rem;
+ padding: 0.5rem;
+ background: color-mix(in srgb, var(--viewer-bg) 80%, black);
+ border-top: 1px solid var(--viewer-border);
+}
+
+.hint {
+ display: flex;
+ align-items: center;
+ gap: 0.35rem;
+ color: var(--viewer-muted);
+ font-size: 0.75rem;
+}
diff --git a/src/lib/assets/css/navbar-waybar.css b/src/lib/assets/css/navbar-waybar.css
new file mode 100644
index 0000000..9f92cd5
--- /dev/null
+++ b/src/lib/assets/css/navbar-waybar.css
@@ -0,0 +1,377 @@
+/* Waybar main container */
+.waybar {
+ position: fixed;
+ top: 0;
+ left: 0;
+ right: 0;
+ z-index: 1000;
+ height: var(--navbar-height);
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding: 0 0.75rem;
+ background: var(--bar-bg);
+ border-bottom: 1px solid var(--bar-border);
+ font-family: 'JetBrains Mono', 'Fira Code', monospace;
+ font-size: 0.8rem;
+}
+
+/* Bar sections */
+.bar-left,
+.bar-center,
+.bar-right {
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
+}
+
+.bar-left {
+ flex: 1;
+}
+
+.bar-right {
+ flex: 1;
+ justify-content: flex-end;
+}
+
+/* Desktop-only items */
+.desktop-only {
+ display: flex;
+}
+
+@media (max-width: 768px) {
+ .desktop-only {
+ display: none;
+ }
+}
+
+/* Module base style */
+.module {
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
+ padding: 0.35rem 0.6rem;
+ background: var(--bar-bg-module);
+ border-radius: 6px;
+ transition: all 0.15s ease;
+}
+
+/* Launcher / Logo */
+.launcher {
+ padding: 0.4rem;
+ border-radius: 6px;
+}
+
+.launcher:hover {
+ background: color-mix(in srgb, var(--bar-primary) 20%, transparent);
+}
+
+/* Mobile menu toggle button */
+.mobile-menu-toggle {
+ display: none;
+ align-items: center;
+ justify-content: center;
+ width: 36px;
+ height: 36px;
+ padding: 0;
+ background: var(--bar-bg-module);
+ border: 1px solid var(--bar-border);
+ border-radius: 6px;
+ color: var(--bar-text);
+ cursor: pointer;
+ transition: all 0.15s ease;
+}
+
+.mobile-menu-toggle:hover {
+ background: color-mix(in srgb, var(--bar-primary) 20%, transparent);
+ border-color: var(--bar-primary);
+}
+
+@media (max-width: 768px) {
+ .mobile-menu-toggle {
+ display: flex;
+ }
+}
+
+/* Workspaces */
+.workspaces {
+ gap: 0.25rem;
+ background: transparent;
+ padding: 0;
+}
+
+.workspace {
+ display: flex;
+ align-items: center;
+ gap: 0.35rem;
+ padding: 0.35rem 0.6rem;
+ color: var(--bar-muted);
+ text-decoration: none;
+ border-radius: 4px;
+ transition: all 0.15s ease;
+ font-size: 0.75rem;
+}
+
+.workspace:hover {
+ color: var(--bar-text);
+ background: var(--bar-bg-module);
+}
+
+.workspace.active {
+ color: var(--bar-primary);
+ background: color-mix(in srgb, var(--bar-primary) 15%, transparent);
+}
+
+.workspace.external {
+ color: var(--bar-accent);
+}
+
+.workspace.external:hover {
+ background: color-mix(in srgb, var(--bar-accent) 15%, transparent);
+}
+
+.ws-name {
+ font-weight: 500;
+}
+
+/* Window title */
+.window-title {
+ color: var(--bar-text);
+ font-size: 0.75rem;
+}
+
+.title-icon {
+ color: var(--bar-primary);
+}
+
+.title-text {
+ color: var(--bar-muted);
+}
+
+/* Clock */
+.clock {
+ gap: 0.75rem;
+}
+
+.time {
+ color: var(--bar-text);
+ font-weight: 600;
+}
+
+.date {
+ color: var(--bar-muted);
+}
+
+/* Theme selector */
+.theme-selector {
+ position: relative;
+ background: transparent;
+ padding: 0;
+}
+
+.theme-trigger {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ width: 32px;
+ height: 32px;
+ padding: 0;
+ background: var(--bar-bg-module);
+ border: 1px solid var(--bar-border);
+ border-radius: 6px;
+ color: var(--bar-text);
+ cursor: pointer;
+ transition: all 0.15s ease;
+}
+
+.theme-trigger:hover {
+ background: color-mix(in srgb, var(--bar-primary) 20%, transparent);
+ border-color: var(--bar-primary);
+}
+
+.theme-dropdown {
+ position: absolute;
+ top: calc(100% + 0.5rem);
+ right: 0;
+ min-width: 160px;
+ background: var(--bar-bg);
+ border: 1px solid var(--bar-border);
+ border-radius: 8px;
+ padding: 0.5rem;
+ box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);
+ z-index: 1001;
+}
+
+.dropdown-header {
+ padding: 0.25rem 0.5rem;
+ font-size: 0.65rem;
+ text-transform: uppercase;
+ letter-spacing: 0.05em;
+ color: var(--bar-muted);
+}
+
+.dropdown-divider {
+ height: 1px;
+ background: var(--bar-border);
+ margin: 0.5rem 0;
+}
+
+.theme-option {
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
+ width: 100%;
+ padding: 0.5rem 0.75rem;
+ background: transparent;
+ border: none;
+ border-radius: 4px;
+ color: var(--bar-text);
+ cursor: pointer;
+ font-family: inherit;
+ font-size: 0.8rem;
+ text-align: left;
+ transition: all 0.15s ease;
+}
+
+.theme-option:hover {
+ background: color-mix(in srgb, var(--bar-primary) 15%, transparent);
+}
+
+.theme-option.active {
+ color: var(--bar-primary);
+}
+
+:global(.check) {
+ margin-left: auto;
+ color: var(--bar-primary);
+}
+
+/* Backdrop */
+.backdrop {
+ position: fixed;
+ inset: 0;
+ background: transparent;
+ z-index: 999;
+ border: none;
+ cursor: default;
+}
+
+/* Mobile menu dropdown */
+.mobile-menu {
+ position: fixed;
+ top: var(--navbar-height);
+ left: 0;
+ right: 0;
+ background: var(--bar-bg);
+ border-bottom: 1px solid var(--bar-border);
+ z-index: 998;
+ padding: 1rem;
+ font-family: 'JetBrains Mono', 'Fira Code', monospace;
+ box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);
+}
+
+.mobile-nav-links {
+ display: flex;
+ flex-direction: column;
+ gap: 0.5rem;
+}
+
+.mobile-nav-link {
+ display: flex;
+ align-items: center;
+ gap: 0.75rem;
+ padding: 0.75rem 1rem;
+ color: var(--bar-text);
+ text-decoration: none;
+ border-radius: 6px;
+ transition: all 0.15s ease;
+ font-size: 0.9rem;
+}
+
+.mobile-nav-link:hover {
+ background: var(--bar-bg-module);
+}
+
+.mobile-nav-link.active {
+ color: var(--bar-primary);
+ background: color-mix(in srgb, var(--bar-primary) 15%, transparent);
+}
+
+.mobile-nav-link.external {
+ color: var(--bar-accent);
+}
+
+.mobile-menu-divider {
+ height: 1px;
+ background: var(--bar-border);
+ margin: 1rem 0;
+}
+
+.mobile-theme-section {
+ display: flex;
+ flex-direction: column;
+ gap: 0.75rem;
+}
+
+.mobile-section-header {
+ font-size: 0.7rem;
+ text-transform: uppercase;
+ letter-spacing: 0.05em;
+ color: var(--bar-muted);
+ padding: 0 0.5rem;
+}
+
+.mobile-theme-options {
+ display: flex;
+ gap: 0.5rem;
+}
+
+.mobile-theme-btn {
+ flex: 1;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ gap: 0.35rem;
+ padding: 0.75rem 0.5rem;
+ background: var(--bar-bg-module);
+ border: 1px solid var(--bar-border);
+ border-radius: 6px;
+ color: var(--bar-text);
+ cursor: pointer;
+ font-family: inherit;
+ font-size: 0.75rem;
+ transition: all 0.15s ease;
+}
+
+.mobile-theme-btn:hover {
+ background: color-mix(in srgb, var(--bar-primary) 15%, transparent);
+ border-color: var(--bar-primary);
+}
+
+.mobile-theme-btn.active {
+ color: var(--bar-primary);
+ border-color: var(--bar-primary);
+ background: color-mix(in srgb, var(--bar-primary) 20%, transparent);
+}
+
+.mobile-mode-btn {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ gap: 0.5rem;
+ padding: 0.75rem;
+ background: var(--bar-bg-module);
+ border: 1px solid var(--bar-border);
+ border-radius: 6px;
+ color: var(--bar-text);
+ cursor: pointer;
+ font-family: inherit;
+ font-size: 0.8rem;
+ transition: all 0.15s ease;
+ width: 100%;
+}
+
+.mobile-mode-btn:hover {
+ background: color-mix(in srgb, var(--bar-primary) 15%, transparent);
+ border-color: var(--bar-primary);
+}
diff --git a/src/lib/assets/css/navbar.css b/src/lib/assets/css/navbar.css
new file mode 100644
index 0000000..09e3bb2
--- /dev/null
+++ b/src/lib/assets/css/navbar.css
@@ -0,0 +1,331 @@
+.navbar {
+ position: fixed;
+ top: 0;
+ left: 0;
+ right: 0;
+ z-index: 1000;
+ background: var(--nav-bg);
+ border-bottom: 1px solid var(--nav-border);
+ backdrop-filter: blur(10px);
+ font-family: 'JetBrains Mono', 'Fira Code', 'Consolas', monospace;
+}
+
+.nav-container {
+ max-width: 1400px;
+ margin: 0 auto;
+ padding: 0.75rem 1.5rem;
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 2rem;
+}
+
+.nav-brand {
+ display: flex;
+ align-items: center;
+ gap: 0.25rem;
+ font-size: 0.9rem;
+ font-weight: 600;
+}
+
+.terminal-prompt {
+ display: flex;
+ align-items: center;
+ gap: 0;
+}
+
+.terminal-prompt .user {
+ color: var(--nav-accent);
+}
+
+.terminal-prompt .separator {
+ color: var(--nav-text);
+}
+
+.terminal-prompt .path {
+ color: var(--nav-primary);
+}
+
+.terminal-prompt .symbol {
+ color: var(--nav-text);
+ margin-left: 0.25rem;
+}
+
+.cursor {
+ width: 8px;
+ height: 1em;
+ background: var(--nav-primary);
+ animation: blink 1s step-end infinite;
+ margin-left: 0.25rem;
+ vertical-align: text-bottom;
+}
+
+@keyframes blink {
+ 0%, 100% { opacity: 1; }
+ 50% { opacity: 0; }
+}
+
+.mobile-toggle {
+ display: none;
+ background: none;
+ border: none;
+ padding: 0.5rem;
+ cursor: pointer;
+}
+
+.hamburger {
+ display: block;
+ width: 24px;
+ height: 2px;
+ background: var(--nav-text);
+ position: relative;
+ transition: all 0.3s ease;
+}
+
+.hamburger::before,
+.hamburger::after {
+ content: '';
+ position: absolute;
+ width: 24px;
+ height: 2px;
+ background: var(--nav-text);
+ transition: all 0.3s ease;
+}
+
+.hamburger::before {
+ top: -7px;
+}
+
+.hamburger::after {
+ top: 7px;
+}
+
+.hamburger.open {
+ background: transparent;
+}
+
+.hamburger.open::before {
+ top: 0;
+ transform: rotate(45deg);
+}
+
+.hamburger.open::after {
+ top: 0;
+ transform: rotate(-45deg);
+}
+
+.nav-links {
+ display: flex;
+ align-items: center;
+ gap: 1.5rem;
+ flex: 1;
+}
+
+.nav-link {
+ color: var(--nav-text);
+ text-decoration: none;
+ font-size: 0.85rem;
+ padding: 0.5rem 0.75rem;
+ border-radius: 4px;
+ transition: all 0.2s ease;
+ display: flex;
+ align-items: center;
+ position: relative;
+ overflow: hidden;
+}
+
+.nav-link::before {
+ content: '';
+ position: absolute;
+ bottom: 0;
+ left: 0;
+ width: 0;
+ height: 2px;
+ background: var(--nav-primary);
+ transition: width 0.3s ease;
+}
+
+.nav-link:hover::before {
+ width: 100%;
+}
+
+.nav-link:hover {
+ color: var(--nav-primary);
+}
+
+.link-prefix {
+ color: var(--nav-muted);
+ margin-right: 2px;
+}
+
+.nav-controls {
+ display: flex;
+ align-items: center;
+ gap: 1rem;
+}
+
+.theme-selector {
+ position: relative;
+}
+
+.theme-button {
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
+ padding: 0.5rem 0.75rem;
+ background: transparent;
+ border: 1px solid var(--nav-border);
+ border-radius: 6px;
+ color: var(--nav-text);
+ cursor: pointer;
+ font-family: inherit;
+ font-size: 0.8rem;
+ transition: all 0.2s ease;
+}
+
+.theme-button:hover {
+ border-color: var(--nav-primary);
+ background: color-mix(in srgb, var(--nav-primary) 10%, transparent);
+}
+
+.theme-icon {
+ font-size: 1rem;
+ display: flex;
+ align-items: center;
+}
+
+.theme-label {
+ text-transform: capitalize;
+}
+
+:global(.dropdown-arrow) {
+ transition: transform 0.2s ease;
+}
+
+:global(.dropdown-arrow.open) {
+ transform: rotate(180deg);
+}
+
+.theme-dropdown {
+ position: absolute;
+ top: calc(100% + 0.5rem);
+ right: 0;
+ min-width: 180px;
+ background: var(--nav-bg);
+ border: 1px solid var(--nav-border);
+ border-radius: 8px;
+ padding: 0.5rem;
+ box-shadow: 0 10px 40px rgba(0, 0, 0, 0.3);
+ z-index: 1001;
+}
+
+.theme-option {
+ display: flex;
+ align-items: center;
+ gap: 0.75rem;
+ width: 100%;
+ padding: 0.625rem 0.75rem;
+ background: transparent;
+ border: none;
+ border-radius: 6px;
+ color: var(--nav-text);
+ cursor: pointer;
+ font-family: inherit;
+ font-size: 0.85rem;
+ text-align: left;
+ transition: all 0.2s ease;
+}
+
+.theme-option:hover {
+ background: color-mix(in srgb, var(--nav-primary) 15%, transparent);
+}
+
+.theme-option.active {
+ background: color-mix(in srgb, var(--nav-primary) 20%, transparent);
+ color: var(--nav-primary);
+}
+
+.option-icon {
+ font-size: 1.1rem;
+ display: flex;
+ align-items: center;
+}
+
+.option-label {
+ flex: 1;
+}
+
+:global(.check-mark) {
+ color: var(--nav-primary);
+}
+
+.mode-toggle {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ width: 40px;
+ height: 40px;
+ background: transparent;
+ border: 1px solid var(--nav-border);
+ border-radius: 8px;
+ cursor: pointer;
+ transition: all 0.2s ease;
+ color: var(--nav-text);
+}
+
+.mode-toggle:hover {
+ border-color: var(--nav-primary);
+ background: color-mix(in srgb, var(--nav-primary) 10%, transparent);
+ color: var(--nav-primary);
+}
+
+.backdrop {
+ position: fixed;
+ inset: 0;
+ background: transparent;
+ z-index: 999;
+ border: none;
+ cursor: default;
+}
+
+@media (max-width: 768px) {
+ .nav-container {
+ flex-wrap: wrap;
+ padding: 0.75rem 1rem;
+ }
+
+ .mobile-toggle {
+ display: block;
+ order: 2;
+ }
+
+ .nav-links {
+ order: 4;
+ width: 100%;
+ flex-direction: column;
+ align-items: flex-start;
+ gap: 0.5rem;
+ max-height: 0;
+ overflow: hidden;
+ transition: max-height 0.3s ease, padding 0.3s ease;
+ }
+
+ .nav-links.expanded {
+ max-height: 200px;
+ padding-top: 1rem;
+ }
+
+ .nav-controls {
+ order: 3;
+ margin-left: auto;
+ margin-right: 1rem;
+ }
+
+ .theme-label {
+ display: none;
+ }
+
+ .theme-button {
+ padding: 0.5rem;
+ }
+}
diff --git a/src/lib/assets/css/terminal-page.css b/src/lib/assets/css/terminal-page.css
new file mode 100644
index 0000000..badfba1
--- /dev/null
+++ b/src/lib/assets/css/terminal-page.css
@@ -0,0 +1,223 @@
+.terminal-page {
+ font-family: 'JetBrains Mono', 'Fira Code', 'Consolas', monospace;
+ background: var(--terminal-bg);
+ border: 1px solid var(--terminal-border);
+ border-radius: 12px;
+ overflow: hidden;
+ box-shadow:
+ 0 25px 50px -12px rgba(0, 0, 0, 0.4),
+ 0 0 0 1px rgba(255, 255, 255, 0.05) inset;
+ animation: terminalFadeIn 0.5s ease-out;
+ display: flex;
+ flex-direction: column;
+ height: 100%;
+}
+
+@keyframes terminalFadeIn {
+ from {
+ opacity: 0;
+ transform: translateY(20px) scale(0.98);
+ }
+ to {
+ opacity: 1;
+ transform: translateY(0) scale(1);
+ }
+}
+
+.terminal-header {
+ display: flex;
+ align-items: center;
+ padding: 0.75rem 1rem;
+ background: var(--terminal-bg-light);
+ border-bottom: 1px solid var(--terminal-border);
+ flex-shrink: 0;
+}
+
+.terminal-buttons {
+ display: flex;
+ gap: 8px;
+}
+
+.terminal-buttons .btn {
+ width: 12px;
+ height: 12px;
+ border-radius: 50%;
+ cursor: pointer;
+ transition: opacity 0.2s;
+}
+
+.terminal-buttons .btn:hover {
+ opacity: 0.8;
+}
+
+.terminal-buttons .close {
+ background: #ff5f56;
+}
+
+.terminal-buttons .minimize {
+ background: #ffbd2e;
+}
+
+.terminal-buttons .maximize {
+ background: #27ca40;
+}
+
+.terminal-title {
+ flex: 1;
+ text-align: center;
+ font-size: 0.8rem;
+ color: var(--terminal-muted);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ gap: 0.5rem;
+}
+
+.terminal-icon {
+ font-size: 1rem;
+}
+
+.terminal-spacer {
+ width: 52px;
+}
+
+.terminal-body {
+ padding: 1rem 1.25rem;
+ flex: 1;
+ overflow-y: auto;
+ font-size: 0.9rem;
+ line-height: 1.6;
+}
+
+.terminal-line {
+ display: flex;
+ align-items: flex-start;
+ flex-wrap: wrap;
+ margin-bottom: 0.25rem;
+ animation: lineSlideIn 0.2s ease-out;
+ min-height: 1.6em;
+}
+
+.terminal-line.blank {
+ min-height: 0.8em;
+}
+
+@keyframes lineSlideIn {
+ from {
+ opacity: 0;
+ transform: translateX(-10px);
+ }
+ to {
+ opacity: 1;
+ transform: translateX(0);
+ }
+}
+
+.prompt {
+ display: inline-flex;
+ margin-right: 0.5rem;
+ flex-shrink: 0;
+}
+
+.prompt .user {
+ color: var(--terminal-user);
+}
+
+.prompt .separator {
+ color: var(--terminal-text);
+}
+
+.prompt .path {
+ color: var(--terminal-path);
+}
+
+.prompt .symbol {
+ color: var(--terminal-text);
+ margin-left: 0.25rem;
+}
+
+.content {
+ color: var(--terminal-text);
+ word-break: break-word;
+ white-space: pre-wrap;
+}
+
+.terminal-line.output .content {
+ color: var(--terminal-muted);
+}
+
+.terminal-line.error .content {
+ color: #f38ba8;
+}
+
+.terminal-line.success .content {
+ color: #a6e3a1;
+}
+
+.terminal-line.info .content {
+ color: var(--terminal-primary);
+}
+
+.terminal-line.header .content {
+ color: var(--terminal-accent);
+ font-weight: 600;
+ font-size: 1rem;
+}
+
+.header-text {
+ color: var(--terminal-accent);
+ font-weight: 600;
+}
+
+.terminal-image {
+ display: flex;
+ flex-direction: column;
+ gap: 0.5rem;
+ padding: 0.5rem 0;
+}
+
+.terminal-image img {
+ border-radius: 8px;
+ border: 1px solid var(--terminal-border);
+ background: var(--terminal-bg-light);
+ object-fit: contain;
+}
+
+.image-caption {
+ color: var(--terminal-muted);
+ font-size: 0.8rem;
+ font-style: italic;
+}
+
+.cursor {
+ display: inline-block;
+ width: 8px;
+ height: 1em;
+ background: var(--terminal-primary);
+ animation: cursorBlink 1s step-end infinite;
+ margin-left: 2px;
+ vertical-align: text-bottom;
+}
+
+@keyframes cursorBlink {
+ 0%, 100% { opacity: 1; }
+ 50% { opacity: 0; }
+}
+
+/* Scrollbar styling */
+.terminal-body::-webkit-scrollbar {
+ width: 8px;
+}
+
+.terminal-body::-webkit-scrollbar-track {
+ background: transparent;
+}
+
+.terminal-body::-webkit-scrollbar-thumb {
+ background: var(--terminal-border);
+ border-radius: 4px;
+}
+
+.terminal-body::-webkit-scrollbar-thumb:hover {
+ background: var(--terminal-muted);
+}
diff --git a/src/lib/assets/css/terminal-tui.css b/src/lib/assets/css/terminal-tui.css
new file mode 100644
index 0000000..e632d69
--- /dev/null
+++ b/src/lib/assets/css/terminal-tui.css
@@ -0,0 +1,73 @@
+.tui-terminal {
+ font-family: 'JetBrains Mono', 'Fira Code', 'Consolas', monospace;
+ background: var(--terminal-bg);
+ border: 2px solid var(--terminal-border);
+ border-radius: 8px;
+ overflow: hidden;
+ position: relative;
+ display: flex;
+ flex-direction: column;
+ width: 95%;
+ margin: 0 auto;
+ height: calc(100vh - var(--navbar-height) - 80px);
+ max-height: calc(100vh - var(--navbar-height) - 80px);
+ animation: tuiFadeIn 0.4s ease-out;
+}
+
+.tui-terminal:focus-within .tui-border-glow {
+ opacity: 1;
+}
+
+@keyframes tuiFadeIn {
+ from {
+ opacity: 0;
+ transform: scale(0.98);
+ }
+ to {
+ opacity: 1;
+ transform: scale(1);
+ }
+}
+
+/* Hyprland-style animated border glow */
+.tui-border-glow {
+ position: absolute;
+ inset: -2px;
+ border-radius: 10px;
+ background: linear-gradient(
+ 45deg,
+ var(--terminal-primary),
+ var(--terminal-accent),
+ var(--terminal-primary),
+ var(--terminal-accent)
+ );
+ background-size: 400% 400%;
+ animation: borderGlow 8s ease infinite;
+ opacity: 0.5;
+ z-index: -1;
+ filter: blur(4px);
+ transition: opacity 0.3s ease;
+}
+
+@keyframes borderGlow {
+ 0%, 100% { background-position: 0% 50%; }
+ 50% { background-position: 100% 50%; }
+}
+
+.tui-content {
+ display: flex;
+ flex-direction: column;
+ height: 100%;
+ background: var(--terminal-bg);
+ position: relative;
+ z-index: 1;
+}
+
+/* Responsive */
+@media (max-width: 768px) {
+ .tui-terminal {
+ width: 95%;
+ height: calc(100vh - var(--navbar-height) - 60px);
+ max-height: calc(100vh - var(--navbar-height) - 60px);
+ }
+}
diff --git a/src/lib/assets/css/terminal.css b/src/lib/assets/css/terminal.css
new file mode 100644
index 0000000..4417fd9
--- /dev/null
+++ b/src/lib/assets/css/terminal.css
@@ -0,0 +1,183 @@
+.terminal {
+ font-family: 'JetBrains Mono', 'Fira Code', 'Consolas', monospace;
+ background: var(--terminal-bg);
+ border: 1px solid var(--terminal-border);
+ border-radius: 12px;
+ overflow: hidden;
+ box-shadow:
+ 0 25px 50px -12px rgba(0, 0, 0, 0.4),
+ 0 0 0 1px rgba(255, 255, 255, 0.05) inset;
+ animation: terminalFadeIn 0.5s ease-out;
+}
+
+@keyframes terminalFadeIn {
+ from {
+ opacity: 0;
+ transform: translateY(20px) scale(0.98);
+ }
+ to {
+ opacity: 1;
+ transform: translateY(0) scale(1);
+ }
+}
+
+.terminal-header {
+ display: flex;
+ align-items: center;
+ padding: 0.75rem 1rem;
+ background: color-mix(in srgb, var(--terminal-bg) 80%, black);
+ border-bottom: 1px solid var(--terminal-border);
+}
+
+.terminal-buttons {
+ display: flex;
+ gap: 8px;
+}
+
+.terminal-buttons .btn {
+ width: 12px;
+ height: 12px;
+ border-radius: 50%;
+ cursor: pointer;
+ transition: opacity 0.2s;
+}
+
+.terminal-buttons .btn:hover {
+ opacity: 0.8;
+}
+
+.terminal-buttons .close {
+ background: #ff5f56;
+}
+
+.terminal-buttons .minimize {
+ background: #ffbd2e;
+}
+
+.terminal-buttons .maximize {
+ background: #27ca40;
+}
+
+.terminal-title {
+ flex: 1;
+ text-align: center;
+ font-size: 0.8rem;
+ color: var(--terminal-muted);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ gap: 0.5rem;
+}
+
+.terminal-icon {
+ font-size: 1rem;
+}
+
+.terminal-spacer {
+ width: 52px;
+}
+
+.terminal-body {
+ padding: 1rem 1.25rem;
+ min-height: 200px;
+ max-height: 400px;
+ overflow-y: auto;
+ font-size: 0.9rem;
+ line-height: 1.6;
+}
+
+.terminal-line {
+ display: flex;
+ align-items: center;
+ flex-wrap: wrap;
+ margin-bottom: 0.25rem;
+ animation: lineSlideIn 0.2s ease-out;
+}
+
+@keyframes lineSlideIn {
+ from {
+ opacity: 0;
+ transform: translateX(-10px);
+ }
+ to {
+ opacity: 1;
+ transform: translateX(0);
+ }
+}
+
+.prompt {
+ display: inline-flex;
+ margin-right: 0.5rem;
+ flex-shrink: 0;
+}
+
+.prompt .user {
+ color: var(--terminal-user);
+}
+
+.prompt .separator {
+ color: var(--terminal-text);
+}
+
+.prompt .path {
+ color: var(--terminal-path);
+}
+
+.prompt .symbol {
+ color: var(--terminal-text);
+ margin-left: 0.25rem;
+}
+
+.content {
+ color: var(--terminal-text);
+ word-break: break-word;
+}
+
+.terminal-line.output .content {
+ color: var(--terminal-muted);
+}
+
+.terminal-line.error .content {
+ color: #ff6b6b;
+}
+
+.terminal-line.success .content {
+ color: #51cf66;
+}
+
+.terminal-line.info .content {
+ color: var(--terminal-primary);
+}
+
+.cursor {
+ display: inline-block;
+ width: 8px;
+ height: 1em;
+ background: var(--terminal-primary);
+ animation: cursorBlink 1s step-end infinite;
+ margin-left: 2px;
+ vertical-align: text-bottom;
+}
+
+@keyframes cursorBlink {
+ 0%, 100% { opacity: 1; }
+ 50% { opacity: 0; }
+}
+
+/* Scrollbar styling */
+.terminal-body::-webkit-scrollbar {
+ width: 8px;
+}
+
+.terminal-body::-webkit-scrollbar-track {
+ background: transparent;
+}
+
+.terminal-body::-webkit-scrollbar-thumb {
+ background: var(--terminal-border);
+ border-radius: 4px;
+}
+
+.terminal-body::-webkit-scrollbar-thumb:hover {
+ background: var(--terminal-muted);
+}
diff --git a/src/lib/assets/css/tui-accordion.css b/src/lib/assets/css/tui-accordion.css
new file mode 100644
index 0000000..343ffee
--- /dev/null
+++ b/src/lib/assets/css/tui-accordion.css
@@ -0,0 +1,69 @@
+.tui-accordion {
+ margin: 0.5rem 0;
+ border: 1px solid var(--terminal-border);
+ border-radius: 6px;
+ overflow: hidden;
+}
+
+.accordion-item {
+ border-bottom: 1px solid var(--terminal-border);
+}
+
+.accordion-item:last-child {
+ border-bottom: none;
+}
+
+.accordion-header {
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
+ width: 100%;
+ padding: 0.6rem 0.75rem;
+ background: transparent;
+ border: none;
+ color: var(--terminal-text);
+ font-family: inherit;
+ font-size: 0.85rem;
+ font-weight: 500;
+ text-align: left;
+ cursor: pointer;
+ transition: background 0.15s ease;
+}
+
+.accordion-header:hover {
+ background: rgba(255, 255, 255, 0.03);
+}
+
+.accordion-item.open .accordion-header {
+ background: rgba(0, 0, 0, 0.1);
+ border-bottom: 1px solid var(--terminal-border);
+}
+
+:global(.accordion-icon) {
+ color: var(--accordion-accent);
+ transition: transform 0.2s ease;
+}
+
+.accordion-title {
+ flex: 1;
+}
+
+.accordion-content {
+ padding: 0.75rem;
+ color: var(--terminal-muted);
+ font-size: 0.85rem;
+ line-height: 1.6;
+ white-space: pre-wrap;
+ animation: slideDown 0.2s ease-out;
+}
+
+@keyframes slideDown {
+ from {
+ opacity: 0;
+ transform: translateY(-5px);
+ }
+ to {
+ opacity: 1;
+ transform: translateY(0);
+ }
+}
diff --git a/src/lib/assets/css/tui-body.css b/src/lib/assets/css/tui-body.css
new file mode 100644
index 0000000..21523a3
--- /dev/null
+++ b/src/lib/assets/css/tui-body.css
@@ -0,0 +1,227 @@
+.tui-body {
+ flex: 1;
+ padding: 1rem 1.25rem 2rem 1.25rem;
+ overflow-y: auto;
+ overflow-x: hidden;
+ font-size: 0.9rem;
+ line-height: 1.7;
+ min-height: 0;
+}
+
+/* Inline group wrapper - groups consecutive inline elements */
+.tui-inline-group {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 0.5rem;
+ margin-bottom: 0.2rem;
+ animation: lineSlideIn 0.15s ease-out;
+}
+
+.inline-content {
+ display: inline;
+ white-space: pre-wrap;
+}
+
+.inline-content.output {
+ color: var(--terminal-muted);
+}
+
+.inline-content.info {
+ color: var(--terminal-primary);
+}
+
+.inline-content.success {
+ color: #a6e3a1;
+}
+
+.inline-content.error {
+ color: #f38ba8;
+}
+
+.inline-content.warning {
+ color: #f9e2af;
+}
+
+/* Lines */
+.tui-line {
+ display: flex;
+ align-items: flex-start;
+ flex-wrap: wrap;
+ margin-bottom: 0.2rem;
+ animation: lineSlideIn 0.15s ease-out;
+ min-height: 1.7em;
+}
+
+.tui-line.blank {
+ min-height: 0.5em;
+}
+
+@keyframes lineSlideIn {
+ from {
+ opacity: 0;
+ transform: translateX(-5px);
+ }
+ to {
+ opacity: 1;
+ transform: translateX(0);
+ }
+}
+
+/* Prompt styling */
+.prompt {
+ display: inline-flex;
+ margin-right: 0.5rem;
+ flex-shrink: 0;
+}
+
+.prompt .user {
+ color: var(--terminal-user);
+}
+
+.prompt .at {
+ color: var(--terminal-muted);
+}
+
+.prompt .host {
+ color: var(--terminal-accent);
+}
+
+.prompt .separator {
+ color: var(--terminal-muted);
+}
+
+.prompt .path {
+ color: var(--terminal-path);
+}
+
+.prompt .symbol {
+ color: var(--terminal-muted);
+ margin-left: 0.25rem;
+}
+
+/* Content */
+.content {
+ color: var(--terminal-text);
+ word-break: break-word;
+ white-space: pre-wrap;
+}
+
+.tui-line.output .content {
+ color: var(--terminal-muted);
+}
+
+.tui-line.error .content {
+ color: #f38ba8;
+}
+
+.tui-line.success .content {
+ color: #a6e3a1;
+}
+
+.tui-line.info .content {
+ color: var(--terminal-primary);
+}
+
+.tui-line.warning .content {
+ color: #f9e2af;
+}
+
+.header-text {
+ color: var(--terminal-accent);
+ font-weight: 600;
+ font-size: 1rem;
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
+}
+
+:global(.header-icon) {
+ opacity: 0.7;
+}
+
+:global(.inline-icon) {
+ display: inline-block;
+ vertical-align: middle;
+ margin: 0 0.15em;
+}
+
+/* Divider */
+.tui-divider {
+ display: flex;
+ align-items: center;
+ gap: 1rem;
+ margin: 0.75rem 0;
+}
+
+.divider-line {
+ flex: 1;
+ height: 1px;
+ background: linear-gradient(
+ to right,
+ transparent,
+ var(--terminal-border),
+ transparent
+ );
+}
+
+.divider-text {
+ color: var(--terminal-muted);
+ font-size: 0.75rem;
+ text-transform: uppercase;
+ letter-spacing: 0.1em;
+}
+
+/* Images */
+.tui-image {
+ display: flex;
+ flex-direction: column;
+ gap: 0.5rem;
+ padding: 0.5rem 0;
+}
+
+.tui-image img {
+ border-radius: 6px;
+ border: 1px solid var(--terminal-border);
+ background: var(--terminal-bg-light);
+ object-fit: contain;
+}
+
+.image-caption {
+ color: var(--terminal-muted);
+ font-size: 0.8rem;
+ font-style: italic;
+}
+
+/* Cursor */
+.cursor {
+ display: inline-block;
+ width: 8px;
+ height: 1em;
+ background: var(--terminal-primary);
+ animation: cursorBlink 1s step-end infinite;
+ margin-left: 2px;
+ vertical-align: text-bottom;
+}
+
+@keyframes cursorBlink {
+ 0%, 100% { opacity: 1; }
+ 50% { opacity: 0; }
+}
+
+/* Scrollbar */
+.tui-body::-webkit-scrollbar {
+ width: 6px;
+}
+
+.tui-body::-webkit-scrollbar-track {
+ background: transparent;
+}
+
+.tui-body::-webkit-scrollbar-thumb {
+ background: var(--terminal-border);
+ border-radius: 3px;
+}
+
+.tui-body::-webkit-scrollbar-thumb:hover {
+ background: var(--terminal-muted);
+}
diff --git a/src/lib/assets/css/tui-button.css b/src/lib/assets/css/tui-button.css
new file mode 100644
index 0000000..071726f
--- /dev/null
+++ b/src/lib/assets/css/tui-button.css
@@ -0,0 +1,60 @@
+.tui-button {
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
+ width: 100%;
+ padding: 0.5rem 0.75rem;
+ margin: 0.2rem 0;
+ background: transparent;
+ border: 1px solid transparent;
+ border-radius: 4px;
+ color: var(--btn-color);
+ font-family: inherit;
+ font-size: 0.9rem;
+ text-align: left;
+ cursor: pointer;
+ transition: all 0.15s ease;
+}
+
+/* Inline button styles */
+.tui-button.inline {
+ width: auto;
+ display: inline-flex;
+ margin: 0;
+ padding: 0.35rem 0.6rem;
+ border: 1px solid color-mix(in srgb, var(--btn-color) 40%, transparent);
+}
+
+.tui-button.inline .btn-indicator {
+ display: none;
+}
+
+.tui-button:hover,
+.tui-button.selected {
+ background: color-mix(in srgb, var(--btn-color) 15%, transparent);
+ border-color: var(--btn-color);
+}
+
+.btn-indicator {
+ color: var(--btn-color);
+ font-size: 0.8rem;
+ width: 1rem;
+}
+
+.btn-text {
+ flex: 1;
+}
+
+:global(.btn-arrow) {
+ opacity: 0.5;
+}
+
+.tui-button.selected :global(.btn-arrow) {
+ opacity: 1;
+}
+
+:global(.inline-icon) {
+ display: inline-block;
+ vertical-align: middle;
+ margin: 0 0.15em;
+}
diff --git a/src/lib/assets/css/tui-card-grid.css b/src/lib/assets/css/tui-card-grid.css
new file mode 100644
index 0000000..2e780e3
--- /dev/null
+++ b/src/lib/assets/css/tui-card-grid.css
@@ -0,0 +1,222 @@
+.tui-card-grid {
+ display: grid;
+ grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
+ gap: 1rem;
+ padding: 0.5rem 0;
+ width: 100%;
+}
+
+.tui-card {
+ background: var(--terminal-bg);
+ border: 1px solid var(--terminal-border);
+ border-radius: 8px;
+ overflow: hidden;
+ display: flex;
+ flex-direction: column;
+ transition: all 0.2s ease;
+ font-family: 'JetBrains Mono', monospace;
+}
+
+.tui-card:hover {
+ border-color: var(--terminal-primary);
+ transform: translateY(-2px);
+ box-shadow: 0 8px 24px rgba(0, 0, 0, 0.3);
+}
+
+.tui-card.featured {
+ border-color: var(--terminal-accent);
+}
+
+.card-image {
+ position: relative;
+ width: 100%;
+ height: 140px;
+ overflow: hidden;
+ background: var(--terminal-bg-light);
+}
+
+.card-image img {
+ width: 100%;
+ height: 100%;
+ object-fit: cover;
+ transition: transform 0.3s ease;
+}
+
+.tui-card:hover .card-image img {
+ transform: scale(1.05);
+}
+
+.card-header-badge {
+ padding: 0.5rem 0.75rem 0;
+}
+
+.featured-badge {
+ position: absolute;
+ top: 0.5rem;
+ right: 0.5rem;
+ background: rgba(0, 0, 0, 0.75);
+ color: var(--terminal-accent);
+ padding: 0.15rem 0.4rem;
+ border-radius: 3px;
+ font-size: 0.65rem;
+ font-weight: 600;
+ backdrop-filter: blur(4px);
+}
+
+.card-header-badge .featured-badge {
+ position: static;
+ display: inline-block;
+}
+
+.card-body {
+ padding: 0.75rem;
+ display: flex;
+ flex-direction: column;
+ gap: 0.4rem;
+ flex: 1;
+}
+
+.card-title {
+ margin: 0;
+ font-size: 0.9rem;
+ font-weight: 600;
+ color: var(--terminal-text);
+ line-height: 1.3;
+}
+
+.card-meta {
+ display: flex;
+ align-items: center;
+ gap: 0.3rem;
+ font-size: 0.7rem;
+ color: var(--terminal-primary);
+}
+
+.meta-icon {
+ font-size: 0.75rem;
+}
+
+.hackathon-name {
+ font-weight: 500;
+}
+
+.year {
+ color: var(--terminal-muted);
+}
+
+.card-location {
+ display: flex;
+ align-items: center;
+ gap: 0.3rem;
+ font-size: 0.65rem;
+ color: var(--terminal-muted);
+}
+
+.awards {
+ display: flex;
+ flex-direction: column;
+ gap: 0.2rem;
+ margin: 0.25rem 0;
+}
+
+.award {
+ display: flex;
+ align-items: center;
+ gap: 0.3rem;
+ font-size: 0.7rem;
+}
+
+.award-icon {
+ font-size: 0.75rem;
+}
+
+.award-text {
+ color: #a6e3a1;
+ font-weight: 500;
+}
+
+.card-desc {
+ margin: 0;
+ font-size: 0.7rem;
+ color: var(--terminal-muted);
+ line-height: 1.4;
+ display: -webkit-box;
+ -webkit-line-clamp: 2;
+ line-clamp: 2;
+ -webkit-box-orient: vertical;
+ overflow: hidden;
+}
+
+.tags {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 0.25rem;
+ margin-top: auto;
+}
+
+.tag {
+ background: color-mix(in srgb, var(--terminal-primary) 15%, transparent);
+ color: var(--terminal-primary);
+ padding: 0.1rem 0.35rem;
+ border-radius: 3px;
+ font-size: 0.55rem;
+ font-weight: 500;
+ text-transform: lowercase;
+}
+
+.warning {
+ font-size: 0.6rem;
+ color: #f9e2af;
+ padding: 0.2rem 0.35rem;
+ background: rgba(249, 226, 175, 0.1);
+ border-radius: 3px;
+ width: fit-content;
+}
+
+.card-actions {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 0.35rem;
+ margin-top: 0.5rem;
+ padding-top: 0.5rem;
+ border-top: 1px solid var(--terminal-border);
+}
+
+.action-btn {
+ display: inline-flex;
+ align-items: center;
+ gap: 0.25rem;
+ padding: 0.25rem 0.5rem;
+ background: transparent;
+ border: 1px solid var(--terminal-border);
+ border-radius: 4px;
+ color: var(--terminal-text);
+ font-size: 0.65rem;
+ font-weight: 500;
+ text-decoration: none;
+ transition: all 0.15s ease;
+ font-family: inherit;
+}
+
+.action-btn:hover {
+ background: var(--terminal-primary);
+ border-color: var(--terminal-primary);
+ color: var(--terminal-bg);
+}
+
+.action-btn.primary {
+ background: var(--terminal-primary);
+ border-color: var(--terminal-primary);
+ color: var(--terminal-bg);
+}
+
+.action-btn.primary:hover {
+ background: var(--terminal-accent);
+ border-color: var(--terminal-accent);
+}
+
+@media (max-width: 600px) {
+ .tui-card-grid {
+ grid-template-columns: 1fr;
+ }
+}
diff --git a/src/lib/assets/css/tui-card.css b/src/lib/assets/css/tui-card.css
new file mode 100644
index 0000000..922d30c
--- /dev/null
+++ b/src/lib/assets/css/tui-card.css
@@ -0,0 +1,58 @@
+.tui-card {
+ border: 1px solid var(--terminal-border);
+ border-radius: 6px;
+ background: color-mix(in srgb, var(--terminal-bg) 80%, var(--card-accent) 5%);
+ margin: 0.5rem 0;
+ overflow: hidden;
+ transition: border-color 0.2s ease;
+}
+
+.tui-card:hover {
+ border-color: var(--card-accent);
+}
+
+.card-header {
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
+ padding: 0.6rem 0.75rem;
+ border-bottom: 1px solid var(--terminal-border);
+ background: rgba(0, 0, 0, 0.1);
+}
+
+:global(.card-icon) {
+ color: var(--card-accent);
+}
+
+.card-title {
+ font-weight: 600;
+ color: var(--terminal-text);
+ font-size: 0.85rem;
+}
+
+.card-body {
+ padding: 0.75rem;
+}
+
+.card-image {
+ width: 100%;
+ max-height: 200px;
+ object-fit: cover;
+ border-radius: 4px;
+ margin-bottom: 0.5rem;
+}
+
+.card-content {
+ color: var(--terminal-muted);
+ font-size: 0.85rem;
+ line-height: 1.5;
+ white-space: pre-wrap;
+}
+
+.card-footer {
+ padding: 0.5rem 0.75rem;
+ border-top: 1px solid var(--terminal-border);
+ font-size: 0.75rem;
+ color: var(--terminal-muted);
+ background: rgba(0, 0, 0, 0.05);
+}
diff --git a/src/lib/assets/css/tui-checkbox.css b/src/lib/assets/css/tui-checkbox.css
new file mode 100644
index 0000000..679c400
--- /dev/null
+++ b/src/lib/assets/css/tui-checkbox.css
@@ -0,0 +1,55 @@
+.tui-checkbox {
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
+ margin: 0.35rem 0;
+ padding: 0.35rem 0.5rem;
+ font-size: 0.9rem;
+ cursor: pointer;
+ border-radius: 4px;
+ transition: all 0.15s ease;
+ user-select: none;
+}
+
+.tui-checkbox.inline {
+ display: inline-flex;
+ margin: 0 0.75rem 0 0;
+}
+
+.tui-checkbox:hover:not(.disabled) {
+ background: color-mix(in srgb, var(--checkbox-color) 10%, transparent);
+}
+
+.tui-checkbox:focus-visible {
+ outline: 1px solid var(--checkbox-color);
+ outline-offset: 2px;
+}
+
+.tui-checkbox.disabled {
+ opacity: 0.5;
+ cursor: not-allowed;
+}
+
+.checkbox-box {
+ font-family: inherit;
+ font-weight: bold;
+ color: var(--terminal-muted);
+ transition: color 0.15s ease;
+}
+
+.tui-checkbox.checked .checkbox-box,
+.checkbox-box.indeterminate {
+ color: var(--checkbox-color);
+}
+
+:global(.checkbox-icon) {
+ color: var(--checkbox-color);
+}
+
+.checkbox-label {
+ color: var(--terminal-text);
+}
+
+.tui-checkbox.disabled .checkbox-label {
+ color: var(--terminal-muted);
+}
diff --git a/src/lib/assets/css/tui-footer.css b/src/lib/assets/css/tui-footer.css
new file mode 100644
index 0000000..3e76510
--- /dev/null
+++ b/src/lib/assets/css/tui-footer.css
@@ -0,0 +1,59 @@
+.tui-statusbar {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding: 0.4rem 0.75rem;
+ font-size: 0.75rem;
+ background: var(--terminal-bg-light);
+ border-color: var(--terminal-border);
+}
+
+.tui-statusbar.bottom {
+ border-top: 1px solid var(--terminal-border);
+}
+
+.status-left, .status-right {
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
+ color: var(--terminal-muted);
+}
+
+.status-center {
+ color: var(--terminal-primary);
+ font-weight: 600;
+}
+
+.skip-btn {
+ display: flex;
+ align-items: center;
+ gap: 0.3rem;
+ padding: 0.15rem 0.5rem;
+ background: var(--terminal-border);
+ border: 1px solid transparent;
+ border-radius: 3px;
+ color: var(--terminal-muted);
+ font-family: inherit;
+ font-size: 0.7rem;
+ cursor: pointer;
+ transition: all 0.15s ease;
+}
+
+.skip-btn:hover {
+ background: var(--terminal-primary);
+ color: var(--terminal-bg);
+ border-color: var(--terminal-primary);
+}
+
+.typing-indicator {
+ animation: pulse 1s ease-in-out infinite;
+}
+
+@keyframes pulse {
+ 0%, 100% { opacity: 1; }
+ 50% { opacity: 0.5; }
+}
+
+.line-count {
+ color: var(--terminal-muted);
+}
diff --git a/src/lib/assets/css/tui-header.css b/src/lib/assets/css/tui-header.css
new file mode 100644
index 0000000..973a074
--- /dev/null
+++ b/src/lib/assets/css/tui-header.css
@@ -0,0 +1,38 @@
+.tui-statusbar {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding: 0.4rem 0.75rem;
+ font-size: 0.75rem;
+ background: var(--terminal-bg-light);
+ border-color: var(--terminal-border);
+}
+
+.tui-statusbar.top {
+ border-bottom: 1px solid var(--terminal-border);
+}
+
+.status-left, .status-right {
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
+ color: var(--terminal-muted);
+}
+
+.status-center {
+ color: var(--terminal-primary);
+ font-weight: 600;
+}
+
+.hint {
+ padding: 0.1rem 0.4rem;
+ background: var(--terminal-border);
+ border-radius: 3px;
+ font-size: 0.7rem;
+}
+
+@media (max-width: 768px) {
+ .hint {
+ display: none;
+ }
+}
diff --git a/src/lib/assets/css/tui-input.css b/src/lib/assets/css/tui-input.css
new file mode 100644
index 0000000..24dac23
--- /dev/null
+++ b/src/lib/assets/css/tui-input.css
@@ -0,0 +1,96 @@
+.tui-input {
+ margin: 0.5rem 0;
+ font-size: 0.9rem;
+}
+
+.tui-input.inline {
+ display: inline-flex;
+ flex-direction: column;
+ margin: 0 0.5rem 0 0;
+}
+
+.input-label {
+ display: flex;
+ align-items: center;
+ gap: 0.35rem;
+ margin-bottom: 0.35rem;
+ color: var(--terminal-muted);
+ font-size: 0.85rem;
+}
+
+:global(.label-icon) {
+ color: var(--input-color);
+}
+
+.input-wrapper {
+ display: flex;
+ align-items: center;
+ gap: 0.35rem;
+ padding: 0.5rem 0.75rem;
+ background: color-mix(in srgb, var(--terminal-bg) 80%, black);
+ border: 1px solid var(--terminal-muted);
+ border-radius: 4px;
+ transition: all 0.15s ease;
+}
+
+.input-wrapper:focus-within {
+ border-color: var(--input-color);
+ box-shadow: 0 0 0 1px color-mix(in srgb, var(--input-color) 30%, transparent);
+}
+
+.tui-input.error .input-wrapper {
+ border-color: #f38ba8;
+}
+
+.tui-input.disabled .input-wrapper {
+ opacity: 0.5;
+ cursor: not-allowed;
+}
+
+.input-prompt {
+ color: var(--input-color);
+ font-weight: bold;
+ user-select: none;
+}
+
+.input-affix {
+ color: var(--terminal-muted);
+ font-size: 0.85rem;
+}
+
+.input-affix.prefix {
+ margin-right: 0.25rem;
+}
+
+.input-affix.suffix {
+ margin-left: 0.25rem;
+}
+
+input {
+ flex: 1;
+ min-width: 0;
+ background: transparent;
+ border: none;
+ color: var(--terminal-text);
+ font-family: inherit;
+ font-size: inherit;
+ outline: none;
+}
+
+input::placeholder {
+ color: var(--terminal-muted);
+ opacity: 0.6;
+}
+
+input:disabled {
+ cursor: not-allowed;
+}
+
+.input-error {
+ display: flex;
+ align-items: center;
+ gap: 0.35rem;
+ margin-top: 0.35rem;
+ color: #f38ba8;
+ font-size: 0.8rem;
+}
diff --git a/src/lib/assets/css/tui-link.css b/src/lib/assets/css/tui-link.css
new file mode 100644
index 0000000..5da3408
--- /dev/null
+++ b/src/lib/assets/css/tui-link.css
@@ -0,0 +1,45 @@
+.tui-link {
+ display: inline-flex;
+ align-items: center;
+ gap: 0.25rem;
+}
+
+:global(.link-icon) {
+ color: var(--link-color);
+ opacity: 0.8;
+}
+
+.link-text {
+ background: none;
+ border: none;
+ padding: 0;
+ margin: 0;
+ font-family: inherit;
+ font-size: inherit;
+ color: var(--link-color);
+ text-decoration: underline;
+ text-decoration-style: dotted;
+ text-underline-offset: 2px;
+ cursor: pointer;
+ transition: all 0.15s ease;
+}
+
+.link-text:hover {
+ text-decoration-style: solid;
+ filter: brightness(1.2);
+}
+
+:global(.link-external) {
+ color: var(--link-color);
+ opacity: 0.5;
+}
+
+.tui-link:hover :global(.link-external) {
+ opacity: 0.8;
+}
+
+:global(.inline-icon) {
+ display: inline-block;
+ vertical-align: middle;
+ margin: 0 0.15em;
+}
diff --git a/src/lib/assets/css/tui-progress.css b/src/lib/assets/css/tui-progress.css
new file mode 100644
index 0000000..885f340
--- /dev/null
+++ b/src/lib/assets/css/tui-progress.css
@@ -0,0 +1,104 @@
+.tui-progress {
+ margin: 0.5rem 0;
+ font-size: 0.85rem;
+}
+
+/* Inline progress styles */
+.tui-progress.inline {
+ display: inline-flex;
+ align-items: center;
+ gap: 0.5rem;
+ margin: 0;
+ min-width: 120px;
+}
+
+.tui-progress.inline .progress-label {
+ margin-bottom: 0;
+ white-space: nowrap;
+}
+
+.tui-progress.inline .progress-bar {
+ flex: 1;
+ min-width: 80px;
+ height: 0.8rem;
+}
+
+.tui-progress.inline .progress-value {
+ margin-top: 0;
+ white-space: nowrap;
+}
+
+.progress-label {
+ color: var(--terminal-text);
+ margin-bottom: 0.25rem;
+}
+
+.progress-bar {
+ position: relative;
+ height: 1.2rem;
+ background: var(--terminal-border);
+ border-radius: 3px;
+ overflow: hidden;
+}
+
+.progress-fill {
+ position: absolute;
+ top: 0;
+ left: 0;
+ height: 100%;
+ background: linear-gradient(90deg, var(--progress-color), color-mix(in srgb, var(--progress-color) 80%, white 20%));
+ border-radius: 3px;
+ transition: width 0.3s ease;
+}
+
+.progress-glow {
+ position: absolute;
+ right: 0;
+ top: 0;
+ height: 100%;
+ width: 20px;
+ background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.3));
+ animation: shimmer 1.5s infinite;
+}
+
+@keyframes shimmer {
+ 0% { opacity: 0; }
+ 50% { opacity: 1; }
+ 100% { opacity: 0; }
+}
+
+.progress-blocks {
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ display: flex;
+ gap: 2px;
+ padding: 3px;
+}
+
+.block {
+ flex: 1;
+ background: rgba(0, 0, 0, 0.2);
+ border-radius: 1px;
+ transition: background 0.2s;
+}
+
+.block.filled {
+ background: transparent;
+}
+
+.progress-value {
+ text-align: right;
+ color: var(--progress-color);
+ font-size: 0.75rem;
+ margin-top: 0.25rem;
+ font-weight: 600;
+}
+
+:global(.inline-icon) {
+ display: inline-block;
+ vertical-align: middle;
+ margin: 0 0.15em;
+}
diff --git a/src/lib/assets/css/tui-radio.css b/src/lib/assets/css/tui-radio.css
new file mode 100644
index 0000000..3a879ab
--- /dev/null
+++ b/src/lib/assets/css/tui-radio.css
@@ -0,0 +1,87 @@
+.tui-radio-group {
+ margin: 0.5rem 0;
+ font-size: 0.9rem;
+}
+
+.tui-radio-group.inline {
+ display: inline-flex;
+ flex-direction: column;
+ margin: 0 0.75rem 0 0;
+}
+
+.tui-radio-group.disabled {
+ opacity: 0.5;
+}
+
+.radio-label {
+ display: flex;
+ align-items: center;
+ gap: 0.35rem;
+ margin-bottom: 0.5rem;
+ color: var(--terminal-muted);
+ font-size: 0.85rem;
+}
+
+:global(.label-icon) {
+ color: var(--radio-color);
+}
+
+.radio-options {
+ display: flex;
+ flex-direction: column;
+ gap: 0.25rem;
+}
+
+.radio-options.horizontal {
+ flex-direction: row;
+ flex-wrap: wrap;
+ gap: 0.75rem;
+}
+
+.radio-option {
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
+ padding: 0.35rem 0.5rem;
+ cursor: pointer;
+ border-radius: 4px;
+ transition: all 0.15s ease;
+ user-select: none;
+}
+
+.radio-option:hover:not(.option-disabled) {
+ background: color-mix(in srgb, var(--radio-color) 10%, transparent);
+}
+
+.radio-option:focus-visible {
+ outline: 1px solid var(--radio-color);
+ outline-offset: 2px;
+}
+
+.radio-option.option-disabled {
+ opacity: 0.5;
+ cursor: not-allowed;
+}
+
+.radio-symbol {
+ font-family: inherit;
+ font-weight: bold;
+ color: var(--terminal-muted);
+ transition: color 0.15s ease;
+}
+
+.radio-option.selected .radio-symbol {
+ color: var(--radio-color);
+}
+
+:global(.option-icon) {
+ color: var(--radio-color);
+}
+
+.option-label {
+ color: var(--terminal-text);
+}
+
+.radio-option.option-disabled .option-label {
+ color: var(--terminal-muted);
+}
diff --git a/src/lib/assets/css/tui-select.css b/src/lib/assets/css/tui-select.css
new file mode 100644
index 0000000..9a2d038
--- /dev/null
+++ b/src/lib/assets/css/tui-select.css
@@ -0,0 +1,162 @@
+.tui-select {
+ position: relative;
+ margin: 0.5rem 0;
+ font-size: 0.9rem;
+}
+
+.tui-select.inline {
+ display: inline-flex;
+ flex-direction: column;
+ margin: 0 0.5rem 0 0;
+}
+
+.select-label {
+ display: flex;
+ align-items: center;
+ gap: 0.35rem;
+ margin-bottom: 0.35rem;
+ color: var(--terminal-muted);
+ font-size: 0.85rem;
+}
+
+:global(.label-icon) {
+ color: var(--select-color);
+}
+
+.select-trigger {
+ display: flex;
+ align-items: center;
+ gap: 0.35rem;
+ padding: 0.5rem 0.75rem;
+ background: color-mix(in srgb, var(--terminal-bg) 80%, black);
+ border: 1px solid var(--terminal-muted);
+ border-radius: 4px;
+ cursor: pointer;
+ transition: all 0.15s ease;
+}
+
+.tui-select.open .select-trigger,
+.select-trigger:focus-visible {
+ border-color: var(--select-color);
+ box-shadow: 0 0 0 1px color-mix(in srgb, var(--select-color) 30%, transparent);
+}
+
+.tui-select.error .select-trigger {
+ border-color: #f38ba8;
+}
+
+.tui-select.disabled .select-trigger {
+ opacity: 0.5;
+ cursor: not-allowed;
+}
+
+.select-prompt {
+ color: var(--select-color);
+ font-weight: bold;
+}
+
+.select-value {
+ flex: 1;
+ color: var(--terminal-text);
+}
+
+.select-value.placeholder {
+ color: var(--terminal-muted);
+ opacity: 0.6;
+}
+
+.select-arrow {
+ color: var(--terminal-muted);
+ font-size: 0.7rem;
+}
+
+.select-dropdown {
+ position: absolute;
+ top: 100%;
+ left: 0;
+ right: 0;
+ margin-top: 0.25rem;
+ background: var(--terminal-bg);
+ border: 1px solid var(--select-color);
+ border-radius: 4px;
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
+ z-index: 100;
+ overflow: hidden;
+}
+
+.select-search {
+ display: flex;
+ align-items: center;
+ gap: 0.35rem;
+ padding: 0.5rem 0.75rem;
+ border-bottom: 1px solid var(--terminal-muted);
+}
+
+.select-search input {
+ flex: 1;
+ background: transparent;
+ border: none;
+ color: var(--terminal-text);
+ font-family: inherit;
+ font-size: inherit;
+ outline: none;
+}
+
+.select-search input::placeholder {
+ color: var(--terminal-muted);
+}
+
+.select-options {
+ max-height: 200px;
+ overflow-y: auto;
+}
+
+.select-option {
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
+ padding: 0.5rem 0.75rem;
+ cursor: pointer;
+ transition: background 0.1s ease;
+}
+
+.select-option.highlighted {
+ background: color-mix(in srgb, var(--select-color) 15%, transparent);
+}
+
+.select-option.selected {
+ color: var(--select-color);
+}
+
+.select-option.option-disabled {
+ opacity: 0.5;
+ cursor: not-allowed;
+}
+
+:global(.option-icon) {
+ color: var(--select-color);
+}
+
+.option-label {
+ flex: 1;
+}
+
+:global(.check-icon) {
+ color: var(--select-color);
+}
+
+.select-empty {
+ padding: 0.75rem;
+ text-align: center;
+ color: var(--terminal-muted);
+ font-style: italic;
+}
+
+.select-error {
+ display: flex;
+ align-items: center;
+ gap: 0.35rem;
+ margin-top: 0.35rem;
+ color: #f38ba8;
+ font-size: 0.8rem;
+}
diff --git a/src/lib/assets/css/tui-table.css b/src/lib/assets/css/tui-table.css
new file mode 100644
index 0000000..7d61c12
--- /dev/null
+++ b/src/lib/assets/css/tui-table.css
@@ -0,0 +1,49 @@
+.tui-table-wrapper {
+ margin: 0.5rem 0;
+ border: 1px solid var(--terminal-border);
+ border-radius: 6px;
+ overflow: hidden;
+}
+
+.table-title {
+ padding: 0.5rem 0.75rem;
+ font-weight: 600;
+ font-size: 0.85rem;
+ color: var(--terminal-text);
+ background: rgba(0, 0, 0, 0.1);
+ border-bottom: 1px solid var(--terminal-border);
+}
+
+.tui-table {
+ width: 100%;
+ border-collapse: collapse;
+ font-size: 0.8rem;
+}
+
+th {
+ padding: 0.5rem 0.75rem;
+ text-align: left;
+ font-weight: 600;
+ color: var(--table-accent);
+ background: rgba(0, 0, 0, 0.15);
+ border-bottom: 1px solid var(--terminal-border);
+ white-space: nowrap;
+}
+
+td {
+ padding: 0.4rem 0.75rem;
+ color: var(--terminal-text);
+ border-bottom: 1px solid var(--terminal-border);
+}
+
+tr:last-child td {
+ border-bottom: none;
+}
+
+tr.alt {
+ background: rgba(0, 0, 0, 0.03);
+}
+
+tr:hover {
+ background: color-mix(in srgb, var(--table-accent) 5%, transparent);
+}
diff --git a/src/lib/assets/css/tui-textarea.css b/src/lib/assets/css/tui-textarea.css
new file mode 100644
index 0000000..1f4a673
--- /dev/null
+++ b/src/lib/assets/css/tui-textarea.css
@@ -0,0 +1,113 @@
+.tui-textarea {
+ margin: 0.5rem 0;
+ font-size: 0.9rem;
+}
+
+.tui-textarea.inline {
+ display: inline-flex;
+ flex-direction: column;
+ margin: 0 0.5rem 0 0;
+}
+
+.textarea-label {
+ display: flex;
+ align-items: center;
+ gap: 0.35rem;
+ margin-bottom: 0.35rem;
+ color: var(--terminal-muted);
+ font-size: 0.85rem;
+}
+
+:global(.label-icon) {
+ color: var(--input-color);
+}
+
+.textarea-wrapper {
+ display: flex;
+ background: color-mix(in srgb, var(--terminal-bg) 80%, black);
+ border: 1px solid var(--terminal-muted);
+ border-radius: 4px;
+ transition: all 0.15s ease;
+ overflow: hidden;
+}
+
+.tui-textarea.focused .textarea-wrapper {
+ border-color: var(--input-color);
+ box-shadow: 0 0 0 1px color-mix(in srgb, var(--input-color) 30%, transparent);
+}
+
+.tui-textarea.error .textarea-wrapper {
+ border-color: #f38ba8;
+}
+
+.tui-textarea.disabled .textarea-wrapper {
+ opacity: 0.5;
+ cursor: not-allowed;
+}
+
+.line-numbers {
+ display: flex;
+ flex-direction: column;
+ padding: 0.5rem 0;
+ background: color-mix(in srgb, var(--terminal-bg) 60%, black);
+ border-right: 1px solid var(--terminal-muted);
+ user-select: none;
+}
+
+.line-num {
+ padding: 0 0.5rem;
+ color: var(--terminal-muted);
+ font-size: 0.8rem;
+ line-height: 1.5;
+ text-align: right;
+ min-width: 2rem;
+}
+
+textarea {
+ flex: 1;
+ min-width: 0;
+ padding: 0.5rem 0.75rem;
+ background: transparent;
+ border: none;
+ color: var(--terminal-text);
+ font-family: inherit;
+ font-size: inherit;
+ line-height: 1.5;
+ resize: vertical;
+ outline: none;
+}
+
+textarea::placeholder {
+ color: var(--terminal-muted);
+ opacity: 0.6;
+}
+
+textarea:disabled {
+ cursor: not-allowed;
+ resize: none;
+}
+
+.textarea-footer {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-top: 0.35rem;
+}
+
+.textarea-error {
+ display: flex;
+ align-items: center;
+ gap: 0.35rem;
+ color: #f38ba8;
+ font-size: 0.8rem;
+}
+
+.char-count {
+ margin-left: auto;
+ color: var(--terminal-muted);
+ font-size: 0.75rem;
+}
+
+.char-count.warning {
+ color: #f9e2af;
+}
diff --git a/src/lib/assets/css/tui-toggle.css b/src/lib/assets/css/tui-toggle.css
new file mode 100644
index 0000000..1e04a4c
--- /dev/null
+++ b/src/lib/assets/css/tui-toggle.css
@@ -0,0 +1,94 @@
+.tui-toggle {
+ display: flex;
+ align-items: center;
+ gap: 0.75rem;
+ margin: 0.35rem 0;
+ padding: 0.35rem 0.5rem;
+ font-size: 0.9rem;
+ cursor: pointer;
+ border-radius: 4px;
+ transition: all 0.15s ease;
+ user-select: none;
+}
+
+.tui-toggle.inline {
+ display: inline-flex;
+ margin: 0 0.75rem 0 0;
+}
+
+.tui-toggle:hover:not(.disabled) {
+ background: color-mix(in srgb, var(--toggle-color) 10%, transparent);
+}
+
+.tui-toggle:focus-visible {
+ outline: 1px solid var(--toggle-color);
+ outline-offset: 2px;
+}
+
+.tui-toggle.disabled {
+ opacity: 0.5;
+ cursor: not-allowed;
+}
+
+:global(.toggle-icon) {
+ color: var(--toggle-color);
+}
+
+.toggle-label {
+ color: var(--terminal-text);
+}
+
+.toggle-track {
+ display: flex;
+ align-items: center;
+ gap: 0.25rem;
+ padding: 0.25rem 0.5rem;
+ background: color-mix(in srgb, var(--terminal-bg) 80%, black);
+ border: 1px solid var(--terminal-muted);
+ border-radius: 4px;
+ font-size: 0.75rem;
+ transition: all 0.15s ease;
+}
+
+.tui-toggle.checked .toggle-track {
+ border-color: var(--toggle-color);
+ background: color-mix(in srgb, var(--toggle-color) 15%, transparent);
+}
+
+.toggle-off-label,
+.toggle-on-label {
+ color: var(--terminal-muted);
+ font-weight: bold;
+ text-transform: uppercase;
+ min-width: 2rem;
+ text-align: center;
+ transition: color 0.15s ease;
+}
+
+.tui-toggle:not(.checked) .toggle-off-label {
+ color: var(--terminal-text);
+}
+
+.tui-toggle.checked .toggle-on-label {
+ color: var(--toggle-color);
+}
+
+.toggle-switch {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ width: 2.5rem;
+ position: relative;
+}
+
+.toggle-knob {
+ font-size: 1rem;
+ color: var(--terminal-muted);
+ transition: all 0.2s ease;
+ transform: translateX(-0.5rem);
+}
+
+.tui-toggle.checked .toggle-knob {
+ color: var(--toggle-color);
+ transform: translateX(0.5rem);
+}
diff --git a/src/lib/assets/css/tui-tooltip.css b/src/lib/assets/css/tui-tooltip.css
new file mode 100644
index 0000000..d50cd20
--- /dev/null
+++ b/src/lib/assets/css/tui-tooltip.css
@@ -0,0 +1,78 @@
+.tui-tooltip-trigger {
+ position: relative;
+ display: inline-flex;
+ align-items: center;
+ gap: 0.25rem;
+ cursor: help;
+}
+
+.trigger-text {
+ border-bottom: 1px dotted var(--tooltip-color);
+}
+
+.tooltip-indicator {
+ font-size: 0.7rem;
+ color: var(--tooltip-color);
+ opacity: 0.7;
+}
+
+.tooltip {
+ position: fixed;
+ z-index: 99999;
+ padding: 0.5rem 0.75rem;
+ background: var(--terminal-bg);
+ border: 1px solid var(--tooltip-color);
+ border-radius: 4px;
+ font-size: 0.8rem;
+ color: var(--terminal-text);
+ white-space: nowrap;
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.4);
+ animation: tooltipFadeIn 0.15s ease-out;
+ pointer-events: none;
+}
+
+@keyframes tooltipFadeIn {
+ from {
+ opacity: 0;
+ transform: scale(0.95);
+ }
+ to {
+ opacity: 1;
+ transform: scale(1);
+ }
+}
+
+/* Arrow styles - simplified for fixed positioning */
+.tooltip-arrow {
+ position: absolute;
+ width: 8px;
+ height: 8px;
+ background: var(--terminal-bg);
+ border: 1px solid var(--tooltip-color);
+ border-top: none;
+ border-left: none;
+}
+
+.tooltip.top .tooltip-arrow {
+ bottom: -5px;
+ left: 50%;
+ transform: translateX(-50%) rotate(45deg);
+}
+
+.tooltip.bottom .tooltip-arrow {
+ top: -5px;
+ left: 50%;
+ transform: translateX(-50%) rotate(-135deg);
+}
+
+.tooltip.left .tooltip-arrow {
+ right: -5px;
+ top: 50%;
+ transform: translateY(-50%) rotate(-45deg);
+}
+
+.tooltip.right .tooltip-arrow {
+ left: -5px;
+ top: 50%;
+ transform: translateY(-50%) rotate(135deg);
+}
diff --git a/src/lib/components/Background3D.svelte b/src/lib/components/Background3D.svelte
index 0d3e9a2..30dce5c 100644
--- a/src/lib/components/Background3D.svelte
+++ b/src/lib/components/Background3D.svelte
@@ -4,6 +4,7 @@
import ParticleField from './ParticleField.svelte';
import { themeColors, mode } from '$lib/stores/theme';
import * as THREE from 'three';
+ import '$lib/assets/css/background-3d.css';
let bgColor = $derived($mode === 'dark' ? $themeColors.background : $themeColors.background);
@@ -35,19 +36,3 @@