/* vkML documentation theme.
 *
 * PyTorch's reference-docs structure and density, recoloured from the vkML logo:
 * saturated red against charcoal and brushed-metal greys.
 *
 * The layout choices are PyTorch's because they are right for a reference of
 * this shape -- three columns, a section nav that shows where you are, a
 * per-page contents, admonitions whose label is a filled bar, and prev/next at
 * the foot so the docs can be read straight through as well as searched.
 */

:root {
    --red: #e01b10;
    --red-hot: #ff3a2c;

    --mono: ui-monospace, "SF Mono", "JetBrains Mono", "Fira Code", Menlo, Consolas, monospace;
    --sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Inter, Roboto, "Helvetica Neue", sans-serif;

    /* Layout budget, chosen so all three columns fit a 1280 laptop without
       squeezing the prose:  264 nav + 656 text + 216 contents = 1136, leaving
       144 for gutters. Before this, the contents rail was simply hidden below
       1408px, which is every common laptop. */
    --nav-w: 18.5rem;
    --toc-w: 15.5rem;
    --topbar-h: 3.5rem;
    --radius: 4px;

    /* THE READING COLUMN. Measured against twelve reference documentation
       sites at 1440: their median line is 79 characters and the best-reading
       group -- stripe 65, shadcn 64, nextjs 65, tailwind 67 -- sits in the
       mid-60s. This was 50rem, which measured 93 characters: longer than every
       site checked except pytorch and huggingface, and past the 45-75 range
       where return sweeps stay reliable. 41rem against a 16px body measures
       about 74. */
    --measure: 78rem;

    /* TYPE SCALE. The stylesheet had 39 distinct font sizes across 62 uses,
       including 18 different values spanning the 2.4 pixels between 12.8 and
       15.2 -- .84rem, .845rem, .85rem, .855rem, .86rem, .87rem and so on. The
       difference between two of those is under a tenth of a pixel: not a
       decision, an accumulation. A fixed set of steps forces the next component
       to pick one that exists, which is the mechanism that keeps a site
       coherent as it grows.

       Every old value was mapped to its nearest step, so nothing moved by more
       than a pixel except where a heading was deliberately regularised. */
    --fs-1: .6875rem;    /* 11px */
    --fs-2: .75rem;      /* 12px */
    --fs-3: .8125rem;    /* 13px */
    --fs-4: .875rem;     /* 14px */
    --fs-5: 1rem;        /* 16px */
    --fs-6: 1.125rem;    /* 18px */
    --fs-7: 1.375rem;    /* 22px */
    --fs-8: 1.5625rem;   /* 25px */
    --fs-9: 2.125rem;    /* 34px */

    /* Weights. Was 400/500/550/600/650/700 -- 550 and 650 are not standard
       weights, so a family without them either synthesises or rounds, and two
       of the six were not reliably distinct anyway. */
    --fw-normal: 400;
    --fw-medium: 500;
    --fw-semibold: 600;
    --fw-bold: 700;


    /* One spacing scale, so components stop inventing margins. */
    --s-1: .25rem;
    --s-2: .5rem;
    --s-3: .75rem;
    --s-4: 1rem;
    --s-5: 1.5rem;
    --s-6: 2.5rem;
}

:root, :root[data-theme="dark"] {
    --bg: #13141a;
    --bg-nav: #0f1015;
    --bg-panel: #1b1d24;
    --bg-code: #191b21;
    --border: #282a33;
    --border-strong: #3b3e49;
    --fg: #d6d9df;
    --fg-strong: #f4f5f7;
    --fg-muted: #8a8e99;
    --accent: var(--red);
    --accent-fg: #ff4b3e;
    --shadow: rgba(0, 0, 0, .5);

    /* Admonition fills. Deep enough to read white-on-colour in the label bar. */
    --warn-bar: #6b2008;
    --warn-fg: #ffb08a;
    --note-bar: #10305e;
    --note-fg: #8fbaf0;
    --tip-bar: #123f2e;
    --tip-fg: #86d6b0;

    /* The admonition left edges, and the text that sits on the accent. These
       were hardcoded at their use sites, which made them the only colours a
       theme could not restate. */
    --warn-edge: #e2762c;
    --note-edge: #4b86d8;
    --tip-edge: #3ba277;
    --on-accent: #fff;

    /* Syntax. Hues are separated rather than brightnesses, so the code stays
       readable with a red-green deficiency. */
    --t-kw: #ff6152;
    --t-str: #e0a44a;
    --t-num: #56c8de;
    --t-com: #71757f;
    --t-fn: #c9a2ff;
    --t-bi: #7fb8ff;
}

:root[data-theme="light"] {
    --bg: #ffffff;
    --bg-nav: #f4f5f7;
    --bg-panel: #f7f8fa;
    --bg-code: #f5f6f8;
    --border: #e1e2e6;
    --border-strong: #c4c6cd;
    --fg: #22242a;
    --fg-strong: #0d0e12;
    --fg-muted: #61646d;
    --accent: #c11208;      /* the logo red is 3.4:1 on white; this clears 4.5 */
    --accent-fg: #a80f06;
    --shadow: rgba(0, 0, 0, .12);

    --warn-bar: #ffe1cf;  --warn-fg: #8a3208;
    --note-bar: #dbe9fb;  --note-fg: #10406e;
    --tip-bar: #d6f0e3;   --tip-fg: #10553a;

    --t-kw: #b3120a; --t-str: #8a5a00; --t-num: #06697c;
    --t-com: #6b6f78; --t-fn: #6b3fb5; --t-bi: #0b5aa8;

    /* Darker than the dark theme's, which the light theme previously reused.
       Measured against white, the shared values gave 3.06:1 (warn), 3.68 (note)
       and 3.17 (tip) -- warn only just clearing the 3:1 WCAG asks of meaningful
       non-text. These give 4.79, 5.28 and 5.30. The dark theme keeps the
       originals, which measure 6.00, 4.99 and 5.79 on #13141a. */
    --warn-edge: #b35a10; --note-edge: #2f6bbf; --tip-edge: #1f7a52;
    --on-accent: #fff;
}

* { box-sizing: border-box; }
html { scroll-behavior: smooth; scroll-padding-top: calc(var(--topbar-h) + 1rem); }

body {
    margin: 0;
    background: var(--bg);
    color: var(--fg);
    /* 16px, the median of the sites measured; 15.5 paired a slightly small
       body with the longest line on the page, and the two compounded. */
    font: 400 var(--fs-5)/1.68 var(--sans);
    -webkit-font-smoothing: antialiased;
}

/* Scrollbars, themed. The default light scrollbar against a charcoal page is
   the single loudest unthemed element on the screen. */
* { scrollbar-width: thin; scrollbar-color: var(--border-strong) transparent; }
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb {
    background: var(--border-strong);
    border: 2px solid var(--bg);
    border-radius: 6px;
}
::-webkit-scrollbar-thumb:hover { background: var(--fg-muted); }
::-webkit-scrollbar-corner { background: transparent; }
/* The arrow buttons at each end. Themed by omission everywhere else in this
   block, which is how they survived: the track, thumb and corner were all
   given colours and the BUTTON was not, so the browser kept drawing its own
   pale default at the foot of the sidebar -- against a dark panel, the one
   unthemed element left on the page. Removed rather than coloured; a
   scrollbar this thin has no room for a usable arrow. */
::-webkit-scrollbar-button { display: none; width: 0; height: 0; }
.sidenav::-webkit-scrollbar-thumb { border-color: var(--bg-nav); }
pre::-webkit-scrollbar-thumb { border-color: var(--bg-code); }

/* ---------------------------------------------------------------- topbar -- */

.topbar {
    position: sticky; top: 0; z-index: 60;
    display: flex; align-items: center; gap: .9rem;
    height: var(--topbar-h); padding: 0 1.1rem;
    background: var(--bg-nav); border-bottom: 1px solid var(--border);
}
.topbar .brand {
    display: flex; align-items: center; gap: .55rem;
    font: 700 var(--fs-5)/1 var(--sans); letter-spacing: -.02em;
    color: var(--fg-strong); text-decoration: none;
}
.topbar .brand img { height: 1.6rem; width: auto; display: block; }
.topbar .brand .ml { color: var(--accent-fg); }
.ver { padding: .12rem .45rem; border: 1px solid var(--border-strong);
       border-radius: var(--radius); color: var(--fg-muted); font: 500 var(--fs-2)/1.5 var(--mono); }

.topbar nav { display: flex; gap: .15rem; }
.topbar nav a {
    padding: .4rem .7rem; border-bottom: 2px solid transparent;
    color: var(--fg-muted); font-size: var(--fs-4); text-decoration: none; white-space: nowrap;
}
.topbar nav a:hover { color: var(--fg-strong); }
.topbar nav a.active { color: var(--accent-fg); border-bottom-color: var(--accent); }
.spacer { margin-left: auto; }

.search { position: relative; width: min(23rem, 32vw); }
.search input {
    width: 100%; padding: .4rem .6rem .4rem 1.95rem;
    background: var(--bg); border: 1px solid var(--border-strong);
    border-radius: var(--radius); color: var(--fg); font: 400 var(--fs-4) var(--sans);
}
.search input:focus { outline: none; border-color: var(--accent); }
.search .mag { position: absolute; left: .55rem; top: 50%; transform: translateY(-50%);
               color: var(--fg-muted); font-size: var(--fs-3); pointer-events: none; }
.search kbd { position: absolute; right: .45rem; top: 50%; transform: translateY(-50%);
              padding: .05rem .32rem; border: 1px solid var(--border-strong); border-radius: 3px;
              color: var(--fg-muted); font: 500 var(--fs-1) var(--mono); pointer-events: none; }
.search input:focus ~ kbd { display: none; }

.results {
    position: absolute; top: calc(100% + .35rem); left: 0; right: 0;
    max-height: 70vh; overflow-y: auto; display: none;
    background: var(--bg-panel); border: 1px solid var(--border-strong);
    border-radius: var(--radius); box-shadow: 0 .6rem 2rem var(--shadow);
}
.results.open { display: block; }
.results a { display: block; padding: .45rem .7rem; color: var(--fg);
             text-decoration: none; border-bottom: 1px solid var(--border); }
.results a:last-child { border-bottom: 0; }
.results a:hover, .results a.sel { background: var(--bg); }
.results .r-name { font: 600 var(--fs-4) var(--mono); color: var(--fg-strong); }
.results .r-grp { float: right; font-size: var(--fs-2); color: var(--fg-muted); }
.results .r-desc { display: block; font-size: var(--fs-3); color: var(--fg-muted);
                   overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.results .empty { padding: .7rem; color: var(--fg-muted); font-size: var(--fs-4); }

.icon-btn { display: grid; place-items: center; width: 1.95rem; height: 1.95rem;
            background: none; border: 1px solid transparent; border-radius: var(--radius);
            color: var(--fg-muted); cursor: pointer; font-size: var(--fs-5); text-decoration: none; }
.icon-btn:hover { color: var(--fg-strong); border-color: var(--border-strong); }
#nav-toggle { display: none; }

/* ---------------------------------------------------------------- layout -- */

/* FULL WIDTH. Capping and centring the layout removed the gap BETWEEN the
   columns and replaced it with dead bands at both screen edges -- the
   navigation floating away from the left and the contents panel away from the
   right, which reads as a page that failed to load rather than a margin.
   The two rails belong on their edges; the prose takes what is left. */
.layout { display: flex; align-items: flex-start; }
.sidenav, .toc { position: sticky; top: var(--topbar-h);
                 height: calc(100vh - var(--topbar-h)); overflow-y: auto;
                 overscroll-behavior: contain; }

.sidenav { flex: 0 0 var(--nav-w); width: var(--nav-w); padding: 1.3rem 0 4rem;
           background: var(--bg-nav); border-right: 1px solid var(--border); }
.sidenav > h2 { margin: 0 0 1rem; padding: 0 1.2rem; border: 0;
                font: var(--fw-semibold) var(--fs-5)/1 var(--sans); color: var(--fg-strong); }

/* Section headings -- PyTorch's "Core", "C++ Frontend", "Extensions".
   Targets h3, which is what the builder emits. It also targeted `.sect`, a
   class that appeared ZERO times in the built site: the rule styled markup
   that does not exist, and until h3 was added the headings rendered flush
   against the panel edge with no padding at all. `.sect` is gone, and
   scripts/check_css_bindings.py now fails on any rule in that state. */
.sidenav h3 { margin: 1.8rem 0 .5rem; padding: 0 1.2rem;
              font: 700 var(--fs-7)/1.25 var(--sans); color: var(--fg-strong); }
.sidenav ol { list-style: none; margin: 0; padding: 0; }

.sidenav a {
    display: block; padding: .3rem 1.2rem;
    border-left: 3px solid transparent;
    color: var(--fg-muted); font-size: var(--fs-4); text-decoration: none;
    overflow-wrap: anywhere;
}
.sidenav a:hover { color: var(--fg-strong); }

/* The page you are on: bold, a size larger, an accent rule, its own ground.
   PyTorch does all four, and each one is doing work -- weight and size for the
   eye, the rule for position in the tree, the fill to separate it from hover. */
.sidenav a.active {
    color: var(--accent-fg); font-weight: 700; font-size: var(--fs-4);
    border-left-color: var(--accent); background: var(--bg-panel);
}
.sidenav code { font-size: .88em; background: none; padding: 0; border: 0; }

.grp > button {
    /* Chevron first, then the label, both to the left. space-between put the
       chevron at one edge and the text at the other, which read as right-aligned. */
    display: flex; align-items: center; gap: .45rem; width: 100%;
    padding: .32rem 1.2rem; background: none; border: 0; cursor: pointer;
    color: var(--fg); font: 500 var(--fs-4)/1.5 var(--sans); text-align: left;
}
.grp > button:hover { color: var(--fg-strong); }
.grp.here > button { color: var(--accent-fg); font-weight: 700; }
.grp > button .chev { transition: transform .15s; font-size: var(--fs-1); opacity: .7; }
.grp.closed > button .chev { transform: rotate(-90deg); }
.grp.closed > ol { display: none; }

/* The box is capped as well as the measure. Previously `.content` grew to
   fill while its children stopped at --measure, so on a wide window the
   leftover space collected as one dead gap between the prose and the table
   of contents. Capping the box and centring it splits that slack evenly,
   which is what makes the column look deliberate rather than pushed left. */
.content { flex: 1 1 auto; min-width: 0; padding: 1.6rem 3.5rem 5rem; }
.content > * { max-width: var(--measure); }
.content > .cards, .content > .pagenav { max-width: none; }

.toc { flex: 0 0 var(--toc-w); width: var(--toc-w); padding: 1.6rem 1rem 4rem;
       border-left: 1px solid var(--border); }
.toc h4 { margin: 0 0 .55rem; font: 600 var(--fs-3)/1 var(--sans); color: var(--fg-strong);
          display: flex; align-items: center; gap: .35rem; }
.toc ul { list-style: none; margin: 0; padding: 0; }
.toc a { display: block; padding: .22rem .55rem; border-left: 2px solid transparent;
         color: var(--fg-muted); font-size: var(--fs-3); text-decoration: none; overflow-wrap: anywhere; }
.toc a:hover { color: var(--fg-strong); }
/* The active entry is the one the reader is looking for when they glance
   right, so it gets size as well as colour. Weight and an accent rule alone
   left it identical in size to seven neighbours, which is a lot of scanning
   for the one line that answers "where am I". */
.toc a.active { color: var(--accent-fg); border-left-color: var(--accent);
                font-weight: 600; font-size: var(--fs-5); }
.toc a.lvl3 { padding-left: 1.15rem; font-family: var(--mono); font-size: var(--fs-2); }
.toc .side-links { margin-top: 1.5rem; padding-top: 1rem; border-top: 1px solid var(--border); }
.toc .side-links a { padding-left: 0; font-size: var(--fs-3); }

/* ----------------------------------------------------------- breadcrumbs -- */

.crumbs { display: flex; align-items: center; gap: .4rem; flex-wrap: wrap;
          margin: 0 0 1.3rem; font-size: var(--fs-3); color: var(--fg-muted); }
.crumbs a { color: var(--fg-muted); }
.crumbs a:hover { color: var(--accent-fg); }
.crumbs .sep { opacity: .45; }
.crumbs .here { color: var(--fg); }

/* ------------------------------------------------------------ typography -- */

h1, h2, h3, h4, h5 { color: var(--fg-strong); line-height: 1.25; letter-spacing: -.015em; }
h1 { margin: 0 0 .5rem; font-size: var(--fs-9); font-weight: 700; }
h2 { margin: 2.9rem 0 .9rem; font-size: var(--fs-8); font-weight: 600;
     padding-bottom: .35rem; border-bottom: 1px solid var(--border); }
h3 { margin: 2.1rem 0 .5rem; font-size: var(--fs-6); font-weight: var(--fw-semibold); }
/* An entry's NAME. It is marked up as <code> inside the heading, so it was
   inheriting the inline-code chip and rendering smaller and lighter than the
   signature box below it -- the page scanned as a list of signatures rather
   than a list of operators. Plain, full size, heading weight.

   h1 is in the list because the class pages title themselves that way, and
   leaving it out meant every class page led with its own name in a chip. */
h1 > code, h2 > code, h3 > code, h4 > code {
    background: none; border: 0; padding: 0;
    font-size: 1em; font-weight: inherit; color: inherit;
}
h4 { margin: 1.4rem 0 .4rem; font-size: var(--fs-4); font-weight: var(--fw-semibold); }
h5 { margin: 1.2rem 0 .35rem; font-size: var(--fs-3); font-weight: var(--fw-semibold);
     text-transform: uppercase; letter-spacing: .06em; color: var(--fg-muted); }

.anchor { margin-left: .4rem; color: var(--fg-muted); opacity: 0;
          font-weight: 400; text-decoration: none; font-size: .8em; }
h2:hover .anchor, h3:hover .anchor, h4:hover .anchor { opacity: 1; }

.lede { margin: 0 0 1.8rem; color: var(--fg-muted); font-size: var(--fs-5); }
p { margin: 0 0 .95rem; }
a { color: var(--accent-fg); text-decoration: none; }
a:hover { text-decoration: underline; }
ul, ol { margin: 0 0 .95rem; padding-left: 1.35rem; }
li { margin: .25rem 0; }
hr { margin: 2.2rem 0; border: 0; border-top: 1px solid var(--border); }
strong { color: var(--fg-strong); font-weight: var(--fw-semibold); }

/* ------------------------------------------------------------------ code -- */

/* No border. Measured across twelve reference sites, seven mark inline code
   with a tint alone (rust-book, react, tailwind, astro, shadcn, kubernetes,
   huggingface) and four add a hairline. With border + background + radius +
   padding, the matmul page's "six pipelines" sentence became six boxes in two
   lines and the reading rhythm broke. The tint carries the distinction; the
   size stays .875em, which already matched the peer median of 0.86. */
code { font: .875em/1.5 var(--mono); background: var(--bg-code);
       border: 0; border-radius: var(--radius); padding: .1em .35em; }
a > code { color: var(--accent-fg); border-color: var(--border-strong); }
a:hover > code { border-color: var(--accent); text-decoration: none; }

pre {
    position: relative; margin: 0 0 1.25rem; padding: .9rem 1.05rem;
    overflow-x: auto;
    background: var(--bg-code); border: 1px solid var(--border-strong);
    border-radius: var(--radius); font: var(--fs-4)/1.62 var(--mono);
}
pre code { background: none; border: 0; padding: 0; font-size: inherit; }

.copy { position: absolute; top: .4rem; right: .4rem; padding: .15rem .45rem;
        background: var(--bg-panel); border: 1px solid var(--border-strong);
        border-radius: var(--radius); color: var(--fg-muted);
        font: 500 var(--fs-1) var(--sans); cursor: pointer; opacity: 0; transition: opacity .12s; }
pre:hover .copy { opacity: 1; }
.copy:hover { color: var(--fg-strong); border-color: var(--accent); }

.tok-k { color: var(--t-kw); } .tok-s { color: var(--t-str); }
.tok-n { color: var(--t-num); } .tok-c { color: var(--t-com); font-style: italic; }
.tok-f { color: var(--t-fn); } .tok-b { color: var(--t-bi); }
.repl .p { color: var(--fg-muted); user-select: none; }
.repl .o { color: var(--fg-muted); }

/* ------------------------------------------------------- admonition blocks */

/* A filled label bar, then the body on a panel -- PyTorch's shape. The label is
   what the eye must catch, so the fill goes there and not behind the prose,
   which would make the text harder to read to no purpose. */
.admon { margin: 1.25rem 0; border: 1px solid var(--border);
         border-left: 4px solid var(--fg-muted); border-radius: var(--radius);
         overflow: hidden; background: var(--bg-panel); }
/* Horizontal padding clears the 4px accent bar rather than sitting on it.
   .85rem left only 13.6px between a coloured edge and the text, and inline
   code chips carry their own background, so a chip on the first line read as
   touching the border. The bar is decoration; the text should not appear to
   start inside it. */
.admon .label { display: flex; align-items: center; gap: .45rem; padding: .45rem 1.15rem;
                font: var(--fw-semibold) var(--fs-3)/1.4 var(--sans); color: var(--fg-strong); }
.admon .body { padding: .8rem 1.15rem; border-top: 1px solid var(--border); }
.admon .body > :last-child { margin-bottom: 0; }
.admon.warn { border-left-color: var(--warn-edge); }
.admon.warn .label { background: var(--warn-bar); color: var(--warn-fg); }
.admon.note { border-left-color: var(--note-edge); }
.admon.note .label { background: var(--note-bar); color: var(--note-fg); }
.admon.tip { border-left-color: var(--tip-edge); }
.admon.tip .label { background: var(--tip-bar); color: var(--tip-fg); }

/* ------------------------------------------------------------ API blocks -- */

.sig { margin: 0 0 1rem; padding: .8rem 1rem; background: var(--bg-panel);
       border: 1px solid var(--border); border-left: 1px solid var(--border);
       border-radius: var(--radius); font: var(--fs-4)/1.7 var(--mono); overflow-x: auto; }
.sig .name { color: var(--fg-strong); font-weight: 600; }
.sig .param { font-style: italic; }
.sig .ret { color: var(--fg-muted); }

/* A C++ declaration quoted from a header, with a link to the line it is on. */
.decl { margin: .5rem 0 1rem; padding: .7rem .9rem; background: var(--bg-code);
        border: 1px solid var(--border); border-radius: var(--radius);
        font: var(--fs-3)/1.65 var(--mono); overflow-x: auto; }
.decl .where { display: block; margin-top: .45rem; font: 400 var(--fs-2) var(--sans);
               color: var(--fg-muted); }

.params { margin: 0 0 1.2rem; }
.params dt { font: var(--fs-4)/1.6 var(--mono); color: var(--fg-strong); margin-top: .65rem; }
.params dt .type { color: var(--fg-muted); font-style: normal; }
.params dt .opt { color: var(--accent-fg); font-size: .78em; text-transform: uppercase;
                  letter-spacing: .05em; margin-left: .35rem; }
.params dd { margin: .12rem 0 0 1.2rem; color: var(--fg); }

.support { display: flex; flex-wrap: wrap; gap: .35rem; margin: 0 0 1.1rem; }
.chip { padding: .15rem .55rem; border: 1px solid var(--border-strong);
        border-radius: 999px; font: 500 var(--fs-2)/1.45 var(--sans); color: var(--fg-muted); }
.chip.yes { border-color: var(--border-strong); color: var(--fg); background: var(--bg-panel); }
.chip.no { text-decoration: line-through; opacity: .55; }

/* The implementation table: header, shader, kernel, gradient, tests. This is
   what makes the reference usable by someone reading the source, not just
   calling it. */
.impl { width: 100%; border-collapse: collapse; margin: .3rem 0 1.3rem; font-size: var(--fs-4); }
.impl th { width: 11rem; padding: .4rem .7rem .4rem 0; text-align: left; vertical-align: top;
           color: var(--fg-muted); font-weight: 500; border-bottom: 1px solid var(--border); }
.impl td { padding: .4rem 0; border-bottom: 1px solid var(--border); }
.impl td code { font-size: var(--fs-3); }
.impl .none { color: var(--fg-muted); font-style: italic; }

table { width: 100%; border-collapse: collapse; margin: 0 0 1.25rem; font-size: var(--fs-4); }
th, td { padding: .5rem .7rem; text-align: left; border-bottom: 1px solid var(--border); }
thead th { color: var(--fg-strong); font-weight: var(--fw-semibold); background: var(--bg-panel);
           border-bottom: 2px solid var(--accent); }
tbody tr:hover { background: var(--bg-panel); }
.table-scroll { overflow-x: auto; }

/* -------------------------------------------------------- page navigation -- */

.pagenav { display: flex; justify-content: space-between; gap: 1rem;
           margin-top: 3rem; padding-top: 1.25rem; border-top: 1px solid var(--border); }
.pagenav a { display: block; max-width: 48%; color: var(--fg-muted); text-decoration: none; }
.pagenav a:hover { text-decoration: none; }
.pagenav .dir { display: block; font-size: var(--fs-3); }
.pagenav .ttl { display: block; color: var(--accent-fg); font-weight: 600; font-size: var(--fs-5); }
.pagenav a:hover .ttl { text-decoration: underline; }
.pagenav .next { text-align: right; margin-left: auto; }

/* --------------------------------------------------------------- landing -- */


.cards { display: grid; gap: .9rem; grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr)); }
.card { display: block; padding: 1rem 1.1rem; background: var(--bg-panel);
        border: 1px solid var(--border); border-radius: var(--radius);
        color: inherit; text-decoration: none; }
.card:hover { border-color: var(--accent); text-decoration: none; }
.card h3 { margin: 0 0 .3rem; font-size: var(--fs-5); }
.card p { margin: 0; color: var(--fg-muted); font-size: var(--fs-4); }

.btn { display: inline-block; padding: .5rem 1.1rem; border: 1px solid var(--accent);
       border-radius: var(--radius); color: var(--accent-fg); font-weight: var(--fw-medium);
       text-decoration: none; }
.btn:hover { background: var(--accent); color: var(--on-accent); text-decoration: none; }
.btn.solid { background: var(--accent); color: var(--on-accent); }
.btn.solid:hover { background: var(--red-hot); border-color: var(--red-hot); }

footer.page { max-width: none; margin-top: 2.5rem; padding-top: 1.1rem;
              border-top: 1px solid var(--border); color: var(--fg-muted); font-size: var(--fs-3); }

#totop { position: fixed; left: 50%; bottom: 1.25rem;
         transform: translateX(-50%) translateY(1rem); z-index: 50;
         padding: .45rem 1.05rem; background: var(--accent); border: 0; border-radius: 999px;
         color: var(--on-accent); font: var(--fw-medium) var(--fs-4) var(--sans); cursor: pointer;
         box-shadow: 0 .3rem 1rem var(--shadow); opacity: 0; pointer-events: none;
         transition: opacity .18s, transform .18s; }
#totop.show { opacity: 1; transform: translateX(-50%); pointer-events: auto; }
#totop:hover { background: var(--red-hot); }

/* ------------------------------------------------------------- responsive */

/* The contents rail. This was hidden below 88rem (1408px), which is every
   common laptop -- 1280, 1366 and 1440 all lost it, on exactly the pages that
   need it most: an API category page carries ten independent operator entries
   and an architecture page runs to a dozen sections.

   Measured at 1280 across twelve reference sites, seven keep a right-hand rail
   (tailwind 288, astro 280, shadcn 288, jax 272, huggingface 270, nextjs 224,
   kubernetes 209) and five do not (rust-book, react, stripe, pytorch, godot).
   The five that drop it are single-narrative reading pages; none of them drops
   it as late as 1408px. 76rem is 1216px, so 1280 and up keep the rail, and the
   budget above leaves the prose at its full measure. */
@media (max-width: 76rem) { .toc { display: none; } }
@media (max-width: 64rem) {
    #nav-toggle { display: grid; }
    .sidenav { position: fixed; left: 0; top: var(--topbar-h); z-index: 45;
               transform: translateX(-100%); transition: transform .18s ease;
               box-shadow: 0 0 2rem var(--shadow); }
    .sidenav.open { transform: none; }
    .content { padding: 1.25rem 1.15rem 4rem; }
    .topbar nav { display: none; }
    .search { width: auto; flex: 1 1 auto; }
}
@media (prefers-reduced-motion: reduce) {
    html { scroll-behavior: auto; }
    * { transition-duration: .01ms !important; }
}

/* --------------------------------------------------------------- landing -- */

/* The landing page is not a documentation page. It drops the section tree, the
   contents rail and the measure clamp, and centres on the viewport instead of
   on whatever is left after a sidebar -- which is what made the hero sit
   visibly off-centre and squeezed the lede into a three-line block ending in a
   one-word widow. */

.landing .content { max-width: none; padding: 0 0 var(--s-6); }
/* Written as `.content > .lsec` rather than `.lsec`, because the reset above
   is `.landing .content > *` and would otherwise win on specificity -- which it
   did: every section rendered at the full 1280 with no container, and the card
   grid spread to four across. */
.landing .content > * { max-width: none; }
.landing .content > .lsec,
.landing .content > .lhero { max-width: 60rem; margin-left: auto; margin-right: auto; }
.landing footer.page { max-width: 60rem; margin-left: auto; margin-right: auto;
                       padding-left: var(--s-4); padding-right: var(--s-4); }

/* Every landing section shares one container, so the left edges line up down
   the page. Wider than the prose measure because these are display blocks, not
   long-form reading. */
.lsec { max-width: 60rem; margin: 0 auto; padding: var(--s-6) var(--s-4); }
.lsec + .lsec { padding-top: 0; }
.lsec > h2 { margin-top: 0; font-size: var(--fs-7); }
.lsec > h2 + p { color: var(--fg-muted); max-width: 40rem; }

/* Hero. The lede is clamped well inside the container so it breaks into two
   balanced lines rather than three with a widow. */
.lhero { text-align: center; padding: var(--s-6) var(--s-4) var(--s-5); }
.lhero img { height: 7.5rem; width: auto; }
.lhero h1 { margin: var(--s-4) 0 var(--s-3); font-size: clamp(2rem, 5vw, 3rem);
            letter-spacing: -.03em; line-height: 1.1; }
.lhero .lede { max-width: 40rem; margin: 0 auto var(--s-5);
               font-size: var(--fs-6); color: var(--fg-muted); text-wrap: balance; }
.lhero .cta { display: flex; gap: var(--s-3); justify-content: center; flex-wrap: wrap; }

/* A run of short facts under the hero. Each is checkable -- they are counted
   from the tree at build time, not typed here. */
.lstats { display: flex; flex-wrap: wrap; justify-content: center; gap: var(--s-5);
          margin: var(--s-5) auto 0; padding: var(--s-4) var(--s-4) 0;
          border-top: 1px solid var(--border); max-width: 44rem; }
.lstat { text-align: center; }
.lstat b { display: block; font: 700 var(--fs-7)/1.2 var(--sans); color: var(--fg-strong); }
.lstat span { font-size: var(--fs-3); color: var(--fg-muted); }

/* Two columns where the point is a comparison or a code sample beside prose.
   Collapses to one on anything narrow. */
.lsplit { display: grid; gap: var(--s-5); grid-template-columns: 1fr 1fr;
          align-items: start; }
.lsplit pre { margin: 0; }
@media (max-width: 56rem) { .lsplit { grid-template-columns: 1fr; } }

/* The landing card grid: an even 2x2 rather than three across with a fourth
   orphaned onto a second row. */
.landing .cards { grid-template-columns: repeat(auto-fit, minmax(17rem, 1fr)); }
.card:hover { border-color: var(--border-strong); background: var(--bg-code); }
.card h3 { margin: 0 0 var(--s-2); font-size: var(--fs-5); }
.card p { margin: 0; font-size: var(--fs-4); color: var(--fg-muted); }

@media (max-width: 48rem) {
    .lhero img { height: 5.5rem; }
    .lsec { padding: var(--s-5) var(--s-4); }
}

/* ------------------------------------------------------- search on a phone -- */

/* At 390px the topbar carried seven controls -- hamburger, logo, wordmark,
   version chip, search field, theme toggle and a GitHub link -- and the search
   field is what gave way: it collapsed to about 130px, showing the placeholder
   truncated to "S" and still rendering the "/" hint for a key the device has no
   way to press.
 
   Search is the fastest route through a 55-page reference, so below the tablet
   breakpoint it becomes a trigger and a full-width sheet, which is what React,
   Rust, Tailwind, Astro, Next.js and Stripe all do. The reason is the same
   everywhere: a text input squeezed into a crowded header cannot show enough of
   the query or enough of the results to be worth using, and a sheet gives the
   query the whole screen. */

#search-open, .search-close { display: none; }

/* The "/" hint is a promise the device cannot keep without a keyboard. */
@media (pointer: coarse) { .search kbd { display: none; } }

@media (max-width: 48rem) {
    /* Four controls, not seven. The version is on every page's footer and the
       repository is linked from the landing page and the contents rail. */
    .ver, .topbar > a.icon-btn[href] { display: none; }
    #search-open { display: grid; }

    .search {
        position: fixed; inset: 0; z-index: 80;
        display: none; width: auto;
        padding: var(--s-4);
        background: var(--bg);
    }
    .search.open { display: block; }
    .search input {
        width: 100%; height: 2.75rem;          /* >= 44px, a comfortable target */
        padding-left: 2.4rem; font-size: var(--fs-5);
    }
    .search .mag { left: .85rem; top: 2.05rem; transform: none; }
    .search-close {
        display: grid; position: absolute;
        right: var(--s-4); top: calc(var(--s-4) + .35rem);
        width: 2.05rem; height: 2.05rem;
    }
    .search input { padding-right: 2.9rem; }

    /* The sheet owns the screen, so results are a list rather than a dropdown. */
    .results {
        position: static; margin-top: var(--s-4);
        max-height: calc(100vh - 5rem); border: 0; box-shadow: none;
        background: none;
    }
    .results a { padding: .7rem .2rem; }
    .results .r-name { font-size: var(--fs-5); }
}

/* The browser draws its own clear button inside `input[type=search]`, which sat
   beside the sheet's close button on a phone: two crosses, different sizes,
   different colours, one of them the platform's. */
.search input::-webkit-search-cancel-button,
.search input::-webkit-search-decoration { -webkit-appearance: none; appearance: none; }

/* Which surface a class documents, and how many operators a category holds --
   both answer a question the reader would otherwise have to open the page to
   ask. Quiet, because they are labels on the choice, not the choice. */
.sidenav .nav-note { font-size: var(--fs-1); color: var(--fg-muted);
                     text-transform: uppercase; letter-spacing: .06em;
                     margin-left: .35rem; }
.sidenav .nav-count { float: right; font-size: var(--fs-1); color: var(--fg-muted);
                      opacity: .7; font-variant-numeric: tabular-nums; }

/* --------------------------------------------------- capability reasons -- */

/* A limit that says WHY is a different signal from one that just says no. The
   badge carries the category, so a reader can tell "we decided not to" from
   "we have not got to it yet" without reading the paragraph -- those say very
   different things about a project. Neutral by default; only the two that mean
   "this will not change" carry a hue. */
.rz { display: inline-block; padding: .1rem .5rem; border-radius: 999px;
      border: 1px solid var(--border-strong); background: var(--bg-panel);
      color: var(--fg-muted); font: var(--fw-medium) var(--fs-1) var(--sans);
      white-space: nowrap; vertical-align: middle; }
.rz-by-design { border-color: var(--note-edge); color: var(--note-fg); }
.rz-guarantee { border-color: var(--tip-edge); color: var(--tip-fg); }

dl.legend { display: grid; grid-template-columns: auto 1fr; gap: var(--s-2) var(--s-4);
            align-items: baseline; margin: 0 0 var(--s-6); }
dl.legend dt { margin: 0; }
dl.legend dd { margin: 0; color: var(--fg-muted); font-size: var(--fs-4); }

.limit { padding: var(--s-4) 0; border-top: 1px solid var(--border); }
.limit h3 { margin-top: 0; display: flex; align-items: center; gap: var(--s-3);
            flex-wrap: wrap; }
.limit .src { margin: 0; font-size: var(--fs-3); }

/* ------------------------------------------------------------- diagrams -- */

/* Inlined SVG, so it inherits the theme's variables and is correct in both
   without a second file. Everything is drawn with tokens rather than literal
   colours -- a diagram with baked-in greys is the one element that stays dark
   when the page goes light. */
.dia { display: block; width: 100%; height: auto; margin: var(--s-5) 0;
       max-width: 40rem; }
.dia-box { fill: var(--bg-panel); stroke: var(--border-strong); }
/* A declared layer with no files in it. Drawn as absent rather than omitted:
   `plan` is in the enforced layer order and has nothing in it yet, and hiding
   that would make the diagram tidier than the tree. */
.dia-box-empty { fill: none; stroke-dasharray: 3 3; }
.dia-edge { fill: none; stroke: var(--accent); opacity: .38; }
.dia-name { fill: var(--fg-strong); font: var(--fw-medium) var(--fs-3) var(--mono); }
.dia-lv   { fill: var(--fg-muted); font: var(--fw-medium) var(--fs-2) var(--mono); }
.dia-meta { fill: var(--fg-muted); font: var(--fs-2) var(--mono); }
.dia-cap  { fill: var(--fg-muted); font: var(--fs-1) var(--sans);
            text-transform: uppercase; letter-spacing: .08em; }

/* A caption belongs to the diagram above it, so it sits tight to it. */
.dia + .dia-note { margin-top: calc(var(--s-4) * -1); color: var(--fg-muted);
                   font-size: var(--fs-3); }

@media (prefers-reduced-motion: no-preference) {
    .dia-edge { transition: opacity .2s; }
}
.dia:hover .dia-edge { opacity: .55; }
