/* ============================================================================
   oc-doc.css — feature-reference / explainer content blocks
   ----------------------------------------------------------------------------
   Styles the rich content we author as standalone artifacts (feature references,
   design explainers) so the SAME content can live on the site. Everything is
   scoped under `.oc-doc`, so these rules can never leak into the rest of the
   site, and the site's own rules can never surprise the content.

   WHERE THE CONTENT COMES FROM: each page under `artefacts/` starts life as a
   Claude artifact — a single self-contained HTML file that carries its own copy
   of this stylesheet plus the fonts base64-inlined and a `.preview-col` shell,
   so it renders standalone. Landing it on the site means taking the artifact's
   `<div class="oc-doc">` fragment ONLY and dropping it into
   `artefacts/artefact-template.html`. The artifact's `<style>` is discarded:
   this file is the site copy and the source of truth, and the site already
   loads TWK Lausanne and Ufficio Mono and already owns the page shell via
   `.base-grid`.

   So: if an artifact introduces a component this file does not have, add the
   rule HERE, scoped `.oc-doc`, using the existing site tokens. Never paste an
   artifact's own <style> into a page — two copies would drift.

   DESIGNERS: everything tunable is in the token block immediately below. It
   maps the content's roles onto the site's existing variables, so changing the
   site palette carries through. Override any of them here; no component rule
   hard-codes a colour.
   ============================================================================ */

/* ── THE TOKEN BLOCK ─────────────────────────────────────────────────────────
   These are the values the ARTIFACT ships with, verbatim. They are deliberately
   raw hex rather than site variables: this file is the record of what an
   artefact looks like on its own, so that artefacts/artefact-overrides.css can
   be the complete, readable record of what the site does to it. Do not map
   these onto var(--base-grey) and friends here; that is the override file's
   entire job. Every component rule below reads from these, so re-skinning is
   always a token change and never a component change. */
.oc-doc{
  /* ── Surfaces ───────────────────────────────────────────────────────────── */
  --paper: #111111;                  /* page background */
  --panel: #181818;                  /* raised card, a hair lighter than the page */
  --panel-2: #0c0c0c;                /* recessed panel / callout */
  --hair: #252525;                   /* hairline rules */

  /* ── Text ───────────────────────────────────────────────────────────────────
     The artifact's hierarchy is the conventional one: headings are white, body
     copy is a bright off-white, secondary text steps down from it. Note this is
     the INVERSE of the site's, where headings are the lightest thing and body
     copy is the darkest. The override file is where that inversion happens. */
  --heading: #fff;                   /* h1 / h2 */
  --ink: #e6e6e6;                    /* primary body text */
  --strong: #fff;                    /* emphasis */
  --muted: #8a8a8a;                  /* secondary text */
  --faint: #5b5b5b;                  /* tertiary / table headers */

  /* ── Values style.css supplies on the site ──────────────────────────────────
     Restated here because this sheet promises to render standalone, and these
     seven were referenced without being defined: in an artifact they resolved
     to nothing, and every plain table cell fell back to browser black.
     artefact-overrides.css re-links each one to the live site variable, so on
     the site these copies are inert. */
  --black: #000;
  --bg-colour: #111;
  --off-white: #B5B5B5;
  --base-grey: #5B5B5B;
  --code-grey: #838383;
  --dark-grey: #2E2E2E;
  --code-purple-hover: #DEA4FF;

  /* ── Accents ────────────────────────────────────────────────────────────── */
  /* Blue is the affirmative colour: comparison.html paints .dot-has with
     code-blue and .dot-partial with base-grey. Every colour below is one of
     that page's approved set, or a transparency of one. There is no green and
     no amber in the approved range, so state colours borrow from it rather than
     inventing a hue. */
  --accent: #9ec0ff;                                   /* primary, code-blue */
  --accent-2: #9085e9;                                 /* approved violet, use rarely */
  /* Press: solid #BE6EEC, the site's resting purple — the colour on the
     "npm i" of the install bar. NOT #DEA4FF, which the site only ever uses
     as a hover: a colour meant to be held for a moment becomes the brightest
     thing on the page once it is a solid fill, and white on it is barely
     legible (~1.9:1, against ~3.2:1 here). Solid rather than a tint so the
     press still reads at video size and in a thumbnail. */
  --press-bg: #BE6EEC;
  --press-fg: #fff;

  /* ── Terminal block ─────────────────────────────────────────────────────── */
  --term-bg: #000;
  --term-fg: #d6d6d6;
  --term-dim: #7c7c7c;
  --term-hl: rgba(158,192,255,.22);  /* active span: the affirmative blue, dimmed */

  /* ── State (all drawn from the approved range) ──────────────────────────── */
  --live: #9ec0ff;                   --live-bg: rgba(158,192,255,.12);   /* it happened */
  --edge: #d66f6b;                   --edge-bg: rgba(214,111,107,.14);   /* at a limit */
  --mute: #5b5b5b;                                                       /* zero / absent */

  /* ── Type ───────────────────────────────────────────────────────────────── */
  --doc-sans: 'TWK Lausanne', system-ui, -apple-system, 'Segoe UI', sans-serif;
  --doc-display: 'TWK Lausanne 200', 'TWK Lausanne', system-ui, sans-serif;
  --doc-mono: 'Ufficio Mono', ui-monospace, 'SF Mono', Menlo, monospace;

  /* ── Shape ────────────────────────────────────────────────────────────────
     Square everywhere EXCEPT the card. Every other component hard-codes
     border-radius:0, and the site's own rule is that corners are 0 or 50% and
     nothing else — so this token is the one deliberate exception, not the start
     of a rounded system. It is a token rather than a number in the rule because
     the card is unlikely to stay the only place that wants it: round the
     callout or the hero next and they should turn the same dial, not acquire a
     second radius of their own.

     If the exception is ever reverted, set this to 0 rather than deleting it —
     the earlier pair of radius tokens were removed precisely because nothing
     referenced them, and that is not true of this one. */
  --doc-radius: 7px;

  color: var(--ink);
  font-family: var(--doc-sans);
  font-weight: 300;
}

/* ── Typography ─────────────────────────────────────────────────────────────
   Eyebrows, section numbers, table headers and labels use the mono face with
   the site's .kerned tracking; headings use the light display weight.
   Type scale is the SITE's, in rem, not a second scale invented here:
     page title   2.8rem / 3.5rem  TWK Lausanne 200   (h1.blog-post-title)
     section      2rem   / 3rem    TWK Lausanne 200   (.blog-headline h2)
     body         1.2rem / 1.8rem                     (p)
     mono / label 0.8rem / 1.7rem  + .1rem tracking   (body .mono, .kerned) */
/* ── THE VERTICAL RHYTHM ─────────────────────────────────────────────────────
   One scale, the site's: .6 / 1.2 / 2.2 / 4 / 6rem. Text runs at .6; EVERY
   component block (term, ba, table, strip, cards, callout, spec, stats, keys,
   pull, hero) carries 1.2 on both sides; a link row closes its entry at 1.2;
   sections breathe at 6. Adjacent margins collapse to the larger, so any two
   neighbours land on the scale no matter which components meet.

   This section exists because the first build let each block bring its own
   number (1.4rem, 14px, 1.8rem, none at all): a link row measured 0px from a
   table, 10px from a paragraph and 22px from a comparison pair, and two bare
   terminals fused into one box. The relationships between components were
   never defined, so every new page invented them. Now they are defined once,
   here. */
.oc-doc .eyebrow{font-family:var(--doc-mono);font-size:.8rem;line-height:1.7rem;letter-spacing:.1rem;text-transform:uppercase;color:var(--muted);font-weight:300;margin:0 0 .6rem}
/* The fragment carries its own title, so a page can drop it in whole without
   hand-editing. Sized as the site's page title. If a page would rather use the
   site's .page-heading, delete the h1 from the fragment; never have both. */
/* Header rhythm is the site's spacer scale, nothing invented: small-spacer
   (2.2rem) holds the title and its standfirst together as one unit, then a
   medium-spacer (6rem) below the standfirst opens the body — the same 6rem
   every other page puts between its header and its first section, and the
   same 6rem an h2 puts above itself, so the header and the sections share
   one rhythm. */
.oc-doc h1{font-family:var(--doc-display);font-weight:200;font-size:2.8rem;line-height:3.5rem;margin:0 0 2.2rem;color:var(--heading);text-wrap:balance}
/* A page title that opens with a standfirst carries the section divider
   (ruled 2026-08-13): the deep pages' fragment h1 had no breadcrumbs row
   to lend the hairline. A naked index title stays plain, like the Open
   Standard's. */
.oc-doc h1:has(+ .page-standfirst){border-bottom:1px solid var(--hair);padding-bottom:.6rem}
/* A naked index title opens its first section at 4rem (ruled 2026-08-13,
   measured off the Open Standard's title-to-first-entry): the
   inter-section 12rem is for section BOUNDARIES, not the page opening. */
.oc-doc h1 + .entry-section > h2:first-child{margin-top:4rem}
/* Section rhythm follows the site: a medium-spacer (6rem) of air before the
   rule, and the site's .6rem padding after it (its convention on every
   divider). Sections should breathe; these pages are short. */
/* The divider sits UNDER the title and runs the full column, as on the site's
   open-standard and features pages; the override file carries the measured
   rationale. A rule above the heading read as the previous section closing. */
.oc-doc h2{font-family:var(--doc-display);font-weight:200;font-size:2rem;line-height:3rem;margin:6rem 0 .6rem;padding-bottom:.6rem;border-bottom:1px solid var(--hair);color:var(--heading)}
.oc-doc h3{font-family:var(--doc-mono);font-size:.8rem;line-height:1.7rem;letter-spacing:.1rem;font-weight:300;margin:2.2rem 0 .4rem;text-transform:uppercase;color:var(--strong)}
/* A qualifier appended to a heading: PROPOSED, DRAFT, DEPRECATED. Mono and
   faint, so it reads as an annotation on the heading rather than as part of it.
   Not a .badge — that is a chip with a fill, and a fill inside an h2 competes
   with the heading it is qualifying. */
.oc-doc h2 .tag{font-family:var(--doc-mono);font-size:.8rem;letter-spacing:.1rem;color:var(--faint)}
.oc-doc .page-standfirst{font-size:1.5rem;line-height:2.2rem;color:var(--ink);max-width:60ch;margin:0 0 6rem}
.oc-doc p,.oc-doc .lead{font-size:1.2rem;line-height:1.8rem;color:var(--ink);margin:.6rem 0;max-width:66ch}
/* Replaced elements never exceed the column (ruled 2026-08-12: everything
   is 100% max, nothing states an explicit width). Without this floor a
   full-size poster image's min-content width detonates the site grid at
   wide viewports — the content column collapsed onto the nav. This is the
   containment HALF of the image/video story; margins, ground and caption
   stay open gaps until those components are ruled. */
.oc-doc img,.oc-doc video{max-width:100%;height:auto}
/* Content images are BLOCKS: inline-level imgs carry erratic line-box
   leading that would pollute any authored gap. Consecutive media in any mix
   stack at 1.2rem (ruled 2026-08-13, creative cases [3]/[5]). */
.oc-doc img{display:block}
.oc-doc img + img,.oc-doc img + video,.oc-doc video + img,.oc-doc video + video{margin-top:1.2rem}
/* A video FILLS the column (ruled 2026-08-12, case [8] of the layout
   review): full width at the site's 16:9, not the browser's 300px default
   box. Margins/ground/caption stay open gaps. */
.oc-doc video{width:100%;aspect-ratio:16/9}
/* Prose survives an unbreakable token: overflow-wrap ANYWHERE, not
   break-word — break-word leaves min-content at the token's full width, and
   min-content propagation is exactly what forced the site grid's column to
   692px inside a 390px viewport when a paragraph carried a long URL as link
   text. Not applied to table cells: a mono cell depicts a line as typed and
   its table scrolls by design. */
.oc-doc p,.oc-doc li,.oc-doc dd,.oc-doc .note-callout{overflow-wrap:anywhere}
/* ── Lists (approved 2026-08-12) ─────────────────────────────────────────────
   THE SITE'S OWN BULLET SYSTEM (style.css), scoped for fragments: never a
   glyph marker (▪ goes colour-emoji on some mobile browsers) — a .4rem
   square at .6rem down, drawn in currentColor (identical to img/bullet.svg's
   fill here, and colour-correct in the artifact twin). li hangs at 1.2rem
   with .48rem stacking; body type on the site's 55ch list measure. LEVEL 2
   IS ROUND: nesting reads in the marker shape, on the approved radii (50%).
   Numbered lists take muted counters (no site precedent; ruled here). */
.oc-doc ul,.oc-doc ol{font-size:1.2rem;line-height:1.8rem;color:var(--ink);margin:.6rem 0;padding-left:0;max-width:55ch;list-style:none}
.oc-doc li{margin:.48rem 0;position:relative;padding-left:1.2rem;padding-bottom:.3rem}
.oc-doc ul li::before{content:"";position:absolute;left:0;top:.6rem;width:.4rem;height:.4rem;background:currentColor}
.oc-doc ul ul li::before{border-radius:50%}
.oc-doc ol{counter-reset:oc-steps}
.oc-doc ol li{counter-increment:oc-steps;padding-left:1.6rem}
.oc-doc ol li::before{content:counter(oc-steps) ".";position:absolute;left:0;color:var(--muted)}
.oc-doc li ul{margin:0;padding-left:0}
/* A link in RUNNING PROSE is bare and blue — the site's content-body
   treatment (style.css .blog-post-body a et al: --code-blue at rest, purple
   under the cursor), codified here so a fragment carries it on any page and
   the artifact twin matches. .standard-link is the OTHER treatment (quiet
   grey) and belongs to action rows and CTAs, never inside prose. */
.oc-doc p a:not(.standard-link):not(.heading-anchor),.oc-doc li a:not(.standard-link),.oc-doc td a:not(.standard-link),.oc-doc dd a:not(.standard-link),.oc-doc .note-callout a:not(.standard-link){color:var(--accent);text-decoration:none}
@media(hover:hover){.oc-doc p a:not(.standard-link):not(.heading-anchor):hover,.oc-doc li a:not(.standard-link):hover,.oc-doc td a:not(.standard-link):hover,.oc-doc dd a:not(.standard-link):hover,.oc-doc .note-callout a:not(.standard-link):hover{color:var(--code-purple-hover)}}
.oc-doc strong{font-weight:inherit;color:var(--strong)}   /* the site emphasises by colour, not weight */
/* Link colour and the tablet type step used to sit here. Both are things the
   SITE does to an artefact rather than properties of the components, so they
   now live in artefacts/artefact-overrides.css. */
.oc-doc code{font-family:var(--doc-mono);font-size:.9em;background:var(--black);color:var(--code-grey);padding:.1rem .35rem;overflow-wrap:anywhere}
/* inline-block, not the default inline: transform is ignored on non-replaced
   inline elements, so the press below would silently do nothing. */
.oc-doc kbd{display:inline-block;vertical-align:baseline;font-family:var(--doc-mono);font-size:.9em;background:var(--black);border-radius:0;padding:.1rem .35rem;color:var(--strong);white-space:nowrap;box-shadow:0 2px 0 var(--dark-grey)}

/* ── Terminal block ─────────────────────────────────────────────────────────
   ⚠ preserved whitespace means ANY newline/indentation BETWEEN child elements
   is rendered as literal blank space. Keep a .term's children on ONE line:
     <div class="term"><span class="term-buffer">…</span><span class="term-note">…</span></div>
   pre-wrap, not pre: runs of spaces still measure (so a hidden .term-note-pad works) but
   a line too long for the box falls onto a second line rather than scrolling
   out of sight, which is what a terminal does. The block never widens the page
   (overflow-x + min-width:0 + containment below).

   ⚠ contain:inline-size is load-bearing on a phone. A pre line has no wrap
   point, so its minimum width is the whole line, and that minimum travels up
   the tree: the site's centre column is a grid item sized from its content's
   minimum, so ONE long terminal line made the column 440px inside a 390px
   phone and the page scrolled sideways, cutting the title off. Containment
   stops the block reporting a width to its ancestors at all; it still scrolls
   inside itself. */
.oc-doc .term{font-family:var(--doc-mono);font-size:.8rem;line-height:1.7rem;background:var(--term-bg);color:var(--term-fg);
  border-radius:0;padding:.8rem 1rem;overflow-x:auto;scrollbar-width:none;-ms-overflow-style:none;white-space:pre-wrap;min-width:0;max-width:100%;contain:inline-size;margin:1.2rem 0}
/* The site hides scrollbars rather than styling them: its one scrollbar rule
   (on .grid-col-2) sets all three of these. Same here, so a narrow terminal
   does not sprout an unstyled bar. */
.oc-doc .term::-webkit-scrollbar{display:none}
.oc-doc .term .term-buffer{color:var(--term-fg);display:block}
/* NOT scoped to .term: wherever a page shows what your text becomes — a table
   cell, a caption — only the VALUE is selected, and the words around it are
   ordinary text. Showing the whole string in one colour says the product
   selected all of it, which it does not. */
.oc-doc .term-selected{background:var(--term-hl);color:var(--off-white)}
/* A flagged word has TWO states, and they are not interchangeable:

     .term-dimmed   at rest. Something is behind this word: dimmer than the text around
            it and nothing else. Presence, no content.
     .term-selected    the cursor is on it. Arriving auto-selects the word, which is the
            same moment the note appears underneath.

   The fill and the note travel together: a block showing a note shows the fill,
   a block with no note shows the dim. One without the other depicts a state the
   product never reaches. */
.oc-doc /* A BLANK'S SPINNER OCCUPIES ONE CELL. The spin set is _ - ‾ -, and Ufficio
   Mono has no U+203E, so the browser substitutes a fallback face whose glyph
   advances 7.04px against the cell's 8.26px (measured). On a line sitting at
   the wrap boundary that shorter tick pulls the trailing fragment back up, so
   the block loses a line and regains it every spin — a line flicking on and
   off. A real terminal spins in one cell and the line length never moves.
   The engine applies this ONLY to a single-character glyph: a 1ch box
   narrower than its own ink would overlap the next character rather than clip
   it (overflow stays visible), so a longer string keeps its natural width. */
.term-spin{display:inline-block;width:1ch;text-align:center}
.term-dimmed{color:var(--term-dim)}   /* active span = highlight, never an underline */
.oc-doc .term .term-note{color:var(--term-dim);display:block}
/* ── The note's alignment ────────────────────────────────────────────────────
   A note is not painted flush left: it is indented so the `↳ ` CONNECTOR sits
   directly under the value it points at.

   The connector, not the message. Aligning the message instead makes the
   alignment depend on whatever character the message happens to start with —
   an emoji's mark is drawn smaller than the slot it occupies, so it lands off
   the value by a fraction of a cell while a word lands on it exactly. The
   connector is one fixed glyph, so it lines up whatever the note says.

   `.term-note-pad` is a hidden copy of the text up to and INCLUDING the value, so it occupies exactly
   that width in the same monospace face, at any size, with no number to keep
   in step. A value at column 0 takes no pad and the arrow sits flush.

   The connector's width is DECLARED, not inherited from the glyph: `↳` is not
   in the mono face, so it comes from a fallback whose advance is narrower than
   a cell (15.4px against 16.8px). Pinning the box to two cells keeps the
   message on the grid whatever font answers for the arrow. */

/* THE PAD MIMICS THE WRAP. It is a hidden copy of everything up to and
   INCLUDING the value, so it breaks exactly where the buffer breaks: line
   breaking is greedy and left to right, so a value that will not fit moves to
   the next line in the pad for the same reason it does in the buffer. The pad
   then pulls back by the value's own length (--v, counted in cells by whoever
   wrote the note) so the connector lands on the value's FIRST character,
   wherever the wrap put it. It is exact at every width and there is nothing to
   measure, which is what a render at a width other than the page's needs.
   Set --v and the pad's text together or neither: with --v absent the pull is
   zero, so a pad holding only the prefix still behaves as it always did. */
.oc-doc .term .term-note .term-note-pad{visibility:hidden;white-space:pre-wrap}
/* THE VALUE INSIDE THE PAD DOES NOT BREAK, and carries the pull. Nowrap is what
   makes the pull exact: the value either fits on the prefix's line or moves to
   the next line whole, so the pad's last line always ENDS at the value's end,
   and pulling the CONNECTOR back by the value's own length (--v, in cells, on
   the note) lands it on the value's first character. Let the value break inside the pad and the
   pull overshoots by everything that stayed on the line above: measured at
   390px, a wrapping value put the connector 252px to the LEFT of itself. */
.oc-doc .term .term-note .term-note-val{white-space:nowrap}
.oc-doc .term .term-note .term-note-connector{display:inline-block;width:2ch;margin-left:calc(-1ch * var(--v,0))}
.oc-doc .term .term-note-connector{color:#5a5a5a}
/* ── The status line, inside the terminal ────────────────────────────────────
   Hosts render the note on their status line, and in the live DOM the input
   and its status line are ONE surface. Depicting them as two stacked blocks
   (a .term plus a labelled .reel-frame) drew two components where the product has
   one. The divider is full-bleed across the box (the negative margins undo the
   terminal's padding), the label names the region, and the note text is the
   terminal's own dim. */
.oc-doc .term .term-rail{display:block;margin:.8rem -1rem 0;padding:.6rem 1rem 0;border-top:1px solid var(--hair);color:var(--term-dim)}
/* A live demo is a fixed stage: the buffer (and its dedicated note line, when
   the demo uses notes) at the top, the coach rail pinned to the bottom, so no
   frame can move the rail. The engine wraps each frame's buffer in .term-buffer and
   reserves the tallest frame's height plus a constant cushion, which is what
   the auto margin distributes. */
/* border-box, because the engine reserves the measured offsetHeight as
   min-height: content-box would add the block's padding a second time, a
   permanent blank line's worth of slack above the pinned rail */
.oc-doc .term[data-live]{display:flex;flex-direction:column;box-sizing:border-box}
.oc-doc .term[data-live] .term-rail{margin-top:auto;min-height:var(--rail-h,auto);box-sizing:border-box}
/* The key row: presses shown as chips between the buffer and the coach rail,
   so a key-only action is as visible as typed text. A hidden ghost chip holds
   the row's height on pressless frames — the stage never moves. */
/* The key row is a CAPTION ROW in the hero caption's voice: the mono
   caption with the chips inline. No divider of its own — the rail below
   already draws one, and two hairlines in one box is one too many. */
.oc-doc .term .keycast-row{display:block;margin:.8rem 0 0}
.oc-doc .term .keycast-caption{color:var(--term-dim)}
/* In a live demo the key row is ANCHORED TO THE RAIL, not to the buffer: the
   buffer's line box is taller with text than with a bare caret, so a row in
   normal flow would ride up and down with it. The key row takes the auto
   margin and the rail follows at a fixed gap. */
.oc-doc .term[data-live] .keycast-row{margin-top:auto}
.oc-doc .term[data-live] .keycast-row ~ .term-rail{margin-top:.5rem}

.oc-doc .term .keycast-row .keycast-ghost{visibility:hidden}   /* content hides; the divider stays */
/* The Claude Code plate — see theme.css twin. */
.oc-doc .term .claude-plate{display:inline-flex;align-items:center;justify-content:center;width:1.7em;height:1.7em;background:#fff;color:#111;border-radius:0;font-size:.9em;vertical-align:middle}
.oc-doc .term .term-rail .term-rail-label{display:block;font-size:.8rem;line-height:1.7rem;letter-spacing:.1rem;text-transform:uppercase;color:var(--faint)}
.oc-doc .term .term-note-hint{color:var(--term-dim);font-style:italic}
/* Styling inside the text: a model's markdown emphasis is applied, not
   printed, and depicting that borrows the terminal's own vocabulary — bold is
   heavier AND brighter, as every terminal draws it. Not a state: a word can be
   bold and dim, or bold and selected, so these carry no colour of their own
   beyond the lift. */
.oc-doc .term .term-bold{font-weight:700;color:var(--strong)}
.oc-doc .term .term-italic{font-style:italic}
.oc-doc .term .term-strike{text-decoration:line-through}
.oc-doc .term .term-code{background:#1b1b1b;padding:0 .25ch}

/* The # after a section title: the site's own heading anchor, restated here
   so the artifact renders it standalone; on the site the global rules apply
   and these agree with them. */
.oc-doc .heading-anchor{color:var(--paper);text-decoration:none;margin-left:.5rem;padding:.15em 0}
/* Reveal gated on the TITLE TEXT (.heading-text), matching open-standard; nesting the
   anchor inside .heading-text also dodges the site's h2:has(> .heading-anchor)
   shrink-wrap, so the heading stays full width and its divider runs the
   column. */
.oc-doc .heading-text:hover .heading-anchor,.oc-doc .heading-anchor:focus-visible{color:var(--faint)}
/* Hovering the # itself warms it to the site's link hover purple. */
.oc-doc .heading-text:hover .heading-anchor:hover{color:var(--code-purple-hover)}

/* ── Tables ─────────────────────────────────────────────────────────────────*/
/* Inherits the site's global <table> rule (1rem/1.7rem, --base-grey, --border);
   only the header treatment and the tighter cell padding are ours. */
.oc-doc table{margin:1.2rem 0}
.oc-doc th,.oc-doc td{text-align:left;padding:.6rem .8rem;border-bottom:1px solid var(--hair);vertical-align:top}
/* Declared, never inherited: standalone there is no site table rule to
   inherit from, and the fallback is browser black on a dark ground. On the
   site the override file maps --ink onto --base-grey, which is exactly what
   the global rule supplied, so this changes nothing there. */
.oc-doc td{color:var(--ink);font-size:1rem;line-height:1.7rem}
.oc-doc th{font-family:var(--doc-mono);font-size:.8rem;line-height:1.7rem;letter-spacing:.1rem;text-transform:uppercase;color:var(--faint);font-weight:300}
/* A mono cell depicts text in the editor, so it takes the TERMINAL's base text
   colour, not the page's — otherwise the unselected words sit close enough to
   the selected value's white to read as selected themselves. */
/* nowrap because the cell is a line of text as typed: breaking `volume 40 _`
   across two lines shows the reader something they would never see. The wrapper
   below scrolls instead. */
/* The note-format table: the lead (emoji + count) right-aligns in its own
   column so the counts line up whether or not an emoji precedes them, and the
   message column starts at the pipe. The two cells read as ONE note, so the
   gap between them is a single character, not the table's column padding. */
.oc-doc td.note-count-cell{text-align:right;white-space:nowrap;padding-right:0}
.oc-doc td.note-count-cell + td.mono{padding-left:1ch}
.oc-doc td.mono{font-family:var(--doc-mono);font-variant-numeric:tabular-nums;color:var(--term-fg);white-space:nowrap}
.oc-doc th.mono{font-family:var(--doc-mono);font-variant-numeric:tabular-nums}
/* Wrap wide tables so only THEY scroll. The scrollbar is hidden, matching the
   terminal block and the site's own one scrollbar rule — the site hides them
   rather than styling them, and a native bar under a table is loud enough on a
   phone to read as a component in its own right. */
/* The wrap owns the block margin: overflow creates a formatting context, so a
   margin on the table inside is trapped there and never reaches the page —
   table pairs measured 10px while every other block sat at 19px. */
.oc-doc .scroll{overflow-x:auto;scrollbar-width:none;-ms-overflow-style:none;contain:inline-size;margin:1.2rem 0}
/* A paragraph directly under a table wrapper drops its margin-top, and the
   wrapper closes at 1.2rem (ruled 2026-08-12, layout case [21]): the
   wrapper's margin IS the gap, one component step. */
.oc-doc .scroll + p{margin-top:0}
.oc-doc .scroll:has(+ p),.oc-doc .scroll:has(+ .note-callout){margin-bottom:1.2rem}
.oc-doc .scroll table{margin:0}
.oc-doc .scroll::-webkit-scrollbar{display:none}
/* contain:inline-size for the same reason as .term above: the table's minimum
   width must not travel up and widen the page.
   On a phone the columns would otherwise compress to a word or two per line
   before anything scrolls, which is harder to read than scrolling. Hold the
   table at a width its columns can live in and let the wrapper carry it. */
@media(max-width:600px){.oc-doc .scroll>table{min-width:520px}}

/* ── Badges ─────────────────────────────────────────────────────────────────*/
/* A chip already says "this is a key or a mode". Colour on top of that is
   redundant, so badges and kbd stay neutral; colour is reserved for meaning
   the shape cannot carry. */
.oc-doc .badge{display:inline-block;font-family:var(--doc-mono);font-size:.8rem;line-height:1.4rem;font-weight:300;padding:0 .6rem;border-radius:0;background:var(--black);color:var(--strong);}

/* ── Filmstrip ──────────────────────────────────────────────────────────────*/
/* The caption column is set PER STRIP, not globally: one width cannot suit
   every walkthrough, and at 9rem these captions wrapped to three or four
   lines. Override it on the strip itself, e.g.
     <div class="strip" style="--label-col:21rem">
   sized to that strip's longest caption. The terminal beside it may clip in
   exchange: it scrolls on screen, and content length is not something a
   layout can predict. */
.oc-doc .strip{margin:1.2rem 0;--label-col:18rem;container-type:inline-size}
/* A filmstrip followed by prose closes at 0 (ruled 2026-08-12, layout
   case [36]): the paragraph's own margin is the gap. Ruled 2026-08-13:
   the strip under prose drops its margin-top (the paragraph's .6rem is
   the gap), and prose after a strip drops its margin-top too. */
.oc-doc .strip:has(+ p){margin-bottom:0}
.oc-doc p + .strip{margin-top:0}
.oc-doc .strip + p{margin-top:0}
.oc-doc .reel-frame{display:grid;grid-template-columns:var(--label-col,18rem) 1fr;gap:1rem;align-items:center;padding:.7rem 0;border-bottom:1px solid var(--hair)}
.oc-doc .reel-frame:last-child{border-bottom:0}
.oc-doc .reel-frame .reel-note{font-size:1rem;line-height:1.5rem;color:var(--muted);min-width:0}
.oc-doc .reel-frame .reel-note .reel-note-title{display:inline-block;margin-bottom:5px}
.oc-doc .reel-frame .reel-note .reel-note-detail{display:block;margin-top:.2rem;font-family:var(--doc-mono);font-size:.8rem;line-height:1.4rem;color:var(--muted);font-weight:300}
@media(max-width:600px){.oc-doc .reel-frame{grid-template-columns:1fr;gap:7px}}
/* AFTER the base .reel-frame rules, not before: equal specificity means source
   order decides, and placed first this query matched and was silently
   overridden. Collapses the strip in any container too narrow for the label
   column, which includes the site's content column. */
@container (max-width:46rem){.oc-doc .reel-frame{grid-template-columns:1fr;gap:.4rem}}

/* ── Gauges ─────────────────────────────────────────────────────────────────
   ⚠ Grid, not flex: a gauge's track must be the SAME LENGTH on every row, so
   the bars can be read against each other. Under flex the bar was `flex:1` and
   the label was a sibling that grew with its text, so a longer label shortened
   its own bar — three gauges, three different tracks. Here the track is its own
   column, sized from nothing but the column definition, and the label column is
   `minmax(0,1fr)` — the 0 minimum matters, since a bare `1fr` takes the label's
   longest word as its minimum and starts squeezing the track again.
   Narrow screens drop the label to a second row rather than let it fight for
   the width, so the track survives at full length there too. */
.oc-doc .gauge{display:grid;grid-template-columns:3.4rem minmax(120px,340px) minmax(0,1fr);align-items:center;column-gap:10px;margin:6px 0}
/* the stack stays tight at 6px; its outer edges meet the page at the block gap */
.oc-doc p + .gauge,.oc-doc h3 + .gauge,.oc-doc .oc-actions + .gauge{margin-top:1.2rem}
.oc-doc .gauge + p,.oc-doc .gauge + h2{margin-top:1.2rem}
/* The track shrinks about its own middle, and nothing else moves. It is a grid
   item under `align-items:center`, so it is centred in a row whose height comes
   from the label and the value, never from the track — at .3rem it is well
   under both. Changing this height therefore takes the space off the top and
   the bottom equally and leaves the gauge's own height, and the rhythm of a
   stack of them, exactly where it was. Do NOT reach for margin or translate to
   recentre it; that only becomes necessary if something ever makes the track
   the tallest thing in its row, and the fix then is the row, not this. */
.oc-doc .gauge-track{position:relative;height:.3rem;width:100%;background:#1e1e1e;border-radius:0;overflow:hidden}
.oc-doc .gauge-track .gauge-fill{position:absolute;left:0;top:0;bottom:0;background:var(--accent);border-radius:0}
.oc-doc .gauge-track-edge .gauge-fill{background:var(--edge)} .oc-doc .gauge-track-muted .gauge-fill{background:var(--mute)}
.oc-doc .gauge .gauge-value{font-family:var(--doc-mono);font-variant-numeric:tabular-nums;font-size:.8rem;width:3.4rem;color:var(--strong)}
.oc-doc .gauge .gauge-label{font-size:1rem;line-height:1.5rem;color:var(--muted)}
@media(max-width:600px){
  .oc-doc .gauge{grid-template-columns:3.4rem minmax(0,1fr);margin:6px 0 1.2rem}
  .oc-doc .gauge .gauge-label{grid-column:2;margin-top:.4rem}
}

/* ── Cards ──────────────────────────────────────────────────────────────────
   ⚠ min-width:0 on .card is load-bearing: without it a wide .term inside a card
   refuses to shrink and pushes the card past the viewport on mobile. */
.oc-doc .column-pair{display:grid;grid-template-columns:1fr 1fr;gap:1rem;margin:1.2rem 0}
@media(max-width:600px){.oc-doc .column-pair{grid-template-columns:1fr}}
/* Before / after. The artifact this file was extracted from declared .before-after only
   inside its 600px breakpoint, so the pair stacked at EVERY width and the
   comparison the component exists to make was never side by side. Base rule
   restored here; the narrow override further down still collapses it. Same
   shape as .column-pair, but its own rule rather than a shared one: the two are the
   same today and need not stay that way, and a `you type / you get` pair is a
   sequence where two cards are a set. */
/* Sized against its own box, not the viewport: the site's content column is
   538px at a 1200px viewport, so a max-width media query never fires there and
   the halves squeezed to 261px, wrapping commands mid-line. auto-fit collapses
   to one column wherever two 22rem halves do not fit. */
.oc-doc .before-after{display:grid;grid-template-columns:repeat(auto-fit,minmax(22rem,1fr));gap:1rem;margin:1.2rem 0}
/* A before/after followed by prose or a callout closes at 0 (ruled
   2026-08-12, layout cases [26]/[27]): the follower's own margin is the
   gap — a paragraph's .6rem, and the callout steps down to match. */
.oc-doc .before-after:has(+ p),.oc-doc .before-after:has(+ .note-callout){margin-bottom:0}
.oc-doc .before-after + .note-callout{margin-top:.6rem}
/* Both halves stand the same height, always. The cell is already full height —
   a grid item stretches — but the .term inside sizes to its own text, so a
   command that wrapped to two lines put a tall black box beside a short one and
   the pair read as two different KINDS of thing rather than one thing before
   and after. The cell becomes a column and the depiction takes the slack, so
   the two boxes align top and bottom whatever their content does. The caption
   keeps its own height: it is a label on the box, not part of the comparison. */
.oc-doc .before-after>div{min-width:0;display:flex;flex-direction:column}
.oc-doc .before-after>div>.term{flex:1;margin-top:0}
/* A tiny caption ("you type") sits tight on its terminal (ruled 2026-08-12,
   case [26]): the TERM under it drops its margin-top — the caption keeps its
   own .4rem. A full paragraph above a term keeps everything as is. */
.oc-doc .before-after>div>p{font-size:1rem;line-height:1.5rem;color:var(--muted);margin:0 0 .4rem}
/* The one rounded surface on the page — see --doc-radius in the token block.
   Safe to round because the card insets everything it holds by its own padding,
   so nothing (a .term, a .gauge) ever meets the corner and needs clipping. */
.oc-doc .card{border-radius:var(--doc-radius);padding:1rem 1.2rem;background:var(--panel);min-width:0}
.oc-doc .card .card-title{font-weight:300;color:var(--heading);margin:0 0 .5rem;display:flex;align-items:center;gap:.5rem}
.oc-doc .card .card-title .card-title-emoji{font-size:18px}
.oc-doc .card p{font-size:1rem;line-height:1.5rem;color:var(--muted);margin:.4rem 0 0;max-width:none}

/* ── Callout + footer ───────────────────────────────────────────────────────*/
/* Same grey panel as a card: an aside is a block of prose set apart, and the
   accent rail was the last decoration doing that job by colour. */
.oc-doc .note-callout{background:var(--panel);border-radius:var(--doc-radius);padding:1rem 1.2rem;margin:1.2rem 0;font-size:1rem;line-height:1.6rem;color:var(--muted)}
.oc-doc .note-callout b{color:var(--heading);font-weight:inherit}
.oc-doc .foot{margin-top:4rem;padding-top:1.4rem;border-top:1px solid var(--hair);font-family:var(--doc-mono);font-size:.8rem;line-height:1.6rem;color:var(--faint)}

/* ── PROPOSED components ──────────────────────────────────────────────────
   Not yet used by any page. They exist so the component gallery can show what
   the system could carry, in the same idiom as everything above: square, the
   site's palette, colour only where it does work. Delete any that never earn a
   page rather than leaving them as decoration.
   ------------------------------------------------------------------------- */


/* Stat row — a few headline numbers. The number has to LEAD: at anything near
   body size it reads as a label with a number in it. No tabular-nums here —
   that is for columns of figures, and in the display face it spaces a bare "44"
   so widely it looks like two separate digits. */
.oc-doc .stats{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:2.2rem 1.4rem;margin:1.2rem 0}
.oc-doc .stat{min-width:0}
.oc-doc .stat .stat-figure{display:block;font-family:var(--doc-display);font-weight:200;font-size:3.2rem;line-height:3.4rem;color:var(--heading);letter-spacing:-.02em}
.oc-doc .stat .stat-caption{display:block;margin-top:.4rem;font-size:1rem;line-height:1.5rem;color:var(--muted)}

/* Pull quote — a line worth stopping on. No quote marks; the indent is enough. */
.oc-doc .pull{margin:1.2rem 0;padding-left:1.4rem;border-left:1px solid var(--hair);font-family:var(--doc-display);font-weight:200;font-size:1.6rem;line-height:2.4rem;color:var(--heading);max-width:50ch}

/* Key sheet — a grid of shortcuts. Each ROW is itself a grid with a fixed
   keycap column, so every label starts at the same x whatever the key is
   called; a flex row let them wander and the block read as ragged. */
.oc-doc .keys{display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:0 2.2rem;margin:1.2rem 0}
/* A key sheet under prose steps DOWN an extra .6rem (ruled 2026-08-12,
   layout case [29]): 1.2rem + .6rem = 1.8rem. Margins collapse to the
   larger side, so the step lives on the keys' own margin-top — adding
   .6rem to the paragraph is swallowed by the keys' 1.2rem. Off the named
   scale by decision; allowlisted in style-review-allow.json. */
.oc-doc p + .keys{margin-top:1.8rem}
/* ...and the same 1.8rem on the other side: prose FOLLOWING a key sheet
   carries it on its own margin-top (the keys' margins untouched). */
.oc-doc .keys + p{margin-top:1.8rem}
.oc-doc .keys div{display:grid;grid-template-columns:9.5rem 1fr;align-items:baseline;
  gap:.8rem;min-width:0;padding:.6rem 0;border-bottom:1px solid var(--hair)}
.oc-doc .keys kbd{justify-self:start}
.oc-doc .keys span{color:var(--ink);font-size:1rem;line-height:1.7rem;min-width:0}

@media (max-width:600px){.oc-doc .column-pair{grid-template-columns:1fr}}

/* ── Hero animation (optional) ──────────────────────────────────────────────
   Reuses .term so it renders identically to the static examples. Only the frame
   and the caption bar are hero-specific.
   The caption bar must be a CONSTANT height. The hero is vertically centred in
   the video stage, so any change in the bar's height shifts the whole demo
   between frames — a visible jitter. Two ways it can change, both guarded:
     1. wrapping — hence white-space:nowrap (it scrolls sideways instead)
     2. the keycap — an inline-block TALLER than the line box grows the line,
        and the keycap only exists on some frames. line-height is explicit and
        MUST stay greater than .hkey's height (17px). Resize one, resize both. */
.oc-doc .hero{margin:1.2rem 0;border-radius:0;background:var(--panel-2);overflow:hidden}
.oc-doc .hero .term{border:0;border-radius:0;background:transparent;padding:1.1rem 1.1rem .8rem}
.oc-doc .hero .hero-note,.oc-doc .hero .hero-hint{transition:opacity .35s ease}
/* The caret is ordinary terminal text, not an accent: it marks where you are,
   which the blink already says, and a real terminal doesn't colour it. Drawn
   as a thin rule rather than a block glyph — see the note in hero.html. */
.oc-doc .hero .typing-caret{display:inline-block;width:.1em;min-width:2px;height:1.27em;margin-left:1px;vertical-align:-.37em;background:var(--term-fg);animation:oc-doc-blink 1.05s steps(1,end) infinite}
/* The caret is shared with the mini live demos, not hero-only: any .term
   can play a declarative sequence. Same glyphless caret, same reasons. */
/* The caret takes NO layout width: the bar is an absolute overlay. An inline
   caret with real width shifts every character after it, and when it travels
   mid-line the shift point moves with it — a nudge rippling through the text. */
.oc-doc .term .typing-caret{display:inline-block;width:0;height:1.27em;vertical-align:-.37em;position:relative;animation:oc-doc-blink 1.05s steps(1,end) infinite}
.oc-doc .term .typing-caret::after{content:"";position:absolute;left:-1px;top:0;width:2px;height:100%;background:var(--term-fg)}
/* A MOVING caret is solid: a blinking caret is invisible half its cycle, so
   per-character motion reads as multi-character jumps. Only a resting caret
   blinks, which is what a real terminal does. */
.oc-doc .term .typing-caret.typing-caret-moving{animation:none}

@keyframes oc-doc-blink{50%{opacity:0}}
.oc-doc .hero-caption-bar{padding:.7rem 1.1rem 1rem;font-family:var(--doc-mono);font-size:.8rem;line-height:20px;color:var(--muted);border-top:1px solid var(--hair);white-space:nowrap;overflow-x:auto}
/* A ROW, not a box with something absolutely positioned in the corner. The
   mark used to be pinned to the right edge, which meant the instruction beside
   it had no idea it was there: a longer caption simply ran underneath the
   wordmark. As a row the two are siblings and cannot overlap, whatever either
   of them says. */
.oc-doc .hero-caption-bar{display:flex;align-items:center;justify-content:space-between;gap:1rem}
/* ── The mark, far right of the caption bar ──────────────────────────────────
   The site's own logo file, not an approximation of it: `img/OC_logo.svg` is
   the wordmark the page JSON-LD declares as the organisation's logo. Set as a
   MASK over `currentColor` rather than as an image — that keeps the real
   letterforms while letting it take the caption's own grey, which an <img> or a
   background-image could not (they would lock it to the file's white fill).

   A real element rather than ::after, because the caption is white-space:pre
   and rewritten on every frame of the loop; an inline node in the text flow
   would shift with it. Inlined as data URIs for the same reason the fonts are:
   the artifact build is one file with no siblings to fetch.

   HIDDEN ON MOBILE. There is barely room for the instruction on a phone, and a
   mark competing with it is the first thing to go. The video keeps it either
   way — see render-video.cjs, which is a fixed 1280-wide stage. */
/* Hidden on the page; the video stage forces it back (see theme.css twin). */
.oc-doc .hero-caption-bar .hero-caption-text{white-space:nowrap;min-width:0}
.oc-doc .hero-caption-bar .hkey,.oc-doc .term .keycast-row .hkey{color:var(--strong);display:inline-flex;align-items:center;justify-content:center;min-width:15px;height:17px;padding:0 4px;margin:0 1px;font-size:11px;line-height:1;background:#1b1b1b;border-radius:0;vertical-align:middle;transition:none;box-shadow:0 2px 0 var(--dark-grey)}
/* The press is deliberately a quiet tint, chosen over a high-contrast fill
   (Wilfred, Aug 2026). It is subtle on a dark ground by design; do not
   'fix' it to the accent colour. transition:none stays, though: video
   frames are captured the instant the callback fires, so a transition
   would leave even this much off the clip. */
.oc-doc .hero-caption-bar .hkey.press,.oc-doc .term .keycast-row .hkey.press{background:var(--press-bg);color:var(--press-fg);transform:translateY(2px);box-shadow:0 0 0 var(--dark-grey)}

/* ── Download actions + print ───────────────────────────────────────────────
   `.oc-doc .oc-actions` is a small toolbar the page can drop in; it never prints. */
/* A link row closes its entry: 1.2 above, collapsing with whatever block came
   before it, so the gap is identical after a paragraph, a table or a terminal.
   0 below: the next section's own 6rem is the separator. */
.oc-doc .oc-actions{display:flex;gap:1.4rem;flex-wrap:wrap;margin:1.2rem 0 0}
/* A download row directly above a live demo OWNS that demo (its href is
   derived from the demo's section — COMPOSITION.md). Proximity has to say so:
   without this rule the row sits 1.2rem from the prose above AND 1.2rem from
   the demo below — equidistant, ownerless, and indistinguishable from the
   entry's closing CTA. Text-scale .6rem to the demo, block-scale 1.2rem to
   the prose: the row reads as the demo's, not the entry's. */
.oc-doc .oc-actions + .term[data-live]{margin-top:.6rem}
/* Downloads are LINKS, not buttons: assets.html offers its files as a plain
   "Download ↓" in base-grey that warms on hover. Same styling here, kept at
   the small mono size the rest of the page labels use. */
.oc-doc .oc-actions button,.oc-doc .oc-actions a{font-family:var(--doc-mono);font-size:.8rem;line-height:1.7rem;letter-spacing:.06rem;color:var(--base-grey);background:none;border:0;padding:0;cursor:pointer;text-decoration:none;transition:color .5s cubic-bezier(0.25,0.1,0.25,1)}
.oc-doc .oc-actions button:hover,.oc-doc .oc-actions a:hover{color:var(--code-purple-hover)}
.oc-doc .oc-actions button:focus-visible,.oc-doc .oc-actions a:focus-visible{outline:1px solid var(--code-purple-hover);outline-offset:3px}

@media print{
  /* ⚠ The document-level rules in this block are gated on :has(.oc-doc).
     This sheet is loaded on EVERY page (includes.js appends it to any page that
     did not link it), and style.css carries no @media print of its own — so an
     unscoped `html,body` here would quietly make the artefact's print treatment
     the whole site's, and printing an FAQ would come out on a black ground.
     The gate is live, so a page that grows a .oc-doc block later still prints
     correctly. Everything else in this block is already .oc-doc-scoped and
     needs no gate. */
  /* Keep the dark ground: browsers drop backgrounds unless told otherwise. */
  html:has(.oc-doc),html:has(.oc-doc) body{background:var(--bg-colour) !important;-webkit-print-color-adjust:exact;print-color-adjust:exact}
  html:has(.oc-doc) *{-webkit-print-color-adjust:exact;print-color-adjust:exact}
  /* The toolbar offers this very PDF and its video; on paper those links point
     nowhere, so it goes — same reasoning as the hero caption below. */
  .oc-doc .oc-actions{display:none !important}
  /* Don't split a component across a page break. */
  .oc-doc .term,.oc-doc .card,.oc-doc .reel-frame,.oc-doc .gauge,.oc-doc .note-callout,.oc-doc .hero{break-inside:avoid;page-break-inside:avoid}
  .oc-doc h2{break-after:avoid;page-break-after:avoid}
  /* The document is short, so let it breathe: keep each section whole and
     start a fresh page rather than bleed one across a break. Half-empty
     pages are fine here and are the point, not a failure. A section taller
     than a page still breaks naturally, since avoid is a preference. */
  .oc-doc .entry-section{break-inside:avoid;page-break-inside:avoid}
  /* Spacious is not the same as a page holding two lines: keep the closing
     note attached to whatever precedes it. */
  .oc-doc .foot{break-before:avoid;page-break-before:avoid}
  .oc-doc .lead{break-after:avoid;page-break-after:avoid}
  .oc-doc h3{break-after:avoid;page-break-after:avoid}
  /* The hero is an animation; print the frame that is on screen, and drop the
     caption bar since its instruction is meaningless on paper. */
  .oc-doc .hero-caption-bar{display:none !important}
  /* The shader ring is a web-only effect. On paper it would freeze at whatever
     phase the print happened to catch, which is arbitrary rather than designed. */
  .oc-doc .hero canvas[aria-hidden]{display:none !important}
  html:has(.oc-doc) a[href]:after{content:""}   /* no URL footnotes */
  /* @page cannot be conditioned on document content — there is no selector for
     it — so this one is genuinely site-wide now. Left as is deliberately: 14mm
     is within a millimetre or two of the browser default the site was already
     getting, and @page{background} is inert in every engine that matters (the
     html/body rule above is what actually paints the ground). If the site ever
     grows a print stylesheet of its own, this belongs in it, not here. */
  @page{margin:14mm;background:var(--bg-colour)}
}


/* ── Easter egg: the chips that look pressable, are ─────────────────────────
   kbd and the hero keycap carry a 2px bottom border, which reads as depth and
   quietly promises they can be pushed. So they take a pointer and depress under
   the cursor. They do nothing on purpose: it is tactility, not an action. They
   are deliberately NOT focusable and carry no button role, so nothing promises
   a keyboard interaction that does not exist.
   user-select:none because repeated clicking otherwise starts selecting the
   glyph inside, which breaks the illusion that it is a key. */
.oc-doc kbd,.oc-doc .hero-caption-bar .hkey,.oc-doc .term .keycast-row .hkey{cursor:pointer;user-select:none;-webkit-user-select:none;-webkit-tap-highlight-color:transparent}
.oc-doc kbd:active,.oc-doc .hero-caption-bar .hkey:active{background:var(--press-bg);color:var(--press-fg);transform:translateY(2px);box-shadow:0 0 0 var(--dark-grey)}

/* ── HOST THEMES: .lt wrappers that re-point the terminal's tokens ───────────
   A `.term` under `<div class="lt lt-cc">` stops being the site's terminal and
   becomes the host's. The tokens do the work - a theme re-points them and the
   component rules above are untouched - so a theme is a palette plus whatever
   chrome rows the host draws around the input.

   Ported from artefacts/live-dom-themes-src/theme.css, which is the tester and
   the source: 13 colourways live there, and this carries the ONE the site
   uses. Claude Code was the cheap one to bring across - it draws its chrome
   with text, so it needs nothing from the tester's 1,928-line SVG defs, which
   is what gmail or slack would drag in.

   WHAT DID NOT COME ACROSS: the live status-line row (.lt-cc-status driven by
   an "sl" step). That step is a PAGE-LOCAL engine patch in the tester's
   engine-patches.json and is not in the shipped demo-engine.js, so a status
   row here would render as a permanently empty bar. The class is kept so the
   port is complete if the step is ever promoted into the engine; nothing uses
   it. */
.oc-doc .lt{margin:1.2rem 0;background:var(--term-bg);border:1px solid var(--lt-border,transparent);border-radius:var(--lt-radius,0);overflow:hidden;container-type:inline-size}
.oc-doc .lt .term{margin:0}
/* chrome rows share the terminal's metrics */
.oc-doc .lt .lt-row{font-family:var(--doc-mono);font-size:.8rem;line-height:1.65rem;display:flex;flex-wrap:wrap;align-items:center;gap:.8rem;padding:.45rem 1rem;color:var(--term-fg)}
.oc-doc .lt .lt-dim{color:var(--term-dim)}
.oc-doc .lt .term .typing-caret{position:relative}
.oc-doc .lt .term .typing-caret::after{background:var(--term-caret,var(--term-fg));height:calc(1.65rem - 4px);top:50%;transform:translateY(-50%)}
/* the base sheet hard-codes these for the shipped terminal look; a theme
   re-points them */
.oc-doc .lt .term-selected{background:var(--term-hl);color:var(--term-sel-fg,var(--off-white))}
.oc-doc .lt .term .term-note-connector{color:var(--term-dim)}
.oc-doc .lt .term .term-rail{border-top-color:var(--lt-divider,var(--hair))}
.oc-doc .lt .term .keycast-row .hkey{background:var(--lt-chip,#1b1b1b);color:var(--lt-chip-fg,var(--strong));box-shadow:0 2px 0 var(--lt-chip-shadow,var(--dark-grey))}
.oc-doc .lt .term .keycast-row .hkey.press{background:var(--press-bg);color:var(--press-fg);box-shadow:0 0 0 var(--lt-chip-shadow,var(--dark-grey))}
.oc-doc .lt .term .term-buffer{min-height:1.65rem}
.oc-doc .lt .term .term-note{line-height:1rem}

/* claude code - CC's palette and the real host layout: the input box with its
   rule above and below, then CC's own rows beneath it */
.oc-doc .lt-cc{--term-caret:#e5e5e5;--term-bg:#0a0a0a;--term-fg:#aaaaaa;--term-dim:#7a7a7a;--term-hl:#1a1a1a;--term-sel-fg:#ffffff;--lt-divider:#2e2e2e}
.oc-doc .lt-cc .term{margin:.6rem .8rem 0;border:0;border-top:1px solid #7a7a7a;border-bottom:1px solid #7a7a7a;border-radius:0;padding:.35rem 0}
.oc-doc .lt-cc .term .term-buffer::before{content:"> ";color:#aaaaaa}
/* the no-chevron option: no prompt glyph, no gap where it was */
.oc-doc .lt-cc.lt-nochev .term .term-buffer::before{content:none}
/* cc draws the tty BLOCK cursor - a full cell, the glyph showing inverted
   through it (difference blending reproduces the canvas's repaint-in-bg) */
.oc-doc .lt-cc .term .typing-caret::after{left:0;width:1ch;mix-blend-mode:difference}
/* a terminal wraps a long row onto the next LINE; flex columns are not a thing
   a terminal does */
.oc-doc .lt-cc .lt-row{display:block;padding:.05rem .8rem}
.oc-doc .lt-cc .lt-row span{display:inline}
.oc-doc .lt-cc .lt-cc-cwd{padding-top:.35rem}
.oc-doc .lt-cc .lt-cc-auto{padding-bottom:.45rem}
.oc-doc .lt-cc .cc-pc{color:#00FF00;font-weight:700}
.oc-doc .lt-cc .cc-cwd{color:#4e4ee5;font-weight:700}
.oc-doc .lt-cc .cc-auto{color:#FFFF00}
.oc-doc .lt-cc .cc-shells{color:#00FFFF}
/* the status line under the input: the row the product prints its kata coach
   and word rail into. Kept at one line's height when blank so the block never
   jumps; the engine paints a state's `sl` into it (ported from the themes
   tester's page-local patch, 2026-09-15). */
.oc-doc .lt-cc .lt-cc-status{padding-bottom:.45rem;color:#aaaaaa;min-height:1.65rem}
.oc-doc .lt-cc .lt-cc-status .cc-pipe{color:inherit}
.oc-doc .lt-cc .cc-sl-word{color:inherit;font-weight:400}
.oc-doc .lt-cc .cc-pipe{color:#FFFF00;margin-right:1ch}
/* reserved for the status row, which does not ship - see the note above */
.oc-doc .lt-cc .lt-cc-status{padding-bottom:.45rem;color:#aaaaaa;min-height:1.65rem}
.oc-doc .lt-cc .lt-cc-status .cc-pipe{color:inherit}
.oc-doc .lt-cc .cc-sl-word{color:inherit;font-weight:400}

/* ── .lt-voice: THE NARRATION GOES ON THE GROUND, NOT IN THE HOST ────────────
   A coach line is the page speaking, not the product. Left inside the terminal
   it is fine on a bare .term - the block is the whole picture - but inside a
   host surface it reads as a line OpenCues printed into Claude Code, which is
   the ruling the engine's own data-voice-into comment records. So a themed
   demo names this element and the engine moves the rail (and the key chips)
   here on every paint. Same placement the films use for .vt-voice: under the
   card, on the page's ground. The rail arrives with the border and margins it
   wore as the terminal's lower region; out here it is just a caption. */
.oc-doc .lt-voice{font-family:var(--doc-mono);font-size:.8rem;line-height:1.65rem;color:var(--term-dim);margin:.6rem 0 0}
.oc-doc .lt-voice:empty{display:none}
.oc-doc .lt-voice .term-rail{display:block;margin:0;padding:0;border:0;min-height:0;color:inherit}
.oc-doc .lt-voice .keycast-row{display:block;margin:.4rem 0 0;line-height:1}
.oc-doc .lt-voice .keycast-caption{color:inherit}
.oc-doc .lt-voice .keycast-ghost{visibility:hidden}

/* ── x, medium ───────────────────────────────────────────────────────────────
   The compose box with X's one slim icon row under it. Medium deliberately,
   not full: the full case carries an avatar - a real photograph of a real
   person - and a medium is the same host read at a glance without one.

   `lt-empty` is NOT ported. In the tester the ring/divider/Post cluster hides
   while the buffer is empty, and that state is set by a page-local engine
   patch the shipped engine does not have. Here the cluster is simply always
   there, which is what the row looks like once you have typed anything - and
   every demo on this page has typed something. */
.oc-doc .lt .icb{display:inline-flex;align-items:center;justify-content:center;flex:none}
.oc-doc .lt .icb svg{display:block;fill:currentColor;width:100%;height:100%}
.oc-doc .lt .lt-spacer{margin-left:auto}
.oc-doc .lt .lt-pill{display:inline-flex;align-items:center;justify-content:center;gap:.45em;font-family:var(--doc-sans);font-size:.75rem;font-weight:700;border-radius:999px}
.oc-doc .lt .lt-med{padding:.25rem 1rem .55rem;gap:.7em}
.oc-doc .lt .lt-med .lt-pill{height:1.9em;font-size:.68rem;padding:.18em .9em 0}
.oc-doc .lt .lt-med .icb{width:15px;height:15px}

.oc-doc .lt-x{--term-caret:#ffffff;--term-bg:#000000;--term-fg:#E7E9EA;--term-dim:#71767B;--term-hl:rgba(29,155,240,.2);--term-sel-fg:#1D9BF0;--lt-border:#2F3336;--lt-divider:#2F3336;--lt-radius:16px}
.oc-doc .lt-x .lt-med{color:#71767B}
.oc-doc .lt-x .lt-post{background:#fff;color:#000;font-weight:700}
.oc-doc .lt-x .x-ring{width:20px;height:20px;border-radius:50%;flex:none;background:conic-gradient(#1D9BF0 0 14%,#3e4347 14% 100%);-webkit-mask:radial-gradient(farthest-side,transparent calc(100% - 3px),#000 calc(100% - 2px));mask:radial-gradient(farthest-side,transparent calc(100% - 3px),#000 calc(100% - 2px))}
.oc-doc .lt-x .x-vdiv{width:1px;height:1.9em;background:rgba(62,67,71,.5);flex:none}
.oc-doc .lt-x .x-plus{width:20px;height:20px;border:1px solid #536471;border-radius:50%;position:relative;flex:none}
.oc-doc .lt-x .x-plus::before,.oc-doc .lt-x .x-plus::after{content:"";position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);background:#1D9BF0}
.oc-doc .lt-x .x-plus::before{width:50%;height:1.5px}
.oc-doc .lt-x .x-plus::after{width:1.5px;height:50%}
.oc-doc .lt-x .lt-x-bar .x-loc,.oc-doc .lt-x .lt-med .x-loc{opacity:.5}
.oc-doc .lt-x .lt-med .x-ring{width:17px;height:17px}
.oc-doc .lt-x .lt-med .x-plus{width:17px;height:17px}
/* the divider must never be the row's tallest item, or the row gains height
   the moment the ring cluster shows and the whole block nudges down */
.oc-doc .lt-x .lt-med .x-vdiv{height:22px}
/* the promoted icons drop one at a time as the block narrows, then the row
   COMPRESSES rather than dropping the minimum set */
@container (max-width: 350px){ .oc-doc .lt-x .lt-med .lt-o3{display:none} }
@container (max-width: 320px){ .oc-doc .lt-x .lt-med .lt-o2{display:none} }
@container (max-width: 290px){ .oc-doc .lt-x .lt-med .lt-o1{display:none} }
@container (max-width: 310px){
  .oc-doc .lt-x .lt-med{gap:.45em}
  .oc-doc .lt-x .lt-med .icb{width:13px;height:13px}
  .oc-doc .lt-x .lt-med .x-ring{width:15px;height:15px}
  .oc-doc .lt-x .lt-med .x-plus{width:15px;height:15px}
  .oc-doc .lt-x .lt-med .lt-post{font-size:.62rem;padding:2px .8em 0}
}

/* ── THE OTHER MEDIUMS (ported 2026-09-15 from artefacts/live-dom-themes-src/theme.css, the tester and source of every colourway): gmail, reddit, linkedin, claude, gpt, hn, slack, dc - the medium (compact) variants only, no avatar rows. Add a rule here AND in artifact-kit/theme.css. ── */
.oc-doc .lt-gmail{--term-bg:#ffffff;--term-fg:#202124;--term-dim:#80868b;--term-hl:#e8f0fe;--term-sel-fg:#1a73e8;--lt-border:#dadce0;--lt-divider:#e8eaed;--lt-radius:8px;--lt-chip:#f1f3f4;--lt-chip-fg:#202124;--lt-chip-shadow:#dadce0}
.oc-doc .lt-gmail .lt-hdr{font-family:var(--doc-mono);font-size:.8rem;line-height:1.65rem;display:flex;flex-wrap:wrap;gap:.6rem;padding:.3rem 1rem;border-bottom:1px solid #e8eaed;color:#202124}
.oc-doc .lt-gmail .lt-label{color:#5f6368}
.oc-doc .lt-gmail .lt-fmt>span:first-child{position:relative;top:.06em}
.oc-doc .lt-gmail .lt-fmt{display:flex;flex-wrap:wrap;align-items:center;gap:.55em;margin:.3rem 1rem .55rem;padding:.32em .9em;background:#F1F3F4;border-radius:999px;color:#444746;font-family:var(--doc-mono);font-size:.72rem}
.oc-doc .lt-gmail .lt-fmt .icb{width:15px;height:15px}
.oc-doc .lt-gmail .lt-fmt .g-arrow{width:0;height:0;border-left:4px solid transparent;border-right:4px solid transparent;border-top:5px solid #444746;margin-left:-.15em}
.oc-doc .lt-gmail .lt-fmt .g-div{width:1px;height:1em;background:#C7C9CC;flex:none}
.oc-doc .lt-gmail .lt-send-row{padding:.3rem 1rem .75rem;gap:.9em}
.oc-doc .lt-gmail .lt-send{background:#0B57D0;color:#fff;font-size:.78rem;font-weight:700;height:2.4em}
.oc-doc .lt-gmail .lt-send-div{width:1px;height:1.4em;background:rgba(255,255,255,.4)}
.oc-doc .lt-gmail .lt-send .g-arrow{width:0;height:0;border-left:5px solid transparent;border-right:5px solid transparent;border-top:6px solid #fff}
.oc-doc .lt-gmail .lt-send-row .icb{width:17px;height:17px}
.oc-doc .lt-gmail .lt-send-row .icb, .oc-doc .lt-gmail .lt-med .icb{color:#444746}
.oc-doc .lt-gmail .lt-send-row .icb:not(.g-active), .oc-doc .lt-gmail .lt-med .icb:not(.g-active){border-radius:50%;box-sizing:content-box;padding:3.5px;margin:-3.5px}
.oc-doc .lt-gmail .lt-send-row .lt-spacer.icb:not(.g-active), .oc-doc .lt-gmail .lt-med .lt-spacer.icb:not(.g-active){margin:-3.5px -3.5px -3.5px auto}
.oc-doc .lt-gmail .lt-send-row .icb:not(.g-active):hover, .oc-doc .lt-gmail .lt-med .icb:not(.g-active):hover{background:#f2f2f2}
.oc-doc .lt-gmail .g-active{background:#D3E3FD;border-radius:50%;width:24px;height:24px}
.oc-doc .lt-gmail .g-active svg{width:17px;height:17px}
.oc-doc .lt-gmail .g-dim{opacity:.4}
.oc-doc .lt-reddit{--term-bg:#ffffff;--term-fg:#1A1A1B;--term-dim:#7C7C83;--term-hl:#E5F4FE;--term-sel-fg:#0079D3;--lt-border:#D7DADC;--lt-divider:#EDEFF1;--lt-radius:16px;--lt-chip:#EAEDEF;--lt-chip-fg:#1A1A1B;--lt-chip-shadow:#d7dadc}
.oc-doc .lt-reddit .lt-rd-bar{padding:.6rem 1rem .3rem;gap:.55em}
.oc-doc .lt-reddit .rd-pill{display:inline-flex;align-items:center;gap:.4em;height:2.15em;padding:0 .85em;border-radius:999px;background:#EAEDEF;color:#1A1A1B;font-family:var(--doc-sans);font-size:.72rem;font-weight:700;line-height:1}
.oc-doc .lt-reddit .rd-pill .icb{width:14px;height:14px}
.oc-doc .lt-reddit .rd-pill>span:not(.icb){position:relative;top:1px}
.oc-doc .lt-reddit .rd-user{position:relative;top:1px}
.oc-doc .lt-reddit .rd-vote{background:#D93A00;color:#fff}
.oc-doc .lt-reddit .rd-user{font-family:var(--doc-sans);font-size:.72rem;font-weight:700;color:#1A1A1B}
.oc-doc .lt-reddit .rd-av{position:relative;flex:none}
.oc-doc .lt-reddit .rd-av .rd-dot{position:absolute;right:-1px;bottom:-1px;width:8px;height:8px;background:#46D160;border:2px solid #fff;border-radius:50%}
.oc-doc .lt-reddit .rd-card{margin:.5rem 1rem .6rem;border:1px solid #D7DADC;border-radius:16px;overflow:hidden}
.oc-doc .lt-reddit .rd-card-hdr{display:flex;flex-wrap:wrap;align-items:center;gap:.5em;padding:.55rem 1rem 0;font-family:var(--doc-sans);font-size:.72rem;font-weight:700;color:#5C6C74}
.oc-doc .lt-reddit .rd-card-hdr .icb{width:13px;height:13px;color:#1A1A1B}
.oc-doc .lt-reddit .rd-card-hdr .rd-switch{margin-left:auto;color:#1A1A1B}
.oc-doc .lt-reddit .rd-card-btns{display:flex;justify-content:flex-end;gap:.5em;padding:0 .6rem .6rem}
.oc-doc .lt-reddit .lt-cancel{background:#E5E7EB;color:#1A1A1B}
.oc-doc .lt-reddit .lt-comment{background:#0045AC;color:#fff}
.oc-doc .lt-reddit .rd-sort{padding:.15rem 1rem .7rem;font-family:var(--doc-sans);font-size:.72rem;color:#7C7C83;gap:.5em}
.oc-doc .lt-reddit .rd-sort b{color:#576f76;font-weight:700}
.oc-doc .lt-reddit .rd-sort .icb{width:11px;height:11px;color:#576f76}
.oc-doc .lt-reddit .rd-search{display:inline-flex;align-items:center;gap:.5em;border:1px solid #D7DADC;border-radius:999px;height:2.3em;padding:.18em 1em 0;color:#7C7C83}
.oc-doc .lt-reddit .rd-search .icb{width:13px;height:13px}
.oc-doc .lt-linkedin{--term-bg:#1b1f23;--term-fg:#ffffff;--term-dim:#9fa6ad;--term-hl:#1d2b3a;--term-sel-fg:#70b5f9;--lt-border:#38434f;--lt-divider:#38434f;--lt-radius:8px}
.oc-doc .lt-linkedin .lt-li-top{padding-top:.7rem}
.oc-doc .lt-linkedin .lt-li-id{display:flex;flex-direction:column;line-height:1.3;font-family:var(--doc-sans)}
.oc-doc .lt-linkedin .lt-name{font-weight:700;color:#fff;font-size:.8rem;display:inline-flex;align-items:center;gap:.45em}
.oc-doc .lt-linkedin .lt-name .g-arrow{width:0;height:0;border-left:4px solid transparent;border-right:4px solid transparent;border-top:5px solid #fff}
.oc-doc .lt-linkedin .lt-sub{color:#fff;font-size:.7rem}
.oc-doc .lt-linkedin .lt-li-face{padding:.2rem 1rem 0;color:#9fa6ad}
.oc-doc .lt-linkedin .lt-li-face .icb{width:17px;height:17px;margin-left:.9em}
.oc-doc .lt-linkedin .lt-li-tools{padding:.35rem 1rem;gap:1.3em;color:#9fa6ad}
.oc-doc .lt-linkedin .lt-li-tools .icb{width:16px;height:16px}
.oc-doc .lt-linkedin .lt-enhance{display:inline-flex;align-items:center;gap:.55em;border:1px solid #8b95a1;border-radius:999px;height:2.3em;padding:0 1em;font-family:var(--doc-sans);font-size:.72rem;font-weight:700;color:#fff}
.oc-doc .lt-linkedin .lt-enhance .icb{width:14px;height:14px;color:#e7a33e;position:relative;top:-1px}
.oc-doc .lt-linkedin .lt-enhance>span:not(.icb){position:relative;top:1px}
.oc-doc .lt-linkedin .lt-li-postrow{border-top:1px solid #38434f;justify-content:flex-end;gap:1em;padding:.5rem 1rem .7rem;color:#9fa6ad}
.oc-doc .lt-linkedin .lt-li-postrow .icb{width:17px;height:17px}
.oc-doc .lt-linkedin .lt-post-li{background:#70b5f9;color:#0a1f33;font-weight:700}
.oc-doc .lt-linkedin.lt-empty .lt-post-li{background:#383a3d;color:#747578}
.oc-doc .lt-google.lt-empty .term .term-buffer, .oc-doc .lt-google-med.lt-empty .term .term-buffer, .oc-doc .lt-reddit.lt-empty .term .term-buffer{position:relative}
.oc-doc .lt-reddit.lt-empty .term .term-buffer::before{content:"Join the conversation";position:absolute;left:0;top:0;color:#7C7C83}
.oc-doc .lt-claude{--term-bg:transparent;--term-fg:#eeece6;--term-dim:#898782;--term-hl:rgba(217,119,87,.28);--term-sel-fg:#f5f3ed;--term-caret:#d6d4cd;--lt-divider:#3a3a38;--lt-chip:#2c2c2c;--lt-chip-fg:#eeece6;--lt-chip-shadow:#101010}
.oc-doc .lt-claude .cw-box{background:#202020;border:1px solid #3a3a38;border-radius:20px;overflow:hidden}
.oc-doc .lt-claude .term{background:#202020;padding:.8rem 1.2rem .3rem 1rem}
.oc-doc .lt-claude .cw-bar{padding:.4rem 1rem .75rem;gap:.9em;color:#898782}
.oc-doc .lt-claude .cw-plus{width:13.6px;height:13.6px;position:relative;flex:none}
.oc-doc .lt-claude .cw-plus::before, .oc-doc .lt-claude .cw-plus::after{content:"";position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);background:#fff;border-radius:1px}
.oc-doc .lt-claude .cw-plus::before{width:100%;height:1.25px}
.oc-doc .lt-claude .cw-plus::after{width:1.25px;height:100%}
.oc-doc .lt-claude .cw-seg{display:inline-flex;align-items:center;background:#232323;border:1px solid #303030;border-radius:8px;padding:0;font-family:var(--doc-sans);font-size:.72rem;font-weight:500;line-height:1}
.oc-doc .lt-claude .cw-seg .on{background:#3f3f3d;border:1px solid #565553;border-radius:6.5px;padding:.62em .9em .18em;color:#e8e6e1}
.oc-doc .lt-claude .cw-seg .off{color:#7a7975;padding:0 .9em;position:relative;top:.22em}
.oc-doc .lt-claude .cw-model{font-family:var(--doc-sans);font-size:.75rem;color:#e8e6e1;display:inline-flex;align-items:center;gap:.45em}
.oc-doc .lt-claude .cw-model .cw-high{color:#898782}
.oc-doc .lt-claude .cw-model .g-arrow{border:0;width:6px;height:6px;border-right:1.5px solid #898782;border-bottom:1.5px solid #898782;transform:rotate(45deg);margin-top:-4px;border-radius:1px}
.oc-doc .lt-claude .cw-model{border-radius:6px;height:25.7px;box-sizing:border-box;padding:0 .45em;margin:0 -.45em 0 auto}
.oc-doc .lt-claude .cw-model:hover{background:#363635}
.oc-doc .lt-claude .cw-bar .icb{width:20px;height:20px;border-radius:8px;box-sizing:content-box;padding:2.85px;margin:-2.85px}
.oc-doc .lt-claude .cw-bar .icb:hover{background:#363635}
.oc-doc .lt-claude .cw-bar .icb.lt-o2{padding:2.85px 6px;margin:-2.85px -6px}
.oc-doc .lt-claude .lt-med.cw-bar .icb{padding:5.35px;margin:-5.35px -5.35px -5.35px 0}
.oc-doc .lt-claude .lt-med.cw-bar .icb.lt-o2{padding:5.35px 6px;margin:-5.35px -6px -5.35px -1px}
.oc-doc .lt-claude .cw-bar .icb{color:#c9c7c2}
.oc-doc .lt-claude .cw-chips{padding:.9rem 0 0;gap:.6em;justify-content:center;background:transparent}
.oc-doc .lt-claude .cw-chip{display:inline-flex;align-items:center;gap:.35em;background:#2c2c2c;border-radius:8px;height:2.6em;padding:0 calc(1.05em - 2px) 0;color:#eeece6;font-family:var(--doc-sans);font-size:.75rem;font-weight:500;line-height:1;white-space:nowrap}
.oc-doc .lt-claude .cw-chip:hover{background:#393939}
.oc-doc .lt-claude .cw-chip .icb{width:16px;height:16px;color:#c9c7c2}
.oc-doc .lt-claude .cw-chip>span:not(.icb){margin-top:2px}
.oc-doc .lt-claude.lt-m{background:#202020;border:1px solid #3a3a38;border-radius:20px}
.oc-doc .lt-claude.lt-empty .term .term-buffer{position:relative}
.oc-doc .lt-claude.lt-empty .term .term-buffer::before{content:"How can I help you today?";position:absolute;left:0;top:0;color:#898782}
.oc-doc .lt-slack{--term-bg:#222529;--term-fg:#d1d2d3;--term-dim:#9a9b9e;--term-hl:rgba(29,155,209,.3);--term-sel-fg:#d1d2d3;--term-caret:#d1d2d3;--lt-divider:#35383c;--lt-border:#565856;--lt-radius:8px;background:#222529}
.oc-doc .lt-slack .sk-fmt{display:flex;flex-wrap:wrap;align-items:center;gap:.75em;padding:.55rem 1rem .15rem;color:#adaeaf}
.oc-doc .lt-slack .sk-fmt .icb{width:15px;height:15px}
.oc-doc .lt-slack .sk-div{width:1px;height:1.15em;background:#35383c;flex:none;margin:0 -.2em}
.oc-doc .lt-slack .sk-bar{padding:.3rem .7rem .55rem;gap:1.05em;color:#adaeaf}
.oc-doc .lt-slack .sk-bar .icb{width:15px;height:15px}
.oc-doc .lt-slack .sk-bar>.icb{border-radius:4px;box-sizing:content-box;padding:6.5px 4.5px;margin:-6.5px -4.5px}
.oc-doc .lt-slack .sk-bar>.icb:hover{background:#1a1d21;color:#fff}
.oc-doc .lt.lt-slack .lt-med.sk-bar{gap:1.3em}
.oc-doc .lt-slack .sk-plus{width:26px;height:26px;border-radius:50%;background:#2e3135;position:relative;flex:none}
.oc-doc .lt-slack .sk-plus::before, .oc-doc .lt-slack .sk-plus::after{content:"";position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);background:#adaeaf;border-radius:1px}
.oc-doc .lt-slack .sk-plus::before{width:11px;height:1.4px}
.oc-doc .lt-slack .sk-plus::after{width:1.4px;height:11px}
.oc-doc .lt-slack .sk-sendwrap{display:inline-flex;align-items:center;gap:.55em;height:24px;padding:0 7px;border-radius:4px;background:#007a5a;color:#fff}
.oc-doc .lt-slack .sk-sendbtn{display:inline-flex;align-items:center;justify-content:center}
.oc-doc .lt-slack .sk-sendbtn .icb{width:15px;height:15px}
.oc-doc .lt-slack .sk-sendwrap .sk-div{background:rgba(255,255,255,.5)}
.oc-doc .lt-slack .sk-chev{width:11px;height:11px;color:#fff}
.oc-doc .lt-slack.lt-empty .sk-sendwrap{background:transparent;color:#57595d}
.oc-doc .lt-slack.lt-empty .sk-sendwrap .sk-div{background:#35383c}
.oc-doc .lt-slack.lt-empty .sk-chev{color:#57595d}
.oc-doc .lt-slack .sk-field{position:relative}
.oc-doc .lt-slack .sk-ph{position:absolute;left:1rem;top:.8rem;display:none;align-items:center;gap:.4em;color:#9a9b9e;pointer-events:none;font-family:var(--doc-mono);font-size:.8rem;line-height:1.65rem;white-space:nowrap}
.oc-doc .lt-slack.lt-empty .sk-ph{display:inline-flex}
.oc-doc .lt-slack .sk-lock{position:relative;width:9px;height:11px;display:inline-block;flex:none}
.oc-doc .lt-slack .sk-lock::before{content:"";position:absolute;left:1.5px;top:0;width:6px;height:6px;border:1.5px solid #9a9b9e;border-bottom:0;border-radius:3px 3px 0 0;box-sizing:border-box}
.oc-doc .lt-slack .sk-lock::after{content:"";position:absolute;left:0;bottom:0;width:9px;height:6px;background:#9a9b9e;border-radius:1.5px}
.oc-doc .lt-dc{--term-bg:#222327;--term-fg:#dbdee1;--term-dim:#8b8d94;--term-hl:rgba(88,101,242,.4);--term-sel-fg:#ffffff;--term-caret:#dbdee1;--lt-divider:#3b3d44;--lt-radius:8px;background:#222327}
.oc-doc .lt-dc .dc-row{display:flex;align-items:flex-start}
.oc-doc .lt-dc .dc-plus{flex:none;display:flex;align-items:flex-start;justify-content:center;width:2.6rem;padding-top:calc(1.625rem - 9.5px);color:#abacb2}
.oc-doc .lt-dc .dc-plus .icb{width:19px;height:19px}
.oc-doc .lt-dc .dc-field{flex:1;min-width:0;position:relative}
.oc-doc .lt-dc.lt-m .term{padding:.8rem 1rem}
.oc-doc .lt-dc.lt-m .dc-ph{left:1rem}
.oc-doc .lt-dc .dc-icons{flex:none;display:flex;align-items:flex-start;gap:.3em;padding:calc(1.625rem - 15px) .55rem 0 .35rem;color:#abacb2}
.oc-doc .lt-dc .dc-ic{display:inline-flex;align-items:center;justify-content:center;width:30px;height:30px;border-radius:6px}
.oc-doc .lt-dc .dc-ic .icb{width:19px;height:19px}
.oc-doc .lt-dc .dc-ic:hover{background:#343539;color:#fff}
.oc-doc .lt-dc .dc-ph{position:absolute;top:.8rem;display:none;color:#8b8d94;pointer-events:none;font-family:var(--doc-mono);font-size:.8rem;line-height:1.65rem;white-space:nowrap}
.oc-doc .lt-dc.lt-empty .dc-ph{display:block}
.oc-doc .lt-hn{--term-bg:#ffffff;--term-fg:#1a1a1a;--term-dim:#828282;--term-hl:rgba(255,102,0,.35);--term-sel-fg:#000000;--term-caret:#1a1a1a;--lt-divider:#e0e0dc;background:#f6f6ef;padding:0 0 1.2rem}
.oc-doc .lt-hn .hn-topbar{display:flex;align-items:center;gap:.55em;background:#ff6600;padding:.3rem .8rem;font-family:var(--doc-sans);font-size:.78rem;color:#000;white-space:nowrap;overflow:hidden}
.oc-doc .lt-hn .hn-y{width:1.3em;height:1.3em;border:1.5px solid #fff;color:#fff;font-weight:700;display:inline-flex;align-items:center;justify-content:center;flex:none;font-size:.72rem}
.oc-doc .lt-hn .hn-brand{font-weight:700}
.oc-doc .lt-hn .hn-nav{overflow:hidden;text-overflow:ellipsis}
.oc-doc .lt-hn .hn-title{font-family:var(--doc-sans);color:#1a1a1a;line-height:1.2;padding:.95rem 1.2rem 0 calc(1.2rem + 17px);position:relative}
.oc-doc .lt-hn .hn-vote{position:absolute;left:1.2rem;top:calc(.95rem + .3em);width:0;height:0;border-left:5px solid transparent;border-right:5px solid transparent;border-bottom:9px solid #999}
.oc-doc .lt-hn .hn-t{font-size:.95rem}
.oc-doc .lt-hn .hn-domain{font-size:.72rem;color:#828282;white-space:nowrap}
.oc-doc .lt-hn .hn-sub{font-family:var(--doc-sans);font-size:.78rem;color:#828282;line-height:1.4;padding:.3rem 1.2rem 0 calc(1.2rem + 17px)}
.oc-doc .lt-hn .term{margin:.9rem 1.2rem 0;background:var(--term-bg);border:1px solid #3c3c3c;border-radius:3px;padding:.35rem .8rem}
.oc-doc .lt-hn .hn-btnrow{margin:1rem 1.2rem 0}
.oc-doc .lt-hn .hn-btn{display:inline-flex;align-items:center;font-family:var(--doc-sans);font-size:.75rem;background:#f2f2f0;border:1px solid #9a9a9a;color:#111;padding:.18em .8em 0;height:2.2em;border-radius:4px}
.oc-doc .lt-hn.lt-m{--term-bg:#f6f6ef;padding:0}
.oc-doc .lt-hn.lt-m .term{margin:0;border:0;border-radius:0;padding:.8rem 1rem}
.oc-doc .lt-hn .lt-med{padding:.1rem 1rem .6rem}
.oc-doc .lt-gpt{--term-bg:#212121;--term-fg:#ececec;--term-dim:#9f9f9f;--term-hl:rgba(60,102,191,.45);--term-sel-fg:#ffffff;--term-caret:#ececec;--lt-divider:#3a3a3a;background:transparent;padding:0}
.oc-doc .lt-gpt .gpt-bar{background:#212121;border-radius:28px;display:flex;align-items:flex-start}
.oc-doc .lt-gpt .gpt-plus{flex:none;display:flex;align-items:center;justify-content:center;width:2.9rem;height:3.25rem;color:#fff}
.oc-doc .lt-gpt .gpt-plus .icb{width:17px;height:17px}
.oc-doc .lt-gpt .gpt-field{flex:1;min-width:0;position:relative}
.oc-doc .lt-gpt .gpt-bar .term{padding:.8rem 1.3rem .8rem 0}
.oc-doc .lt-gpt .gpt-ph{position:absolute;top:.8rem;left:0;display:none;color:#9f9f9f;pointer-events:none;font-family:var(--doc-mono);font-size:.8rem;line-height:1.65rem;white-space:nowrap}
.oc-doc .lt-gpt.lt-empty .gpt-ph{display:block}
.oc-doc .lt-gpt .gpt-tools{flex:none;display:flex;align-items:center;height:3.25rem;gap:1.5em;padding:0 .55rem 0 .35rem;position:relative;z-index:1}
.oc-doc .lt-gpt .gpt-think{display:inline-flex;align-items:center;gap:.5em;color:#afafaf;font-family:var(--doc-sans);font-size:.75rem}
.oc-doc .lt-gpt .gpt-think .icb{width:16px;height:16px;margin-bottom:2px}
.oc-doc .lt-gpt .gpt-think span{margin-top:2px}
.oc-doc .lt-gpt .gpt-mic{color:#fff;width:17px;height:17px}
.oc-doc .lt-gpt .gpt-voice{display:inline-flex;align-items:center;justify-content:center;width:32px;height:32px;border-radius:50%;background:#3c66bf;color:#fff;flex:none}
.oc-doc .lt-gpt .gpt-voice .icb{width:18px;height:18px}
.oc-doc .lt-gpt .gpt-voice .gpt-vsend{display:none}
.oc-doc .lt-gpt:not(.lt-empty) .gpt-voice .gpt-vaudio{display:none}
.oc-doc .lt-gpt:not(.lt-empty) .gpt-voice .gpt-vsend{display:inline-flex}
.oc-doc .lt-gpt .gpt-think{height:32px;box-sizing:border-box;padding:0 12px;margin:0 -12px;border-radius:999px}
.oc-doc .lt-gpt .gpt-plus .icb, .oc-doc .lt-gpt .gpt-mic{border-radius:50%;box-sizing:content-box;padding:7.5px;margin:-7.5px}
.oc-doc .lt-gpt .gpt-think:hover, .oc-doc .lt-gpt .gpt-plus .icb:hover, .oc-doc .lt-gpt .gpt-mic:hover{background:#2e2e30}
.oc-doc .lt-gpt.lt-m{background:#212121;padding:0;border-radius:12px}
.oc-doc .lt-gpt.lt-m .term{padding:.8rem 1rem}
.oc-doc .lt.lt-gpt .lt-med{gap:1.9em;padding:.1rem 1rem .6rem}
.oc-doc .lt-gpt .lt-med .icb{width:16px;height:16px}
.oc-doc .lt-gpt .lt-med .gpt-w{color:#fff;border-radius:50%;box-sizing:content-box;padding:7px;margin:-7px}
.oc-doc .lt-gpt .lt-med .gpt-mic{width:16px;height:16px;padding:7px;margin:-7px}
.oc-doc .lt-gpt .lt-med .gpt-think{height:29px;padding:0 10px;margin:0 -10px 0 auto}
.oc-doc .lt-gpt .lt-med .gpt-w:hover{background:#2e2e30}
.oc-doc .lt-gpt .lt-med .gpt-voice{width:29px;height:29px}
.oc-doc .lt-gpt .lt-med .gpt-voice .icb{width:16px;height:16px}
.oc-doc .lt-linkedin .lt-med{color:#9fa6ad;gap:1em}
@container (max-width: 460px){ .oc-doc .lt-claude .cw-chips .lt-o3{display:none} }
@container (max-width: 340px){ .oc-doc .lt-claude .cw-chips .lt-o2{display:none} .oc-doc .lt-claude .cw-bar .lt-o2{display:none} }
@container (max-width: 310px){ .oc-doc .lt-claude .lt-med .lt-o1{display:none} }
@container (max-width: 380px){ .oc-doc .lt-gmail .lt-hdr .lt-ccbcc{display:none} }
@container (max-width: 470px){ .oc-doc .lt-gmail .lt-fmt .lt-o3{display:none} }
@container (max-width: 350px){ .oc-doc .lt-gmail .lt-fmt .lt-o2{display:none} .oc-doc .lt-gmail .lt-send-row .lt-o3{display:none} }
@container (max-width: 290px){ .oc-doc .lt-gmail .lt-fmt .lt-o1{display:none} }
@container (max-width: 460px){ .oc-doc .lt-reddit .lt-rd-bar .lt-o3{display:none} }
@container (max-width: 430px){ .oc-doc .lt-gpt .gpt-think{display:none} }
@container (max-width: 560px){ .oc-doc .lt-gmail .lt-med .lt-o3{display:none} }
@container (max-width: 450px){ .oc-doc .lt-gmail .lt-med .lt-o2{display:none} }
@container (max-width: 380px){ .oc-doc .lt-gmail .lt-med .lt-o1{display:none} }
@container (max-width: 460px){ .oc-doc .lt-reddit .lt-med .lt-o3{display:none} }
@container (max-width: 390px){ .oc-doc .lt-reddit .lt-med .lt-o2{display:none} }
@container (max-width: 330px){ .oc-doc .lt-reddit .lt-med .lt-o1{display:none} }
@container (max-width: 360px){ .oc-doc .lt-linkedin .lt-med .lt-o3{display:none} }
@container (max-width: 320px){ .oc-doc .lt-linkedin .lt-med .lt-o2{display:none} }
@container (max-width: 290px){ .oc-doc .lt-linkedin .lt-med .lt-o1{display:none} }
