html {
  scroll-behavior: smooth;
  /* Prevent horizontal scroll from off-viewport nav children on narrow
     screens. Use `clip` not `hidden`: `overflow-x: hidden` establishes
     a scroll container on <html> that silently breaks position:sticky
     on every descendant (including the .md-header tabs strip that we
     want pinned during scroll). `clip` clips the overflow without
     establishing a scroll container, so sticky descendants keep working
     — supported in Chrome 90+ / Safari 16+ / Firefox 81+. */
  overflow-x: clip;
}

/* ============================================================================
   locus docs — brand palette + brand rules.

   Brand (from docs/img/logo.svg):
     - Wordmark is always lowercase "locus", never capitalized.
     - Body type is sans (Inter), and so are headings, hero, tabs, the
       footer brand and the header wordmark (the original lockup).
     - Wordmark colour:  #312D2A   (warm near-black)
     - Mark accent:      #C74634   (locus red, also accent3)
     - Tagline:          uppercase, weight 500, letter-spacing 0.16em,
                         colour #78716C.
     - Wordmark display: weight 700, letter-spacing -0.04em.

   Palette: locus palette.
   ========================================================================== */

:root {
  /* locus brand greys (logo-derived) */
  --locus-ink:      #18181B;
  --locus-mute:     #52525B;
  --locus-paper:    #FAFAFC;
  --locus-surface:  #FFFFFF;   /* elevated surface (header, cards, focused inputs) */
  --locus-table-stripe: rgba(244, 239, 236, 0.45);
  --locus-code-inline: #4A434C;

  /* locus palette */
  --tl-text:        #18181B;
  --tl-bg:          #FAFAFC;
  --tl-bg-soft:     #F4F4F5;
  --tl-rule:        #E4E4E7;

  /* Legacy names, kept so the ~45 existing call sites keep working. They are
     aliases now, not values — the design-system token is the single source. */
  --tl-red:         var(--tl-accent);
  --tl-red-deep:    var(--tl-accent-hover);
  --tl-red-light:   #E2715F;

  --tl-link:        #A03828;
  --tl-rose-tint:   #F2C4BD;   /* light rose tint */
  --tl-green:       #16A34A;   /* the one true green (success accents) */

  /* locus type stack — sans for body and headings; the header title
     (wordmark) is sans too */
  --locus-sans: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI",
                Helvetica, system-ui, sans-serif;
  --locus-mono: "JetBrains Mono", ui-monospace, "SF Mono", Menlo,
                Consolas, monospace;
  /* display face — same as the sans; the Fraunces serif is no longer
     loaded. Kept so older rules referencing it keep resolving. */
  --locus-display: var(--locus-sans);

  /* pink -> deep-rose brand gradient (hero accent word, footer wordmark,
     header hairline) */
  --locus-grad: linear-gradient(135deg, #E2715F 0%, #A03828 100%);

  /* -------------------------------------------------------------------------
     Design-system tokens. Source of truth: the "Locus Agents Design System"
     Figma file, where every variable carries this exact `var(--…)` name as its
     code syntax. Change a value there and here together, or they drift.

     The rule these tokens exist to enforce: BRAND COLOUR AND STATUS COLOUR ARE
     SEPARATE. Pink means Locus or an interactive element. Green, amber, red and
     grey mean allow, hold, deny and abstain. A decision must never be pink, and
     a button must never be green — otherwise the page teaches the reader a
     colour code it then contradicts.
     ------------------------------------------------------------------------- */

  /* Brand. `--tl-brand-mark` is the logo pink; it measures 4.43:1 on the light
     canvas, which is under the 4.5:1 body-text floor, so it is for the mark and
     large display only. `--tl-accent` is the darker interactive pink (5.79:1)
     and is what links, buttons and active states use. */
  --tl-brand-mark:    #C74634;
  --tl-accent:        #C74634;
  --tl-accent-hover:  #A03828;
  --tl-accent-subtle: #FBEDEA;

  /* Surface and text, beyond the four already declared above. */
  --tl-surface:        #FFFFFF;
  --tl-surface-raised: #FFFFFF;
  /* Diagram lane bands. Light keeps the soft background; dark needs its own
     step above the figure surface, which --tl-bg-soft equals there. */
  --tl-lane-bg:        #F4F4F5;
  --tl-text-soft:      #52525B;
  --tl-text-mute:      #67676F;   /* 5.2:1 on the soft background, so lane titles and notes clear AA */
  --tl-text-inverse:   #FFFFFF;
  --tl-on-accent:      #FFFFFF;
  --tl-rule-subtle:    #F4F4F7;
  --tl-rule-strong:    #D3D3DB;
  --tl-focus:          #C74634;

  /* Status quad. Every one of these is paired with a word in the markup —
     colour is reinforcement, never the only signal, so the page still works in
     greyscale and for colour-blind readers. */
  --tl-allow-fg:      #15803D;
  --tl-allow-bg:      #ECFDF3;
  --tl-allow-border:  #6EE7A8;
  --tl-hold-fg:       #B45309;
  --tl-hold-bg:       #FFFBEB;
  --tl-hold-border:   #FCD34D;
  --tl-deny-fg:       #B91C1C;
  --tl-deny-bg:       #FEF2F2;
  --tl-deny-border:   #FCA5A5;
  --tl-abstain-fg:    #52525B;
  --tl-abstain-bg:    #F4F4F7;
  --tl-abstain-border:#D3D3DB;

  /* 4px spacing scale and radius scale. */
  --tl-space-3xs: 2px;
  --tl-space-2xs: 4px;
  --tl-space-xs:  8px;
  --tl-space-sm:  12px;
  --tl-space-md:  16px;
  --tl-space-lg:  24px;
  --tl-space-xl:  32px;
  --tl-space-2xl: 48px;
  --tl-space-3xl: 64px;

  --tl-radius-xs:   4px;
  --tl-radius-sm:   6px;
  --tl-radius-md:   10px;
  --tl-radius-lg:   14px;
  --tl-radius-xl:   20px;
  --tl-radius-pill: 999px;
}

/* ---------------------------------------------------------------------------
   Light scheme (default).
   --------------------------------------------------------------------------- */
[data-md-color-scheme="default"] {
  /* White header slab; ink text/icons on it (dev-brand look). */
  --md-primary-fg-color:        #FFFFFF;
  --md-primary-fg-color--light:  var(--tl-red-light);
  --md-primary-fg-color--dark:   var(--tl-red-deep);
  --md-primary-bg-color:        #241F2B;
  --md-primary-bg-color--light: #FFFFFFcc;

  --md-accent-fg-color:         var(--tl-link);
  --md-accent-fg-color--transparent: rgba(214, 51, 108, 0.10);
  --md-accent-bg-color:         #FFFFFF;

  --md-default-bg-color:        var(--tl-bg);
  --md-default-fg-color:        var(--tl-text);
  --md-default-fg-color--light: #4a4f4f;
  --md-default-fg-color--lighter: #7a7e7e;
  --md-default-fg-color--lightest: #c5c8c8;

  --md-typeset-color:           var(--tl-text);
  --md-typeset-a-color:          var(--tl-link);
  --md-typeset-mark-color:       rgba(247, 162, 30, 0.45);  /* sand */

  --md-footer-bg-color:         #1F2424;
  --md-footer-bg-color--dark:    #161A1A;
  --md-footer-fg-color:         #FFFFFF;
  --md-footer-fg-color--light:   #C9CCCC;

  --md-code-bg-color:           #F4EFEC;
  --md-code-fg-color:           #312D2A;
}

/* ---------------------------------------------------------------------------
   Dark scheme — keep locus red but tone the canvas.
   --------------------------------------------------------------------------- */
[data-md-color-scheme="slate"] {
  --md-hue: 200;

  /* locus warm-dark palette (the same tokens the site uses in dark mode).
     Same canvas, same red, same sage links. */
  --locus-ink:        #F4F4F5;
  --locus-mute:       #B4B4BC;
  --locus-paper:      #111318;
  --locus-surface:    #1B1E26;
  --locus-table-stripe: rgba(244, 244, 245, 0.04);
  --locus-code-inline: #D4D4D8;

  --tl-text:          #F4F4F5;
  --tl-text-soft:     #D4D4D8;
  --tl-text-mute:     #A1A1AA;
  --tl-bg:            #111318;
  --tl-bg-soft:       #1B1E26;
  --tl-surface:       #1B1E26;
  --tl-rule:          #343843;

  /* Warm rose-coral primary; lighter in dark for contrast */
  --tl-red:           var(--tl-accent);
  --tl-red-deep:      var(--tl-accent-hover);
  --tl-red-light:     #E2715F;
  /* Warm rose becomes the link colour in dark */
  --tl-link:          #E2715F;
  --tl-rose-tint:     #F2C4BD;
  --tl-green:         #16A34A;

  /* Material overrides — deep header slab, white text/icons on it. */
  --md-primary-fg-color:        #111318;
  --md-primary-fg-color--light: #E2715F;
  --md-primary-fg-color--dark:  #E2715F;
  --md-primary-bg-color:        #FFFFFF;
  --md-primary-bg-color--light: #111318cc;

  --md-accent-fg-color:         #E2715F;
  --md-accent-fg-color--transparent: rgba(244, 166, 194, 0.15);
  --md-accent-bg-color:         #1B1E26;

  --md-default-bg-color:        #111318;
  --md-default-fg-color:        #F4F4F5;
  --md-default-fg-color--light: #D4D4D8;
  --md-default-fg-color--lighter: #A1A1AA;
  --md-default-fg-color--lightest: #52525B;

  --md-typeset-color:           #F4F4F5;
  --md-typeset-a-color:         #E2715F;
  --md-typeset-mark-color:      rgba(247, 162, 30, 0.28);

  --md-footer-bg-color:         #0D0F13;
  --md-footer-bg-color--dark:   #090A0D;
  --md-footer-fg-color:         #F4F4F5;
  --md-footer-fg-color--light:  #B4B4BC;

  --md-code-bg-color:           #15181E;
  --md-code-fg-color:           #F4F4F5;

  --md-shadow-z1: 0 0 0.2rem rgba(0,0,0,.4), 0 0.2rem 0.4rem rgba(0,0,0,.3);
  --md-shadow-z2: 0 0 0.2rem rgba(0,0,0,.5), 0 0.2rem 0.8rem rgba(0,0,0,.4);

  /* Design-system tokens — dark mode. Mirrors the Figma Color collection's
     Dark mode; the status foregrounds lighten and the fills deepen so each
     pair keeps its contrast instead of inverting into mud. */
  --tl-accent:        #E2715F;
  --tl-accent-hover:  #C74634;
  --tl-accent-subtle: #4A0A26;

  --tl-surface:        #1B1E26;
  --tl-surface-raised: #252932;
  --tl-lane-bg:        #252932;
  --tl-text-soft:      #D3D3DB;
  --tl-text-mute:      #A1A1AA;
  --tl-text-inverse:   #18181B;
  /* Dark-mode accent is a light pink, so text on it must be dark, not white. */
  --tl-on-accent:      #111318;
  --tl-rule-subtle:    #252932;
  --tl-rule-strong:    #434A56;
  --tl-focus:          #E2715F;

  --tl-allow-fg:      #6EE7A8;
  --tl-allow-bg:      #0B2E1B;
  --tl-allow-border:  #15803D;
  --tl-hold-fg:       #FCD34D;
  --tl-hold-bg:       #3A2708;
  --tl-hold-border:   #B45309;
  --tl-deny-fg:       #FCA5A5;
  --tl-deny-bg:       #3B1113;
  --tl-deny-border:   #B91C1C;
  --tl-abstain-fg:    #D3D3DB;
  --tl-abstain-bg:    #252932;
  --tl-abstain-border:#434A56;
}

/* ---------------------------------------------------------------------------
   Typography — sans (Inter) for body and headings; only the header
   wordmark uses the body sans (--locus-sans). The page-title
   topic that Material would swap in on scroll is hidden site-wide below.
   Display headings carry the wordmark's tight tracking (-0.04em on h1, -0.02em
   below). Subheadings can opt into the tagline pattern (uppercase + 0.16em)
   via the `.tagline` utility class.
   --------------------------------------------------------------------------- */
.md-typeset {
  font-family: var(--locus-sans);
  font-feature-settings: "ss01", "cv11";
  color: var(--locus-ink);
}
/* The snackbar (.md-dialog, "Copied to clipboard") is inverted — a light
   panel on the dark canvas. Its inner div also carries .md-typeset, so the
   ink override above painted its text the same cream as the panel and the
   toast showed as an empty box; restore the inversion. */
.md-typeset.md-dialog__inner {
  color: var(--md-default-bg-color);
}
.md-typeset code,
.md-typeset pre {
  font-family: var(--locus-mono);
}

/* Code blocks: the repository formats Python at 100 columns, and the
   article column is 828px wide. At Material's default .68rem the block
   fits 97 columns, so a line at the project limit scrolls; at .66rem with
   slightly narrower side padding it fits 101. Inline code is unchanged. */
.md-typeset pre > code {
  font-size: 0.66rem;
  padding-left: 0.9em;
  padding-right: 0.9em;
}
/* The line-number gutter of a numbered listing (the collapsed source blocks
   on the API pages) is a second <pre> beside the code. It has to take the
   same size as the code, or the numbers drift from their lines: inside a
   details block it was 10.9px against 13.2px, 52px off by line fifteen. */
.md-typeset .highlighttable .linenodiv pre {
  font-size: 0.66rem;
}

/* Program output (```text blocks) wraps like a terminal does, so a long
   printed line is read in full instead of scrolled. Source code keeps
   its line structure and scrolls. */
.md-typeset .language-text pre > code {
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

.md-typeset h1,
.md-typeset h2,
.md-typeset h3,
.md-typeset h4,
.md-typeset h5,
.md-header__topic > .md-ellipsis,
.md-nav__title {
  font-family: var(--locus-sans);
}


.md-typeset h1 {
  color: var(--locus-ink);
  font-weight: 700;
  font-size: 2.4rem;
  line-height: 1.10;
  letter-spacing: -0.04em;       /* wordmark tracking */
  margin: 0 0 1.2rem;
}
@media (max-width: 76em) {
  .md-typeset h1 { font-size: 1.7rem !important; }
}
@media (max-width: 48em) {
  .md-typeset h1 { font-size: 1.6rem !important; line-height: 1.15; }
  .md-typeset h1 a.headerlink { display: none; }
  .md-typeset h2 { font-size: 1.25rem; }
  .md-typeset h3 { font-size: 1.05rem; }
}
@media (max-width: 36em) {
  .md-typeset h1 { font-size: 1.45rem !important; }
}
.md-typeset h2 {
  color: var(--locus-ink);
  font-weight: 700;
  letter-spacing: -0.02em;
  border-bottom: 1px solid var(--tl-rule);
  padding-bottom: 0.4rem;
  margin-top: 1.6rem;
}
.md-typeset h3 {
  color: var(--tl-red-deep);
  font-weight: 700;
  letter-spacing: -0.015em;
}
.md-typeset h4 {
  color: var(--locus-ink);
  font-weight: 700;
}

.md-typeset p,
.md-typeset li {
  line-height: 1.65;
}

/* Homepage hero — split layout (copy left, code right) with
   soft-glow background blobs for visual warmth without
   enterprise stiffness. */
.md-typeset .locus-hero {
  position: relative;
  display: grid;
  grid-template-columns: 1.05fr 1fr;
  gap: 2.4rem;
  align-items: start;          /* both columns top-align — no dead vertical space */
  margin: -0.4rem 0 1.4rem;
  padding: 0.4rem 0 0.8rem;
  isolation: isolate;
  overflow: hidden;
}
/* Tighten the gap between the tabs strip and the hero on the home page —
   the default Material content padding leaves dead space above the H1. */
.md-content__inner:has(> .locus-hero),
.md-content__inner:has(> div > .locus-hero) {
  padding-top: 0.2rem;
  margin-top: 0;
}
/* locus-red soft glow behind the H1 — the warm spotlight */
.md-typeset .locus-hero::before {
  content: "";
  position: absolute;
  top: -180px; left: -220px;
  width: 760px; height: 760px;
  background: radial-gradient(circle,
              rgba(237, 47, 126, 0.12) 0%,
              rgba(247, 101, 30, 0.07) 35%,   /* sand */
              transparent 70%);
  z-index: -1;
  border-radius: 50%;
  pointer-events: none;
}
/* Sage glow on the right side — accent6, behind the code editor */
.md-typeset .locus-hero::after {
  content: "";
  position: absolute;
  top: 60px; right: -160px;
  width: 560px; height: 560px;
  background: radial-gradient(circle,
              rgba(22, 163, 74, 0.10) 0%,    /* sage green */
              rgba(244, 166, 194, 0.05) 40%,   /* sage teal */
              transparent 70%);
  z-index: -1;
  border-radius: 50%;
  pointer-events: none;
}
.md-typeset .locus-hero h1:first-of-type {
  font-family: var(--locus-sans);
  font-size: 2.9rem;
  line-height: 1.05;
  letter-spacing: -0.035em;
  font-weight: 700;
  text-transform: lowercase;
  color: var(--locus-ink);
  margin: 0 0 0.6rem;
}
/* Grid items must have min-width:0 so the 1fr track isn't forced to
   max-content width (the Python code block is ~492px and would otherwise
   blow past the hero's 358px container on mobile). */
.md-typeset .locus-hero__copy,
.md-typeset .locus-hero__code {
  min-width: 0;
}
/* Indent the hero copy column so the wordmark + H1 + kicker don't sit
   flush against the content edge. Mobile drops the indent (handled by the
   responsive block further down — the single-column stack already has the
   container's own padding). */
.md-typeset .locus-hero__copy {
  padding-left: 1.75rem;
}
.md-typeset .locus-hero h1 .accent {
  color: var(--tl-red);
}
/* Keeps a token such as a licence id on one line where a phone-width column
   would otherwise break it at the hyphen. */
.md-typeset .locus-nowrap { white-space: nowrap; }
.md-typeset .locus-hero p {
  font-size: 1.05rem;
  line-height: 1.55;
  color: var(--locus-ink);
  margin: 0 0 1rem;
}
.md-typeset .locus-hero__copy > p:first-of-type strong {
  font-size: 1.15rem;
  font-weight: 700;
  letter-spacing: -0.01em;
}
.md-typeset .locus-hero p em {
  display: block;
  margin-top: 1rem;
  font-style: normal;
  font-size: 0.78rem;
  color: var(--locus-mute);
  letter-spacing: 0.04em;
}
.md-typeset .locus-hero .md-button {
  margin: 0.5rem 0.5rem 0.5rem 0;
  padding: 0.55rem 1.4rem;
  font-size: 0.85rem;
}
.md-typeset .locus-hero pre {
  font-size: 0.68rem;
  line-height: 1.45;
  overflow-x: auto;
  max-width: 100%;
}
.md-typeset .locus-hero .locus-hero__code .highlight {
  border-radius: 8px;
  box-shadow: 0 18px 50px -16px rgba(49, 45, 42, 0.18);
  border-left: 0;
}
/* Inline `pip install` chip in the hero — clean rounded pill, no duplicate
   left-rule. The global `.md-typeset .highlight` rule already adds the red
   left border + rounded corners; we override it inside the hero so the
   chip reads as a single piece, not stacked borders. */
.md-typeset .locus-hero__copy .highlight {
  border-left: 0;
  border-radius: 6px;
  display: inline-block;
  max-width: 100%;
}
.md-typeset .locus-hero__copy pre {
  background: var(--tl-bg-soft);
  border: 0;
  border-radius: 6px;
  /* extra right padding clears the floating copy button so the closing
     quote of `pip install "locus-sdk[anthropic]"` stays visible */
  padding: 0.45rem 2.2rem 0.45rem 0.9rem;
  margin: 0.6rem 0;
  font-size: 0.78rem;
}

/* Hide the ¶ permalink on the hero h1. */
.md-typeset .locus-hero h1 a.headerlink {
  display: none;
}

/* Feature card grid — tighter, icon-first cards for the six-things section. */
.md-typeset .locus-feature-cards {
  margin-bottom: 2.4rem;
}
.md-typeset .grid.cards.locus-feature-cards > ul > li,
.md-typeset .grid.cards.locus-feature-cards > ol > li {
  border-left: 3px solid var(--tl-red);
  border-radius: 0 6px 6px 0;
  padding: 0.9rem 1rem;
  /* Anchor the absolutely-positioned overlay link to the card. */
  position: relative;
  transition: background-color 0.15s ease, transform 0.15s ease;
}
.md-typeset .grid.cards.locus-feature-cards > ul > li:hover,
.md-typeset .grid.cards.locus-feature-cards > ol > li:hover {
  background-color: var(--tl-surface-hover, rgba(229, 72, 103, 0.05));
  transform: translateY(-1px);
}
.md-typeset .grid.cards.locus-feature-cards p {
  font-size: 0.82rem;
  color: var(--tl-text);
  margin: 0;
  line-height: 1.5;
}
.md-typeset .grid.cards.locus-feature-cards strong {
  font-size: 1rem;
  display: block;
  margin-bottom: 0.25rem;
  color: var(--tl-accent, #C74634);
}
/* Make the whole card clickable: stretch the title's <a> over the card
   surface so anywhere inside the <li> opens the linked concept page. */
.md-typeset .grid.cards.locus-feature-cards strong a {
  color: inherit;
  text-decoration: none;
}
.md-typeset .grid.cards.locus-feature-cards strong a::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
}
.md-typeset .grid.cards.locus-feature-cards > ul > li:focus-within,
.md-typeset .grid.cards.locus-feature-cards > ol > li:focus-within {
  outline: 2px solid var(--tl-accent, #C74634);
  outline-offset: 2px;
}
@media (max-width: 76em) {
  .md-typeset .locus-hero {
    grid-template-columns: 1fr;
    gap: 1.4rem;
    overflow: visible;
  }
  /* Drop the desktop hero-copy indent when columns stack. */
  .md-typeset .locus-hero__copy {
    padding-left: 0;
  }
  .md-typeset .locus-hero::before,
  .md-typeset .locus-hero::after {
    display: none;
  }
  .md-typeset .locus-hero h1:first-of-type {
    font-size: 2.2rem;
  }
  .md-typeset .locus-hero p {
    font-size: 1rem;
  }
  .md-typeset .locus-hero__copy > p:first-of-type strong {
    font-size: 1rem;
    font-weight: 600;
  }
}
@media (max-width: 48em) {
  .md-typeset .locus-hero h1:first-of-type {
    font-size: 1.9rem;
    letter-spacing: -0.04em;
  }
  .md-typeset .locus-hero p {
    font-size: 0.95rem;
  }
}
@media (max-width: 36em) {
  .md-typeset .locus-hero h1:first-of-type {
    font-size: 1.65rem;
    letter-spacing: -0.035em;
  }
  .md-typeset .locus-hero p {
    font-size: 0.9rem;
  }
}

/* Grid cards (workflows you can build) */
.md-typeset .grid.cards {
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
  gap: 0.9rem;
}
.md-typeset .grid.cards > ul > li,
.md-typeset .grid.cards > ol > li {
  background: var(--locus-surface);
  border: 1px solid var(--tl-rule);
  border-radius: 6px;
  padding: 1rem 1.1rem;
  transition: box-shadow 0.15s, transform 0.15s, border-color 0.15s;
}
.md-typeset .grid.cards > ul > li:hover,
.md-typeset .grid.cards > ol > li:hover {
  box-shadow: 0 8px 28px -16px rgba(49, 45, 42, 0.22);
  transform: translateY(-2px);
  border-color: var(--tl-red-light);
}
.md-typeset .grid.cards .twemoji,
.md-typeset .grid.cards svg {
  color: var(--tl-red);
}

/* ---------------------------------------------------------------------------
   Header — white slab, hairline locus-red rule below.
   Layout: locus mark (icon) left · "locus" + tagline middle · GitHub right.
   --------------------------------------------------------------------------- */
.md-header {
  background-color: var(--locus-surface);
  color: var(--locus-ink);
  border-bottom: 1px solid var(--tl-rule);
  box-shadow: 0 6px 16px -12px rgba(49, 45, 42, 0.18);
}
/* (The brand hairline under the header is the 2px gradient border-image in
   the dev-brand section near the end of this file — one line, not two.) */
.md-header__inner {
  min-height: 4rem;
  padding: 0.45rem 1rem 0.7rem;
}

/* Bigger locus mark on the left — always visible, including mobile where
   Material hides it by default. */
.md-header__button.md-logo {
  display: inline-flex;
  margin: 0 0.15rem 0 0;
  padding: 0;
}
.md-header__button.md-logo img,
.md-header__button.md-logo svg {
  height: 2.6rem;
  max-height: 56px;
  width: auto;
}
/* Scale the mark down on narrow screens to give the title breathing room. */
@media (max-width: 56em) {
  .md-header__button.md-logo img,
  .md-header__button.md-logo svg {
    height: 1.8rem;
    max-height: 32px;
  }
}
.md-header__button.md-logo:hover {
  opacity: 0.85;
}

/* Title block in the middle — "locus" wordmark with the product name
   stacked beneath it (see the ::after rule below; the topic swap that
   used to fight the stacked layout is disabled site-wide further down).
   `flex: 0 0 auto` keeps the title from taking the full available row;
   that leaves room for the palette toggle, search, and source slot to
   cluster together on the right (see `form.md-header__option { margin-left: auto }` below). */
.md-header .md-header__title {
  display: flex;
  align-items: center;
  /* tight lockup: the mark and the wordmark read as one logo.
     Extra class in the selector: Material sets this margin via
     [dir=ltr] rules that outrank a lone class. */
  margin-left: 0.15rem;
  align-self: center;
  flex: 0 0 auto;
}
/* Push the palette toggle, search, and source slot to the right side
   of the header inner row, leaving a clean gap after the title. */
form.md-header__option {
  margin-left: auto;
}
/* Stack the first topic vertically: "locus" wordmark + the slogan
   beneath ('Oracle Agentic Harness SDK'), matching the wordmark+tagline
   lockup the SVG logo carries. One short line, so it fits alongside the
   dark-mode toggle and the search slot at common viewport widths. */
.md-header__ellipsis > .md-header__topic:first-of-type {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: center;
  gap: 0.15rem;
}
.md-header__ellipsis > .md-header__topic:first-of-type > .md-ellipsis {
  font-family: var(--locus-sans);
  font-weight: 700;
  font-size: 1.55rem;
  line-height: 1;
  letter-spacing: -0.04em;
  text-transform: lowercase;
  color: var(--locus-ink);
}
.md-header__ellipsis > .md-header__topic:first-of-type::after {
  content: "Oracle Agentic Harness SDK";
  font-family: var(--locus-sans);
  font-size: 0.55rem;
  font-weight: 600;
  letter-spacing: 0.12em;
  color: var(--tl-red);
  line-height: 1.25;
  white-space: nowrap;
  /* Push the line away from the dark-mode toggle that sits immediately
     to the right of the title slot, so they don't visually touch. */
  padding-right: 1rem;
}
@media (max-width: 56em) {
  /* Mobile: same slogan, slightly tighter tracking to fit. */
  .md-header__ellipsis > .md-header__topic:first-of-type::after {
    font-size: 0.5rem;
    letter-spacing: 0.06em;
  }
  /* Always show "locus" (site title) in the mobile header — suppress
     Material's page-title swap so users always see the brand name. */
  .md-header__ellipsis > .md-header__topic:not(:first-of-type) {
    display: none;
  }
  .md-header__ellipsis > .md-header__topic:first-of-type {
    transform: translateY(0) !important;
    opacity: 1 !important;
    pointer-events: auto;
  }
}

/* Mobile/tablet (whenever the drawer hamburger is visible): Material's DOM
   order is logo · hamburger · title, which splits the brand lockup in half —
   the mark sits alone in the corner and "locus" lands on the far side
   of the menu button. Reorder so the hamburger comes first and the mark +
   wordmark read as one logo, same as desktop. */
@media (max-width: 76.1875em) {
  .md-header__inner > label[for="__drawer"] {
    order: -1;
    margin-right: 0.2rem;
  }
}

/* The wordmark anchors to the top of the title box (Material sizes
   .md-header__ellipsis to the full row for its scroll-swap animation, which
   we disable). Center it so the wordmark sits on the mark's midline. */
.md-header__ellipsis {
  display: flex;
  align-items: center;
  height: 100%;
}

/* Site-wide: never let Material swap the header topic on scroll. The default
   behaviour translates topic #1 (site name + our tagline) up and fades in
   topic #2 (page title), which strips the approved product-name line and
   replaces it with the current page's name. Pin topic #1 and hide #2 on every
   page so the brand banner (diamond mark + "locus" + product name) stays put
   as the user scrolls.
   `position: static` matters: Material absolutely-positions the topic for
   its swap animation, which collapses .md-header__title to 0 width — the
   wordmark only rendered on desktop because it spilled out of that empty
   box, and on mobile (where the title gets overflow:hidden) it vanished
   entirely. With the swap disabled the absolute positioning serves nothing;
   static lets the wordmark size its box and actually show on phones. */
.md-header__ellipsis > .md-header__topic:first-of-type {
  position: static !important;
  transform: translateY(0) !important;
  opacity: 1 !important;
  pointer-events: auto !important;
}
.md-header__ellipsis > .md-header__topic:not(:first-of-type) {
  display: none !important;
}

/* Header right slot — keep the PyPI badge and GitHub icon on one row.
   Material wraps source.html in `<div class="md-header__source">`, and our
   anchors inside it are also `md-header__source` (block, width:100%). Force the
   parent slot to flex-row and let the children size to content. */
.md-header__source:has(> .md-header__pypi) {
  display: flex !important;
  align-items: center;
  flex-direction: row;
  gap: 0.25rem;
  width: auto;
  max-width: none;
}

@media (max-width: 60em) {
  /* Tighten header inner padding so logo + hamburger + title + icons fit. */
  .md-header__inner {
    padding-left: 0.5rem;
    padding-right: 0.5rem;
  }
  /* Scale the locus mark down on narrow screens. */
  .md-header__button.md-logo img,
  .md-header__button.md-logo svg {
    height: 1.6rem;
    max-height: 28px;
  }
}

/* GitHub icon in the mobile drawer uses ink on the drawer surface. */
.md-nav--primary .md-header__source.md-header__github,
.md-drawer .md-header__source.md-header__github {
  color: var(--locus-ink);
}

/* Header right slot — PyPI version badge sits to the right of the GitHub
   icon, hugging the far right edge of the header. */
.md-header__source.md-header__pypi {
  display: inline-flex;
  align-items: center;
  margin-left: 0.4rem;
  padding: 0;
  border-radius: 4px;
  transition: transform 0.15s;
}
.md-header__source.md-header__pypi:hover {
  transform: translateY(-1px);
}
.md-header__sdk-badge {
  display: block;
  padding: 0.18rem 0.42rem;
  border: 1px solid color-mix(in srgb, var(--tl-red-light) 60%, transparent);
  border-radius: 4px;
  color: var(--md-primary-bg-color);
  font: 600 0.56rem/1 var(--locus-mono);
  white-space: nowrap;
}
@media (max-width: 60em) {
  /* Honor "always show PyPI": Material hides .md-header__source below 60em,
     so force the PyPI badge to stay in the header on mobile too. */
  .md-header__source.md-header__pypi {
    display: inline-flex !important;
    margin-left: 0.25rem;
  }
  .md-header__sdk-badge { font-size: 0.5rem; }
  /* Drop the palette toggle on mobile (the scheme follows the system there)
     to free the width the brand title needs. */
  .md-header__option { display: none !important; }
  /* The palette form used to carry margin-left:auto (it right-aligned the
     controls); now that it's hidden, move that onto the search button so
     search + PyPI + GitHub hug the right edge, leaving the left for the
     brand title. */
  .md-header__button.md-icon[for="__search"] { margin-left: auto !important; }
  /* Show the brand title ("locus" wordmark + the slogan line) on mobile
     — small and hard-clamped so it stays clear of the right-aligned
     controls. The clamp must fit the slogan ("Oracle Agentic Harness SDK",
     ~180px at 0.55rem/0.12em plus the 1rem right padding); below 30em
     the slogan is dropped, so the clamp only ever bites on the wordmark
     there. Target the REAL title span (.md-header__title .md-ellipsis)
     directly. */
  .md-header__title {
    display: flex !important;
    flex: 0 1 auto;
    min-width: 0;
    max-width: 13.5rem;
    overflow: hidden;
    margin-left: 0.4rem;
  }
  .md-header__title .md-ellipsis {
    font-size: 0.85rem !important;
    line-height: 1.2;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }
}
.md-nav--primary .md-header__source.md-header__github:hover {
  color: var(--tl-red);
  opacity: 0.8;
}

.md-tabs {
  background-color: var(--tl-bg);
  color: var(--locus-ink);
  border-bottom: 1px solid var(--tl-rule);
}
/* Tighter tab strip — Material defaults to a 2.4rem item height with a
   0.8rem top-margin on each link, leaving a tall empty band above the
   labels. Compact both so the tabs sit closer to the banner. */
.md-tabs__item {
  height: 1.8rem;
}
.md-tabs__link {
  color: var(--locus-mute);
  font-weight: 600;
  opacity: 1;
  letter-spacing: 0.01em;
  margin-top: 0.35rem;
}
.md-tabs__link:hover {
  color: var(--tl-red);
}
.md-tabs__link--active {
  color: var(--locus-ink);
  position: relative;
}
.md-tabs__link--active::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: -1px;
  height: 2px;
  background: var(--tl-red);
}

/* ---------------------------------------------------------------------------
   Side-nav — calmer, off-white feel.
   --------------------------------------------------------------------------- */
.md-nav__title {
  color: var(--tl-text);
  font-weight: 700;
}

/* Mobile drawer header — override Material's red primary background with
   the same surface + red hairline the desktop header uses. */
.md-nav--primary .md-nav__title[for="__drawer"] {
  background-color: var(--locus-surface);
  color: var(--locus-ink);
  border-bottom: 2px solid var(--tl-red);
  box-shadow: none;
}
.md-nav--primary .md-nav__title[for="__drawer"] .md-nav__button {
  color: var(--locus-ink);
}
/* Source slot inside the drawer — target the actual container. Same surface
   as the drawer header above it in each scheme. */
.md-nav__source {
  background-color: var(--tl-surface);
  border-bottom: 1px solid var(--tl-rule);
}
[data-md-color-scheme="slate"] .md-nav--primary .md-nav__title[for="__drawer"] {
  background-color: var(--tl-surface);
  color: var(--tl-text);
}

/* Mobile: float the palette toggle into the right rail. At cramped
   widths the toggle was rendering on top of the "s" in "locus" because
   the flex flow placed it immediately after the wordmark, where the
   title block doesn't end cleanly. ``margin-left: auto`` shoves it to
   the right edge of the header__inner row, joining the search +
   source-link cluster — no more overlap, and the toggle stays
   discoverable next to the other header actions. */
@media (max-width: 56em) {
  form.md-header__option {
    margin-left: auto;
    margin-right: 0.25rem;
    flex: 0 0 auto;
  }
}

/* Section headers (Multi-agent, Agents, Tools …) — teal accent, uppercase,
   small caps so they read as category labels not nav items. */
.md-nav--primary .md-nav__item--section > .md-nav__link,
.md-nav--primary .md-nav__item--section > .md-nav__link:not(.md-nav__link--active) {
  color: var(--locus-mute) !important;
  font-size: 0.68rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  margin-top: 0.5rem;
  padding-top: 0.5rem;
  border-top: 1px solid var(--tl-rule);
  opacity: 1;
}
.md-nav--primary .md-nav__item--section:first-child > .md-nav__link {
  border-top: none;
  margin-top: 0;
  padding-top: 0.2rem;
}

.md-nav__link--active,
.md-nav__link[aria-current="true"] {
  color: var(--tl-red-deep) !important;
  font-weight: 600;
}
.md-nav__item .md-nav__link:hover {
  color: var(--tl-link);
}

/* ---------------------------------------------------------------------------
   Code blocks — soft sand background, locus red filename tab.
   --------------------------------------------------------------------------- */
.md-typeset code {
  background-color: rgba(128, 128, 128, 0.14);
  color: var(--locus-code-inline);
  border-radius: 3px;
  font-size: 0.85em;
}
.md-typeset pre > code {
  background-color: var(--tl-bg-soft);
  color: var(--tl-text);
}
.md-typeset .highlight {
  border-left: 3px solid var(--tl-red);
  border-radius: 0 4px 4px 0;
}

/* The hero example is the showcase — a notch larger than body code. */
.md-typeset .locus-hero__code pre > code,
.md-typeset .locus-hero__code .highlight code {
  font-size: 0.92rem;
  line-height: 1.6;
}
/* On mobile the hero example must fit a ~390px column — at 0.92rem (≈18px)
   it overflowed and looked cramped, so drop it to a compact size. */
@media (max-width: 60em) {
  .md-typeset .locus-hero__code pre > code,
  .md-typeset .locus-hero__code .highlight code {
    font-size: 0.7rem;
    line-height: 1.5;
  }
}

/* ---------------------------------------------------------------------------
   Tables — off-white striping, subtle red header underline.
   --------------------------------------------------------------------------- */
.md-typeset table:not([class]) {
  border: 1px solid var(--tl-rule);
  border-radius: 4px;
  overflow: hidden;
  font-size: 0.84rem;
}
.md-typeset table:not([class]) th {
  background-color: var(--tl-bg-soft);
  color: var(--tl-text);
  font-weight: 700;
  border-bottom: 2px solid var(--tl-red);
}
.md-typeset table:not([class]) tr:nth-child(even) {
  background-color: var(--locus-table-stripe);
}

/* ---------------------------------------------------------------------------
   Admonitions — re-tint to accents.
   --------------------------------------------------------------------------- */
.md-typeset .admonition.note,
.md-typeset details.note {
  border-left-color: var(--tl-link);
}
.md-typeset .admonition.note > .admonition-title,
.md-typeset details.note > summary {
  background-color: var(--tl-bg-soft);
  color: var(--tl-link);
}
/* Warning and tip take the status tokens (hold and allow), not the brand
   pink: pink means Locus or an interactive element, never a status. The
   tokens are defined per scheme, so the title keeps its contrast in dark. */
.md-typeset .admonition.warning,
.md-typeset details.warning {
  border-left-color: var(--tl-hold-border);
}
.md-typeset .admonition.warning > .admonition-title,
.md-typeset details.warning > summary {
  background-color: var(--tl-hold-bg);
  color: var(--tl-hold-fg);
}
.md-typeset .admonition.warning > .admonition-title::before,
.md-typeset details.warning > summary::before {
  background-color: var(--tl-hold-fg);
}
.md-typeset .admonition.tip,
.md-typeset details.tip {
  border-left-color: var(--tl-allow-border);
}
.md-typeset .admonition.tip > .admonition-title,
.md-typeset details.tip > summary {
  background-color: var(--tl-allow-bg);
  color: var(--tl-allow-fg);
}

/* ---------------------------------------------------------------------------
   Buttons / pills — locus red CTA.
   --------------------------------------------------------------------------- */
/* Secondary buttons are neutral ink — one rose element per viewport (the
   primary CTA). Rose appears on hover only. */
.md-typeset .md-button {
  background-color: transparent;
  border: 1px solid color-mix(in srgb, var(--locus-ink) 35%, transparent);
  color: var(--locus-ink);
  border-radius: 3px;
  font-weight: 600;
  letter-spacing: 0.01em;
}
.md-typeset .md-button:hover,
.md-typeset .md-button:focus {
  background-color: color-mix(in srgb, var(--tl-red) 8%, transparent);
  color: var(--tl-red);
  border-color: var(--tl-red);
}
.md-typeset .md-button--primary {
  background-color: var(--tl-red);
  color: #FFFFFF;
}
.md-typeset .md-button--primary:hover {
  background-color: var(--tl-red-deep);
}

/* ---------------------------------------------------------------------------
   Footer — dark bar with red micro-accent + locus wordmark.
   --------------------------------------------------------------------------- */
.md-footer-meta {
  background-color: var(--md-footer-bg-color--dark);
}
.md-footer__inner {
  border-top: 2px solid var(--tl-red);
}

/* Footer brand block — product title + copyright line.
   Driven by HTML in mkdocs.yml `copyright:`. */
.md-copyright {
  font-size: 0.72rem;
  letter-spacing: 0.04em;
  line-height: 1.45;
}
.md-copyright__highlight {
  display: block;
  padding: 0;
}

.footer-brand {
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
  font-family: var(--locus-sans);
  font-weight: 700;
  font-size: 1.05rem;
  letter-spacing: -0.005em;
  color: #FFFFFF;
  margin: 0 0 0.25rem;
  text-transform: none;
}
.footer-copy {
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
  flex-wrap: wrap;
  color: rgba(255, 255, 255, 0.72);
}

/* ---------------------------------------------------------------------------
   Search input — keep neutral, red focus ring.
   --------------------------------------------------------------------------- */
.md-search__input {
  background-color: var(--tl-bg-soft);
  color: var(--locus-ink);
}
.md-search__input::placeholder {
  color: var(--locus-mute);
}
.md-search__input + .md-search__icon {
  color: var(--locus-mute);
}
.md-search__input:focus,
.md-search__input:hover {
  background-color: var(--locus-surface);
  box-shadow: 0 0 0 2px rgba(229, 72, 103, 0.20);
}

/* ---------------------------------------------------------------------------
   Hero treatment for the index page (`# Locus` h1).
   --------------------------------------------------------------------------- */
.md-typeset h1:first-of-type {
  font-size: 2.8rem;
  letter-spacing: -0.01em;
}

/* ---------------------------------------------------------------------------
   SDK-distinctive callout — used on the Capabilities page to highlight
   wedge features. locus-red border + warm sand tint, red star icon.
   Trigger with: `!!! sdk-distinctive "Distinctive to locus"`
   --------------------------------------------------------------------------- */
:root {
  --md-admonition-icon--sdk-distinctive: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 17.27 18.18 21l-1.64-7.03L22 9.24l-7.19-.61L12 2 9.19 8.63 2 9.24l5.46 4.73L5.82 21z"/></svg>');
}
.md-typeset .admonition.sdk-distinctive,
.md-typeset details.sdk-distinctive {
  border-color: var(--tl-red);
  background: linear-gradient(135deg,
    rgba(229, 72, 103, 0.04) 0%,
    rgba(173, 46, 92, 0.04) 100%);
}
.md-typeset .sdk-distinctive > .admonition-title,
.md-typeset .sdk-distinctive > summary {
  background-color: rgba(229, 72, 103, 0.08);
  color: var(--tl-red-deep);
  font-weight: 700;
  letter-spacing: -0.01em;
}
.md-typeset .sdk-distinctive > .admonition-title::before,
.md-typeset .sdk-distinctive > summary::before {
  background-color: var(--tl-red);
  -webkit-mask-image: var(--md-admonition-icon--sdk-distinctive);
          mask-image: var(--md-admonition-icon--sdk-distinctive);
}

/* ---------------------------------------------------------------------------
   Dark-mode logo handling.
   - locus wordmark → live text in var(--locus-ink), which flips per scheme;
     no filter.
   - locus mark → swapped to img/mark-dark.svg on the slate scheme (header
     and drawer).
   --------------------------------------------------------------------------- */
/* Header AND mobile drawer — same mark in dark (the drawer was stuck on the
   pink variant while the header swapped to the rose→amber one). */
[data-md-color-scheme="slate"] .md-header__button.md-logo img,
[data-md-color-scheme="slate"] .md-nav--primary .md-nav__title .md-logo img {
  content: url("../img/mark-dark.svg");
}

/* Header GitHub link — sits next to the brand source button. */
.md-header__source.md-header__github {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  max-width: none;
  padding: 0;
  margin-left: 0;
  border-radius: 8px;
  color: var(--locus-ink);
  transition: background-color 0.15s, color 0.15s, transform 0.15s;
}
.md-header__source.md-header__github:hover {
  background-color: rgba(128, 128, 128, 0.14);
  color: var(--tl-red);
  transform: translateY(-1px);
}
.md-header__github-icon {
  width: 22px;
  height: 22px;
  display: block;
}

/* Hide the ¶ permalink anchor on the hero h1 — noise on a marketing page. */
.md-typeset .locus-hero h1 a.headerlink {
  display: none;
}

/* Header title area — pointer cursor so users know it goes home. */
.md-header__ellipsis {
  cursor: pointer;
}

/* ---------------------------------------------------------------------------
 * Notebook index filter — live search.
 * --------------------------------------------------------------------------- */

.notebook-filter {
  margin: 1rem 0 1.5rem;
}

.notebook-filter__input {
  width: 100%;
  padding: 0.7rem 1rem;
  font: inherit;
  font-size: 0.95rem;
  background: var(--md-default-bg-color);
  color: var(--md-default-fg-color);
  border: 1px solid var(--md-default-fg-color--lightest);
  border-radius: 0.5rem;
  transition: border-color 120ms, box-shadow 120ms;
}

.notebook-filter__input:focus {
  outline: none;
  border-color: var(--md-accent-fg-color);
  box-shadow: 0 0 0 3px rgba(196, 36, 32, 0.12);
}

.notebook-filter__input::placeholder {
  color: var(--md-default-fg-color--light);
}

/* Sidebar notebook filter — same UX, scaled to the primary sidebar. */
.sidebar-filter {
  margin: 0.4rem 0.6rem 0.8rem;
  list-style: none;
}
.sidebar-filter__input {
  width: 100%;
  padding: 0.4rem 0.6rem;
  font: inherit;
  font-size: 0.72rem;
  background: var(--md-default-bg-color);
  color: var(--md-default-fg-color);
  border: 1px solid var(--md-default-fg-color--lightest);
  border-radius: 0.35rem;
  transition: border-color 120ms, box-shadow 120ms;
}
.sidebar-filter__input:focus {
  outline: none;
  border-color: var(--md-accent-fg-color);
  box-shadow: 0 0 0 2px rgba(196, 36, 32, 0.18);
}
.sidebar-filter__input::placeholder {
  color: var(--md-default-fg-color--light);
}

/* ---------------------------------------------------------------------------
 * Mobile polish — narrow viewports (<= 48em).
 *
 *   Material's default per-table horizontal scroll is workable for one
 *   table but painful on /notebooks/ where the page is a stack of nine.
 *   We let tables fit the viewport instead: 100% width, auto layout,
 *   prose wraps with `overflow-wrap: anywhere` (which only breaks when
 *   needed — unlike `break-all` which splits in the middle of perfectly
 *   sized tokens like `openai.gpt-5.5-pro`).
 *
 *   The scrollwrap stays `auto`, not `hidden`: a dense table whose
 *   min-content width exceeds the viewport (code chips + 4-5 columns —
 *   the homepage comparison table, /integrations/, the mkdocstrings
 *   parameter tables) CANNOT shrink to 100%, and with `hidden` its last
 *   column was clipped with no way to reach it. Fit-first still wins
 *   wherever the table can compress; the overflow scrollbar only appears
 *   on the tables that would otherwise lose content.
 *
 *   Also: cap any in-content image (gifs, screenshots) at the column
 *   width so it never blows past the viewport edge.
 * --------------------------------------------------------------------- */
@media (max-width: 48em) {
  /* Tables: fit the viewport when possible, scroll in-place when not. */
  .md-typeset__scrollwrap {
    margin-left: -0.4rem;
    margin-right: -0.4rem;
    overflow-x: auto;
  }
  /* The global table rule sets `overflow: hidden` for rounded corners;
     Material tables are their own scroll container, so on mobile that
     clipped the rows of any table too dense to compress (min-content
     wider than the phone). Restore in-table scrolling here — the tiny
     unclipped 4px header corner is a fair trade for reachable content. */
  .md-typeset table:not([class]) {
    overflow-x: auto;
  }
  .md-typeset__table {
    display: block;
    width: 100%;
    padding: 0 0.4rem;
    overflow-x: visible;
  }
  .md-typeset__table > table:not([class]) {
    width: 100%;
    table-layout: auto;
    font-size: 0.78rem;
  }
  .md-typeset table:not([class]) th,
  .md-typeset table:not([class]) td {
    padding: 0.45em 0.5em;
    line-height: 1.4;
    /* break-word, not anywhere: anywhere lets the auto layout shrink a column
       below its longest word ("Requireme / nts"); break-word keeps the word's
       width as the column minimum and only splits a token wider than the cell. */
    overflow-wrap: break-word;
  }
  /* Material keeps the table inline-block; with width:100% that stretched the
     frame but not the rows, leaving a blank strip inside the border at 768px. */
  .md-typeset__table > table:not([class]) {
    display: table;
  }
  /* On /notebooks/ index the first column is the row number ("01"…"63") —
     slim it to a chip so the prose columns get more room. Other pages
     keep auto-sized first columns (Setting/DSN-style text headers). */
  .notebook-filter ~ * .md-typeset__table > table:not([class]) th:first-child,
  .notebook-filter ~ * .md-typeset__table > table:not([class]) td:first-child,
  article:has(.notebook-filter) .md-typeset__table > table:not([class]) th:first-child,
  article:has(.notebook-filter) .md-typeset__table > table:not([class]) td:first-child {
    width: 1.6rem;
    padding-left: 0.4em;
    padding-right: 0.3em;
    text-align: center;
    color: var(--locus-mute);
    font-variant-numeric: tabular-nums;
  }
  /* Cap in-content media at the column width. */
  .md-typeset img,
  .md-typeset video {
    max-width: 100%;
    height: auto;
  }
}

/* ---------------------------------------------------------------------------
 * Mobile header — keep the wordmark, tagline, search icon, and source
 * badges from colliding at narrow widths.
 *
 *   At ~480–560px the "locus" + tagline title block grows wide enough to
 *   visually overlap the search magnifier sitting in the right rail. We
 *   stage the trimming in two steps:
 *     - ≤ 56em: shrink the wordmark, tighten the tagline letter-spacing.
 *     - ≤ 30em: drop the tagline + the PyPI version pill entirely; the
 *       wordmark and brand/GitHub icons stay.
 * --------------------------------------------------------------------- */
@media (max-width: 56em) {
  .md-header__ellipsis > .md-header__topic:first-of-type > .md-ellipsis {
    font-size: 1.2rem;
  }
  /* Title takes only the space it needs; the right rail keeps its slot. */
  .md-header__title { flex: 0 0 auto; }
}
@media (max-width: 30em) {
  /* Drop the PyPI badge to free up room on small phones.
     !important: the <=60em rule above force-shows the badge with
     !important, so the narrow-phone hide must outrank it. */
  .md-header__source.md-header__pypi { display: none !important; }
  .md-header__ellipsis > .md-header__topic:first-of-type > .md-ellipsis {
    font-size: 1.1rem;
  }
  /* Tighter spacing between right-rail icons. */
  .md-header__source.md-header__github { margin-left: 0.2rem; }
}

/* ---------------------------------------------------------------------------
 * Code-block copy button
 *
 * mkdocs-material's default ``.md-clipboard`` uses
 * ``--md-default-fg-color--lightest`` (#c5c8c8 in our light scheme,
 * #4a4844 in slate). On our pale-cream code-block background the
 * light-scheme variant is practically invisible until you hover.
 * Promote the resting state to ``--lighter`` (darker neutral) for
 * baseline contrast, and switch to locus red on hover so the affordance
 * is obvious.
 * --------------------------------------------------------------------- */
.md-clipboard {
  color: var(--md-default-fg-color--lighter);
  opacity: 0.85;
  transition: color 120ms ease-in-out, opacity 120ms ease-in-out;
}
.md-clipboard:focus,
.md-clipboard:hover {
  color: var(--tl-red);
  opacity: 1;
}
[data-md-color-scheme="slate"] .md-clipboard {
  color: var(--md-default-fg-color--light);
  opacity: 0.9;
}
[data-md-color-scheme="slate"] .md-clipboard:focus,
[data-md-color-scheme="slate"] .md-clipboard:hover {
  color: var(--tl-red-light);
  opacity: 1;
}

/* ===================================================================
   locus brand — polished, cohesive (light + dark).
   Light: clean WHITE header showcasing the precise locus mark.
   Dark:  deep header. Pink->rose gradient as a thin hairline + the
   logo + accents; locus-rose links/CTAs.
   (Scheme variables + --locus-grad live in the blocks at the top of
   this file — single source of truth.)
   =================================================================== */

/* Header + tabs: soft elevation + a pink->rose hairline at the bottom. */
.md-header {
  box-shadow: 0 1px 0 rgba(0,0,0,0.04), 0 2px 12px rgba(0,0,0,0.05);
  border-bottom: 2px solid transparent;
  /* Signature hairline — fades at both edges so it garnishes instead of
     shouting a full-width saturated rule. */
  border-image: linear-gradient(90deg,
      transparent 0%, #C74634 18%, #AD2E5C 82%, transparent 100%) 1;
}
.md-tabs { border-bottom: 1px solid rgba(0,0,0,0.06); }
[data-md-color-scheme="slate"] .md-tabs { border-bottom-color: rgba(255,255,255,0.06); }

/* Logo mark: a touch larger so the bloom reads clearly. */
.md-header__button.md-logo img { height: 1.7rem; width: auto; }

/* Wordmark next to the logo — lowercase, tight. */
.md-header__topic > .md-ellipsis { font-weight: 700; letter-spacing: -0.02em; }

/* Links + active/hover — via --tl-link so each scheme keeps its own
   luminance (hardcoding the light value made dark-mode links ~3:1). */
.md-typeset a { color: var(--tl-link); }
.md-nav__link--active, .md-nav__item .md-nav__link--active { color: var(--tl-link); }

/* Primary CTA in the brand red; hover deepens the same red, never shifts hue. */
.md-typeset .md-button--primary {
  background-color: var(--tl-red); border-color: var(--tl-red); color: #FFFFFF;
}
.md-typeset .md-button--primary:hover,
.md-typeset .md-button--primary:focus {
  background-color: var(--tl-red-deep); border-color: var(--tl-red-deep); color: #FFFFFF;
}

/* Gradient garnish: hero accent word + footer wordmark. */
.md-typeset .locus-hero h1 .accent,
.md-footer-meta .footer-brand__text {
  background: var(--locus-grad);
  -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent; color: transparent;
}
.md-footer-meta .footer-brand__text { font-weight: 700; }

/* ===================================================================
   locus — "modern dev-brand" redesign (distinct from the stock
   Material template): sans headings and wordmark, and bordered
   hover-lift feature cards.
   =================================================================== */

/* Product and documentation headings stay crisp and technical. */
.md-typeset h1, .md-typeset h2, .md-typeset h3,
.md-typeset .locus-hero h1,
.md-tabs__link,
.md-footer-meta .footer-brand__text {
  font-family: var(--locus-sans);
  letter-spacing: -0.02em;
}

/* ---- Feature cards: full border, rounded, hover-lift ---- */
.md-typeset .grid.cards.locus-feature-cards > ul > li,
.md-typeset .grid.cards.locus-feature-cards > ol > li {
  border: 1px solid var(--tl-rule);
  border-radius: 16px;
  padding: 1.2rem 1.25rem;
  background: var(--md-default-bg-color);
  transition: transform 0.16s ease, box-shadow 0.16s ease, border-color 0.16s ease;
}
.md-typeset .grid.cards.locus-feature-cards > ul > li:hover,
.md-typeset .grid.cards.locus-feature-cards > ol > li:hover {
  transform: translateY(-4px);
  box-shadow: 0 16px 40px -16px rgba(20,16,24,0.18);
  border-color: rgba(229,72,103,0.40);
  background: var(--md-default-bg-color);
}
.md-typeset .grid.cards.locus-feature-cards strong { color: var(--locus-ink); }
.md-typeset .grid.cards.locus-feature-cards .lg.middle { color: #C74634; }

/* ===================================================================
   Two-column hero (left copy / right code) refinements.
   =================================================================== */
.md-typeset .locus-hero h1:first-of-type {
  text-transform: none;
  font-size: 2.9rem;
  line-height: 1.06;
}
.md-typeset .locus-hero .locus-hero__code .highlight {
  border-radius: 14px;
  box-shadow: 0 24px 60px -20px rgba(20, 16, 24, 0.28);
  overflow: hidden;
}

/* Header title is clickable → home (see header-home.js). */
.md-header__title { cursor: pointer; }

/* ===================================================================
   Nav section labels — hover accent tint
   =================================================================== */

.md-nav--primary .md-nav__item--section > .md-nav__link:not(.md-nav__link--active):hover {
  background: var(--md-accent-fg-color--transparent);
  border-top-color: var(--tl-red-light);
  color: var(--tl-link) !important;
}

/* ===================================================================
   Code — warm syntax palette (both schemes).
   Stock Material highlights in cool blues/purples that fight the warm
   canvas. Same token roles, warm hues: rose keywords, amber functions,
   sage strings, aubergine numbers, warm-grey punctuation.
   =================================================================== */

[data-md-color-scheme="default"] {
  --md-code-hl-color:             rgba(214, 51, 108, 0.10);
  --md-code-hl-keyword-color:     #A61E4D;
  --md-code-hl-function-color:    #A34E0E;
  --md-code-hl-string-color:      #1B6E44;
  --md-code-hl-number-color:      #7E4A8C;
  --md-code-hl-constant-color:    #7E4A8C;
  --md-code-hl-special-color:     #C2384F;
  --md-code-hl-name-color:        var(--md-code-fg-color);
  --md-code-hl-variable-color:    #4A434C;
  --md-code-hl-operator-color:    #78716C;
  --md-code-hl-punctuation-color: #99938D;
  --md-code-hl-comment-color:     #6B6560; /* 5.2:1 on --tl-bg-soft (WCAG AA) */
  --md-code-hl-generic-color:     #4A434C;
}
[data-md-color-scheme="slate"] {
  --md-code-hl-color:             rgba(236, 90, 119, 0.12);
  --md-code-hl-keyword-color:     #F27E95;
  --md-code-hl-function-color:    #E5A961;
  --md-code-hl-string-color:      #8FCE9F;
  --md-code-hl-number-color:      #C9A3E0;
  --md-code-hl-constant-color:    #C9A3E0;
  --md-code-hl-special-color:     #F2C4BD;
  --md-code-hl-name-color:        var(--md-code-fg-color);
  --md-code-hl-variable-color:    #D8D2C9;
  --md-code-hl-operator-color:    #A39C94;
  --md-code-hl-punctuation-color: #8A837C;
  --md-code-hl-comment-color:     #837C74;
  --md-code-hl-generic-color:     #D8D2C9;
}

/* ===================================================================
   Dark-mode tuning — hero glow + kicker.
   =================================================================== */

/* The light-mode glow's orange stop turns brown on the dark canvas —
   keep the spotlight rose-on-rose in dark. */
[data-md-color-scheme="slate"] .md-typeset .locus-hero::before {
  background: radial-gradient(circle,
              rgba(236, 90, 119, 0.15) 0%,
              rgba(214, 51, 108, 0.07) 40%,
              transparent 70%);
}
[data-md-color-scheme="slate"] .md-typeset .locus-hero::after {
  background: radial-gradient(circle,
              rgba(22, 163, 74, 0.06) 0%,
              rgba(244, 166, 194, 0.04) 40%,
              transparent 70%);
}
/* ===================================================================
   Mobile — CTA buttons stack full-width (no orphan third button on a
   row of its own), kicker tightens to fit the narrow column.
   =================================================================== */

@media screen and (max-width: 36em) {
  .md-typeset .md-button,
  .md-typeset .locus-hero .md-button {
    display: flex;
    justify-content: center;
    width: 100%;
    margin: 0 0 0.55rem;
  }
  /* The one-line pill is ~400px; on phones stack brand over name inside a
     rounded tag instead of overflowing the column. */
  /* At 0.78rem the one-liner spills past the copy button; at 0.7rem the
     whole command fits a 390px column with no scroll. */
  .md-typeset .locus-hero__copy pre {
    font-size: 0.7rem;
  }
}

/* ===================================================================
   Mobile — code blocks. Material full-bleeds top-level blocks below
   45em, which turns the rose left rule into a stray sliver at the
   screen edge, and long lines clipped mid-token with no hint that
   they scroll. Square the blocks off, and fade sliced glyphs into
   the block background at the clipped edge: the <code> scrolls under
   a thin veil pinned to the <pre>. The veil is narrower than the
   code's own end padding, so at full scroll it covers only padding,
   never characters.
   =================================================================== */

@media screen and (max-width: 44.9375em) {
  .md-content__inner > .highlight {
    border-left: 0;
    border-radius: 0;
  }
  .md-typeset pre {
    position: relative;
  }
  .md-typeset pre::after {
    content: "";
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    width: 0.9rem;
    pointer-events: none;
    border-top-right-radius: inherit;
    border-bottom-right-radius: inherit;
    background: linear-gradient(to left, var(--tl-bg-soft) 15%, transparent);
  }
  /* The copy button sits in the veil's corner — keep it above. Material
     renamed .md-clipboard to .md-code__button; cover both. */
  .md-typeset .md-clipboard,
  .md-typeset .md-code__button {
    z-index: 1;
  }
}

/* ===================================================================
   Review pass — readable prose, execution diagram, and API wrapping.
   =================================================================== */

/* Keep long-form prose at a comfortable measure while allowing tables,
   diagrams, and API documentation to use the full article column. */
.md-typeset > p,
.md-typeset > ul,
.md-typeset > ol,
.md-typeset > blockquote {
  max-width: 48rem;
}

.md-typeset .execution-flow {
  display: grid;
  grid-template-columns: minmax(8rem, 1fr) auto minmax(9rem, 1.1fr) auto minmax(9rem, 1fr);
  gap: 0.65rem;
  align-items: center;
  max-width: 58rem;
  margin: 1.25rem 0 0.75rem;
  padding: 1rem;
  border: 1px solid var(--tl-rule);
  border-radius: 0.65rem;
  background: var(--locus-surface);
}
.execution-flow__node,
.execution-flow__audit {
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
}
.execution-flow__node,
.execution-flow__audit {
  padding: 0.75rem;
  border: 1px solid var(--tl-rule);
  border-radius: 0.45rem;
  background: var(--tl-bg-soft);
}
.execution-flow__node span,
.execution-flow__audit span {
  color: var(--locus-mute);
  font-size: 0.72rem;
}
.execution-flow__node--gate {
  border-color: var(--tl-red);
}
.execution-flow__arrow {
  color: var(--tl-red);
  font-size: 1.4rem;
  font-weight: 700;
}
.execution-flow__audit {
  grid-column: 3 / 6;
  border-style: dashed;
}

/* mkdocstrings signatures should wrap at tokens instead of forcing the API
   article to scroll horizontally as one long line. */
.md-typeset .doc-signature,
.md-typeset .doc-signature code,
.md-typeset .doc-signature .highlight,
.md-typeset .doc-signature pre {
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  word-break: normal;
}
.md-typeset .doc-signature pre {
  overflow-x: visible;
}
/* Older released docstrings contain indented examples that the Google-style
   parser exposes as paragraphs. Preserve their whitespace and present them as
   code until those releases carry fenced examples themselves. */
.md-typeset .doc details.usage > p,
.md-typeset .doc details.example > p {
  margin: 0.6rem 0;
  padding: 0.75rem 0.9rem;
  overflow-x: auto;
  white-space: pre-wrap;
  font-family: var(--locus-mono);
  font-size: 0.78rem;
  line-height: 1.55;
  background: var(--tl-bg-soft);
  border-left: 3px solid var(--tl-red);
}
.md-typeset math[display="block"] {
  margin: 1.4rem auto;
  padding: 0.8rem 1rem;
  overflow-x: auto;
  color: var(--tl-text);
  font-size: 1.08rem;
}

/* Dark-theme contrast: raise secondary copy, syntax comments (including
   docstrings and hashbang lines), and code-action icons above the subdued
   palette used by decorative chrome. */
[data-md-color-scheme="slate"] {
  --locus-mute: #B4B4BC;
  --md-default-fg-color--lighter: #A1A1AA;
}
[data-md-color-scheme="slate"] .highlight .c,
[data-md-color-scheme="slate"] .highlight .c1,
[data-md-color-scheme="slate"] .highlight .ch,
[data-md-color-scheme="slate"] .highlight .cm,
[data-md-color-scheme="slate"] .highlight .cs,
[data-md-color-scheme="slate"] .highlight .sd {
  color: #B4B4BC;
}
[data-md-color-scheme="slate"] .md-code__button,
[data-md-color-scheme="slate"] .md-clipboard {
  color: #F4F4F5;
  opacity: 0.82;
}

/* Homepage control workspace. Status colors carry a text label and symbol as
   well as hue, and the selected rule gets a visible left marker. */
.md-typeset .action-demo {
  max-width: 58rem;
  margin: 1.25rem 0 0.8rem;
  overflow: hidden;
  border: 1px solid var(--tl-rule);
  border-radius: 0.8rem;
  background: var(--locus-surface);
  box-shadow: 0 20px 50px -38px rgba(24, 24, 27, 0.45);
}
.action-demo__tabs {
  display: flex;
  flex-wrap: wrap;
  gap: var(--tl-space-2xs);
  padding: var(--tl-space-sm);
  border-bottom: 1px solid var(--tl-rule);
}
.action-demo__tabs button {
  flex: 0 1 auto;
  padding: 0.4rem 0.68rem;
  border: 1px solid transparent;
  border-radius: 0.45rem;
  color: var(--locus-mute);
  background: transparent;
  font: 600 0.72rem/1.25 var(--locus-sans);
  cursor: pointer;
}
.action-demo__tabs button:hover,
.action-demo__tabs button:focus-visible {
  color: var(--locus-ink);
  background: var(--tl-bg-soft);
}
.action-demo__tabs button[aria-selected="true"] {
  border-color: var(--tl-accent);
  color: var(--tl-accent);
  background: var(--tl-accent-subtle);
  font-weight: 700;
}
/* Keyboard focus needs its own ring: the selected-tab rule above overrides
   the focus tint, so without an outline the focused selected tab shows no
   change at all. */
.action-demo__tabs button:focus-visible {
  outline: 2px solid var(--tl-focus);
  outline-offset: 2px;
}
.action-demo__workspace {
  display: grid;
  grid-template-columns: minmax(0, 1.08fr) minmax(17rem, 0.92fr);
}
.action-demo__code {
  min-width: 0;
  border-right: 1px solid var(--tl-rule);
  background: var(--md-code-bg-color);
}
.action-demo__bar {
  display: flex;
  justify-content: space-between;
  padding: 0.55rem 0.8rem;
  border-bottom: 1px solid var(--tl-rule);
  color: var(--locus-mute);
  font: 500 0.62rem/1.3 var(--locus-mono);
}
.md-typeset .action-demo__code pre {
  margin: 0;
  padding: 0.8rem 0;
  border: 0;
  border-radius: 0;
  background: transparent;
}
.action-demo__code code > span {
  display: block;
  min-height: 1.4em;
  padding: 0 1rem;
  border-left: 3px solid transparent;
  transition: background 0.15s ease, border-color 0.15s ease;
}
/* Brand pink is correct here: this marks "look at this line", an interactive
   pointer, not a decision outcome. */
.action-demo__code code > span.is-active {
  border-left-color: var(--tl-accent);
  background: color-mix(in srgb, var(--tl-accent) 12%, transparent);
}
.action-demo__result { padding: 1rem 1.1rem; }
.action-demo__result p { min-height: 3.4em; margin: 0.7rem 0 0.9rem; }
.action-demo__status {
  display: inline-flex;
  padding: var(--tl-space-2xs) var(--tl-space-xs);
  border-radius: var(--tl-radius-pill);
  font: 700 0.7rem/1.2 var(--locus-mono);
}
/* The same status tokens the execution flow uses. These pills previously
   carried a second, different set of greens and reds, so the same decision
   was one colour in the diagram and another in the demo. The tokens flip with
   the colour scheme, so no per-scheme duplicate rules are needed.

   `revise` is the abstain case: the agent withheld rather than acted. It reads
   neutral grey on purpose — it is not a failure, and it is not a denial. */
.action-demo__status--allow {
  color: var(--tl-allow-fg);
  background: var(--tl-allow-bg);
  border: 1px solid var(--tl-allow-border);
}
.action-demo__status--hold {
  color: var(--tl-hold-fg);
  background: var(--tl-hold-bg);
  border: 1px solid var(--tl-hold-border);
}
.action-demo__status--deny {
  color: var(--tl-deny-fg);
  background: var(--tl-deny-bg);
  border: 1px solid var(--tl-deny-border);
}
.action-demo__status--abstain {
  color: var(--tl-abstain-fg);
  background: var(--tl-abstain-bg);
  border: 1px solid var(--tl-abstain-border);
}
.action-demo__result dl { margin: 0; font-size: 0.72rem; }
.action-demo__result dt {
  margin-top: 0.55rem;
  color: var(--locus-mute);
  font: 600 0.6rem/1.4 var(--locus-mono);
  letter-spacing: 0.06em;
  text-transform: uppercase;
}
.action-demo__result dd { margin: 0.08rem 0 0; overflow-wrap: anywhere; }
.md-typeset .action-demo__note {
  max-width: none;
  margin: 0;
  padding: 0.55rem 0.8rem;
  border-top: 1px solid var(--tl-rule);
  color: var(--locus-mute);
  font-size: 0.65rem;
  text-align: center;
}

@media screen and (max-width: 48em) {
  .action-demo__workspace { grid-template-columns: 1fr; }
  .action-demo__code { border-right: 0; border-bottom: 1px solid var(--tl-rule); }
}

@media screen and (max-width: 60em) {
  .md-typeset .execution-flow {
    grid-template-columns: 1fr;
  }
  .execution-flow__arrow {
    transform: rotate(90deg);
    justify-self: center;
  }
  .execution-flow__audit {
    grid-column: 1;
  }
}

/* ===================================================================
   Diagram system. Diagrams are SVG inlined by the build hook
   ({{ locus_diagram name }}), so every shape reads the live --tl-* tokens
   and follows the light/dark toggle exactly. An <img> cannot see the page's
   theme, which is why the old diagrams sat on a white card in dark mode.

   Authoring vocabulary (classes on SVG elements; see docs/diagrams/README.md):
     g.node[.primary|.allow|.hold|.deny|.abstain|.optional|.end] > rect + text
     text.sub            secondary line inside a node (mono, muted)
     path.edge[.allow|.hold|.deny|.dashed]   connector; arrowheads via marker
     text.label + rect.label-bg              edge label on a knockout
     g.store > path      datastore (cylinder)
     g.decision > polygon
     g.lane > rect + text.lane-title         grouping band
     text.note           footnote inside the figure
   Status classes always carry a text label too: colour is never the only cue.
   =================================================================== */
.md-typeset .tl-dia {
  /* Material sizes <figure> to fit-content; an SVG that is width:100% of a
     fit-content parent has nothing to resolve against and falls back to the
     browser's 300px default. Give the figure the column width instead.
     Padding is kept small: every pixel of it is taken from the drawing, whose
     labels are already at the small end of legible in a 48rem column. */
  position: relative;
  width: 100%;
  margin: var(--tl-space-xl) auto;
  max-width: 960px;
  padding: var(--tl-space-md) var(--tl-space-sm);
  border: 1px solid var(--tl-rule);
  border-radius: var(--tl-radius-lg);
  background: var(--tl-surface);
}
.md-typeset .tl-dia svg { display: block; width: 100%; height: auto; overflow: visible; }
/* geometricPrecision: the viewBox scales the text, and Chrome otherwise hints
   each glyph's advance at the unscaled size, which spaces small labels
   unevenly ("r eflection"). The page's ss01/cv11 features stay out of diagrams. */
.tl-dia svg text {
  font-family: var(--locus-sans); fill: var(--tl-text);
  text-rendering: geometricPrecision; font-feature-settings: normal;
}

.tl-dia .node rect { fill: var(--tl-bg); stroke: var(--tl-rule-strong); stroke-width: 1.5; }
.tl-dia .node text { font-size: 15px; font-weight: 600; text-anchor: middle; dominant-baseline: middle; }
.tl-dia .node text.sub {
  font-family: var(--locus-mono); font-size: 11.5px; font-weight: 500;
  fill: var(--tl-text-mute);
}
.tl-dia .node.primary rect { fill: var(--tl-accent-subtle); stroke: var(--tl-accent); stroke-width: 2; }
/* --tl-link rather than --tl-accent: on the --tl-accent-subtle fill the light
   accent measures 4.23:1, under the 4.5:1 floor for text this small. The link
   token is the same hue at 5.95:1 in light and resolves to the accent in dark
   (4.96:1), so the dark scheme is unchanged. */
.tl-dia .node.primary text { fill: var(--tl-link); }
.tl-dia .node.primary text.sub { fill: var(--tl-text-soft); }
.tl-dia .node.optional rect { stroke-dasharray: 6 4; }
.tl-dia .node.end rect { fill: var(--tl-text); stroke: var(--tl-text); }
.tl-dia .node.end text { fill: var(--tl-text-inverse); }
.tl-dia .node.end text.sub { fill: var(--tl-text-inverse); opacity: 0.75; }
.tl-dia .node.allow rect   { fill: var(--tl-allow-bg);   stroke: var(--tl-allow-border); }
.tl-dia .node.allow text   { fill: var(--tl-allow-fg); }
.tl-dia .node.hold rect    { fill: var(--tl-hold-bg);    stroke: var(--tl-hold-border); }
.tl-dia .node.hold text    { fill: var(--tl-hold-fg); }
.tl-dia .node.deny rect    { fill: var(--tl-deny-bg);    stroke: var(--tl-deny-border); }
.tl-dia .node.deny text    { fill: var(--tl-deny-fg); }
.tl-dia .node.abstain rect { fill: var(--tl-abstain-bg); stroke: var(--tl-abstain-border); }
.tl-dia .node.abstain text { fill: var(--tl-abstain-fg); }

.tl-dia .edge { fill: none; stroke: var(--tl-text-mute); stroke-width: 1.6; }
.tl-dia .edge.dashed { stroke-dasharray: 5 4; }
.tl-dia .edge.allow { stroke: var(--tl-allow-fg); }
.tl-dia .edge.hold  { stroke: var(--tl-hold-fg); }
.tl-dia .edge.deny  { stroke: var(--tl-deny-fg); }
/* An arrowhead takes the colour of the edge it ends (context-stroke), so an
   allow/hold/deny path stays coloured right up to its node. The first fill is
   the fallback for engines without marker context paint. */
.tl-dia .arrowhead { fill: var(--tl-text-mute); fill: context-stroke; }
.tl-dia .label { font-size: 12.5px; font-weight: 500; fill: var(--tl-text-soft); text-anchor: middle; dominant-baseline: middle; }
.tl-dia .label-bg { fill: var(--tl-surface); }
/* A label that sits on a lane band takes the band's colour, so the knockout
   hides the edge under it without showing as a lighter rectangle. */
.tl-dia .label-bg.on-lane { fill: var(--tl-lane-bg); }

.tl-dia .store path { fill: var(--tl-bg); stroke: var(--tl-rule-strong); stroke-width: 1.5; }
.tl-dia .decision polygon { fill: var(--tl-bg); stroke: var(--tl-rule-strong); stroke-width: 1.5; }
.tl-dia .lane rect { fill: var(--tl-lane-bg); stroke: var(--tl-rule-subtle); }
.tl-dia .lane-title {
  font-family: var(--locus-mono); font-size: 11px; font-weight: 500;
  letter-spacing: 0.08em; text-transform: uppercase; fill: var(--tl-text-mute);
}
/* 11px uppercase on the lane band: the light mute token measures 4.4:1 there,
   under the 4.5:1 floor for small text, so light uses the soft token (7:1).
   The dark mute token clears the floor on its band and is left alone. */
[data-md-color-scheme="default"] .tl-dia .lane-title { fill: var(--tl-text-soft); }
.tl-dia .note { font-size: 12.5px; fill: var(--tl-text-mute); text-anchor: middle; }

/* Card illustrations. A feature card opens with a small drawing in the
   diagram vocabulary (docs/diagrams/cards/, inlined by {{ locus_glyph … }}),
   not a generic icon. The SVGs are drawn at their display size (96×56) and
   carry no text; the classes below mirror the .tl-dia rules so a glyph themes
   with the page. The card title carries the meaning; the span is aria-hidden. */
.md-typeset .tl-glyph {
  display: block;
  width: 96px;
  margin: 0 0 0.75rem;
  line-height: 0;
}
.md-typeset .tl-glyph svg { display: block; width: 100%; height: auto; overflow: visible; }
.tl-glyph .node rect,
.tl-glyph .store path,
.tl-glyph .decision polygon { fill: var(--tl-bg); stroke: var(--tl-rule-strong); stroke-width: 1.5; }
.tl-glyph .node.primary rect,
.tl-glyph .store.primary path { fill: var(--tl-accent-subtle); stroke: var(--tl-accent); stroke-width: 1.5; }
.tl-glyph .node.optional rect { stroke-dasharray: 4 3; }
.tl-glyph .node.end rect { fill: var(--tl-text); stroke: var(--tl-text); }
.tl-glyph .node.allow rect   { fill: var(--tl-allow-bg);   stroke: var(--tl-allow-border); }
.tl-glyph .node.hold rect    { fill: var(--tl-hold-bg);    stroke: var(--tl-hold-border); }
.tl-glyph .node.deny rect    { fill: var(--tl-deny-bg);    stroke: var(--tl-deny-border); }
.tl-glyph .node.abstain rect { fill: var(--tl-abstain-bg); stroke: var(--tl-abstain-border); }
.tl-glyph .edge { fill: none; stroke: var(--tl-text-mute); stroke-width: 1.5; stroke-linecap: round; stroke-linejoin: round; }
.tl-glyph .edge.dashed { stroke-dasharray: 3 3; }
.tl-glyph .edge.allow { stroke: var(--tl-allow-fg); }
.tl-glyph .edge.hold  { stroke: var(--tl-hold-fg); }
.tl-glyph .edge.deny  { stroke: var(--tl-deny-fg); }
.tl-glyph .arrowhead { fill: var(--tl-text-mute); fill: context-stroke; }
.tl-glyph .lane rect { fill: var(--tl-lane-bg); stroke: var(--tl-rule-subtle); }
.tl-glyph .divider { fill: none; stroke: var(--tl-rule-strong); stroke-width: 1.2; stroke-dasharray: 3 3; }
.tl-glyph .dot { fill: var(--tl-text-mute); }

/* On a phone the column is ~330px, a third of a drawing's design width. The
   inline figure fits the column so the shape of the diagram is visible at a
   glance, and the drawing is read in the expand overlay, which opens it at its
   design size (docs/javascripts/diagram-zoom.js makes the whole figure tappable
   on touch screens; the Expand pill stays as the visible affordance). A pannable
   600px minimum was tried first: it showed 60% of the drawing at 9px and hid
   the rest, which is the worst of both. */
@media screen and (max-width: 48em) {
  .md-typeset .tl-dia { padding: var(--tl-space-sm) var(--tl-space-xs); }
}
.md-typeset .tl-dia--tap { cursor: zoom-in; }

/* ---------------------------------------------------------------------------
   Homepage bands and the hero bloom motif.

   The landing page is one long markdown article, so its only rhythm used to be
   heading spacing. These two pieces give it a shape without touching a word of
   the copy:

   1. `.tl-band` sections break out of the centred article column and run the
      full width of the viewport, so the page reads as bands — paper, tint,
      ink, paper, tint, paper — instead of one flat scroll.
   2. `.locus-hero__motif` puts the mark's own petal geometry behind the hero
      as a large, low-contrast outline drawing. Brand presence, not a logo
      pasted at size.
   --------------------------------------------------------------------------- */

:root {
  --tl-band-tint: #F1F1F5;
  --tl-band-deep: #131317;
}
[data-md-color-scheme="slate"] {
  --tl-band-tint: #171A21;
  --tl-band-deep: #0A0C10;
}

/* A band is 100vw wide and centred on the article column, which is itself
   centred in the viewport — so the escape is symmetric. 100vw counts the
   scrollbar, which would otherwise leave the page scrollable sideways by a few
   pixels; clipping on `.md-main` (which spans the same area) removes that
   without touching the sticky header, and `clip` rather than `hidden` means no
   new scroll container is created. */
.md-main:has(.tl-band) {
  overflow-x: clip;
}

.md-typeset .tl-band {
  position: relative;
  width: 100vw;
  max-width: 100vw;
  margin-inline: calc(50% - 50vw);
  margin-block: 0;
  padding-block: clamp(2.4rem, 5vw, 3.8rem);
}

/* Re-constrain the band's contents to the same column the unbanded sections
   use: Material's 61rem grid with its 0.8rem content inset. Keeping both
   numbers here is what makes a banded heading line up exactly with the hero
   above it. */
.md-typeset .tl-band__inner {
  max-width: 61rem;
  margin-inline: auto;
  padding-inline: 0.8rem;
}

/* `.md-typeset > p` caps prose at a readable measure. Inside a band the text is
   a grandchild, so the cap has to be restated or the banded paragraphs run the
   full 61rem while the unbanded ones stay at 48rem. */
.md-typeset .tl-band__inner > p,
.md-typeset .tl-band__inner > ul,
.md-typeset .tl-band__inner > ol,
.md-typeset .tl-band__inner > blockquote {
  max-width: 48rem;
}

/* A band opens with its own heading, so drop the heading's top margin — the
   band's padding is the spacing. */
.md-typeset .tl-band__inner > h2:first-child {
  margin-top: 0;
}

.md-typeset .tl-band--tint {
  background: var(--tl-band-tint);
  border-block: 1px solid var(--tl-rule-subtle);
}

/* The ink band carries the dark token set in BOTH colour schemes: in light mode
   that inverts it against the page, and in dark mode it simply stays dark and a
   shade deeper than the canvas. Every component inside it — the control demo,
   the execution flow, the status pills — is already token-driven, so redefining
   the tokens here is all the inversion that is needed. */
.md-typeset .tl-band--deep {
  background: var(--tl-band-deep);
  color: #F4F4F5;

  --locus-ink:         #F4F4F5;
  --locus-mute:        #B4B4BC;
  --locus-paper:       #131317;
  --locus-surface:     #1E222B;
  --locus-code-inline: #D4D4D8;

  --tl-text:           #F4F4F5;
  --tl-text-soft:      #D3D3DB;
  --tl-text-mute:      #A1A1AA;
  --tl-bg:             #131317;
  --tl-bg-soft:        #1E212A;
  --tl-surface:        #1E222B;
  --tl-surface-raised: #272C36;
  --tl-rule:           #383D49;
  --tl-rule-subtle:    #252932;
  --tl-rule-strong:    #434A56;

  /* `--tl-red` and `--tl-red-deep` are aliases resolved on `:root`, so they do
     not follow a redefined `--tl-accent` here — they have to be set too. */
  --tl-accent:        #E2715F;
  --tl-accent-hover:  #C74634;
  --tl-accent-subtle: #4A0A26;
  --tl-red:           #E2715F;
  --tl-red-deep:      #C74634;
  --tl-red-light:     #E2715F;
  --tl-link:          #E2715F;
  --tl-on-accent:     #111318;
  --tl-focus:         #E2715F;

  --tl-allow-fg:      #6EE7A8;
  --tl-allow-bg:      #0B2E1B;
  --tl-allow-border:  #15803D;
  --tl-hold-fg:       #FCD34D;
  --tl-hold-bg:       #3A2708;
  --tl-hold-border:   #B45309;
  --tl-deny-fg:       #FCA5A5;
  --tl-deny-bg:       #3B1113;
  --tl-deny-border:   #B91C1C;
  --tl-abstain-fg:    #D3D3DB;
  --tl-abstain-bg:    #252932;
  --tl-abstain-border:#434A56;

  --md-typeset-color:           #F4F4F5;
  --md-typeset-a-color:         #E2715F;
  --md-default-fg-color:        #F4F4F5;
  --md-default-fg-color--light: #D4D4D8;
  --md-code-bg-color:           #15181E;
  --md-code-fg-color:           #F4F4F5;
}

/* Headings and body text inside the ink band take the inverted ink directly:
   several base rules name `--locus-ink` at a specificity the band cannot win
   by token redefinition alone when the rule hardcodes a colour. */
.md-typeset .tl-band--deep h2,
.md-typeset .tl-band--deep h3,
.md-typeset .tl-band--deep p,
.md-typeset .tl-band--deep li,
.md-typeset .tl-band--deep dd,
.md-typeset .tl-band--deep strong {
  color: var(--locus-ink);
}
.md-typeset .tl-band--deep a {
  color: var(--tl-link);
}

/* The brand hairline that runs under the site header, reused as the ink band's
   top edge so the dark slab reads as part of the same system. */
.md-typeset .tl-band--deep::before {
  content: "";
  position: absolute;
  inset: 0 0 auto 0;
  height: 2px;
  background: var(--locus-grad);
}

/* Hero bloom — the mark's petals, opened and drawn as outlines. The hero clips
   its overflow on desktop, so the drawing bleeds off the left edge instead of
   sitting in a box. */
.locus-hero__motif {
  position: absolute;
  z-index: -2;
  /* Anchored to the hero's bottom-left corner and mostly clipped by it, so
     what shows is the upper sweep of the petals in the sparse area beside the
     install chip — never a watermark behind the headline. */
  bottom: -15rem;
  left: -11rem;
  width: min(32rem, 52vw);
  aspect-ratio: 1;
  transform: rotate(-12deg);
  background: none;  /* the former petal motif; the Oracle mark carries no decorative bloom */
  opacity: 0.13;
  pointer-events: none;
}
[data-md-color-scheme="slate"] .locus-hero__motif {
  opacity: 0.2;
}

@media (max-width: 76em) {
  /* The stacked hero switches to `overflow: visible` so the code column can
     breathe; `clip` on the inline axis alone keeps the motif from adding a few
     pixels of sideways scroll without re-clipping the vertical overflow.
     (`clip` + `visible` is the one legal mixed pair.) */
  .md-typeset .locus-hero {
    overflow-x: clip;
    overflow-y: visible;
  }
  .locus-hero__motif {
    bottom: auto;
    top: -2rem;
    left: auto;
    right: -4.5rem;
    width: 13rem;
    transform: rotate(-12deg);
    opacity: 0.1;
  }
  [data-md-color-scheme="slate"] .locus-hero__motif {
    opacity: 0.14;
  }
}

@media (max-width: 48em) {
  .md-typeset .tl-band {
    padding-block: 2rem;
  }
  .locus-hero__motif {
    right: -5rem;
    width: 10rem;
  }
}

/* ===================================================================
   Oracle brand — carried over from the original Locus site.
   The header keeps the OCI rounded-O mark and the Oracle wordmark next to
   the locus mark, the right slot keeps the GitHub link and PyPI badge, and
   the footer keeps the Oracle wordmark; everything else on the page takes
   the newer styles above.
   =================================================================== */
.md-header__source:has(> .md-header__oci) {
  display: flex !important;
  align-items: center;
  flex-direction: row;
  gap: 0.25rem;
  width: auto;
  max-width: none;
}

.md-header__source.md-header__oci {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.35rem 0.55rem;
  margin-right: 0;
  margin-left: 0.3rem;
  border-radius: 7px;
  transition: background-color 0.15s, transform 0.15s, box-shadow 0.15s;
}

.md-header__source.md-header__oci:hover {
  background-color: rgba(199, 70, 52, 0.08);
  transform: translateY(-1px);
  box-shadow: 0 2px 8px -2px rgba(199, 70, 52, 0.25);
}

.md-header__oci-mark {
  width: 32px;
  height: 32px;
  display: block;
  flex: 0 0 auto;
}

.md-header__oracle-wordmark {
  height: 22px;
  width: auto;
  aspect-ratio: 109.36 / 22.96;
  display: block;
  flex: 0 0 auto;
}

@media (max-width: 60em) {
  /* Tighten header inner padding so logo + hamburger + title + icons fit. */
  .md-header__inner {
    padding-left: 0.5rem;
    padding-right: 0.5rem;
  }
  /* Scale the locus mark down on narrow screens. */
  .md-header__button.md-logo img,
  .md-header__button.md-logo svg {
    height: 1.6rem;
    max-height: 28px;
  }
  /* Show Oracle mark at reduced size; hide wordmark. */
  .md-header__oracle-wordmark { display: none; }
  .md-header__oci-mark { width: 20px; height: 20px; }
  .md-header__source.md-header__oci { padding: 0.2rem 0.3rem; }
}

.md-header__source.md-header__pypi {
  display: inline-flex;
  align-items: center;
  margin-left: 0.4rem;
  padding: 0;
  border-radius: 4px;
  transition: transform 0.15s;
}

.md-header__source.md-header__pypi:hover {
  transform: translateY(-1px);
}

@media (max-width: 60em) {
  .md-header__source.md-header__pypi { margin-left: 0.25rem; }
}

.md-nav--primary .md-header__source.md-header__github:hover {
  color: #FFFFFF;
  opacity: 0.8;
}

.md-drawer .md-header__source .md-header__oracle-wordmark {
  opacity: 0.85;
  filter: brightness(0) invert(1);
}

.footer-brand__o {
  display: inline-block;
  width: 22px;
  height: 22px;
  background-image: url("../img/oci-mark.svg");
  background-size: contain;
  background-position: center;
  background-repeat: no-repeat;
  flex: 0 0 auto;
}

.oracle-mark {
  display: inline-block;
  height: 14px;
  aspect-ratio: 109.36 / 22.96;
  width: auto;
  min-width: 66.7px;
  background-image: url("../img/oracle.svg");
  background-position: left center;
  background-repeat: no-repeat;
  background-size: contain;
  filter: brightness(0) invert(1) opacity(0.85);
  vertical-align: middle;
}

[data-md-color-scheme="slate"] .md-header__oracle-wordmark {
  content: url("../img/oracle-white.svg");
}

[data-md-color-scheme="slate"] .oracle-mark {
  background-image: url("../img/oracle-white.svg");
  filter: none;
}

@media (max-width: 30em) {
  /* Drop the tagline and the PyPI badge to free up room on small phones. */
  .md-header__ellipsis > .md-header__topic:first-of-type::after { display: none; }
  .md-header__source.md-header__pypi { display: none; }
  .md-header__ellipsis > .md-header__topic:first-of-type > .md-ellipsis {
    font-size: 1.1rem;
  }
  /* Tighter spacing between right-rail icons. */
  .md-header__source.md-header__oci { margin-left: 0.15rem; padding: 0.15rem 0.25rem; }
  .md-header__source.md-header__github { margin-left: 0.2rem; }
}

/* ---------------------------------------------------------------------------
   Model chips on the home page ("Oracle Cloud, native"): small pills with
   a check mark. Both schemes read from the palette vars.
   --------------------------------------------------------------------------- */
.md-typeset .locus-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem 0.45rem;
  margin: 0.5rem 0 1rem;
  padding: 0;
  list-style: none;
}
.md-typeset .locus-chips span,
.md-typeset .locus-chips li {
  margin: 0;
  padding: 0.22rem 0.65rem 0.22rem 0.5rem;
  border: 1px solid var(--tl-rule);
  border-radius: 999px;
  font-family: var(--locus-mono);
  font-size: 0.66rem;
  line-height: 1.4;
  color: var(--locus-ink);
  background: var(--md-default-bg-color);
}
.md-typeset .locus-chips span::before,
.md-typeset .locus-chips li::before {
  content: "✓";
  margin-right: 0.4rem;
  font-weight: 700;
  color: var(--tl-red);
}
.md-typeset .locus-chips li.is-partial::before { content: "◐"; }
/* Provider-prefix chips: the string you type, no check mark. */
.md-typeset .locus-chips--prefixes span::before { content: none; }
.md-typeset .locus-chips--prefixes span { font-family: var(--locus-mono); }
.md-typeset .locus-chips__vendor {
  margin: 0.6rem 0 0.1rem;
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--locus-mute);
}

/* ===================================================================
   Facts row — build facts, requirements and catalogue status as a row of
   small tiles instead of a two-column key/value table. Markup:
     <dl class="locus-facts" markdown="block">
       <div markdown="block"><dt>Label</dt><dd markdown="span">Value</dd></div>
     </dl>
   Tiles wrap on narrow screens; labels are the tagline pattern, values are
   body text. Status colours are not used here: these are facts, not decisions.
   =================================================================== */
.md-typeset dl.locus-facts {
  display: flex;
  flex-wrap: wrap;
  gap: var(--tl-space-xs) var(--tl-space-sm);
  margin: var(--tl-space-md) 0 var(--tl-space-lg);
}
.md-typeset dl.locus-facts > div {
  flex: 1 1 11rem;
  min-width: 0;
  margin: 0;
  padding: var(--tl-space-xs) var(--tl-space-sm);
  border: 1px solid var(--tl-rule);
  border-radius: var(--tl-radius-md);
  background: var(--tl-surface);
}
.md-typeset dl.locus-facts dt {
  margin: 0 0 2px;
  font-size: 0.6rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--tl-text-mute);
}
.md-typeset dl.locus-facts dd {
  margin: 0;
  font-size: 0.72rem;
  line-height: 1.45;
  color: var(--tl-text);
}
.md-typeset dl.locus-facts dd code { font-size: 0.66rem; }

/* ===================================================================
   Copy page — the button docs/javascripts/copy-page.js adds beside the
   page title. It copies the page's Markdown twin (…/index.md, written by
   hooks/llms_txt.py) and offers the raw file and llms.txt in a menu. Floats
   right next to Material's edit/view icons.
   =================================================================== */
.md-content__inner .locus-copy-page {
  position: relative;
  float: right;
  display: inline-flex;
  align-items: stretch;
  margin: 0.45rem 0 0.4rem 0.6rem;
  font-family: var(--locus-sans);
}
.locus-copy-page__btn,
.locus-copy-page__more {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  margin: 0;
  padding: 0.28rem 0.6rem;
  border: 1px solid var(--tl-rule);
  background: var(--tl-surface);
  color: var(--tl-text-soft);
  font: 600 0.62rem/1.2 var(--locus-sans);
  cursor: pointer;
  transition: border-color 0.15s ease, color 0.15s ease, background 0.15s ease;
}
.locus-copy-page__btn { border-radius: var(--tl-radius-pill) 0 0 var(--tl-radius-pill); }
.locus-copy-page__more { border-left: 0; border-radius: 0 var(--tl-radius-pill) var(--tl-radius-pill) 0; padding: 0.28rem 0.45rem; }
.locus-copy-page__btn:hover, .locus-copy-page__more:hover,
.locus-copy-page__btn:focus-visible, .locus-copy-page__more:focus-visible {
  border-color: var(--tl-accent);
  color: var(--tl-accent);
  outline: none;
}
.locus-copy-page__btn svg, .locus-copy-page__more svg { width: 0.8rem; height: 0.8rem; fill: currentColor; }
.locus-copy-page__btn.is-done { border-color: var(--tl-allow-border); color: var(--tl-allow-fg); background: var(--tl-allow-bg); }
.locus-copy-page__btn.is-failed { border-color: var(--tl-deny-border); color: var(--tl-deny-fg); background: var(--tl-deny-bg); }
.md-typeset .locus-copy-page__menu {
  position: absolute;
  top: calc(100% + 0.3rem);
  right: 0;
  z-index: 4;
  min-width: 11rem;
  margin: 0;
  padding: 0.3rem;
  list-style: none;
  border: 1px solid var(--tl-rule);
  border-radius: var(--tl-radius-md);
  background: var(--tl-surface);
  box-shadow: 0 12px 32px -12px rgba(20, 16, 24, 0.35);
}
.md-typeset .locus-copy-page__menu[hidden] { display: none; }
.md-typeset .locus-copy-page__menu li { margin: 0; padding: 0; }
.md-typeset .locus-copy-page__menu a {
  display: block;
  padding: 0.4rem 0.7rem;
  border-radius: var(--tl-radius-sm);
  color: var(--tl-text);
  font-size: 0.66rem;
  text-decoration: none;
}
.md-typeset .locus-copy-page__menu a:hover,
.md-typeset .locus-copy-page__menu a:focus-visible { background: var(--tl-accent-subtle); color: var(--tl-accent); outline: none; }
/* Material's own content buttons float right too; keep the cluster aligned. */
.md-content__inner > .md-content__button { margin-top: 0.45rem; }

/* Identifiers in table cells never break mid-token. Material's code spans use
   word-break: break-word, which turned `SlidingWindowManager` into four
   fragments in a narrow column. Breaking only at spaces keeps every token
   whole while a multi-word snippet can still wrap, so a table only scrolls
   when a single token is wider than its column. */
.md-typeset table:not([class]) code {
  white-space: normal;
  word-break: normal;
  overflow-wrap: normal;
}

/* The landing page is a marketing page: no edit/view-source icons over the hero. */
.md-content__inner:has(> .locus-hero) > .md-content__button,
.md-content__inner:has(> div > .locus-hero) > .md-content__button { display: none; }

/* ===================================================================
   Page width. Material's 61rem grid leaves a 43rem article column once both
   sidebars are open, which rendered a 940-unit diagram at two-thirds scale and
   pushed four-column tables into horizontal scroll. 68rem fits a 1280px laptop
   with room to spare and gives the column about 50rem.
   =================================================================== */
.md-grid { max-width: 68rem; }

/* ===================================================================
   Diagram expand. docs/javascripts/diagram-zoom.js adds an "Expand" button to
   every inlined diagram and opens a copy of the SVG in a full-width overlay on
   click, so a dense drawing can be read at full size without widening the page.
   The overlay reuses the figure styling, so it themes with the scheme.
   =================================================================== */
.md-typeset .tl-dia__expand {
  position: absolute;
  top: 0.45rem;
  right: 0.45rem;
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  padding: 0.22rem 0.5rem;
  border: 1px solid var(--tl-rule);
  border-radius: var(--tl-radius-pill);
  background: var(--tl-surface);
  color: var(--tl-text-mute);
  font: 600 0.6rem/1.2 var(--locus-sans);
  cursor: zoom-in;
  opacity: 0;
  transition: opacity 0.15s ease, color 0.15s ease, border-color 0.15s ease;
}
.md-typeset .tl-dia:hover .tl-dia__expand,
.md-typeset .tl-dia__expand:focus-visible { opacity: 1; outline: none; }
.md-typeset .tl-dia__expand:hover, .md-typeset .tl-dia__expand:focus-visible { color: var(--tl-accent); border-color: var(--tl-accent); }
.md-typeset .tl-dia__expand svg { width: 0.75rem; height: 0.75rem; fill: currentColor; }
@media (hover: none) { .md-typeset .tl-dia__expand { opacity: 1; } }

.tl-dia-overlay {
  position: fixed;
  inset: 0;
  z-index: 50;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 2rem;
  background: rgba(17, 19, 24, 0.72);
  backdrop-filter: blur(2px);
  cursor: zoom-out;
}
.tl-dia-overlay__panel {
  width: min(96vw, 1480px);
  max-height: 92vh;
  overflow: auto;
  padding: var(--tl-space-lg);
  border: 1px solid var(--tl-rule);
  border-radius: var(--tl-radius-lg);
  background: var(--tl-surface);
  box-shadow: 0 24px 80px -24px rgba(0, 0, 0, 0.6);
  cursor: default;
}
.tl-dia-overlay__panel svg { display: block; width: 100%; height: auto; }
.tl-dia-overlay__panel svg text { font-family: var(--locus-sans); fill: var(--tl-text); text-rendering: geometricPrecision; }
.tl-dia-overlay__close {
  position: fixed;
  top: 1rem;
  right: 1.25rem;
  padding: 0.4rem 0.8rem;
  border: 1px solid var(--tl-rule);
  border-radius: var(--tl-radius-pill);
  background: var(--tl-surface);
  color: var(--tl-text);
  font: 600 0.68rem/1.2 var(--locus-sans);
  cursor: pointer;
}
/* The overlay panel is outside .tl-dia, so give it the same diagram classes. */
.tl-dia-overlay__panel .node rect { fill: var(--tl-bg); stroke: var(--tl-rule-strong); stroke-width: 1.5; }

/* Inside the expand overlay the figure rules still apply (the panel carries
   .tl-dia and .md-typeset); lift the inline width cap so the drawing fills it. */
.md-typeset.tl-dia-overlay__panel { max-width: none; margin: 0; }

/* Feature-card grids stay three across. Material sizes grid cards from a 16rem
   minimum, which on the wider page grid flows nine cards as 4 + 4 + 1 and
   leaves one card alone on its row; a 19rem minimum gives three columns on a
   desktop landing page and still collapses to two and one on narrow screens. */
.md-typeset .grid.cards.locus-feature-cards {
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 19rem), 1fr));
}

/* The H1 permalink is the page's own URL and is invisible until hover, but it
   still takes a slot at the end of the title line; on a title that fills the
   column it wraps alone onto a second, empty-looking line. Drop it on H1 only. */
.md-typeset h1 .headerlink { display: none; }

/* ===================================================================
   Table filter — docs/javascripts/table-filter.js adds a search box above
   any article table with fifteen or more rows (event catalogues, environment
   variables, backend comparisons). Same field styling as the Examples filter.
   =================================================================== */
.md-typeset .locus-table-filter {
  display: flex;
  align-items: center;
  gap: var(--tl-space-sm);
  margin: var(--tl-space-md) 0 var(--tl-space-xs);
}
.md-typeset .locus-table-filter__input {
  flex: 1 1 auto;
  min-width: 0;
  padding: 0.45rem 0.8rem;
  font: inherit;
  font-size: 0.72rem;
  color: var(--tl-text);
  background: var(--tl-surface);
  border: 1px solid var(--tl-rule);
  border-radius: var(--tl-radius-md);
  transition: border-color 120ms, box-shadow 120ms;
}
.md-typeset .locus-table-filter__input:focus {
  outline: none;
  border-color: var(--tl-accent);
  box-shadow: 0 0 0 3px var(--tl-accent-subtle);
}
.md-typeset .locus-table-filter__count {
  flex: 0 0 auto;
  font-size: 0.66rem;
  color: var(--tl-text-mute);
  font-variant-numeric: tabular-nums;
}

/* Catalogue filter: rows and sections it hides, and a legible placeholder in
   both schemes (the browser default is too faint on the dark surface). */
.locus-filter-hidden { display: none !important; }
.md-typeset .locus-table-filter__input::placeholder,
.notebook-filter__input::placeholder { color: var(--tl-text-mute); opacity: 1; }


/* ===================================================================
   Mobile pass. Everything below applies to phones and tablets only (the
   drawer breakpoint, 60em, and the one-column breakpoint, 48em) or to touch
   screens (hover: none). Desktop layout is untouched.
   =================================================================== */

/* Header: 80px of a 844px screen was the sticky header. 56px holds the mark
   (28px) and the wordmark (24px) with room to spare, like a native app bar. */
@media (max-width: 60em) {
  .md-header__inner {
    min-height: 2.8rem;
    padding-top: 0.25rem;
    padding-bottom: 0.3rem;
  }
}

/* Inputs: iPhone Safari zooms the page when a focused field is under 16px and
   leaves it zoomed. Every filter field is 16px below the drawer breakpoint
   (Material's own search field already is). */
@media (max-width: 60em) {
  .sidebar-filter__input,
  .notebook-filter__input,
  .md-typeset .locus-table-filter__input {
    font-size: 0.8rem;
  }
}

/* Title row: the Copy page group and Material's view/edit icons float right
   of the H1 and took 212px of a 358px column, so "Capabilities" broke as
   "Capabilitie / s" and most titles ran to two or three lines. On one-column
   screens the actions sit on their own row above the title and the title gets
   the full column. */
@media (max-width: 48em) {
  .md-content__inner > h1,
  .md-content__inner > .md-typeset > h1 {
    clear: both;
  }
  .md-content__inner .locus-copy-page {
    margin: 0 0 0.9rem 0.5rem;
  }
  .md-content__inner > .md-content__button {
    margin-top: 0;
    margin-bottom: 0.9rem;
  }
}

/* Touch targets. Material's code copy button is 1.5em (20px) and the diagram
   Expand pill was 26px tall; both grow to a finger-sized box on touch screens
   without moving anything on a pointer device. */
@media (hover: none) {
  .md-typeset .md-code__button {
    width: 2.2em;
    height: 2.2em;
  }
  .md-typeset .md-code__button::after {
    width: 1.3em;
    height: 1.3em;
  }
  .md-typeset .tl-dia__expand {
    padding: 0.45rem 0.8rem;
    font-size: 0.66rem;
    top: 0.5rem;
    right: 0.5rem;
  }
  .md-typeset .tl-dia__expand svg { width: 0.85rem; height: 0.85rem; }
  /* The always-visible pill sat on the drawing's top-right corner and hid a
     node there on some pages; on touch the figure reserves a band for it. */
  .md-typeset .tl-dia--tap {
    padding-top: 2.9rem;
  }
}

/* Diagram overlay. The panel was 96vw with the drawing scaled to fit, which on
   a phone made the expanded drawing smaller than the inline one (260px against
   600px). The clone now carries its design width as a minimum (set by
   diagram-zoom.js from the viewBox), so on a phone or a tablet the overlay
   shows the drawing at the size it was designed at and pans in both axes;
   pinch zoom still works because the overlay is in the page. On one-column
   screens the panel is the whole screen, and the page behind does not scroll
   while it is open. */
.tl-dia-overlay__panel {
  overscroll-behavior: contain;
}
html.tl-dia-open,
html.tl-dia-open body {
  overflow: hidden;
}
@media (max-width: 48em) {
  .tl-dia-overlay {
    padding: 0;
    align-items: stretch;
  }
  .tl-dia-overlay__panel {
    display: grid;
    align-content: center;
    justify-items: start;
    width: 100vw;
    height: 100vh;
    height: 100dvh;
    max-height: none;
    padding: 3.4rem var(--tl-space-sm) var(--tl-space-lg);
    border: 0;
    border-radius: 0;
  }
  .tl-dia-overlay__close {
    top: 0.6rem;
    right: 0.6rem;
    min-height: 2.2rem;
    padding: 0.5rem 1rem;
    font-size: 0.75rem;
  }
}

/* Stacked tables. A table with three or more columns that cannot give each
   column a readable width on a one-column screen is shown as a list of rows
   (docs/javascripts/mobile-tables.js sets data-stack after measuring, and
   copies each header into data-label). The first cell is the row's title, the
   other cells carry their column header as a small caption, so the event
   catalogues, the capability matrix and the API parameter tables read as cards
   instead of five-word-wide columns with broken words. Two-column tables and
   short matrices stay tables. */
@media (max-width: 48em) {
  .md-typeset__scrollwrap:has(> .md-typeset__table > table[data-stack]) {
    margin-left: 0;
    margin-right: 0;
    overflow: visible;
  }
  .md-typeset__table:has(> table[data-stack]) {
    padding: 0;
  }
  .md-typeset table[data-stack] {
    display: block;
    width: 100%;
    border: 0;
    border-radius: 0;
    background: transparent;
    font-size: 0.74rem;
    overflow: visible;
  }
  .md-typeset table[data-stack] > thead {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
  }
  .md-typeset table[data-stack] > thead > tr,
  .md-typeset table[data-stack] > thead th {
    display: block;
    width: 1px;
    padding: 0;
  }
  .md-typeset table[data-stack] > tbody {
    display: block;
  }
  .md-typeset table[data-stack] > tbody > tr {
    display: block;
    margin: 0 0 var(--tl-space-xs);
    padding: var(--tl-space-xs) var(--tl-space-sm) var(--tl-space-sm);
    border: 1px solid var(--tl-rule);
    border-radius: var(--tl-radius-md);
    background: var(--tl-surface);
  }
  .md-typeset table[data-stack] > tbody > tr:nth-child(even) {
    background: var(--tl-surface);
  }
  .md-typeset table[data-stack] td {
    display: block;
    min-width: 0;
    padding: 0.2rem 0 0;
    border: 0;
    line-height: 1.5;
    overflow-wrap: anywhere;
  }
  /* A card is as wide as the column, so an endpoint URL or a long variable
     name in a code span has to break rather than push the page sideways. */
  .md-typeset table[data-stack] td code {
    white-space: normal;
    /* break-word: a chip breaks at its <wbr> separators first and only
       mid-token when a segment has none. */
    overflow-wrap: break-word;
  }
  .md-typeset table[data-stack] td:empty {
    display: none;
  }
  .md-typeset table[data-stack] td::before {
    content: attr(data-label);
    display: block;
    margin-bottom: 2px;
    font-size: 0.6rem;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--tl-text-mute);
  }
  .md-typeset table[data-stack] td:first-child {
    padding: 0 0 0.3rem;
    margin-bottom: 0.15rem;
    border-bottom: 1px solid var(--tl-rule-subtle);
    font-size: 0.8rem;
    font-weight: 600;
  }
  .md-typeset table[data-stack] td:first-child::before {
    display: none;
  }
  .md-typeset table[data-stack] td:first-child code {
    font-size: 0.85em;
  }
  /* A table whose first column is sentences (a comparison, a symptom list)
     has no name column: both cells keep their captions and neither is the
     title, so the first header is not lost. */
  .md-typeset table[data-stack][data-first-long="1"] td:first-child {
    padding: 0.2rem 0 0;
    margin-bottom: 0;
    border-bottom: 0;
    font-size: inherit;
    font-weight: inherit;
  }
  .md-typeset table[data-stack][data-first-long="1"] td:first-child::before {
    display: block;
  }
}

/* Admonitions and details are 12.8px in Material at every width, which on a
   phone is the smallest text on the page apart from captions. 14px below the
   drawer breakpoint; the desktop size is unchanged. */
@media (max-width: 60em) {
  .md-typeset .admonition,
  .md-typeset details {
    font-size: 0.7rem;
  }
}

/* The PyPI badge in the tablet header is a 16px-tall image; the link around
   it gets the vertical padding a finger needs. */
@media (max-width: 60em) {
  .md-header__source.md-header__pypi {
    padding-top: 0.5rem;
    padding-bottom: 0.5rem;
  }
}

/* Smaller touch-screen details: the file name in a collapsed source block's
   summary, the copyright line's Legal link and Material's tab-strip scroll
   arrows all get a readable size or a finger-sized hit area on phones. */
@media (max-width: 60em) {
  .md-typeset details > summary code {
    font-size: 0.9em;
  }
}
@media (hover: none) {
  .md-footer-meta .footer-copy a {
    display: inline-block;
    padding: 0.5rem 0.25rem;
    margin: -0.5rem -0.25rem;
  }
  .md-typeset .tabbed-button {
    width: 1.4rem;
    height: 1.4rem;
  }
  /* The larger copy button needs more clearance in the hero's install chip,
     or it covers the closing quote of the command. */
  .md-typeset .locus-hero__copy pre {
    padding-right: 3rem;
  }
}

/* Dark scheme: the holder behind the code copy button is a translucent light
   square on the dark code background; on touch, where the button is larger,
   it read as a lighter box in the corner of every block. Same token as the
   block, so only the icon shows. */

/* Headings on a phone wrap to two or three lines; balanced wrapping stops a
   parenthesis or a short last word being left alone on the final line.
   Browsers without text-wrap: balance ignore the rule. */
@media (max-width: 60em) {
  .md-typeset h1,
  .md-typeset h2,
  .md-typeset h3 {
    text-wrap: balance;
  }
}

/* ===================================================================
   Mobile pass, round three: what the page-by-page review of the first
   round's build found.
   =================================================================== */

/* Code copy button. Material renamed .md-clipboard to .md-code__button, so
   the resting colour fix above never applied: the icon sat at 1.5:1 on the
   block. Same tokens as the old rule. */
.md-typeset .md-code__button {
  color: var(--md-default-fg-color--lighter);
  opacity: 1;
}
.md-typeset .md-code__button:hover,
.md-typeset .md-code__button:focus-visible {
  color: var(--tl-red);
}
[data-md-color-scheme="slate"] .md-typeset .md-code__button {
  color: var(--md-default-fg-color--light);
}
/* The holder behind the button is translucent, so on touch, where the button
   is always visible and larger, code glyphs showed through the icon in light
   and a lighter square sat in the corner in dark. The holder takes the block
   colour with a soft left edge, so a long first line fades under it like the
   right-edge veil and nothing is drawn through the icon. */
@media (hover: none) {
  .md-typeset .md-code__nav {
    top: 0.15em;
    right: 0.15em;
    padding: 0.15rem;
    background-color: var(--tl-bg-soft);
    box-shadow: -0.9rem 0 0.9rem -0.3rem var(--tl-bg-soft);
    border-radius: 0.2rem;
  }
  .md-typeset .md-code__button {
    width: 2em;
    height: 2em;
  }
  /* Code ends before the button's column: a line that fits the block is
     never under the holder (the opaque holder would otherwise hide the end
     of a short command for good), a wrapped output or signature line wraps
     before it, and a line longer than the block still scrolls under the
     fade and comes out when panned. */
  .md-typeset pre > code {
    padding-right: 2.6rem;
  }
  .md-typeset .doc-signature pre > code {
    padding-right: 3rem;
  }
}

/* Heading permalinks are revealed on hover, which a touch screen has not got;
   the invisible glyph still took an inline slot and, when a title filled the
   column, wrapped alone onto a blank second line between the text and the
   rule. Hidden below the drawer breakpoint, as the H1's already was. */
@media (hover: none), (max-width: 60em) {
  .md-typeset h2 .headerlink,
  .md-typeset h3 .headerlink,
  .md-typeset h4 .headerlink,
  .md-typeset h5 .headerlink,
  .md-typeset h6 .headerlink {
    display: none;
  }
}

/* Inline code inside admonitions and details inherits 0.85em of their 14px
   phone size, 11.9px; the identifiers a note is made of get the 12px floor. */
@media (max-width: 60em) {
  .md-typeset .admonition code,
  .md-typeset details code {
    font-size: 0.9em;
  }
}

/* Inline code in prose and lists: a long identifier that wraps is one chip
   across the break instead of two pills, and docs/hooks/inline_code_breaks.py
   gives it break opportunities at its separators so the browser does not cut
   it at an arbitrary letter. Code in table cells stays whole; when a chip is
   wider than the table can afford, mobile-tables.js lets the table's code wrap
   (data-wrap-code) and, if that is not enough, stacks the table. */
@media (max-width: 60em) {
  .md-typeset :not(pre) > code {
    -webkit-box-decoration-break: slice;
    box-decoration-break: slice;
  }
}
@media (max-width: 48em) {
  .md-typeset table:not([class]):not([data-stack]) td code {
    white-space: nowrap;
  }
  .md-typeset table[data-wrap-code]:not([data-stack]) td code {
    white-space: normal;
    /* break-word, so a chip breaks at the <wbr> separators the build hook
       inserts and only mid-token when a segment has none. */
    overflow-wrap: break-word;
  }
}

/* Stacked cards: a header that is a code identifier keeps its case and
   face as a caption; a cell holding only a dash reads inline after its
   caption; a table whose first column is a one- or two-character index shows
   that index as a chip and uses the second cell as the card title. */
@media (max-width: 48em) {
  .md-typeset table[data-stack] td[data-label-code]::before {
    font-family: var(--locus-mono);
    text-transform: none;
    letter-spacing: 0;
  }
  .md-typeset table[data-stack] td[data-dash] {
    display: flex;
    gap: 0.4rem;
    align-items: baseline;
  }
  .md-typeset table[data-stack] td[data-dash]::before {
    margin-bottom: 0;
  }
  .md-typeset table[data-stack][data-index-col] td:first-child {
    display: inline-block;
    margin: 0 0 0.3rem;
    padding: 0 0.45rem;
    border: 1px solid var(--tl-rule);
    border-radius: var(--tl-radius-pill);
    font-family: var(--locus-mono);
    font-size: 0.62rem;
    font-weight: 600;
    line-height: 1.7;
    color: var(--tl-text-mute);
  }
  .md-typeset table[data-stack][data-index-col] td:nth-child(2) {
    padding: 0 0 0.3rem;
    margin-bottom: 0.15rem;
    border-bottom: 1px solid var(--tl-rule-subtle);
    font-size: 0.8rem;
    font-weight: 600;
  }
  .md-typeset table[data-stack][data-index-col] td:nth-child(2)::before {
    display: none;
  }
}

/* Program output on a phone: a banner or rule line printed at sixty columns
   is clipped to the line instead of wrapping into a stub (output-blocks.js
   marks them), wrapped lines keep a hanging indent so a continuation reads as
   one, and a column-aligned block scrolls instead of wrapping (the script sets
   white-space: pre on it). The GSAR piecewise definition and the posture
   report are the aligned cases. */
@media (max-width: 48em) {
  .md-typeset .language-text pre > code > span[id^="__span"] {
    display: block;
    padding-left: 2ch;
    text-indent: -2ch;
  }
  .md-typeset .language-text pre > code > span.tl-out-rule {
    overflow: hidden;
    white-space: nowrap;
    text-overflow: clip;
  }
  .md-typeset .language-text pre > code.tl-out-aligned {
    white-space: pre;
    overflow-x: auto;
  }
  .md-typeset .language-text pre > code.tl-out-aligned > span[id^="__span"] {
    padding-left: 0;
    text-indent: 0;
  }
}

/* Block math scales to the phone column instead of clipping its right end. */
@media (max-width: 36em) {
  .md-typeset math[display="block"] {
    font-size: 0.9rem;
    padding: 0.6rem 0.25rem;
  }
}

/* The hero's install command wraps on small phones instead of running under
   the copy button: at the space, with the quoted package name kept whole. */
@media (max-width: 36em) {
  .md-typeset .locus-hero__copy pre > code {
    white-space: pre-wrap;
    overflow-wrap: normal;
  }
  .md-typeset .locus-hero__copy pre > code .s2 {
    white-space: nowrap;
  }
}

/* Link rows on the home page: each link stays on one line, so a row wraps
   between links and the arrow never starts a line on its own. */
.md-typeset .locus-links a {
  display: inline-block;
  white-space: nowrap;
}

/* Docstring example fallback paragraphs match the code size and never
   break an identifier or ligate an arrow. */
.md-typeset .doc details.usage > p,
.md-typeset .doc details.example > p {
  font-size: 0.66rem;
  word-break: normal;
  overflow-wrap: normal;
  font-variant-ligatures: none;
  font-feature-settings: "kern";
}

/* Page top on phones: the action row sat in a 50px void under the header and
   the title started 97px below it. Tighter margins bring the title to about
   60px under the header while the actions keep their own row. */
@media (max-width: 48em) {
  .md-main__inner {
    margin-top: 0.6rem;
  }
  .md-content__inner {
    padding-top: 0;
  }
  .md-content__inner .locus-copy-page {
    margin-bottom: 0.5rem;
  }
  .md-content__inner > .md-content__button {
    margin-bottom: 0.5rem;
  }
}

/* Header controls on phones: the Oracle mark and the home mark get the same
   40px box as Material's own buttons; the tagline is 12px rather than 10px
   where it is shown (481px to 896px). */
@media (max-width: 60em) {
  .md-header__source.md-header__oci,
  .md-header__button.md-logo {
    min-width: 2rem;
    min-height: 2rem;
    display: inline-flex;
    align-items: center;
    justify-content: center;
  }
}
@media (max-width: 56em) and (min-width: 30.0625em) {
  .md-header__ellipsis > .md-header__topic:first-of-type::after {
    font-size: 0.6rem;
    letter-spacing: 0.05em;
  }
}

/* Drawer: every level's title takes the surface, ink and red hairline the
   root level already had, instead of Material's grey slab. */
@media (max-width: 76.1875em) {
  .md-nav--primary .md-nav__title {
    background-color: var(--locus-surface);
    color: var(--locus-ink);
    border-bottom: 2px solid var(--tl-red);
    box-shadow: none;
  }
  .md-nav--primary .md-nav__title .md-nav__button,
  .md-nav--primary .md-nav__title .md-nav__icon {
    color: var(--locus-ink);
  }
}

/* Footer on phones: the Next title wraps instead of truncating, the social
   icons get finger-sized boxes, and the copyright line clears AA. */
.md-footer-meta .md-copyright,
.md-footer-meta .footer-copy {
  color: rgba(255, 255, 255, 0.8);
}
@media (max-width: 44.9375em) {
  .md-footer__link--next .md-footer__title,
  .md-footer__link--next .md-ellipsis {
    white-space: normal;
  }
}
@media (hover: none) {
  .md-social {
    gap: 0.4rem;
  }
  .md-social__link {
    display: inline-flex;
    width: 2.2rem;
    height: 2.2rem;
    align-items: center;
    justify-content: center;
  }
}

/* Code blocks inside content tabs take the same full-bleed treatment as
   top-level blocks on phones, so one page does not show two code styles. */
@media screen and (max-width: 44.9375em) {
  .md-typeset .tabbed-block > .highlight,
  .md-typeset .tabbed-block > .highlighttable {
    margin-left: -0.8rem;
    margin-right: -0.8rem;
    border-left: 0;
    border-radius: 0;
  }
}

/* Notebook filter placeholder ends in an ellipsis rather than mid-word. */
.notebook-filter__input {
  text-overflow: ellipsis;
}

/* Diagram overlay: when the drawing pans, a line pinned to the bottom of the
   screen says so (outside the panel, so it does not scroll with the drawing). */
.tl-dia-overlay__hint {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  margin: 0;
  padding: 0.5rem 1rem 0.9rem;
  font: 500 0.66rem/1.4 var(--locus-sans);
  color: var(--tl-text-mute);
  text-align: center;
  background: var(--tl-surface);
  pointer-events: none;
}
