/* Hallmark · v7.16.0 · the Franca documentation surface (快速开始 · 接口参考 · 指南 · 规则 · 错误码 · 更新公告) · shape: the reference platforms' docs anatomy — the site chrome up top, a left menu tree, the document in a right column (the user's ruling: docs as their own surface, navigated by a menu, not by scattered in-sentence links) · job: find the page in the menu, read the answer, make the first call · carries: the home sheet's tokens and chrome via import, the docs shell, the code panel, the error tables and the prose measures these pages alone need */
/* critique: the docs were islands before the v7 pass — three single pages whose only cross-links were sentences the global anchor style made invisible, which the user called 没有一点意义, and the reference sites (OpenRouter, SiliconFlow) all answer the same problem the same way: a left menu that names the whole document set on every page; that shell is built and this pass takes the user's second ruling on it: the menu names the document set only — the eleven console error category pages are control-plane landing pages reached by the URLs the API emits verbatim (model-r.com/problems/<slug>), not docs entries, so the group and its styles go and no page of the set is stranded: the category pages keep the shell, their menu names the docs and carries no aria-current, because the page the reader stands on is not one of them; the errors page's control-plane note now states the address scheme alone, pointing at no listing that no longer exists; the docs banner stays gone, the menu still folds into an expand-in-flow 目录 button below the docs breakpoint, and the anchors on every error code row stay untouched — the shell wraps content whose URLs are wire contracts  — v7.2.0 answers the user's next two orders: the code column links (a table row that names a destination is a door to it, so each code now carries an underline and jumps to its own detail block) and the detail exists — before this pass a code was one sentence, now every code lists the concrete situations it covers and the handling for each, taken from the validation code's own contract (RequestValidationCode), nothing invented; the #<code> anchor moves from the table row to the detail heading so the address the future error.doc_url mints lands on the full answer, not on a one-line row — v7.3.0 answers the order that the per-code details must be written against the code and the scenarios, in the reference platforms' pattern (OpenAI's error guide, Zhipu's 错误码 page): every block now carries the concrete situations, one request that triggers the code, the envelope the gateway actually renders (each message text is the throw site's literal, verified against JsonGuard, the three dialect validators, and the admission gates), and the repair — prose detail is replaced by evidence — v7.4.0 answers the user's two orders on that evidence: the JSON panels go compact (one row per top-level member, nested values inline — pretty-print air was padding the panels, not explaining them) and the code links' underline takes the code accent's colour, because the global anchor's near-white currentColor drew a white bar under the azure code text (the affordance the prose links already wear: colour says link, the accent says which register) — v7.4.0 also compacted the JSON panels; the user's correction followed: the compaction was the wrong reading, the nesting itself stays expanded (a key per line is how reference platforms print JSON), and the air the user saw was the code line-height (1.8 at 14px, 25px between rows); v7.5.0 restored the expanded renderer at a 1.5 rhythm, and the user ruled again with a sample: the JSON members sit on consecutive tight lines, no inter-line air at all — v7.6.0 set the code rhythm to 1.3 (18px at 14px mono) — and the user then asked the question that found the real defect: the envelope sample and the request panels were NOT one style; the panels' rows were display:block inside a pre, so the preserved newline plus the block break stacked into a blank line between every row (the 孔 the user saw from the start — the line-height passes treated the symptom), and only the envelope sample, whose lines carry no row spans, was tight; v7.7.0 makes every panel the envelope sample's shape: the rows are inline spans, the pre's own newlines break the lines, and the line-number column is gone (the reference platforms print JSON samples unnumbered) — v7.8.0 answers the user's report that model-r.com broke mid-token across a line in the prose: '-' and '/' are the browser's default break opportunities, so an address inside running text can split at model-; every inline code token in docs prose is now white-space: nowrap — the token moves to the next line whole or not at all — v7.9.0 answers the user's order to fill the gap against the reference platforms' taxonomy (Zhipu's 接口参考/指南/规则/公告): thirteen pages built from the backend's own contracts (the three dialect validators, the models endpoint, the pricing windows, the rate-limit kinds, the compaction operation), no invented capability anywhere — embeddings and the other unimplemented surfaces stay undocumented; the menu, flat since the shell was built, now carries group labels so a 20-entry tree reads as sections, and the labels are the reference platforms' spelling: the body face, a step smaller, untracked, never buttons or tracked caps — v7.10.0 answers the user's order that the menu's first level read as structure: the group labels wore the same grey as the member links (both text-2), so the twenty-entry tree read flat and a section head was indistinguishable from an entry; the labels now take their own dimmer grey, declared as a token on the same hue line (still above 4.5:1 on the navy ground), and drop a step in size (fs-xs against the links' fs-sm) — grey says structure, size says which register — v7.11.0 documents the Responses endpoint's WebSocket transport, the user's order grounded in franca-spring-protocol-websocket: the same-path upgrade handshake, the flat response.create envelope (never the Realtime nested shape), stream_id lanes, the connection-local continuation cache behind previous_response_id, the transport error codes, and the session bounds; the Responses page gains the section, the streaming guide's Responses bullet and the announcements entry cross-link it, and the previous_response_id row now states both surfaces (HTTP 404 on this deployment, WebSocket resolves from the connection-local cache); the sheet follows main-41, whose c8 hanzi subset carries the eight new glyphs — v7.12.0 answers the user's order that the prose stop auto-wrapping: hanzi are legal break points everywhere, so the browser's greedy wrap cut lines mid-clause at arbitrary characters; every lead, note and list row now carries an authored <br class="docs-br"> after a clause punctuation with every line inside its container's measure — the marks are literal copy in the builder, placed by hand, no computation at build time — and they fold away below the docs breakpoint where the measure is narrower than any authored line; the same pass fixes three raw <密钥> spellings that parsed as unknown elements and silently dropped the word from the rendered text — v7.13.0 answers the user's final ruling: the authored break marks and the clause-break machinery are gone from every page and from this sheet (the fold rule below the breakpoint is deleted with them); the prose is ordinary flowing paragraphs the browser wraps at word boundaries, the one protection kept being v7.8.0's nowrap inline-code tokens, which still keep addresses like model-r.com whole across the wrap; the pages are now hand-maintained HTML — the generator that produced them is deleted — v7.14.0 answers the user's design order (照人家的文档页重新设计，该对齐的对齐，不要糊弄): the document column is capped at one measure (780px) so prose, tables and panels share a single aligned width instead of sprawling full-bleed to the viewport; CJK prose goes justified — the Chinese reference platforms' convention — because a ragged right edge on hanzi reads as a saw cut, and the nowrap v7.8.0 tokens ride inside the justified flow; the endpoint fact line under each API page's H1 becomes its own register (mono, the method in the accent) instead of grey body copy; inline code tokens in prose become frosted mono chips and leave the accent colour — colour in prose now means only a link, so the page stops being a field of azure shards; the per-code status facts go mono too; tables get semantic column rules (the params variant: identifier mono nowrap, type mono grey, constraint, description carrying the measure; the codes variant: linked identifier, HTTP fact, meaning), so the wide tables sit in proportion inside the column; headings take the SemiBold weight the PuHuiTi subset always carried but the sheet never spent — size plus weight now says hierarchy, and the h2 drops a step to live inside the narrower column — v7.15.0 answers the user's defect report on that justification (一行被拉长，字之间像有很多空格): the v7.8.0 nowrap chips are large unbreakable atoms, and when a chip does not fit the rest of a justified line, the justifier stretched the short remainder across the 780px measure, so the shared lead's first line read as hanzi separated by wide gaps. Justification is removed: hanzi wrap at every character, so a left-aligned line ends within one hanzi of the edge and reads flush without any stretching, and a line a whole chip moves down from leaves white space at the edge, never air between characters. The chips keep the v7.8.0 nowrap rule (addresses still never split at a hyphen), and the shared lead on the four API pages now names the two headers by identifier only (Authorization, Content-Type) — the concrete values sit in every 请求示例 panel — v7.16.0 answers the user's ruling on the parameter tables (这种表格允许出现横向滚动，不要太过挤压): the v7.14.0 width hints (identifier 30%, code 26%) spent a fixed share of the measure on the widest row's shape — a five-character identifier sat in a 234px column and the description column paid for it with early wraps; the hints are removed, the auto layout sizes the identifier column to its widest token and the constraint column to its widest cell, and the description takes the remainder; and every table now sits inside its own scroll wrapper, so a table whose minimum width still exceeds the column (a long token, a phone canvas) scrolls horizontally instead of being squeezed or clipped by the page — one mechanism at every width, which also retires the ≤960px display:block rule v7.14.0 carried for the same problem */
/* answered, on the record: the section count · these are reference pages (layout.md § 7): the errors page is rows of one vocabulary, a category page reads on a single screen, and more sections would be padding */
/* answered, on the record, not waivable: 40 rides the home sheet's own answered line (brand-1 under white text, the production portal's measured primary) */
/* answered, on the record: F22 justified prose on these pages · hyphenation is a Latin concern (Chrome hyphenates no zh-CN text anyway), the prose is hanzi that breaks between characters by definition, the warn rode the v7.14.0 justification and dies with it — v7.15.0 removed the justified-alignment after the user reported the stretched lines (the nowrap chips are unbreakable atoms, and the justification spread the leftover measure between the characters); the prose is left-aligned, hanzi wrap within one character of the edge, no hyphenation needed
/* answered, on the record: 58 on the errors page · the per-code blocks are the reference evidence the user ordered written against the code (situations, triggering request, real envelope, repair, one block per code); the 450-word cap rules a marketing screen, and trimming evidence to fit it would undo the order */
@import url('main-41.css');

/* The menu's section labels' grey: one step dimmer than text-2 on the same hue
   line, above 4.5:1 on the navy ground — grey says structure, not a link. */
:root {
	--menu-label: oklch(0.58 0.02 250);
}

/* ------------------------------------------------------------------ */
/* The docs shell — menu left, document right                           */
/* ------------------------------------------------------------------ */

.docs-shell {
	display: grid;
	grid-template-columns: 232px minmax(0, 1fr);
	column-gap: 64px;
	align-items: start;
	padding: 48px 0 96px;
}

/* The menu rides under the sticky 64px bar and owns the viewport below it,
   so a long tree scrolls inside the menu, never the page. */
.docs-menu {
	position: sticky;
	top: 88px;
	max-height: calc(100vh - 120px);
	overflow-y: auto;
	display: flex;
	flex-direction: column;
}

.docs-menu a {
	padding: 8px 12px;
	border-left: 2px solid transparent;
	color: var(--text-2);
	font-size: var(--fs-sm);
	line-height: 1.5;
	transition: color var(--speed), border-color var(--speed);
}

.docs-menu a:hover {
	color: var(--text-1);
}

.docs-menu a[aria-current='page'] {
	color: var(--text-1);
	border-left-color: var(--code-accent);
}

/* A group label names a section of the tree (接口参考, 指南, 规则): the body
   face, a step smaller than its member links, untracked — the reference
   platforms' section labels, never buttons and never tracked caps. The dimmer
   label grey separates structure from entries (the user's order); it opens its
   block with air above, and the links under it are its members. */
.docs-menu-group {
	padding: 20px 12px 4px;
	color: var(--menu-label);
	font-size: var(--fs-xs);
	font-weight: 500;
}

/* The fold-out control the menu becomes below the docs breakpoint: a plain
   button, hidden on wide screens where the menu is always a column. */
.docs-menu-toggle {
	display: none;
}

/* ------------------------------------------------------------------ */
/* The document column — one measure for every register                  */
/* ------------------------------------------------------------------ */

/* The whole document lives in one capped measure (the reference platforms'
   doc column): prose, tables and panels share the same width and left edge,
   so nothing sprawls toward the viewport and every register aligns. The
   measure is 780px — 43em at the 18px body — wide enough for the four-column
   parameter tables to sit in proportion, narrow enough that a prose line
   stays a comfortable read. */
.docs-page {
	max-width: 780px;
}

/* The page opens on its H1 at working size in the SemiBold weight the subset
   always carried — size plus weight says hierarchy, not size alone. */
.docs-page h1 {
	font-size: 30px;
	font-weight: 600;
	letter-spacing: 0.01em;
}

.docs-section {
	padding: 56px 0 0;
}

/* The section head drops a step from the old 25px to live inside the narrower
   column, and takes the SemiBold weight; its air above carries the section,
   no rules, no chips. */
.docs-section h2 {
	font-size: 22px;
	font-weight: 600;
	letter-spacing: 0.01em;
}

.docs-section h2 + .docs-note {
	margin-top: 12px;
}

.docs-section h2 + .docs-list {
	margin-top: 24px;
}

/* The endpoint fact line under the H1: one mono line, the method in the
   accent, the address in the first ink — the page's identity in its own
   register, not grey body copy (the reference platforms print the method and
   path in the code face here). */
.docs-endpoint {
	margin-top: 12px;
	font-family: var(--font-mono);
	font-size: 14px;
	color: var(--text-1);
	/* The address is one unbroken token (no spaces), so below the docs
	   breakpoint the chat/completions path outgrows the phone column; the
	   endpoint register allows the last-resort wrap the prose chips forbid —
	   at the 780px measure this never fires, every endpoint sits on one
	   line. */
	overflow-wrap: anywhere;
}

.docs-endpoint .docs-method {
	color: var(--code-accent);
}

/* ------------------------------------------------------------------ */
/* Docs prose — chipped, one colour discipline                          */
/* ------------------------------------------------------------------ */

/* Hanzi prose is left-aligned, never justified (the v7.15.0 ruling). Hanzi
   wrap at every character, so a left-aligned line ends within one hanzi of
   the edge and reads flush on its own — the saw-cut raggedness v7.14.0 was
   answering belonged to the old uncapped measure. Justification, by
   contrast, had to pay for the v7.8.0 nowrap chips: a chip is one
   unbreakable atom, and when it moved down a line the justifier stretched
   the short remainder across the measure — the wide gaps between characters
   the user reported. Left-aligned, a line a chip moves down from ends short
   at the edge instead: the leftover sits at the margin where it belongs,
   never between the characters. Line-height 1.85 — hanzi need more leading
   than Latin at the same size. */
.docs-lead,
.docs-note,
.docs-list li {
	line-height: 1.85;
}

.docs-lead {
	margin-top: 12px;
	color: var(--text-2);
	font-size: 17px;
}

.docs-note {
	margin-top: 12px;
	color: var(--text-2);
}

/* Inline code in prose is a frosted mono chip: the reference platforms'
   inline-code treatment. The accent colour LEAVES the prose tokens — colour
   in running text now means only a link, so the page stops reading as a
   field of azure shards. The chip keeps the v7.8.0 nowrap rule: an address
   never splits at a hyphen, and a chip that does not fit moves down whole. */
.docs-lead code,
.docs-note code,
.docs-list li code {
	font-family: var(--font-mono);
	font-size: 0.88em;
	color: var(--text-1);
	background: var(--frost);
	border: 1px solid var(--border);
	border-radius: 5px;
	padding: 0 8px;
	white-space: nowrap;
}

/* Prose links keep the one colour that means a link: the code accent plus an
   underline that never goes — colour says link, the chip says identifier,
   and the two registers no longer share a face. */
.docs-lead a,
.docs-note a,
.docs-list li a {
	color: var(--code-accent);
	text-decoration: underline;
	text-underline-offset: 3px;
}

.docs-lead a:hover,
.docs-note a:hover,
.docs-list li a:hover {
	color: var(--text-1);
}

.docs-list {
	list-style: none;
	margin: 24px 0 0;
	padding: 0;
	display: flex;
	flex-direction: column;
}

/* The row measure is the column: the old 42em cap is gone, the column cap
   rules every register together. */
.docs-list li {
	padding: 20px 0;
	border-top: 1px solid var(--border);
	color: var(--text-2);
}

/* ------------------------------------------------------------------ */
/* The tables — one scroll lane, columns sized to content                */
/* ------------------------------------------------------------------ */

/* A wide table scrolls in its own lane, it never compresses its columns:
   the wrapper is the scroll container at every width, so a table whose
   minimum width exceeds the column — a long identifier, a phone canvas —
   scrolls horizontally instead of being squeezed into wraps or clipped
   invisibly by the page (the user's ruling). */
.docs-table-scroll {
	overflow-x: auto;
}

.docs-table {
	width: 100%;
	margin-top: 28px;
	border-collapse: collapse;
	font-size: var(--fs-sm);
}

/* Heads are labels: the body face, one weight, a step smaller, untracked —
   never small caps (67). */
.docs-table th {
	text-align: left;
	padding: 0 20px 8px 0;
	border-bottom: 1px solid var(--border-strong);
	color: var(--text-2);
	font-size: var(--fs-foot);
	font-weight: 500;
}

.docs-table td {
	padding: 12px 20px 12px 0;
	border-bottom: 1px solid var(--border);
	color: var(--text-2);
	vertical-align: top;
}

/* Identifier cells in tables are plain mono in the first ink — no chip, no
   accent: the chip is a prose device, the table keeps its cells flat so a
   14-row param table does not read as a tray of pills. */
.docs-table code {
	font-family: var(--font-mono);
	font-size: 13px;
	color: var(--text-1);
	white-space: nowrap;
}

/* The params variant (参数 · 类型 · 约束 · 说明): no width hints — the
   identifier column is nowrap mono and the auto layout sizes it to its
   widest token (stream_options.include_usage stays one token), the type
   column is mono grey (string, array are code words, not hanzi), the
   constraint column hugs its widest cell, and the description column takes
   the whole remainder. The v7.14.0 hint spent a fixed 30% of the measure on
   the identifier column regardless of its content — five characters sat in
   234px while the description wrapped early (the 挤压 the user ruled
   against); content-based sizing gives the description everything the
   narrower rows leave free. */

.docs-table--params td:nth-child(2) {
	font-family: var(--font-mono);
	font-size: 13px;
	white-space: nowrap;
	color: var(--text-2);
}

/* The codes variant (type/code · HTTP · 含义) on the errors page: the same
   ruling — the identifier column carries the anchors and sizes to its widest
   code, the HTTP column is a two-to-three character mono fact, the meaning
   column takes the remainder. */

.docs-table--codes td:nth-child(2) {
	font-family: var(--font-mono);
	font-size: 13px;
	white-space: nowrap;
	color: var(--text-2);
}

/* A code cell is a door to its detail block: the mono accent the code already
   wears, plus the underline that says the destination exists. */
.docs-table td a {
	text-decoration: underline;
	text-decoration-color: var(--code-accent);
	text-underline-offset: 3px;
}

.docs-table td a:hover {
	color: var(--text-1);
}

/* ------------------------------------------------------------------ */
/* The per-code detail blocks (分码说明)                                */
/* ------------------------------------------------------------------ */

.docs-code {
	padding: 32px 0 0;
}

/* The heading anchors the code (the #<code> address the future doc_url
   mints); the page reads under a sticky bar, so a hash jump clears it. */
.docs-code h3 {
	margin-top: 24px;
	font-size: 17px;
	font-weight: 600;
	scroll-margin-top: 96px;
}

.docs-code h3 a {
	color: var(--text-1);
	font-family: var(--font-mono);
	font-size: 16px;
}

.docs-code h3 a:hover {
	color: var(--code-accent);
}

/* The status fact under the code name: mono, a step smaller — HTTP numbers
   and error classes are code vocabulary, set in the code face (the user's
   font-register order), never part of the heading itself (38iii). */
.docs-code-status {
	margin-top: 8px;
	color: var(--text-2);
	font-family: var(--font-mono);
	font-size: var(--fs-sm);
}

/* The case list rides tighter than the section list: each row is one
   situation, read in a sweep. */
.docs-code-cases {
	margin-top: 16px;
}

.docs-code-cases li {
	padding: 12px 0;
}

/* The per-code panel captions name which payload is which: a fact line in
   the body face, a step smaller, never tracked caps. */
.docs-code-cap {
	margin-top: 20px;
	color: var(--text-2);
	font-size: var(--fs-sm);
}

/* Inside a detail block the panels follow their caption tightly. */
.docs-code .code-panel {
	margin-top: 8px;
}

.docs-code-fix {
	margin-top: 16px;
}

/* ------------------------------------------------------------------ */
/* Tabs + the code panel                                               */
/* ------------------------------------------------------------------ */

.tabs {
	display: flex;
	gap: 8px;
	margin-top: 40px;
}

.tab {
	appearance: none;
	background: transparent;
	border: 0;
	padding: 8px 16px;
	color: var(--text-2);
	font-family: var(--font);
	font-size: var(--fs-sm);
	cursor: pointer;
	transition: color var(--speed);
}

.tab:hover {
	color: var(--text-1);
}

.tab:active {
	color: var(--code-accent);
}

.tab[aria-selected='true'] {
	color: var(--text-1);
	box-shadow: inset 0 -2px 0 var(--code-accent);
}

.code-panel {
	margin-top: 16px;
	background: var(--surface);
	color: var(--text-1);
	border: 1px solid var(--border);
	border-radius: var(--radius-sm);
	padding: 20px 24px;
	overflow-x: auto;
}

.code {
	margin: 0;
}

.code code {
	display: block;
	font-family: var(--font-mono);
	font-size: 14px;
	/* The panel's rhythm is 1.3, set by the user's sample: JSON members sit on
	   consecutive tight lines, 18px at 14px mono — terminal density, no air
	   between rows. */
	line-height: 1.3;
	color: var(--text-1);
	min-width: max-content;
}

/* The rows stay inline: inside a pre the preserved newline already breaks
   the line, so a block row would stack a second break into a blank line
   between every row — the air the user saw. No line-number column: the
   reference platforms print JSON samples unnumbered, and the panel padding
   is uniform now the number gutter is gone. */
.tok-key {
	color: var(--code-accent);
}

.tok-str {
	color: var(--code-string);
}

.tok-hl {
	outline: 1px solid var(--code-accent);
	outline-offset: 3px;
	border-radius: 2px;
}

/* ------------------------------------------------------------------ */
/* The /docs.html redirect stub                                         */
/* ------------------------------------------------------------------ */

.docs-redirect {
	padding: 96px 0;
	color: var(--text-2);
}

.docs-redirect a {
	color: var(--code-accent);
	text-decoration: underline;
	text-underline-offset: 3px;
}

/* ------------------------------------------------------------------ */
/* Below the docs breakpoint the menu folds into an expand-in-flow list */
/* ------------------------------------------------------------------ */

@media (max-width: 960px) {
	.docs-shell {
		grid-template-columns: minmax(0, 1fr);
		column-gap: 0;
		padding-top: 24px;
	}

	.docs-menu-toggle {
		display: block;
		appearance: none;
		background: transparent;
		border: 1px solid var(--border);
		border-radius: var(--radius-sm);
		padding: 8px 16px;
		margin-bottom: 8px;
		color: var(--text-2);
		font-family: var(--font);
		font-size: var(--fs-sm);
		cursor: pointer;
	}

	.docs-menu-toggle:hover,
	.docs-menu-toggle:active {
		color: var(--text-1);
	}

	.docs-menu {
		display: none;
	}

	.docs-menu.is-open {
		position: static;
		display: flex;
		max-height: none;
		margin-bottom: 24px;
	}
}
