Files
shd.build/src/routes/isac/mechanic-reference/+page.svelte
T
jb d09b6220ee
Validate and deploy production / validate (push) Canceled after 0s
Validate and deploy production / deploy (push) Canceled after 0s
Validate and deploy staging / validate (push) Successful in 27s
Validate and deploy staging / deploy (push) Successful in 54s
feat: defer advanced build calculations
2026-08-02 03:07:12 -04:00

1123 lines
33 KiB
Svelte
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script lang="ts">
import PseudoScript from '$lib/components/PseudoScript.svelte';
import { TRIGGER_ACTION_REGISTRY } from '$lib/calculations/conditional';
import {
MECHANIC_COMBAT_REFERENCE_REGISTRY,
MECHANIC_EVENT_REGISTRY
} from '$lib/calculations/mechanic';
type AttributeVariable = {
id: string;
name: string;
description?: string | null;
unit?: string | null;
type?: string | null;
category?: string | null;
calculation_type?: string | null;
cap_value?: number | null;
gear_min?: number | null;
gear_max?: number | null;
weapon_min?: number | null;
weapon_max?: number | null;
skill_chip_min?: number | null;
skill_chip_max?: number | null;
};
let { data } = $props();
let variableSearch = $state('');
const normalizedVariableSearch = $derived(variableSearch.trim().toLocaleLowerCase());
const matchingAttributes = $derived((data.attributes as AttributeVariable[]).filter((attribute) => {
if (!normalizedVariableSearch) return true;
return [
attribute.name,
attribute.description,
attribute.unit,
attribute.type,
attribute.category,
attribute.calculation_type
].some((value) => String(value ?? '').toLocaleLowerCase().includes(normalizedVariableSearch));
}));
const sections = [
{ id: 'reading-scripts', label: 'READING SCRIPTS' },
{ id: 'events', label: 'EVENTS' },
{ id: 'action-families', label: 'ACTION FAMILIES' },
{ id: 'values', label: 'VALUES + CONDITIONS' },
{ id: 'attribute-variables', label: 'ATTRIBUTE VARIABLES' },
{ id: 'reducers', label: 'REDUCERS' },
{ id: 'state', label: 'STATE' },
{ id: 'outcomes', label: 'OUTCOMES' },
{ id: 'scenarios', label: 'SCENARIOS' },
{ id: 'examples', label: 'WORKED EXAMPLES' }
];
const statements = [
{ token: 'MECHANIC', meaning: 'Names one complete mechanic program.' },
{ token: 'STATE', meaning: 'Declares an Agent- or target-scoped value that branches can share.' },
{ token: 'WHEN', meaning: 'Selects the normalized combat event that starts a branch.' },
{ token: 'IF', meaning: 'Tests event, Agent, target, team, encounter, or state values.' },
{ token: 'COUNT / EVERY / AFTER / DERIVE', meaning: 'Reduces matching events or scenario data into an activation value.' },
{ token: 'COOLDOWN', meaning: 'Blocks that branch from activating again for the configured duration.' },
{ token: 'WEIGHT', meaning: 'Applies a scenario-dependent contribution to a branch.' },
{ token: 'ADD / SET / CONSUME / CLEAR / TRANSFER', meaning: 'Changes a named state pool.' },
{ token: 'APPLY / RELOAD', meaning: 'Emits an Attribute modifier, damage, restoration, resource cost, weapon action, or marker.' }
];
const valueSources = [
{ syntax: 'EVENT.<path>', use: 'A value carried by the current event, such as target distance or critical state.' },
{ syntax: 'SCENARIO.<key>', use: 'A builder assumption supplied by Maximum Potential or Custom Scenario mode.' },
{ syntax: 'COMBAT.currentHealth', use: MECHANIC_COMBAT_REFERENCE_REGISTRY.currentHealth.description },
{ syntax: 'COMBAT.currentHealthPercent', use: `${MECHANIC_COMBAT_REFERENCE_REGISTRY.currentHealthPercent.description} “Below” conditions use a strict < comparison.` },
{ syntax: 'PRE-EVENT COMBAT.<path>', use: 'Combat state captured before the current branch changes it.' },
{ syntax: 'ATTRIBUTE[<id>]', use: 'The authoritative loadout total for a stable Attribute ID. Percentage Attributes use their displayed percentage value.' },
{ syntax: 'EQUIPMENT.<path>', use: 'A value from the equipped item, including OS Protocol talent upgrades.' },
{ syntax: 'REDUCER VALUE', use: 'The number produced by the branch reducer.' },
{ syntax: '<pool> FOR AGENT / EVENT TARGET', use: 'The current value in an Agent- or target-scoped state pool.' }
];
const predicateOperators = [
{ syntax: '== / !=', use: 'Equality and inequality.' },
{ syntax: '> / >= / < / <=', use: 'Numeric threshold comparisons.' },
{ syntax: 'AND / OR / NOT', use: 'Combines or negates conditions.' },
{ syntax: 'EXISTS', use: 'Requires an event, scenario, combat, equipment, or state value.' }
];
const reducers = [
{ syntax: 'COUNT n MATCHES', use: 'Activates after a configured number of matching events.' },
{ syntax: 'EVERY n MATCHES', use: 'Activates on every nth match, such as every ten shots.' },
{ syntax: 'COUNT n MATCHES WITHIN xs', use: 'Counts events inside a sliding time window.' },
{ syntax: 'AFTER CONDITION HOLDS FOR xs', use: 'Activates after a condition remains true for a duration.' },
{ syntax: 'EVERY <expression>s WHILE TRUE', use: 'Runs on an explicit periodic cadence while its condition remains true.' },
{ syntax: 'DERIVE <expression>', use: 'Calculates a scalar from current event, scenario, combat, equipment, or state values.' }
];
const mutations = [
{ syntax: 'ADD value TO pool FOR EVENT TARGET', use: 'Increases one enemy’s target-scoped state, respecting the pool maximum.' },
{ syntax: 'SET value AS pool', use: 'Replaces the current pool value.' },
{ syntax: 'CONSUME value FROM pool', use: 'Spends available state without falling below the pool minimum.' },
{ syntax: 'CLEAR pool', use: 'Resets the selected state pool.' },
{ syntax: 'TRANSFER value pool FROM target TO target', use: 'Moves target-scoped state between entities.' }
];
const phases = [
{ syntax: 'ON_EVENT', use: 'Applies against combat state as the event arrives.' },
{ syntax: 'AFTER_EVENT', use: 'Applies after branch mutations and resource costs.' },
{ syntax: 'ON_ENTER', use: 'Applies when tracked state enters an active range.' },
{ syntax: 'ON_EXIT', use: 'Applies when tracked state leaves an active range, using its final pre-exit value for stack thresholds and scaling.' },
{ syntax: 'WHILE_ACTIVE', use: 'Remains active while the referenced state satisfies its stack range.' }
];
const outcomeKinds = [
{ token: 'ATTRIBUTE MODIFIER', detail: 'Adds or multiplies a referenced Attribute.' },
{ token: 'DIRECT DAMAGE', detail: 'Deals damage from a flat value or a configured percentage basis.' },
{ token: 'RESTORATION', detail: 'Restores Health from a flat value or Health basis.' },
{ token: 'RESOURCE COST', detail: 'Consumes Health or another modeled resource in branch order.' },
{ token: 'WEAPON RELOAD', detail: 'Reloads the inactive weapon after the configured delay. A new activation refreshes a pending reload timer.' },
{ token: 'MARKER', detail: 'Emits a typed state marker without changing a numeric Attribute.' }
];
const bases = [
'FLAT',
'MAX HEALTH PERCENT',
'CURRENT HEALTH PERCENT',
'WEAPON BASE PERCENT'
];
const valueRange = (minimum: number | null | undefined, maximum: number | null | undefined) => {
if (minimum === null || minimum === undefined || maximum === null || maximum === undefined) return null;
return `${minimum}–${maximum}`;
};
const sourceRanges = (attribute: AttributeVariable) => [
{ label: 'GEAR', value: valueRange(attribute.gear_min, attribute.gear_max) },
{ label: 'WEAPON', value: valueRange(attribute.weapon_min, attribute.weapon_max) },
{ label: 'SKILL CHIP', value: valueRange(attribute.skill_chip_min, attribute.skill_chip_max) }
].filter((source) => source.value);
const superiorFirepower = [
'MECHANIC SUPERIOR FIREPOWER',
'STATE relentless [AGENT] 0..10; EXPIRES 10s AFTER WRITE',
'',
'WHEN WEAPON HIT // Build Relentless',
'COUNT 9 MATCHES WITHIN 3s PER EVENT.targetId',
'ADD 1 TO relentless FOR AGENT',
'WHILE_ACTIVE: APPLY 3% FLAT weapon_damage PER STACK // Weapon Damage',
'WHILE_ACTIVE: APPLY 1% FLAT critical_damage PER STACK // Critical Damage'
];
const happySurvival = [
'MECHANIC HAPPY SURVIVAL',
'',
'WHEN PROXIMITY SNAPSHOT // Count nearby enemies',
'DERIVE MIN(EVENT.enemiesWithin10m, 5)',
'SET REDUCER VALUE AS nearby_enemies FOR AGENT',
'',
'WHEN SIMULATION TICK // Restore Health on an explicit cadence',
'EVERY SCENARIO.restorationIntervalSeconds WHILE TRUE',
'AFTER_EVENT: APPLY (0.5 * (1 + (EQUIPMENT.protocolTalentUpgrades / 5))) MAX_HEALTH_PERCENT PER STACK // Restore Health',
'',
'WHEN SHOT FIRED // Pay Health, then calculate damage',
'ON_EVENT: APPLY 2 CURRENT_HEALTH_PERCENT // Health cost',
'AFTER_EVENT: APPLY (0.6 * (1 + (EQUIPMENT.protocolTalentUpgrades / 5))) CURRENT_HEALTH_PERCENT USING CURRENT HEALTH // Additional damage'
];
const preciseTrauma = [
'MECHANIC PRECISE TRAUMA',
'STATE trauma [TARGET] 0..10; EXPIRES 1s AFTER WRITE',
'',
'WHEN WEAPON HIT // Body shot',
'IF EVENT.targetId EXISTS AND EVENT.values.headshot == false',
'ADD 1 TO trauma FOR EVENT TARGET',
'',
'WHEN WEAPON HIT // Headshot',
'IF EVENT.targetId EXISTS AND EVENT.values.headshot == true',
'ADD 2 TO trauma FOR EVENT TARGET',
'',
'WHEN SIMULATION TICK // Shared refreshed expiry',
'ON_EXIT: APPLY (1 * ATTRIBUTE[skill-damage-id]) FLAT DIRECT_DAMAGE PER STACK TO EVENT TARGET'
];
</script>
<svelte:head>
<title>Mechanic script reference — SHD.build ISAC</title>
<meta
name="description"
content="Reference for the generated mechanic language used by SHD.build combat calculations."
/>
</svelte:head>
<div class="reference-toolbar">
<div>
<p class="eyebrow">CALCULATION MODEL REFERENCE</p>
<h2>MECHANIC SCRIPT LANGUAGE</h2>
<p>Read the generated scripts used to explain combat mechanics. ISAC stores and evaluates typed data; displayed scripts are read-only.</p>
</div>
<div class="reference-actions">
<a class="secondary" href="/isac/talents">TALENT MECHANICS</a>
<a class="secondary" href="/isac/calculations">COMBAT CALCULATIONS</a>
</div>
</div>
<div class="reference-layout">
<nav class="reference-index" aria-label="Mechanic reference sections">
<strong>REFERENCE INDEX</strong>
{#each sections as section, index}
<a href={`#${section.id}`}><span>{String(index + 1).padStart(2, '0')}</span>{section.label}</a>
{/each}
</nav>
<main class="reference-content">
<section id="reading-scripts" class="reference-section lead-section">
<header>
<div><span>01</span><h3>READING GENERATED SCRIPTS</h3></div>
<b>READ ONLY</b>
</header>
<p>Editors create structured events, conditions, state changes, and outcomes. ISAC transcribes those records into a compact script so you can inspect calculation order without reading JSON or application code.</p>
<div class="reference-matrix statement-matrix">
{#each statements as statement}
<div><code>{statement.token}</code><span>{statement.meaning}</span></div>
{/each}
</div>
</section>
<section id="events" class="reference-section">
<header>
<div><span>02</span><h3>NORMALIZED COMBAT EVENTS</h3></div>
<b>{Object.keys(MECHANIC_EVENT_REGISTRY).length} EVENTS</b>
</header>
<p>Each branch begins with one event. Event values carry details such as target identity, distance, critical state, movement state, and nearby entity counts.</p>
<div class="event-registry">
{#each Object.values(MECHANIC_EVENT_REGISTRY) as event}
<article>
<div><strong>{event.label}</strong><code>{event.key}</code></div>
<p>{event.description}</p>
{#if event.fields?.length}
<ul aria-label={`${event.label} typed fields`}>
{#each event.fields as field}
<li><code>{field.path}</code><span>{field.label} · {field.type.toUpperCase()}</span></li>
{/each}
</ul>
{/if}
</article>
{/each}
</div>
</section>
<section id="action-families" class="reference-section">
<header>
<div><span>03</span><h3>ACTION FAMILY RECIPES</h3></div>
<b>{Object.keys(TRIGGER_ACTION_REGISTRY).length} RECIPES</b>
</header>
<p>Action Families seed common mechanic shapes. They map familiar game language to normalized events and validated parameters, then copy an editable branch into the source item.</p>
<div class="action-registry">
{#each Object.values(TRIGGER_ACTION_REGISTRY) as action}
<div><strong>{action.label}</strong><code>{action.key}</code></div>
{/each}
</div>
</section>
<section id="values" class="reference-section">
<header><div><span>04</span><h3>VALUES, EXPRESSIONS, AND CONDITIONS</h3></div></header>
<p>Expressions combine numbers with references through addition, subtraction, multiplication, division, minimum, maximum, and clamp operations.</p>
<div class="split-reference">
<div>
<h4>VALUE SOURCES</h4>
<div class="reference-matrix">
{#each valueSources as item}<div><code>{item.syntax}</code><span>{item.use}</span></div>{/each}
</div>
</div>
<div>
<h4>CONDITION OPERATORS</h4>
<div class="reference-matrix">
{#each predicateOperators as item}<div><code>{item.syntax}</code><span>{item.use}</span></div>{/each}
</div>
</div>
</div>
</section>
<section id="attribute-variables" class="reference-section attribute-variable-section">
<header>
<div><span>05</span><h3>ISAC ATTRIBUTE VARIABLES</h3></div>
<b>{data.attributeSummary.documented}/{data.attributeSummary.total} DOCUMENTED</b>
</header>
<p>Attribute outcomes reference the current ISAC Attribute registry. Names and descriptions below update with that data, so improving an Attribute description improves this reference.</p>
<div class="variable-controls">
<label>
<span>SEARCH VARIABLES</span>
<input
type="search"
bind:value={variableSearch}
placeholder="Search name, description, type, or category…"
autocomplete="off"
/>
</label>
<strong>{matchingAttributes.length} OF {data.attributeSummary.total} SHOWN</strong>
</div>
<div class="attribute-variable-list" aria-live="polite">
{#each matchingAttributes as attribute (attribute.id)}
<article>
<header>
<div>
<strong>{attribute.name}{attribute.unit ? ` (${attribute.unit})` : ''}</strong>
<code>{attribute.id}</code>
</div>
<div class="variable-classification">
<span>{String(attribute.category ?? 'UNCATEGORIZED').toLocaleUpperCase()}</span>
<span>{String(attribute.type ?? 'UNCLASSIFIED').toLocaleUpperCase()}</span>
<span>{String(attribute.calculation_type ?? 'UNSPECIFIED').toLocaleUpperCase()}</span>
</div>
</header>
<p class:missing-description={!String(attribute.description ?? '').trim()}>
{String(attribute.description ?? '').trim() || 'DESCRIPTION NEEDED · Add calculation guidance in the ISAC Attribute editor.'}
</p>
{#if sourceRanges(attribute).length || attribute.cap_value !== null}
<footer>
{#each sourceRanges(attribute) as source}
<span><b>{source.label}</b>{source.value}{attribute.unit ?? ''}</span>
{/each}
{#if attribute.cap_value !== null}
<span><b>CAP</b>{attribute.cap_value}{attribute.unit ?? ''}</span>
{/if}
</footer>
{/if}
</article>
{:else}
<div class="variable-empty">
<strong>NO ATTRIBUTE VARIABLES MATCH</strong>
<span>Change the search terms to inspect another Attribute.</span>
</div>
{/each}
</div>
</section>
<section id="reducers" class="reference-section">
<header><div><span>06</span><h3>EVENT REDUCERS</h3></div></header>
<p>Reducers turn matching event history or current scenario data into an activation. A periodic reducer must name its interval; ISAC excludes a branch when its cadence is unknown.</p>
<div class="reference-matrix">
{#each reducers as item}<div><code>{item.syntax}</code><span>{item.use}</span></div>{/each}
</div>
</section>
<section id="state" class="reference-section">
<header><div><span>07</span><h3>TRACKED STATE</h3></div></header>
<p>State pools track stacks, counts, scalars, marks, or resources. Agent pools belong to the build; target pools keep separate values for each enemy.</p>
<div class="reference-matrix">
{#each mutations as item}<div><code>{item.syntax}</code><span>{item.use}</span></div>{/each}
</div>
<aside class="contract">
<strong>EXPIRY CONTRACT</strong>
<span>A pool can expire after its last write. Each write refreshes its timer. Target pools maintain independent values and timers for each bound enemy.</span>
</aside>
</section>
<section id="outcomes" class="reference-section">
<header><div><span>08</span><h3>OUTCOMES AND ORDER</h3></div></header>
<p>Outcome phases control calculation order. This distinction matters when one event changes Health before another outcome reads current Health.</p>
<div class="outcome-grid">
<div>
<h4>PHASES</h4>
<div class="reference-matrix">
{#each phases as item}<div><code>{item.syntax}</code><span>{item.use}</span></div>{/each}
</div>
</div>
<div>
<h4>RESULT TYPES</h4>
<div class="result-types">
{#each outcomeKinds as item}<div><strong>{item.token}</strong><span>{item.detail}</span></div>{/each}
</div>
<h4>VALUE BASES</h4>
<div class="basis-list">{#each bases as basis}<code>{basis}</code>{/each}</div>
</div>
</div>
<aside class="contract">
<strong>CONTINUOUS RESTORATION</strong>
<span><code>DELIVER TOTAL CONTINUOUSLY OVER xs</code> distributes one resolved restoration total at a constant rate. Overlapping activations add independently, and excess restoration is lost when it reaches the resource maximum.</span>
</aside>
<aside class="contract">
<strong>LIVE ATTRIBUTE VALUES</strong>
<span><code>ATTRIBUTE[&lt;id&gt;]</code> reads the current loadout value by stable Attribute ID. For a displayed percentage, divide by 100 before applying a flat coefficient: <code>240 * (ATTRIBUTE[&lt;id&gt;] / 100)</code>.</span>
</aside>
</section>
<section id="scenarios" class="reference-section">
<header><div><span>09</span><h3>PLANNED BUILDER SCENARIOS</h3></div></header>
<div class="scenario-grid">
<article>
<strong>MAXIMUM POTENTIAL</strong>
<p>The planned mode uses each mechanic’s configured best-case values to calculate a ceiling. It applies peak stacks and maximum supported target or ally counts.</p>
</article>
<article>
<strong>CUSTOM SCENARIO</strong>
<p>The planned mode uses player-selected toggles, counts, percentages, and cadence inputs to model a specific combat situation.</p>
</article>
</div>
<aside class="contract">
<strong>REQUIRES ASSUMPTIONS</strong>
<span>The runtime withholds a branch when the mechanic needs an undefined scenario value. An author or future scenario control must supply it before the runtime includes that contribution.</span>
</aside>
<aside class="contract protocol-contract">
<strong>OS PROTOCOL TALENT UPGRADES</strong>
<span><code>EQUIPMENT.protocolTalentUpgrades</code> supplies a value from 0 through 5. Each outcome decides whether that value scales its effect. Rank 5 can reach double the base value while costs and other fixed values remain unchanged.</span>
</aside>
</section>
<section id="examples" class="reference-section examples-section">
<header><div><span>10</span><h3>WORKED MECHANICS</h3></div></header>
<div class="example-intro">
<div>
<h4>PRECISE TRAUMA</h4>
<p>Body shots add one target-bound stack and headshots add two. Each hit refreshes that enemy’s shared one-second expiry; the expiry deals one live Skill Damage value per final stack.</p>
</div>
<div>
<h4>SUPERIOR FIREPOWER</h4>
<p>Nine hits on one target add a Relentless stack. Each write refreshes the ten-second pool timer.</p>
</div>
<div>
<h4>HAPPY SURVIVAL</h4>
<p>A periodic branch restores Health from nearby-enemy count. Each shot pays its Health cost before calculating additional damage from current Health.</p>
</div>
</div>
<div class="example-scripts">
<PseudoScript title="PRECISE TRAUMA · GENERATED EXAMPLE" lines={preciseTrauma} readiness="READY" />
<PseudoScript title="SUPERIOR FIREPOWER · GENERATED EXAMPLE" lines={superiorFirepower} readiness="READY" />
<PseudoScript title="HAPPY SURVIVAL · GENERATED EXAMPLE" lines={happySurvival} readiness="REQUIRES ASSUMPTIONS" />
</div>
</section>
</main>
</div>
<style>
.reference-toolbar {
display: flex;
align-items: end;
justify-content: space-between;
gap: var(--shd-gap-lg);
padding-bottom: var(--shd-gap-md);
border-bottom: 1px solid var(--shd-border);
}
.reference-toolbar h2,
.reference-toolbar p {
margin: 0;
}
.reference-toolbar h2 {
margin-top: 2px;
font-size: clamp(1.55rem, 2vw, 2.25rem);
letter-spacing: -0.02em;
}
.reference-toolbar > div:first-child > p:last-child {
max-width: 72ch;
margin-top: 7px;
color: var(--shd-text-muted);
line-height: 1.5;
}
.reference-actions {
display: flex;
gap: var(--shd-gap-sm);
flex: 0 0 auto;
}
.reference-actions a {
display: inline-flex;
align-items: center;
justify-content: center;
min-height: 40px;
padding: 0 13px;
}
.reference-layout {
display: grid;
grid-template-columns: 190px minmax(0, 1fr);
gap: var(--shd-gap-md);
align-items: start;
padding-top: var(--shd-gap-md);
}
.reference-index {
position: sticky;
top: 82px;
display: grid;
border: 1px solid var(--shd-border);
background: var(--shd-surface);
}
.reference-index > strong {
padding: 10px;
border-bottom: 1px solid var(--shd-border);
color: var(--shd-orange);
font-size: var(--shd-type-telemetry);
letter-spacing: 0.08em;
}
.reference-index a {
display: grid;
grid-template-columns: 28px 1fr;
gap: 8px;
align-items: center;
min-height: 39px;
padding: 6px 8px;
border-bottom: 1px solid var(--shd-border-soft);
color: var(--shd-text-muted);
font-size: var(--shd-type-telemetry);
font-weight: 900;
letter-spacing: 0.05em;
}
.reference-index a:last-child {
border-bottom: 0;
}
.reference-index a:hover,
.reference-index a:focus-visible {
background: var(--shd-surface-raised);
color: var(--shd-orange);
}
.reference-index a:focus-visible {
outline: 2px solid var(--shd-focus-ring);
outline-offset: -2px;
}
.reference-index a span {
color: var(--shd-text-dim);
font-variant-numeric: tabular-nums;
}
.reference-content {
display: grid;
gap: var(--shd-gap-md);
min-width: 0;
}
.reference-section {
scroll-margin-top: 90px;
border: 1px solid var(--shd-border);
background: var(--shd-surface);
}
.reference-section > header {
display: flex;
align-items: center;
justify-content: space-between;
gap: var(--shd-gap-md);
min-height: 52px;
padding: 9px 12px;
border-bottom: 1px solid var(--shd-border);
background: var(--shd-surface-raised);
}
.reference-section > header > div {
display: flex;
align-items: baseline;
gap: 10px;
}
.reference-section > header span {
color: var(--shd-text-dim);
font-size: var(--shd-type-telemetry);
font-weight: 900;
}
.reference-section h3,
.reference-section h4,
.reference-section > p,
.scenario-grid p,
.example-intro p {
margin: 0;
}
.reference-section h3 {
font-size: var(--shd-type-title);
letter-spacing: 0.03em;
}
.reference-section h4 {
color: var(--shd-text-muted);
font-size: var(--shd-type-telemetry);
letter-spacing: 0.08em;
}
.reference-section > header > b {
padding: 5px 7px;
border: 1px solid var(--shd-border);
color: var(--shd-info);
font-size: var(--shd-type-telemetry);
letter-spacing: 0.06em;
}
.reference-section > p {
max-width: 76ch;
padding: 12px;
color: var(--shd-text-muted);
line-height: 1.55;
}
.lead-section {
border-top: 2px solid var(--shd-info);
}
.reference-matrix {
display: grid;
margin: 0 12px 12px;
border: 1px solid var(--shd-border-soft);
}
.reference-matrix > div {
display: grid;
grid-template-columns: minmax(185px, 0.62fr) minmax(0, 1.38fr);
gap: 12px;
align-items: start;
padding: 9px;
border-bottom: 1px solid var(--shd-border-soft);
background: var(--shd-bg);
}
.reference-matrix > div:last-child {
border-bottom: 0;
}
code {
color: var(--shd-success);
font-family: var(--shd-font-mono);
font-size: var(--shd-type-supporting);
font-weight: 900;
overflow-wrap: anywhere;
}
.reference-matrix span,
.result-types span {
color: var(--shd-text-muted);
font-size: var(--shd-type-supporting);
line-height: 1.45;
}
.statement-matrix {
grid-template-columns: repeat(3, minmax(0, 1fr));
}
.statement-matrix > div {
grid-template-columns: 1fr;
align-content: start;
}
.event-registry {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
margin: 0 12px 12px;
border: 1px solid var(--shd-border-soft);
}
.event-registry article {
display: grid;
gap: 6px;
padding: 10px;
border-right: 1px solid var(--shd-border-soft);
border-bottom: 1px solid var(--shd-border-soft);
background: var(--shd-bg);
}
.event-registry article:nth-child(2n) {
border-right: 0;
}
.event-registry article:nth-last-child(-n + 2) {
border-bottom: 0;
}
.event-registry article > div {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
gap: 7px;
}
.event-registry strong {
font-size: var(--shd-type-supporting);
}
.event-registry p {
margin: 0;
color: var(--shd-text-muted);
font-size: var(--shd-type-supporting);
line-height: 1.45;
}
.event-registry ul {
display: grid;
gap: 4px;
margin: 2px 0 0;
padding: 0;
list-style: none;
}
.event-registry li {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
gap: 6px;
padding-top: 5px;
border-top: 1px solid var(--shd-border-soft);
color: var(--shd-text-muted);
font-size: var(--shd-type-telemetry);
}
.action-registry {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
margin: 0 12px 12px;
border: 1px solid var(--shd-border-soft);
}
.action-registry > div {
display: grid;
gap: 4px;
min-width: 0;
padding: 9px;
border-right: 1px solid var(--shd-border-soft);
border-bottom: 1px solid var(--shd-border-soft);
background: var(--shd-bg);
}
.action-registry > div:nth-child(3n) {
border-right: 0;
}
.action-registry strong {
font-size: var(--shd-type-supporting);
}
.split-reference,
.outcome-grid {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 1px;
margin: 0 12px 12px;
background: var(--shd-border);
}
.split-reference > div,
.outcome-grid > div {
min-width: 0;
padding-top: 10px;
background: var(--shd-surface-raised);
}
.split-reference h4,
.outcome-grid h4 {
padding: 0 12px 8px;
}
.contract {
display: grid;
grid-template-columns: 190px minmax(0, 1fr);
gap: 12px;
margin: 0 12px 12px;
padding: 10px;
border: 1px solid var(--shd-model-border);
background: var(--shd-model-surface);
}
.contract strong {
color: var(--shd-info);
font-size: var(--shd-type-telemetry);
letter-spacing: 0.07em;
}
.contract span {
color: var(--shd-text-muted);
font-size: var(--shd-type-supporting);
line-height: 1.45;
}
.result-types {
display: grid;
margin: 0 12px 14px;
border: 1px solid var(--shd-border-soft);
}
.result-types > div {
display: grid;
grid-template-columns: 145px 1fr;
gap: 10px;
padding: 9px;
border-bottom: 1px solid var(--shd-border-soft);
background: var(--shd-bg);
}
.result-types > div:last-child {
border-bottom: 0;
}
.result-types strong {
color: var(--shd-text);
font-size: var(--shd-type-telemetry);
}
.basis-list {
display: flex;
flex-wrap: wrap;
gap: 5px;
padding: 0 12px 12px;
}
.basis-list code {
padding: 5px 7px;
border: 1px solid var(--shd-border);
background: var(--shd-bg);
}
.scenario-grid,
.example-intro {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 1px;
margin: 12px;
background: var(--shd-border);
}
.scenario-grid article,
.example-intro > div {
display: grid;
align-content: start;
gap: 6px;
padding: 12px;
background: var(--shd-bg);
}
.scenario-grid strong {
color: var(--shd-orange);
font-size: var(--shd-type-supporting);
}
.scenario-grid p,
.example-intro p {
color: var(--shd-text-muted);
line-height: 1.5;
}
.protocol-contract code {
font-size: inherit;
}
.variable-controls {
display: flex;
align-items: end;
justify-content: space-between;
gap: var(--shd-gap-md);
margin: 0 12px 8px;
}
.variable-controls label {
display: grid;
gap: 5px;
width: min(620px, 100%);
color: var(--shd-text-muted);
font-size: var(--shd-type-telemetry);
font-weight: 900;
letter-spacing: 0.07em;
}
.variable-controls input {
width: 100%;
min-height: 42px;
}
.variable-controls > strong {
padding-bottom: 11px;
color: var(--shd-info);
font-size: var(--shd-type-telemetry);
letter-spacing: 0.06em;
white-space: nowrap;
}
.attribute-variable-list {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 1px;
margin: 0 12px 12px;
border: 1px solid var(--shd-border-soft);
background: var(--shd-border-soft);
}
.attribute-variable-list article {
display: grid;
grid-template-rows: auto 1fr auto;
min-width: 0;
background: var(--shd-bg);
}
.attribute-variable-list article > header {
display: grid;
gap: 7px;
padding: 10px;
border-bottom: 1px solid var(--shd-border-soft);
}
.attribute-variable-list article > header > div:first-child {
display: flex;
align-items: baseline;
justify-content: space-between;
gap: 9px;
min-width: 0;
}
.attribute-variable-list article > header strong {
font-size: var(--shd-type-body);
}
.attribute-variable-list article > header code {
max-width: 45%;
overflow: hidden;
color: var(--shd-text-dim);
font-size: var(--shd-type-telemetry);
text-overflow: ellipsis;
white-space: nowrap;
}
.variable-classification {
display: flex;
flex-wrap: wrap;
gap: 4px;
}
.variable-classification span {
padding: 3px 5px;
border: 1px solid var(--shd-border);
color: var(--shd-text-muted);
font-size: var(--shd-type-telemetry);
font-weight: 900;
letter-spacing: 0.04em;
}
.attribute-variable-list article > p {
margin: 0;
padding: 10px;
color: var(--shd-text-muted);
line-height: 1.5;
}
.attribute-variable-list article > p.missing-description {
color: var(--shd-danger);
font-size: var(--shd-type-supporting);
font-weight: 700;
}
.attribute-variable-list article > footer {
display: flex;
flex-wrap: wrap;
gap: 5px;
padding: 8px 10px;
border-top: 1px solid var(--shd-border-soft);
}
.attribute-variable-list article > footer span {
display: inline-flex;
gap: 5px;
padding: 3px 5px;
border: 1px solid var(--shd-border);
color: var(--shd-text-muted);
font-size: var(--shd-type-telemetry);
font-variant-numeric: tabular-nums;
}
.attribute-variable-list article > footer b {
color: var(--shd-text);
}
.variable-empty {
display: grid;
grid-column: 1 / -1;
gap: 5px;
place-items: center;
min-height: 150px;
padding: 24px;
background: var(--shd-bg);
text-align: center;
}
.variable-empty strong {
color: var(--shd-text);
font-size: var(--shd-type-supporting);
}
.variable-empty span {
color: var(--shd-text-muted);
}
.example-scripts {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 8px;
padding: 0 12px 12px;
}
.example-scripts > :global(*) {
min-width: 0;
}
@media (max-width: 1000px) {
.reference-layout {
grid-template-columns: 1fr;
}
.reference-index {
position: static;
grid-template-columns: repeat(3, minmax(0, 1fr));
}
.reference-index > strong {
grid-column: 1 / -1;
}
.reference-index a {
border-right: 1px solid var(--shd-border-soft);
}
.statement-matrix,
.action-registry {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
.action-registry > div:nth-child(3n) {
border-right: 1px solid var(--shd-border-soft);
}
.action-registry > div:nth-child(2n) {
border-right: 0;
}
.example-scripts {
grid-template-columns: 1fr;
}
.attribute-variable-list {
grid-template-columns: 1fr;
}
}
@media (max-width: 680px) {
.reference-toolbar,
.reference-actions {
display: grid;
align-items: stretch;
}
.reference-actions a {
min-height: 44px;
}
.reference-index {
grid-template-columns: 1fr;
}
.reference-index > strong {
grid-column: 1;
}
.reference-index a {
min-height: 44px;
border-right: 0;
}
.statement-matrix,
.event-registry,
.action-registry,
.split-reference,
.outcome-grid,
.scenario-grid,
.example-intro {
grid-template-columns: 1fr;
}
.event-registry article,
.event-registry article:nth-child(2n),
.event-registry article:nth-last-child(-n + 2),
.action-registry > div,
.action-registry > div:nth-child(2n),
.action-registry > div:nth-child(3n) {
border-right: 0;
border-bottom: 1px solid var(--shd-border-soft);
}
.event-registry article:last-child,
.action-registry > div:last-child {
border-bottom: 0;
}
.reference-matrix > div,
.result-types > div,
.contract {
grid-template-columns: 1fr;
gap: 5px;
}
.reference-section > header {
align-items: start;
}
.reference-section > header > div {
align-items: start;
}
.variable-controls {
display: grid;
align-items: stretch;
}
.variable-controls > strong {
padding-bottom: 0;
}
.attribute-variable-list article > header > div:first-child {
display: grid;
}
.attribute-variable-list article > header code {
max-width: 100%;
}
}
</style>