mirror of
https://github.com/simstudioai/sim.git
synced 2026-11-01 13:22:04 +08:00
* improvement(docs): make the API reference read as code, and unify the type token The API-page font override matched every span/div/p inside the page, which outranks the .font-mono class on specificity, so every parameter name, type, and identifier silently rendered in the body sans face. Exclude .font-mono so code tokens stay monospace. Consolidate the three divergent type-slot treatments — plain scalar, union, and schema reference each carried their own chip definition, differing in size, weight, face, and box height — onto one code token that reuses the docs inline-code recipe and the platform's 20px chip height. Demote the row metadata: 'required' and 'header' were filled pills, 'required' on the error token, making a constraint the loudest element on the page and a page of required parameters read as a page of alarms. Both are now uncontained text, leaving the type token as the only box on the row. Pin the two 'application/json' labels to one treatment; the Request Body and Response headers rendered the same string at different weights and faces. * improvement(docs): mono status-code tabs, and match fumadocs' lucide icons to emcn Status codes in the example panel are numeric literals and render as code everywhere else on the page, including the Response header's own trigger, but fumadocs rendered the strip in the body sans face. Language tabs sit in a separate container and stay sans — those are product names, not code. fumadocs draws a few lucide glyphs on API pages that its client-component overrides do not expose (the heading anchor and the code-block copy button). emcn strokes at 1.55 and lucide at 2, so those icons read heavier than every icon around them; match the weight. * fix(docs): align the auth type chip with every other property row, and wrap example code The auth row collapses its real `<token>` type and renders the chip through ::after, so the span is only a wrapper — but it still matched the type-token rule and kept that rule's border, height, and gap. The border drew a second empty box around the real chip and the gap opened in front of it, because the collapsed text remains an anonymous flex item; together they pushed the chip right by roughly 8px that no other row had. Example-panel code overflowed sideways instead of wrapping: fumadocs sizes the block with `w-max`, so it grew to its longest line inside a 400px scroller and the existing pre-wrap never applied. Cap the width, switch break-all to overflow-wrap anywhere so only unfittable tokens split, and reserve room for the copy button fumadocs floats over the first line. * revert(docs): let example code overflow instead of wrapping Wrapping restarts every continuation line at column zero, and in a JSON body indentation is what carries nesting depth — so a wrapped response misreports its own structure. A hanging indent keeps the depth but needs the shiki lines forced from flex rows to blocks, which breaks the line rhythm. Removes the pre-wrap rules rather than repointing them: fumadocs sizes the block with w-max, so the previous rule never took effect and overflow was already the behaviour on the page. * fix(docs): tighten array type tokens and keep the union separator legible An `array<T>` slot holds its angle brackets as bare text nodes, which become anonymous flex items, so the slot's gap prised `array<` and `>` away from the type they wrap. Drop the gap and let the union separator carry its own margin; this also makes the auth row's gap override redundant. The separator was dimmed twice, by a muted token and again by opacity, which on the dark chip fill left `string | null` reading as `string null`. * fix(docs): restore the hidden API key description, and drop dead API-reference CSS The rule hiding the trailing `In: header` line matched `p:has(> code)`, which is a shape, not a target — every scheme description in our specs cites a status code, so the whole explanation of personal vs workspace-scoped keys was display:none on every API reference page. Match the last child instead, and shorten the description to one line now that it renders. The dropdown trigger's hover rule had been left below a new id-qualified base rule that outranked it, so the trigger could no longer change colour on hover. Removes what does not run: the four `::-webkit-scrollbar` rules (specifying a non-auto scrollbar-width makes Chromium ignore them, and Firefox never had them) and an `order: 2` block whose selectors and declaration the type-token rule above it already carried. Names the two values the API reference repeats — the monospace stack, written out eleven times, and the 12.5px code size, written nine — as --font-mono-stack and --text-code. Also drops four !important declarations that already won on specificity, a --text-muted fallback that can never fire, and a lucide selector subsumed by the one beside it. * refactor(docs): define the API-reference chrome once, and cut the commentary The metadata face — size, leading, weight, mono stack — was written out in seven rules that a comment asked future readers to keep in sync by hand; it is now one rule those seven consume, each adding only its own colour, content, and order. The auth row's chip likewise re-derived all eleven declarations of the type token and now joins that rule, keeping only its label. Comments were running longer than the rules they documented — 88 added comment lines against 73 declarations. Trimmed to the load-bearing facts: cascade traps, browser behaviour, and the bugs a rule prevents. Dropped the block narrating why the wrap rules were reverted, which duplicated its own commit message. Also retires a scrollbar token left unreferenced by the webkit removal, moves the last two fumadocs colours in our own components onto platform tokens, and brings the callout icon to 1.55 so the docs really do have one icon weight. * fix(docs): keep the union separator in the type token's own face The `|` between union members is a classless span, so the page-wide `span:not(.font-mono)` rule assigned it the body sans face while the members beside it stayed mono — one chip rendering in two faces. Applies the inherit reset to every descendant of a type token rather than just its links, so anything fumadocs nests there later is covered too.
1797 lines
58 KiB
CSS
1797 lines
58 KiB
CSS
@import "tailwindcss";
|
|
@import "fumadocs-ui/css/neutral.css";
|
|
@import "fumadocs-ui/css/preset.css";
|
|
@import "fumadocs-openapi/css/preset.css";
|
|
@source "../../../packages/emcn/src";
|
|
@source "../../../packages/workflow-renderer/src";
|
|
|
|
/* Every @sim/emcn component expresses hover through `hover-hover:` so touch
|
|
devices never latch a sticky hover state. The app registers it as a plugin
|
|
variant in apps/sim/tailwind.config.ts; docs is CSS-first Tailwind v4 with no
|
|
config, so without this declaration the variant compiles to nothing and every
|
|
emcn hover state silently no-ops here. */
|
|
@custom-variant hover-hover {
|
|
@media (hover: hover) and (pointer: fine) {
|
|
&:hover {
|
|
@slot;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Prevent overscroll bounce effect on the page */
|
|
html,
|
|
body {
|
|
overscroll-behavior: none;
|
|
}
|
|
|
|
/* Prevent modals/dialogs from shifting layout via scroll-lock compensation */
|
|
html,
|
|
body {
|
|
padding-right: 0 !important;
|
|
margin-right: 0 !important;
|
|
}
|
|
|
|
@theme {
|
|
--color-fd-primary: var(--color-fd-foreground);
|
|
/* Sim's custom type scale — emcn components (Label, Badge, the shared block
|
|
views) use these names, so they must resolve here or text falls back to the
|
|
inherited size. Mirrors apps/sim/tailwind.config.ts. */
|
|
--text-micro: 10px;
|
|
--text-xs: 11px;
|
|
--text-caption: 12px;
|
|
--text-small: 13px;
|
|
--text-base: 15px;
|
|
--text-md: 16px;
|
|
|
|
/* Code-token size for the API reference — a deliberate sixth step, between
|
|
--text-caption and --text-small, because the mono face reads small at 12px. */
|
|
--text-code: 0.78125rem;
|
|
|
|
--font-mono-stack: var(--font-geist-mono), ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas,
|
|
"Liberation Mono", "Courier New", monospace;
|
|
}
|
|
|
|
/* Pure white light mode background */
|
|
:root:not(.dark) {
|
|
--color-fd-background: hsl(0, 0%, 100%) !important;
|
|
}
|
|
|
|
/* Match landing page dark background (#1b1b1b) */
|
|
.dark {
|
|
--color-fd-background: hsl(0, 0%, 10.6%) !important;
|
|
--color-fd-card: hsl(0, 0%, 13%) !important;
|
|
--color-fd-popover: hsl(0, 0%, 14%) !important;
|
|
--color-fd-secondary: hsl(0, 0%, 15.5%) !important;
|
|
--color-fd-muted: hsl(0, 0%, 18%) !important;
|
|
}
|
|
|
|
/*
|
|
* emcn workspace tokens — mirrored from apps/sim/app/_styles/globals.css so the
|
|
* docs chip chrome (components/ui/chip.tsx, dropdown-menu.tsx, badges) renders
|
|
* identically to the platform. Keep values in sync with the main app.
|
|
*/
|
|
:root {
|
|
--bg: #fefefe;
|
|
--workflow-edge: #e0e0e0;
|
|
--surface-1: #fbfbfb;
|
|
--surface-2: #ffffff;
|
|
--surface-3: #f7f7f7;
|
|
--surface-4: #f5f5f5;
|
|
--surface-5: #f3f3f3;
|
|
--surface-6: #e5e5e5;
|
|
--surface-7: #d9d9d9;
|
|
--surface-active: #ececec;
|
|
--surface-hover: #f2f2f2;
|
|
--border: #d8d8d8;
|
|
/** Legacy neutral-border aliases. New work should use --border. */
|
|
--border-1: var(--border);
|
|
--text-primary: #1a1a1a;
|
|
--text-secondary: #525252;
|
|
--text-tertiary: #5c5c5c;
|
|
--text-body: #434343;
|
|
--text-muted: #7a7a7a;
|
|
--text-subtle: #8c8c8c;
|
|
--text-icon: #5a5a5a;
|
|
--text-icon-muted: #5c5c5c;
|
|
--text-inverse: #ffffff;
|
|
--text-error: #ef4444;
|
|
--text-muted-inverse: #a0a0a0;
|
|
--brand-accent: #33c482;
|
|
--brand-accent-hover: #2dac72;
|
|
--brand-secondary: #33b4ff;
|
|
--surface-inverted: #1b1b1b;
|
|
--surface-inverted-hover: #363636;
|
|
--border-inverted: #363636;
|
|
--border-muted: var(--border);
|
|
--badge-success-bg: #bbf7d0;
|
|
--badge-success-text: #15803d;
|
|
/* Shared-component tokens: referenced by @sim/emcn and @sim/workflow-renderer.
|
|
Undefined here, a var() silently falls back to currentColor. Values mirror
|
|
apps/sim/app/_styles/globals.css. */
|
|
--border-success: #e0e0e0;
|
|
--success: #22c55e;
|
|
--error: #dc2626;
|
|
--warning: #ea580c;
|
|
--caution: #f59e0b;
|
|
--text-placeholder: #8d8d8d;
|
|
--badge-teal-bg: #99f6e4;
|
|
--badge-teal-text: #0f766e;
|
|
--badge-cyan-bg: #cffafe;
|
|
--badge-cyan-text: #0891b2;
|
|
--badge-pink-bg: #fbcfe8;
|
|
--badge-pink-text: #be185d;
|
|
--badge-blue-secondary-bg: #bae6fd;
|
|
--badge-blue-secondary-text: #0369a1;
|
|
--badge-blue-bg: #bfdbfe;
|
|
--badge-blue-text: #1d4ed8;
|
|
--badge-purple-bg: #e9d5ff;
|
|
--badge-purple-text: #7c3aed;
|
|
--badge-amber-bg: #fde68a;
|
|
--badge-amber-text: #a16207;
|
|
--badge-orange-bg: #fed7aa;
|
|
--badge-orange-text: #c2410c;
|
|
--badge-error-bg: #fecaca;
|
|
--badge-error-text: #dc2626;
|
|
--badge-gray-bg: #e7e5e4;
|
|
--badge-gray-text: #57534e;
|
|
--code-bg: #f5f5f5;
|
|
--code-foreground: #1a1a1a;
|
|
--code-line-number: #737373;
|
|
--selection-bg: #add6ff;
|
|
--selection-dark: #264f78;
|
|
--highlight-search-active: #f6ad55;
|
|
--scrollbar-thumb-color: #c0c0c0;
|
|
--shadow-subtle: 0 2px 4px 0 rgba(0, 0, 0, 0.08);
|
|
--shadow-medium: 0 4px 12px rgba(0, 0, 0, 0.1);
|
|
--shadow-overlay: 0 10px 30px rgba(0, 0, 0, 0.11);
|
|
--shadow-card: 0 1px 3px rgba(0, 0, 0, 0.04);
|
|
/* z-index scale — poppers sit above the modal so menus stay clickable over
|
|
the modal overlay. Mirrors apps/sim/app/_styles/globals.css. */
|
|
--z-toast: 150;
|
|
--z-modal: 200;
|
|
--z-popover: 300;
|
|
--z-tooltip: 400;
|
|
}
|
|
|
|
.dark {
|
|
--bg: #1b1b1b;
|
|
--workflow-edge: #454545;
|
|
--surface-1: #1e1e1e;
|
|
--surface-2: #232323;
|
|
--surface-3: #242424;
|
|
--surface-4: #292929;
|
|
--surface-5: #363636;
|
|
--surface-6: #454545;
|
|
--surface-7: #505050;
|
|
--surface-active: #2c2c2c;
|
|
--surface-hover: #262626;
|
|
--border: #444444;
|
|
/** Legacy neutral-border aliases. New work should use --border. */
|
|
--border-1: var(--border);
|
|
--text-primary: #e6e6e6;
|
|
--text-secondary: #cccccc;
|
|
--text-tertiary: #b3b3b3;
|
|
--text-body: #c1c1c1;
|
|
--text-muted: #6e6e6e;
|
|
--text-subtle: #7d7d7d;
|
|
--text-icon: #969696;
|
|
--text-icon-muted: #949494;
|
|
--text-inverse: #1b1b1b;
|
|
--text-error: #ef4444;
|
|
--text-muted-inverse: #b3b3b3;
|
|
--brand-accent: #33c482;
|
|
--brand-accent-hover: #2dac72;
|
|
--brand-secondary: #33b4ff;
|
|
--surface-inverted: #242424;
|
|
--surface-inverted-hover: #363636;
|
|
--border-inverted: #3d3d3d;
|
|
--border-muted: var(--border);
|
|
--badge-success-bg: rgba(34, 197, 94, 0.2);
|
|
--badge-success-text: #86efac;
|
|
/* Shared-component tokens: referenced by @sim/emcn and @sim/workflow-renderer.
|
|
Undefined here, a var() silently falls back to currentColor. Values mirror
|
|
apps/sim/app/_styles/globals.css. */
|
|
--border-success: #575757;
|
|
--success: #22c55e;
|
|
--error: #f87171;
|
|
--warning: #ff6600;
|
|
--caution: #f59e0b;
|
|
--text-placeholder: #8d8d8d;
|
|
--badge-teal-bg: rgba(20, 184, 166, 0.2);
|
|
--badge-teal-text: #5eead4;
|
|
--badge-cyan-bg: rgba(14, 165, 233, 0.2);
|
|
--badge-cyan-text: #7dd3fc;
|
|
--badge-pink-bg: rgba(236, 72, 153, 0.2);
|
|
--badge-pink-text: #f9a8d4;
|
|
--badge-blue-secondary-bg: rgba(51, 180, 255, 0.2);
|
|
--badge-blue-secondary-text: #7dd3fc;
|
|
--badge-blue-bg: rgba(59, 130, 246, 0.2);
|
|
--badge-blue-text: #93c5fd;
|
|
--badge-purple-bg: rgba(168, 85, 247, 0.2);
|
|
--badge-purple-text: #d8b4fe;
|
|
--badge-amber-bg: rgba(245, 158, 11, 0.2);
|
|
--badge-amber-text: #fcd34d;
|
|
--badge-orange-bg: rgba(249, 115, 22, 0.2);
|
|
--badge-orange-text: #fdba74;
|
|
--badge-error-bg: #551a1a;
|
|
--badge-error-text: #fca5a5;
|
|
--badge-gray-bg: #3a3a3a;
|
|
--badge-gray-text: #a8a8a8;
|
|
--code-bg: #1f1f1f;
|
|
--code-foreground: #eeeeee;
|
|
--code-line-number: #a8a8a8;
|
|
--selection-bg: #264f78;
|
|
--scrollbar-thumb-color: #5a5a5a;
|
|
--shadow-overlay: 0 10px 30px rgba(0, 0, 0, 0.3);
|
|
}
|
|
|
|
/* Scrollbars — platform thumb tokens, transparent track. A non-auto
|
|
`scrollbar-width`/`scrollbar-color` makes Chromium ignore every
|
|
`::-webkit-scrollbar*` rule on the element, so no webkit block here. Hover
|
|
shading is not expressible through the standard properties. */
|
|
* {
|
|
scrollbar-width: thin;
|
|
scrollbar-color: var(--scrollbar-thumb-color) transparent;
|
|
}
|
|
|
|
/* Font family utilities */
|
|
.font-sans {
|
|
font-family: var(--font-geist-sans), ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont,
|
|
"Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
|
}
|
|
|
|
.font-mono {
|
|
font-family: var(--font-mono-stack);
|
|
}
|
|
|
|
/* Platform UI font — Season Sans, used by the chip chrome to match the main app */
|
|
.font-season {
|
|
font-family: var(--font-season), system-ui, "Segoe UI", Roboto, "Helvetica Neue", Arial,
|
|
"Noto Sans", sans-serif;
|
|
}
|
|
|
|
:root {
|
|
--fd-border-sidebar: transparent !important;
|
|
--fd-nav-height: 92px; /* Custom navbar height (52px top + 40px tabs) */
|
|
/* Content container width used to center main content */
|
|
--spacing-fd-container: 1400px;
|
|
/* Edge gutter = leftover space on each side of centered container */
|
|
--edge-gutter: max(1rem, calc((100vw - var(--spacing-fd-container)) / 2));
|
|
/* How far sidebar/TOC shift inward from the edge gutter */
|
|
--sidebar-shift: 50px;
|
|
--sidebar-offset: max(0px, calc(var(--edge-gutter) - var(--sidebar-shift)));
|
|
--toc-shift: 50px;
|
|
--toc-offset: max(0px, calc(var(--edge-gutter) - var(--toc-shift)));
|
|
/* Inner padding for navbar and sidebar — single source of truth */
|
|
--nav-inset: 44px;
|
|
/* Extra gap between sidebar/TOC and the main text content */
|
|
--content-gap: 2.25rem;
|
|
}
|
|
|
|
/* Light mode navbar background */
|
|
:root:not(.dark) nav {
|
|
background-color: hsla(0, 0%, 100%, 0.85) !important;
|
|
}
|
|
|
|
/* Dark mode navbar background */
|
|
:root.dark nav {
|
|
background-color: hsla(0, 0%, 10.6%, 0.92) !important;
|
|
}
|
|
|
|
/* Floating sidebar appearance - remove background */
|
|
[data-sidebar-container],
|
|
#nd-sidebar {
|
|
background: transparent !important;
|
|
border: none !important;
|
|
--color-fd-muted: transparent !important;
|
|
--color-fd-card: transparent !important;
|
|
--color-fd-secondary: transparent !important;
|
|
}
|
|
|
|
aside[data-sidebar],
|
|
aside#nd-sidebar {
|
|
background: transparent !important;
|
|
border: none !important;
|
|
}
|
|
|
|
/* Remove the fade-out mask on sidebar scroll viewport (Fumadocs applies inline maskImage) */
|
|
[data-sidebar-placeholder] [data-radix-scroll-area-viewport],
|
|
#nd-sidebar [data-radix-scroll-area-viewport],
|
|
#nd-sidebar [data-radix-scroll-area-viewport] > div,
|
|
aside#nd-sidebar [data-radix-scroll-area-viewport] {
|
|
mask: none !important;
|
|
mask-image: none !important;
|
|
-webkit-mask: none !important;
|
|
-webkit-mask-image: none !important;
|
|
}
|
|
|
|
/* Fumadocs v16: Add sidebar placeholder styling for grid area */
|
|
[data-sidebar-placeholder] {
|
|
background: transparent !important;
|
|
}
|
|
|
|
/* Fumadocs v16: Hide sidebar panel (floating collapse button) */
|
|
[data-sidebar-panel] {
|
|
display: none !important;
|
|
}
|
|
|
|
/* Mobile only: Reduce gap between navbar and content (custom navbar hidden on mobile) */
|
|
@media (max-width: 1023px) {
|
|
#nd-docs-layout {
|
|
margin-top: -25px;
|
|
}
|
|
}
|
|
|
|
/* Hide TOC popover on tablet/medium screens (768px - 1279px) */
|
|
/* Keeps it visible on mobile (<768px) for easy navigation */
|
|
/* Desktop (>=1280px) already hides it via fumadocs xl:hidden */
|
|
@media (min-width: 768px) and (max-width: 1279px) {
|
|
#nd-docs-layout {
|
|
--fd-toc-popover-height: 0px !important;
|
|
}
|
|
|
|
[data-toc-popover] {
|
|
display: none !important;
|
|
}
|
|
}
|
|
|
|
/* Desktop only: Apply custom navbar offset, sidebar width and margin offsets */
|
|
/* On mobile, let fumadocs handle the layout natively */
|
|
@media (min-width: 1024px) {
|
|
:root {
|
|
--fd-banner-height: 92px !important; /* 52px top + 40px tabs */
|
|
}
|
|
|
|
#nd-docs-layout {
|
|
/* Use 100dvh so sidebar height = 100dvh - 92px (banner) = full viewport below navbar */
|
|
--fd-docs-height: 100dvh !important;
|
|
--fd-sidebar-width: 300px !important;
|
|
margin-left: var(--sidebar-offset) !important;
|
|
margin-right: var(--toc-offset) !important;
|
|
min-height: var(--fd-docs-height) !important;
|
|
}
|
|
|
|
/* Pin the sidebar to the viewport instead of letting fumadocs' `sticky` do it.
|
|
A sticky box is bottom-limited by its containing block, and #nd-docs-layout
|
|
ends ~660px above the document bottom because the site footer is a sibling
|
|
of the layout, not a grid child. So across the whole footer the sidebar gets
|
|
pushed upward — and any content-height change while the reader is in that
|
|
zone (expanding an FAQ row, say) makes it visibly jump. A fixed box ignores
|
|
both the container's end and the document's height, so neither happens.
|
|
|
|
Safe because the grid columns are explicit (`0px 300px 1fr 268px 0px`), so
|
|
removing the placeholder from flow leaves its track intact. `left`/`width`
|
|
are restated because a fixed box no longer derives them from its grid cell,
|
|
and `height` already comes from fumadocs' own utility classes.
|
|
|
|
Anchoring to `bottom` rather than `top` is what keeps the footer off it: the
|
|
offset is how far the footer currently reaches into the viewport (published
|
|
by `FooterOverlapProbe`), so the sidebar keeps its full height and slides up
|
|
out of view as the footer arrives, the way it did before it was pinned. With
|
|
no footer on screen the offset is 0 and this resolves back to top: 92px. */
|
|
[data-sidebar-placeholder] {
|
|
position: fixed !important;
|
|
left: var(--sidebar-offset);
|
|
width: var(--fd-sidebar-width);
|
|
top: auto !important;
|
|
bottom: var(--docs-footer-overlap, 0px) !important;
|
|
}
|
|
|
|
/* Sidebar divider line — pinned for the same reason, and so it stays glued to
|
|
the sidebar's right edge. Being fixed takes it out of #nd-docs-layout's grid
|
|
entirely, so it needs no grid placement and cannot skew a content cell; its
|
|
position comes from `left`/`top`/`bottom` alone. Unlike the sidebar it is
|
|
shortened rather than slid, so it runs from the navbar down to the footer's
|
|
top border and the two meet instead of the line stopping short. */
|
|
#nd-docs-layout::before {
|
|
content: "";
|
|
display: block;
|
|
position: fixed;
|
|
top: 92px; /* below navbar */
|
|
bottom: var(--docs-footer-overlap, 0px);
|
|
left: calc(var(--sidebar-offset) + var(--fd-sidebar-width));
|
|
width: 1px;
|
|
background-color: var(--surface-active);
|
|
pointer-events: none;
|
|
z-index: 21;
|
|
}
|
|
|
|
/* Hide fumadocs nav on desktop - we use custom navbar there */
|
|
#nd-docs-layout > header {
|
|
display: none !important;
|
|
}
|
|
}
|
|
|
|
/* Sidebar spacing — left padding aligns item text with navbar content (item has 8px internal padding) */
|
|
[data-sidebar-viewport],
|
|
#nd-sidebar > div {
|
|
padding: 0 14px 0 calc(var(--nav-inset) - 8px) !important;
|
|
background: transparent !important;
|
|
}
|
|
|
|
/* Override Fumadocs p-4 on scroll viewport — must beat Tailwind v4 utility layer specificity */
|
|
html #nd-sidebar [data-radix-scroll-area-viewport],
|
|
html #nd-sidebar [data-radix-scroll-area-viewport].p-4,
|
|
html aside#nd-sidebar [data-radix-scroll-area-viewport] {
|
|
padding: 0 !important;
|
|
padding-top: 0 !important;
|
|
padding-bottom: 0 !important;
|
|
padding-left: 0 !important;
|
|
padding-right: 0 !important;
|
|
}
|
|
|
|
/* Top/bottom breathing room inside the scrollable sidebar content — scrollable, not clipped */
|
|
html #nd-sidebar [data-radix-scroll-area-viewport] > div {
|
|
padding-top: 20px !important;
|
|
padding-bottom: 16px !important;
|
|
}
|
|
|
|
/* Override sidebar item styling to match Raindrop */
|
|
/* Target Link and button elements in sidebar - override Fumadocs itemVariants */
|
|
/* Exclude the small chevron-only toggle buttons */
|
|
/* Using html prefix for higher specificity over Tailwind v4 utilities */
|
|
/* NEVER set `display` here. This selector scores (1,2,2) and carries
|
|
`!important`, so it out-specifies every rule below that hides the language
|
|
selector, theme toggle, and search button — a `display` declaration here
|
|
forces all of them back into the sidebar. The 30px chip height therefore
|
|
comes from line-height + padding (20 + 5 + 5), not from flex centering. */
|
|
html #nd-sidebar a:not(:has(span.font-mono)),
|
|
html #nd-sidebar button:not([aria-label*="ollapse"]):not([aria-label*="xpand"]) {
|
|
font-size: 0.875rem !important; /* 14px to match navbar items */
|
|
line-height: 20px !important;
|
|
padding: 5px 0.5rem !important; /* 30px tall overall — the app's chip pill, at its px-2 */
|
|
font-weight: 400 !important;
|
|
border-radius: 0.5rem !important; /* platform rounded-lg */
|
|
font-family: var(--font-geist-sans), ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont,
|
|
"Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif !important;
|
|
}
|
|
|
|
/* Sidebar text — platform --text-body */
|
|
html #nd-sidebar a:not(:has(span.font-mono)),
|
|
html #nd-sidebar button:not([aria-label*="ollapse"]):not([aria-label*="xpand"]) {
|
|
color: var(--text-body) !important;
|
|
}
|
|
|
|
/* Chevron icons — platform --text-icon */
|
|
#nd-sidebar svg {
|
|
display: inline-block !important;
|
|
opacity: 1 !important;
|
|
color: var(--text-icon) !important;
|
|
flex-shrink: 0 !important;
|
|
}
|
|
|
|
/* Ensure the small chevron toggle buttons are visible */
|
|
#nd-sidebar button[aria-label*="ollapse"],
|
|
#nd-sidebar button[aria-label*="xpand"] {
|
|
display: flex !important;
|
|
opacity: 1 !important;
|
|
padding: 0.25rem !important;
|
|
}
|
|
|
|
/* Add tiny gap between nested items */
|
|
#nd-sidebar ul li {
|
|
margin-bottom: 0.0625rem !important;
|
|
}
|
|
|
|
#nd-sidebar ul li:last-child {
|
|
margin-bottom: 0 !important;
|
|
}
|
|
|
|
/* Section separator headers — match the app sidebar's group label: 12px,
|
|
sentence case, normal weight. Only the fumadocs defaults are overridden here;
|
|
size and color stay on the component. */
|
|
[data-sidebar-viewport] [data-separator] p,
|
|
#nd-sidebar [data-separator] p {
|
|
font-weight: 400 !important;
|
|
text-transform: none !important;
|
|
letter-spacing: normal !important;
|
|
margin: 0 !important;
|
|
padding: 0 !important;
|
|
}
|
|
|
|
/* The first group sits flush against the top padding — it has nothing to be
|
|
separated from. */
|
|
[data-separator]:not([data-separator] ~ [data-separator]) {
|
|
margin-top: 0;
|
|
}
|
|
|
|
/* Active state — aligned with platform --surface-active */
|
|
#nd-sidebar a[data-active="true"]:not(:has(span.font-mono)),
|
|
#nd-sidebar button[data-active="true"] {
|
|
background-image: none !important;
|
|
}
|
|
|
|
html #nd-sidebar a[data-active="true"]:not(:has(span.font-mono)),
|
|
html #nd-sidebar button[data-active="true"] {
|
|
background-color: var(--surface-active) !important;
|
|
color: var(--text-body) !important;
|
|
}
|
|
|
|
/* Hover state — emcn's two-surface row model (see `chipHoverSurfaceClass`).
|
|
These rules must carry !important to beat fumadocs' own sidebar styles, which
|
|
also means they override the Tailwind hover utilities on the items; keep the
|
|
two in step. */
|
|
html #nd-sidebar a:not(:has(span.font-mono)):hover:not([data-active="true"]),
|
|
html #nd-sidebar button:hover:not([data-active="true"]) {
|
|
background-color: var(--surface-hover) !important;
|
|
}
|
|
|
|
/* Hide search, platform, and collapse button from sidebar completely */
|
|
[data-sidebar] [data-search],
|
|
[data-sidebar] .search-toggle,
|
|
#nd-sidebar [data-search],
|
|
#nd-sidebar .search-toggle,
|
|
[data-sidebar-viewport] [data-search],
|
|
[data-sidebar-viewport] button[data-search],
|
|
aside[data-sidebar] [role="button"]:has([data-search]),
|
|
aside[data-sidebar] > div > button:first-child,
|
|
#nd-sidebar > div > button:first-child,
|
|
[data-sidebar] a[href*="sim.ai"],
|
|
#nd-sidebar a[href*="sim.ai"],
|
|
[data-sidebar-viewport] a[href*="sim.ai"],
|
|
/* Hide search buttons (but NOT folder chevron buttons) */
|
|
aside[data-sidebar] > div:first-child
|
|
> button:not([aria-label="Collapse"]):not([aria-label="Expand"]),
|
|
#nd-sidebar > div:first-child > button:not([aria-label="Collapse"]):not([aria-label="Expand"]),
|
|
/* Hide sidebar collapse button (panel icon) - direct children only */
|
|
aside[data-sidebar] > button:first-of-type:not([aria-label="Collapse"]):not([aria-label="Expand"]),
|
|
[data-sidebar]
|
|
> button[type="button"]:first-of-type:not([aria-label="Collapse"]):not([aria-label="Expand"]),
|
|
button[data-collapse]:not([aria-label="Collapse"]):not([aria-label="Expand"]),
|
|
[data-sidebar-header] button,
|
|
/* Hide theme toggle from sidebar footer */
|
|
aside[data-sidebar] [data-theme-toggle],
|
|
[data-sidebar-footer],
|
|
[data-sidebar] footer,
|
|
footer button[aria-label*="heme"],
|
|
aside[data-sidebar] > div:last-child:has(button[aria-label*="heme"]),
|
|
aside[data-sidebar] button[aria-label*="heme"],
|
|
[data-sidebar] button[aria-label*="Theme"],
|
|
/* Additional theme toggle selectors */
|
|
aside[data-sidebar] > *:last-child
|
|
button,
|
|
[data-sidebar-viewport] ~ *,
|
|
aside[data-sidebar] > div:not([data-sidebar-viewport]),
|
|
/* Aggressive theme toggle hiding */
|
|
aside[data-sidebar] svg[class*="sun"],
|
|
aside[data-sidebar] svg[class*="moon"],
|
|
aside[data-sidebar] button[type="button"]:last-child,
|
|
aside button:has(svg:only-child),
|
|
[data-sidebar] div:has(> button[type="button"]:only-child:last-child),
|
|
/* Hide theme toggle and other non-content elements */
|
|
aside[data-sidebar] > *:not([data-sidebar-viewport]) {
|
|
display: none !important;
|
|
}
|
|
|
|
/* Desktop only: Hide sidebar toggle buttons and nav title/logo (keep visible on mobile) */
|
|
@media (min-width: 1025px) {
|
|
[data-sidebar-container] > button,
|
|
[data-sidebar-container] [data-toggle],
|
|
aside[data-sidebar] [data-sidebar-toggle],
|
|
button[data-sidebar-toggle],
|
|
nav button[data-sidebar-toggle],
|
|
button[aria-label="Toggle Sidebar"],
|
|
button[aria-label="Collapse Sidebar"],
|
|
/* Hide nav title/logo in sidebar on desktop - target all possible locations */
|
|
/* Lower specificity selectors first (attribute selectors) */
|
|
[data-sidebar-header],
|
|
[data-sidebar] [data-title],
|
|
aside[data-sidebar] a[href="/"],
|
|
aside[data-sidebar] a[href="/"] img,
|
|
aside[data-sidebar] > a:first-child,
|
|
aside[data-sidebar] > div > a:first-child,
|
|
aside[data-sidebar] img[alt="Sim"],
|
|
aside[data-sidebar] svg[aria-label="Sim"],
|
|
/* Higher specificity selectors (ID selectors) */
|
|
#nd-sidebar
|
|
a[href="/"],
|
|
#nd-sidebar a[href="/"] img,
|
|
#nd-sidebar a[href="/"] svg,
|
|
#nd-sidebar > a:first-child,
|
|
#nd-sidebar > div:first-child > a:first-child,
|
|
#nd-sidebar img[alt="Sim"],
|
|
#nd-sidebar svg[aria-label="Sim"],
|
|
/* Hide theme toggle at bottom of sidebar on desktop */
|
|
#nd-sidebar
|
|
> footer,
|
|
#nd-sidebar footer,
|
|
aside#nd-sidebar > *:last-child:not(div),
|
|
#nd-sidebar > button:last-child,
|
|
#nd-sidebar button[aria-label*="theme" i],
|
|
#nd-sidebar button[aria-label*="Theme"],
|
|
#nd-sidebar > div:last-child > button {
|
|
display: none !important;
|
|
}
|
|
}
|
|
|
|
/* Extra aggressive - hide everything after the viewport */
|
|
aside[data-sidebar] [data-sidebar-viewport] ~ * {
|
|
display: none !important;
|
|
}
|
|
|
|
/* Tighter spacing for sidebar content */
|
|
[data-sidebar-viewport] > * {
|
|
margin-bottom: 0.0625rem;
|
|
}
|
|
|
|
[data-sidebar-viewport] > *:last-child {
|
|
margin-bottom: 0;
|
|
}
|
|
|
|
[data-sidebar-viewport] ul {
|
|
margin: 0;
|
|
padding: 0;
|
|
}
|
|
|
|
/* Ensure sidebar starts with content immediately */
|
|
aside[data-sidebar] > div:first-child {
|
|
padding-top: 0;
|
|
}
|
|
|
|
/* Remove all sidebar borders and backgrounds (except the right divider) */
|
|
[data-sidebar-container],
|
|
aside[data-sidebar],
|
|
[data-sidebar],
|
|
[data-sidebar] *,
|
|
#nd-sidebar,
|
|
#nd-sidebar * {
|
|
border: none !important;
|
|
}
|
|
|
|
/* Sidebar border is handled via #nd-docs-layout::before pseudo-element (see desktop section below) */
|
|
|
|
/* Override fumadocs background colors for sidebar */
|
|
.dark #nd-sidebar,
|
|
.dark [data-sidebar-container],
|
|
.dark aside[data-sidebar] {
|
|
--color-fd-muted: transparent !important;
|
|
--color-fd-secondary: transparent !important;
|
|
background: transparent !important;
|
|
}
|
|
|
|
/* Force normal text flow in sidebar */
|
|
[data-sidebar],
|
|
[data-sidebar] *,
|
|
[data-sidebar-viewport],
|
|
[data-sidebar-viewport] * {
|
|
writing-mode: horizontal-tb !important;
|
|
}
|
|
|
|
/* Apply Geist Mono to code elements */
|
|
code,
|
|
pre,
|
|
pre code {
|
|
font-family: var(--font-mono-stack);
|
|
}
|
|
|
|
/* Inline code — neutral colors aligned with sim design system */
|
|
:not(pre) > code {
|
|
padding: 0.2em 0.4em;
|
|
border-radius: 0.375rem;
|
|
font-size: 0.875em;
|
|
font-weight: 500;
|
|
}
|
|
|
|
/* Inline code — platform surface-4 / text-body / border-1 */
|
|
:not(pre) > code {
|
|
background-color: var(--surface-4);
|
|
color: var(--text-body);
|
|
border: 1px solid var(--border-1);
|
|
}
|
|
|
|
/* Remove heavy shadows globally — aligned with sim design system (shadow-card: 0 1px 3px rgba(0,0,0,0.04)) */
|
|
figure.shiki,
|
|
figure[data-rehype-pretty-code-figure],
|
|
.shiki {
|
|
box-shadow: none !important;
|
|
}
|
|
|
|
/* Search dialog — lighter shadow + constrained size */
|
|
[data-radix-popper-content-wrapper] > div,
|
|
[role="dialog"][data-state] {
|
|
box-shadow: var(--shadow-medium) !important;
|
|
}
|
|
|
|
[role="dialog"][data-state] {
|
|
max-width: 480px !important;
|
|
}
|
|
|
|
/* Search dialog overlay + panel must cover the sticky navbar — both default to z-50,
|
|
and the navbar wins the tie by DOM order, leaving it unblurred above the overlay */
|
|
.bg-fd-overlay,
|
|
[role="dialog"][data-state] {
|
|
z-index: 60 !important;
|
|
}
|
|
|
|
pre {
|
|
font-size: 0.875rem;
|
|
line-height: 1.7;
|
|
tab-size: 2;
|
|
-webkit-overflow-scrolling: touch;
|
|
}
|
|
|
|
pre code {
|
|
display: block;
|
|
width: fit-content;
|
|
min-width: 100%;
|
|
}
|
|
|
|
/* Syntax highlighting adjustments for better readability */
|
|
pre code .line {
|
|
padding-left: 0;
|
|
padding-right: 0;
|
|
}
|
|
|
|
/* Content typography — align heading sizes and weights with platform */
|
|
main article h1,
|
|
[data-content] h1,
|
|
#nd-page h1 {
|
|
font-size: 1.5rem !important;
|
|
font-weight: 550 !important;
|
|
letter-spacing: -0.02em;
|
|
color: var(--text-primary);
|
|
}
|
|
|
|
main article h2,
|
|
[data-content] h2,
|
|
#nd-page h2 {
|
|
font-size: 1.25rem !important;
|
|
font-weight: 500 !important;
|
|
letter-spacing: -0.015em;
|
|
color: var(--text-primary);
|
|
}
|
|
|
|
main article h3,
|
|
main article h4,
|
|
[data-content] h3,
|
|
[data-content] h4,
|
|
#nd-page h3,
|
|
#nd-page h4 {
|
|
font-size: var(--text-md) !important;
|
|
font-weight: 470 !important;
|
|
letter-spacing: -0.01em;
|
|
color: var(--text-body);
|
|
}
|
|
|
|
/* Body text — platform --text-secondary */
|
|
main article p,
|
|
[data-content] p,
|
|
[data-docs-page] p {
|
|
color: var(--text-secondary);
|
|
}
|
|
|
|
/* Muted text — platform --text-muted */
|
|
main article .text-muted-foreground,
|
|
[data-content] .text-muted-foreground,
|
|
[data-docs-page] .text-muted-foreground {
|
|
color: var(--text-muted);
|
|
}
|
|
|
|
/* List items — inherit body text color */
|
|
main article li,
|
|
[data-content] li,
|
|
[data-docs-page] li {
|
|
color: var(--text-secondary);
|
|
}
|
|
|
|
/* Custom text highlighting styles */
|
|
.text-highlight {
|
|
color: var(--color-fd-primary);
|
|
}
|
|
|
|
/* Override marker color for highlighted lists */
|
|
.highlight-markers li::marker {
|
|
color: var(--color-fd-primary);
|
|
}
|
|
|
|
/* Remove the thin border-left on nested TOC items (keeps main indicator only) */
|
|
#nd-toc a[style*="padding-inline-start"] {
|
|
border-left: none !important;
|
|
}
|
|
|
|
/* The clerk TOC draws its active range twice: a track segment, plus a dot that
|
|
animates along the track to the current heading. The dot is redundant with the
|
|
segment and reads as a stray artifact, so hide it and keep the segment. It is
|
|
the only node fumadocs gives an inline offset-path, which is what anchors it. */
|
|
#nd-toc [style*="offset-path"] {
|
|
display: none !important;
|
|
}
|
|
|
|
/* TOC heading — align weight with landing */
|
|
#nd-toc h3,
|
|
#nd-toc [class*="title"] {
|
|
font-weight: 480 !important;
|
|
font-size: var(--text-small) !important;
|
|
color: var(--text-muted);
|
|
}
|
|
|
|
/* TOC links — softer colors aligned with landing muted text */
|
|
#nd-toc a {
|
|
font-weight: 430 !important;
|
|
font-size: var(--text-small) !important;
|
|
color: var(--text-muted);
|
|
transition: color 0.2s;
|
|
}
|
|
|
|
#nd-toc a:hover {
|
|
color: var(--text-body);
|
|
}
|
|
|
|
#nd-toc a[data-active="true"] {
|
|
color: var(--text-primary) !important;
|
|
font-weight: 470 !important;
|
|
}
|
|
|
|
/* Add bottom spacing to prevent abrupt page endings */
|
|
[data-content] {
|
|
padding-top: 1.5rem !important;
|
|
padding-bottom: 4rem;
|
|
}
|
|
|
|
/* Alternative fallback for different Fumadocs versions */
|
|
main article,
|
|
.docs-page main {
|
|
padding-top: 1.5rem !important;
|
|
padding-bottom: 4rem;
|
|
}
|
|
|
|
/* Main content area - center and constrain like turborepo/raindrop */
|
|
/* Note: --sidebar-offset and --toc-offset are now applied at #nd-docs-layout level */
|
|
main[data-main] {
|
|
max-width: var(--spacing-fd-container, 1400px);
|
|
margin-left: auto;
|
|
margin-right: auto;
|
|
padding-top: 1rem;
|
|
padding-left: var(--content-gap);
|
|
padding-right: var(--content-gap);
|
|
order: 1 !important;
|
|
}
|
|
|
|
/* Adjust for smaller screens */
|
|
@media (max-width: 768px) {
|
|
main[data-main] {
|
|
padding-left: 1rem;
|
|
padding-right: 1rem;
|
|
}
|
|
#nd-page:has(.api-page-header) {
|
|
padding-left: 1rem;
|
|
padding-right: 1rem;
|
|
}
|
|
}
|
|
|
|
/* Ensure docs page content is properly constrained */
|
|
[data-docs-page] {
|
|
max-width: 1400px;
|
|
margin-left: auto;
|
|
margin-right: auto;
|
|
padding-top: 1.5rem !important;
|
|
}
|
|
|
|
/* Remove any unwanted outlines from video elements */
|
|
video {
|
|
outline: none !important;
|
|
}
|
|
|
|
/* API Reference Pages — Mintlify-style overrides */
|
|
|
|
/* OpenAPI pages: span main + TOC grid columns for wide two-column layout.
|
|
Use named grid lines from grid-template-areas so this works regardless
|
|
of whether the grid has 3 columns (production) or 5 columns (local dev). */
|
|
#nd-page:has(.api-page-header) {
|
|
grid-column: main-start / toc-end !important;
|
|
max-width: 1400px !important;
|
|
padding-left: calc(var(--content-gap) + 1rem);
|
|
padding-right: calc(var(--content-gap) + 1rem);
|
|
}
|
|
|
|
/* Hide the empty TOC aside on OpenAPI pages so it doesn't overlay content */
|
|
#nd-docs-layout:has(#nd-page:has(.api-page-header)) #nd-toc {
|
|
display: none;
|
|
}
|
|
|
|
/* Hide the default "Response Body" heading rendered by fumadocs-openapi */
|
|
.response-section-wrapper > .response-section-content > h2,
|
|
.response-section-wrapper > .response-section-content > h3 {
|
|
display: none !important;
|
|
}
|
|
|
|
/* Hide default accordion triggers (status code rows) — we show our own dropdown */
|
|
.response-section-wrapper [data-orientation="vertical"] > [data-state] > h3 {
|
|
display: none !important;
|
|
}
|
|
|
|
/* Ensure API reference pages use the same font as the rest of the docs.
|
|
`.font-mono` is excluded: this selector (id + element) outranks the
|
|
`.font-mono` class rule, so without it every code identifier renders sans. */
|
|
#nd-page:has(.api-page-header),
|
|
#nd-page:has(.api-page-header) h2,
|
|
#nd-page:has(.api-page-header) h3,
|
|
#nd-page:has(.api-page-header) h4,
|
|
#nd-page:has(.api-page-header) p:not(.font-mono),
|
|
#nd-page:has(.api-page-header) span:not(.font-mono),
|
|
#nd-page:has(.api-page-header) div:not(.font-mono),
|
|
#nd-page:has(.api-page-header) label:not(.font-mono),
|
|
#nd-page:has(.api-page-header) button:not(.font-mono) {
|
|
font-family: var(--font-geist-sans), ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont,
|
|
"Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
|
}
|
|
|
|
/* Method badge pills — shared background colors (page + sidebar) */
|
|
span.font-mono.font-medium[data-method="get"],
|
|
span.font-mono.font-medium[data-method="head"],
|
|
span.font-mono.font-medium[data-method="options"] {
|
|
background-color: var(--badge-success-bg);
|
|
}
|
|
span.font-mono.font-medium[data-method="post"] {
|
|
background-color: var(--badge-blue-bg);
|
|
}
|
|
span.font-mono.font-medium[data-method="put"] {
|
|
background-color: var(--badge-amber-bg);
|
|
}
|
|
span.font-mono.font-medium[data-method="patch"] {
|
|
background-color: var(--badge-orange-bg);
|
|
}
|
|
span.font-mono.font-medium[data-method="delete"] {
|
|
background-color: var(--badge-error-bg);
|
|
}
|
|
|
|
/* Sidebar links with method badges — match regular item padding */
|
|
html #nd-sidebar a:has(span.font-mono.font-medium) {
|
|
display: flex !important;
|
|
align-items: center !important;
|
|
gap: 0.375rem;
|
|
padding: 0.375rem 0.875rem !important;
|
|
font-size: 0.875rem !important;
|
|
line-height: 1.4 !important;
|
|
font-weight: 450 !important;
|
|
border-radius: 0.75rem !important;
|
|
}
|
|
|
|
/* Sidebar method badges — fixed-width for right-aligned labels */
|
|
#nd-sidebar a span.font-mono.font-medium {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
width: 2.625rem;
|
|
font-size: var(--text-micro) !important;
|
|
line-height: 1 !important;
|
|
padding: 0.15625rem 0.25rem;
|
|
border-radius: 0.375rem;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
/* Footer navigation method badges — pill styling to match sidebar */
|
|
#nd-page span.font-mono.font-medium[data-method] {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
font-size: var(--text-micro) !important;
|
|
line-height: 1 !important;
|
|
padding: 0.15625rem 0.375rem;
|
|
border-radius: 0.375rem;
|
|
}
|
|
|
|
/* API page code/card containers — transparent background */
|
|
#nd-page:has(.api-page-header) {
|
|
--color-fd-card: transparent !important;
|
|
}
|
|
|
|
#nd-page:has(.api-page-header) figure.shiki {
|
|
border-radius: 0.75rem !important;
|
|
background-color: transparent !important;
|
|
}
|
|
|
|
/* API page code example panels — transparent */
|
|
#nd-page:has(.api-page-header) .rounded-xl.border.bg-fd-card {
|
|
background-color: transparent !important;
|
|
}
|
|
|
|
#nd-page:has(.api-page-header) .rounded-xl.border.shadow-md.bg-fd-card {
|
|
background-color: transparent !important;
|
|
box-shadow: none !important;
|
|
}
|
|
|
|
/* Hide "Filter Properties" search bar everywhere — main page and popovers */
|
|
input[placeholder="Filter Properties"] {
|
|
display: none !important;
|
|
}
|
|
div:has(> input[placeholder="Filter Properties"]) {
|
|
display: none !important;
|
|
}
|
|
/* Remove top border on first visible property after hidden Filter Properties */
|
|
div:has(> input[placeholder="Filter Properties"]) + .text-sm.border-t {
|
|
border-top: none !important;
|
|
}
|
|
|
|
/* Hide "TypeScript Definitions" copy panel on API pages */
|
|
#nd-page:has(.api-page-header) div.not-prose.rounded-xl.border.p-3.mb-4 {
|
|
display: none !important;
|
|
}
|
|
#nd-page:has(.api-page-header) div.not-prose.rounded-xl.border.p-3:has(> div > p.font-medium) {
|
|
display: none !important;
|
|
}
|
|
|
|
/* Hide info tags (Format, Default, etc.) everywhere — main page and popovers */
|
|
div.flex.flex-row.gap-2.flex-wrap.not-prose:has(> div.bg-fd-secondary) {
|
|
display: none !important;
|
|
}
|
|
div.flex.flex-row.items-start.bg-fd-secondary.border.rounded-lg.text-xs {
|
|
display: none !important;
|
|
}
|
|
|
|
/* Method+path bar — cleaner, lighter styling like Gumloop.
|
|
Override bg-fd-card CSS variable directly for reliability. */
|
|
#nd-page:has(.api-page-header) div.flex.flex-row.items-center.rounded-xl.border.not-prose {
|
|
--color-fd-card: var(--surface-3) !important;
|
|
background-color: var(--surface-3) !important;
|
|
border-color: var(--border-1) !important;
|
|
}
|
|
/* Method badge inside path bar — cleaner sans-serif, softer colors */
|
|
#nd-page:has(.api-page-header)
|
|
div.flex.flex-row.items-center.rounded-xl.border.not-prose
|
|
span.font-mono.font-medium {
|
|
font-family: var(--font-geist-sans), ui-sans-serif, system-ui, sans-serif !important;
|
|
font-weight: 600 !important;
|
|
font-size: var(--text-xs) !important;
|
|
letter-spacing: 0.025em;
|
|
text-transform: uppercase;
|
|
padding: 0.125rem 0.5rem !important;
|
|
border-radius: 0.375rem !important;
|
|
}
|
|
/* Path bar per-method colors (fumadocs renders these, so we match by class) */
|
|
/* GET */
|
|
#nd-page:has(.api-page-header)
|
|
div.flex.flex-row.items-center.rounded-xl.border.not-prose
|
|
span.font-mono.font-medium[class*="text-green"] {
|
|
color: var(--badge-success-text) !important;
|
|
background-color: var(--badge-success-bg) !important;
|
|
}
|
|
/* POST */
|
|
#nd-page:has(.api-page-header)
|
|
div.flex.flex-row.items-center.rounded-xl.border.not-prose
|
|
span.font-mono.font-medium[class*="text-blue"] {
|
|
color: var(--badge-blue-text) !important;
|
|
background-color: var(--badge-blue-bg) !important;
|
|
}
|
|
/* PUT */
|
|
#nd-page:has(.api-page-header)
|
|
div.flex.flex-row.items-center.rounded-xl.border.not-prose
|
|
span.font-mono.font-medium[class*="text-yellow"] {
|
|
color: var(--badge-amber-text) !important;
|
|
background-color: var(--badge-amber-bg) !important;
|
|
}
|
|
/* PATCH */
|
|
#nd-page:has(.api-page-header)
|
|
div.flex.flex-row.items-center.rounded-xl.border.not-prose
|
|
span.font-mono.font-medium[class*="text-orange"] {
|
|
color: var(--badge-orange-text) !important;
|
|
background-color: var(--badge-orange-bg) !important;
|
|
}
|
|
/* DELETE */
|
|
#nd-page:has(.api-page-header)
|
|
div.flex.flex-row.items-center.rounded-xl.border.not-prose
|
|
span.font-mono.font-medium[class*="text-red"] {
|
|
color: var(--badge-error-text) !important;
|
|
background-color: var(--badge-error-bg) !important;
|
|
}
|
|
|
|
/* Path text inside method+path bar — monospace, bright like Gumloop */
|
|
#nd-page:has(.api-page-header) div.flex.flex-row.items-center.rounded-xl.border.not-prose code {
|
|
color: var(--text-body) !important;
|
|
background: none !important;
|
|
border: none !important;
|
|
padding: 0 !important;
|
|
font-size: var(--text-small) !important;
|
|
}
|
|
/* Inline code in API pages — neutral color aligned with sim design.
|
|
Exclude code inside the method+path bar (handled above). */
|
|
#nd-page:has(.api-page-header) .prose :not(pre) > code {
|
|
color: var(--text-body) !important;
|
|
}
|
|
|
|
/* Response Section — custom dropdown-based rendering (Mintlify style) */
|
|
|
|
/* Hide divider lines between accordion items */
|
|
.response-section-wrapper [data-orientation="vertical"].divide-y > * {
|
|
border-top-width: 0 !important;
|
|
border-bottom-width: 0 !important;
|
|
}
|
|
.response-section-wrapper [data-orientation="vertical"].divide-y {
|
|
border-top: none !important;
|
|
}
|
|
|
|
/* Remove content type labels inside accordion items (we show one in the header) */
|
|
.response-section-wrapper [data-orientation="vertical"] p.not-prose:has(code.text-xs) {
|
|
display: none !important;
|
|
}
|
|
|
|
/* Hide the top-level response description (e.g. "Execution was successfully cancelled.")
|
|
but NOT field descriptions inside Schema which also use prose-no-margin.
|
|
The response description is a direct child of AccordionContent (role=region) with mb-2. */
|
|
.response-section-wrapper [data-orientation="vertical"] [role="region"] > .prose-no-margin.mb-2,
|
|
.response-section-wrapper
|
|
[data-orientation="vertical"]
|
|
[role="region"]
|
|
> div
|
|
> .prose-no-margin.mb-2 {
|
|
display: none !important;
|
|
}
|
|
|
|
/* Remove left padding on accordion content so it aligns with Path Parameters */
|
|
.response-section-wrapper [data-orientation="vertical"] [role="region"] {
|
|
padding-inline-start: 0 !important;
|
|
}
|
|
|
|
/* Response section header */
|
|
.response-section-header {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 1rem;
|
|
margin-top: 1.75rem;
|
|
margin-bottom: 0.25rem;
|
|
}
|
|
|
|
.response-section-title {
|
|
font-size: 1.25rem;
|
|
font-weight: 500;
|
|
letter-spacing: -0.015em;
|
|
margin: 0;
|
|
color: var(--text-primary);
|
|
font-family: var(--font-geist-sans), ui-sans-serif, system-ui, -apple-system, sans-serif;
|
|
}
|
|
|
|
.response-section-meta {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.75rem;
|
|
margin-left: auto;
|
|
}
|
|
|
|
/* Status code dropdown */
|
|
.response-section-dropdown-wrapper {
|
|
position: relative;
|
|
}
|
|
|
|
/* API-reference metadata face — the status trigger, the content-type label, the
|
|
`required` / `header` markers, and the status-code tabs. Defined once; each
|
|
consumer below adds only its own colour, content, and order. The `code.text-xs`
|
|
label further down needs `!important` to beat fumadocs and stays separate. */
|
|
#nd-page:has(.api-page-header) button.response-section-dropdown-trigger,
|
|
.response-section-dropdown-trigger,
|
|
#nd-page:has(.api-page-header) span.response-section-content-type,
|
|
.response-section-content-type,
|
|
#nd-page:has(.api-page-header)
|
|
.flex.flex-wrap.items-center.gap-3.not-prose:has(span.text-red-400)::after,
|
|
#nd-page:has(.api-page-header) div.my-4 > .flex.flex-wrap.items-center.gap-3.not-prose::before,
|
|
#nd-page:has(.api-page-header) div.my-4 > .flex.flex-wrap.items-center.gap-3.not-prose::after,
|
|
#nd-page:has(.api-page-header) .flex.gap-3\.5.overflow-x-auto.not-prose > button {
|
|
font-size: var(--text-code);
|
|
line-height: 1.25rem;
|
|
font-weight: 400;
|
|
font-family: var(--font-mono-stack);
|
|
}
|
|
|
|
/* Status-code trigger — matches the content-type label beside it. */
|
|
#nd-page:has(.api-page-header) button.response-section-dropdown-trigger,
|
|
.response-section-dropdown-trigger {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.25rem;
|
|
height: 1.25rem;
|
|
padding: 0 0.25rem;
|
|
color: var(--text-secondary);
|
|
background: none;
|
|
border: none;
|
|
cursor: pointer;
|
|
border-radius: 0.375rem;
|
|
transition: color 0.15s;
|
|
}
|
|
/* Carries the same id-qualified prefix as the base rule above; without it the
|
|
base rule outranks this one and the trigger never changes colour on hover. */
|
|
#nd-page:has(.api-page-header) button.response-section-dropdown-trigger:hover,
|
|
.response-section-dropdown-trigger:hover {
|
|
color: var(--text-primary);
|
|
}
|
|
|
|
.response-section-chevron {
|
|
width: 0.75rem;
|
|
height: 0.75rem;
|
|
transition: transform 0.15s;
|
|
}
|
|
.response-section-chevron-open {
|
|
transform: rotate(180deg);
|
|
}
|
|
|
|
.response-section-dropdown-menu {
|
|
position: absolute;
|
|
top: calc(100% + 0.25rem);
|
|
left: 0;
|
|
z-index: 50;
|
|
min-width: 5rem;
|
|
background-color: var(--bg);
|
|
border: 1px solid var(--border);
|
|
border-radius: 0.75rem;
|
|
box-shadow: var(--shadow-card);
|
|
padding: 0.375rem;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.response-section-dropdown-item {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
width: 100%;
|
|
padding: 0.375rem 0.5rem;
|
|
font-size: 0.875rem;
|
|
color: var(--text-body);
|
|
background: none;
|
|
border: none;
|
|
cursor: pointer;
|
|
border-radius: 0.5rem;
|
|
transition:
|
|
background-color 0.1s,
|
|
color 0.1s;
|
|
font-family: var(--font-geist-sans), ui-sans-serif, system-ui, sans-serif;
|
|
}
|
|
.response-section-dropdown-item:hover {
|
|
background-color: var(--surface-active);
|
|
color: var(--text-primary);
|
|
}
|
|
.response-section-dropdown-item-selected {
|
|
color: var(--text-primary);
|
|
}
|
|
|
|
.response-section-check {
|
|
width: 0.875rem;
|
|
height: 0.875rem;
|
|
}
|
|
|
|
/* Content-type label. The Response header renders this class; the Request Body
|
|
header renders a fumadocs `code.text-xs`. Keep the two in sync — the same
|
|
string at different weights reads as one being lighter than the other. */
|
|
#nd-page:has(.api-page-header) span.response-section-content-type,
|
|
.response-section-content-type {
|
|
color: var(--text-secondary);
|
|
background: none;
|
|
border: none;
|
|
padding: 0;
|
|
}
|
|
|
|
/* Response schema container — remove border to match Path Parameters style */
|
|
.response-section-wrapper [data-orientation="vertical"] .border.px-3.py-2.rounded-lg {
|
|
border: none !important;
|
|
padding: 0 !important;
|
|
border-radius: 0 !important;
|
|
background-color: transparent;
|
|
}
|
|
|
|
/* Property row — reorder: name (1) → type badge (2) → required badge (3) */
|
|
#nd-page:has(.api-page-header) .flex.flex-wrap.items-center.gap-3.not-prose {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
align-items: center;
|
|
}
|
|
|
|
/* Name span — order 1 */
|
|
#nd-page:has(.api-page-header)
|
|
.flex.flex-wrap.items-center.gap-3.not-prose
|
|
> span.font-medium.font-mono.text-fd-primary {
|
|
order: 1;
|
|
}
|
|
|
|
/* Type token — order 2. Covers every shape the slot takes: scalar span, union
|
|
wrapper, schema-reference button, and the auth row's `::after` label. Reuses
|
|
the docs inline-code recipe, so a type reads as code wherever it appears; the
|
|
explicit 20px height keeps a union level with a scalar, which its nested
|
|
links would otherwise push to 26px. */
|
|
#nd-page:has(.api-page-header)
|
|
.flex.flex-wrap.items-center.gap-3.not-prose
|
|
> span.text-sm.font-mono.text-fd-muted-foreground,
|
|
#nd-page:has(.api-page-header) .flex.flex-wrap.items-center.gap-3.not-prose > button,
|
|
#nd-page:has(.api-page-header) .flex.flex-wrap.items-center.gap-3.not-prose > span:has(> button),
|
|
#nd-page:has(.api-page-header)
|
|
div.my-4
|
|
> .flex.flex-wrap.items-center.gap-3.not-prose
|
|
> span.text-sm.font-mono.text-fd-muted-foreground::after {
|
|
order: 2;
|
|
display: inline-flex;
|
|
align-items: center;
|
|
height: 1.25rem;
|
|
/* No gap: an `array<T>` slot holds its brackets as bare text nodes, which
|
|
become anonymous flex items, so any gap here would prise `array<` and `>`
|
|
away from the type they wrap. The union separator spaces itself instead. */
|
|
gap: 0;
|
|
background-color: var(--surface-4);
|
|
border: 1px solid var(--border-1);
|
|
color: var(--text-body);
|
|
padding: 0 0.3125rem;
|
|
border-radius: 0.375rem;
|
|
font-size: var(--text-code);
|
|
line-height: 1;
|
|
font-weight: 400;
|
|
font-family: var(--font-mono-stack);
|
|
}
|
|
|
|
/* Everything inside a type token inherits the token's own face, size, and ink.
|
|
Applied to every descendant, not just the links: a union's `|` separator is a
|
|
classless `span`, so the page-wide `span:not(.font-mono)` rule assigned it the
|
|
body sans face and one chip rendered in two faces. Anything fumadocs nests in
|
|
here later is covered by the same reset.
|
|
Underline is deferred to hover so links don't read heavier than a plain scalar
|
|
in the same box. The button that *is* the slot needs its own rule below: it
|
|
cannot `inherit`, which would pull the row's 14px sans back in. */
|
|
#nd-page:has(.api-page-header)
|
|
.flex.flex-wrap.items-center.gap-3.not-prose
|
|
> span.text-sm.font-mono.text-fd-muted-foreground
|
|
* {
|
|
text-decoration: none;
|
|
color: inherit;
|
|
font-size: inherit;
|
|
font-family: inherit;
|
|
}
|
|
#nd-page:has(.api-page-header)
|
|
.flex.flex-wrap.items-center.gap-3.not-prose
|
|
> button.text-sm.font-mono.text-fd-muted-foreground {
|
|
text-decoration: none;
|
|
}
|
|
#nd-page:has(.api-page-header)
|
|
.flex.flex-wrap.items-center.gap-3.not-prose
|
|
> span.text-sm.font-mono.text-fd-muted-foreground
|
|
:is(a, button):hover,
|
|
#nd-page:has(.api-page-header)
|
|
.flex.flex-wrap.items-center.gap-3.not-prose
|
|
> button.text-sm.font-mono.text-fd-muted-foreground:hover {
|
|
text-decoration: underline;
|
|
text-underline-offset: 2px;
|
|
}
|
|
|
|
/* Union separator — dimmed one step, no further: `string | null` started
|
|
reading as `string null` on the chip fill. Own margin; the slot has no gap. */
|
|
#nd-page:has(.api-page-header)
|
|
.flex.flex-wrap.items-center.gap-3.not-prose
|
|
> span.text-sm.font-mono.text-fd-muted-foreground
|
|
> span {
|
|
margin: 0 0.375rem;
|
|
color: var(--text-muted);
|
|
}
|
|
|
|
/* Hide the "*" inside the name span — we'll add "required" as a ::after on the flex row */
|
|
#nd-page:has(.api-page-header) span.font-medium.font-mono.text-fd-primary > span.text-red-400 {
|
|
display: none;
|
|
}
|
|
|
|
/* Required marker — order 3. Error text colour but no fill: eight required
|
|
params on one page should not read as eight alarms. */
|
|
#nd-page:has(.api-page-header)
|
|
.flex.flex-wrap.items-center.gap-3.not-prose:has(span.text-red-400)::after {
|
|
content: "required";
|
|
order: 3;
|
|
display: inline-flex;
|
|
align-items: center;
|
|
color: var(--badge-error-text);
|
|
}
|
|
/* Optional "?" indicator — hide it */
|
|
#nd-page:has(.api-page-header)
|
|
span.font-medium.font-mono.text-fd-primary
|
|
> span.text-fd-muted-foreground {
|
|
display: none;
|
|
}
|
|
|
|
/* Hide the auth scheme type label (e.g. "apiKey") next to Authorization heading */
|
|
#nd-page:has(.api-page-header) .flex.items-start.justify-between.gap-2 > div.not-prose {
|
|
display: none !important;
|
|
}
|
|
|
|
/* Auth property — replace "<token>" with "string" badge, add "header" and "required" badges.
|
|
Auth properties use my-4 (vs py-4 for regular properties). */
|
|
|
|
/* Auth property flex row — name: order 1, type: order 2, ::before "header": order 3, ::after "required": order 4 */
|
|
#nd-page:has(.api-page-header)
|
|
div.my-4
|
|
> .flex.flex-wrap.items-center.gap-3.not-prose
|
|
> span.font-medium.font-mono.text-fd-primary {
|
|
order: 1;
|
|
}
|
|
/* Auth rows collapse the real `<token>` text to zero and draw the chip in the
|
|
`::after` below, so this span is a bare wrapper: it must drop the type-token
|
|
box it matches, or the chip renders inside a second, empty bordered box. */
|
|
#nd-page:has(.api-page-header)
|
|
div.my-4
|
|
> .flex.flex-wrap.items-center.gap-3.not-prose
|
|
> span.text-sm.font-mono.text-fd-muted-foreground {
|
|
order: 2;
|
|
font-size: 0;
|
|
padding: 0;
|
|
background: none;
|
|
border: none;
|
|
height: auto;
|
|
line-height: 0;
|
|
}
|
|
/* Only the label — the box comes from the shared type-token rule above, which
|
|
this pseudo-element is a member of. */
|
|
#nd-page:has(.api-page-header)
|
|
div.my-4
|
|
> .flex.flex-wrap.items-center.gap-3.not-prose
|
|
> span.text-sm.font-mono.text-fd-muted-foreground::after {
|
|
content: "string";
|
|
}
|
|
|
|
/* "header" location via ::before on the auth flex row — uncontained metadata,
|
|
matching the `required` marker rather than the type token. */
|
|
#nd-page:has(.api-page-header) div.my-4 > .flex.flex-wrap.items-center.gap-3.not-prose::before {
|
|
content: "header";
|
|
order: 3;
|
|
display: inline-flex;
|
|
align-items: center;
|
|
color: var(--text-secondary);
|
|
}
|
|
|
|
/* "required" marker via ::after on the auth flex row */
|
|
#nd-page:has(.api-page-header) div.my-4 > .flex.flex-wrap.items-center.gap-3.not-prose::after {
|
|
content: "required";
|
|
order: 4;
|
|
display: inline-flex;
|
|
align-items: center;
|
|
color: var(--badge-error-text);
|
|
}
|
|
/* Hide the trailing "In: header" line — redundant with the header marker.
|
|
Matched by position, not shape: descriptions contain a `code` too (status
|
|
codes), so a bare `p:has(> code)` also hid the API-key description. */
|
|
#nd-page:has(.api-page-header) div.my-4 .prose-no-margin > p:last-child:has(> code) {
|
|
display: none !important;
|
|
}
|
|
|
|
/* Section dividers — bottom border after Authorization and Body sections. */
|
|
.api-section-divider {
|
|
padding-bottom: 0.5rem;
|
|
border-bottom: 1px solid var(--surface-active);
|
|
}
|
|
|
|
/* Property rows — breathing room like Mintlify.
|
|
Regular properties use border-t py-4; auth properties use border-t my-4. */
|
|
#nd-page:has(.api-page-header) .text-sm.border-t.py-4 {
|
|
padding-top: 1.25rem !important;
|
|
padding-bottom: 1.25rem !important;
|
|
}
|
|
#nd-page:has(.api-page-header) .text-sm.border-t.my-4 {
|
|
margin-top: 1.25rem !important;
|
|
margin-bottom: 1.25rem !important;
|
|
padding-top: 1.25rem;
|
|
}
|
|
|
|
/* Divider lines between fields — very subtle like Mintlify */
|
|
#nd-page:has(.api-page-header) .text-sm.border-t {
|
|
border-color: var(--surface-active);
|
|
}
|
|
|
|
/* Body/Callback "application/json" label — strip inline-code chrome and keep in
|
|
sync with `.response-section-content-type`; same string, two headers. */
|
|
#nd-page:has(.api-page-header) .flex.gap-2.items-center.justify-between p.not-prose code.text-xs,
|
|
#nd-page:has(.api-page-header) .flex.justify-between.gap-2.items-end p.not-prose code.text-xs {
|
|
background: none !important;
|
|
border: none !important;
|
|
padding: 0 !important;
|
|
color: var(--text-secondary) !important;
|
|
font-size: var(--text-code) !important;
|
|
line-height: 1.25rem !important;
|
|
font-weight: 400 !important;
|
|
font-family: var(--font-mono-stack) !important;
|
|
}
|
|
|
|
/* Section headings (Authorization, Path Parameters, etc.) — consistent top spacing */
|
|
#nd-page:has(.api-page-header) .min-w-0.flex-1 h2 {
|
|
margin-top: 1.75rem !important;
|
|
margin-bottom: 0.25rem !important;
|
|
}
|
|
|
|
/* Example-panel code overflows rather than wraps: a wrapped line restarts at
|
|
column zero and misreports the JSON nesting depth. */
|
|
|
|
/* fumadocs' own lucide glyphs (heading anchor, copy button) ship at stroke-width
|
|
2 while emcn strokes at 1.55, so they read heavier than everything near them.
|
|
Layout-wide on purpose: one icon weight across the docs. Retired once
|
|
createAPIPage is given renderHeading/renderCodeBlock. */
|
|
#nd-docs-layout svg[class*="lucide"] {
|
|
stroke-width: 1.55;
|
|
}
|
|
|
|
/* Callout/alert — transparent background, no shadow, hide colored bar, add padding */
|
|
div.rounded-xl.border.bg-fd-card.shadow-md:has(> [role="none"]) {
|
|
background-color: transparent !important;
|
|
box-shadow: none !important;
|
|
border-color: var(--border-1) !important;
|
|
padding-left: 0.875rem !important;
|
|
align-items: center !important;
|
|
}
|
|
|
|
div.rounded-xl.border.bg-fd-card.shadow-md > [role="none"] {
|
|
display: none !important;
|
|
}
|
|
|
|
/* Files component — transparent background */
|
|
div.not-prose.rounded-md.border.bg-fd-card.p-2 {
|
|
background-color: transparent !important;
|
|
border-color: var(--border-1) !important;
|
|
}
|
|
|
|
/* Callout icon — outline style, text color, vertically centered */
|
|
div.rounded-xl.border.bg-fd-card.shadow-md:has(> [role="none"]) > svg {
|
|
fill: none !important;
|
|
color: var(--color-fd-foreground) !important;
|
|
stroke-width: 1.55 !important;
|
|
flex-shrink: 0;
|
|
width: 1rem !important;
|
|
height: 1rem !important;
|
|
}
|
|
|
|
/* API page header — constrain title/copy-page to left content column, not full width.
|
|
Only applies on OpenAPI pages (which have the two-column layout). */
|
|
@media (min-width: 1280px) {
|
|
.api-page-header {
|
|
max-width: calc(100% - 400px - 1.5rem);
|
|
}
|
|
}
|
|
|
|
/* Footer navigation — constrain to left content column on OpenAPI pages only.
|
|
Target pages that contain the two-column layout via :has() selector. */
|
|
#nd-page:has(.api-page-header) > div:last-child {
|
|
max-width: calc(100% - 400px - 1.5rem);
|
|
}
|
|
@media (max-width: 1024px) {
|
|
#nd-page:has(.api-page-header) > div:last-child {
|
|
max-width: 100%;
|
|
}
|
|
}
|
|
|
|
/* ─── Content Components — aligned with platform design system ─── */
|
|
|
|
/* Heading anchor links — no underline, inherit color */
|
|
#nd-page h1 a,
|
|
#nd-page h2 a,
|
|
#nd-page h3 a,
|
|
#nd-page h4 a,
|
|
#nd-page h5 a,
|
|
#nd-page h6 a,
|
|
.prose h1 a,
|
|
.prose h2 a,
|
|
.prose h3 a,
|
|
.prose h4 a,
|
|
.prose h5 a,
|
|
.prose h6 a {
|
|
text-decoration: none !important;
|
|
color: inherit !important;
|
|
border: none !important;
|
|
}
|
|
|
|
/* Tables — clean divider-based style matching chat markdown renderer */
|
|
.prose table,
|
|
[data-docs-page] table,
|
|
[data-content] table,
|
|
main article table {
|
|
border-collapse: collapse !important;
|
|
border-spacing: 0 !important;
|
|
background: none !important;
|
|
border: none !important;
|
|
border-radius: 0 !important;
|
|
overflow: visible !important;
|
|
font-size: 0.875rem !important;
|
|
}
|
|
|
|
.prose thead th,
|
|
[data-docs-page] thead th,
|
|
[data-content] thead th,
|
|
main article thead th {
|
|
background: none !important;
|
|
font-weight: 600 !important;
|
|
padding: 0.5rem 0.75rem !important;
|
|
border-bottom: 1px solid var(--border) !important;
|
|
border-left: none !important;
|
|
border-right: none !important;
|
|
border-top: none !important;
|
|
border-inline-start: none !important;
|
|
color: var(--text-primary);
|
|
text-align: left;
|
|
white-space: nowrap;
|
|
line-height: 1.5;
|
|
}
|
|
|
|
.prose td,
|
|
[data-docs-page] td,
|
|
[data-content] td,
|
|
main article td {
|
|
padding: 0.5rem 0.75rem !important;
|
|
border-bottom: 1px solid var(--surface-active) !important;
|
|
border-left: none !important;
|
|
border-right: none !important;
|
|
border-top: none !important;
|
|
border-inline-start: none !important;
|
|
color: var(--text-secondary);
|
|
line-height: 1.5;
|
|
}
|
|
|
|
/* Remove bottom border on last row */
|
|
.prose tbody tr:last-child td,
|
|
[data-docs-page] tbody tr:last-child td,
|
|
[data-content] tbody tr:last-child td,
|
|
main article tbody tr:last-child td {
|
|
border-bottom: none !important;
|
|
}
|
|
|
|
/* Code blocks — aligned with platform chat code block styling */
|
|
|
|
/* Standalone code block figure — border + rounded */
|
|
figure.shiki:not(div > figure.shiki),
|
|
figure[data-rehype-pretty-code-figure]:not(div > figure[data-rehype-pretty-code-figure]),
|
|
figure:has(pre):not(div > figure:has(pre)) {
|
|
border-radius: 0.5rem !important;
|
|
border: 1px solid var(--border) !important;
|
|
overflow: hidden !important;
|
|
background-color: transparent !important;
|
|
box-shadow: none !important;
|
|
}
|
|
|
|
/* Code block inside tabs (API examples) — no extra border, inherits from parent */
|
|
div > figure.shiki {
|
|
border: none !important;
|
|
background-color: transparent !important;
|
|
box-shadow: none !important;
|
|
}
|
|
|
|
/* Tabbed code block container (cURL/JS/Go tabs) */
|
|
div:has(> [role="tablist"]):has(> div > figure.shiki) {
|
|
border-radius: 0.5rem !important;
|
|
border: 1px solid var(--border) !important;
|
|
overflow: hidden !important;
|
|
background-color: transparent !important;
|
|
box-shadow: none !important;
|
|
}
|
|
|
|
/* Tab list bar — match platform surface-4 */
|
|
div:has(> div > figure.shiki) > [role="tablist"] {
|
|
background: none !important;
|
|
border-bottom: 1px solid var(--surface-active) !important;
|
|
}
|
|
|
|
/* Tab triggers — muted text, active gets foreground */
|
|
div:has(> div > figure.shiki) > [role="tablist"] button {
|
|
color: var(--text-muted) !important;
|
|
font-weight: 470 !important;
|
|
}
|
|
|
|
div:has(> div > figure.shiki) > [role="tablist"] button:hover {
|
|
color: var(--text-body) !important;
|
|
}
|
|
|
|
div:has(> div > figure.shiki) > [role="tablist"] button[data-state="active"] {
|
|
color: var(--text-primary) !important;
|
|
}
|
|
|
|
/* Code block title header (figcaption with filename) */
|
|
figure.shiki > div:first-child:has(figcaption) {
|
|
background-color: var(--surface-4) !important;
|
|
border-bottom: 1px solid var(--surface-active) !important;
|
|
}
|
|
|
|
figure.shiki figcaption {
|
|
color: var(--text-muted) !important;
|
|
}
|
|
|
|
/* Code block pre element — transparent bg */
|
|
figure.shiki pre {
|
|
background-color: transparent !important;
|
|
}
|
|
|
|
/* Code viewport scroll area — transparent bg */
|
|
figure.shiki > div[role="region"] {
|
|
background-color: transparent !important;
|
|
}
|
|
|
|
/* Copy button — minimal ghost style */
|
|
figure.shiki button[aria-label="Copy Text"],
|
|
figure.shiki button[aria-label="Copied Text"] {
|
|
color: var(--text-muted) !important;
|
|
background: none !important;
|
|
border: none !important;
|
|
box-shadow: none !important;
|
|
backdrop-filter: none !important;
|
|
}
|
|
|
|
figure.shiki button[aria-label="Copy Text"]:hover {
|
|
color: var(--text-icon) !important;
|
|
}
|
|
|
|
figure.shiki button[aria-label="Copied Text"] {
|
|
color: var(--brand-accent) !important;
|
|
}
|
|
|
|
/* Copy button container — remove backdrop blur bg */
|
|
figure.shiki > div:has(> button[aria-label]) {
|
|
background: none !important;
|
|
backdrop-filter: none !important;
|
|
}
|
|
|
|
/* Cards container — vertical list with line dividers instead of grid boxes */
|
|
.prose .grid:has(> a[data-card]),
|
|
#nd-page .grid:has(> a[data-card]) {
|
|
display: flex !important;
|
|
flex-direction: column !important;
|
|
gap: 0 !important;
|
|
border-top: 1px solid var(--border) !important;
|
|
border-bottom: 1px solid var(--border) !important;
|
|
}
|
|
|
|
/* Card items — line-separated rows with hover bg (scoped to grid container only) */
|
|
.grid > a[data-card] {
|
|
display: flex !important;
|
|
flex-direction: column !important;
|
|
gap: 0.125rem !important;
|
|
background: none !important;
|
|
border: none !important;
|
|
border-bottom: 1px solid var(--border) !important;
|
|
border-radius: 0 !important;
|
|
padding: 0.875rem 1rem !important;
|
|
transition: background-color 0.15s !important;
|
|
box-shadow: none !important;
|
|
}
|
|
|
|
.grid > a[data-card]:last-child {
|
|
border-bottom: none !important;
|
|
}
|
|
|
|
.grid > a[data-card]:hover {
|
|
background-color: var(--surface-3) !important;
|
|
}
|
|
|
|
/* Card title */
|
|
.grid > a[data-card] h3 {
|
|
font-weight: 470 !important;
|
|
font-size: 0.875rem !important;
|
|
color: var(--text-primary) !important;
|
|
}
|
|
|
|
/* Card description */
|
|
.grid > a[data-card] p,
|
|
.grid > a[data-card] div {
|
|
color: var(--text-muted) !important;
|
|
font-size: var(--text-small) !important;
|
|
}
|
|
|
|
/* Steps — lighter styling aligned with platform */
|
|
.fd-steps {
|
|
border-left-color: var(--surface-active) !important;
|
|
}
|
|
|
|
.fd-step::before {
|
|
background-color: var(--surface-4) !important;
|
|
color: var(--text-muted) !important;
|
|
font-weight: 500 !important;
|
|
}
|
|
|
|
/* Blockquotes — subtle left border, matching platform divider */
|
|
.prose blockquote,
|
|
[data-docs-page] blockquote,
|
|
[data-content] blockquote,
|
|
main article blockquote {
|
|
border-left: 3px solid var(--border-1) !important;
|
|
padding: 0.25rem 0 0.25rem 1rem !important;
|
|
color: var(--text-muted) !important;
|
|
font-style: italic;
|
|
background: none !important;
|
|
margin: 1.5rem 0 !important;
|
|
}
|
|
|
|
/* Remove all remaining box-shadows on content components */
|
|
.prose > *,
|
|
[data-docs-page] figure,
|
|
[data-docs-page] table,
|
|
[data-docs-page] [data-card] {
|
|
box-shadow: none !important;
|
|
}
|
|
|
|
/* Tailwind v4 content sources */
|
|
@source '../app/**/*.{js,ts,jsx,tsx,mdx}';
|
|
@source '../components/**/*.{js,ts,jsx,tsx,mdx}';
|
|
@source '../content/**/*.{js,ts,jsx,tsx,mdx}';
|
|
@source '../mdx-components.tsx';
|
|
@source '../node_modules/fumadocs-ui/dist/**/*.js';
|