/* Syntax highlighting comes from Fumadocs's Shiki-based `rehypeCode` * (see `src/app/[framework]/[[...slug]]/page.tsx` etc.). Shiki ships * inline `--shiki-light` / `--shiki-dark` CSS variables on each token * span; Fumadocs's preset CSS swaps between them via the `.dark` * ancestor selector, so theme switching just works. We no longer pull * in `highlight.js/styles/github.css` — see git history for the prior * setup. */ @import "tailwindcss"; @import "fumadocs-ui/css/shadcn.css"; @import "fumadocs-ui/css/preset.css"; /* Activate `dark:` Tailwind variants based on the `.dark` class on an * ancestor (typically ) instead of the default * `prefers-color-scheme: dark` media query. Required for the navbar * theme toggle to actually switch sun/moon icons and slanted-border * SVG variants — they all key off `dark:` classes. Mirrors canonical * docs.copilotkit.ai/app/global.css. */ @custom-variant dark (&:is(.dark *)); /* Top-of-layout chrome heights: * - Desktop (xl+): BrandNav is rendered in body flow at 64px. * - Tablet/mobile (< xl): BrandNav is hidden; MobileTopNav (inside * DocsLayout's nav slot, position: fixed) renders as a compact * single-row header. * * --fd-nav-height drives: * - Fumadocs sidebar's `top:` offset * - #nd-docs-layout's pt-(--fd-nav-height) (we override on desktop — * see below — but it's load-bearing on mobile to leave space for * the fixed mobile nav). * * --fd-banner-height is set dynamically by Banners (40px / 0px). */ :root { --fd-nav-height: 64px; --shell-docs-layout-width: calc(97rem + 11px); --shell-docs-grid-gutter: 0px; --shell-docs-grid-top-offset: 0px; --radius: 0.875rem; --shell-docs-radius: var(--radius); --shell-docs-radius-control: var(--radius); --shell-docs-radius-surface: var(--radius); --shell-docs-radius-icon: var(--radius); --shadow-control: 0 1px 0 rgba(1, 5, 7, 0.03); --shadow-panel: 0 18px 50px rgba(1, 5, 7, 0.18); --shadow-modal: 0 24px 70px rgba(1, 5, 7, 0.22), 0 0 0 1px rgba(109, 69, 249, 0.05); --overlay-backdrop: rgba(1, 5, 7, 0.25); --accent-strong: color-mix(in oklch, var(--accent) 88%, black); --nav-control-border: color-mix(in srgb, var(--accent) 24%, var(--border)); --nav-control-border-hover: color-mix( in srgb, var(--accent) 42%, var(--border) ); --warning: oklch(0.72 0.16 76); --warning-dim: color-mix(in oklch, var(--warning) 10%, transparent); --warning-border: color-mix(in oklch, var(--warning) 46%, var(--border)); --warning-text: color-mix(in oklch, var(--warning) 70%, var(--text)); --window-control-close: #ff5f57; --window-control-minimize: #ffbd2e; --window-control-zoom: #28c840; } @media (min-width: 1280px) { :root { --fd-nav-height: 64px; --shell-docs-grid-top-offset: 5px; --shell-docs-grid-gutter: max( 0px, calc((100% - var(--shell-docs-layout-width)) / 2) ); } } .shell-docs-mobile-nav { box-sizing: border-box; height: var(--fd-nav-height); display: flex; align-items: center; padding: 0 1rem; } .shell-docs-mobile-nav-top { display: grid; width: 100%; grid-template-columns: minmax(0, 1fr) auto; align-items: center; gap: 0.625rem; } .shell-docs-mobile-brand { display: flex; min-width: 0; align-items: center; gap: 0.5rem; } .shell-docs-mobile-brand > span:not([aria-hidden="true"]) { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .shell-docs-mobile-search { display: none; } .shell-docs-mobile-actions { display: flex; align-items: center; gap: 0.375rem; justify-self: end; } .shell-docs-mobile-tabs { display: none; min-width: 0; align-items: center; justify-content: center; gap: 0.375rem; overflow-x: auto; padding-bottom: 0.125rem; scrollbar-width: none; } .shell-docs-mobile-tabs::-webkit-scrollbar, .shell-docs-mobile-sidebar-tabs::-webkit-scrollbar { display: none; } .shell-docs-primary-tab { display: inline-flex; height: 2.25rem; min-width: max-content; align-items: center; justify-content: center; gap: 0.375rem; padding: 0 0.75rem; font-size: 0.8125rem; font-weight: 500; transition: background-color 150ms ease-out, color 150ms ease-out, box-shadow 150ms ease-out; } @media (min-width: 768px) and (max-width: 1279px) { .shell-docs-mobile-nav { padding: 0 1.25rem; } .shell-docs-mobile-search { display: block; justify-self: end; } } @media (min-width: 768px) and (max-width: 1279px) { .shell-docs-mobile-nav-top { grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr); } .shell-docs-mobile-tabs { display: flex; gap: 0.5rem; } .shell-docs-mobile-menu { display: none !important; } } @media (min-width: 1280px) { .shell-docs-mobile-nav { display: none !important; } } .shell-docs-mobile-sidebar-tabs { display: flex; width: 100%; min-width: 0; align-items: center; gap: 0.375rem; overflow-x: auto; padding-bottom: 0.75rem; scrollbar-width: none; } .shell-docs-mobile-sidebar-tabs .shell-docs-primary-tab { flex: 1 0 max-content; } @media (min-width: 768px) { .shell-docs-mobile-sidebar-tabs { display: none; } } /* BrandNav keeps its content inset, but the bottom divider should span the * full viewport width instead of stopping at the nav's 22px desktop margins. */ .shell-docs-brand-nav::after { position: absolute; right: -22px; bottom: 0; left: -22px; height: 1px; background: var(--border); content: ""; } /* BrandNav is a full-width top bar. Keep a named hook so layout tests can * assert the header does not regress back to the earlier capped pill chrome. */ .shell-docs-brand-nav-inner { width: 100%; } .shell-docs-brand-link { margin-left: max( 0px, calc((100vw - var(--shell-docs-layout-width)) / 2 - 22px) ); } .shell-docs-radius-control { border-radius: var(--shell-docs-radius-control) !important; } .shell-docs-radius-surface { border-radius: var(--shell-docs-radius-surface) !important; } .shell-docs-radius-icon { border-radius: var(--shell-docs-radius-icon) !important; } .shell-docs-surface { border: 1px solid var(--border); border-radius: var(--shell-docs-radius-surface); background: var(--bg-surface); box-shadow: var(--shadow-control); } .shell-docs-icon-surface { display: inline-flex; align-items: center; justify-content: center; border-radius: var(--shell-docs-radius-icon); border: 1px solid var(--border); background: var(--bg-surface); color: var(--text-muted); } .shell-docs-picker-icon-chip { display: inline-flex; align-items: center; justify-content: center; border: 1px solid color-mix(in oklch, var(--accent) 12%, var(--border)); border-radius: 9999px; background: #ffffff; color: var(--accent); } .dark .shell-docs-picker-icon-chip { border-color: color-mix(in oklch, var(--accent) 20%, var(--border)); background: color-mix(in oklch, var(--foreground) 94%, var(--accent) 6%); color: var(--accent); } .shell-docs-warning-surface { border-color: var(--warning-border); border-left-color: var(--warning); background: var(--warning-dim); } .shell-docs-commit-label { position: fixed; right: 12px; bottom: 8px; z-index: 9999; color: var(--text-faint); font-family: var(--font-docs-code); font-size: 10px; opacity: 0.55; pointer-events: none; user-select: none; } .reference-content a.shell-docs-cta-link, .reference-content a.shell-docs-cta-link:hover { color: var(--text); text-decoration: none; } .reference-content a.shell-docs-cta-accent, .reference-content a.shell-docs-cta-accent:hover, .reference-content .shell-docs-cta-accent { color: var(--accent); text-decoration: none; } .shell-docs-cta-stripe { background: var(--accent); } .shell-docs-course-banner { background: linear-gradient( 90deg, color-mix(in oklch, var(--accent) 78%, black) 0%, var(--accent) 52%, color-mix(in oklch, var(--accent) 90%, white) 100% ) !important; border-color: color-mix(in oklch, var(--accent) 70%, white) !important; } .dark .shell-docs-course-banner { background: linear-gradient( 90deg, color-mix(in oklch, var(--accent) 72%, black) 0%, color-mix(in oklch, var(--accent) 86%, black) 52%, var(--accent) 100% ) !important; border-color: color-mix(in oklch, var(--accent) 62%, transparent) !important; } #shell-docs-course-banner > button { width: 24px !important; height: 24px !important; border: 1px solid color-mix(in srgb, white 26%, transparent) !important; background: color-mix(in srgb, white 10%, transparent) !important; opacity: 1 !important; color: white !important; cursor: pointer !important; } #shell-docs-course-banner > button:hover { background: color-mix(in srgb, white 16%, transparent) !important; } .shell-docs-nav-link-idle { color: var(--text-muted); } .shell-docs-nav-link-idle:hover { background: var(--accent-dim); color: var(--accent); } .shell-docs-nav-link-active { background: color-mix(in oklch, var(--accent) 13%, transparent); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--accent) 24%, var(--border)), 0 1px 0 rgba(1, 5, 7, 0.04); color: var(--accent); } .shell-docs-nav-cta { border-color: var(--nav-control-border); background: color-mix(in oklch, var(--accent) 8%, transparent); color: var(--accent); } .shell-docs-nav-cta:hover { border-color: var(--nav-control-border-hover); background: color-mix(in oklch, var(--accent) 13%, transparent); color: var(--accent); } .dark .shell-docs-nav-link-idle:hover { background: var(--accent-dim); color: var(--accent); } .dark .shell-docs-nav-link-active { background: color-mix(in oklch, var(--accent) 20%, transparent); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--accent) 34%, var(--border)), 0 1px 0 rgba(0, 0, 0, 0.25); color: var(--accent); } /* shell-docs sidebar overrides. * * Fumadocs's DocsLayout sidebar reserves a header row with the home * logo + sidebar-collapse toggle. shell-docs has its own BrandNav with * the same logo, and `collapsible: false` removes the toggle — but the * empty home-link `` still occupies space at the top of the sidebar * column. Hide it so the framework selector (rendered via the `banner` * slot) sits flush at the top. */ /* Sidebar banner (holds the framework picker). Keep horizontal padding at * zero so the picker edge aligns with BrandNav's visible surface. The top * gap keeps the picker aligned under BrandNav; the larger bottom gap gives * the first section header the same breathing room as section breaks below. */ .shell-docs-sidebar > div:first-child { padding: 0.75rem 0 1.25rem !important; } /* Hide the empty home-link wrapper Fumadocs ships in the desktop * SidebarHeader. Scoped via `:has(> a:only-child:empty)` so it ONLY * matches the desktop case — the mobile SidebarHeader's first flex * child contains the iconLinks + theme-toggle row (children: real * anchors + a button), so this selector deliberately doesn't apply * there. */ .shell-docs-sidebar > div:first-child > .flex:first-child:has(> a:only-child:empty) { display: none !important; } /* Tighten Fumadocs folder rendering. The default gives folders an * extra row of vertical padding above their children, which reads as * a hole between the folder label and the first item. */ #nd-sidebar [data-folder] > [data-folder-trigger] { padding-top: 0.375rem; padding-bottom: 0.375rem; } /* Fumadocs animates collapsible folder panels after mount. Because * shell-docs currently mounts DocsLayout per page, route changes can * replay those "open" animations for folders that are already open. * SidebarFolderStatePreserver marks route-mounted panels with this * attribute and removes it before a real folder-toggle click, so user * interactions keep the default animation while navigation stays calm. */ .shell-docs-sidebar [data-shell-docs-skip-initial-animation] { animation: none !important; } /* Sidebar section headers (PageTree `separator` nodes). Fumadocs defaults * to body-weight foreground text with `inline-flex`, which makes section * labels (a) compete with the actual nav links underneath, and (b) flow * onto the SAME row when two separators are adjacent (e.g. a folder's * title + its first child separator). Push them into "shelf label" * territory and force block-level layout so each one sits on its own row. * The unique `--sidebar-item-offset` class fragment isolates these from * any other `

` elements in the sidebar. */ .shell-docs-sidebar p[class*="sidebar-item-offset"] { display: flex !important; font-size: 12px !important; font-weight: 600 !important; letter-spacing: 0 !important; color: var(--text-secondary) !important; /* Heavier `padding-top` opens a breath of space between the last * item of the previous section and this header, so the section * boundary reads as a real break instead of one continuous list. * `padding-bottom` separates the header from its first child entry * without making the header feel detached. Mirrors Mintlify's * roomier section spacing. */ padding-top: 1.75rem !important; padding-bottom: 0.625rem !important; margin-top: 0.25rem !important; margin-bottom: 0 !important; } /* Sidebar entry rhythm. Fumadocs ships `p-2` on every `` link and * `