@rcsb/rcsb-statistics 0.3.42 → 0.3.44-dev.aipcb.0
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 +12 -0
- package/build/ai/chart-catalog.json +61 -0
- package/build/ai/chart-core.d.ts +39 -0
- package/build/ai/chart-core.js +1 -0
- package/build/index.html +1 -1
- package/build/static/css/221.70921a0b.chunk.css +73 -0
- package/build/static/css/81.70921a0b.chunk.css +73 -0
- package/build/static/css/main.894a09f3.css +10 -0
- package/build/static/js/221.6ab15159.chunk.js +1 -0
- package/build/static/js/233.044321e4.chunk.js +2 -0
- package/build/static/js/233.044321e4.chunk.js.LICENSE.txt +13 -0
- package/build/static/js/417.a91bf47f.chunk.js +1 -0
- package/build/static/js/463.93a9a793.chunk.js +1 -0
- package/build/static/js/503.aa3a1e3b.chunk.js +1 -0
- package/build/static/js/646.d06a86d8.chunk.js +1 -0
- package/build/static/js/669.4bc24392.chunk.js +2 -0
- package/build/static/js/{152.d0d96551.chunk.js.LICENSE.txt → 669.4bc24392.chunk.js.LICENSE.txt} +0 -14
- package/build/static/js/690.c5f42ab2.chunk.js +1 -0
- package/build/static/js/732.59dd3430.chunk.js +1 -0
- package/build/static/js/81.3f4b69e8.chunk.js +1 -0
- package/build/static/js/main.760776f1.js +2 -0
- package/package.json +2 -1
- package/build/static/css/main.a8ce960b.css +0 -8
- package/build/static/js/10.d9d49a66.chunk.js +0 -1
- package/build/static/js/109.2ff3158c.chunk.js +0 -1
- package/build/static/js/152.d0d96551.chunk.js +0 -2
- package/build/static/js/317.d5ab18f4.chunk.js +0 -1
- package/build/static/js/47.96ede111.chunk.js +0 -1
- package/build/static/js/613.8638dc20.chunk.js +0 -1
- package/build/static/js/630.bc43e10d.chunk.js +0 -1
- package/build/static/js/main.94502a31.js +0 -2
- /package/build/static/js/{main.94502a31.js.LICENSE.txt → main.760776f1.js.LICENSE.txt} +0 -0
package/README.md
CHANGED
|
@@ -32,6 +32,18 @@ These statistics are generated using Web Services and represent the current hold
|
|
|
32
32
|
|
|
33
33
|
This module is intended to be used within the RCSB Sierra web application. To get a local copy up and running, follow these steps.
|
|
34
34
|
|
|
35
|
+
### AI Powered Chart Builder
|
|
36
|
+
|
|
37
|
+
The standalone chart workspace is available at `/ai-powered-chart-builder` beneath the configured statistics basename. It supports conversation, clarification, iterative refinement, live preview, explicit Apply/Discard, and chart/table/CSV/JSON/PNG views.
|
|
38
|
+
|
|
39
|
+
Sierra supplies `window.__RCSB_AI_COMMANDS__` (or `sierraConfig.aiCommands`) with `execute(request, { signal })`, asynchronous `getStatus()`, and `settingsUrl`. Requests use action `configureChart`, conversation `messages`, validated `context.currentChart` / `context.pendingChart`, and `previousCommand`. Provider credentials are owned by Sierra; this package neither stores credentials nor calls model providers.
|
|
40
|
+
|
|
41
|
+
The package includes `build/ai/chart-catalog.json` and `build/ai/chart-core.js`. The server and browser share the same schema, validation, Search API request construction, and data formatting. A ready response includes `command: { action: 'configureChart', spec }` plus `preview.chartData`, populated by the server from real Search API aggregations. The browser rejects incomplete or inconsistent preview data.
|
|
42
|
+
|
|
43
|
+
Supported dimensions are release year, experimental method, source organism, resolution, polymer type, integrative input data, and determination methodology. All measures count released PDB entries, not chains or unique sequences. Up to four named cohorts can add entry-level filters. Overlap, missing-value denominators, current-year coverage, category limits, and cumulative-window semantics are disclosed; unsupported statistics require clarification.
|
|
44
|
+
|
|
45
|
+
Run `npm test`, `npx tsc --noEmit`, and `npm run build` before packaging. The tests use mocked model/service responses; they do not spend provider credits.
|
|
46
|
+
|
|
35
47
|
### Prerequisites
|
|
36
48
|
|
|
37
49
|
You’ll need [Node.js](https://nodejs.org/) and npm:
|
|
@@ -0,0 +1,61 @@
|
|
|
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
|
+
"Comparisons use up to four explicit named cohorts with independent additional filters; cohorts may overlap. Never fabricate counts or arbitrary Search API attributes.",
|
|
15
|
+
"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."
|
|
16
|
+
],
|
|
17
|
+
"dimensions": {
|
|
18
|
+
"releaseYear": {"label": "Release year", "attribute": "rcsb_accession_info.initial_release_date", "aggregation": "date_histogram", "interval": "year", "ordered": true, "overlapping": false},
|
|
19
|
+
"method": {"label": "Experimental method", "attribute": "exptl.method", "aggregation": "terms", "ordered": false, "overlapping": true},
|
|
20
|
+
"sourceOrganism": {"label": "Source organism", "attribute": "rcsb_entity_source_organism.ncbi_scientific_name", "aggregation": "terms", "ordered": false, "overlapping": true},
|
|
21
|
+
"resolution": {"label": "Resolution (Å)", "attribute": "rcsb_entry_info.resolution_combined", "aggregation": "histogram", "ordered": true, "overlapping": true},
|
|
22
|
+
"polymerType": {"label": "Polymer type", "attribute": "entity_poly.rcsb_entity_polymer_type", "aggregation": "terms", "ordered": false, "overlapping": true},
|
|
23
|
+
"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"]}},
|
|
24
|
+
"methodology": {"label": "Structure determination methodology", "attribute": "rcsb_entry_info.structure_determination_methodology", "aggregation": "terms", "ordered": false, "overlapping": false}
|
|
25
|
+
},
|
|
26
|
+
"filters": {
|
|
27
|
+
"releaseYear": {"label": "Release year", "attribute": "rcsb_accession_info.initial_release_date", "kind": "year", "operators": ["gte", "lte"], "minimum": 1971, "maximum": 2100},
|
|
28
|
+
"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"]},
|
|
29
|
+
"resolution": {"label": "Resolution (Å)", "attribute": "rcsb_entry_info.resolution_combined", "kind": "number", "operators": ["gte", "lte"], "minimum": 0.01, "maximum": 1000},
|
|
30
|
+
"sourceTaxonomy": {"label": "Source organism NCBI taxonomy ID (including descendants)", "attribute": "rcsb_entity_source_organism.taxonomy_lineage.id", "kind": "taxonomy", "operators": ["in"]},
|
|
31
|
+
"sourceOrganism": {"label": "Exact source organism scientific name", "attribute": "rcsb_entity_source_organism.ncbi_scientific_name", "kind": "text", "operators": ["in"]},
|
|
32
|
+
"ligand": {"label": "Non-polymer chemical component ID present in entry", "attribute": "rcsb_nonpolymer_entity.rcsb_nonpolymer_comp_id", "kind": "identifier", "operators": ["in"]},
|
|
33
|
+
"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"]},
|
|
34
|
+
"methodology": {"label": "Structure determination methodology", "attribute": "rcsb_entry_info.structure_determination_methodology", "kind": "enum", "operators": ["in"], "values": ["experimental", "integrative"]}
|
|
35
|
+
},
|
|
36
|
+
"knownTaxa": {"human": 9606, "mouse": 10090, "Escherichia coli": 562, "Saccharomyces cerevisiae": 4932},
|
|
37
|
+
"specSchema": {
|
|
38
|
+
"type": "object", "additionalProperties": false,
|
|
39
|
+
"required": ["version", "title", "categoryLabel", "valueLabel", "dimension", "chartType", "measure", "scale", "orientation", "sort", "topN", "interval", "cumulative", "filters", "series"],
|
|
40
|
+
"properties": {
|
|
41
|
+
"version": {"type": "integer", "enum": [1]},
|
|
42
|
+
"title": {"type": "string", "minLength": 1, "maxLength": 140},
|
|
43
|
+
"categoryLabel": {"type": "string", "minLength": 1, "maxLength": 100},
|
|
44
|
+
"valueLabel": {"type": "string", "minLength": 1, "maxLength": 100},
|
|
45
|
+
"dimension": {"type": "string", "enum": ["releaseYear", "method", "sourceOrganism", "resolution", "polymerType", "integrativeInput", "methodology"]},
|
|
46
|
+
"chartType": {"type": "string", "enum": ["bar", "line", "pie"]},
|
|
47
|
+
"measure": {"type": "string", "enum": ["count", "percent"]},
|
|
48
|
+
"scale": {"type": "string", "enum": ["linear", "logarithmic"]},
|
|
49
|
+
"orientation": {"type": "string", "enum": ["vertical", "horizontal"]},
|
|
50
|
+
"sort": {"type": "string", "enum": ["labelAsc", "countDesc"]},
|
|
51
|
+
"topN": {"type": "integer", "minimum": 1, "maximum": 60},
|
|
52
|
+
"interval": {"type": "number", "minimum": 0.1, "maximum": 100},
|
|
53
|
+
"cumulative": {"type": "boolean"},
|
|
54
|
+
"filters": {"type": "array", "maxItems": 12, "items": {"$ref": "#/$defs/filter"}},
|
|
55
|
+
"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"}}}}}
|
|
56
|
+
},
|
|
57
|
+
"$defs": {
|
|
58
|
+
"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}]}}]}}}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
export interface ChartFilter { field: string; operator: 'in' | 'gte' | 'lte'; value: number | Array<string | number>; }
|
|
2
|
+
export interface ChartSpec {
|
|
3
|
+
version: 1;
|
|
4
|
+
title: string;
|
|
5
|
+
categoryLabel: string;
|
|
6
|
+
valueLabel: string;
|
|
7
|
+
dimension: 'releaseYear' | 'method' | 'sourceOrganism' | 'resolution' | 'polymerType' | 'integrativeInput' | 'methodology';
|
|
8
|
+
chartType: 'bar' | 'line' | 'pie';
|
|
9
|
+
measure: 'count' | 'percent';
|
|
10
|
+
scale: 'linear' | 'logarithmic';
|
|
11
|
+
orientation: 'vertical' | 'horizontal';
|
|
12
|
+
sort: 'labelAsc' | 'countDesc';
|
|
13
|
+
topN: number;
|
|
14
|
+
interval: number;
|
|
15
|
+
cumulative: boolean;
|
|
16
|
+
filters: ChartFilter[];
|
|
17
|
+
series: Array<{ label: string; filters: ChartFilter[] }>;
|
|
18
|
+
}
|
|
19
|
+
export interface ChartDataResult {
|
|
20
|
+
rows: Array<{ label: string; counts: number[]; values: number[] }>;
|
|
21
|
+
series: Array<{ label: string; total: number }>;
|
|
22
|
+
warnings: string[];
|
|
23
|
+
retrievedAt: string;
|
|
24
|
+
categoryCount: number;
|
|
25
|
+
}
|
|
26
|
+
export const catalog: {
|
|
27
|
+
version: number;
|
|
28
|
+
dimensions: Record<string, { label: string; attribute: string; aggregation: string; ordered: boolean; overlapping: boolean }>;
|
|
29
|
+
filters: Record<string, { label: string; attribute: string }>;
|
|
30
|
+
specSchema: Record<string, unknown>;
|
|
31
|
+
countingRules: string[];
|
|
32
|
+
};
|
|
33
|
+
export function validateChartSpec(input: unknown): ChartSpec;
|
|
34
|
+
export function buildChartRequests(input: ChartSpec): Array<Record<string, unknown>>;
|
|
35
|
+
export function describeFilter(input: ChartFilter): string;
|
|
36
|
+
export function describeChart(input: ChartSpec): string;
|
|
37
|
+
export function chartWarnings(input: ChartSpec): string[];
|
|
38
|
+
export function chartChanges(previous: ChartSpec | null, input: ChartSpec): string[];
|
|
39
|
+
export function formatChartData(input: ChartSpec, responses: unknown[]): ChartDataResult;
|
|
@@ -0,0 +1 @@
|
|
|
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"!==t.chartType||r.ordered&&"vertical"===t.orientation&&"labelAsc"===t.sort||fail("Line charts require release year or resolution, vertical orientation, and ascending labels."),"pie"===t.chartType&&(r.overlapping||1!==t.series.length||t.cumulative||"linear"!==t.scale)&&fail("Pie 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 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"}`),{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),s=i.filter(e=>"lte"===e.operator).map(e=>e.value);if(!n.length||!s.length)return[terminal({...r,operator:n.length?"gte":"lte",value:n.length?Math.max(...n):Math.min(...s)})];const l=Math.max(...n),o=Math.min(...s);return[{type:"terminal",service:"text",parameters:{attribute:a.attribute,operator:"range",value:{from:"year"===a.kind?`${l}-01-01`:l,to:"year"===a.kind?`${o}-12-31`:o,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 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."),"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),Object.keys(t).filter(r=>JSON.stringify(e[r])!==JSON.stringify(t[r])).map(r=>"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 s=[...new Set(n.flatMap(e=>[...e.values.keys()]))];const l=s.every(e=>Number.isFinite(Number(e)));if(s.sort((e,t)=>l?Number(e)-Number(t):e.localeCompare(t)),"releaseYear"===r.dimension&&s.length){const e=Number(s[0]),t=Number(s[s.length-1]);t-e>200&&fail("The Search API returned an unsupported year range."),s=Array.from({length:t-e+1},(t,r)=>String(e+r))}if("resolution"===r.dimension&&s.length){const e=Number(s[0]),t=Math.round((Number(s[s.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."),s=Array.from({length:t},(t,a)=>String(Number((e+a*r.interval).toPrecision(12))))}const o=s.map(e=>({label:e,counts:n.map(t=>t.values.get(e)||0)}));if(r.cumulative){const e=n.map(()=>0);o.forEach(t=>{t.counts=t.counts.map((t,r)=>e[r]+=t)})}"countDesc"===r.sort&&o.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?o.slice(0,r.topN):o).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&&o.length>c.length&&h.push(`Showing ${c.length} of ${o.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"!==r.chartType||!i&&c.length===o.length||fail("A pie chart must show all categories. Increase the category limit or use a bar chart."),"pie"===r.chartType&&c.reduce((e,t)=>e+t.counts[0],0)!==n[0].total&&fail("A pie 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:o.length}}module.exports={catalog,validateSchema,validateChartSpec,buildChartRequests,describeFilter,describeChart,chartWarnings,chartChanges,formatChartData};
|
package/build/index.html
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
<!doctype html><html lang="en"><head><meta charset="utf-8"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="RCSB Protein Data Bank: A Resource for Studying Biological Macromolecules"/><title>RCSB Statistics</title><script defer="defer" src="/static/js/main.
|
|
1
|
+
<!doctype html><html lang="en"><head><meta charset="utf-8"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="RCSB Protein Data Bank: A Resource for Studying Biological Macromolecules"/><title>RCSB Statistics</title><script defer="defer" src="/static/js/main.760776f1.js"></script><link href="/static/css/main.894a09f3.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript sto run this app.</noscript><div id="statsroot"></div></body></html>
|
|
@@ -0,0 +1,73 @@
|
|
|
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: 26px 0 22px; }
|
|
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-eyebrow svg { font-size: 17px; margin-right: 4px; }
|
|
7
|
+
:where(#statsroot) .ai-chart-layout { display: grid; grid-template-columns: minmax(310px, 370px) minmax(0, 1fr); gap: 22px; align-items: start; }
|
|
8
|
+
:where(#statsroot) .ai-chart-chat { border: 1px solid var(--ai-border); border-radius: 9px; overflow: hidden; background: #fff; box-shadow: 0 3px 12px #28435b08; }
|
|
9
|
+
:where(#statsroot) .ai-chart-panel-heading { display: flex; align-items: center; justify-content: space-between; padding: 13px 15px; background: #f3f7fa; border-bottom: 1px solid var(--ai-border); }
|
|
10
|
+
:where(#statsroot) .ai-chart-panel-heading strong { display: flex; gap: 7px; align-items: center; }
|
|
11
|
+
:where(#statsroot) .ai-chart-panel-heading .btn { font-size: 12px; text-decoration: none; }
|
|
12
|
+
:where(#statsroot) .ai-chart-conversation { padding: 18px 15px; max-height: 520px; min-height: 250px; overflow: auto; display: flex; flex-direction: column; gap: 13px; }
|
|
13
|
+
:where(#statsroot) .ai-chart-welcome { font-size: 18px; line-height: 1.4; font-weight: 600; margin: 0; }
|
|
14
|
+
:where(#statsroot) .ai-chart-muted { font-size: 13px; line-height: 1.6; color: #647787; margin: 0; }
|
|
15
|
+
:where(#statsroot) .ai-chart-examples { display: grid; gap: 9px; }
|
|
16
|
+
:where(#statsroot) .ai-chart-examples button { text-align: left; border: 1px solid #dce5ec; background: #fff; border-radius: 6px; padding: 11px 12px; color: #355774; line-height: 1.5; 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: 14px 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: 86px; }
|
|
30
|
+
:where(#statsroot) .ai-chart-composer-actions { display: flex; justify-content: space-between; align-items: center; gap: 10px; margin-top: 12px; }
|
|
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: 540px; 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: 45px; text-align: center; }
|
|
57
|
+
:where(#statsroot) .ai-chart-placeholder > svg { color: #78a4c4; font-size: 42px; margin-bottom: 20px; }
|
|
58
|
+
:where(#statsroot) .ai-chart-placeholder h2 { color: #45627a; font-size: 25px; font-weight: 500; }
|
|
59
|
+
:where(#statsroot) .ai-chart-placeholder p { color: #758797; max-width: 400px; line-height: 1.7; font-size: 14px; }
|
|
60
|
+
:where(#statsroot) .ai-chart-placeholder > div { display: flex; flex-wrap: wrap; justify-content: center; gap: 8px; margin-top: 10px; }
|
|
61
|
+
:where(#statsroot) .ai-chart-placeholder span { border: 1px solid #d7e3eb; border-radius: 20px; padding: 6px 11px; color: #71889b; font-size: 11px; background: #fff; }
|
|
62
|
+
:where(#statsroot) .ai-chart-previous { margin-top: 16px; font-size: 13px; color: #5b768d; }
|
|
63
|
+
:where(#statsroot) .ai-chart-previous summary { cursor: pointer; padding: 8px 0; }
|
|
64
|
+
:where(#statsroot) .ai-chart-empty { text-align: center; padding: 65px 25px; color: #718493; line-height: 1.6; }
|
|
65
|
+
:where(#statsroot) .ai-chart-footnote { font-size: 12px; color: #798994; margin: 20px 0 0; line-height: 1.7; }
|
|
66
|
+
: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; }
|
|
67
|
+
:where(#statsroot) .ai-chart-home-card:hover { border-color: #83b0d0; color: #214b6c; background: #f1f8fd; }
|
|
68
|
+
:where(#statsroot) .ai-chart-home-card h2 { font-size: 21px; margin: 0 0 8px; }
|
|
69
|
+
:where(#statsroot) .ai-chart-home-card p { font-size: 14px; margin: 0; color: #6b7f8e; }
|
|
70
|
+
:where(#statsroot) .ai-chart-home-card > svg { font-size: 35px; flex-shrink: 0; color: #5790b7; }
|
|
71
|
+
@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; } }
|
|
72
|
+
@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-conversation { max-height: 330px; } :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; } }
|
|
73
|
+
|
|
@@ -0,0 +1,73 @@
|
|
|
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: 26px 0 22px; }
|
|
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-eyebrow svg { font-size: 17px; margin-right: 4px; }
|
|
7
|
+
:where(#statsroot) .ai-chart-layout { display: grid; grid-template-columns: minmax(310px, 370px) minmax(0, 1fr); gap: 22px; align-items: start; }
|
|
8
|
+
:where(#statsroot) .ai-chart-chat { border: 1px solid var(--ai-border); border-radius: 9px; overflow: hidden; background: #fff; box-shadow: 0 3px 12px #28435b08; }
|
|
9
|
+
:where(#statsroot) .ai-chart-panel-heading { display: flex; align-items: center; justify-content: space-between; padding: 13px 15px; background: #f3f7fa; border-bottom: 1px solid var(--ai-border); }
|
|
10
|
+
:where(#statsroot) .ai-chart-panel-heading strong { display: flex; gap: 7px; align-items: center; }
|
|
11
|
+
:where(#statsroot) .ai-chart-panel-heading .btn { font-size: 12px; text-decoration: none; }
|
|
12
|
+
:where(#statsroot) .ai-chart-conversation { padding: 18px 15px; max-height: 520px; min-height: 250px; overflow: auto; display: flex; flex-direction: column; gap: 13px; }
|
|
13
|
+
:where(#statsroot) .ai-chart-welcome { font-size: 18px; line-height: 1.4; font-weight: 600; margin: 0; }
|
|
14
|
+
:where(#statsroot) .ai-chart-muted { font-size: 13px; line-height: 1.6; color: #647787; margin: 0; }
|
|
15
|
+
:where(#statsroot) .ai-chart-examples { display: grid; gap: 9px; }
|
|
16
|
+
:where(#statsroot) .ai-chart-examples button { text-align: left; border: 1px solid #dce5ec; background: #fff; border-radius: 6px; padding: 11px 12px; color: #355774; line-height: 1.5; 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: 14px 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: 86px; }
|
|
30
|
+
:where(#statsroot) .ai-chart-composer-actions { display: flex; justify-content: space-between; align-items: center; gap: 10px; margin-top: 12px; }
|
|
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: 540px; 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: 45px; text-align: center; }
|
|
57
|
+
:where(#statsroot) .ai-chart-placeholder > svg { color: #78a4c4; font-size: 42px; margin-bottom: 20px; }
|
|
58
|
+
:where(#statsroot) .ai-chart-placeholder h2 { color: #45627a; font-size: 25px; font-weight: 500; }
|
|
59
|
+
:where(#statsroot) .ai-chart-placeholder p { color: #758797; max-width: 400px; line-height: 1.7; font-size: 14px; }
|
|
60
|
+
:where(#statsroot) .ai-chart-placeholder > div { display: flex; flex-wrap: wrap; justify-content: center; gap: 8px; margin-top: 10px; }
|
|
61
|
+
:where(#statsroot) .ai-chart-placeholder span { border: 1px solid #d7e3eb; border-radius: 20px; padding: 6px 11px; color: #71889b; font-size: 11px; background: #fff; }
|
|
62
|
+
:where(#statsroot) .ai-chart-previous { margin-top: 16px; font-size: 13px; color: #5b768d; }
|
|
63
|
+
:where(#statsroot) .ai-chart-previous summary { cursor: pointer; padding: 8px 0; }
|
|
64
|
+
:where(#statsroot) .ai-chart-empty { text-align: center; padding: 65px 25px; color: #718493; line-height: 1.6; }
|
|
65
|
+
:where(#statsroot) .ai-chart-footnote { font-size: 12px; color: #798994; margin: 20px 0 0; line-height: 1.7; }
|
|
66
|
+
: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; }
|
|
67
|
+
:where(#statsroot) .ai-chart-home-card:hover { border-color: #83b0d0; color: #214b6c; background: #f1f8fd; }
|
|
68
|
+
:where(#statsroot) .ai-chart-home-card h2 { font-size: 21px; margin: 0 0 8px; }
|
|
69
|
+
:where(#statsroot) .ai-chart-home-card p { font-size: 14px; margin: 0; color: #6b7f8e; }
|
|
70
|
+
:where(#statsroot) .ai-chart-home-card > svg { font-size: 35px; flex-shrink: 0; color: #5790b7; }
|
|
71
|
+
@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; } }
|
|
72
|
+
@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-conversation { max-height: 330px; } :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; } }
|
|
73
|
+
|