@rcsb/rcsb-statistics 0.3.44-dev.aipcb.2 → 0.3.44
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/README.md +0 -12
- package/build/index.html +1 -1
- package/build/static/css/main.a8ce960b.css +8 -0
- package/build/static/js/10.d9d49a66.chunk.js +1 -0
- package/build/static/js/109.2ff3158c.chunk.js +1 -0
- package/build/static/js/152.d0d96551.chunk.js +2 -0
- package/build/static/js/{717.312e799d.chunk.js.LICENSE.txt → 152.d0d96551.chunk.js.LICENSE.txt} +16 -0
- package/build/static/js/317.c95bf735.chunk.js +1 -0
- package/build/static/js/47.96ede111.chunk.js +1 -0
- package/build/static/js/613.8638dc20.chunk.js +1 -0
- package/build/static/js/630.bc43e10d.chunk.js +1 -0
- package/build/static/js/main.0e4cd2a8.js +2 -0
- package/package.json +1 -2
- package/build/ai/chart-catalog.json +0 -76
- package/build/ai/chart-core.d.ts +0 -53
- package/build/ai/chart-core.js +0 -1
- package/build/static/css/221.be447a2a.chunk.css +0 -68
- package/build/static/css/489.00de475c.chunk.css +0 -92
- package/build/static/css/main.894a09f3.css +0 -10
- package/build/static/js/221.00ed9342.chunk.js +0 -1
- package/build/static/js/417.a91bf47f.chunk.js +0 -1
- package/build/static/js/463.93a9a793.chunk.js +0 -1
- package/build/static/js/489.37e3a556.chunk.js +0 -1
- package/build/static/js/503.3d99188e.chunk.js +0 -1
- package/build/static/js/639.a102039f.chunk.js +0 -2
- package/build/static/js/639.a102039f.chunk.js.LICENSE.txt +0 -15
- package/build/static/js/646.d06a86d8.chunk.js +0 -1
- package/build/static/js/690.c5f42ab2.chunk.js +0 -1
- package/build/static/js/717.312e799d.chunk.js +0 -2
- package/build/static/js/732.59dd3430.chunk.js +0 -1
- package/build/static/js/main.a02d7dee.js +0 -2
- /package/build/static/js/{main.a02d7dee.js.LICENSE.txt → main.0e4cd2a8.js.LICENSE.txt} +0 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rcsb/rcsb-statistics",
|
|
3
|
-
"version": "0.3.44
|
|
3
|
+
"version": "0.3.44",
|
|
4
4
|
"private": false,
|
|
5
5
|
"files": [
|
|
6
6
|
"build"
|
|
@@ -70,7 +70,6 @@
|
|
|
70
70
|
"webpack-dev-server": "^5.1.0"
|
|
71
71
|
},
|
|
72
72
|
"scripts": {
|
|
73
|
-
"test": "jest --runInBand",
|
|
74
73
|
"start": "webpack serve --mode development",
|
|
75
74
|
"build": "webpack --mode production",
|
|
76
75
|
"publishDev": "npm version prerelease --preid=dev && npm publish --tag next --access public",
|
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 1,
|
|
3
|
-
"action": "configureChart",
|
|
4
|
-
"name": "AI Powered Chart Builder",
|
|
5
|
-
"checkedAt": "2026-09-13",
|
|
6
|
-
"sources": ["https://search.rcsb.org/#faceted-queries", "https://search.rcsb.org/rcsbsearch/v2/metadata/schema"],
|
|
7
|
-
"countingRules": [
|
|
8
|
-
"Every value is a live count of released PDB entries, not polymer entities, atoms, chains, downloads, citations, or unique sequences. Computed models are excluded.",
|
|
9
|
-
"Categories may overlap when an entry has multiple methods, organisms, polymer types, input datasets, or resolution values. Do not sum overlapping buckets to claim a unique total.",
|
|
10
|
-
"Percentages use all matching entries in each cohort as the denominator, including entries missing the chart attribute. They are not normalized to the displayed top categories.",
|
|
11
|
-
"All filters are entry-level requirements. An organism and ligand filter may match different entities in the same entry. Do not promise same-chain, binding-site, or same-entity relationships.",
|
|
12
|
-
"Lower and upper bounds on one numeric or date attribute are combined into one inclusive interval. At least one value must satisfy both bounds; different reported resolutions cannot satisfy opposite ends of the interval.",
|
|
13
|
-
"Cumulative release-year counts start at the selected lower release-year bound, not necessarily the beginning of the archive. Current-year counts are incomplete.",
|
|
14
|
-
"Area charts require an ordered dimension, ascending labels, vertical orientation and linear scale. Their translucent series are not stacked. Doughnut charts follow the same complete, non-overlapping partition rules as pie charts.",
|
|
15
|
-
"Presentation settings change appearance only. They cannot change chart counts, filters, aggregation attributes, or destinations. Use only the supported palettes, legend positions, grid, line styles and numeric drawing controls.",
|
|
16
|
-
"Selecting a bucket searches matching entries, keeping every global and cohort filter. The clicked bucket is an independent requirement: in a multi-valued entry, the value in the bucket may differ from the value satisfying a population filter. Resolution buckets use one half-open interval including the lower bound and excluding the upper bound.",
|
|
17
|
-
"Comparisons use up to four explicit named cohorts with independent additional filters; cohorts may overlap. Never fabricate counts or arbitrary Search API attributes.",
|
|
18
|
-
"Ask a clarification when a request needs unsupported statistics, ambiguous units or entity relationships, or an unknown organism taxon. Preserve the existing chart and filters during refinement unless the user requests a change."
|
|
19
|
-
],
|
|
20
|
-
"dimensions": {
|
|
21
|
-
"releaseYear": {"label": "Release year", "attribute": "rcsb_accession_info.initial_release_date", "aggregation": "date_histogram", "interval": "year", "ordered": true, "overlapping": false},
|
|
22
|
-
"method": {"label": "Experimental method", "attribute": "exptl.method", "aggregation": "terms", "ordered": false, "overlapping": true},
|
|
23
|
-
"sourceOrganism": {"label": "Source organism", "attribute": "rcsb_entity_source_organism.ncbi_scientific_name", "aggregation": "terms", "ordered": false, "overlapping": true},
|
|
24
|
-
"resolution": {"label": "Resolution (Å)", "attribute": "rcsb_entry_info.resolution_combined", "aggregation": "histogram", "ordered": true, "overlapping": true},
|
|
25
|
-
"polymerType": {"label": "Polymer type", "attribute": "entity_poly.rcsb_entity_polymer_type", "aggregation": "terms", "ordered": false, "overlapping": true},
|
|
26
|
-
"integrativeInput": {"label": "Integrative input data type", "attribute": "rcsb_ihm_dataset_list.name", "aggregation": "terms", "ordered": false, "overlapping": true, "requiredFilter": {"field": "methodology", "operator": "in", "value": ["integrative"]}},
|
|
27
|
-
"methodology": {"label": "Structure determination methodology", "attribute": "rcsb_entry_info.structure_determination_methodology", "aggregation": "terms", "ordered": false, "overlapping": false}
|
|
28
|
-
},
|
|
29
|
-
"filters": {
|
|
30
|
-
"releaseYear": {"label": "Release year", "attribute": "rcsb_accession_info.initial_release_date", "kind": "year", "operators": ["gte", "lte"], "minimum": 1971, "maximum": 2100},
|
|
31
|
-
"method": {"label": "Experimental method", "attribute": "exptl.method", "kind": "enum", "operators": ["in"], "values": ["X-RAY DIFFRACTION", "ELECTRON MICROSCOPY", "SOLUTION NMR", "SOLID-STATE NMR", "NEUTRON DIFFRACTION", "ELECTRON CRYSTALLOGRAPHY", "FIBER DIFFRACTION", "POWDER DIFFRACTION", "SOLUTION SCATTERING", "INFRARED SPECTROSCOPY", "EPR", "FLUORESCENCE TRANSFER"]},
|
|
32
|
-
"resolution": {"label": "Resolution (Å)", "attribute": "rcsb_entry_info.resolution_combined", "kind": "number", "operators": ["gte", "lte"], "minimum": 0.01, "maximum": 1000},
|
|
33
|
-
"sourceTaxonomy": {"label": "Source organism NCBI taxonomy ID (including descendants)", "attribute": "rcsb_entity_source_organism.taxonomy_lineage.id", "kind": "taxonomy", "operators": ["in"]},
|
|
34
|
-
"sourceOrganism": {"label": "Exact source organism scientific name", "attribute": "rcsb_entity_source_organism.ncbi_scientific_name", "kind": "text", "operators": ["in"]},
|
|
35
|
-
"ligand": {"label": "Non-polymer chemical component ID present in entry", "attribute": "rcsb_nonpolymer_entity.rcsb_nonpolymer_comp_id", "kind": "identifier", "operators": ["in"]},
|
|
36
|
-
"polymerType": {"label": "Polymer type present in entry", "attribute": "entity_poly.rcsb_entity_polymer_type", "kind": "enum", "operators": ["in"], "values": ["Protein", "DNA", "RNA", "NA-hybrid", "Other"]},
|
|
37
|
-
"methodology": {"label": "Structure determination methodology", "attribute": "rcsb_entry_info.structure_determination_methodology", "kind": "enum", "operators": ["in"], "values": ["experimental", "integrative"]}
|
|
38
|
-
},
|
|
39
|
-
"knownTaxa": {"human": 9606, "mouse": 10090, "Escherichia coli": 562, "Saccharomyces cerevisiae": 4932},
|
|
40
|
-
"presentationDefaults": {"palette": "default", "legend": "auto", "grid": true, "lineStyle": "smooth", "pointRadius": 3, "borderWidth": 1, "barRadius": 0, "doughnutCutout": 60},
|
|
41
|
-
"specSchema": {
|
|
42
|
-
"type": "object", "additionalProperties": false,
|
|
43
|
-
"required": ["version", "title", "categoryLabel", "valueLabel", "dimension", "chartType", "measure", "scale", "orientation", "sort", "topN", "interval", "cumulative", "filters", "series"],
|
|
44
|
-
"properties": {
|
|
45
|
-
"version": {"type": "integer", "enum": [1]},
|
|
46
|
-
"title": {"type": "string", "minLength": 1, "maxLength": 140},
|
|
47
|
-
"categoryLabel": {"type": "string", "minLength": 1, "maxLength": 100},
|
|
48
|
-
"valueLabel": {"type": "string", "minLength": 1, "maxLength": 100},
|
|
49
|
-
"dimension": {"type": "string", "enum": ["releaseYear", "method", "sourceOrganism", "resolution", "polymerType", "integrativeInput", "methodology"]},
|
|
50
|
-
"chartType": {"type": "string", "enum": ["bar", "line", "area", "pie", "doughnut"]},
|
|
51
|
-
"measure": {"type": "string", "enum": ["count", "percent"]},
|
|
52
|
-
"scale": {"type": "string", "enum": ["linear", "logarithmic"]},
|
|
53
|
-
"orientation": {"type": "string", "enum": ["vertical", "horizontal"]},
|
|
54
|
-
"sort": {"type": "string", "enum": ["labelAsc", "countDesc"]},
|
|
55
|
-
"topN": {"type": "integer", "minimum": 1, "maximum": 60},
|
|
56
|
-
"interval": {"type": "number", "minimum": 0.1, "maximum": 100},
|
|
57
|
-
"cumulative": {"type": "boolean"},
|
|
58
|
-
"presentation": {"$ref": "#/$defs/presentation"},
|
|
59
|
-
"filters": {"type": "array", "maxItems": 12, "items": {"$ref": "#/$defs/filter"}},
|
|
60
|
-
"series": {"type": "array", "minItems": 1, "maxItems": 4, "items": {"type": "object", "additionalProperties": false, "required": ["label", "filters"], "properties": {"label": {"type": "string", "minLength": 1, "maxLength": 80}, "filters": {"type": "array", "maxItems": 8, "items": {"$ref": "#/$defs/filter"}}}}}
|
|
61
|
-
},
|
|
62
|
-
"$defs": {
|
|
63
|
-
"presentation": {"type": "object", "additionalProperties": false, "properties": {
|
|
64
|
-
"palette": {"type": "string", "enum": ["default", "accessible", "warm", "cool", "monochrome"]},
|
|
65
|
-
"legend": {"type": "string", "enum": ["auto", "top", "bottom", "left", "right", "hidden"]},
|
|
66
|
-
"grid": {"type": "boolean"},
|
|
67
|
-
"lineStyle": {"type": "string", "enum": ["straight", "smooth", "stepped"]},
|
|
68
|
-
"pointRadius": {"type": "integer", "minimum": 0, "maximum": 8},
|
|
69
|
-
"borderWidth": {"type": "integer", "minimum": 1, "maximum": 5},
|
|
70
|
-
"barRadius": {"type": "integer", "minimum": 0, "maximum": 12},
|
|
71
|
-
"doughnutCutout": {"type": "integer", "minimum": 20, "maximum": 85}
|
|
72
|
-
}},
|
|
73
|
-
"filter": {"type": "object", "additionalProperties": false, "required": ["field", "operator", "value"], "properties": {"field": {"type": "string", "enum": ["releaseYear", "method", "resolution", "sourceTaxonomy", "sourceOrganism", "ligand", "polymerType", "methodology"]}, "operator": {"type": "string", "enum": ["in", "gte", "lte"]}, "value": {"anyOf": [{"type": "number"}, {"type": "array", "minItems": 1, "maxItems": 10, "uniqueItems": true, "items": {"anyOf": [{"type": "string", "minLength": 1, "maxLength": 120}, {"type": "integer", "minimum": 1, "maximum": 999999999}]}}]}}}
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
}
|
package/build/ai/chart-core.d.ts
DELETED
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
export interface ChartFilter { field: string; operator: 'in' | 'gte' | 'lte'; value: number | Array<string | number>; }
|
|
2
|
-
export interface ChartPresentation {
|
|
3
|
-
palette: 'default' | 'accessible' | 'warm' | 'cool' | 'monochrome';
|
|
4
|
-
legend: 'auto' | 'top' | 'bottom' | 'left' | 'right' | 'hidden';
|
|
5
|
-
grid: boolean;
|
|
6
|
-
lineStyle: 'straight' | 'smooth' | 'stepped';
|
|
7
|
-
pointRadius: number;
|
|
8
|
-
borderWidth: number;
|
|
9
|
-
barRadius: number;
|
|
10
|
-
doughnutCutout: number;
|
|
11
|
-
}
|
|
12
|
-
export interface ChartSpec {
|
|
13
|
-
version: 1;
|
|
14
|
-
title: string;
|
|
15
|
-
categoryLabel: string;
|
|
16
|
-
valueLabel: string;
|
|
17
|
-
dimension: 'releaseYear' | 'method' | 'sourceOrganism' | 'resolution' | 'polymerType' | 'integrativeInput' | 'methodology';
|
|
18
|
-
chartType: 'bar' | 'line' | 'area' | 'pie' | 'doughnut';
|
|
19
|
-
measure: 'count' | 'percent';
|
|
20
|
-
scale: 'linear' | 'logarithmic';
|
|
21
|
-
orientation: 'vertical' | 'horizontal';
|
|
22
|
-
sort: 'labelAsc' | 'countDesc';
|
|
23
|
-
topN: number;
|
|
24
|
-
interval: number;
|
|
25
|
-
cumulative: boolean;
|
|
26
|
-
presentation?: Partial<ChartPresentation>;
|
|
27
|
-
filters: ChartFilter[];
|
|
28
|
-
series: Array<{ label: string; filters: ChartFilter[] }>;
|
|
29
|
-
}
|
|
30
|
-
export interface ChartDataResult {
|
|
31
|
-
rows: Array<{ label: string; counts: number[]; values: number[] }>;
|
|
32
|
-
series: Array<{ label: string; total: number }>;
|
|
33
|
-
warnings: string[];
|
|
34
|
-
retrievedAt: string;
|
|
35
|
-
categoryCount: number;
|
|
36
|
-
}
|
|
37
|
-
export const catalog: {
|
|
38
|
-
version: number;
|
|
39
|
-
dimensions: Record<string, { label: string; attribute: string; aggregation: string; ordered: boolean; overlapping: boolean }>;
|
|
40
|
-
filters: Record<string, { label: string; attribute: string }>;
|
|
41
|
-
specSchema: Record<string, unknown>;
|
|
42
|
-
countingRules: string[];
|
|
43
|
-
presentationDefaults: ChartPresentation;
|
|
44
|
-
};
|
|
45
|
-
export function validateChartSpec(input: unknown): ChartSpec;
|
|
46
|
-
export function buildChartRequests(input: ChartSpec): Array<Record<string, unknown>>;
|
|
47
|
-
export function getChartPresentation(input: ChartSpec): ChartPresentation;
|
|
48
|
-
export function buildChartDrilldownRequest(input: ChartSpec, rowLabel: string, seriesIndex: number): Record<string, unknown>;
|
|
49
|
-
export function describeFilter(input: ChartFilter): string;
|
|
50
|
-
export function describeChart(input: ChartSpec): string;
|
|
51
|
-
export function chartWarnings(input: ChartSpec): string[];
|
|
52
|
-
export function chartChanges(previous: ChartSpec | null, input: ChartSpec): string[];
|
|
53
|
-
export function formatChartData(input: ChartSpec, responses: unknown[]): ChartDataResult;
|
package/build/ai/chart-core.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
const catalog=require("./chart-catalog.json"),isObject=e=>Boolean(e&&"object"==typeof e&&!Array.isArray(e)),has=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),fail=e=>{throw new Error(e)};function validateSchema(e,t,r=t,a="Chart"){if(t.$ref)return validateSchema(e,r.$defs[t.$ref.split("/").pop()],r,a);if(t.anyOf)return void(t.anyOf.some(t=>{try{return validateSchema(e,t,r,a),!0}catch{return!1}})||fail(`${a} has an invalid value.`));const i=t.type;("object"===i&&!isObject(e)||"array"===i&&!Array.isArray(e)||"integer"===i&&!Number.isInteger(e)||"number"===i&&("number"!=typeof e||!Number.isFinite(e))||"string"===i&&"string"!=typeof e||"boolean"===i&&"boolean"!=typeof e)&&fail(`${a} must be ${i}.`),t.enum&&!t.enum.includes(e)&&fail(`${a} is not supported.`),"number"==typeof e&&(void 0!==t.minimum&&e<t.minimum||void 0!==t.maximum&&e>t.maximum)&&fail(`${a} is outside the supported range.`),"string"==typeof e&&(t.minLength&&e.trim().length<t.minLength||t.maxLength&&e.length>t.maxLength||/[\u0000-\u0008\u000b\u000c\u000e-\u001f]/.test(e))&&fail(`${a} has invalid text.`),Array.isArray(e)&&((t.minItems&&e.length<t.minItems||t.maxItems&&e.length>t.maxItems||t.uniqueItems&&new Set(e.map(e=>JSON.stringify(e))).size!==e.length)&&fail(`${a} has an invalid number of items.`),e.forEach((e,i)=>validateSchema(e,t.items,r,`${a}[${i}]`))),isObject(e)&&((t.required||[]).forEach(t=>{has(e,t)||fail(`${a}.${t} is required.`)}),Object.keys(e).forEach(i=>{has(t.properties||{},i)?validateSchema(e[i],t.properties[i],r,`${a}.${i}`):!1===t.additionalProperties&&fail(`${a}.${i} is not supported.`)}))}function validateChartSpec(e){validateSchema(e,catalog.specSchema);const t=JSON.parse(JSON.stringify(e)),r=catalog.dimensions[t.dimension];return!["line","area"].includes(t.chartType)||r.ordered&&"vertical"===t.orientation&&"labelAsc"===t.sort||fail("Line and area charts require release year or resolution, vertical orientation, and ascending labels."),"area"===t.chartType&&"linear"!==t.scale&&fail("Area charts require a linear scale for their zero baseline."),["pie","doughnut"].includes(t.chartType)&&(r.overlapping||1!==t.series.length||t.cumulative||"linear"!==t.scale)&&fail("Pie and doughnut charts require a single non-overlapping series (release year or methodology), linear scale, and non-cumulative values."),!t.cumulative||"releaseYear"===t.dimension&&"labelAsc"===t.sort||fail("Cumulative charts require release year in chronological order."),"percent"===t.measure&&"linear"!==t.scale&&fail("Percentages require a linear scale."),new Set(t.series.map(e=>e.label)).size!==t.series.length&&fail("Give each comparison series a different label."),[t.filters,...t.series.map(e=>e.filters)].forEach(e=>e.forEach(e=>{const t=catalog.filters[e.field];t.operators.includes(e.operator)||fail(`Unsupported operator for ${t.label}.`),"in"===e.operator?(Array.isArray(e.value)||fail(`${t.label} requires a list.`),e.value.forEach(e=>{"taxonomy"===t.kind?(!Number.isInteger(e)||e<=0)&&fail("Taxonomy IDs must be positive integers."):("string"!=typeof e||t.values&&!t.values.includes(e)||"identifier"===t.kind&&!/^[A-Z0-9]{1,10}$/.test(e))&&fail(`Invalid value for ${t.label}.`)})):("number"!=typeof e.value||e.value<t.minimum||e.value>t.maximum||"year"===t.kind&&!Number.isInteger(e.value))&&fail(`Invalid range for ${t.label}.`)})),t.series.forEach(e=>{const r=[...t.filters,...e.filters];["releaseYear","resolution"].forEach(e=>{const t=r.filter(t=>t.field===e&&"gte"===t.operator).map(e=>e.value),a=r.filter(t=>t.field===e&&"lte"===t.operator).map(e=>e.value);t.length&&a.length&&Math.max(...t)>Math.min(...a)&&fail(`The ${e} lower bound exceeds its upper bound.`)}),"integrativeInput"===t.dimension&&r.some(e=>"methodology"===e.field&&!e.value.includes("integrative"))&&fail("Integrative input charts cannot exclude integrative structures.")}),t}function getChartPresentation(e){const t=validateChartSpec(e);return{...catalog.presentationDefaults,borderWidth:["line","area"].includes(t.chartType)?2:1,...t.presentation}}function terminal(e){const t=catalog.filters[e.field];let r=e.value;return"year"===t.kind&&(r=`${r}-${"gte"===e.operator?"01-01":"12-31"}`),"taxonomy"===t.kind&&(r=r.map(String)),{type:"terminal",service:"text",parameters:{attribute:t.attribute,operator:{in:"in",gte:"greater_or_equal",lte:"less_or_equal"}[e.operator],value:r}}}function filterTerminals(e){const t=new Set;return e.flatMap(r=>{const a=catalog.filters[r.field];if(!["number","year"].includes(a.kind))return[terminal(r)];if(t.has(r.field))return[];t.add(r.field);const i=e.filter(e=>e.field===r.field),n=i.filter(e=>"gte"===e.operator).map(e=>e.value),o=i.filter(e=>"lte"===e.operator).map(e=>e.value);if(!n.length||!o.length)return[terminal({...r,operator:n.length?"gte":"lte",value:n.length?Math.max(...n):Math.min(...o)})];const l=Math.max(...n),s=Math.min(...o);return[{type:"terminal",service:"text",parameters:{attribute:a.attribute,operator:"range",value:{from:"year"===a.kind?`${l}-01-01`:l,to:"year"===a.kind?`${s}-12-31`:s,include_lower:!0,include_upper:!0}}}]})}function buildChartRequests(e){const t=validateChartSpec(e),r=catalog.dimensions[t.dimension],a={name:"chart",aggregation_type:r.aggregation,attribute:r.attribute,min_interval_population:1};return"terms"===r.aggregation&&(a.max_num_intervals=1e3),"date_histogram"===r.aggregation&&(a.interval="year"),"histogram"===r.aggregation&&(a.interval=t.interval),t.series.map(e=>{const i=[...t.filters,...e.filters,...r.requiredFilter?[r.requiredFilter]:[]],n={return_type:"entry",request_options:{results_content_type:["experimental"],paginate:{start:0,rows:0},facets:[a]}};return i.length&&(n.query={type:"group",logical_operator:"and",nodes:filterTerminals(i).map(e=>({type:"group",logical_operator:"and",nodes:[e]}))}),n})}function buildChartDrilldownRequest(e,t,r){const a=validateChartSpec(e);(!Number.isInteger(r)||r<0||r>=a.series.length)&&fail("Select a valid chart series."),("string"!=typeof t||!t.trim()||t.length>300||/[\u0000-\u001f\u007f]/.test(t))&&fail("Select a valid chart category.");const i={attribute:catalog.dimensions[a.dimension].attribute,operator:"exact_match",value:t};if("releaseYear"===a.dimension){(!/^\d{4}$/.test(t)||Number(t)<catalog.filters.releaseYear.minimum||Number(t)>catalog.filters.releaseYear.maximum)&&fail("Select a valid release year.");const e=`${Number(t)+1}-01-01`;i.operator=a.cumulative?"less":"range",i.value=a.cumulative?e:{from:`${t}-01-01`,to:e,include_lower:!0,include_upper:!1}}else if("resolution"===a.dimension){const e=Number(t);(!/^(?:0|[1-9]\d*)(?:\.\d+)?$/.test(t)||!Number.isFinite(e)||e<0||e>catalog.filters.resolution.maximum||Math.abs(e/a.interval-Math.round(e/a.interval))>1e-8)&&fail("Select a valid resolution interval."),i.operator="range",i.value={from:e,to:Number((e+a.interval).toPrecision(12)),include_lower:!0,include_upper:!1}}const n=buildChartRequests(a)[r];return{return_type:"entry",query:{type:"group",logical_operator:"and",nodes:[...n.query?.nodes||[],{type:"group",logical_operator:"and",nodes:[{type:"terminal",service:"text",parameters:i}]}]},request_options:{results_content_type:["experimental"],paginate:{start:0,rows:25}}}}function describeFilter(e){return`${catalog.filters[e.field].label} ${"in"===e.operator?"is any of":"gte"===e.operator?"≥":"≤"} ${Array.isArray(e.value)?e.value.join(", "):e.value}`}function describeChart(e){return validateChartSpec(e),`${e.cumulative?"Cumulative ":""}${"count"===e.measure?"PDB entry counts":"Percentage of matching PDB entries"} by ${catalog.dimensions[e.dimension].label.toLowerCase()}; ${e.chartType} chart; ${e.series.length} ${1===e.series.length?"series":"comparison series"}.`}function chartWarnings(e){const t=[];return catalog.dimensions[e.dimension].overlapping&&t.push("An entry may occur in more than one category. Bucket counts must not be summed as a unique entry total."),e.series.length>1&&t.push("Comparison cohorts may overlap; each is counted independently."),"sourceOrganism"===e.dimension&&t.push("Source organisms are those recorded for any matching entry; they are not expression hosts. All source types are included."),"releaseYear"===e.dimension&&t.push("Counts describe the current archive by initial release year, not historical archive snapshots. The current year is incomplete."),e.cumulative&&t.push("Cumulative values begin at the earliest year included by the filters."),"area"===e.chartType&&t.push("Area series use a zero baseline and are not stacked; overlapping cohorts are counted independently."),"logarithmic"===e.scale&&t.push("Zero values are omitted from the logarithmic chart; the table retains them."),"percent"===e.measure&&t.push("The denominator is every matching entry in that series, including entries missing the chart attribute."),t}function chartChanges(e,t){return e?(validateChartSpec(e),validateChartSpec(t),[...new Set([...Object.keys(e),...Object.keys(t)])].filter(r=>JSON.stringify(e[r])!==JSON.stringify(t[r])).flatMap(r=>{if("presentation"===r){const r=getChartPresentation(e),a=getChartPresentation(t),i={palette:"Color palette",legend:"Legend",grid:"Grid lines",lineStyle:"Line style",pointRadius:"Point radius",borderWidth:"Border width",barRadius:"Bar corner radius",doughnutCutout:"Doughnut cutout"},n=(e,t)=>"grid"===e?t?"shown":"hidden":"doughnutCutout"===e?`${t}%`:String(t);return Object.keys(a).filter(e=>r[e]!==a[e]).map(e=>`${i[e]}: ${n(e,r[e])} → ${n(e,a[e])}.`)}return"filters"===r?`Filters: ${t.filters.length?t.filters.map(describeFilter).join("; "):"none"}.`:"series"===r?`Series: ${t.series.map(e=>`${e.label}${e.filters.length?` (${e.filters.map(describeFilter).join("; ")})`:""}`).join("; ")}.`:`${r}: ${String(e[r])} → ${String(t[r])}`})):["Create a new chart."]}function formatChartData(e,t){const r=validateChartSpec(e);Array.isArray(t)&&t.length===r.series.length||fail("A response is required for every chart series.");const a=catalog.dimensions[r.dimension];let i=!1;const n=t.map((e,t)=>{(!isObject(e)||!Number.isInteger(e.total_count)||e.total_count<0)&&fail("The Search API did not return a valid entry count.");const a=e.facets?.find(e=>"chart"===e.name)?.buckets;Array.isArray(a)||0===e.total_count||fail("The Search API did not return the requested chart aggregation."),(a||[]).length>=1e3&&(i=!0);const n=new Map;return(a||[]).forEach(t=>{(!Number.isInteger(t.population)||t.population<0||t.population>e.total_count||!["string","number"].includes(typeof t.label)||String(t.label).length>300)&&fail("The Search API returned an invalid chart bucket.");let a=String(t.label);if("releaseYear"===r.dimension){const e=a.match(/\d{4}/);e||fail("The Search API returned an invalid release year."),a=e[0]}"resolution"===r.dimension&&((!Number.isFinite(Number(a))||Number(a)<0)&&fail("The Search API returned an invalid resolution interval."),a=String(Number(Number(a).toPrecision(12)))),n.has(a)&&fail("The Search API returned duplicate chart buckets."),n.set(a,t.population)}),{label:r.series[t].label,total:e.total_count,values:n}});let o=[...new Set(n.flatMap(e=>[...e.values.keys()]))];const l=o.every(e=>Number.isFinite(Number(e)));if(o.sort((e,t)=>l?Number(e)-Number(t):e.localeCompare(t)),"releaseYear"===r.dimension&&o.length){const e=Number(o[0]),t=Number(o[o.length-1]);t-e>200&&fail("The Search API returned an unsupported year range."),o=Array.from({length:t-e+1},(t,r)=>String(e+r))}if("resolution"===r.dimension&&o.length){const e=Number(o[0]),t=Math.round((Number(o[o.length-1])-e)/r.interval)+1;t>1e3&&fail("This resolution histogram exceeds 1,000 bins. Increase the bin width or narrow the resolution range."),o=Array.from({length:t},(t,a)=>String(Number((e+a*r.interval).toPrecision(12))))}const s=o.map(e=>({label:e,counts:n.map(t=>t.values.get(e)||0)}));if(r.cumulative){const e=n.map(()=>0);s.forEach(t=>{t.counts=t.counts.map((t,r)=>e[r]+=t)})}"countDesc"===r.sort&&s.sort((e,t)=>t.counts.reduce((e,t)=>e+t,0)-e.counts.reduce((e,t)=>e+t,0)||e.label.localeCompare(t.label));const u=!a.ordered,c=(u?s.slice(0,r.topN):s).map(e=>({...e,values:e.counts.map((e,t)=>"percent"===r.measure?n[t].total?100*e/n[t].total:0:e)})),h=chartWarnings(r);return u&&s.length>c.length&&h.push(`Showing ${c.length} of ${s.length}${i?"+":""} categories returned. Omitted categories are not combined into an invented “Other” count.`),i&&h.push("The category aggregation reached its 1,000-bucket limit. Narrow the filters for a more complete category listing."),["pie","doughnut"].includes(r.chartType)&&(i||c.length!==s.length)&&fail("A pie or doughnut chart must show all categories. Increase the category limit or use a bar chart."),["pie","doughnut"].includes(r.chartType)&&c.reduce((e,t)=>e+t.counts[0],0)!==n[0].total&&fail("A pie or doughnut chart requires complete, non-overlapping categories covering every matching entry. Use a bar chart for this population."),{rows:c,series:n.map(({label:e,total:t})=>({label:e,total:t})),warnings:h,retrievedAt:(new Date).toISOString(),categoryCount:s.length}}module.exports={catalog,validateSchema,validateChartSpec,getChartPresentation,buildChartRequests,buildChartDrilldownRequest,describeFilter,describeChart,chartWarnings,chartChanges,formatChartData};
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
:where(#statsroot) .ai-chart-workspace { --ai-brand: #337ab7; --ai-border: #d5e2ed; color: #283747; padding: 0 4px 24px; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; }
|
|
2
|
-
:where(#statsroot) .ai-chart-page-heading { display: flex; justify-content: space-between; align-items: flex-start; gap: 18px; margin: 18px 0 18px; }
|
|
3
|
-
:where(#statsroot) .ai-chart-page-heading h1 { font-size: 29px; font-weight: 650; margin: 8px 0 9px; color: #253f56; }
|
|
4
|
-
:where(#statsroot) .ai-chart-page-heading p { color: #617080; max-width: 750px; margin-bottom: 0; line-height: 1.55; }
|
|
5
|
-
:where(#statsroot) .ai-chart-eyebrow { text-transform: uppercase; letter-spacing: .08em; color: #587b98; font-size: 11px; font-weight: 700; }
|
|
6
|
-
:where(#statsroot) .ai-chart-layout { display: grid; grid-template-columns: minmax(310px, 370px) minmax(0, 1fr); gap: 22px; align-items: start; }
|
|
7
|
-
:where(#statsroot) .ai-chart-chat { border: 1px solid var(--ai-border); border-radius: 9px; overflow: hidden; background: #fff; box-shadow: 0 3px 12px #28435b08; }
|
|
8
|
-
:where(#statsroot) .ai-chart-panel-heading { display: flex; align-items: center; justify-content: space-between; padding: 10px 15px; background: #f3f7fa; border-bottom: 1px solid var(--ai-border); }
|
|
9
|
-
:where(#statsroot) .ai-chart-panel-heading strong { display: flex; gap: 7px; align-items: center; }
|
|
10
|
-
:where(#statsroot) .ai-chart-panel-heading .btn { font-size: 12px; text-decoration: none; }
|
|
11
|
-
:where(#statsroot) .ai-chart-conversation { padding: 14px 15px; max-height: clamp(100px, calc(100vh - 680px), 260px); min-height: 100px; overflow: auto; overscroll-behavior: contain; scrollbar-gutter: stable; display: flex; flex-direction: column; gap: 10px; }
|
|
12
|
-
:where(#statsroot) .ai-chart-conversation:focus-visible, :where(#statsroot) .ai-chart-examples button:focus-visible { outline: 2px solid #337ab7; outline-offset: -2px; }
|
|
13
|
-
:where(#statsroot) .ai-chart-welcome { font-size: 16px; line-height: 1.4; font-weight: 600; margin: 0; }
|
|
14
|
-
:where(#statsroot) .ai-chart-muted { font-size: 12px; line-height: 1.5; color: #647787; margin: 0; }
|
|
15
|
-
:where(#statsroot) .ai-chart-examples { display: grid; gap: 7px; }
|
|
16
|
-
:where(#statsroot) .ai-chart-examples button { text-align: left; border: 1px solid #dce5ec; background: #fff; border-radius: 6px; padding: 8px 10px; color: #355774; line-height: 1.4; transition: background .15s, border-color .15s; }
|
|
17
|
-
:where(#statsroot) .ai-chart-examples button:hover { background: #f0f7fc; border-color: #83accd; }
|
|
18
|
-
:where(#statsroot) .ai-chart-examples strong { display: block; font-size: 12px; margin-bottom: 4px; }
|
|
19
|
-
:where(#statsroot) .ai-chart-examples span { display: block; color: #6b7b87; font-size: 12px; }
|
|
20
|
-
:where(#statsroot) .ai-chart-message { white-space: pre-wrap; overflow-wrap: anywhere; font-size: 13px; line-height: 1.55; border-radius: 8px; padding: 11px 12px; max-width: 95%; }
|
|
21
|
-
:where(#statsroot) .ai-chart-message-user { align-self: flex-end; background: #337ab7; color: #fff; border-bottom-right-radius: 2px; }
|
|
22
|
-
:where(#statsroot) .ai-chart-message-assistant { align-self: flex-start; background: #f0f4f7; border-bottom-left-radius: 2px; }
|
|
23
|
-
:where(#statsroot) .ai-chart-question { font-size: 13px; line-height: 1.5; }
|
|
24
|
-
:where(#statsroot) .ai-chart-question > div { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
|
|
25
|
-
:where(#statsroot) .ai-chart-question .btn { white-space: normal; text-align: left; font-size: 12px; }
|
|
26
|
-
:where(#statsroot) .ai-chart-wait { display: flex; align-items: center; gap: 9px; font-size: 13px; color: #47718f; padding: 10px 0; }
|
|
27
|
-
:where(#statsroot) .ai-chart-composer { padding: 12px 15px; background: #fafcfd; border-top: 1px solid #e1e9ef; }
|
|
28
|
-
:where(#statsroot) .ai-chart-composer label { font-size: 12px; font-weight: 600; }
|
|
29
|
-
:where(#statsroot) .ai-chart-composer textarea { font-size: 13px; line-height: 1.5; resize: vertical; min-height: 64px; }
|
|
30
|
-
:where(#statsroot) .ai-chart-composer-actions { display: flex; justify-content: space-between; align-items: center; gap: 10px; margin-top: 8px; }
|
|
31
|
-
:where(#statsroot) .ai-chart-composer-actions span { font-size: 11px; color: #748593; overflow-wrap: anywhere; }
|
|
32
|
-
:where(#statsroot) .ai-chart-workspace .btn { display: inline-flex; align-items: center; justify-content: center; gap: 6px; }
|
|
33
|
-
:where(#statsroot) .ai-chart-workspace .btn-primary { background: #337ab7; border-color: #337ab7; }
|
|
34
|
-
:where(#statsroot) .ai-chart-workspace .btn-primary:hover { background: #286294; border-color: #286294; }
|
|
35
|
-
:where(#statsroot) .ai-chart-review { background: #f1f8fd; border: 1px solid #bcd6e9; border-radius: 8px; padding: 16px 19px; margin-bottom: 16px; font-size: 13px; line-height: 1.5; }
|
|
36
|
-
:where(#statsroot) .ai-chart-review strong { color: #295c80; font-size: 15px; }
|
|
37
|
-
:where(#statsroot) .ai-chart-review p { margin: 5px 0 10px; }
|
|
38
|
-
:where(#statsroot) .ai-chart-review ul { margin: 7px 0 12px; padding-left: 20px; }
|
|
39
|
-
:where(#statsroot) .ai-chart-review-actions { display: flex; gap: 10px; margin-top: 13px; }
|
|
40
|
-
:where(#statsroot) .ai-chart-result { padding: 20px; background: #fff; border: 1px solid #dbe3e9; border-radius: 8px; }
|
|
41
|
-
:where(#statsroot) .ai-chart-result-heading { display: flex; justify-content: space-between; align-items: flex-start; gap: 14px; margin-bottom: 16px; }
|
|
42
|
-
:where(#statsroot) .ai-chart-result-heading h2 { font-size: 21px; font-weight: 600; line-height: 1.4; margin: 6px 0 0; color: #30485c; }
|
|
43
|
-
:where(#statsroot) .ai-chart-result-heading .btn { flex-shrink: 0; }
|
|
44
|
-
:where(#statsroot) .ai-chart-totals { display: flex; flex-wrap: wrap; gap: 8px 16px; font-size: 12px; color: #64798a; padding-bottom: 15px; }
|
|
45
|
-
:where(#statsroot) .ai-chart-totals strong { color: #355976; font-size: 14px; }
|
|
46
|
-
:where(#statsroot) .ai-chart-export-row { display: flex; flex-wrap: wrap; align-items: center; gap: 7px; border-top: 1px solid #edf0f3; padding-top: 14px; margin-top: 13px; }
|
|
47
|
-
:where(#statsroot) .ai-chart-export-row .btn { font-size: 11px; }
|
|
48
|
-
:where(#statsroot) .ai-chart-export-row > span { font-size: 11px; color: #7a8995; margin-left: auto; }
|
|
49
|
-
:where(#statsroot) .ai-chart-table { max-height: 490px; overflow: auto; font-size: 12px; }
|
|
50
|
-
:where(#statsroot) .ai-chart-table th, :where(#statsroot) .ai-chart-table td { padding: 8px; }
|
|
51
|
-
:where(#statsroot) .ai-chart-table thead { position: sticky; top: 0; background: #f4f8fb; }
|
|
52
|
-
:where(#statsroot) .ai-chart-provenance { font-size: 12px; line-height: 1.6; margin-top: 16px; color: #607383; }
|
|
53
|
-
:where(#statsroot) .ai-chart-provenance summary { cursor: pointer; color: #3b6f94; margin-bottom: 8px; }
|
|
54
|
-
:where(#statsroot) .ai-chart-provenance pre { font-size: 11px; max-height: 300px; overflow: auto; background: #f5f7f9; padding: 10px; }
|
|
55
|
-
:where(#statsroot) .ai-chart-provenance ul { padding-left: 19px; }
|
|
56
|
-
:where(#statsroot) .ai-chart-placeholder { min-height: 400px; border: 1px dashed #bccedb; border-radius: 9px; background: linear-gradient(150deg, #f7fbfe, #fff); display: flex; flex-direction: column; justify-content: center; align-items: center; padding: 30px; text-align: center; }
|
|
57
|
-
:where(#statsroot) .ai-chart-placeholder p { color: #758797; max-width: 400px; line-height: 1.7; font-size: 14px; }
|
|
58
|
-
:where(#statsroot) .ai-chart-previous { margin-top: 16px; font-size: 13px; color: #5b768d; }
|
|
59
|
-
:where(#statsroot) .ai-chart-previous summary { cursor: pointer; padding: 8px 0; }
|
|
60
|
-
:where(#statsroot) .ai-chart-empty { text-align: center; padding: 65px 25px; color: #718493; line-height: 1.6; }
|
|
61
|
-
:where(#statsroot) .ai-chart-home-card { display: flex; justify-content: space-between; align-items: center; gap: 20px; border: 1px solid #c9dce9; border-radius: 8px; padding: 22px 25px; background: linear-gradient(120deg,#eff7fd,#fff); margin: 16px 0 26px; color: #345871; text-decoration: none; }
|
|
62
|
-
:where(#statsroot) .ai-chart-home-card:hover { border-color: #83b0d0; color: #214b6c; background: #f1f8fd; }
|
|
63
|
-
:where(#statsroot) .ai-chart-home-card h2 { font-size: 21px; margin: 0 0 8px; }
|
|
64
|
-
:where(#statsroot) .ai-chart-home-card p { font-size: 14px; margin: 0; color: #6b7f8e; }
|
|
65
|
-
:where(#statsroot) .ai-chart-home-card > svg { font-size: 35px; flex-shrink: 0; color: #5790b7; }
|
|
66
|
-
@media (max-width: 1100px) { :where(#statsroot) .ai-chart-layout { grid-template-columns: minmax(280px, 330px) minmax(0,1fr); gap: 14px; } :where(#statsroot) .ai-chart-result { padding: 14px; } :where(#statsroot) .ai-chart-result-heading { flex-wrap: wrap; } }
|
|
67
|
-
@media (max-width: 800px) { :where(#statsroot) .ai-chart-layout { grid-template-columns: 1fr; } :where(#statsroot) .ai-chart-page-heading { flex-wrap: wrap; } :where(#statsroot) .ai-chart-placeholder { min-height: 300px; } :where(#statsroot) .ai-chart-result-heading h2 { font-size: 18px; } :where(#statsroot) .ai-chart-export-row > span { width: 100%; margin: 5px 0 0; } }
|
|
68
|
-
|
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
:where(#statsroot) .ai-chart-customize { border-top: 1px solid #e4ebf1; border-bottom: 1px solid #e4ebf1; padding: 11px 0; margin-bottom: 16px; font-size: 12px; color: #46647c; }
|
|
2
|
-
:where(#statsroot) .ai-chart-customize > summary { cursor: pointer; font-weight: 600; }
|
|
3
|
-
:where(#statsroot) .ai-chart-customize fieldset { border: 0; margin: 12px 0 0; padding: 0; }
|
|
4
|
-
:where(#statsroot) .ai-chart-style-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 10px 14px; }
|
|
5
|
-
:where(#statsroot) .ai-chart-style-grid label { display: flex; flex-direction: column; gap: 5px; font-size: 12px; color: #465e73; }
|
|
6
|
-
:where(#statsroot) .ai-chart-style-grid select, :where(#statsroot) .ai-chart-style-grid input { font-size: 12px; max-width: 100%; }
|
|
7
|
-
:where(#statsroot) .ai-chart-style-grid .ai-chart-grid-toggle { flex-direction: row; align-items: center; align-self: end; min-height: 31px; }
|
|
8
|
-
:where(#statsroot) .ai-chart-customize p { color: #74818c; line-height: 1.5; margin: 10px 0 0; }
|
|
9
|
-
:where(#statsroot) .ai-chart-zoom { display: flex; flex-wrap: wrap; align-items: center; gap: 7px; margin: 0 0 10px; }
|
|
10
|
-
:where(#statsroot) .ai-chart-zoom .btn { font-size: 11px; }
|
|
11
|
-
:where(#statsroot) .ai-chart-zoom small { color: #718393; font-size: 11px; line-height: 1.4; }
|
|
12
|
-
:where(#statsroot) .ai-chart-inspect { margin-top: 15px; padding-top: 12px; border-top: 1px solid #e6edf2; }
|
|
13
|
-
:where(#statsroot) .ai-chart-inspect > p { color: #6b7f8e; font-size: 12px; margin: 0 0 8px; }
|
|
14
|
-
:where(#statsroot) .ai-chart-inspect-controls { display: flex; flex-wrap: wrap; align-items: end; gap: 9px; }
|
|
15
|
-
:where(#statsroot) .ai-chart-inspect-controls label { display: flex; flex-direction: column; gap: 4px; flex: 1 1 150px; min-width: 0; font-size: 11px; color: #546f85; }
|
|
16
|
-
:where(#statsroot) .ai-chart-inspect-controls select { font-size: 12px; }
|
|
17
|
-
:where(#statsroot) .ai-chart-selection { background: #f2f7fb; border: 1px solid #d1e1ed; border-radius: 6px; margin-top: 11px; padding: 12px 14px; color: #3e5b73; font-size: 12px; line-height: 1.6; }
|
|
18
|
-
:where(#statsroot) .ai-chart-selection > strong { display: block; font-size: 14px; }
|
|
19
|
-
:where(#statsroot) .ai-chart-selection p { margin: 3px 0 8px; }
|
|
20
|
-
:where(#statsroot) .ai-chart-selection a { font-weight: 600; }
|
|
21
|
-
:where(#statsroot) .ai-chart-table .ai-chart-cell { border: 0; padding: 0; background: transparent; color: #326d98; text-decoration: underline; text-underline-offset: 2px; text-align: left; font: inherit; }
|
|
22
|
-
:where(#statsroot) .ai-chart-table .ai-chart-cell:focus-visible { outline: 2px solid #337ab7; outline-offset: 3px; }
|
|
23
|
-
:where(#statsroot) .ai-chart-export-scope { margin: -5px 0 16px; font-size: 11px; color: #718393; }
|
|
24
|
-
|
|
25
|
-
:where(#statsroot) .ai-chart-workspace { --ai-brand: #337ab7; --ai-border: #d5e2ed; color: #283747; padding: 0 4px 24px; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; }
|
|
26
|
-
:where(#statsroot) .ai-chart-page-heading { display: flex; justify-content: space-between; align-items: flex-start; gap: 18px; margin: 18px 0 18px; }
|
|
27
|
-
:where(#statsroot) .ai-chart-page-heading h1 { font-size: 29px; font-weight: 650; margin: 8px 0 9px; color: #253f56; }
|
|
28
|
-
:where(#statsroot) .ai-chart-page-heading p { color: #617080; max-width: 750px; margin-bottom: 0; line-height: 1.55; }
|
|
29
|
-
:where(#statsroot) .ai-chart-eyebrow { text-transform: uppercase; letter-spacing: .08em; color: #587b98; font-size: 11px; font-weight: 700; }
|
|
30
|
-
:where(#statsroot) .ai-chart-layout { display: grid; grid-template-columns: minmax(310px, 370px) minmax(0, 1fr); gap: 22px; align-items: start; }
|
|
31
|
-
:where(#statsroot) .ai-chart-chat { border: 1px solid var(--ai-border); border-radius: 9px; overflow: hidden; background: #fff; box-shadow: 0 3px 12px #28435b08; }
|
|
32
|
-
:where(#statsroot) .ai-chart-panel-heading { display: flex; align-items: center; justify-content: space-between; padding: 10px 15px; background: #f3f7fa; border-bottom: 1px solid var(--ai-border); }
|
|
33
|
-
:where(#statsroot) .ai-chart-panel-heading strong { display: flex; gap: 7px; align-items: center; }
|
|
34
|
-
:where(#statsroot) .ai-chart-panel-heading .btn { font-size: 12px; text-decoration: none; }
|
|
35
|
-
:where(#statsroot) .ai-chart-conversation { padding: 14px 15px; max-height: clamp(100px, calc(100vh - 680px), 260px); min-height: 100px; overflow: auto; overscroll-behavior: contain; scrollbar-gutter: stable; display: flex; flex-direction: column; gap: 10px; }
|
|
36
|
-
:where(#statsroot) .ai-chart-conversation:focus-visible, :where(#statsroot) .ai-chart-examples button:focus-visible { outline: 2px solid #337ab7; outline-offset: -2px; }
|
|
37
|
-
:where(#statsroot) .ai-chart-welcome { font-size: 16px; line-height: 1.4; font-weight: 600; margin: 0; }
|
|
38
|
-
:where(#statsroot) .ai-chart-muted { font-size: 12px; line-height: 1.5; color: #647787; margin: 0; }
|
|
39
|
-
:where(#statsroot) .ai-chart-examples { display: grid; gap: 7px; }
|
|
40
|
-
:where(#statsroot) .ai-chart-examples button { text-align: left; border: 1px solid #dce5ec; background: #fff; border-radius: 6px; padding: 8px 10px; color: #355774; line-height: 1.4; transition: background .15s, border-color .15s; }
|
|
41
|
-
:where(#statsroot) .ai-chart-examples button:hover { background: #f0f7fc; border-color: #83accd; }
|
|
42
|
-
:where(#statsroot) .ai-chart-examples strong { display: block; font-size: 12px; margin-bottom: 4px; }
|
|
43
|
-
:where(#statsroot) .ai-chart-examples span { display: block; color: #6b7b87; font-size: 12px; }
|
|
44
|
-
:where(#statsroot) .ai-chart-message { white-space: pre-wrap; overflow-wrap: anywhere; font-size: 13px; line-height: 1.55; border-radius: 8px; padding: 11px 12px; max-width: 95%; }
|
|
45
|
-
:where(#statsroot) .ai-chart-message-user { align-self: flex-end; background: #337ab7; color: #fff; border-bottom-right-radius: 2px; }
|
|
46
|
-
:where(#statsroot) .ai-chart-message-assistant { align-self: flex-start; background: #f0f4f7; border-bottom-left-radius: 2px; }
|
|
47
|
-
:where(#statsroot) .ai-chart-question { font-size: 13px; line-height: 1.5; }
|
|
48
|
-
:where(#statsroot) .ai-chart-question > div { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
|
|
49
|
-
:where(#statsroot) .ai-chart-question .btn { white-space: normal; text-align: left; font-size: 12px; }
|
|
50
|
-
:where(#statsroot) .ai-chart-wait { display: flex; align-items: center; gap: 9px; font-size: 13px; color: #47718f; padding: 10px 0; }
|
|
51
|
-
:where(#statsroot) .ai-chart-composer { padding: 12px 15px; background: #fafcfd; border-top: 1px solid #e1e9ef; }
|
|
52
|
-
:where(#statsroot) .ai-chart-composer label { font-size: 12px; font-weight: 600; }
|
|
53
|
-
:where(#statsroot) .ai-chart-composer textarea { font-size: 13px; line-height: 1.5; resize: vertical; min-height: 64px; }
|
|
54
|
-
:where(#statsroot) .ai-chart-composer-actions { display: flex; justify-content: space-between; align-items: center; gap: 10px; margin-top: 8px; }
|
|
55
|
-
:where(#statsroot) .ai-chart-composer-actions span { font-size: 11px; color: #748593; overflow-wrap: anywhere; }
|
|
56
|
-
:where(#statsroot) .ai-chart-workspace .btn { display: inline-flex; align-items: center; justify-content: center; gap: 6px; }
|
|
57
|
-
:where(#statsroot) .ai-chart-workspace .btn-primary { background: #337ab7; border-color: #337ab7; }
|
|
58
|
-
:where(#statsroot) .ai-chart-workspace .btn-primary:hover { background: #286294; border-color: #286294; }
|
|
59
|
-
:where(#statsroot) .ai-chart-review { background: #f1f8fd; border: 1px solid #bcd6e9; border-radius: 8px; padding: 16px 19px; margin-bottom: 16px; font-size: 13px; line-height: 1.5; }
|
|
60
|
-
:where(#statsroot) .ai-chart-review strong { color: #295c80; font-size: 15px; }
|
|
61
|
-
:where(#statsroot) .ai-chart-review p { margin: 5px 0 10px; }
|
|
62
|
-
:where(#statsroot) .ai-chart-review ul { margin: 7px 0 12px; padding-left: 20px; }
|
|
63
|
-
:where(#statsroot) .ai-chart-review-actions { display: flex; gap: 10px; margin-top: 13px; }
|
|
64
|
-
:where(#statsroot) .ai-chart-result { padding: 20px; background: #fff; border: 1px solid #dbe3e9; border-radius: 8px; }
|
|
65
|
-
:where(#statsroot) .ai-chart-result-heading { display: flex; justify-content: space-between; align-items: flex-start; gap: 14px; margin-bottom: 16px; }
|
|
66
|
-
:where(#statsroot) .ai-chart-result-heading h2 { font-size: 21px; font-weight: 600; line-height: 1.4; margin: 6px 0 0; color: #30485c; }
|
|
67
|
-
:where(#statsroot) .ai-chart-result-heading .btn { flex-shrink: 0; }
|
|
68
|
-
:where(#statsroot) .ai-chart-totals { display: flex; flex-wrap: wrap; gap: 8px 16px; font-size: 12px; color: #64798a; padding-bottom: 15px; }
|
|
69
|
-
:where(#statsroot) .ai-chart-totals strong { color: #355976; font-size: 14px; }
|
|
70
|
-
:where(#statsroot) .ai-chart-export-row { display: flex; flex-wrap: wrap; align-items: center; gap: 7px; border-top: 1px solid #edf0f3; padding-top: 14px; margin-top: 13px; }
|
|
71
|
-
:where(#statsroot) .ai-chart-export-row .btn { font-size: 11px; }
|
|
72
|
-
:where(#statsroot) .ai-chart-export-row > span { font-size: 11px; color: #7a8995; margin-left: auto; }
|
|
73
|
-
:where(#statsroot) .ai-chart-table { max-height: 490px; overflow: auto; font-size: 12px; }
|
|
74
|
-
:where(#statsroot) .ai-chart-table th, :where(#statsroot) .ai-chart-table td { padding: 8px; }
|
|
75
|
-
:where(#statsroot) .ai-chart-table thead { position: sticky; top: 0; background: #f4f8fb; }
|
|
76
|
-
:where(#statsroot) .ai-chart-provenance { font-size: 12px; line-height: 1.6; margin-top: 16px; color: #607383; }
|
|
77
|
-
:where(#statsroot) .ai-chart-provenance summary { cursor: pointer; color: #3b6f94; margin-bottom: 8px; }
|
|
78
|
-
:where(#statsroot) .ai-chart-provenance pre { font-size: 11px; max-height: 300px; overflow: auto; background: #f5f7f9; padding: 10px; }
|
|
79
|
-
:where(#statsroot) .ai-chart-provenance ul { padding-left: 19px; }
|
|
80
|
-
:where(#statsroot) .ai-chart-placeholder { min-height: 400px; border: 1px dashed #bccedb; border-radius: 9px; background: linear-gradient(150deg, #f7fbfe, #fff); display: flex; flex-direction: column; justify-content: center; align-items: center; padding: 30px; text-align: center; }
|
|
81
|
-
:where(#statsroot) .ai-chart-placeholder p { color: #758797; max-width: 400px; line-height: 1.7; font-size: 14px; }
|
|
82
|
-
:where(#statsroot) .ai-chart-previous { margin-top: 16px; font-size: 13px; color: #5b768d; }
|
|
83
|
-
:where(#statsroot) .ai-chart-previous summary { cursor: pointer; padding: 8px 0; }
|
|
84
|
-
:where(#statsroot) .ai-chart-empty { text-align: center; padding: 65px 25px; color: #718493; line-height: 1.6; }
|
|
85
|
-
:where(#statsroot) .ai-chart-home-card { display: flex; justify-content: space-between; align-items: center; gap: 20px; border: 1px solid #c9dce9; border-radius: 8px; padding: 22px 25px; background: linear-gradient(120deg,#eff7fd,#fff); margin: 16px 0 26px; color: #345871; text-decoration: none; }
|
|
86
|
-
:where(#statsroot) .ai-chart-home-card:hover { border-color: #83b0d0; color: #214b6c; background: #f1f8fd; }
|
|
87
|
-
:where(#statsroot) .ai-chart-home-card h2 { font-size: 21px; margin: 0 0 8px; }
|
|
88
|
-
:where(#statsroot) .ai-chart-home-card p { font-size: 14px; margin: 0; color: #6b7f8e; }
|
|
89
|
-
:where(#statsroot) .ai-chart-home-card > svg { font-size: 35px; flex-shrink: 0; color: #5790b7; }
|
|
90
|
-
@media (max-width: 1100px) { :where(#statsroot) .ai-chart-layout { grid-template-columns: minmax(280px, 330px) minmax(0,1fr); gap: 14px; } :where(#statsroot) .ai-chart-result { padding: 14px; } :where(#statsroot) .ai-chart-result-heading { flex-wrap: wrap; } }
|
|
91
|
-
@media (max-width: 800px) { :where(#statsroot) .ai-chart-layout { grid-template-columns: 1fr; } :where(#statsroot) .ai-chart-page-heading { flex-wrap: wrap; } :where(#statsroot) .ai-chart-placeholder { min-height: 300px; } :where(#statsroot) .ai-chart-result-heading h2 { font-size: 18px; } :where(#statsroot) .ai-chart-export-row > span { width: 100%; margin: 5px 0 0; } }
|
|
92
|
-
|