@import "tailwindcss"; /* Syntax-highlight theme for fenced code blocks in rendered Markdown. */ @import "highlight.js/styles/atom-one-dark.min.css"; /* Custom monokai theme — must be imported BEFORE the @plugin block. */ @import "./themes/monokai.css"; /* DaisyUI v5 — enable the plugin AND bundle the monokai theme (set as default, applied via ). Themes not listed here are NOT bundled, so monokai must be named explicitly, not merely referenced. */ @plugin "daisyui" { themes: monokai --default; } /* Inset "well" — the Artix wiki's code blocks (darkstrap `pre`): a panel that reads as pressed INTO the page — the page colour darkened, a dark inner shadow under the top edge, a faint light catch-line under the bottom edge. Shared by the chat's thinking/tool blocks (LazyCollapse) and the sidebar views (TilePanels). darkstrap: background rgba(0,0,0,.3); box-shadow rgba(255,255,255,.1) 0 1px 0, rgba(0,0,0,.8) 0 1px 7px 0 inset; radius 4px. Ported onto the active daisyUI theme so it always matches, and toned down a step: the fill is the theme's page colour (base-100 — both the chat and the sidebar sit on it) darkened 18% (darkstrap: 30%), computed OPAQUE and exposed as --inset-well-bg so sticky children can paint the same colour; the inner shadow is 0.6 (darkstrap: 0.8); the catch-line is the theme's text colour at 10% instead of plain white. In @layer components so utilities can override. */ @layer components { .inset-well { --inset-well-bg: color-mix(in srgb, var(--color-base-100) 82%, black); background-color: var(--inset-well-bg); border: 0; border-radius: var(--radius-box); box-shadow: 0 1px 0 color-mix(in srgb, var(--color-base-content) 10%, transparent), inset 0 1px 7px 0 rgb(0 0 0 / 0.6); } } /* App navbar — the Artix wiki's navbar (darkstrap `.navbar-inner` on a fixed-top bar): a top-to-bottom gradient (#444 → #222), a soft drop shadow under the bar (0 1px 10px), and engraved text (1px black text-shadow). Shared by the workspace top bar (App) and the home page header. Ported onto the active daisyUI theme so it always matches. darkstrap's bar is LIGHTER than its near-black page (that's what makes the shadow read), so the gradient is shifted to keep that relationship on our lighter page: it runs from the page colour (base-100) lifted 20% toward the text colour down to base-100 lifted 3%. No bottom border (darkstrap has a 1px #030303 one — removed by user request; the gradient + shadow carry the edge). The shadow is 0.5 (darkstrap: 0.1 — invisible on our lighter page). Positioned + z-indexed so the shadow paints over the content below. */ @layer components { .app-navbar { position: relative; z-index: 10; flex-shrink: 0; background-image: linear-gradient( to bottom, color-mix(in srgb, var(--color-base-100) 80%, var(--color-base-content)), color-mix(in srgb, var(--color-base-100) 97%, var(--color-base-content)) ); box-shadow: 0 1px 10px rgb(0 0 0 / 0.5); } /* Engraved navbar text — titles only; on tiny faint labels it muddies. */ .app-navbar-engraved { text-shadow: 0 1px 0 black; } } /* Navbar buttons — the navbar's (`.app-navbar`) raised button, in the same depth language as the rest of the UI: at rest they're RAISED (a gradient a step lighter than the bar, a light highlight inside the top edge, a thin dark edge + small drop below, light primary-blue text), and when PRESSED they flip to the inset well (dark inner shadow) — pushed into the bar. `.navbar-btn-primary` is the main action: the same button, tinted with the theme's primary colour. `.navbar-btn-icon` is the square icon-only form. Self-contained (not DaisyUI .btn) so nothing fights the gradients; colours all come from the theme. */ @layer components { .navbar-btn { display: inline-flex; align-items: center; justify-content: center; gap: 0.375rem; height: 2rem; padding-inline: 0.75rem; border-radius: var(--radius-field); font-size: 0.875rem; font-weight: 600; line-height: 1; white-space: nowrap; cursor: pointer; user-select: none; /* The theme's primary, lifted toward white: crisp on the grey gradient (plain primary read dim, and an engraved text-shadow muddied it at this size — the shadow stays on the big titles only). */ color: color-mix(in srgb, var(--color-primary) 75%, white); border: 1px solid rgb(0 0 0 / 0.55); background-image: linear-gradient( to bottom, color-mix(in srgb, var(--color-base-100) 72%, var(--color-base-content)), color-mix(in srgb, var(--color-base-100) 90%, var(--color-base-content)) ); box-shadow: inset 0 1px 0 rgb(255 255 255 / 0.12), 0 1px 2px rgb(0 0 0 / 0.45); transition: filter 120ms ease-out, box-shadow 120ms ease-out; } .navbar-btn:hover { filter: brightness(1.12); } .navbar-btn:active, .navbar-btn[aria-expanded="true"] { /* Pressed → the inset well: pushed into the bar. */ filter: none; background-image: none; background-color: color-mix(in srgb, var(--color-base-100) 82%, black); box-shadow: inset 0 1px 5px rgb(0 0 0 / 0.7), 0 1px 0 color-mix(in srgb, var(--color-base-content) 10%, transparent); } .navbar-btn:focus-visible { outline: 2px solid var(--color-primary); outline-offset: 2px; } .navbar-btn-icon { width: 2rem; padding-inline: 0; } /* Secondary navbar actions: visually just text — no background, border or shadow. The light primary-blue colour (same as the buttons' text) and the spacing mark them as clickable; hover brightens + underlines, press dims. */ .navbar-link { display: inline-flex; align-items: center; justify-content: center; gap: 0.375rem; height: 2rem; min-width: 2rem; /* icon-only (compact) links keep a comfortable tap target */ padding-inline: 0.375rem; border-radius: var(--radius-field); font-size: 0.875rem; font-weight: 600; line-height: 1; white-space: nowrap; cursor: pointer; user-select: none; background: none; border: 0; color: color-mix(in srgb, var(--color-primary) 75%, white); text-underline-offset: 4px; transition: color 120ms ease-out; } .navbar-link:hover { color: color-mix(in srgb, var(--color-primary) 45%, white); text-decoration: underline; } .navbar-link:active { color: var(--color-primary); } .navbar-link:focus-visible { outline: 2px solid var(--color-primary); outline-offset: 2px; } .navbar-btn-primary { color: var(--color-primary-content); background-image: linear-gradient( to bottom, color-mix(in srgb, var(--color-primary) 82%, white), color-mix(in srgb, var(--color-primary) 88%, black) ); box-shadow: inset 0 1px 0 rgb(255 255 255 / 0.35), 0 1px 2px rgb(0 0 0 / 0.45); } .navbar-btn-primary:active { background-color: color-mix(in srgb, var(--color-primary) 80%, black); } } /* Raised button — the exact mirror of `.inset-well`, for a neutral surface that pops OUT where the wells sink in (the sidebar's "+ Add view" under the view wells). The well = page colour darkened 18%, dark shadow INSIDE under the top edge (inset 0 1px 7px), light catch-line OUTSIDE below (0 1px 0). Mirrored: page colour LIFTED toward the text colour, light highlight INSIDE the top edge (inset 0 1px 0), the dark shadow OUTSIDE below (0 1px 7px), plus a faint top-lit gradient. Pressed → it becomes the well (pushed in). */ @layer components { .raised-btn { display: flex; align-items: center; justify-content: center; border: 0; border-radius: var(--radius-box); cursor: pointer; color: color-mix(in srgb, var(--color-primary) 75%, white); background-color: color-mix(in srgb, var(--color-base-100) 90%, var(--color-base-content)); background-image: linear-gradient(to bottom, rgb(255 255 255 / 0.06), rgb(0 0 0 / 0.1)); box-shadow: inset 0 1px 0 color-mix(in srgb, var(--color-base-content) 18%, transparent), 0 1px 7px 0 rgb(0 0 0 / 0.6); transition: filter 120ms ease-out, box-shadow 120ms ease-out; } .raised-btn:hover { filter: brightness(1.12); } .raised-btn:active { filter: none; background-image: none; background-color: color-mix(in srgb, var(--color-base-100) 82%, black); box-shadow: 0 1px 0 color-mix(in srgb, var(--color-base-content) 10%, transparent), inset 0 1px 7px 0 rgb(0 0 0 / 0.6); } .raised-btn:focus-visible { outline: 2px solid var(--color-primary); outline-offset: 2px; } } /* Raised — the INVERSE of `.inset-well`, for things that pop OUT of the page (the home page's workspace tiles). Where the well has a dark shadow INSIDE under its top edge and a light catch-line OUTSIDE below it, a raised surface has a light highlight INSIDE along its top edge, a soft shadow OUTSIDE below it, and a faint top-lit gradient over its own colour (lighter top → darker bottom — convex, where the well is concave). Built on Tailwind's shadow variables (not a bare box-shadow) so it COMPOSES with the ring / shadow utilities: the inner highlight rides --tw-inset-shadow (kept by `hover:shadow-xl`, rings, drag), the drop rides --tw-shadow (which `hover:shadow-xl` / `shadow-2xl` swap for a bigger lift). Works on any background colour (the tiles' tone colours), so it always matches the theme. */ @layer components { .raised { --tw-inset-shadow: inset 0 1px 0 rgb(255 255 255 / 0.45), inset 0 -1px 0 rgb(0 0 0 / 0.25); --tw-shadow: 0 2px 9px 0 rgb(0 0 0 / 0.7); box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow, 0 0 #0000), var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); background-image: linear-gradient(to bottom, rgb(255 255 255 / 0.14), rgb(0 0 0 / 0.14)); } } /* Rendered-Markdown (assistant messages) typography — scoped to .markdown-body so it never leaks into the rest of the app. */ .markdown-body { & p { margin-block: 0.5em; &:first-child { margin-block-start: 0; } &:last-child { margin-block-end: 0; } } & h1, & h2, & h3, & h4, & h5, & h6 { font-weight: 600; line-height: 1.25; margin-block: 0.75em 0.25em; &:first-child { margin-block-start: 0; } } & h1 { font-size: 1.4em; } & h2 { font-size: 1.2em; } & h3 { font-size: 1.1em; } & ul, & ol { padding-inline-start: 1.5em; margin-block: 0.5em; } & ul { list-style-type: disc; } & ol { list-style-type: decimal; } & li { margin-block: 0.15em; } & pre { overflow-x: auto; border-radius: var(--radius-box); margin-block: 0.5em; } & pre code { display: block; padding: 0.75em 1em; font-size: 0.8125em; line-height: 1.5; } & :not(pre) > code { font-size: 0.875em; padding: 0.15em 0.4em; border-radius: var(--radius-selector); background-color: oklch(var(--color-base-content) / 0.1); } & blockquote { border-inline-start: 3px solid oklch(var(--color-base-content) / 0.2); padding-inline-start: 0.75em; margin-block: 0.5em; opacity: 0.8; } & a { color: oklch(var(--color-primary)); text-decoration: underline; &:hover { opacity: 0.8; } } & strong { font-weight: 600; } & table { width: 100%; border-collapse: collapse; margin-block: 0.5em; font-size: 0.875em; } & th, & td { border: 1px solid oklch(var(--color-base-content) / 0.15); padding: 0.4em 0.75em; text-align: start; } & th { font-weight: 600; background-color: oklch(var(--color-base-200)); } & hr { border: none; border-top: 1px solid oklch(var(--color-base-content) / 0.2); margin-block: 0.75em; } } /* App shell fills the viewport and never scrolls/overflows at the page level — the inner regions (tab strip, chat transcript) own their own scrolling. */ html, body, #app { height: 100%; } body { overflow: hidden; } /* App-shell height. NOT `h-screen` (100vh): on iOS/iPadOS WebKit (Safari, Vivaldi, …) 100vh is the viewport with the browser toolbars RETRACTED, so while they're showing the bottom of the app sits underneath them (the sidebar's last item / the composer looked flush against the bottom edge). 100dvh tracks the visible viewport as the toolbars show/hide; 100vh stays as the fallback for engines without dvh. */ .h-app { height: 100vh; } @supports (height: 100dvh) { .h-app { height: 100dvh; } } /* Transcript rows: skip layout + paint for rows scrolled out of view. A long turn has hundreds of rows; without this every one is laid out on first paint (and on every resize). `contain-intrinsic-size: auto ` makes the browser remember each row's last rendered height, so scrolling back up doesn't jump; the 64px is only the estimate for never-rendered rows. */ .chat-row { content-visibility: auto; contain-intrinsic-size: auto 64px; }