/* ── Self-hosted typefaces ───────────────────────────
   Inter and JetBrains Mono, the same pair gpustack.ai uses. Served
   from this site rather than fonts.googleapis.com so the page does not
   depend on a third party being reachable — the marketing site already
   self-hosts these (next/font downloads them at build time), and this
   keeps the two consistent.

   Variable fonts: one file spans the whole weight axis, so 300/400/700
   all come from the same download. The `unicode-range` on each face is
   what keeps this cheap — a page of English text pulls only the latin
   subsets (~110 KB) and never fetches latin-ext.

   To refresh: request the URL below with a current desktop User-Agent
   (the API returns woff2 only to browsers that support it), then save
   each woff2 it points at into docs/assets/fonts/ and mirror the
   font-weight / unicode-range values here. Latin subsets only — the
   Cyrillic/Greek/Vietnamese ones would roughly triple the payload for
   glyphs these docs do not use.

   https://fonts.googleapis.com/css2
     ?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900
     &family=JetBrains+Mono:ital,wght@0,100..800;1,100..800
     &display=swap */
@font-face {
    font-family: 'Inter';
    font-style: italic;
    font-weight: 100 900;
    font-display: swap;
    src: url('../assets/fonts/inter-italic-latin.woff2') format('woff2');
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
    font-family: 'Inter';
    font-style: italic;
    font-weight: 100 900;
    font-display: swap;
    src: url('../assets/fonts/inter-italic-latin-ext.woff2') format('woff2');
    unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
    font-family: 'Inter';
    font-style: normal;
    font-weight: 100 900;
    font-display: swap;
    src: url('../assets/fonts/inter-normal-latin.woff2') format('woff2');
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
    font-family: 'Inter';
    font-style: normal;
    font-weight: 100 900;
    font-display: swap;
    src: url('../assets/fonts/inter-normal-latin-ext.woff2') format('woff2');
    unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
    font-family: 'JetBrains Mono';
    font-style: italic;
    font-weight: 100 800;
    font-display: swap;
    src: url('../assets/fonts/jetbrains-mono-italic-latin.woff2') format('woff2');
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
    font-family: 'JetBrains Mono';
    font-style: italic;
    font-weight: 100 800;
    font-display: swap;
    src: url('../assets/fonts/jetbrains-mono-italic-latin-ext.woff2') format('woff2');
    unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
    font-family: 'JetBrains Mono';
    font-style: normal;
    font-weight: 100 800;
    font-display: swap;
    src: url('../assets/fonts/jetbrains-mono-normal-latin.woff2') format('woff2');
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
    font-family: 'JetBrains Mono';
    font-style: normal;
    font-weight: 100 800;
    font-display: swap;
    src: url('../assets/fonts/jetbrains-mono-normal-latin-ext.woff2') format('woff2');
    unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* Hand these to Material, which composes its own stacks around them
   (it falls back to system fonts when these are undefined). */
:root {
    --md-text-font: 'Inter';
    --md-code-font: 'JetBrains Mono';
}

/* ── Brand ───────────────────────────────────────────
   #0055ff, matching gpustack.ai so the docs and the marketing site
   read as one product. The hue carries meaning through links and
   accents; the chrome (header, tabs) stays neutral — a saturated
   bar across the top is what made the page feel heavy. */
:root {
    --gps-accent: #0055ff;
    --gps-accent-hover: #3377ff;
    --gps-accent-tint: rgba(0, 85, 255, 0.1);
}

/* On the dark scheme the brand blue is too dim against the slate
   background, so step up to a lighter tint of the same hue. */
[data-md-color-scheme="slate"] {
    --gps-accent: #66a3ff;
    --gps-accent-hover: #99c2ff;
    --gps-accent-tint: rgba(102, 163, 255, 0.14);
}

/* ── Dark scheme legibility ──────────────────────────
   Material's slate ramp puts secondary text at 0.56 alpha, which
   measures 4.08:1 against the page — under AA, and it is what makes
   the left nav read as a grey haze. Raising it also lifts code
   comments, punctuation and variables, which all derive from this
   same variable.

   Code blocks barely separate from the prose (their surface is only 4%
   lighter than the page), but lifting that surface is the wrong fix:
   the syntax palette is tuned against it, and raising it to 21% pushed
   four token colours below 4.5:1. A hairline gives the same separation
   and costs the highlighting nothing. */
[data-md-color-scheme="slate"] {
    --md-default-fg-color--light: hsla(var(--md-hue), 15%, 90%, 0.74);
}
[data-md-color-scheme="slate"] .md-typeset pre > code {
    border: 1px solid hsla(var(--md-hue), 15%, 32%, 1);
}

/* Headings and body text are both 0.82 on slate, so hierarchy rests
   entirely on size. A brighter heading restores the step that the
   light scheme gets for free from pure black on white. */
[data-md-color-scheme="slate"] .md-typeset h1,
[data-md-color-scheme="slate"] .md-typeset h2,
[data-md-color-scheme="slate"] .md-typeset h3,
[data-md-color-scheme="slate"] .md-typeset h4 {
    color: hsla(var(--md-hue), 15%, 95%, 0.96);
}

/* Material sets --md-typeset-a-color from the *primary* palette, and on
   the slate scheme it does so through a combined
   [data-md-color-scheme][data-md-color-primary] rule (0,2,0). Matching
   both attributes plus `body` gives (0,2,1), which clears it; anything
   less and the links silently fall back to Material's blue. One rule
   serves both schemes — the custom properties it reads are already
   scheme-aware. */
body[data-md-color-scheme][data-md-color-primary] {
    --md-accent-fg-color: var(--gps-accent-hover);
    --md-accent-fg-color--transparent: var(--gps-accent-tint);
    --md-typeset-a-color: var(--gps-accent);
}

/* ── Logo ────────────────────────────────────────────
   The header used to be a saturated blue block, so a single white mark
   worked everywhere. Now that the light scheme has a white header, the
   white mark would disappear into it — swap in the colour mark there.
   Both files are shipped by partials/logo.html. */
/* Material forces `display: block` on the logo image from several
   places (.md-header__button.md-logo img, and again for the drawer's
   .md-nav__button.md-logo img). Selector tweaks only won the header
   and left the drawer rendering both marks side by side, so this is
   one of the few spots where !important is the honest fix: exactly one
   mark may be visible, and no theme rule should be able to override
   that. */
.md-logo img.gps-logo--dark {
    display: none !important;
}
[data-md-color-scheme="slate"] .md-logo img.gps-logo--light {
    display: none !important;
}
[data-md-color-scheme="slate"] .md-logo img.gps-logo--dark {
    display: block !important;
}

/* The title's 20px left margin is there to clear the drawer toggle —
   but that toggle is hidden once the viewport is wide enough for the
   tabs bar, leaving the wordmark stranded 32px from a 24px logo when
   the two should read as one lockup. Tighten it on that breakpoint
   only, so the narrow layout keeps its room for the toggle.

   The [dir] prefix is required, not decorative: Material writes every
   direction-dependent property as `[dir=ltr] .foo` for RTL support, so
   a bare `.md-header__title` is a specificity step short and loses. */
@media screen and (min-width: 76.25em) {
    [dir="ltr"] .md-header__title {
        margin-left: 4px;
    }
    [dir="rtl"] .md-header__title {
        margin-right: 4px;
    }
}

/* ── Chrome ──────────────────────────────────────────
   Hairline separators instead of a shadow under a colour block. */
.md-header {
    box-shadow: none;
    border-bottom: 1px solid var(--md-default-fg-color--lightest);
}
.md-tabs {
    border-bottom: 1px solid var(--md-default-fg-color--lightest);
}
.md-tabs__link {
    opacity: 1;
    color: var(--md-default-fg-color--light);
    font-size: 0.72rem;
}
.md-tabs__link:hover,
.md-tabs__link--active {
    color: var(--md-default-fg-color);
}
/* Mark the active tab with a rule rather than by colouring the text,
   so the tab strip stays quiet. */
.md-tabs__item--active {
    box-shadow: inset 0 -2px 0 var(--gps-accent);
}

/* ── Reading rhythm ──────────────────────────────────
   Slightly larger type and looser leading: the docs are long-form
   reference, read for minutes at a time, not scanned. */
.md-typeset {
    font-size: 0.8rem;
    line-height: 1.75;
}
.md-typeset h1 {
    font-weight: 700;
    letter-spacing: -0.02em;
    color: var(--md-default-fg-color);
}
.md-typeset h2 {
    margin-top: 2.2em;
    font-weight: 650;
    letter-spacing: -0.012em;
}
.md-typeset h3 {
    margin-top: 1.7em;
    font-weight: 600;
}
/* Give a section break some air before the next heading. */
.md-typeset h2 + h3 {
    margin-top: 1em;
}

/* Cap the measure of running prose at ~78 characters. Full column
   width came out at 88, which is past the point where the eye starts
   losing the start of the next line. Tables, code blocks, figures and
   admonitions are deliberately excluded — they carry wide content and
   should keep the whole column. */
.md-typeset > p,
.md-typeset > ul,
.md-typeset > ol,
.md-typeset > blockquote {
    max-width: 38em;
}

/* Tables and code sat at 12.8px/13.6px against 16px body text — enough
   of a drop to make scanning a spec table tiring. */
.md-typeset table:not([class]) {
    font-size: 0.7rem;
}
.md-typeset table:not([class]) th {
    font-weight: 600;
}
.md-typeset pre > code {
    font-size: 0.72rem;
}

/* ── Links ───────────────────────────────────────────
   Prose here is dense with inline links; at full brand saturation
   every one of them competes with the sentence. Hold them close to
   the body colour and let the accent appear on hover. */
.md-typeset a {
    color: inherit;
    text-decoration: none;
    border-bottom: 1px solid color-mix(in srgb, var(--gps-accent) 35%, transparent);
    transition: color 0.15s, border-color 0.15s;
}
.md-typeset a:hover,
.md-typeset a:focus-visible {
    color: var(--gps-accent);
    border-bottom-color: var(--gps-accent);
}
/* Navigation, tables of contents and cards are not prose — no rule. */
.md-typeset .md-nav a,
.md-typeset .md-button,
.md-typeset .grid.cards a,
.md-typeset a.headerlink,
.md-typeset .tabbed-labels a {
    border-bottom: none;
}


.center-table {
    text-align: center;
}

.md-typeset .center-table :is(td,th):not([align]) {
    text-align: initial;
}

.md-typeset pre > code {
    border-radius: 0.5rem;
    box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05);
}

::-webkit-scrollbar {
    width: 6px;
    height: 6px;
}

::-webkit-scrollbar-thumb {
    background-color: rgba(150, 150, 150, 0.4);
    border-radius: 3px;
}

::-webkit-scrollbar-thumb:hover {
    background-color: rgba(150, 150, 150, 0.7);
}

.md-typeset img {
    border-radius: 0.4rem;
    transition: transform 0.3s ease, box-shadow 0.3s ease;
}

.md-typeset img:hover {
    transform: translateY(-2px);
    box-shadow: 0 8px 15px rgba(0, 0, 0, 0.1);
}

.md-typeset .admonition {
    border-radius: 0.4rem;
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.04);
}

/* The "primary" icon in the overview cards — follows the brand hue.
   The semantic colours below (green/orange/red/purple) are content
   categories, not brand, so they stay put. */
.icon-blue {
    color: var(--gps-accent);
}

.icon-green {
    color: #28a745;
}

.icon-orange {
    color: #fd7e14;
}

.icon-red {
    color: #dc3545;
}

.icon-purple {
    color: #6f42c1;
}

.logo-tile-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 16px;
    margin: 2em 0;
}

.logo-tile {
    position: relative;
    display: flex;
    justify-content: center;
    align-items: center;
    background: #ffffff;
    border: 1px solid #f0f0f2;
    border-radius: 12px;
    height: 100px;
    transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
    padding: 24px;
}

.logo-tile::after {
    content: attr(data-tooltip);
    position: absolute;
    bottom: 100%;
    left: 50%;
    transform: translateX(-50%) translateY(0);
    padding: 6px 12px;
    background-color: #333;
    color: #fff;
    font-size: 0.75rem;
    font-weight: 500;
    border-radius: 6px;
    white-space: nowrap;
    opacity: 0;
    visibility: hidden;
    transition: all 0.2s ease;
    pointer-events: none;
    z-index: 10;
    box-shadow: 0 4px 10px rgba(0, 0, 0, 0.15);
}

.logo-tile::before {
    content: "";
    position: absolute;
    bottom: 100%;
    left: 50%;
    transform: translateX(-50%) translateY(0);
    border: 6px solid transparent;
    border-top-color: #333;
    opacity: 0;
    visibility: hidden;
    transition: all 0.2s ease;
    pointer-events: none;
    z-index: 10;
}

.logo-tile:hover::after {
    opacity: 1;
    visibility: visible;
    transform: translateX(-50%) translateY(-12px);
}

.logo-tile:hover::before {
    opacity: 1;
    visibility: visible;
    transform: translateX(-50%) translateY(-2px);
}

.logo-tile:hover {
    border-color: var(--gps-accent);
    box-shadow: 0 10px 30px var(--gps-accent-tint);
    transform: translateY(-4px);
    z-index: 1;
}

.logo-tile img {
    height: 35px !important;
    width: auto !important;
    max-width: 100%;
    object-fit: contain;
    margin: 0 !important;
    filter: grayscale(15%) opacity(0.9);
    transition: all 0.3s ease;
    transform: none !important;
    box-shadow: none !important;
    border-radius: 0 !important;
}

.logo-tile:hover img {
    filter: grayscale(0%) opacity(1);
    transform: scale(1.05) !important;
}

@media screen and (max-width: 768px) {
    .logo-tile-grid {
        grid-template-columns: repeat(2, 1fr);
    }
}

@media screen and (max-width: 480px) {
    .logo-tile-grid {
        grid-template-columns: 1fr;
    }
}

/* The bundled documentation's build stamp, beside the site name in the header.
   Only the offline build defines the property; everywhere else the pseudo-element
   resolves to `none` and no box is generated, so the online site is untouched.

   The selector deliberately excludes the topic carrying data-md-component, which
   is the page title Material swaps in while scrolling — the stamp belongs to the
   site name alone. */
.md-header__topic:not([data-md-component]) .md-ellipsis::after {
    content: var(--gpustack-docs-stamp, none);
    margin-left: 0.6rem;
    padding-left: 0.6rem;
    border-left: 1px solid rgba(255, 255, 255, 0.3);
    color: rgba(255, 255, 255, 0.7);
    font-size: 0.6rem;
    font-weight: 400;
}
