@use 'kit-deps' as *;
// ─── Breakpoints ───────────────────────────────────────────────────────────
$bp-mobile: 768px;
// ─── App shell ─────────────────────────────────────────────────────────────
$sidebar-width: 380px;
html, body {
height: 100%;
}
// #app is the Vue mount point — full viewport flex container
#app {
display: flex;
height: 100vh;
height: 100dvh;
overflow: hidden;
}
// ─── Main content area (sibling of sidebar) ────────────────────────────────
.app-main {
flex: 1 1 0; // flex-basis:0 prevents content from dictating height
min-width: 0;
min-height: 0;
display: flex;
flex-direction: column;
overflow: hidden;
background: $surface-page;
}
// ─── Sidebar ───────────────────────────────────────────────────────────────
.app-sidebar {
width: $sidebar-width;
min-width: $sidebar-width;
display: flex;
flex-direction: column;
background: $surface-panel;
border-right: $border-width-base $border-style-base $border-color-muted;
overflow: hidden;
flex-shrink: 0;
@media (max-width: $bp-mobile) {
position: fixed;
inset: 0;
z-index: 100;
width: 100% !important;
min-width: unset !important;
transform: translateX(-100%);
transition: transform 0.28s ease;
&.is-mobile-open {
transform: translateX(0);
}
}
}
.sidebar-header {
padding: $space-md;
border-bottom: $border-width-base $border-style-base $border-color-muted;
display: flex;
flex-direction: column;
gap: $space-sm;
}
.sidebar-controls-row {
display: flex;
align-items: center;
gap: $space-sm;
.sidebar-profile-select {
flex: 1;
min-width: 0;
}
}
.sidebar-logo {
display: flex;
align-items: center;
gap: $space-sm;
text-decoration: none;
img {
width: 28px;
height: 28px;
}
span {
font-size: 18px;
font-weight: 700;
color: $color-text-light;
letter-spacing: -0.3px;
}
}
.sidebar-sessions {
flex: 1;
overflow: hidden;
display: flex;
flex-direction: column;
}
.sessions-label {
padding: $space-sm $space-md;
font-size: 11px;
text-transform: uppercase;
letter-spacing: 0.08em;
color: $color-text-dark;
}
// ─── Sidebar profile selector ──────────────────────────────────────────────
// Standalone .input-style select (outside .form-group context)
.sidebar-profile-select {
position: relative;
select {
width: 100%;
appearance: none;
-webkit-appearance: none;
min-height: $control-height-md;
font-family: inherit;
font-size: 13px;
font-weight: 500;
padding: $space-xs $space-xl $space-xs $space-md;
border: $border-width-base $border-style-base $border-color-muted;
border-bottom-width: $border-width-accent;
border-bottom-color: $color-text-light;
color: $color-text-light;
background-color: $surface-panel-muted;
cursor: pointer;
transition: border-color $motion-base $motion-ease, background-color $motion-base $motion-ease;
outline: none;
&:hover {
border-bottom-color: $color-text-dark;
}
&:focus {
@include focus_ring;
border-color: $color-electric-blue;
background-color: transparent;
}
option {
background: $surface-panel;
color: $color-text-light;
}
}
// Custom chevron arrow
&::after {
content: "";
position: absolute;
right: $space-md;
top: 50%;
transform: translateY(-50%);
width: 0;
height: 0;
border-left: 4px solid transparent;
border-right: 4px solid transparent;
border-top: 5px solid $color-text-medium;
pointer-events: none;
}
}
// ─── Session item ──────────────────────────────────────────────────────────
.session-item {
display: flex;
align-items: flex-start;
gap: $space-sm;
padding: $space-sm $space-md;
height: 74px;
box-sizing: border-box;
cursor: pointer;
border-radius: 0;
transition: background $motion-fast $motion-ease;
position: relative;
&:hover {
background: $surface-panel-muted;
.session-actions {
opacity: 1;
}
}
&.is-active {
background: $surface-panel-strong;
border-left: $border-width-accent $border-style-base $color-secondary;
padding-left: calc(#{$space-md} - #{$border-width-accent});
}
&.is-pinned {
background: rgba($color-warning, 0.07);
.session-pin-icon {
opacity: 1;
color: $color-warning;
}
.session-name {
color: $color-warning;
}
}
}
.session-pin-icon {
color: $color-text-dark;
font-size: $icon-size-xs;
opacity: 0;
transition: opacity $motion-fast $motion-ease;
flex-shrink: 0;
margin-top: 2px;
}
.session-info {
flex: 1;
overflow: hidden;
}
.session-name {
font-size: 12px;
color: $color-text-medium;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
line-height: 1.4;
}
.session-preview {
font-size: 13px;
color: $color-text-light;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
line-height: 1.4;
margin-top: 3px;
}
.session-actions {
display: flex;
gap: $space-xs;
opacity: 0;
transition: opacity $motion-fast $motion-ease;
flex-shrink: 0;
align-self: flex-start;
margin-top: 1px;
}
// ─── Chat area (ChatArea.vue root) ─────────────────────────────────────────
.chat-area {
flex: 1 1 0;
min-height: 0;
min-width: 0;
display: flex;
flex-direction: column;
overflow: hidden;
background: $surface-page;
}
// ─── Chat header ───────────────────────────────────────────────────────────
.chat-header {
display: flex;
align-items: center;
gap: $space-sm;
padding: $space-sm $space-md;
border-bottom: $border-width-base $border-style-base $border-color-muted;
background: $surface-panel;
flex-shrink: 0;
min-height: 54px;
}
.chat-header-info {
flex: 1;
display: flex;
align-items: center;
gap: $space-sm;
overflow: hidden;
min-width: 0;
}
.chat-header-title {
font-size: 14px;
font-weight: 600;
color: $color-text-light;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
flex-shrink: 1;
min-width: 0;
}
.btn-sidebar-toggle {
display: none;
@media (max-width: $bp-mobile) {
display: flex;
}
}
// ─── Context bar (token indicator) ─────────────────────────────────────────
.context-bar {
display: flex;
flex-direction: column;
gap: 4px;
flex-shrink: 0;
cursor: default;
align-items: flex-end;
}
.context-bar-track {
width: 100px;
height: 5px;
background: $surface-panel-strong;
overflow: hidden;
}
.context-bar-fill {
height: 100%;
transition: width $motion-base $motion-ease, background-color $motion-base $motion-ease;
background: $color-success;
&.is-warn { background: $color-warning; }
&.is-crit { background: $color-error; }
}
// ─── Profile badge ─────────────────────────────────────────────────────────
.profile-badge {
display: inline-flex;
align-items: center;
gap: $space-xs;
padding: 2px $space-sm;
background: $surface-panel-muted;
border: $border-width-base $border-style-base $border-color-muted;
font-size: 12px;
color: $color-text-medium;
white-space: nowrap;
}
// ─── Message list ──────────────────────────────────────────────────────────
.message-list {
flex: 1;
overflow-y: auto;
overflow-x: hidden;
padding: $space-lg $space-md;
display: flex;
flex-direction: column;
gap: $space-md;
// Virtual scroller overrides
.vue-recycle-scroller {
flex: 1;
}
}
.message-list-inner {
display: flex;
flex-direction: column;
gap: $space-xl;
width: 100%;
padding: $space-xl $space-lg;
}
// ─── Messages ──────────────────────────────────────────────────────────────
.msg-user {
display: flex;
justify-content: flex-end;
gap: $space-sm;
}
.msg-user-bubble {
max-width: 70%;
background: $color-secondary;
color: $color-black;
padding: $space-sm $space-md;
font-size: 14px;
line-height: 1.6;
word-wrap: break-word;
@media (max-width: $bp-mobile) {
max-width: 90%;
}
}
.msg-user-attachments {
display: flex;
flex-wrap: wrap;
gap: $space-xs;
margin-top: $space-xs;
}
.msg-user-image {
width: 80px;
height: 80px;
object-fit: cover;
cursor: zoom-in;
}
.msg-user-file-pill {
display: inline-flex;
align-items: center;
gap: $space-xs;
padding: 2px $space-sm;
background: rgba($color-black, 0.3);
font-size: 12px;
}
.msg-assistant {
display: flex;
flex-direction: column;
gap: $space-sm;
max-width: 100%;
}
.msg-assistant-avatar {
width: 28px;
height: 28px;
border-radius: 50%;
flex-shrink: 0;
}
.msg-assistant-content {
font-size: 14px;
line-height: 1.7;
color: $color-text-light;
// Markdown styles
p { margin: 0 0 $space-md; &:last-child { margin-bottom: 0; } }
h1, h2, h3, h4 { margin: $space-lg 0 $space-sm; color: $color-text-light; }
ul, ol { padding-left: $space-lg; margin-bottom: $space-md; }
li { margin-bottom: $space-sm; }
blockquote {
margin: $space-sm 0;
padding-left: $space-md;
border-left: $border-width-accent $border-style-base $color-secondary;
color: $color-text-medium;
}
a { color: $color-secondary; }
strong { color: $color-text-light; }
hr { border: none; border-top: 1px solid $border-color-muted; margin: $space-md 0; }
// Markdown tables: map native elements to kit .table visual style
.table {
margin: $space-md 0;
thead {
border-bottom: $border-width-base $border-style-base $color-primary;
}
tbody {
tr {
transition: background $motion-base $motion-ease;
&:hover {
background: rgba($color-secondary, 0.08);
td:first-child { color: $color-secondary; }
}
}
}
tr th, tr td {
padding: $space-sm $space-md;
font-size: 13px;
vertical-align: middle;
border-bottom: $border-width-base $border-style-base rgba($color-text-light, 0.08);
}
tr th {
color: $color-primary;
background: rgba($color-text-light, 0.04);
text-transform: uppercase;
letter-spacing: 0.06em;
}
}
// Code inline
:not(pre) > code {
font-family: "IBM Plex Mono", monospace;
font-size: 13px;
background: $surface-panel-strong;
padding: 1px 5px;
color: $color-cyan;
}
// Code blocks — .code-block wraps header + pre
.code-block {
margin: $space-md 0;
background: $surface-panel;
border: $border-width-base $border-style-base $border-color-muted;
overflow: hidden;
.code-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: $space-xs $space-md;
background: $surface-panel-strong;
border-bottom: $border-width-base $border-style-base $border-color-muted;
font-size: 12px;
color: $color-text-dark;
font-family: "IBM Plex Mono", monospace;
}
pre {
margin: 0;
background: $surface-panel !important;
code {
font-family: "IBM Plex Mono", monospace;
font-size: 13px;
display: block;
padding: $space-md;
overflow-x: auto;
}
}
}
}
// ─── Thinking card ─────────────────────────────────────────────────────────
.thinking-card {
margin-bottom: $space-sm;
summary {
list-style: none;
display: flex;
align-items: center;
gap: $space-sm;
padding: $space-sm $space-md;
cursor: pointer;
color: $color-text-dark;
font-size: 13px;
font-style: italic;
background: $surface-panel-muted;
border: $border-width-base $border-style-base $border-color-muted;
transition: background $motion-fast $motion-ease;
user-select: none;
&::-webkit-details-marker { display: none; }
&:hover { background: $surface-panel-strong; }
}
&[open] summary {
border-bottom-color: transparent;
}
.thinking-body {
padding: $space-md;
font-size: 13px;
font-style: italic;
color: $color-text-medium;
line-height: 1.6;
background: $surface-panel-muted;
border: $border-width-base $border-style-base $border-color-muted;
border-top: none;
white-space: pre-wrap;
}
}
// ─── Plan card ─────────────────────────────────────────────────────────────
.plan-card {
border: $border-width-base $border-style-base $color-info;
border-left-width: $border-width-accent;
border-left-color: $color-info;
overflow: hidden;
font-size: 13px;
margin-bottom: $space-sm;
summary {
list-style: none;
display: flex;
align-items: center;
gap: $space-sm;
padding: $space-sm $space-md;
cursor: pointer;
background: rgba($color-info, 0.08);
color: $color-info;
font-size: 13px;
user-select: none;
&::-webkit-details-marker { display: none; }
&:hover { background: rgba($color-info, 0.14); }
.plan-chevron {
margin-left: auto;
font-size: $icon-size-sm;
color: rgba($color-info, 0.6);
transition: transform $motion-fast $motion-ease;
flex-shrink: 0;
}
}
&[open] .plan-chevron {
transform: rotate(180deg);
}
.plan-body {
padding: $space-md;
font-size: 13px;
color: $color-text-medium;
line-height: 1.6;
background: rgba($color-info, 0.04);
border-top: $border-width-base $border-style-base rgba($color-info, 0.3);
p { margin: 0 0 $space-sm; &:last-child { margin-bottom: 0; } }
ul, ol { padding-left: $space-lg; margin-bottom: $space-sm; }
li { margin-bottom: $space-xs; }
strong { color: $color-text-light; }
}
}
// ─── Tool card ─────────────────────────────────────────────────────────────
.tool-card {
border: $border-width-base $border-style-base $border-color-muted;
border-left-width: $border-width-accent;
margin-bottom: $space-sm;
border-left-color: $color-secondary;
overflow: hidden;
font-size: 13px;
&.is-success { border-left-color: $color-success; }
&.is-error { border-left-color: $color-error; }
summary {
list-style: none;
display: flex;
align-items: center;
gap: $space-sm;
padding: $space-sm $space-md;
cursor: pointer;
background: $surface-panel-muted;
color: $color-text-medium;
user-select: none;
&::-webkit-details-marker { display: none; }
&:hover { background: $surface-panel-strong; }
}
.tool-name {
flex: 1;
font-family: "IBM Plex Mono", monospace;
font-size: 12px;
}
.tool-status-icon {
display: flex;
align-items: center;
justify-content: center;
width: $icon-size-sm;
height: $icon-size-sm;
font-size: $icon-size-sm;
flex-shrink: 0;
}
.tool-emoji {
font-size: $icon-size-sm;
line-height: 1;
flex-shrink: 0;
}
.tool-chevron {
font-size: $icon-size-sm;
color: $color-text-dark;
flex-shrink: 0;
transition: transform $motion-fast $motion-ease;
}
&[open] .tool-chevron {
transform: rotate(180deg);
}
}
.tool-card-body {
background: $surface-panel-muted;
border-top: $border-width-base $border-style-base $border-color-muted;
}
.tool-section {
padding: $space-sm $space-md;
& + & {
border-top: 1px solid $border-color-muted;
}
}
.tool-section-label {
font-size: 11px;
text-transform: uppercase;
letter-spacing: 0.06em;
color: $color-text-dark;
margin-bottom: $space-xs;
}
.tool-code {
font-family: "IBM Plex Mono", monospace;
font-size: 12px;
color: $color-text-medium;
white-space: pre-wrap;
word-break: break-all;
max-height: 200px;
overflow-y: auto;
}
// ─── Subagent steps ────────────────────────────────────────────────────────
.subagent-steps {
display: flex;
flex-direction: column;
gap: $space-xs;
padding: $space-xs $space-md $space-md;
background: $surface-panel-muted;
}
// ─── Summary / compression notice ──────────────────────────────────────────
.summary-card {
border: $border-width-base $border-style-base $color-info;
overflow: hidden;
font-size: 13px;
summary {
list-style: none;
display: flex;
align-items: center;
gap: $space-sm;
padding: $space-sm $space-md;
cursor: pointer;
background: rgba($color-info, 0.08);
color: $color-info;
user-select: none;
&::-webkit-details-marker { display: none; }
}
}
.compression-notice {
text-align: center;
padding: $space-sm;
font-size: 12px;
color: $color-text-dark;
display: flex;
align-items: center;
justify-content: center;
gap: $space-sm;
&::before, &::after {
content: '';
flex: 1;
height: 1px;
background: $border-color-muted;
}
}
// ─── Input bar ─────────────────────────────────────────────────────────────
.input-bar {
flex-shrink: 0;
padding: $space-sm $space-md $space-md;
background: $surface-page;
border-top: $border-width-base $border-style-base $border-color-muted;
}
.input-dropzone {
position: relative;
&.is-dragging::after {
content: 'Drop files here';
position: absolute;
inset: 0;
display: flex;
align-items: center;
justify-content: center;
background: rgba($color-secondary, 0.12);
border: 2px dashed $color-secondary;
font-size: 14px;
color: $color-secondary;
pointer-events: none;
z-index: 10;
}
}
.file-preview-strip {
display: flex;
flex-wrap: wrap;
gap: $space-xs;
margin-bottom: $space-xs;
}
.file-preview-image {
position: relative;
width: 60px;
height: 60px;
img {
width: 100%;
height: 100%;
object-fit: cover;
border: $border-width-base $border-style-base $border-color-muted;
}
}
.file-preview-pill {
display: inline-flex;
align-items: center;
gap: $space-xs;
padding: $space-xs $space-sm;
background: $surface-panel-muted;
border: $border-width-base $border-style-base $border-color-muted;
font-size: 12px;
color: $color-text-medium;
max-width: 180px;
span {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
.file-preview-remove {
background: none;
border: none;
cursor: pointer;
color: $color-text-dark;
padding: 0;
display: flex;
align-items: center;
font-size: $icon-size-xs;
transition: color $motion-fast $motion-ease;
flex-shrink: 0;
&:hover { color: $color-error; }
}
.upload-progress {
height: 2px;
background: $surface-panel-strong;
margin-bottom: $space-xs;
overflow: hidden;
}
.upload-progress-fill {
height: 100%;
background: $color-secondary;
transition: width $motion-base $motion-ease;
}
.input-row {
display: flex;
align-items: center;
gap: $space-sm;
background: $surface-panel;
border: $border-width-base $border-style-base $border-color-muted;
padding: $space-sm;
transition: border-color $motion-fast $motion-ease;
&:focus-within {
border-color: $color-secondary;
}
}
.input-textarea {
flex: 1;
background: none;
border: none;
outline: none;
resize: none;
color: $color-text-light;
font-size: 14px;
line-height: 1.5;
font-family: inherit;
min-height: 24px;
max-height: 144px;
overflow-y: auto;
padding: 2px 0;
&::placeholder { color: $color-text-dark; }
}
// ─── Welcome screen ────────────────────────────────────────────────────────
.welcome-screen {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: $space-xl;
gap: $space-xl;
text-align: center;
}
.welcome-logo {
display: flex;
flex-direction: column;
align-items: center;
gap: $space-sm;
img { width: 64px; height: 64px; }
h1 {
font-size: 32px;
font-weight: 700;
letter-spacing: -0.5px;
color: $color-text-light;
margin: 0;
}
p {
font-size: 15px;
color: $color-text-medium;
margin: 0;
}
}
.welcome-profiles {
display: flex;
gap: $space-md;
flex-wrap: wrap;
justify-content: center;
max-width: 600px;
}
.welcome-profile-card {
display: flex;
flex-direction: column;
align-items: center;
gap: $space-sm;
padding: $space-md;
background: $surface-panel-muted;
border: $border-width-base $border-style-base $border-color-muted;
cursor: pointer;
transition: border-color $motion-fast $motion-ease, background $motion-fast $motion-ease;
width: 160px;
text-align: center;
&:hover, &.is-selected {
border-color: $color-secondary;
background: $surface-panel-strong;
}
&.is-selected {
border-color: $color-secondary;
}
.profile-icon {
font-size: $icon-size-xl;
color: $color-secondary;
}
.profile-name {
font-size: 14px;
font-weight: 600;
color: $color-text-light;
}
.profile-desc {
font-size: 12px;
color: $color-text-dark;
line-height: 1.4;
}
}
// ─── Empty state ───────────────────────────────────────────────────────────
.empty-chat {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: $space-md;
color: $color-text-dark;
padding: $space-xl;
.empty-icon {
font-size: $icon-size-display;
opacity: 0.4;
}
p {
font-size: 15px;
margin: 0;
}
}
// ─── Spinner ───────────────────────────────────────────────────────────────
.spinner {
display: inline-block;
width: 14px;
height: 14px;
border: 2px solid $border-color-muted;
border-top-color: $color-secondary;
border-radius: 50%;
animation: spin 0.6s linear infinite;
flex-shrink: 0;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
// ─── Animations ────────────────────────────────────────────────────────────
.fade-enter-active,
.fade-leave-active {
transition: opacity $motion-fast $motion-ease;
}
.fade-enter-from,
.fade-leave-to {
opacity: 0;
}
.slide-up-enter-active {
transition: opacity $motion-base $motion-ease, transform $motion-base $motion-ease;
}
.slide-up-enter-from {
opacity: 0;
transform: translateY(8px);
}
.slide-left-enter-active,
.slide-left-leave-active {
transition: transform $motion-slow $motion-ease, opacity $motion-slow $motion-ease;
}
.slide-left-enter-from {
transform: translateX(-100%);
opacity: 0;
}
.slide-left-leave-to {
transform: translateX(-100%);
opacity: 0;
}
// ─── UI kit overrides ──────────────────────────────────────────────────────
// Disable btn-icon icon rotation on hover — too distracting for utility buttons.
// Use .with-rotate class to opt back in where rotation makes sense.
.btn-icon:not(.with-rotate) .ph {
transform: none !important;
transition: none !important;
}
// Tool card chevron should still rotate (opt-in)
.tool-card[open] .tool-chevron,
.thinking-card[open] .tool-chevron {
transform: rotate(180deg) !important;
}