/*
 * Documentation portal styling for the CoolMS product site.
 *
 * Ported from `docs/overview/coolms-portal.html`. Every rule below the theme
 * block is the designer's, unchanged.
 *
 * ⚠️ This sheet OWNS the docs pages and is not loaded anywhere else. It sets
 * its own `body`, `.btn`, `.wrap` and `.tag`, all of which the theme's
 * `partials/styles.html.dtmpl` also defines in a different palette. The docs
 * templates fill the base layout's `styles` slot with THIS sheet instead of the
 * theme's, so which one wins is a decision rather than a source-order accident
 * -- the same arrangement the landing page uses.
 */

/* Tokens carried over unchanged from the Cool!MS landing page. */
  :root{
    /* Highlight palette. The server emits `.hljs-…` spans for every fenced
       block; without these every one of them computed to --ink, i.e. the same
       colour as the surrounding prose, and the highlighting was invisible. */
    --hl-keyword:#A2410B; --hl-string:#1E6F46; --hl-variable:#2C4A7C;
    --hl-number:#B0670A; --hl-built_in:#0F6E7A; --hl-literal:#A2410B;
    --hl-meta:#55637A; --hl-symbol:#8795A9; --hl-comment:#6B7A8F;
    /* Error ink, for the server-emitted failure states below. The design had
       no such token -- `.code .bad` is a class, not a colour. */
    --bad:#B42318; --bad-soft:rgba(180,35,24,.08);
  }
  @media (prefers-color-scheme:dark){
    :root:not([data-theme="light"]){
      --hl-keyword:#FFB840; --hl-string:#7FD8A6; --hl-variable:#8FB6E8;
      --hl-number:#F5A623; --hl-built_in:#5FC9D6; --hl-literal:#FFB840;
      --hl-meta:#93A0B4; --hl-symbol:#7C8AA0; --hl-comment:#7F8FA6;
      --bad:#F97066; --bad-soft:rgba(249,112,102,.12);
    }
  }
  *{box-sizing:border-box}
  html{-webkit-text-size-adjust:100%; scroll-behavior:smooth}
  [id]{scroll-margin-top:150px}
  @media (prefers-reduced-motion:reduce){ html{scroll-behavior:auto} }
  body{
    margin:0; background:var(--bg); color:var(--ink);
    font-family:var(--sans); font-size:16px; line-height:1.65;
    -webkit-font-smoothing:antialiased;
  }
  a{color:inherit; text-decoration:none}
  ::selection{background:var(--accent-soft)}
  :focus-visible{outline:2px solid var(--accent); outline-offset:3px; border-radius:3px}
  .wrap{max-width:var(--wrap); margin:0 auto; padding:0 28px}
  .eyebrow{
    font-family:var(--mono); font-size:.72rem; letter-spacing:.16em;
    text-transform:uppercase; color:var(--accent); margin:0 0 14px; font-weight:600;
  }

  /* ---------- header ---------- */
  .site-header{
    position:sticky; top:0; z-index:50;
    background:color-mix(in srgb, var(--bg) 88%, transparent);
    backdrop-filter:saturate(1.4) blur(10px);
    border-bottom:1px solid var(--hair);
  }
  .nav{display:flex; align-items:center; gap:26px; height:64px}
  .wordmark{font-weight:800; font-size:1.24rem; letter-spacing:-.03em}
  .wordmark .bang{color:var(--accent)}
  .tabs{display:flex; gap:4px; margin-left:14px}
  .tabs a{
    font-family:var(--mono); font-size:.82rem; color:var(--muted);
    padding:7px 13px; border-radius:8px; border:1px solid transparent; transition:.18s;
  }
  .tabs a:hover{color:var(--ink); background:var(--panel-2)}
  .tabs a[aria-current="page"]{color:var(--ink); background:var(--panel); border-color:var(--hair); font-weight:600}
  /* ⚠️ NO `margin-left:auto`. The shared header partial already pushes the menu
     right with `.nav-desktop{margin-left:auto}`, which reaches every page via
     blocks.css -- and `landing.css` says the same thing on `.nav-links`, exactly
     as the design does. Two DIFFERENT flex children with an auto margin split
     the free space between them instead of one taking it all, so the docs menu
     sat mid-bar while the landing menu sat right, from the same markup.
     Measured: nav-links margin-left 26.275px here against 47.375px there. */
  .nav-right{display:flex; align-items:center; gap:12px}
  .ver{
    font-family:var(--mono); font-size:.74rem; color:var(--muted);
    border:1px solid var(--hair); border-radius:7px; padding:6px 10px; background:var(--panel);
  }
  .btn{
    display:inline-flex; align-items:center; gap:8px; font-family:var(--mono);
    font-size:.8rem; font-weight:600; padding:9px 15px; border-radius:9px;
    cursor:pointer; border:1px solid transparent; transition:.18s;
  }
  /* ⚠️ THE BOOTSTRAP VARIABLES, NOT JUST `background`. `.btn-primary` is
     BOOTSTRAP's class, and Bootstrap 5.3 drives every state through custom
     properties: `.btn:active` reads `--bs-btn-active-bg`, the focus ring reads
     `--bs-btn-focus-shadow-rgb`. Overriding only `background` and `:hover`
     leaves those pointing at Bootstrap's own palette, so the button was amber
     at rest and #0a58ca the moment it was pressed. Measured on the live button:
     `--bs-btn-active-bg: #0a58ca`, `--bs-btn-bg: #0d6efd`,
     `--bs-btn-focus-shadow-rgb: 49,132,253`.

     Setting the variables fixes every state at once -- hover, active, focus and
     disabled -- instead of chasing them one selector at a time, which is also
     why the `:hover` rule below can stay a one-liner rather than growing a
     `:active` twin. `.btn-ghost` needs none of this: it is the design's own
     class, not a Bootstrap variant, so it carries no `--bs-btn-*` at all.

     ⚠️ The focus ring is an rgb TRIPLE because that is the shape Bootstrap
     wants, so it cannot be `var(--brand)`. It must track `--brand` by hand. */
  .btn-primary{
    --bs-btn-bg:var(--brand); --bs-btn-color:var(--navy); --bs-btn-border-color:transparent;
    --bs-btn-hover-bg:var(--brand-deep); --bs-btn-hover-color:var(--navy);
    --bs-btn-hover-border-color:transparent;
    --bs-btn-active-bg:var(--brand-deep); --bs-btn-active-color:var(--navy);
    --bs-btn-active-border-color:transparent;
    --bs-btn-disabled-bg:var(--brand); --bs-btn-disabled-color:var(--navy);
    --bs-btn-disabled-border-color:transparent;
    /* #F5A623 -- keep in step with `--brand`. */
    --bs-btn-focus-shadow-rgb:245,166,35;
    background:var(--brand); color:var(--navy);
  }
  .btn-primary:hover{background:var(--brand-deep)}
  .btn-ghost{background:transparent; color:var(--ink); border-color:var(--hair)}
  .btn-ghost:hover{border-color:var(--accent); color:var(--accent)}
  .alpha-strip{
    background:var(--navy); color:#EEF2F8; font-family:var(--mono);
    font-size:.72rem; letter-spacing:.04em;
  }
  .alpha-strip .wrap{display:flex; gap:14px; align-items:center; padding-block:8px; flex-wrap:wrap}
  .alpha-strip b{color:var(--brand); font-weight:600}
  .alpha-strip .sp{margin-left:auto; color:#95A3B8}

  /* ---------- docs layout ---------- */
  /* ⚠️ `padding-block`, NOT the `padding` shorthand. This element also carries
     `.wrap`, whose `padding:0 28px` is the site's gutter -- and a shorthand
     here sets the inline axis to 0 at equal specificity, later in the file, so
     it wins. The documentation then ran edge to edge while the header above it
     kept its 28px: measured content at x=52 against the nav's x=80, and at any
     width below the 1180 max-width the text reached the viewport edge and
     clipped.
     `landing.css`'s `.hero-grid` carries this same warning; this rule is the
     case it was warning about. */
  /* -- The bottom air is on `main`, not here. Three docs templates have three
     different content containers (`.docs`, `.docs-home`, the index), and the
     one that had no bottom padding put its last card against the footer with a
     1px gap. `main` is the element all three share. */
  main{padding-bottom:80px}
  /* The rails give up a little so the article gains more than the container
     did: 1320 - 56 padding - 240 - 200 - 64 gaps = 760, against 560 before. */
  /* -- 10px, not 34. The submenu strip above already carries 14px of its own
     below the tab, so 34 here made the gap under the tab 48px against the 14px
     above it -- the tab sat tight to the header and floated over the content.
     10 brings the total to 24, which is the row rhythm the landing blocks use,
     and close enough to the 14 above to read as one band. */
  .docs{display:grid; grid-template-columns:240px minmax(0,1fr) 200px; gap:32px; padding-block:10px 0}
  /* ⚠️ NO GUTTER AND NO RIGHT PADDING -- the three columns are separated by the
     grid's `gap` and by nothing else, so the space either side of the article
     is the same number.

     This carried `padding-right:6px`, then `scrollbar-gutter:stable`, both
     reserving room for a scrollbar in a rail that does not scroll: measured,
     the longest section is 273px of entries against a 453px cap. Each one came
     out of the rail's CONTENT box while the grid track stayed 240px, so the
     visible gap on that side was the gap PLUS the reserve -- 45px against the
     grid's 30 with `stable`, which is bigger than the 6px it replaced.

     If a section ever does outgrow the viewport the scrollbar takes those
     pixels from the links for as long as it is there, which is the right time
     to pay for it rather than on every page that never scrolls. */
  .rail{position:sticky; top:104px; align-self:start; max-height:calc(100vh - 130px); overflow:auto}
  .search{position:relative; margin-bottom:18px}
  .search input{
    width:100%; font:inherit; font-family:var(--mono); font-size:.82rem;
    padding:9px 12px 9px 32px; border-radius:9px; border:1px solid var(--hair);
    background:var(--panel); color:var(--ink);
  }
  .search input:focus{outline:none; border-color:var(--brand); box-shadow:0 0 0 3px var(--accent-soft)}
  .search svg{position:absolute; left:10px; top:50%; transform:translateY(-50%); stroke:var(--faint)}
  .tree{font-family:var(--mono); font-size:.82rem}
  .tree section{margin-bottom:16px}
  .tree h4{
    margin:0 0 6px; font-size:.7rem; letter-spacing:.14em; text-transform:uppercase;
    color:var(--faint); font-weight:600;
  }
  .tree a{
    display:flex; gap:8px; padding:4px 8px; border-radius:6px; color:var(--muted);
    border-left:2px solid transparent; margin-left:-2px;
  }
  .tree a:hover{color:var(--ink); background:var(--panel-2)}
  .tree a[aria-current="true"]{color:var(--accent); border-left-color:var(--brand); background:var(--accent-soft); font-weight:600}
  .tree a .dim{color:var(--faint)}
  .tree .soon{opacity:.5; pointer-events:none}

  article{min-width:0}
  .doc-path{
    /* ⚠️ `nowrap`, and the PATH is the part that gives way. With `wrap`, a long
       path pushed `.tag` -- which `margin-left:auto` holds right -- onto a
       second line on its own, so the panel doubled in height with an empty
       gutter beside it. The mode, the owner and the tag are all fixed-length;
       the path is the only variable one, so it is the only one that should
       shrink. It truncates with an ellipsis and keeps its full text in
       `title`. */
    display:flex; align-items:center; gap:12px; flex-wrap:nowrap;
    font-family:var(--mono); font-size:.74rem; color:var(--faint);
    border:1px solid var(--hair); border-radius:9px; padding:10px 12px;
    /* 10px, not 8: this panel and the rail's search input start on the
       same line, and at 8px they stood 37px against the input's 41px. */
    background:var(--panel); margin-bottom:24px;
  }
  .doc-path > .m, .doc-path > .n, .doc-path > .tag{flex:none}
  /* The unclassed span is the path itself -- see pages/docs_page.html.dtmpl. */
  .doc-path > span:not([class]){
    min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
  }
  .doc-path .m{color:var(--accent)}
  .doc-path .n{color:var(--muted)}
  .doc-path .tag{margin-left:auto; color:var(--good)}
  article h1{font-size:clamp(1.9rem,3.4vw,2.6rem); line-height:1.1; font-weight:800;
    letter-spacing:-.025em; margin:0 0 12px; text-wrap:balance}
  article .sub{color:var(--muted); font-size:1.08rem; margin:0 0 32px; max-width:44em}
  article h2{font-size:1.35rem; font-weight:760; letter-spacing:-.015em; margin:38px 0 12px;
    padding-top:14px; border-top:1px solid var(--hair)}
  article h3{font-size:1.04rem; font-weight:700; margin:26px 0 8px}
  article p{color:var(--muted); margin:0 0 14px; max-width:46em}
  article p b, article li b{color:var(--ink); font-weight:650}
  article ul{color:var(--muted); margin:0 0 14px; padding-left:20px; max-width:46em}
  article li{margin-bottom:7px}
  /* Bootstrap paints an alert's ink on the CONTAINER, as `--bs-alert-color`, and
     lets it INHERIT down to the text. The `article p` / `article ul` rules above
     match those descendants THEMSELVES, and a matching rule always beats an
     inherited value however low its specificity -- so an alert kept Bootstrap's
     tint and lost Bootstrap's ink. In dark that is `--muted` on a fixed light
     tint: 2.39 on the warning, 2.27 on the info, 2.02 on the primary, across 52
     elements. Hand the container's own colour back rather than invent one --
     Bootstrap's own pairs measure 7.21, 7.65 and 10.28. `strong` and `a` are not
     listed because they carry no colour of their own here and follow the `p`
     they sit in; `code` is left alone because it brings its own themed
     background and reads 13.31 inside an alert. */
  article .alert p,
  article .alert ul,
  article .alert li,
  article .alert b{color:inherit}
  /* The docs' boxes are now the page editor's callouts (2026-09-25): the markdown
     converter writes `div.callout.callout-{note,tip,warning}` instead of a
     Bootstrap alert, so a docs page opened and saved in the admin keeps its box.
     Painted with the values of the SAME Bootstrap 5.3 pairs the alerts used --
     info, success, warning -- as this sheet's own tokens: a `--bs-*` reference
     here names a token nothing in this theme defines (check-cms-tokens), and on
     this site Bootstrap's tints stay light in dark mode anyway. The ink is
     handed down to the text for the reason given above. The title line is the
     platform's CalloutTitleProcessor. */
  article .callout{margin:0 0 14px; padding:14px 16px; max-width:46em; border:1px solid var(--callout-border);
    border-radius:6px; color:var(--callout-ink); background:var(--callout-bg)}
  article .callout-note{--callout-ink:#055160; --callout-bg:#cff4fc;
    --callout-border:#9eeaf9}
  article .callout-tip{--callout-ink:#0a3622; --callout-bg:#d1e7dd;
    --callout-border:#a3cfbb}
  article .callout-warning{--callout-ink:#664d03; --callout-bg:#fff3cd;
    --callout-border:#ffe69c}
  article .callout p,
  article .callout ul,
  article .callout li,
  article .callout b{color:inherit}
  article .callout > :last-child{margin-bottom:0}
  article .callout__title{display:flex; align-items:center; gap:6px; margin-bottom:8px; font-weight:650; line-height:1.2}
  article .callout__icon{flex:0 0 auto; width:1.1em; height:1.1em}
  article code{font-family:var(--mono); font-size:.87em; color:var(--ink);
    background:var(--panel-2); border:1px solid var(--hair); padding:1px 6px; border-radius:5px}
  /* A fenced block. The `article code` chip above is for INLINE code; inside a
     `<pre>` it was painting a separate rounded pill per wrapped line, because an
     inline box gets its background once per line box. So the block owns the
     frame and the `code` inside it is reset to carry none. */
  article pre{margin:0 0 20px; padding:14px 16px; overflow-x:auto;
    background:var(--panel-2); border:1px solid var(--hair); border-radius:11px}
  article pre code{display:block; background:none; border:0; padding:0; border-radius:0;
    font-size:.79rem; line-height:1.8; white-space:pre}
  /* Server-side highlight scopes. Every one of these must have a value: an
     unstyled scope inherits --ink and is indistinguishable from prose, which is
     the state this replaced. */
  article pre .hljs-keyword{color:var(--hl-keyword); font-weight:600}
  article pre .hljs-string{color:var(--hl-string)}
  article pre .hljs-variable{color:var(--hl-variable)}
  article pre .hljs-number{color:var(--hl-number)}
  article pre .hljs-built_in{color:var(--hl-built_in)}
  article pre .hljs-literal{color:var(--hl-literal)}
  article pre .hljs-meta{color:var(--hl-meta)}
  article pre .hljs-symbol,article pre .hljs-operator,article pre .hljs-punctuation{color:var(--hl-symbol)}
  article pre .hljs-title,article pre .hljs-name,article pre .hljs-attr{color:var(--hl-built_in)}
  article pre .hljs-comment,article pre .hljs-quote{color:var(--hl-comment); font-style:italic}
  /* Server-emitted widget states. Both were styled by nothing, so a broken link
     and a failed widget rendered as ordinary body text -- the class was in the
     markup all along, which is exactly why nobody noticed. */
  .broken-link{color:var(--bad); text-decoration:underline wavy; text-underline-offset:.2em; cursor:help}
  .cms-document-widget--error{display:block; padding:12px 14px; border-left:3px solid var(--bad);
    background:var(--bad-soft); color:var(--bad); font-size:.94rem; border-radius:0 8px 8px 0}
  .code{border:1px solid var(--hair); border-radius:11px; overflow:hidden; background:var(--panel); margin:0 0 20px}
  .code-bar{display:flex; align-items:center; gap:10px; padding:8px 13px; border-bottom:1px solid var(--hair);
    background:var(--panel-2); font-family:var(--mono); font-size:.72rem; color:var(--muted)}
  .code-bar .tag{margin-left:auto; color:var(--faint)}
  .code pre{margin:0; padding:14px 16px; overflow-x:auto; font-family:var(--mono);
    font-size:.79rem; line-height:1.8; color:var(--muted); white-space:pre}
  .code .cmd{color:var(--ink); font-weight:600}
  .code .ok{color:var(--good)}
  .code .bad{color:var(--accent-strong); font-weight:600}
  .code .idf{color:var(--accent)}
  .code .dim{color:var(--faint)}
  .note{
    border:1px solid var(--hair); border-left:3px solid var(--brand); border-radius:0 10px 10px 0;
    padding:14px 16px; margin:0 0 20px; background:var(--panel);
  }
  .note .lbl{font-family:var(--mono); font-size:.7rem; letter-spacing:.12em; text-transform:uppercase;
    color:var(--accent); font-weight:600; display:block; margin-bottom:5px}
  .note p{margin:0; font-size:.94rem}
  table.ref{border-collapse:collapse; width:100%; font-size:.88rem; margin:0 0 20px}
  table.ref th,table.ref td{padding:8px 12px; text-align:left; border-bottom:1px solid var(--hair)}
  table.ref th{font-family:var(--mono); font-size:.68rem; text-transform:uppercase; letter-spacing:.13em;
    color:var(--faint); font-weight:600}
  table.ref td{color:var(--muted)}
  table.ref td:first-child{font-family:var(--mono); font-size:.82rem; color:var(--ink)}
  /* A table the content wrote WITHOUT `.ref` still has to stay inside the
     column. `table-layout:auto` sizes to the longest unbreakable token, and a
     documentation table is full of them: measured 2026-09-15, the `--type`
     row's `(text|textarea|richtext|localizedText|...)` value list made a
     1036px table inside a 609px column and put its right edge 427px into the
     on-this-page rail. `article{min-width:0}` above keeps the GRID honest; it
     cannot help a table that reports a wider minimum content width.
     So: cap the table at the column, and let a long run of pipe-separated
     values break rather than push. `width:1%` on the first cell is
     shrink-to-fit -- it gives the option name exactly its own width, which is
     also what stops `--entity-alias` being broken across three lines. */
  article table{width:100%; max-width:100%; border-collapse:collapse; font-size:.88rem; margin:0 0 20px}
  /* break-word, not anywhere: `anywhere` drops a cell's min-content width to a
     single character, and the `td:first-child{width:1%}` below then collapses
     any first column that is not one short token into a vertical stack of
     characters (measured 2026-09-16 on Settings and Anatomy of a module).
     `break-word` still wraps a long unbreakable token to stop it overflowing
     the rail -- the reason `anywhere` was here -- without shrinking min-content. */
  article table th,article table td{padding:8px 12px; text-align:left;
    border-bottom:1px solid var(--hair); overflow-wrap:break-word}
  article table th{font-family:var(--mono); font-size:.68rem; text-transform:uppercase;
    letter-spacing:.13em; color:var(--faint); font-weight:600}
  article table td{color:var(--muted)}
  article table td:first-child{width:1%; font-family:var(--mono); font-size:.82rem; color:var(--ink)}
  .pager{display:flex; gap:14px; margin-top:44px; padding-top:22px; border-top:1px solid var(--hair)}
  .pager a{
    flex:1; border:1px solid var(--hair); border-radius:11px; padding:14px 16px; background:var(--panel);
    transition:border-color .18s;
  }
  .pager a:hover{border-color:var(--brand)}
  .pager span{display:block; font-family:var(--mono); font-size:.7rem; color:var(--faint);
    letter-spacing:.1em; text-transform:uppercase; margin-bottom:4px}
  .pager b{font-weight:650; font-size:.96rem}
  .pager .next{text-align:right}

  .toc{position:sticky; top:104px; align-self:start; font-family:var(--mono); font-size:.78rem}
  .toc h4{margin:0 0 10px; font-size:.68rem; letter-spacing:.14em; text-transform:uppercase;
    color:var(--faint); font-weight:600}
  .toc a{display:block; padding:4px 0 4px 11px; color:var(--muted); border-left:1px solid var(--hair)}
  .toc a:hover{color:var(--ink)}
  .toc a.on{color:var(--accent); border-left-color:var(--brand); font-weight:600}

  /* ---------- marketplace ---------- */
  .mk-head{padding:44px 0 26px}
  .mk-head h1{font-size:clamp(1.9rem,3.4vw,2.7rem); font-weight:800; letter-spacing:-.025em; margin:0 0 12px}
  .mk-head p{color:var(--muted); font-size:1.06rem; margin:0; max-width:48em}
  .mk-controls{display:flex; gap:10px; flex-wrap:wrap; align-items:center; padding-bottom:26px}
  .mk-controls .search{margin:0; flex:1; min-width:220px; max-width:340px}
  .chip{
    font-family:var(--mono); font-size:.76rem; color:var(--muted); cursor:pointer;
    border:1px solid var(--hair); border-radius:8px; padding:7px 12px; background:var(--panel);
    transition:.18s;
  }
  .chip:hover{color:var(--ink); border-color:var(--wire)}
  .chip[aria-pressed="true"]{background:var(--brand); border-color:var(--brand); color:var(--navy); font-weight:600}
  .mods{display:grid; grid-template-columns:repeat(auto-fill,minmax(310px,1fr)); gap:14px; padding-bottom:26px}
  .mod{
    background:var(--panel); border:1px solid var(--hair); border-radius:12px; padding:18px;
    display:flex; flex-direction:column; gap:10px; transition:border-color .18s, transform .18s, box-shadow .18s;
  }
  .mod:hover{border-color:var(--brand); transform:translateY(-2px); box-shadow:0 16px 34px -24px rgba(22,32,46,.4)}
  .mod-top{display:flex; align-items:flex-start; gap:10px}
  .mod h3{margin:0; font-size:1.04rem; font-weight:730; letter-spacing:-.01em}
  .mod .id{font-family:var(--mono); font-size:.72rem; color:var(--faint); margin-top:2px}
  .badges{display:flex; gap:6px; flex-wrap:wrap; margin-left:auto}
  .b{font-family:var(--mono); font-size:.64rem; letter-spacing:.08em; text-transform:uppercase;
    padding:3px 7px; border-radius:5px; border:1px solid var(--hair); color:var(--muted); font-weight:600}
  .b.mit{color:var(--good); border-color:color-mix(in srgb,var(--good) 40%,transparent)}
  .b.paid{background:var(--accent-soft); color:var(--accent); border-color:transparent}
  .b.core{color:var(--muted)}
  .b.soon{color:var(--faint)}
  .mod p{margin:0; color:var(--muted); font-size:.9rem; line-height:1.55}
  .mod .req{font-family:var(--mono); font-size:.7rem; color:var(--faint); line-height:1.7}
  .mod .req b{color:var(--muted); font-weight:600}
  .mod-foot{display:flex; align-items:center; gap:10px; margin-top:auto; padding-top:12px;
    border-top:1px solid var(--hair); font-family:var(--mono); font-size:.72rem; color:var(--faint)}
  .mod-foot .install{
    margin-left:auto; color:var(--accent); font-weight:600; cursor:pointer; background:none;
    border:none; font-family:var(--mono); font-size:.72rem; padding:0;
  }
  .empty{
    border:1px dashed var(--wire); border-radius:12px; padding:34px 24px; text-align:center;
    color:var(--muted); background:var(--panel);
  }
  .empty b{display:block; color:var(--ink); font-weight:700; margin-bottom:6px; font-size:1.02rem}
  .empty p{margin:0 auto; max-width:40em; font-size:.94rem}
  .hidden{display:none !important}


  /* ---------- the shared footer, in this sheet's palette ----------
     `partials/footer.html.dtmpl` is the SITE's footer and carries no colour of
     its own -- see the note in that file. This sheet replaces
     `partials/styles.html.dtmpl`, so the dark `.cms-footer` declared there
     never loads here and the footer sits on the page background, muted, the
     way the design's own footer does.

     Measured before this existed: a transparent footer with `rgb(255,255,255)`
     brand text on a `rgb(251,252,253)` page. */
  /* ⚠️ STATES ITS OWN FONT, and that is not belt-and-braces. This markup is
     shared across every page, so it must not inherit whatever a page sheet
     happens to say about the `footer` ELEMENT -- which is exactly how it came
     to render mono on the docs pages and sans on the landing page. Children
     that want mono ask for it by name below. */
  .cms-footer{
    background:none; color:var(--muted); padding:56px 0 46px;
    font-family:var(--sans); font-size:1rem;
    border-top:1px solid var(--hair);
  }
  .cms-footer-brand{color:var(--ink); text-decoration:none}
  .cms-footer-brand .bang{color:var(--accent)}
  .cms-footer-tagline{font-family:var(--mono); font-size:.74rem; color:var(--faint); line-height:1.7}
  .cms-footer-head{font-family:var(--mono); font-size:.7rem; text-transform:uppercase;
    letter-spacing:.12em; color:var(--faint); font-weight:600; margin:0 0 14px}
  .cms-footer-links{list-style:none; padding:0; margin:0}
  .cms-footer-links a{display:block; font-size:.9rem; color:var(--muted); padding:5px 0; text-decoration:none}
  .cms-footer-links a:hover{color:var(--accent)}
  .cms-footer-rule{border:0; border-top:1px solid var(--hair); opacity:1}
  .cms-footer-legal{font-family:var(--mono); font-size:.72rem; color:var(--faint)}
  .cms-social{
    display:inline-grid; place-items:center; width:36px; height:36px; border-radius:9px;
    border:1px solid var(--hair); font-family:var(--mono); font-size:.72rem;
    color:var(--muted); text-decoration:none;
  }
  .cms-social:hover{border-color:var(--accent); color:var(--accent)}

  /* -- THE BARE `footer` RULE IS GONE, with `.foot` and `.foot .sp`. They
     styled the design's own standalone docs footer, and no template renders
     that markup: `git grep class="foot"` finds nothing, and the only footer on
     a docs page comes from `partials/footer.html.dtmpl`, which is `.cms-footer`.

     Dead rules, except for one live effect -- `font-family:var(--mono)` on a
     bare element selector reached the SHARED footer and won over inheritance,
     so the same partial rendered mono on the docs pages and sans on the landing
     page. Measured: `.cms-footer-brand` and the footer links came back
     `ui-monospace` on /en/docs/ and `ui-sans-serif` on /en/. The header never
     diverged because `.nav-links a` states its own font on both. */

  @media (max-width:1080px){
    .docs{grid-template-columns:240px minmax(0,1fr); gap:30px}
    .toc{display:none}
  }
  @media (max-width:820px){
    .docs{grid-template-columns:1fr; padding-top:22px}
    .rail{position:static; max-height:none; border-bottom:1px solid var(--hair); padding-bottom:18px}
    .nav{gap:12px; height:auto; padding-block:12px; flex-wrap:wrap}
    .tabs{margin-left:0; order:3; width:100%; flex-wrap:nowrap; overflow-x:auto; scrollbar-width:none}
    .tabs::-webkit-scrollbar{display:none}
    .tabs a{white-space:nowrap}
    .nav-right .ver{display:none}
  }

/* ---------------------------------------------------------------------------
 * Explicit light/dark, layered on top of the design's own palettes.
 *
 * The design shipped a light `:root` and one `prefers-color-scheme: dark`
 * block, which gives two states and no way to disagree with the system. Three
 * are needed: explicit light, explicit dark, and follow-the-system as the
 * default. So the media query above is guarded with
 * `:not([data-theme="light"])` -- letting an explicit light choice win inside a
 * dark system -- and the dark palette is repeated below for an explicit dark
 * choice inside a light system. Every colour still has its definition on bare
 * `:root`; these blocks only re-point tokens.
 * ------------------------------------------------------------------------- */
:root[data-theme="dark"]{
      --hl-keyword:#FFB840; --hl-string:#7FD8A6; --hl-variable:#8FB6E8;
      --hl-number:#F5A623; --hl-built_in:#5FC9D6; --hl-literal:#FFB840;
      --hl-meta:#93A0B4; --hl-symbol:#7C8AA0; --hl-comment:#7F8FA6;
      --bad:#F97066; --bad-soft:rgba(249,112,102,.12);
}

/* A tree entry hidden by the search filter. Filtering is real: it narrows the
   entries already on the page. Nothing here queries a server. */
.tree a[hidden], .tree section[hidden]{ display:none; }
.tree .no-match{
  font-family:var(--mono); font-size:.78rem; color:var(--faint); padding:6px 10px;
}


/* Heading permalinks. The markdown converter appends one to every heading; the
   design had no anchors at all, so they arrive unstyled and read as a stray "#"
   welded to the title. Revealed on hover or keyboard focus, which is the
   convention every docs site already teaches. */
.page-content h2, .page-content h3{ position:relative; }
.heading-anchor{
  opacity:0; margin-left:.4rem; color:var(--faint); text-decoration:none;
  font-weight:400; transition:opacity .12s ease;
}
.page-content h2:hover .heading-anchor,
.page-content h3:hover .heading-anchor,
.heading-anchor:focus{ opacity:1; color:var(--accent); }
.heading-anchor:focus{ outline:2px solid var(--accent-soft); outline-offset:2px; }

/* The third grid column collapses when there is nothing to put in it, rather
   than leaving 210px of dead space beside a short page. */
.toc[hidden]{ display:none; }
@media (max-width:1100px){ .toc{ display:none; } }

/* Group overview list. The design has no equivalent -- its docs view is always
   a page -- so this is the smallest thing that reads as deliberate: the same
   monospace register as the rail, one row per document, in reading order. */
.cards{ display:grid; gap:8px; margin-top:22px; }
.card{
  display:flex; align-items:baseline; gap:12px;
  padding:13px 16px; border:1px solid var(--hair); border-radius:10px;
  background:var(--panel); color:var(--ink); text-decoration:none;
}
.card:hover{ border-color:var(--wire); background:var(--panel-2); }
.card b{ font-weight:600; }
.card .idx{ font-family:var(--mono); font-size:.75rem; color:var(--faint); }
