@suveren/gateway 0.6.2 → 0.6.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/content/integrations/calendar.json +6 -3
- package/content/integrations/crm.json +6 -3
- package/content/integrations/deploy-github.json +5 -1
- package/content/integrations/gmail.json +16 -6
- package/content/integrations/linkedin.json +75 -16
- package/content/integrations/records.json +76 -14
- package/dist/mcp-server/http.mjs +215 -28
- package/dist/ui/assets/index-DIcuh0I4.css +1 -0
- package/dist/ui/assets/index-Dl5isaOV.js +105 -0
- package/dist/ui/index.html +2 -2
- package/dist/ui/mockups/audit-and-header.html +192 -0
- package/node_modules/@hap/core/dist/index.d.mts +139 -6
- package/node_modules/@hap/core/dist/index.d.ts +139 -6
- package/node_modules/@hap/core/dist/index.js +93 -0
- package/node_modules/@hap/core/dist/index.mjs +88 -0
- package/node_modules/@hap/core/package.json +1 -1
- package/node_modules/@hap/core/src/content-binding.ts +168 -0
- package/node_modules/@hap/core/src/types.ts +85 -5
- package/node_modules/jose/dist/webapi/jwe/general/decrypt.js +8 -0
- package/node_modules/jose/dist/webapi/jwe/general/encrypt.js +1 -1
- package/node_modules/jose/dist/webapi/jwks/local.js +3 -3
- package/node_modules/jose/dist/webapi/jwks/remote.js +1 -1
- package/node_modules/jose/dist/webapi/key/generate_key_pair.js +3 -3
- package/node_modules/jose/dist/webapi/key/generate_secret.js +2 -2
- package/node_modules/jose/dist/webapi/lib/asn1.js +3 -3
- package/node_modules/jose/dist/webapi/lib/jwe_algorithms.js +6 -15
- package/node_modules/jose/dist/webapi/lib/jws_algorithms.js +2 -5
- package/node_modules/jose/dist/webapi/lib/key.js +1 -1
- package/node_modules/jose/dist/webapi/lib/key_algorithm.js +8 -8
- package/node_modules/jose/package.json +1 -1
- package/package.json +2 -2
- package/profiles/deploy/0.7.profile.json +2 -1
- package/profiles/email/0.5.profile.json +200 -0
- package/profiles/index.json +1 -0
- package/dist/ui/assets/index-DoZvxHLN.js +0 -105
- package/dist/ui/assets/index-JHaCddDE.css +0 -1
package/dist/mcp-server/http.mjs
CHANGED
|
@@ -188,6 +188,22 @@ var SPClient = class {
|
|
|
188
188
|
const data = await res.json();
|
|
189
189
|
return data.proposals;
|
|
190
190
|
}
|
|
191
|
+
/**
|
|
192
|
+
* Look up ONE proposal by id, whatever its status. `null` when the AS has no
|
|
193
|
+
* such proposal (or the caller may not see it).
|
|
194
|
+
*
|
|
195
|
+
* Distinct from {@link getCommittedProposals}, which answers only "is this
|
|
196
|
+
* ready to execute?". Asking "what happened to this proposal?" through that
|
|
197
|
+
* list makes pending, executed, rejected and a wrong id look identical —
|
|
198
|
+
* which is how a caller ends up retrying work that already ran.
|
|
199
|
+
*/
|
|
200
|
+
async getProposalById(id) {
|
|
201
|
+
const res = await this.fetch(`/api/proposals/${encodeURIComponent(id)}`);
|
|
202
|
+
if (res.status === 404 || res.status === 403) return null;
|
|
203
|
+
if (!res.ok) throw new Error(`SP proposal request failed: ${res.status}`);
|
|
204
|
+
const data = await res.json();
|
|
205
|
+
return data.proposal ?? null;
|
|
206
|
+
}
|
|
191
207
|
// NOTE: v0.3 used POST /api/proposals/{id}/resolve with action: 'executed'
|
|
192
208
|
// to mark a proposal as executed after the gateway ran the tool. In v0.4
|
|
193
209
|
// the committed→executed transition is atomic with receipt issuance, so
|
|
@@ -1146,13 +1162,33 @@ function appendVerificationFooter(tool, args, receiptId, subject) {
|
|
|
1146
1162
|
}
|
|
1147
1163
|
|
|
1148
1164
|
// src/lib/content-binding.ts
|
|
1149
|
-
import {
|
|
1165
|
+
import {
|
|
1166
|
+
computeContentHash,
|
|
1167
|
+
computeFieldsContentHash,
|
|
1168
|
+
isFieldBinding,
|
|
1169
|
+
bindingAppliesTo,
|
|
1170
|
+
getProfile as getProfile2
|
|
1171
|
+
} from "@hap/core";
|
|
1150
1172
|
function getContentBinding(profileId) {
|
|
1151
1173
|
return getProfile2(profileId)?.content_binding;
|
|
1152
1174
|
}
|
|
1153
|
-
function computeContentBinding(profileId, tool, toolArgs) {
|
|
1175
|
+
function computeContentBinding(profileId, tool, toolArgs, actionType) {
|
|
1154
1176
|
const binding = getContentBinding(profileId);
|
|
1155
1177
|
if (!binding) return void 0;
|
|
1178
|
+
if (isFieldBinding(binding)) {
|
|
1179
|
+
if (!bindingAppliesTo(binding, actionType)) {
|
|
1180
|
+
if (!actionType && binding.appliesTo) {
|
|
1181
|
+
console.error(
|
|
1182
|
+
`[Suveren MCP] Warning: ${tool?.namespacedName ?? profileId} has no action_type in staticExecution, so the ${profileId} content binding (${binding.appliesTo.join(", ")}) does not apply and the receipt will bind no content. Fix the integration manifest.`
|
|
1183
|
+
);
|
|
1184
|
+
}
|
|
1185
|
+
return void 0;
|
|
1186
|
+
}
|
|
1187
|
+
return {
|
|
1188
|
+
contentHash: computeFieldsContentHash(binding, toolArgs),
|
|
1189
|
+
contentBinding: { version: binding.version, kind: binding.kind, fields: binding.fields }
|
|
1190
|
+
};
|
|
1191
|
+
}
|
|
1156
1192
|
let contentHash;
|
|
1157
1193
|
if (binding.kind === "jcs") {
|
|
1158
1194
|
contentHash = computeContentHash(binding, toolArgs);
|
|
@@ -1175,6 +1211,108 @@ function attachReceiptId(tool, args, receiptId) {
|
|
|
1175
1211
|
return { ...args, receipt_id: receiptId };
|
|
1176
1212
|
}
|
|
1177
1213
|
|
|
1214
|
+
// src/lib/arg-encoding.ts
|
|
1215
|
+
function rfc2047Encode(value) {
|
|
1216
|
+
if (!/[^\x00-\x7F]/.test(value)) return value;
|
|
1217
|
+
const CHARSET = "=?UTF-8?Q?";
|
|
1218
|
+
const SUFFIX = "?=";
|
|
1219
|
+
const MAX_PAYLOAD = 75 - CHARSET.length - SUFFIX.length;
|
|
1220
|
+
const atoms = [];
|
|
1221
|
+
for (const char of value) {
|
|
1222
|
+
if (char === " ") {
|
|
1223
|
+
atoms.push("_");
|
|
1224
|
+
continue;
|
|
1225
|
+
}
|
|
1226
|
+
if (/^[A-Za-z0-9!*+\-/]$/.test(char)) {
|
|
1227
|
+
atoms.push(char);
|
|
1228
|
+
continue;
|
|
1229
|
+
}
|
|
1230
|
+
const bytes = Buffer.from(char, "utf8");
|
|
1231
|
+
let encoded = "";
|
|
1232
|
+
for (const byte of bytes) encoded += "=" + byte.toString(16).toUpperCase().padStart(2, "0");
|
|
1233
|
+
atoms.push(encoded);
|
|
1234
|
+
}
|
|
1235
|
+
const words = [];
|
|
1236
|
+
let current = "";
|
|
1237
|
+
for (const atom of atoms) {
|
|
1238
|
+
if (current.length + atom.length > MAX_PAYLOAD) {
|
|
1239
|
+
if (current) words.push(CHARSET + current + SUFFIX);
|
|
1240
|
+
current = atom;
|
|
1241
|
+
} else {
|
|
1242
|
+
current += atom;
|
|
1243
|
+
}
|
|
1244
|
+
}
|
|
1245
|
+
if (current) words.push(CHARSET + current + SUFFIX);
|
|
1246
|
+
return words.join(" ");
|
|
1247
|
+
}
|
|
1248
|
+
var ENCODERS = {
|
|
1249
|
+
rfc2047: rfc2047Encode
|
|
1250
|
+
};
|
|
1251
|
+
function encodeOutgoingArgs(tool, args) {
|
|
1252
|
+
const declared = tool?.gating?.argEncoding;
|
|
1253
|
+
if (!declared) return args;
|
|
1254
|
+
let out = null;
|
|
1255
|
+
for (const [field, encoding] of Object.entries(declared)) {
|
|
1256
|
+
const encoder = ENCODERS[encoding];
|
|
1257
|
+
if (!encoder) {
|
|
1258
|
+
console.error(
|
|
1259
|
+
`[Suveren MCP] Warning: ${tool?.namespacedName} declares argEncoding "${encoding}" for "${field}", which this gateway does not implement. Sending the value unencoded.`
|
|
1260
|
+
);
|
|
1261
|
+
continue;
|
|
1262
|
+
}
|
|
1263
|
+
const value = args[field];
|
|
1264
|
+
if (typeof value !== "string") continue;
|
|
1265
|
+
const encoded = encoder(value);
|
|
1266
|
+
if (encoded === value) continue;
|
|
1267
|
+
out ??= { ...args };
|
|
1268
|
+
out[field] = encoded;
|
|
1269
|
+
}
|
|
1270
|
+
return out ?? args;
|
|
1271
|
+
}
|
|
1272
|
+
|
|
1273
|
+
// src/lib/arg-normalization.ts
|
|
1274
|
+
function normalizeUrl(value) {
|
|
1275
|
+
const trimmed = value.trim();
|
|
1276
|
+
if (!trimmed) return value;
|
|
1277
|
+
const withScheme = /^[a-zA-Z][a-zA-Z0-9+.-]*:\/\//.test(trimmed) ? trimmed : `https://${trimmed}`;
|
|
1278
|
+
let url;
|
|
1279
|
+
try {
|
|
1280
|
+
url = new URL(withScheme);
|
|
1281
|
+
} catch {
|
|
1282
|
+
return value;
|
|
1283
|
+
}
|
|
1284
|
+
if (!url.hostname) return value;
|
|
1285
|
+
const scheme = url.protocol.replace(/:$/, "").toLowerCase();
|
|
1286
|
+
const host = url.hostname.toLowerCase();
|
|
1287
|
+
const defaultPort = scheme === "https" && url.port === "443" || scheme === "http" && url.port === "80";
|
|
1288
|
+
const port2 = url.port && !defaultPort ? `:${url.port}` : "";
|
|
1289
|
+
return `${scheme}://${host}${port2}`;
|
|
1290
|
+
}
|
|
1291
|
+
var NORMALIZERS = {
|
|
1292
|
+
url: normalizeUrl
|
|
1293
|
+
};
|
|
1294
|
+
function normalizeIncomingArgs(tool, args) {
|
|
1295
|
+
const declared = tool?.gating?.argNormalization;
|
|
1296
|
+
if (!declared || !args) return args;
|
|
1297
|
+
let out = null;
|
|
1298
|
+
for (const [field, form] of Object.entries(declared)) {
|
|
1299
|
+
const normalize = NORMALIZERS[form];
|
|
1300
|
+
if (!normalize) {
|
|
1301
|
+
console.error(
|
|
1302
|
+
`[Suveren MCP] Warning: ${tool?.namespacedName} declares argNormalization "${form}" for "${field}", which this gateway does not implement. Using the value as supplied.`
|
|
1303
|
+
);
|
|
1304
|
+
continue;
|
|
1305
|
+
}
|
|
1306
|
+
const value = args[field];
|
|
1307
|
+
if (typeof value !== "string") continue;
|
|
1308
|
+
const normalized = normalize(value);
|
|
1309
|
+
if (normalized === value) continue;
|
|
1310
|
+
out ??= { ...args };
|
|
1311
|
+
out[field] = normalized;
|
|
1312
|
+
}
|
|
1313
|
+
return out ?? args;
|
|
1314
|
+
}
|
|
1315
|
+
|
|
1178
1316
|
// src/lib/scope-specificity.ts
|
|
1179
1317
|
function tokenSet(value) {
|
|
1180
1318
|
if (value === void 0 || value === null) return /* @__PURE__ */ new Set();
|
|
@@ -1359,7 +1497,7 @@ function clampAgeFloor(requested, maxAgeDays, nowMs, format = "iso") {
|
|
|
1359
1497
|
}
|
|
1360
1498
|
|
|
1361
1499
|
// src/lib/tool-proxy.ts
|
|
1362
|
-
import { getProfile as getProfile3 } from "@hap/core";
|
|
1500
|
+
import { getProfile as getProfile3, ContentBindingError } from "@hap/core";
|
|
1363
1501
|
import { readFile } from "fs/promises";
|
|
1364
1502
|
import { extname } from "path";
|
|
1365
1503
|
import { randomUUID } from "crypto";
|
|
@@ -1447,7 +1585,8 @@ function denyRead(state2, tool, reason, detail, target) {
|
|
|
1447
1585
|
return { content: [{ type: "text", text: `Read blocked by Gatekeeper: ${detail}` }], isError: true };
|
|
1448
1586
|
}
|
|
1449
1587
|
function createGatedToolHandler(tool, integrationManager2, state2) {
|
|
1450
|
-
const
|
|
1588
|
+
const gated = createGatedToolHandlerInner(tool, integrationManager2, state2);
|
|
1589
|
+
const inner = async (args) => gated(normalizeIncomingArgs(tool, args));
|
|
1451
1590
|
const blocked = tool.gating?.blockedArgs ?? [];
|
|
1452
1591
|
if (blocked.length === 0) return inner;
|
|
1453
1592
|
return async (args) => {
|
|
@@ -1780,7 +1919,7 @@ Proposal ID: ${proposal.id}. Check status with check-pending-commitments(proposa
|
|
|
1780
1919
|
`[Suveren MCP] Warning: tool ${tool.namespacedName} has no action_type in staticExecution. Bounds check may be skipped. Fix the integration manifest.`
|
|
1781
1920
|
);
|
|
1782
1921
|
}
|
|
1783
|
-
const binding = computeContentBinding(auth.profileId, tool, args);
|
|
1922
|
+
const binding = computeContentBinding(auth.profileId, tool, args, actionType);
|
|
1784
1923
|
const { receipt } = await state2.spClient.postReceipt({
|
|
1785
1924
|
authorizationId: authzId,
|
|
1786
1925
|
// Optional cross-check — the AS fails closed on a mismatch.
|
|
@@ -1795,6 +1934,15 @@ Proposal ID: ${proposal.id}. Check status with check-pending-commitments(proposa
|
|
|
1795
1934
|
});
|
|
1796
1935
|
receiptId = typeof receipt?.id === "string" ? receipt.id : void 0;
|
|
1797
1936
|
} catch (err) {
|
|
1937
|
+
if (err instanceof ContentBindingError) {
|
|
1938
|
+
return {
|
|
1939
|
+
content: [{
|
|
1940
|
+
type: "text",
|
|
1941
|
+
text: `Blocked: this action's content cannot be bound to the receipt \u2014 ${err.message}`
|
|
1942
|
+
}],
|
|
1943
|
+
isError: true
|
|
1944
|
+
};
|
|
1945
|
+
}
|
|
1798
1946
|
if (err instanceof SPReceiptError && err.statusCode === 409) {
|
|
1799
1947
|
const spBody = err.body;
|
|
1800
1948
|
let pendingApprovers = spBody.approvers ?? [];
|
|
@@ -1873,6 +2021,7 @@ Proposal ID: ${proposal.id}. Use check-pending-commitments to track status.`
|
|
|
1873
2021
|
});
|
|
1874
2022
|
let outgoingArgs = shouldAttachFooter() && receiptId ? appendVerificationFooter(tool, args, receiptId, auth.subjects?.[0]) : args;
|
|
1875
2023
|
if (receiptId) outgoingArgs = attachReceiptId(tool, outgoingArgs, receiptId);
|
|
2024
|
+
outgoingArgs = encodeOutgoingArgs(tool, outgoingArgs);
|
|
1876
2025
|
return integrationManager2.callTool(tool.integrationId, tool.originalName, outgoingArgs);
|
|
1877
2026
|
}
|
|
1878
2027
|
});
|
|
@@ -2203,6 +2352,7 @@ function listIntegrationsHandler(state2, integrationManager2) {
|
|
|
2203
2352
|
}
|
|
2204
2353
|
|
|
2205
2354
|
// src/tools/commitments.ts
|
|
2355
|
+
import { ContentBindingError as ContentBindingError2 } from "@hap/core";
|
|
2206
2356
|
async function executeCommitted(proposal, state2, integrationManager2) {
|
|
2207
2357
|
if (!integrationManager2) {
|
|
2208
2358
|
return { text: `Proposal ${proposal.id} committed but integration manager unavailable for execution.`, isError: true };
|
|
@@ -2222,7 +2372,12 @@ async function executeCommitted(proposal, state2, integrationManager2) {
|
|
|
2222
2372
|
}
|
|
2223
2373
|
let receiptId;
|
|
2224
2374
|
try {
|
|
2225
|
-
const binding = computeContentBinding(
|
|
2375
|
+
const binding = computeContentBinding(
|
|
2376
|
+
proposal.profileId,
|
|
2377
|
+
discovered,
|
|
2378
|
+
proposal.toolArgs,
|
|
2379
|
+
proposalActionType
|
|
2380
|
+
);
|
|
2226
2381
|
const { receipt } = await state2.spClient.postReceipt({
|
|
2227
2382
|
authorizationId: proposal.authorizationId,
|
|
2228
2383
|
profileId: proposal.profileId,
|
|
@@ -2236,6 +2391,12 @@ async function executeCommitted(proposal, state2, integrationManager2) {
|
|
|
2236
2391
|
});
|
|
2237
2392
|
receiptId = typeof receipt?.id === "string" ? receipt.id : void 0;
|
|
2238
2393
|
} catch (err) {
|
|
2394
|
+
if (err instanceof ContentBindingError2) {
|
|
2395
|
+
return {
|
|
2396
|
+
text: `Proposal ${proposal.id}: blocked \u2014 the approved content cannot be bound to the receipt. ${err.message}`,
|
|
2397
|
+
isError: true
|
|
2398
|
+
};
|
|
2399
|
+
}
|
|
2239
2400
|
if (err instanceof SPReceiptError) {
|
|
2240
2401
|
const code = err.body.errors?.[0]?.code;
|
|
2241
2402
|
if (code === "PROPOSAL_ALREADY_EXECUTED") {
|
|
@@ -2260,6 +2421,7 @@ async function executeCommitted(proposal, state2, integrationManager2) {
|
|
|
2260
2421
|
outgoingArgs = appendVerificationFooter(discovered, outgoingArgs, receiptId);
|
|
2261
2422
|
}
|
|
2262
2423
|
outgoingArgs = attachReceiptId(discovered, outgoingArgs, receiptId);
|
|
2424
|
+
outgoingArgs = encodeOutgoingArgs(discovered, outgoingArgs);
|
|
2263
2425
|
}
|
|
2264
2426
|
const result = await integrationManager2.callTool(integrationId, toolName, outgoingArgs);
|
|
2265
2427
|
state2.executionLog.record({
|
|
@@ -2286,36 +2448,59 @@ function checkPendingCommitmentsHandler(state2, integrationManager2) {
|
|
|
2286
2448
|
}
|
|
2287
2449
|
try {
|
|
2288
2450
|
if (args.proposal_id) {
|
|
2289
|
-
const
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2451
|
+
const match = await state2.spClient.getProposalById(args.proposal_id);
|
|
2452
|
+
if (!match) {
|
|
2453
|
+
return {
|
|
2454
|
+
content: [{
|
|
2455
|
+
type: "text",
|
|
2456
|
+
text: `No proposal with id ${args.proposal_id} \u2014 check the id. Do NOT retry the original tool call: if a proposal was created, it still exists under its own id, and calling the tool again would create a second one.`
|
|
2457
|
+
}]
|
|
2458
|
+
};
|
|
2459
|
+
}
|
|
2460
|
+
if (match.status === "committed") {
|
|
2461
|
+
const { text, isError } = await executeCommitted(match, state2, integrationManager2);
|
|
2462
|
+
return {
|
|
2463
|
+
content: [{ type: "text", text }],
|
|
2464
|
+
...isError ? { isError: true } : {}
|
|
2465
|
+
};
|
|
2466
|
+
}
|
|
2467
|
+
if (match.status === "executed") {
|
|
2468
|
+
const result = match.executionResult ? `
|
|
2469
|
+
Result: ${JSON.stringify(match.executionResult, null, 2)}` : " The action ran; the gateway did not retain its output.";
|
|
2470
|
+
return {
|
|
2471
|
+
content: [{
|
|
2472
|
+
type: "text",
|
|
2473
|
+
text: `Proposal ${match.id} was approved and has already been EXECUTED \u2014 it is finished, do not call the tool again.${result}`
|
|
2474
|
+
}]
|
|
2475
|
+
};
|
|
2476
|
+
}
|
|
2477
|
+
if (match.status === "rejected") {
|
|
2478
|
+
const by = match.approverRejectedBy ?? match.rejectedBy;
|
|
2479
|
+
const reason = match.approverRejectedBy?.reason;
|
|
2480
|
+
return {
|
|
2481
|
+
content: [{
|
|
2482
|
+
type: "text",
|
|
2483
|
+
text: `Proposal ${match.id} was REJECTED${by ? ` by ${by.userId}` : ""}${reason ? `: ${reason}` : "."} The action did not run and must not be retried \u2014 a decision owner declined it. Ask before proposing anything similar.`
|
|
2484
|
+
}]
|
|
2485
|
+
};
|
|
2486
|
+
}
|
|
2487
|
+
if (match.status === "expired") {
|
|
2308
2488
|
return {
|
|
2309
2489
|
content: [{
|
|
2310
2490
|
type: "text",
|
|
2311
|
-
text: `Proposal ${match.id}
|
|
2491
|
+
text: `Proposal ${match.id} EXPIRED before it was approved, so the action never ran. Re-submit the tool call if it is still wanted.`
|
|
2312
2492
|
}]
|
|
2313
2493
|
};
|
|
2314
2494
|
}
|
|
2495
|
+
const waitingOn = (match.pendingApprovers?.length ?? 0) > 0 ? match.pendingApprovers.filter((u) => !(u in (match.approvedBy ?? {}))) : match.pendingDomains.filter((d) => !(d in match.committedBy));
|
|
2496
|
+
const done = (match.pendingApprovers?.length ?? 0) > 0 ? Object.keys(match.approvedBy ?? {}) : Object.keys(match.committedBy);
|
|
2315
2497
|
return {
|
|
2316
2498
|
content: [{
|
|
2317
2499
|
type: "text",
|
|
2318
|
-
text: `Proposal ${
|
|
2500
|
+
text: `Proposal ${match.id} is PENDING \u2014 awaiting approval, nothing has run.
|
|
2501
|
+
Approved by: [${done.join(", ") || "nobody yet"}]
|
|
2502
|
+
Still waiting on: [${waitingOn.join(", ")}]
|
|
2503
|
+
Wait for the human to approve; do not re-submit the tool call.`
|
|
2319
2504
|
}]
|
|
2320
2505
|
};
|
|
2321
2506
|
}
|
|
@@ -3062,7 +3247,9 @@ var IntegrationManager = class {
|
|
|
3062
3247
|
// copied here is silently dropped — the receipt is still issued and
|
|
3063
3248
|
// simply carries no binding, which only surfaces when a verifier asks.
|
|
3064
3249
|
contentField: ext.contentField,
|
|
3065
|
-
blockedArgs: ext.blockedArgs
|
|
3250
|
+
blockedArgs: ext.blockedArgs,
|
|
3251
|
+
argEncoding: ext.argEncoding,
|
|
3252
|
+
argNormalization: ext.argNormalization
|
|
3066
3253
|
};
|
|
3067
3254
|
}
|
|
3068
3255
|
return {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@font-face{font-family:Inter;font-style:normal;font-weight:400;font-display:swap;src:url(/fonts/Inter-Regular.woff2) format("woff2")}@font-face{font-family:Inter;font-style:normal;font-weight:500;font-display:swap;src:url(/fonts/Inter-Medium.woff2) format("woff2")}@font-face{font-family:Inter;font-style:normal;font-weight:600;font-display:swap;src:url(/fonts/Inter-SemiBold.woff2) format("woff2")}@font-face{font-family:Inter;font-style:normal;font-weight:700;font-display:swap;src:url(/fonts/Inter-Bold.woff2) format("woff2")}*,*:before,*:after{margin:0;padding:0;box-sizing:border-box}:root{--text-primary: #111111;--text-secondary: #111111;--text-tertiary: #111111;--text-muted: #888888;--bg-main: #fafafa;--bg-elevated: #ffffff;--bg-input: #ffffff;--accent: #888888;--accent-subtle: #f0f0f0;--accent-hover: #555555;--border: #e5e5e5;--edit-border: #c7c7c7;--danger: #dc2626;--danger-subtle: #fef2f2;--success: #16a34a;--success-subtle: #f0fdf4;--warning: #d97706;--btn-primary-bg: #111111;--btn-primary-fg: #ffffff;--btn-primary-bg-hover: #000000;--btn-primary-bg-active: #2a2a2a;--icon-filter: brightness(0) invert(1);--primary-glow: rgba(0, 0, 0, .2);--primary-focus-ring: rgba(0, 0, 0, .15);--bg-field: #111111;--text-field: #ffffff;--border-field: #111111;--placeholder-field: rgba(255, 255, 255, .55);--field-focus-ring: rgba(0, 0, 0, .18);--nav-height: 3.5rem;--sidebar-width: 15rem;--content-width: 75rem;--content-padding: 2rem}:root[data-theme=dark]{--text-primary: #ffffff;--text-secondary: #ffffff;--text-tertiary: #ffffff;--text-muted: #888888;--bg-main: #0a0a0a;--bg-elevated: #1a1a1a;--bg-input: #141414;--accent: #888888;--accent-subtle: #1f1f1f;--accent-hover: #bbbbbb;--border: #2a2a2a;--edit-border: #4a4a4a;--danger-subtle: #2a0a0a;--success-subtle: #0a2a0a;--btn-primary-bg: #ffffff;--btn-primary-fg: #000000;--btn-primary-bg-hover: #e5e5e5;--btn-primary-bg-active: #c4c4c4;--icon-filter: brightness(0);--primary-glow: rgba(255, 255, 255, .25);--primary-focus-ring: rgba(255, 255, 255, .2);--bg-field: #ffffff;--text-field: #111111;--border-field: #ffffff;--placeholder-field: rgba(0, 0, 0, .5);--field-focus-ring: rgba(255, 255, 255, .25)}html{scroll-behavior:smooth}body{font-family:Inter,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif;font-feature-settings:"cv11","ss01","ss03";font-size:16px;line-height:1.6;color:var(--text-primary);background:var(--bg-main);-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}@media (min-width: 1900px){body{font-size:17.5px}}@media (min-width: 2800px){body{font-size:19px}}a{color:var(--accent);text-decoration:none}a:hover{text-decoration:underline}h1,h2,h3,h4{font-weight:700;letter-spacing:-.02em;line-height:1.2;color:var(--text-primary)}code{background:var(--bg-elevated);border:1px solid var(--border);padding:.15rem .4rem;border-radius:.25rem;font-size:.875em;font-family:SF Mono,Monaco,Cascadia Code,Courier New,monospace}.top-nav{position:fixed;top:0;width:100%;height:var(--nav-height);background:#fafafaeb;backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);border-bottom:1px solid var(--border);z-index:1000}[data-theme=dark] .top-nav{background:#0a0a0aeb}.top-nav-inner{max-width:100%;margin:0 auto;padding:0 1.5rem;height:100%;display:flex;align-items:center;gap:1rem}.logo-group{display:flex;align-items:center;gap:.5rem;flex-shrink:0}.logo{font-weight:700;font-size:.95rem;color:var(--text-primary);text-decoration:none}.logo:hover{text-decoration:none}.version-badge{font-size:.65rem;font-weight:600;padding:.15rem .4rem;background:var(--btn-primary-bg);color:var(--btn-primary-fg);border-radius:.25rem}.gw-version{font-size:.7rem;padding:.15rem .4rem;border-radius:.25rem;color:var(--text-muted);background:var(--accent-subtle);font-variant-numeric:tabular-nums;white-space:nowrap}.gw-version[data-stale=true]{color:var(--warning);background:transparent;border:1px solid var(--warning)}.nav-spacer{flex:1}.nav-actions{display:flex;align-items:center;gap:.75rem}.user-chip{display:flex;align-items:center;gap:.5rem;font-size:.8rem;color:var(--text-secondary)}.user-chip strong{color:var(--text-primary)}.user-chip .dot{width:3px;height:3px;border-radius:50%;background:var(--text-tertiary)}.theme-toggle{width:2rem;height:2rem;background:none;border:1px solid var(--border);border-radius:.375rem;cursor:pointer;color:var(--text-secondary);font-size:1rem;display:flex;align-items:center;justify-content:center}.theme-toggle:hover{color:var(--accent);border-color:var(--accent)}.nav-logout{font-size:.8rem;color:var(--text-tertiary);cursor:pointer;background:none;border:none;font-family:inherit}.nav-logout:hover{color:var(--text-primary)}.domain-switcher{position:relative}.domain-switcher-btn{background:none;border:none;font-family:inherit;font-size:.8rem;color:var(--text-secondary);cursor:pointer;display:flex;align-items:center;gap:.25rem;padding:.125rem .25rem;border-radius:.25rem}.domain-switcher-btn:hover{color:var(--accent)}.domain-switcher-arrow{font-size:.6rem;color:var(--text-tertiary)}.domain-switcher-menu{position:absolute;top:calc(100% + .375rem);right:0;min-width:10rem;background:var(--bg-elevated);border:1px solid var(--border);border-radius:.5rem;box-shadow:0 4px 12px #0000001a;z-index:200;padding:.25rem}.domain-switcher-item{display:block;width:100%;text-align:left;background:none;border:none;font-family:inherit;font-size:.8rem;color:var(--text-secondary);padding:.5rem .75rem;border-radius:.375rem;cursor:pointer;white-space:nowrap}.domain-switcher-item:hover{background:var(--accent-subtle);color:var(--text-primary)}.domain-switcher-item.active{color:var(--accent);font-weight:600}.sidebar{position:fixed;top:var(--nav-height);left:0;width:var(--sidebar-width);height:calc(100vh - var(--nav-height));background:var(--bg-elevated);border-right:1px solid var(--border);padding:1rem 0;z-index:900;display:flex;flex-direction:column}.sidebar-nav{list-style:none;padding:0 .5rem;flex:1}.sidebar-item{display:flex;align-items:center;gap:.625rem;padding:.5rem .75rem;margin-bottom:.125rem;border-radius:.5rem;font-size:.85rem;font-weight:500;color:var(--text-secondary);cursor:pointer;transition:background .15s,color .15s;text-decoration:none}.sidebar-item:hover{background:var(--accent-subtle);color:var(--text-primary);text-decoration:none}.sidebar-item.active{background:var(--accent-subtle);color:var(--accent);font-weight:600}.sidebar-item .icon{width:1.125rem;text-align:center;font-size:.9rem;flex-shrink:0}.sidebar-section-label{font-size:.65rem;font-weight:600;text-transform:uppercase;letter-spacing:.06em;color:var(--text-tertiary);padding:1rem .75rem .375rem}.sidebar-context{padding:.75rem 1rem;border-top:1px solid var(--border);font-size:.75rem;color:var(--text-tertiary)}.sidebar-context .ctx-label{font-weight:600;color:var(--text-secondary);margin-bottom:.125rem}.sidebar-context .ctx-value{color:var(--text-primary);font-weight:500}.main-content{margin-left:var(--sidebar-width);margin-top:var(--nav-height);padding:2rem;min-height:calc(100vh - var(--nav-height))}.main-content.no-sidebar{margin-left:0}.page-inner{max-width:56rem;margin:0 auto}.page-header{margin-bottom:1.5rem}.page-title{font-size:1.5rem;margin-bottom:.25rem}.page-subtitle{font-size:.9rem;color:var(--text-secondary)}.btn{display:inline-flex;align-items:center;justify-content:center;gap:.5rem;padding:.625rem 1.25rem;font-size:.9rem;font-weight:500;font-family:inherit;border-radius:.5rem;border:none;cursor:pointer;transition:all .2s;text-decoration:none;line-height:1.4}.btn:disabled{opacity:.5;cursor:not-allowed}.btn-primary{background:var(--btn-primary-bg);color:var(--btn-primary-fg);border:2px solid var(--btn-primary-bg)}.btn-primary:hover:not(:disabled){background:var(--btn-primary-bg-hover);border-color:var(--btn-primary-bg-hover);color:var(--btn-primary-fg);transform:translateY(-1px);box-shadow:0 4px 12px var(--primary-glow)}.btn-primary:active:not(:disabled){background:var(--btn-primary-bg-active);border-color:var(--btn-primary-bg-active)}.btn-secondary{background:transparent;color:var(--text-primary);border:1px solid var(--border)}.btn-secondary:hover:not(:disabled){border-color:var(--btn-primary-bg);color:var(--text-primary);background:var(--accent-subtle)}.btn-ghost{background:transparent;color:var(--text-secondary);border:none;padding:.5rem .75rem}.btn-ghost:hover:not(:disabled){color:var(--text-primary);background:var(--accent-subtle)}.btn-full{width:100%}.btn-sm{padding:.375rem .75rem;font-size:.8rem}.btn-lg{padding:.875rem 2rem;font-size:1rem;font-weight:600}.form-group{margin-bottom:1.25rem}.form-label{display:block;font-size:.875rem;font-weight:600;color:var(--text-primary);margin-bottom:.375rem}.form-input,.form-select,.form-textarea{width:100%;padding:.625rem .75rem;font-size:.9rem;font-family:inherit;color:var(--text-field);background:var(--bg-field);border:1px solid var(--border-field);border-radius:.5rem;outline:none;transition:box-shadow .2s,border-color .2s}.form-input::placeholder,.form-textarea::placeholder{color:var(--placeholder-field);opacity:1}.form-input:focus,.form-textarea:focus,.form-select:focus{box-shadow:0 0 0 3px var(--field-focus-ring)}.form-input:disabled,.form-textarea:disabled,.form-select:disabled{opacity:.55;cursor:not-allowed}.form-input-invalid,.form-input-invalid:focus{border-color:var(--danger);box-shadow:0 0 0 3px #dc26262e}.form-textarea{resize:vertical;min-height:120px;line-height:1.5}.form-hint{font-size:.8rem;color:var(--text-tertiary);margin-top:.375rem}.form-select{-webkit-appearance:none;-moz-appearance:none;appearance:none;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%23ffffff' d='M6 8L1 3h10z'/%3E%3C/svg%3E");background-repeat:no-repeat;background-position:right .75rem center;padding-right:2.25rem}[data-theme=dark] .form-select{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%23111111' d='M6 8L1 3h10z'/%3E%3C/svg%3E")}.card{background:var(--bg-elevated);border:1px solid var(--border);border-radius:.75rem;padding:1.5rem}.card+.card{margin-top:1rem}.card-highlight{animation:hap-card-highlight 2.4s ease-out 1}@keyframes hap-card-highlight{0%{box-shadow:0 0 0 2px var(--accent),0 0 24px var(--accent-subtle);border-color:var(--accent)}60%{box-shadow:0 0 0 2px var(--accent),0 0 24px var(--accent-subtle);border-color:var(--accent)}to{box-shadow:0 0 0 0 transparent,0 0 0 transparent;border-color:var(--border)}}@media (prefers-reduced-motion: reduce){.card-highlight{animation:none;border-color:var(--accent)}}.card-header{display:flex;justify-content:space-between;align-items:flex-start;margin-bottom:1rem}.card-title{font-size:1rem;font-weight:600;margin:0}.auth-card{background:var(--bg-elevated);border:1px solid var(--border);border-radius:.75rem;padding:1.25rem;transition:opacity .2s,border-color .2s;cursor:pointer}.auth-card:hover{border-color:var(--accent)}.auth-card+.auth-card{margin-top:.75rem}.auth-card.expired{opacity:.5}.auth-card-header{display:flex;align-items:center;gap:.75rem;margin-bottom:.5rem;flex-wrap:wrap}.auth-card-path{font-weight:600;font-size:.95rem}.auth-card-time{font-size:.8rem;color:var(--text-tertiary);margin-left:auto}.success-card{background:var(--accent-subtle);border:1px solid var(--accent);border-radius:.75rem;padding:1.5rem;text-align:center}.success-card-title{font-size:1.1rem;font-weight:700;color:var(--accent);margin-bottom:.5rem}.success-card-hash{font-family:SF Mono,Monaco,monospace;font-size:.8rem;color:var(--text-secondary);word-break:break-all;margin-bottom:.5rem}.status-badge{display:inline-block;padding:.2rem .6rem;border-radius:9999px;font-size:.7rem;font-weight:600;letter-spacing:.03em;text-transform:uppercase}.status-active{background:var(--accent-subtle);color:var(--accent)}.status-pending{background:var(--danger-subtle);color:var(--danger)}.status-expired{background:var(--bg-elevated);color:var(--text-tertiary)}.status-revoked{background:var(--danger-subtle);color:var(--danger)}.int-chip{display:inline-flex;align-items:center;gap:.4rem;padding:.2rem .6rem;border-radius:9999px;font-size:.7rem;font-weight:600;letter-spacing:.03em;text-transform:uppercase}.int-chip .int-dot{width:6px;height:6px;border-radius:50%;flex:none}.int-chip-ok{background:var(--success-subtle);color:var(--success)}.int-chip-ok .int-dot{background:var(--success)}.int-chip-bad{background:var(--danger-subtle);color:var(--danger)}.int-chip-bad .int-dot{background:var(--danger)}.int-chip-idle{background:var(--accent-subtle);color:var(--accent)}.int-chip-idle .int-dot{background:#bbb}.int-details{border-top:1px solid var(--border);padding-top:.7rem;margin-top:.25rem}.int-details>summary{cursor:pointer;font-size:.78rem;color:var(--text-muted);list-style:none;display:flex;align-items:center;gap:.35rem;-webkit-user-select:none;user-select:none}.int-details>summary::-webkit-details-marker{display:none}.int-details>summary:before{content:"▸";font-size:.7rem;transition:transform .15s}.int-details[open]>summary:before{transform:rotate(90deg)}.int-meta{display:grid;grid-template-columns:auto 1fr;gap:.4rem 1rem;font-size:.8rem;margin-top:.7rem}.int-meta .int-k{color:var(--text-muted)}.int-account{font-size:.85rem;display:flex;align-items:center;gap:.5rem}.int-account .int-none{color:var(--text-muted);font-style:italic}.domain-badge{display:inline-block;padding:.2rem .5rem;font-size:.8rem;font-family:SF Mono,Monaco,monospace;background:var(--bg-main);border:1px solid var(--border);border-radius:.25rem;color:var(--text-secondary)}.domain-attested{color:var(--accent);border-color:var(--accent)}.domain-missing{color:var(--text-tertiary)}.profile-badge{display:inline-block;padding:.15rem .5rem;font-size:.7rem;font-weight:600;text-transform:uppercase;letter-spacing:.03em;background:var(--accent-subtle);color:var(--accent);border-radius:.25rem}.step-indicator{display:flex;align-items:center;justify-content:center;margin-bottom:2rem;gap:0}.step{display:flex;align-items:center;position:relative}.step-circle{width:2rem;height:2rem;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:.75rem;font-weight:600;border:2px solid var(--border);color:var(--text-tertiary);background:var(--bg-main);flex-shrink:0;transition:all .2s}.step-circle.completed{background:var(--accent);border-color:var(--accent);color:#fff;cursor:pointer}.step-circle.current{border-color:var(--accent);color:var(--accent);box-shadow:0 0 0 3px var(--primary-focus-ring)}.step-line{width:2rem;height:2px;background:var(--border);flex-shrink:1;min-width:.5rem}.step-line.completed{background:var(--accent)}.step-label{font-size:.65rem;color:var(--text-tertiary);position:absolute;top:2.25rem;white-space:nowrap;text-align:center}.alert{padding:.75rem 1rem;border-radius:.5rem;font-size:.875rem;margin-bottom:1rem;color:#fff}.alert-error{background:var(--danger)}.alert-info{background:var(--accent)}.alert-success{background:#1a7f37}.nav-tabs{display:flex;gap:0;border-bottom:1px solid var(--border);margin-bottom:1.5rem}.nav-tab{padding:.75rem 1.25rem;font-size:.9rem;font-weight:500;color:var(--text-tertiary);background:none;border:none;border-bottom:2px solid transparent;cursor:pointer;transition:color .2s;margin-bottom:-1px;font-family:inherit}.nav-tab:hover{color:var(--text-primary)}.nav-tab.active{color:var(--accent);border-bottom-color:var(--accent);font-weight:600}.review-grid{display:grid;grid-template-columns:auto 1fr;gap:.5rem 1rem;font-size:.9rem;margin-bottom:1.5rem}.review-grid dt{font-weight:600;color:var(--text-secondary);padding:.25rem 0}.review-grid dd{color:var(--text-primary);padding:.25rem 0}.gate-content-block{background:var(--bg-main);border:1px solid var(--border);border-radius:.5rem;padding:1rem;font-size:.875rem;margin-bottom:1.5rem}.gate-content-item{margin-bottom:.5rem}.gate-content-item:last-child{margin-bottom:0}.gate-content-label{font-weight:600;color:var(--text-secondary);font-size:.75rem;text-transform:uppercase;letter-spacing:.04em;margin-bottom:.125rem}.gate-content-text{color:var(--text-primary);line-height:1.5}.empty-state{text-align:center;padding:3rem 1.5rem;color:var(--text-tertiary)}.empty-state-icon{font-size:2.5rem;margin-bottom:.75rem;opacity:.5}.empty-state-title{font-size:1rem;font-weight:600;color:var(--text-secondary);margin-bottom:.25rem}.empty-state-text{font-size:.875rem;color:var(--text-tertiary);margin-bottom:1rem;max-width:28rem;margin-left:auto;margin-right:auto}.login-split{margin-top:var(--nav-height);display:flex;min-height:calc(100vh - var(--nav-height))}.login-split-left{flex:1;background:var(--bg-main);display:flex;align-items:center;justify-content:center;padding:4rem 3rem}.login-split-right{flex:1;background:var(--bg-elevated);border-left:1px solid var(--border);display:flex;align-items:center;justify-content:center;padding:4rem 3rem}.login-page{display:flex;align-items:center;justify-content:center;min-height:calc(100vh - var(--nav-height));padding:2rem}.login-card{width:100%;max-width:420px}.login-header{text-align:center;margin-bottom:2rem}.login-title{font-size:1.5rem;font-weight:700;margin-bottom:.5rem}.login-subtitle{font-size:.9rem;color:var(--text-secondary);line-height:1.5}.login-divider{display:flex;align-items:center;gap:.75rem;margin:1.5rem 0;font-size:.8rem;color:var(--text-tertiary)}.login-divider:before,.login-divider:after{content:"";flex:1;height:1px;background:var(--border)}.onboarding-card{background:var(--bg-elevated);border:1px solid var(--border);border-radius:.75rem;padding:2rem;max-width:32rem;margin:0 auto}.onboarding-step{display:flex;gap:1rem;margin-bottom:1.25rem}.onboarding-step:last-child{margin-bottom:0}.onboarding-num{width:1.75rem;height:1.75rem;border-radius:50%;background:var(--accent);color:#fff;display:flex;align-items:center;justify-content:center;font-size:.75rem;font-weight:700;flex-shrink:0;margin-top:.1rem}.onboarding-num.done{background:var(--accent)}.onboarding-text h4{font-size:.9rem;margin-bottom:.125rem}.onboarding-text p{font-size:.825rem;color:var(--text-secondary);line-height:1.5}.selection-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(14rem,1fr));gap:.75rem;margin-bottom:1.5rem}.selection-card{background:var(--bg-elevated);border:2px solid var(--border);border-radius:.75rem;padding:1.25rem;cursor:pointer;transition:all .15s}.selection-card:hover{border-color:var(--accent);transform:translateY(-1px);box-shadow:0 4px 12px #0000000f}.selection-card.selected{border-color:var(--accent);background:var(--accent-subtle)}.selection-card-title{font-size:1rem;font-weight:600;margin-bottom:.25rem}.selection-card-subtitle{font-size:.8rem;color:var(--text-secondary);margin-bottom:.5rem}.selection-card-id{font-size:.7rem;color:var(--text-tertiary);margin-bottom:.375rem;word-break:break-all}.selection-card-meta{display:flex;gap:.375rem;flex-wrap:wrap}.dashboard-section{margin-bottom:2rem}.section-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:1rem}.section-title{font-size:1rem;font-weight:600}.section-count{font-size:.8rem;color:var(--text-tertiary)}.ttl-badge{display:inline-flex;align-items:center;gap:.25rem;font-size:.75rem;font-weight:600;padding:.2rem .5rem;border-radius:.25rem;font-family:SF Mono,Monaco,monospace}.ttl-ok{background:var(--accent-subtle);color:var(--accent)}.ttl-warn{background:var(--danger-subtle);color:var(--danger)}.quick-actions{display:grid;grid-template-columns:repeat(auto-fill,minmax(16rem,1fr));gap:.75rem;margin-bottom:2rem}.quick-action-card{background:var(--bg-elevated);border:1px solid var(--border);border-radius:.75rem;padding:1.25rem;cursor:pointer;transition:all .15s;display:flex;align-items:flex-start;gap:.875rem;text-decoration:none;color:inherit}.quick-action-card:hover{border-color:var(--accent);transform:translateY(-1px);box-shadow:0 4px 12px #0000000f;text-decoration:none}.quick-action-icon{width:2.5rem;height:2.5rem;border-radius:.5rem;background:var(--accent-subtle);color:var(--accent);display:flex;align-items:center;justify-content:center;font-size:1.25rem;flex-shrink:0}.quick-action-title{font-size:.9rem;font-weight:600;margin-bottom:.125rem}.quick-action-desc{font-size:.8rem;color:var(--text-secondary)}.pr-card{background:var(--bg-elevated);border:1px solid var(--border);border-radius:.75rem;padding:1.25rem;cursor:pointer;transition:border-color .15s}.pr-card:hover{border-color:var(--accent)}.pr-card+.pr-card{margin-top:.75rem}.pr-card-header{display:flex;align-items:center;gap:.5rem;margin-bottom:.375rem}.pr-card-repo{font-size:.75rem;color:var(--text-tertiary);font-family:SF Mono,Monaco,monospace}.pr-card-title{font-weight:600;font-size:.95rem}.pr-card-footer{display:flex;align-items:center;gap:.75rem;margin-top:.5rem;flex-wrap:wrap}.member-row{display:flex;align-items:center;gap:.75rem;padding:.75rem 0;border-bottom:1px solid var(--border)}.member-row:last-child{border-bottom:none}.member-avatar{width:2rem;height:2rem;border-radius:50%;background:var(--accent-subtle);color:var(--accent);display:flex;align-items:center;justify-content:center;font-size:.75rem;font-weight:700;flex-shrink:0}.member-info{flex:1}.member-name{font-size:.9rem;font-weight:600}.member-email{font-size:.75rem;color:var(--text-tertiary)}.member-domains{display:flex;gap:.25rem;flex-wrap:wrap}.char-counter{text-align:right;font-size:.75rem;color:var(--text-tertiary);margin-top:.25rem}.invite-input-row{display:flex;gap:.5rem}.invite-input-row .form-input{flex:1}.service-card{background:var(--bg-elevated);border:1px solid var(--border);border-radius:.75rem;padding:1.25rem;display:flex;align-items:center;gap:1rem;transition:border-color .15s}.service-card:hover{border-color:var(--accent)}.service-card+.service-card{margin-top:.75rem}.service-icon{width:2.75rem;height:2.75rem;border-radius:.625rem;display:flex;align-items:center;justify-content:center;font-size:1.25rem;flex-shrink:0}.service-icon-configured{background:var(--success-subtle);color:var(--success)}.service-icon-missing{background:var(--bg-main);color:var(--text-tertiary);border:1px dashed var(--border)}.service-icon-error{background:var(--danger-subtle);color:var(--danger)}.service-info{flex:1}.service-name{font-size:.95rem;font-weight:600;margin-bottom:.125rem}.service-desc{font-size:.8rem;color:var(--text-secondary);margin-bottom:.375rem}.service-status{display:inline-flex;align-items:center;gap:.375rem;font-size:.75rem;font-weight:600}.service-status-dot{width:6px;height:6px;border-radius:50%}.service-status-connected .service-status-dot{background:var(--success)}.service-status-connected{color:var(--success)}.service-status-missing .service-status-dot{background:var(--text-tertiary)}.service-status-missing{color:var(--text-tertiary)}.service-status-error .service-status-dot{background:var(--danger)}.service-status-error{color:var(--danger)}.service-tools{display:flex;gap:.25rem;flex-wrap:wrap;margin-top:.25rem}.service-tool-badge{display:inline-block;padding:.1rem .4rem;font-size:.65rem;font-family:SF Mono,Monaco,monospace;background:var(--bg-main);border:1px solid var(--border);border-radius:.25rem;color:var(--text-tertiary)}.template-card{display:flex;flex-direction:column;align-items:flex-start;text-align:left;padding:.75rem;border:1px solid var(--border);border-radius:var(--radius);background:var(--bg-main);cursor:pointer;transition:border-color .15s,background .15s;font-family:inherit;font-size:inherit;color:inherit}.template-card:hover{border-color:var(--btn-primary-bg);background:var(--bg-elevated)}.template-mode{display:inline-block;padding:.1rem .4rem;font-size:.6rem;font-weight:700;letter-spacing:.06em;text-transform:uppercase;border-radius:3px}.template-mode-auto{background:#16a34a1f;color:#16a34a}.template-mode-review{background:#d977061f;color:#d97706}.template-risk{font-size:.6rem;font-weight:600;text-transform:uppercase;letter-spacing:.04em;color:var(--text-tertiary)}.template-tag{display:inline-block;padding:.1rem .35rem;font-size:.6rem;background:var(--bg-elevated);border:1px solid var(--border);border-radius:3px;color:var(--text-secondary)}@media (max-width: 560px){.template-card{grid-column:span 1!important}}.modal-backdrop{position:fixed;top:0;left:0;right:0;bottom:0;background:#00000080;z-index:1500;display:flex;align-items:center;justify-content:center}.modal{background:var(--bg-elevated);border-radius:.75rem;width:100%;max-width:32rem;max-height:calc(100vh - 4rem);overflow-y:auto;box-shadow:0 16px 48px #00000026}.modal-header{padding:1.5rem 1.5rem 0;display:flex;justify-content:space-between;align-items:flex-start}.modal-title{font-size:1.125rem;font-weight:700}.modal-close{width:2rem;height:2rem;background:none;border:none;cursor:pointer;color:var(--text-tertiary);font-size:1.25rem;display:flex;align-items:center;justify-content:center;border-radius:.375rem}.modal-close:hover{background:var(--bg-main);color:var(--text-primary)}.modal-body{padding:1.25rem 1.5rem}.modal-footer{padding:0 1.5rem 1.5rem;display:flex;gap:.5rem;justify-content:flex-end}.status-banner{padding:.625rem 1rem;font-size:.8rem;display:flex;align-items:center;gap:.5rem;border-radius:.5rem;margin-bottom:1rem}.status-banner-warn{background:var(--accent-subtle);color:var(--accent-hover);border:1px solid var(--accent)}.status-banner-error{background:var(--danger-subtle);color:var(--danger);border:1px solid var(--danger)}.status-banner-success{background:var(--success-subtle);color:var(--success);border:1px solid var(--success)}.status-banner-icon{font-size:1rem;flex-shrink:0}.status-banner-text{flex:1}.status-banner a{font-weight:600}.vault-progress{display:flex;flex-direction:column;align-items:center;gap:.75rem;padding:1.5rem 0}.vault-spinner{width:2rem;height:2rem;border:3px solid var(--border);border-top-color:var(--accent);border-radius:50%;animation:spin .8s linear infinite}@keyframes spin{to{transform:rotate(360deg)}}.vault-progress-text{font-size:.875rem;color:var(--text-secondary)}.service-health-row{display:flex;align-items:center;gap:.75rem;padding:.625rem 0;border-bottom:1px solid var(--border);font-size:.85rem}.service-health-row:last-child{border-bottom:none}.service-health-indicator{width:8px;height:8px;border-radius:50%;flex-shrink:0}.service-health-indicator.connected{background:var(--success)}.service-health-indicator.missing{background:var(--text-tertiary)}.service-health-indicator.error{background:var(--danger)}.service-health-name{font-weight:600;flex:1}.service-health-detail{font-size:.75rem;color:var(--text-tertiary)}.cred-field{position:relative}.cred-field .form-input{padding-right:3rem}.cred-toggle{position:absolute;right:.5rem;top:50%;transform:translateY(-50%);background:none;border:none;font-size:.75rem;color:var(--text-tertiary);cursor:pointer;padding:.25rem}.cred-toggle:hover{color:var(--accent)}.context-strip{background:var(--bg-elevated);border:1px solid var(--border);border-radius:.5rem;padding:.625rem 1rem;margin-bottom:1.5rem;display:flex;align-items:center;gap:.75rem;font-size:.8rem}.context-strip-label{font-weight:600;color:var(--text-secondary)}.timeline{position:relative;padding-left:2rem}.timeline:before{content:"";position:absolute;left:.5rem;top:0;bottom:0;width:2px;background:var(--border)}.timeline-event{position:relative;margin-bottom:1.5rem}.timeline-event:before{content:"";position:absolute;left:-1.625rem;top:.5rem;width:10px;height:10px;border-radius:50%;background:var(--accent);border:2px solid var(--bg-main)}.timeline-event.expired:before{background:var(--text-tertiary)}.error-message{padding:.75rem 1rem;background:#dc262614;border:1px solid var(--danger);border-radius:.5rem;color:var(--danger);font-size:.875rem;margin-bottom:1rem}.mobile-menu-btn{display:none;width:2.25rem;height:2.25rem;background:none;border:1px solid var(--border);border-radius:.375rem;cursor:pointer;color:var(--text-secondary);font-size:1.1rem;align-items:center;justify-content:center;font-family:inherit}.mobile-menu-btn:hover{color:var(--accent);border-color:var(--accent)}.mobile-menu-backdrop{display:none;position:fixed;top:0;right:0;bottom:0;left:0;background:#0006;z-index:2000}.mobile-menu-panel{display:none;position:fixed;top:0;right:0;bottom:0;width:16rem;background:var(--bg-elevated);border-left:1px solid var(--border);z-index:2001;flex-direction:column;overflow-y:auto}.mobile-menu-header{padding:1.25rem 1rem;border-bottom:1px solid var(--border);display:flex;flex-direction:column;gap:.25rem}.mobile-menu-nav{flex:1;padding:.5rem;display:flex;flex-direction:column}.mobile-menu-item{display:flex;align-items:center;gap:.625rem;padding:.5rem .75rem;margin-bottom:.125rem;border-radius:.375rem;font-size:.85rem;color:var(--text-secondary);text-decoration:none;transition:background .15s,color .15s}.mobile-menu-item:hover{background:var(--accent-subtle);color:var(--text-primary)}.mobile-menu-item.active{background:var(--accent-subtle);color:var(--accent);font-weight:600}.mobile-menu-item .icon{width:1.125rem;text-align:center;font-size:.9rem;flex-shrink:0}.mobile-menu-footer{padding:.75rem 1rem;border-top:1px solid var(--border);display:flex;flex-direction:column;gap:.25rem}.mobile-menu-action{display:flex;align-items:center;gap:.625rem;padding:.5rem .75rem;border-radius:.375rem;font-size:.85rem;color:var(--text-secondary);background:none;border:none;cursor:pointer;font-family:inherit;text-align:left}.mobile-menu-action:hover{background:var(--accent-subtle);color:var(--text-primary)}.mobile-menu-action .icon{width:1.125rem;text-align:center;font-size:.9rem;flex-shrink:0}@media (max-width: 768px){.sidebar{display:none}.main-content{margin-left:0}.quick-actions,.selection-grid{grid-template-columns:1fr}.nav-actions-desktop,.step-label-text{display:none}.mobile-menu-btn{display:flex}.mobile-menu-backdrop{display:block}.mobile-menu-panel{display:flex}.login-split{flex-direction:column;min-height:auto}.login-split-left{padding:3rem 1.5rem;align-items:flex-start}.login-split-right{max-width:none;border-left:none;border-top:1px solid var(--border);padding:2.5rem 1.5rem}}.update-banner{position:fixed;top:var(--nav-height);left:0;right:0;z-index:900;background:#c0392b;color:#fff;border-top:1px solid rgba(0,0,0,.2);border-bottom:1px solid rgba(0,0,0,.2);padding:.6rem 1.25rem;display:flex;flex-direction:column;gap:.6rem}body.has-update-banner .sidebar{top:calc(var(--nav-height) + var(--update-banner-h, 0px));height:calc(100vh - var(--nav-height) - var(--update-banner-h, 0px))}body.has-update-banner .main-content{margin-top:calc(var(--nav-height) + var(--update-banner-h, 0px))}.update-banner-row{display:flex;align-items:center;justify-content:space-between;gap:1rem;min-width:0}.update-banner-cmd-row{flex-wrap:wrap}.update-banner-text{font-size:.9rem;font-weight:600;color:#fff}.update-banner-cmd{display:block;flex:1;min-width:0;font-size:.78rem;padding:.5rem .75rem;word-break:break-all;white-space:pre-wrap;background:#0003;border:1px solid rgba(255,255,255,.65);border-radius:.375rem;font-family:SF Mono,Fira Code,Fira Mono,Menlo,Consolas,monospace;color:#fff;-webkit-user-select:all;user-select:all}.update-banner-hint{margin:0;font-size:.8rem;color:#ffffffe6}.update-banner .btn-secondary{color:#fff;border-color:#ffffffa6;background:transparent}.update-banner .btn-secondary:hover:not(:disabled){background:#ffffff26;color:#fff;border-color:#fff}.update-banner-x{background:transparent;border:none;color:#ffffffd9;cursor:pointer;font-size:1.15rem;line-height:1;padding:0 .25rem}.update-banner-x:hover{color:#fff}.update-banner.is-live{background:var(--success)}body.is-updating .top-nav,body.is-updating .sidebar,body.is-updating .main-content,body.is-updating .update-banner{filter:blur(5px);pointer-events:none;-webkit-user-select:none;user-select:none}.update-overlay{position:fixed;top:0;right:0;bottom:0;left:0;z-index:2000;display:flex;align-items:center;justify-content:center;background:#11111159;padding:1rem}.update-overlay-card{background:var(--bg-elevated);border:1px solid var(--border);border-radius:1rem;padding:2rem 2.25rem;max-width:460px;width:100%;text-align:center;box-shadow:0 20px 60px #00000040}.update-overlay-card h2{margin:0 0 .6rem;font-size:1.15rem}.update-overlay-card p{margin:0 0 .5rem;font-size:.88rem;color:var(--text-muted);line-height:1.55}.update-spinner{width:2.25rem;height:2.25rem;border:3px solid var(--border);border-top-color:var(--text-primary);border-radius:50%;margin:0 auto 1.1rem;animation:update-spin 1s linear infinite}@keyframes update-spin{to{transform:rotate(360deg)}}.update-cmd-row{display:flex;gap:.5rem;align-items:flex-start;margin:.9rem 0;text-align:left}.update-cmd{flex:1;min-width:0;font-size:.78rem;padding:.6rem .75rem;background:#111;color:#fff;border-radius:.45rem;font-family:SF Mono,Fira Code,Fira Mono,Menlo,Consolas,monospace;word-break:break-all;white-space:pre-wrap}.update-status{font-size:.8rem;color:var(--text-muted);margin:.4rem 0 1.1rem;display:flex;align-items:center;justify-content:center;gap:.4rem}.update-pulse{width:.55rem;height:.55rem;border-radius:50%;background:var(--success);animation:update-pulse 1.2s ease infinite}@keyframes update-pulse{0%,to{opacity:.3}50%{opacity:1}}.update-overlay-actions{display:flex;gap:.6rem;justify-content:center}.search-filter-bar{display:flex;gap:.5rem;margin-bottom:.75rem}.search-input-wrap{flex:1;position:relative}.search-icon{position:absolute;left:.75rem;top:50%;transform:translateY(-50%);color:var(--text-tertiary);font-size:1rem;pointer-events:none}.search-input{padding-left:2.25rem!important;padding-right:2rem!important}.search-clear{position:absolute;right:.5rem;top:50%;transform:translateY(-50%);background:none;border:none;color:var(--text-tertiary);font-size:1.1rem;cursor:pointer;padding:.25rem;line-height:1}.search-clear:hover{color:var(--text-primary)}.filter-panel{background:var(--bg-elevated);border:1px solid var(--border);border-radius:.5rem;padding:1rem;margin-bottom:.75rem;display:flex;flex-direction:column;gap:.75rem}.filter-section{display:flex;align-items:baseline;gap:.75rem}.filter-label{font-size:.75rem;font-weight:600;color:var(--text-tertiary);text-transform:uppercase;letter-spacing:.04em;min-width:5rem;flex-shrink:0}.filter-chips{display:flex;flex-wrap:wrap;gap:.375rem}.filter-chip{font-family:inherit;font-size:.8rem;padding:.3rem .625rem;border-radius:1rem;border:1px solid var(--border);background:var(--bg-main);color:var(--text-secondary);cursor:pointer;transition:all .15s}.filter-chip:hover{border-color:var(--accent);color:var(--text-primary)}.filter-chip.selected{background:var(--accent-subtle);border-color:var(--accent);color:var(--accent);font-weight:600}.active-filters{display:flex;flex-wrap:wrap;align-items:center;gap:.375rem;margin-bottom:.75rem}.active-chip{display:inline-flex;align-items:center;gap:.25rem;font-size:.75rem;padding:.2rem .5rem;border-radius:1rem;background:var(--accent-subtle);color:var(--accent);cursor:pointer;transition:background .15s}.active-chip:hover{background:var(--accent);color:var(--bg-elevated)}.chip-remove{font-size:.85rem;line-height:1}.clear-filters{font-family:inherit;font-size:.75rem;color:var(--text-tertiary);background:none;border:none;cursor:pointer;padding:.2rem 0}.clear-filters:hover{color:var(--text-primary)}.receipt-action{display:inline-block;font-size:.75rem;font-weight:600;padding:.15rem .5rem;border-radius:1rem;background:var(--bg-main);border:1px solid var(--border);color:var(--text-secondary);font-family:SF Mono,Monaco,monospace}.bounds-section,.context-section{background:var(--bg-elevated);border:2px solid var(--edit-border);border-radius:.75rem;padding:1.25rem;margin-bottom:1.25rem;transition:border-color .15s}.bounds-section:hover,.bounds-section:focus-within,.context-section:hover,.context-section:focus-within{border-color:var(--accent-hover)}.bounds-section-header{display:flex;align-items:flex-start;gap:.625rem;margin-bottom:1rem}.bounds-section-icon{font-size:1.1rem;flex-shrink:0;margin-top:.1rem}.bounds-section-title{font-size:.9rem;font-weight:700;color:var(--text-primary)}.bounds-section-subtitle{font-size:.75rem;color:var(--text-tertiary)}.bounds-fields-grid{display:flex;flex-direction:column;gap:.75rem}.bounds-field-row{display:flex;flex-direction:row;align-items:center;justify-content:space-between;gap:1rem;width:100%}.bounds-field-label{flex:1;min-width:0}.bounds-field-label .form-label{display:inline;margin-bottom:0}.bounds-field-input{flex-shrink:0;display:flex;flex-direction:column;align-items:flex-end}.bounds-field-input .bounded-input{align-items:flex-end}.bounds-field-input .bounded-input-presets{justify-content:flex-end}.bounds-field-label-inline{display:flex;align-items:center;gap:.375rem;margin-bottom:.375rem}.bounds-field-label-inline .form-label{margin-bottom:0}.field-info-toggle{display:inline-flex;align-items:center;justify-content:center;width:1.125rem;height:1.125rem;border-radius:50%;border:1px solid var(--border);background:var(--bg-main);color:var(--text-tertiary);font-size:.65rem;font-weight:700;cursor:pointer;flex-shrink:0;transition:color .15s,border-color .15s;font-family:inherit;line-height:1;padding:0}.field-info-toggle:hover{color:var(--accent);border-color:var(--accent)}.field-description{margin-top:.25rem;margin-bottom:.25rem}@media (max-width: 768px){.bounds-field-row{flex-direction:column;gap:.375rem}}.bounded-input{display:flex;flex-direction:column;align-items:flex-start;gap:.375rem}.bounded-input-field{display:inline-flex;align-items:stretch;border:1px solid var(--border-field);border-radius:.5rem;overflow:hidden;background:var(--bg-field);color:var(--text-field)}.stepper-btn{display:flex;align-items:center;justify-content:center;width:2.25rem;height:2.25rem;background:transparent;border:none;cursor:pointer;font-size:1.1rem;font-weight:600;color:var(--text-field);font-family:inherit;flex-shrink:0;transition:background .15s}.stepper-btn:hover:not(:disabled){background:var(--placeholder-field)}.stepper-btn:disabled{opacity:.35;cursor:not-allowed}.stepper-input{width:4.5rem;text-align:center;border:none;border-left:1px solid var(--placeholder-field);border-right:1px solid var(--placeholder-field);padding:.5rem .25rem;font-size:.9rem;font-family:inherit;color:var(--text-field);background:var(--bg-field);outline:none;-moz-appearance:textfield}.stepper-input::-webkit-outer-spin-button,.stepper-input::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}.stepper-input:focus{box-shadow:inset 0 0 0 2px var(--field-focus-ring)}.bounded-input-unit{display:inline-flex;align-items:center;padding:0 .75rem;font-size:.8rem;color:var(--text-field);opacity:.7;white-space:nowrap;-webkit-user-select:none;user-select:none;background:transparent}.bounded-input-presets{display:flex;flex-wrap:wrap;gap:.25rem}.preset-chip{font-family:inherit;font-size:.75rem;padding:.2rem .625rem;border:1px solid var(--border);border-radius:999px;background:transparent;color:var(--text-secondary);cursor:pointer;transition:background .15s,color .15s,border-color .15s}.preset-chip:hover{background:var(--accent-subtle);color:var(--accent);border-color:var(--accent)}.preset-chip-selected{background:var(--accent);color:var(--bg-main);border-color:var(--accent)}.bounded-input-echo{font-size:.75rem;color:var(--text-secondary);font-style:italic}.field-label-with-tip{display:inline-flex;align-items:center;gap:.375rem;position:relative}.field-tip-trigger{display:inline-flex;align-items:center;justify-content:center;width:1.125rem;height:1.125rem;border-radius:999px;border:1px solid var(--border);background:transparent;color:var(--text-secondary);font-size:.7rem;font-style:italic;font-family:serif;font-weight:600;line-height:1;cursor:help;padding:0}.field-tip-trigger:hover,.field-tip-trigger[aria-expanded=true]{border-color:var(--accent);color:var(--accent)}.field-tip-bubble{position:absolute;top:calc(100% + .375rem);left:0;z-index:10;width:max-content;max-width:22rem;padding:.5rem .75rem;background:var(--bg-elevated);border:1px solid var(--border);border-radius:.375rem;font-size:.8rem;color:var(--text-primary);line-height:1.45;box-shadow:0 4px 12px #00000040;pointer-events:none}.tag-input{display:flex;flex-wrap:wrap;align-items:center;gap:.375rem;padding:.375rem .5rem;background:var(--bg-field);border:1px solid var(--border-field);border-radius:.5rem;cursor:text;min-height:2.5rem;transition:box-shadow .2s,border-color .2s;color:var(--text-field)}.tag-input:focus-within{box-shadow:0 0 0 3px var(--field-focus-ring)}.tag-input-invalid{border-color:var(--danger)}.tag-input-invalid:focus-within{box-shadow:0 0 0 3px #dc26262e}.tag-pill{display:inline-flex;align-items:center;gap:.25rem;font-size:.8rem;padding:.2rem .5rem;border-radius:1rem;background:var(--placeholder-field);color:var(--text-field);font-weight:500;white-space:nowrap}.tag-remove{display:inline-flex;align-items:center;justify-content:center;background:none;border:none;font-size:.9rem;line-height:1;color:var(--text-field);cursor:pointer;padding:0;margin-left:.125rem;opacity:.7;transition:opacity .15s}.tag-remove:hover{opacity:1}.tag-input-field{flex:1;min-width:8rem;border:none;outline:none;background:transparent;font-size:.875rem;font-family:inherit;color:var(--text-field);padding:.2rem 0}.tag-input-field::placeholder{color:var(--placeholder-field);opacity:1}.checkbox-group{display:flex;flex-wrap:wrap;gap:.5rem}.checkbox-pill{display:inline-flex;align-items:center;gap:.35rem;font-size:.85rem;padding:.35rem .75rem;border-radius:1rem;border:1px solid var(--border);background:var(--bg-secondary);color:var(--text-secondary);cursor:pointer;transition:all .15s;-webkit-user-select:none;user-select:none}.checkbox-pill input[type=checkbox]{display:none}.checkbox-pill:hover{border-color:var(--accent);color:var(--text-primary)}.checkbox-pill-selected{background:var(--btn-primary-bg);border-color:var(--btn-primary-bg);color:var(--btn-primary-fg);font-weight:500}.checkbox-pill-selected:hover{background:var(--btn-primary-bg-hover);border-color:var(--btn-primary-bg-hover);color:var(--btn-primary-fg)}@keyframes hap-skeleton-shimmer{0%{background-position:200% 0}to{background-position:-200% 0}}.skeleton{display:block;position:relative;border-radius:.375rem;background-color:var(--bg-main);background-image:linear-gradient(90deg,transparent 0%,rgba(255,255,255,.06) 20%,rgba(255,255,255,.16) 50%,rgba(255,255,255,.06) 80%,transparent 100%);background-size:200% 100%;background-repeat:no-repeat;animation:hap-skeleton-shimmer 1.6s ease-in-out infinite;will-change:background-position}[data-theme=light] .skeleton,:root:not([data-theme=dark]) .skeleton{background-image:linear-gradient(90deg,transparent 0%,rgba(0,0,0,.03) 20%,rgba(0,0,0,.08) 50%,rgba(0,0,0,.03) 80%,transparent 100%)}.skeleton-title{height:1.5rem;width:3rem;margin:0 auto}.skeleton-line{height:.75rem;width:100%}.skeleton-line-sm{height:.65rem;width:60%}.skeleton-card{background:var(--bg-elevated);border:1px solid var(--border);border-radius:.5rem;padding:.75rem 1rem;box-shadow:0 1px 2px #0000000a;display:flex;align-items:center;gap:.75rem}.skeleton-dot{width:.5rem;height:.5rem;border-radius:50%;flex-shrink:0}@media (prefers-reduced-motion: reduce){.skeleton{animation:none;background-image:none}}.intent-layout{display:grid;grid-template-columns:minmax(320px,1fr) minmax(420px,1.4fr);gap:1.25rem;align-items:start}.intent-pane.chat{display:flex;flex-direction:column;gap:.75rem;position:sticky;top:1rem;align-self:start;max-height:calc(100vh - 4rem)}.intent-pane.document{display:flex;flex-direction:column;gap:.875rem}.intent-pane .card-title{font-size:1.25rem;margin:0 0 1rem}.intent-textarea{width:100%;background:var(--bg-field);border:1px solid var(--border-field);border-radius:.5rem;padding:.625rem .75rem;color:var(--text-field);font-size:.9rem;line-height:1.5;resize:vertical;min-height:22rem;outline:none;font-family:inherit;transition:box-shadow .15s}.intent-textarea:focus{box-shadow:0 0 0 3px var(--field-focus-ring)}.intent-textarea::placeholder{color:var(--placeholder-field);opacity:1}.intent-footer{display:flex;align-items:center;gap:.625rem;margin-top:.5rem}.intent-continue-btn{flex:1}.intent-chat{display:flex;flex-direction:column;gap:.75rem;flex:1;min-height:0}.intent-chat .chat-header{font-size:.72rem;font-weight:700;text-transform:uppercase;letter-spacing:.07em;color:var(--text-muted)}.intent-chat .chat-messages{flex:1;overflow-y:auto;display:flex;flex-direction:column;gap:1rem;padding:.25rem 0;min-height:14rem;max-height:32rem}.intent-chat .chat-msg{display:flex;max-width:100%}.intent-chat .chat-msg.assistant{justify-content:flex-start}.intent-chat .chat-msg.assistant .chat-msg-body{max-width:100%;color:var(--text-primary);font-size:.9rem;line-height:1.65;white-space:pre-wrap;word-break:break-word}.intent-chat .chat-msg.user{justify-content:flex-end}.intent-chat .chat-msg.user .chat-msg-body{max-width:85%;background:var(--bg-main);border:1px solid var(--border);border-radius:1.125rem;padding:.55rem .875rem;color:var(--text-primary);font-size:.9rem;line-height:1.55;white-space:pre-wrap;word-break:break-word}.intent-chat .chat-msg-prose{white-space:pre-wrap;word-break:break-word}.intent-chat .chat-msg-thinking{color:var(--text-muted);font-style:italic}.intent-chat .chat-fenced-block{display:block;background:var(--bg-elevated);border:1px solid var(--border);border-radius:.5rem;padding:.625rem .75rem;margin:.5rem 0;font-family:SF Mono,Monaco,Cascadia Code,monospace;font-size:.8rem;white-space:pre-wrap;color:var(--text-primary);line-height:1.55}.intent-chat .chat-apply-btn{margin-top:.5rem}.intent-chat .chat-composer{display:flex;flex-direction:column;gap:.375rem}.intent-chat .chat-composer-pill{display:flex;align-items:center;gap:.5rem;background:var(--bg-field);border:1px solid var(--border-field);border-radius:1.5rem;padding:.25rem .25rem .25rem 1rem;transition:box-shadow .15s;color:var(--text-field)}.intent-chat .chat-composer-pill:focus-within{box-shadow:0 0 0 3px var(--field-focus-ring)}.intent-chat .chat-input{flex:1;resize:none;background:transparent;border:none;padding:.5rem 0;color:var(--text-field);font-size:.9rem;line-height:1.4;outline:none;font-family:inherit;max-height:8rem;align-self:stretch}.intent-chat .chat-input::placeholder{color:var(--placeholder-field);opacity:1}.intent-chat .chat-send-btn{flex-shrink:0;width:2rem;height:2rem;border-radius:999px;background:var(--text-field);color:var(--bg-field);border:none;cursor:pointer;display:inline-flex;align-items:center;justify-content:center;font-size:1rem;font-weight:700;line-height:1;align-self:center;transition:opacity .15s,transform .1s}.intent-chat .chat-send-btn:hover:not(:disabled){opacity:.85}.intent-chat .chat-send-btn:active:not(:disabled){transform:scale(.95)}.intent-chat .chat-send-btn:disabled{opacity:.35;cursor:not-allowed}.intent-chat .chat-composer-hint{font-size:.72rem;color:var(--text-muted);padding-left:.5rem}.hint-box{display:flex;gap:.625rem;padding:.75rem .875rem;background:var(--bg-main);border:1px solid var(--border);border-left:3px solid var(--accent);border-radius:.5rem;font-size:.85rem;color:var(--text-primary);line-height:1.55;margin-top:.25rem}.hint-icon{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;width:1.125rem;height:1.125rem;border-radius:999px;border:1px solid var(--accent);color:var(--accent);font-size:.7rem;font-style:italic;font-family:serif;font-weight:700;line-height:1;margin-top:.125rem}.hint-body{flex:1;min-width:0}.hint-head{font-weight:600;margin-bottom:.25rem}@media (max-width: 1024px){.intent-layout{grid-template-columns:1fr}.intent-pane.chat{position:static;max-height:none}}@media (max-width: 768px){.intent-layout>.intent-pane.chat{display:none}.floating-help{display:inline-flex}}.floating-help{display:none;align-items:center;gap:.5rem;position:fixed;bottom:1rem;right:1rem;z-index:5;background:var(--btn-primary-bg);color:var(--btn-primary-fg);border:2px solid var(--btn-primary-bg);border-radius:999px;padding:.625rem 1.125rem;font-weight:700;font-size:.85rem;cursor:pointer;font-family:inherit;box-shadow:0 6px 18px var(--primary-glow)}.floating-help:hover{background:var(--btn-primary-bg-hover);border-color:var(--btn-primary-bg-hover)}.bottom-sheet{position:fixed;left:0;right:0;bottom:0;height:88vh;background:var(--bg-elevated);border-top:1px solid var(--border);border-radius:.75rem .75rem 0 0;z-index:11;padding:1rem 1rem 1.25rem;overflow-y:auto;display:flex;flex-direction:column;gap:.75rem;transform:translateY(100%);transition:transform .25s ease-out;box-shadow:0 -8px 32px #0009;outline:none}.bottom-sheet.is-open{transform:translateY(0)}.bottom-sheet-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;background:#0000008c;z-index:10;opacity:0;pointer-events:none;transition:opacity .2s}.bottom-sheet-backdrop.is-open{opacity:1;pointer-events:auto}.bottom-sheet-handle{width:2.5rem;height:.25rem;background:var(--text-muted);border-radius:999px;margin:0 auto .5rem;flex-shrink:0}.bottom-sheet-close{position:absolute;top:.5rem;right:.875rem;background:transparent;border:none;color:var(--text-primary);cursor:pointer;font-size:1.5rem;line-height:1;font-family:inherit}@media (prefers-reduced-motion: reduce){.bottom-sheet,.bottom-sheet-backdrop{transition:none}}.field-editable{background:var(--bg-elevated);border:2px solid var(--edit-border);border-radius:.5rem;padding:.875rem 1rem;margin-bottom:1rem;transition:border-color .15s}.field-editable:hover,.field-editable:focus-within{border-color:var(--accent-hover)}.field-label{font-size:.7rem;font-weight:600;text-transform:uppercase;letter-spacing:.05em;color:var(--text-tertiary);margin-bottom:.5rem;display:flex;align-items:center;gap:.35rem}.field-label .pen{opacity:.7;font-size:.75rem}.info-block{background:var(--bg-main);border-left:3px solid var(--border);border-radius:0 .375rem .375rem 0;padding:.75rem 1rem;margin-bottom:.75rem;font-size:.85rem;color:var(--text-secondary)}.info-head{display:flex;justify-content:space-between;align-items:baseline;margin-bottom:.4rem}.info-title{font-size:.7rem;font-weight:600;text-transform:uppercase;letter-spacing:.05em;color:var(--text-tertiary)}.info-edit{font-size:.72rem;color:var(--text-tertiary);text-decoration:underline;cursor:pointer;background:none;border:none;font-family:inherit;padding:0}.info-edit:hover{color:var(--accent-hover)}.info-kv{display:grid;grid-template-columns:max-content 1fr;gap:.15rem 1rem;margin:0}.info-kv dt{color:var(--text-tertiary)}.info-kv dd{margin:0;color:var(--text-secondary);word-break:break-word}.info-section-label{margin:1.25rem 0 .5rem;font-size:.7rem;font-weight:600;text-transform:uppercase;letter-spacing:.05em;color:var(--text-tertiary)}.intent-pane.chat.tool{background:var(--bg-main);border:1px dashed var(--border)}.recent-blocks .card-header{margin-bottom:.35rem}.recent-blocks .rb-sub{color:var(--text-muted);font-size:.8rem;margin:0 0 1.1rem;line-height:1.45;max-width:36ch}.recent-blocks .rb-count{flex:none;min-width:1.6rem;height:1.6rem;padding:0 .45rem;display:inline-flex;align-items:center;justify-content:center;font-size:.8rem;font-weight:600;font-variant-numeric:tabular-nums;background:color-mix(in srgb,var(--warning) 14%,transparent);color:var(--warning);border:1px solid color-mix(in srgb,var(--warning) 35%,transparent);border-radius:999px}.recent-blocks .rb-rows{display:flex;flex-direction:column}.recent-blocks .rb-row{display:grid;grid-template-columns:auto 1fr auto;gap:.75rem .85rem;align-items:start;padding:.85rem 0;border-top:1px solid var(--border)}.recent-blocks .rb-row:first-child{border-top:none}.recent-blocks .rb-dot{width:.5rem;height:.5rem;border-radius:999px;margin-top:.35rem;background:var(--warning)}.recent-blocks .rb-dot.act{background:var(--danger)}.recent-blocks .rb-dot.info{background:var(--text-muted)}.recent-blocks .rb-body{min-width:0}.recent-blocks .rb-line{font-size:.86rem;line-height:1.4;color:var(--text-primary)}.recent-blocks .rb-line b{font-weight:600}.recent-blocks .rb-meta{display:flex;align-items:center;gap:.5rem;margin-top:.3rem;flex-wrap:wrap}.recent-blocks .rb-chip{font-size:.64rem;letter-spacing:.06em;text-transform:uppercase;font-weight:600;padding:.12rem .44rem;border-radius:.35rem;background:var(--accent-subtle);color:var(--text-muted)}.recent-blocks .rb-chip.warn{background:color-mix(in srgb,var(--warning) 14%,transparent);color:var(--warning)}.recent-blocks .rb-chip.act{background:var(--danger-subtle);color:var(--danger)}.recent-blocks .rb-via{font-size:.72rem;color:var(--text-muted)}.recent-blocks .rb-when{font-size:.74rem;color:var(--text-muted);font-variant-numeric:tabular-nums;white-space:nowrap;text-align:right}.recent-blocks .rb-fix{display:inline-block;margin-top:.4rem;font-size:.76rem;color:var(--text-primary);text-underline-offset:2px}.recent-blocks .rb-foot{margin-top:1rem;padding-top:.9rem;border-top:1px solid var(--border)}.recent-blocks .rb-viewall{font:inherit;font-size:.8rem;color:var(--text-primary);background:none;border:none;padding:0;cursor:pointer;text-decoration:underline;text-underline-offset:3px}.recent-blocks .rb-empty{text-align:center;padding:1.25rem 1rem .25rem}.recent-blocks .rb-mark{width:2.25rem;height:2.25rem;border-radius:999px;background:var(--success-subtle);color:var(--success);display:inline-flex;align-items:center;justify-content:center;margin-bottom:.75rem}.recent-blocks .rb-empty h3{font-size:.9rem;margin:0 0 .3rem}.recent-blocks .rb-empty p{font-size:.8rem;color:var(--text-muted);margin:0 auto;max-width:30ch;line-height:1.45}.receipt-head{display:flex;align-items:center;gap:.5rem;flex-wrap:wrap}.receipt-what{font-size:.95rem;font-weight:600;letter-spacing:-.01em;color:var(--text-primary)}.receipt-tag{font-size:.68rem;padding:.12rem .4rem;border-radius:4px;border:1px solid var(--border);color:var(--text-muted);white-space:nowrap}.receipt-tag-bound{color:var(--success);border-color:var(--success)}.receipt-scope{font-size:.82rem;color:var(--text-muted);margin-top:.2rem}.receipt-foot{display:flex;align-items:center;gap:.75rem;flex-wrap:wrap;margin-top:.55rem;padding-top:.55rem;border-top:1px solid var(--border)}.receipt-link{font-size:.78rem;color:var(--text-secondary);text-decoration:none;border-bottom:1px solid var(--border)}.receipt-link:hover{color:var(--accent-hover);border-color:var(--accent-hover)}.receipt-id{font-family:SF Mono,Monaco,monospace;font-size:.7rem;color:var(--text-muted)}.receipt-more{margin-top:.5rem}.receipt-more summary{cursor:pointer;font-size:.75rem;color:var(--text-muted);list-style:none}.receipt-more summary::-webkit-details-marker{display:none}.receipt-more summary:before{content:"▸"}.receipt-more[open] summary:before{content:"▾"}.receipt-kv{font-size:.72rem;color:var(--text-muted);margin-top:.4rem;line-height:1.7;font-family:SF Mono,Monaco,monospace;word-break:break-all}
|