From 6b00e4d6658834b71892c35abb6df6e5e56d05ce Mon Sep 17 00:00:00 2001 From: Jordan Wages Date: Sat, 21 Jun 2025 18:52:00 -0500 Subject: [PATCH 001/148] docs: update README and add changelog --- CHANGELOG.md | 14 ++++++++++++++ README.md | 6 +++++- 2 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..b33c8aa --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,14 @@ +# Changelog + +## 1.2 - 2025-06-21 + +### Added +- Custom logging framework with colorized output. Debug mode can be toggled from the Options page. +- Advanced AI parameters (max tokens, temperature, etc.) are configurable in the Options page. +- Hash-based persistent caching to reuse classification results across Thunderbird restarts. +- Multiple icon sizes for better integration. +- Custom system prompt field for specifying additional instructions for the AI service. + +### Fixed +- Improved logger import to avoid security errors. +- Logging now reports only updated cache entries. diff --git a/README.md b/README.md index daee88a..9e9fd34 100644 --- a/README.md +++ b/README.md @@ -13,9 +13,12 @@ message meets a specified criterion. `matches` and `doesn't match` operators. - **Configurable endpoint** – set the classification service URL on the options page. - **Prompt templates** – choose between several model formats or provide your own custom template. +- **Custom system prompts** – tailor the instructions sent to the model for more precise results. - **Filter editor integration** – patches Thunderbird's filter editor to accept text criteria for AI classification. -- **Result caching** – avoids duplicate requests for already-evaluated messages. +- **Persistent result caching** – classification results are saved to disk so messages aren't re-evaluated across restarts. +- **Advanced parameters** – tune generation settings like temperature, top‑p and more from the options page. +- **Debug logging** – optional colorized logs help troubleshoot interactions with the AI service. - **Packaging script** – `build-xpi.ps1` builds an XPI ready for installation. ## Architecture Overview @@ -43,6 +46,7 @@ APIs: | `experiment/api.js` | Bridges WebExtension code with privileged APIs.| | `content/filterEditor.js` | Patches the filter editor interface. | | `options/options.html` and `options.js` | Endpoint configuration UI. | +| `logger.js` and `modules/logger.jsm` | Colorized logging with optional debug mode. | ## Building From e0795ed394ef7f36936ef5d881f83b3f7651c1e2 Mon Sep 17 00:00:00 2001 From: Jordan Wages Date: Sat, 21 Jun 2025 18:54:01 -0500 Subject: [PATCH 002/148] Delete CHANGELOG.md --- CHANGELOG.md | 14 -------------- 1 file changed, 14 deletions(-) delete mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index b33c8aa..0000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,14 +0,0 @@ -# Changelog - -## 1.2 - 2025-06-21 - -### Added -- Custom logging framework with colorized output. Debug mode can be toggled from the Options page. -- Advanced AI parameters (max tokens, temperature, etc.) are configurable in the Options page. -- Hash-based persistent caching to reuse classification results across Thunderbird restarts. -- Multiple icon sizes for better integration. -- Custom system prompt field for specifying additional instructions for the AI service. - -### Fixed -- Improved logger import to avoid security errors. -- Logging now reports only updated cache entries. From 1d1d30d80f85f2b2300d3da6eec02c67214623bc Mon Sep 17 00:00:00 2001 From: Jordan Wages Date: Sat, 21 Jun 2025 22:27:40 -0500 Subject: [PATCH 003/148] Manifest Housekeeping --- ai-filter.sln | 8 ++++++++ manifest.json | 26 ++++++++++++++++---------- resources/img/logo128.png | Bin 0 -> 8433 bytes resources/img/logo16.png | Bin 0 -> 717 bytes resources/img/logo32.png | Bin 0 -> 1707 bytes resources/img/logo48.png | Bin 0 -> 2920 bytes resources/img/logo64.png | Bin 0 -> 4138 bytes resources/img/logo96.png | Bin 0 -> 6527 bytes 8 files changed, 24 insertions(+), 10 deletions(-) create mode 100644 resources/img/logo128.png create mode 100644 resources/img/logo16.png create mode 100644 resources/img/logo32.png create mode 100644 resources/img/logo48.png create mode 100644 resources/img/logo64.png create mode 100644 resources/img/logo96.png diff --git a/ai-filter.sln b/ai-filter.sln index 243c1c1..f5fa952 100644 --- a/ai-filter.sln +++ b/ai-filter.sln @@ -7,6 +7,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution ProjectSection(SolutionItems) = preProject background.js = background.js build-xpi.ps1 = build-xpi.ps1 + logger.js = logger.js manifest.json = manifest.json EndProjectSection ProjectSection(FolderGlobals) = preProject @@ -28,6 +29,7 @@ EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "modules", "modules", "{75ED3C1E-D3C7-4546-9F2E-AC85859DDF4B}" ProjectSection(SolutionItems) = preProject modules\ExpressionSearchFilter.jsm = modules\ExpressionSearchFilter.jsm + modules\logger.jsm = modules\logger.jsm EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "_locales", "_locales", "{D446E5C6-BDDE-4091-BD1A-EC57170003CF}" @@ -61,6 +63,12 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "img", "img", "{F266602F-175 ProjectSection(SolutionItems) = preProject resources\img\full-logo.png = resources\img\full-logo.png resources\img\logo.png = resources\img\logo.png + resources\img\logo128.png = resources\img\logo128.png + resources\img\logo16.png = resources\img\logo16.png + resources\img\logo32.png = resources\img\logo32.png + resources\img\logo48.png = resources\img\logo48.png + resources\img\logo64.png = resources\img\logo64.png + resources\img\logo96.png = resources\img\logo96.png EndProjectSection EndProject Global diff --git a/manifest.json b/manifest.json index b7753dd..0d1384f 100644 --- a/manifest.json +++ b/manifest.json @@ -1,16 +1,22 @@ { "manifest_version": 2, - "name": "AI Filter", - "version": "1.1", + "name": "Sortana", + "version": "1.2.1", "default_locale": "en-US", - "applications": { "gecko": { "id": "ai-filter@example" } }, + "applications": { + "gecko": { + "id": "ai-filter@jordanwages", + "strict_min_version": "128.0", + "strict_max_version": "128.*" + } + }, "icons": { - "16": "resources/img/logo.png", - "32": "resources/img/logo.png", - "48": "resources/img/logo.png", - "64": "resources/img/logo.png", - "96": "resources/img/logo.png", - "128": "resources/img/logo.png" + "16": "resources/img/logo16.png", + "32": "resources/img/logo32.png", + "48": "resources/img/logo48.png", + "64": "resources/img/logo64.png", + "96": "resources/img/logo96.png", + "128": "resources/img/logo128.png" }, "background": { "scripts": [ "background.js" ] }, "experiment_apis": { @@ -34,7 +40,7 @@ }, "options_ui": { "page": "options/options.html", - "open_in_tab": false + "open_in_tab": true }, "permissions": [ "storage" ] } diff --git a/resources/img/logo128.png b/resources/img/logo128.png new file mode 100644 index 0000000000000000000000000000000000000000..1f56a14d1318aa7a5195a1104bd6286b6d0df3f0 GIT binary patch literal 8433 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

q#N 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 literal 0 HcmV?d00001 diff --git a/resources/img/logo32.png b/resources/img/logo32.png new file mode 100644 index 0000000000000000000000000000000000000000..b7c82b544709e32695ad32464c1c02b73b1d82ac GIT binary patch literal 1707 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 literal 0 HcmV?d00001 From 60c0ca4793feb6769f4b0260dfcdba5dcca6e383 Mon Sep 17 00:00:00 2001 From: Jordan Wages Date: Sat, 21 Jun 2025 22:55:30 -0500 Subject: [PATCH 004/148] Set max version to * --- manifest.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/manifest.json b/manifest.json index 0d1384f..8940043 100644 --- a/manifest.json +++ b/manifest.json @@ -7,7 +7,7 @@ "gecko": { "id": "ai-filter@jordanwages", "strict_min_version": "128.0", - "strict_max_version": "128.*" + "strict_max_version": "*" } }, "icons": { From d28a6e297cba19ceec87500af136f8122732827b Mon Sep 17 00:00:00 2001 From: Jordan Wages Date: Sat, 21 Jun 2025 23:06:00 -0500 Subject: [PATCH 005/148] More housekeeping. This is all in order to comply with Mozilla's add-on developer hub rules. --- manifest.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/manifest.json b/manifest.json index 8940043..c31479d 100644 --- a/manifest.json +++ b/manifest.json @@ -7,7 +7,7 @@ "gecko": { "id": "ai-filter@jordanwages", "strict_min_version": "128.0", - "strict_max_version": "*" + "strict_max_version": "139.*" } }, "icons": { From 6279cfe6e0b16f29a7cc58de5cc68bda1a60836a Mon Sep 17 00:00:00 2001 From: Jordan Wages Date: Sat, 21 Jun 2025 23:58:30 -0500 Subject: [PATCH 006/148] Fix extension lookup --- modules/ExpressionSearchFilter.jsm | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/modules/ExpressionSearchFilter.jsm b/modules/ExpressionSearchFilter.jsm index d543b1b..2b5d322 100644 --- a/modules/ExpressionSearchFilter.jsm +++ b/modules/ExpressionSearchFilter.jsm @@ -33,7 +33,9 @@ Do not add any other keys, text, or formatting.`; class CustomerTermBase { constructor(nameId, operators) { - this.extension = ExtensionParent.GlobalManager.getExtension("ai-filter@example"); + // Lookup our extension instance using the ID from manifest.json + // so locale strings are resolved correctly. + this.extension = ExtensionParent.GlobalManager.getExtension("ai-filter@jordanwages"); this.id = "aifilter#" + nameId; this.name = this.extension.localeData.localizeMessage(nameId); this.operators = operators; From 5ad2efa409af55502d5769912f3ebb23f6479bae Mon Sep 17 00:00:00 2001 From: Jordan Wages Date: Sun, 22 Jun 2025 04:06:01 -0500 Subject: [PATCH 007/148] Update README.md Added some filter examples. --- README.md | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/README.md b/README.md index 9e9fd34..e6b8e41 100644 --- a/README.md +++ b/README.md @@ -66,6 +66,33 @@ the version from `manifest.json` and creates an XPI in the `release` folder. 3. When the filter runs, the add-on sends the message text to the service and checks the JSON response for a match. +### Example Filters + +Here are some useful and fun example criteria you can use in your filters. Filters should be able to be answered as either `true` or `false`. + +- **"Does this message require my attention, response, or decision soon?"** + Identify emails with deadlines, requests, or actionable items. + +- **"Is this message spam, phishing, or irrelevant bulk mail?"** + Catch low-value or deceptive messages and sweep them into the junk folder. + +- **"Is this email promotional, advertising a product or service, or part of a mass mailing?"** + Great for filtering out newsletters, deals, and marketing campaigns. + +- **"Is this a personal message from a friend or family member?"** + Keep emotionally meaningful or social emails from getting lost. + +- **"Is this message a receipt, invoice, or shipping notification?"** + Automatically tag or file transactional messages for easy lookup. + +- **"Does this message relate to one of my current work projects?"** + Focus your inbox around what matters right now. + +- **"Would I roll my eyes reading this email?"** + For when you're ready to filter based on vibes. + +You can define as many filters as you'd like, each using a different prompt and triggering tags, moves, or actions based on the model's classification. + ## License This project is licensed under the terms of the GNU General Public License From 6968d2d2dd74d61ada9bbc05272b40fd28e9d858 Mon Sep 17 00:00:00 2001 From: Jordan Wages Date: Sun, 22 Jun 2025 06:27:29 -0500 Subject: [PATCH 008/148] Strip base64 and attachment content --- modules/ExpressionSearchFilter.jsm | 76 ++++++++++++++++++++++++++++-- 1 file changed, 71 insertions(+), 5 deletions(-) diff --git a/modules/ExpressionSearchFilter.jsm b/modules/ExpressionSearchFilter.jsm index 2b5d322..8f981ce 100644 --- a/modules/ExpressionSearchFilter.jsm +++ b/modules/ExpressionSearchFilter.jsm @@ -125,12 +125,78 @@ function getPlainText(msgHdr) { let stream = folder.getMsgInputStream(msgHdr, reusable); let data = NetUtil.readInputStreamToString(stream, msgHdr.messageSize); if (!reusable.value) stream.close(); + let parser = Cc["@mozilla.org/parserutils;1"].getService(Ci.nsIParserUtils); - return parser.convertToPlainText(data, - Ci.nsIDocumentEncoder.OutputLFLineBreak | - Ci.nsIDocumentEncoder.OutputNoScriptContent | - Ci.nsIDocumentEncoder.OutputNoFramesContent | - Ci.nsIDocumentEncoder.OutputBodyOnly, 0); + + try { + let root = MimeParser.parseSync(data, {strformat: "unicode"}); + let parts = []; + + function pushPlaceholder(type, info, bytes) { + bytes = bytes || 0; + let prettyType = type.split("/")[1] || type; + parts.push(`[${info}: ${prettyType}, ${bytes} bytes]`); + } + + function byteSizeFromBase64(str) { + let clean = str.replace(/[^A-Za-z0-9+/=]/g, ""); + return Math.floor(clean.length * 3 / 4); + } + + function replaceInlineBase64(text) { + return text.replace(/[A-Za-z0-9+/]{100,}={0,2}/g, + m => `[base64: ${byteSizeFromBase64(m)} bytes]`); + } + + function walk(node) { + if (node.parts && node.parts.length) { + for (let child of node.parts) { + walk(child); + } + return; + } + + let ct = (node.contentType || "text/plain").toLowerCase(); + let cd = (node.headers?.["content-disposition"]?.[0] || "").toLowerCase(); + let enc = (node.headers?.["content-transfer-encoding"]?.[0] || "").toLowerCase(); + let bodyText = String(node.body || ""); + + if (cd.includes("attachment")) { + pushPlaceholder(ct, "binary attachment", byteSizeFromBase64(bodyText)); + } else if (ct.startsWith("text/plain")) { + if (enc === "base64") { + parts.push(`[base64: ${byteSizeFromBase64(bodyText)} bytes]`); + } else { + parts.push(replaceInlineBase64(bodyText)); + } + } else if (ct.startsWith("text/html")) { + if (enc === "base64") { + parts.push(`[base64: ${byteSizeFromBase64(bodyText)} bytes]`); + } else { + let txt = parser.convertToPlainText(bodyText, + Ci.nsIDocumentEncoder.OutputLFLineBreak | + Ci.nsIDocumentEncoder.OutputNoScriptContent | + Ci.nsIDocumentEncoder.OutputNoFramesContent | + Ci.nsIDocumentEncoder.OutputBodyOnly, 0); + parts.push(replaceInlineBase64(txt)); + } + } else { + // Other single part types treated as attachments + pushPlaceholder(ct, "binary attachment", byteSizeFromBase64(bodyText)); + } + } + + walk(root); + return parts.join("\n"); + } catch (e) { + // Fallback: convert entire raw message to text + aiLog(`Failed to parse MIME, falling back to raw conversion`, {level: 'warn'}, e); + return parser.convertToPlainText(data, + Ci.nsIDocumentEncoder.OutputLFLineBreak | + Ci.nsIDocumentEncoder.OutputNoScriptContent | + Ci.nsIDocumentEncoder.OutputNoFramesContent | + Ci.nsIDocumentEncoder.OutputBodyOnly, 0); + } } let gEndpoint = "http://127.0.0.1:5000/v1/classify"; From d1b475b5e3b331c34685fdad6f919cdc409e9cb0 Mon Sep 17 00:00:00 2001 From: Jordan Wages Date: Mon, 23 Jun 2025 00:25:55 -0500 Subject: [PATCH 009/148] Update manifest.json --- manifest.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/manifest.json b/manifest.json index c31479d..bea687f 100644 --- a/manifest.json +++ b/manifest.json @@ -1,7 +1,7 @@ { "manifest_version": 2, "name": "Sortana", - "version": "1.2.1", + "version": "1.2.2", "default_locale": "en-US", "applications": { "gecko": { From eb2af513eafe78815692f6143aeec0e9011aa8c2 Mon Sep 17 00:00:00 2001 From: Jordan Wages Date: Tue, 24 Jun 2025 13:58:49 -0500 Subject: [PATCH 010/148] Refactor AI logic into separate classifier module --- experiment/api.js | 30 ++-- modules/AiClassifier.jsm | 211 +++++++++++++++++++++++++++++ modules/ExpressionSearchFilter.jsm | 183 +------------------------ 3 files changed, 223 insertions(+), 201 deletions(-) create mode 100644 modules/AiClassifier.jsm diff --git a/experiment/api.js b/experiment/api.js index c95d5f4..c225779 100644 --- a/experiment/api.js +++ b/experiment/api.js @@ -1,6 +1,7 @@ var { ExtensionCommon } = ChromeUtils.importESModule("resource://gre/modules/ExtensionCommon.sys.mjs"); var { Services } = globalThis || ChromeUtils.importESModule("resource://gre/modules/Services.sys.mjs"); var { MailServices } = ChromeUtils.importESModule("resource:///modules/MailServices.sys.mjs"); +var { AiClassifier } = ChromeUtils.import("resource://aifilter/modules/AiClassifier.jsm"); var aiLog = (...args) => console.log("[ai-filter][api]", ...args); var setDebug = () => {}; @@ -21,7 +22,6 @@ function registerResourceUrl(extension, namespace) { resProto.setSubstitutionWithFlags(namespace, uri, resProto.ALLOW_CONTENT_ACCESS); } -var gTerm; var AIFilterMod; var aiFilter = class extends ExtensionCommon.ExtensionAPI { @@ -61,33 +61,19 @@ var aiFilter = class extends ExtensionCommon.ExtensionAPI { aiFilter: { initConfig: async (config) => { try { - if (AIFilterMod?.AIFilter?.setConfig) { - AIFilterMod.AIFilter.setConfig(config); - if (typeof config.debugLogging === "boolean") { - setDebug(config.debugLogging); - } - aiLog("[api] configuration applied", {debug: true}, config); + AiClassifier.setConfig(config); + if (typeof config.debugLogging === "boolean") { + setDebug(config.debugLogging); } + aiLog("[api] configuration applied", {debug: true}, config); } catch (err) { aiLog("[api] failed to apply config", {level: 'error'}, err); } }, - classify: (msg) => { - aiLog("[api] classify() called with msg", {debug: true}, msg); + classify: (text, criterion) => { + aiLog("[api] classify() called", {debug: true}, text, criterion); try { - if (!gTerm) { - aiLog("[api] instantiating new ClassificationTerm", {debug: true}); - let mod = AIFilterMod || ChromeUtils.import("resource://aifilter/modules/ExpressionSearchFilter.jsm"); - gTerm = new mod.ClassificationTerm(); - } - aiLog("[api] calling gTerm.match()", {debug: true}); - let matchResult = gTerm.match( - msg.msgHdr, - msg.value, - Ci.nsMsgSearchOp.Contains - ); - aiLog("[api] gTerm.match() returned", {debug: true}, matchResult); - return matchResult; + return AiClassifier.classifyTextSync(text, criterion); } catch (err) { aiLog("[api] error in classify()", {level: 'error'}, err); diff --git a/modules/AiClassifier.jsm b/modules/AiClassifier.jsm new file mode 100644 index 0000000..eb399c4 --- /dev/null +++ b/modules/AiClassifier.jsm @@ -0,0 +1,211 @@ +"use strict"; +var { Services } = globalThis || ChromeUtils.importESModule("resource://gre/modules/Services.sys.mjs"); +var { NetUtil } = ChromeUtils.importESModule("resource://gre/modules/NetUtil.sys.mjs"); +var { FileUtils } = ChromeUtils.importESModule("resource://gre/modules/FileUtils.sys.mjs"); +var { aiLog, setDebug } = ChromeUtils.import("resource://aifilter/modules/logger.jsm"); + +var EXPORTED_SYMBOLS = ["AiClassifier"]; + +const SYSTEM_PREFIX = `You are an email-classification assistant. +Read the email below and the classification criterion provided by the user. +`; + +const DEFAULT_CUSTOM_SYSTEM_PROMPT = "Determine whether the email satisfies the user's criterion."; + +const SYSTEM_SUFFIX = ` +Return ONLY a JSON object on a single line of the form: +{"match": true} - if the email satisfies the criterion +{"match": false} - otherwise + +Do not add any other keys, text, or formatting.`; + +let gEndpoint = "http://127.0.0.1:5000/v1/classify"; +let gTemplateName = "openai"; +let gCustomTemplate = ""; +let gCustomSystemPrompt = DEFAULT_CUSTOM_SYSTEM_PROMPT; +let gTemplateText = ""; + +let gAiParams = { + max_tokens: 4096, + temperature: 0.6, + top_p: 0.95, + seed: -1, + repetition_penalty: 1.0, + top_k: 20, + min_p: 0, + presence_penalty: 0, + frequency_penalty: 0, + typical_p: 1, + tfs: 1, +}; + +let gCache = new Map(); +let gCacheLoaded = false; +let gCacheFile; + +function ensureCacheFile() { + if (!gCacheFile) { + gCacheFile = Services.dirsvc.get("ProfD", Ci.nsIFile); + gCacheFile.append("aifilter_cache.json"); + } +} + +function loadCache() { + if (gCacheLoaded) { + return; + } + ensureCacheFile(); + aiLog(`[AiClassifier] Loading cache from ${gCacheFile.path}`, {debug: true}); + try { + if (gCacheFile.exists()) { + let stream = Cc["@mozilla.org/network/file-input-stream;1"].createInstance(Ci.nsIFileInputStream); + stream.init(gCacheFile, -1, 0, 0); + let data = NetUtil.readInputStreamToString(stream, stream.available()); + stream.close(); + aiLog(`[AiClassifier] Cache file contents: ${data}`, {debug: true}); + let obj = JSON.parse(data); + for (let [k, v] of Object.entries(obj)) { + aiLog(`[AiClassifier] ⮡ Loaded entry '${k}' → ${v}`, {debug: true}); + gCache.set(k, v); + } + aiLog(`[AiClassifier] Loaded ${gCache.size} cache entries`, {debug: true}); + } else { + aiLog(`[AiClassifier] Cache file does not exist`, {debug: true}); + } + } catch (e) { + aiLog(`Failed to load cache`, {level: 'error'}, e); + } + gCacheLoaded = true; +} + +function saveCache(updatedKey, updatedValue) { + ensureCacheFile(); + aiLog(`[AiClassifier] Saving cache to ${gCacheFile.path}`, {debug: true}); + if (typeof updatedKey !== "undefined") { + aiLog(`[AiClassifier] ⮡ Persisting entry '${updatedKey}' → ${updatedValue}`, {debug: true}); + } + try { + let obj = Object.fromEntries(gCache); + let data = JSON.stringify(obj); + let stream = Cc["@mozilla.org/network/file-output-stream;1"].createInstance(Ci.nsIFileOutputStream); + stream.init(gCacheFile, + FileUtils.MODE_WRONLY | FileUtils.MODE_CREATE | FileUtils.MODE_TRUNCATE, + FileUtils.PERMS_FILE, + 0); + stream.write(data, data.length); + stream.close(); + } catch (e) { + aiLog(`Failed to save cache`, {level: 'error'}, e); + } +} + +function loadTemplate(name) { + try { + let url = `resource://aifilter/prompt_templates/${name}.txt`; + let xhr = new XMLHttpRequest(); + xhr.open("GET", url, false); + xhr.overrideMimeType("text/plain"); + xhr.send(); + if (xhr.status === 0 || xhr.status === 200) { + return xhr.responseText; + } + } catch (e) { + aiLog(`Failed to load template '${name}':`, {level: 'error'}, e); + } + return ""; +} + +function setConfig(config = {}) { + if (config.endpoint) { + gEndpoint = config.endpoint; + } + if (config.templateName) { + gTemplateName = config.templateName; + } + if (typeof config.customTemplate === "string") { + gCustomTemplate = config.customTemplate; + } + if (typeof config.customSystemPrompt === "string") { + gCustomSystemPrompt = config.customSystemPrompt; + } + if (config.aiParams && typeof config.aiParams === "object") { + for (let [k, v] of Object.entries(config.aiParams)) { + if (k in gAiParams && typeof v !== "undefined") { + gAiParams[k] = v; + } + } + } + if (typeof config.debugLogging === "boolean") { + setDebug(config.debugLogging); + } + gTemplateText = gTemplateName === "custom" ? gCustomTemplate : loadTemplate(gTemplateName); + aiLog(`[AiClassifier] Endpoint set to ${gEndpoint}`, {debug: true}); + aiLog(`[AiClassifier] Template set to ${gTemplateName}`, {debug: true}); +} + +function buildSystemPrompt() { + return SYSTEM_PREFIX + (gCustomSystemPrompt || DEFAULT_CUSTOM_SYSTEM_PROMPT) + SYSTEM_SUFFIX; +} + +function buildPrompt(body, criterion) { + aiLog(`[AiClassifier] Building prompt with criterion: "${criterion}"`, {debug: true}); + const data = { + system: buildSystemPrompt(), + email: body, + query: criterion, + }; + let template = gTemplateText || loadTemplate(gTemplateName); + return template.replace(/{{\s*(\w+)\s*}}/g, (m, key) => data[key] || ""); +} + +function classifyTextSync(text, criterion, cacheKey = null) { + loadCache(); + if (cacheKey && gCache.has(cacheKey)) { + aiLog(`[AiClassifier] Cache hit for key: ${cacheKey}`, {debug: true}); + return gCache.get(cacheKey); + } + + let payloadObj = Object.assign({ + prompt: buildPrompt(text, criterion) + }, gAiParams); + let payload = JSON.stringify(payloadObj); + + aiLog(`[AiClassifier] Sending classification request to ${gEndpoint}`, {debug: true}); + + let matched = false; + try { + let xhr = new XMLHttpRequest(); + xhr.open("POST", gEndpoint, false); + xhr.setRequestHeader("Content-Type", "application/json"); + xhr.send(payload); + + if (xhr.status < 200 || xhr.status >= 300) { + aiLog(`HTTP status ${xhr.status}`, {level: 'warn'}); + } else { + const result = JSON.parse(xhr.responseText); + aiLog(`[AiClassifier] Received response:`, {debug: true}, result); + const rawText = result.choices?.[0]?.text || ""; + const thinkText = rawText.match(/[\s\S]*?<\/think>/gi)?.join('') || ''; + aiLog('[AiClassifier] ⮡ Reasoning:', {debug: true}, thinkText); + const cleanedText = rawText.replace(/[\s\S]*?<\/think>/gi, "").trim(); + aiLog('[AiClassifier] ⮡ Cleaned Response Text:', {debug: true}, cleanedText); + const obj = JSON.parse(cleanedText); + matched = obj.matched === true || obj.match === true; + if (cacheKey) { + aiLog(`[AiClassifier] Caching entry '${cacheKey}' → ${matched}`, {debug: true}); + gCache.set(cacheKey, matched); + saveCache(cacheKey, matched); + } + } + } catch (e) { + aiLog(`HTTP request failed`, {level: 'error'}, e); + } + + return matched; +} + +async function classifyText(text, criterion, cacheKey = null) { + return classifyTextSync(text, criterion, cacheKey); +} + +var AiClassifier = { classifyText, classifyTextSync, setConfig }; diff --git a/modules/ExpressionSearchFilter.jsm b/modules/ExpressionSearchFilter.jsm index 8f981ce..2403b01 100644 --- a/modules/ExpressionSearchFilter.jsm +++ b/modules/ExpressionSearchFilter.jsm @@ -4,8 +4,8 @@ var { MailServices } = ChromeUtils.importESModule("resource:///modules/MailSe var { Services } = globalThis || ChromeUtils.importESModule("resource://gre/modules/Services.sys.mjs"); var { NetUtil } = ChromeUtils.importESModule("resource://gre/modules/NetUtil.sys.mjs"); var { MimeParser } = ChromeUtils.importESModule("resource:///modules/mimeParser.sys.mjs"); -var { FileUtils } = ChromeUtils.importESModule("resource://gre/modules/FileUtils.sys.mjs"); -var { aiLog, setDebug } = ChromeUtils.import("resource://aifilter/modules/logger.jsm"); +var { aiLog } = ChromeUtils.import("resource://aifilter/modules/logger.jsm"); +var { AiClassifier } = ChromeUtils.import("resource://aifilter/modules/AiClassifier.jsm"); function sha256Hex(str) { const hasher = Cc["@mozilla.org/security/hash;1"].createInstance(Ci.nsICryptoHash); @@ -18,19 +18,6 @@ function sha256Hex(str) { var EXPORTED_SYMBOLS = ["AIFilter", "ClassificationTerm"]; -const SYSTEM_PREFIX = `You are an email-classification assistant. -Read the email below and the classification criterion provided by the user. -`; - -const DEFAULT_CUSTOM_SYSTEM_PROMPT = "Determine whether the email satisfies the user's criterion."; - -const SYSTEM_SUFFIX = ` -Return ONLY a JSON object on a single line of the form: -{"match": true} - if the email satisfies the criterion -{"match": false} - otherwise - -Do not add any other keys, text, or formatting.`; - class CustomerTermBase { constructor(nameId, operators) { // Lookup our extension instance using the ID from manifest.json @@ -39,56 +26,10 @@ class CustomerTermBase { this.id = "aifilter#" + nameId; this.name = this.extension.localeData.localizeMessage(nameId); this.operators = operators; - this.cache = new Map(); - this._cacheFile = Services.dirsvc.get("ProfD", Ci.nsIFile); - this._cacheFile.append("aifilter_cache.json"); - this._loadCache(); aiLog(`[ExpressionSearchFilter] Initialized term base "${this.id}"`, {debug: true}); } - _loadCache() { - aiLog(`[ExpressionSearchFilter] Loading cache from ${this._cacheFile.path}` , {debug: true}); - try { - if (this._cacheFile.exists()) { - let stream = Cc["@mozilla.org/network/file-input-stream;1"].createInstance(Ci.nsIFileInputStream); - stream.init(this._cacheFile, -1, 0, 0); - let data = NetUtil.readInputStreamToString(stream, stream.available()); - stream.close(); - aiLog(`[ExpressionSearchFilter] Cache file contents: ${data}`, {debug: true}); - let obj = JSON.parse(data); - for (let [k, v] of Object.entries(obj)) { - aiLog(`[ExpressionSearchFilter] ⮡ Loaded entry '${k}' → ${v}`, {debug: true}); - this.cache.set(k, v); - } - aiLog(`[ExpressionSearchFilter] Loaded ${this.cache.size} cache entries`, {debug: true}); - } else { - aiLog(`[ExpressionSearchFilter] Cache file does not exist`, {debug: true}); - } - } catch (e) { - aiLog(`Failed to load cache`, {level: 'error'}, e); - } - } - - _saveCache(updatedKey, updatedValue) { - aiLog(`[ExpressionSearchFilter] Saving cache to ${this._cacheFile.path}`, {debug: true}); - if (typeof updatedKey !== "undefined") { - aiLog(`[ExpressionSearchFilter] ⮡ Persisting entry '${updatedKey}' → ${updatedValue}`, {debug: true}); - } - try { - let obj = Object.fromEntries(this.cache); - let data = JSON.stringify(obj); - let stream = Cc["@mozilla.org/network/file-output-stream;1"].createInstance(Ci.nsIFileOutputStream); - stream.init(this._cacheFile, - FileUtils.MODE_WRONLY | FileUtils.MODE_CREATE | FileUtils.MODE_TRUNCATE, - FileUtils.PERMS_FILE, - 0); - stream.write(data, data.length); - stream.close(); - } catch (e) { - aiLog(`Failed to save cache`, {level: 'error'}, e); - } - } getEnabled() { aiLog(`[ExpressionSearchFilter] getEnabled() called on "${this.id}"`, {debug: true}); @@ -199,84 +140,6 @@ function getPlainText(msgHdr) { } } -let gEndpoint = "http://127.0.0.1:5000/v1/classify"; -let gTemplateName = "openai"; -let gCustomTemplate = ""; -let gCustomSystemPrompt = DEFAULT_CUSTOM_SYSTEM_PROMPT; -let gTemplateText = ""; - -let gAiParams = { - max_tokens: 4096, - temperature: 0.6, - top_p: 0.95, - seed: -1, - repetition_penalty: 1.0, - top_k: 20, - min_p: 0, - presence_penalty: 0, - frequency_penalty: 0, - typical_p: 1, - tfs: 1, -}; - -function loadTemplate(name) { - try { - let url = `resource://aifilter/prompt_templates/${name}.txt`; - let xhr = new XMLHttpRequest(); - xhr.open("GET", url, false); - xhr.overrideMimeType("text/plain"); - xhr.send(); - if (xhr.status === 0 || xhr.status === 200) { - return xhr.responseText; - } - } catch (e) { - aiLog(`Failed to load template '${name}':`, {level: 'error'}, e); - } - return ""; -} - -function setConfig(config = {}) { - if (config.endpoint) { - gEndpoint = config.endpoint; - } - if (config.templateName) { - gTemplateName = config.templateName; - } - if (typeof config.customTemplate === "string") { - gCustomTemplate = config.customTemplate; - } - if (typeof config.customSystemPrompt === "string") { - gCustomSystemPrompt = config.customSystemPrompt; - } - if (config.aiParams && typeof config.aiParams === "object") { - for (let [k, v] of Object.entries(config.aiParams)) { - if (k in gAiParams && typeof v !== "undefined") { - gAiParams[k] = v; - } - } - } - if (typeof config.debugLogging === "boolean") { - setDebug(config.debugLogging); - } - gTemplateText = gTemplateName === "custom" ? gCustomTemplate : loadTemplate(gTemplateName); - aiLog(`[ExpressionSearchFilter] Endpoint set to ${gEndpoint}`, {debug: true}); - aiLog(`[ExpressionSearchFilter] Template set to ${gTemplateName}`, {debug: true}); -} - -function buildSystemPrompt() { - return SYSTEM_PREFIX + (gCustomSystemPrompt || DEFAULT_CUSTOM_SYSTEM_PROMPT) + SYSTEM_SUFFIX; -} - -function buildPrompt(body, criterion) { - aiLog(`[ExpressionSearchFilter] Building prompt with criterion: "${criterion}"`, {debug: true}); - const data = { - system: buildSystemPrompt(), - email: body, - query: criterion, - }; - let template = gTemplateText || loadTemplate(gTemplateName); - return template.replace(/{{\s*(\w+)\s*}}/g, (m, key) => data[key] || ""); -} class ClassificationTerm extends CustomerTermBase { constructor() { @@ -292,47 +155,9 @@ class ClassificationTerm extends CustomerTermBase { aiLog(`[ExpressionSearchFilter] Matching message ${msgHdr.messageId} using op "${opName}" and value "${value}"`, {debug: true}); let key = [msgHdr.messageId, op, value].map(sha256Hex).join("|"); - if (this.cache.has(key)) { - aiLog(`[ExpressionSearchFilter] Cache hit for key: ${key}`, {debug: true}); - return this.cache.get(key); - } - let body = getPlainText(msgHdr); - let payloadObj = Object.assign({ - prompt: buildPrompt(body, value) - }, gAiParams); - let payload = JSON.stringify(payloadObj); - - aiLog(`[ExpressionSearchFilter] Sending classification request to ${gEndpoint}`, {debug: true}); - - let matched = false; - try { - let xhr = new XMLHttpRequest(); - xhr.open("POST", gEndpoint, false); // synchronous request - xhr.setRequestHeader("Content-Type", "application/json"); - xhr.send(payload); - - if (xhr.status < 200 || xhr.status >= 300) { - aiLog(`HTTP status ${xhr.status}`, {level: 'warn'}); - } else { - const result = JSON.parse(xhr.responseText); - aiLog(`[ExpressionSearchFilter] Received response:`, {debug: true}, result); - const rawText = result.choices?.[0]?.text || ""; - const thinkText = rawText.match(/[\s\S]*?<\/think>/gi)?.join('') || ''; - aiLog('[ExpressionSearchFilter] ⮡ Reasoning:', {debug: true}, thinkText); - const cleanedText = rawText.replace(/[\s\S]*?<\/think>/gi, "").trim(); - aiLog('[ExpressionSearchFilter] ⮡ Cleaned Response Text:', {debug: true}, cleanedText); - const obj = JSON.parse(cleanedText); - matched = obj.matched === true || obj.match === true; - - aiLog(`[ExpressionSearchFilter] Caching entry '${key}' → ${matched}`, {debug: true}); - this.cache.set(key, matched); - this._saveCache(key, matched); - } - } catch (e) { - aiLog(`HTTP request failed`, {level: 'error'}, e); - } + let matched = AiClassifier.classifyTextSync(body, value, key); if (op === Ci.nsMsgSearchOp.DoesntMatch) { matched = !matched; @@ -355,4 +180,4 @@ class ClassificationTerm extends CustomerTermBase { } })(); -var AIFilter = { setConfig }; +var AIFilter = { setConfig: AiClassifier.setConfig }; From 606e612ab0b5d79ee166c59b29383b5305af8fd3 Mon Sep 17 00:00:00 2001 From: Jordan Wages Date: Tue, 24 Jun 2025 14:05:03 -0500 Subject: [PATCH 011/148] Refactor getPlainText into shared module --- modules/ExpressionSearchFilter.jsm | 85 +--------------------------- modules/messageUtils.jsm | 89 ++++++++++++++++++++++++++++++ 2 files changed, 90 insertions(+), 84 deletions(-) create mode 100644 modules/messageUtils.jsm diff --git a/modules/ExpressionSearchFilter.jsm b/modules/ExpressionSearchFilter.jsm index 2403b01..c50dd59 100644 --- a/modules/ExpressionSearchFilter.jsm +++ b/modules/ExpressionSearchFilter.jsm @@ -2,10 +2,9 @@ var { ExtensionParent } = ChromeUtils.importESModule("resource://gre/modules/ExtensionParent.sys.mjs"); var { MailServices } = ChromeUtils.importESModule("resource:///modules/MailServices.sys.mjs"); var { Services } = globalThis || ChromeUtils.importESModule("resource://gre/modules/Services.sys.mjs"); -var { NetUtil } = ChromeUtils.importESModule("resource://gre/modules/NetUtil.sys.mjs"); -var { MimeParser } = ChromeUtils.importESModule("resource:///modules/mimeParser.sys.mjs"); var { aiLog } = ChromeUtils.import("resource://aifilter/modules/logger.jsm"); var { AiClassifier } = ChromeUtils.import("resource://aifilter/modules/AiClassifier.jsm"); +var { getPlainText } = ChromeUtils.import("resource://aifilter/modules/messageUtils.jsm"); function sha256Hex(str) { const hasher = Cc["@mozilla.org/security/hash;1"].createInstance(Ci.nsICryptoHash); @@ -58,88 +57,6 @@ class CustomerTermBase { } } -function getPlainText(msgHdr) { - aiLog(`[ExpressionSearchFilter] Extracting plain text for message ID ${msgHdr.messageId}`, {debug: true}); - let folder = msgHdr.folder; - if (!folder.getMsgInputStream) return ""; - let reusable = {}; - let stream = folder.getMsgInputStream(msgHdr, reusable); - let data = NetUtil.readInputStreamToString(stream, msgHdr.messageSize); - if (!reusable.value) stream.close(); - - let parser = Cc["@mozilla.org/parserutils;1"].getService(Ci.nsIParserUtils); - - try { - let root = MimeParser.parseSync(data, {strformat: "unicode"}); - let parts = []; - - function pushPlaceholder(type, info, bytes) { - bytes = bytes || 0; - let prettyType = type.split("/")[1] || type; - parts.push(`[${info}: ${prettyType}, ${bytes} bytes]`); - } - - function byteSizeFromBase64(str) { - let clean = str.replace(/[^A-Za-z0-9+/=]/g, ""); - return Math.floor(clean.length * 3 / 4); - } - - function replaceInlineBase64(text) { - return text.replace(/[A-Za-z0-9+/]{100,}={0,2}/g, - m => `[base64: ${byteSizeFromBase64(m)} bytes]`); - } - - function walk(node) { - if (node.parts && node.parts.length) { - for (let child of node.parts) { - walk(child); - } - return; - } - - let ct = (node.contentType || "text/plain").toLowerCase(); - let cd = (node.headers?.["content-disposition"]?.[0] || "").toLowerCase(); - let enc = (node.headers?.["content-transfer-encoding"]?.[0] || "").toLowerCase(); - let bodyText = String(node.body || ""); - - if (cd.includes("attachment")) { - pushPlaceholder(ct, "binary attachment", byteSizeFromBase64(bodyText)); - } else if (ct.startsWith("text/plain")) { - if (enc === "base64") { - parts.push(`[base64: ${byteSizeFromBase64(bodyText)} bytes]`); - } else { - parts.push(replaceInlineBase64(bodyText)); - } - } else if (ct.startsWith("text/html")) { - if (enc === "base64") { - parts.push(`[base64: ${byteSizeFromBase64(bodyText)} bytes]`); - } else { - let txt = parser.convertToPlainText(bodyText, - Ci.nsIDocumentEncoder.OutputLFLineBreak | - Ci.nsIDocumentEncoder.OutputNoScriptContent | - Ci.nsIDocumentEncoder.OutputNoFramesContent | - Ci.nsIDocumentEncoder.OutputBodyOnly, 0); - parts.push(replaceInlineBase64(txt)); - } - } else { - // Other single part types treated as attachments - pushPlaceholder(ct, "binary attachment", byteSizeFromBase64(bodyText)); - } - } - - walk(root); - return parts.join("\n"); - } catch (e) { - // Fallback: convert entire raw message to text - aiLog(`Failed to parse MIME, falling back to raw conversion`, {level: 'warn'}, e); - return parser.convertToPlainText(data, - Ci.nsIDocumentEncoder.OutputLFLineBreak | - Ci.nsIDocumentEncoder.OutputNoScriptContent | - Ci.nsIDocumentEncoder.OutputNoFramesContent | - Ci.nsIDocumentEncoder.OutputBodyOnly, 0); - } -} - class ClassificationTerm extends CustomerTermBase { constructor() { diff --git a/modules/messageUtils.jsm b/modules/messageUtils.jsm new file mode 100644 index 0000000..a4978a7 --- /dev/null +++ b/modules/messageUtils.jsm @@ -0,0 +1,89 @@ +"use strict"; +var { NetUtil } = ChromeUtils.importESModule("resource://gre/modules/NetUtil.sys.mjs"); +var { MimeParser } = ChromeUtils.importESModule("resource:///modules/mimeParser.sys.mjs"); +var { aiLog } = ChromeUtils.import("resource://aifilter/modules/logger.jsm"); + +var EXPORTED_SYMBOLS = ["getPlainText"]; + +function getPlainText(msgHdr) { + aiLog(`[ExpressionSearchFilter] Extracting plain text for message ID ${msgHdr.messageId}`, {debug: true}); + let folder = msgHdr.folder; + if (!folder.getMsgInputStream) return ""; + let reusable = {}; + let stream = folder.getMsgInputStream(msgHdr, reusable); + let data = NetUtil.readInputStreamToString(stream, msgHdr.messageSize); + if (!reusable.value) stream.close(); + + let parser = Cc["@mozilla.org/parserutils;1"].getService(Ci.nsIParserUtils); + + try { + let root = MimeParser.parseSync(data, {strformat: "unicode"}); + let parts = []; + + function pushPlaceholder(type, info, bytes) { + bytes = bytes || 0; + let prettyType = type.split("/")[1] || type; + parts.push(`[${info}: ${prettyType}, ${bytes} bytes]`); + } + + function byteSizeFromBase64(str) { + let clean = str.replace(/[^A-Za-z0-9+/=]/g, ""); + return Math.floor(clean.length * 3 / 4); + } + + function replaceInlineBase64(text) { + return text.replace(/[A-Za-z0-9+/]{100,}={0,2}/g, + m => `[base64: ${byteSizeFromBase64(m)} bytes]`); + } + + function walk(node) { + if (node.parts && node.parts.length) { + for (let child of node.parts) { + walk(child); + } + return; + } + + let ct = (node.contentType || "text/plain").toLowerCase(); + let cd = (node.headers?.["content-disposition"]?.[0] || "").toLowerCase(); + let enc = (node.headers?.["content-transfer-encoding"]?.[0] || "").toLowerCase(); + let bodyText = String(node.body || ""); + + if (cd.includes("attachment")) { + pushPlaceholder(ct, "binary attachment", byteSizeFromBase64(bodyText)); + } else if (ct.startsWith("text/plain")) { + if (enc === "base64") { + parts.push(`[base64: ${byteSizeFromBase64(bodyText)} bytes]`); + } else { + parts.push(replaceInlineBase64(bodyText)); + } + } else if (ct.startsWith("text/html")) { + if (enc === "base64") { + parts.push(`[base64: ${byteSizeFromBase64(bodyText)} bytes]`); + } else { + let txt = parser.convertToPlainText(bodyText, + Ci.nsIDocumentEncoder.OutputLFLineBreak | + Ci.nsIDocumentEncoder.OutputNoScriptContent | + Ci.nsIDocumentEncoder.OutputNoFramesContent | + Ci.nsIDocumentEncoder.OutputBodyOnly, 0); + parts.push(replaceInlineBase64(txt)); + } + } else { + // Other single part types treated as attachments + pushPlaceholder(ct, "binary attachment", byteSizeFromBase64(bodyText)); + } + } + + walk(root); + return parts.join("\n"); + } catch (e) { + // Fallback: convert entire raw message to text + aiLog(`Failed to parse MIME, falling back to raw conversion`, {level: 'warn'}, e); + return parser.convertToPlainText(data, + Ci.nsIDocumentEncoder.OutputLFLineBreak | + Ci.nsIDocumentEncoder.OutputNoScriptContent | + Ci.nsIDocumentEncoder.OutputNoFramesContent | + Ci.nsIDocumentEncoder.OutputBodyOnly, 0); + } +} + From 312de63b2e729541610942d3a6e6045b0caf688a Mon Sep 17 00:00:00 2001 From: Jordan Wages Date: Tue, 24 Jun 2025 16:10:38 -0500 Subject: [PATCH 012/148] Refactor classifier to share code --- background.js | 4 +- experiment/api.js | 4 +- modules/AiClassifier.jsm | 85 +++++++++++++++++++++++++++++++--------- 3 files changed, 71 insertions(+), 22 deletions(-) diff --git a/background.js b/background.js index 7ae1e8a..c28a265 100644 --- a/background.js +++ b/background.js @@ -35,7 +35,7 @@ let logger; })(); // Listen for messages from UI/devtools -browser.runtime.onMessage.addListener((msg) => { +browser.runtime.onMessage.addListener(async (msg) => { logger.aiLog("onMessage received", {debug: true}, msg); if (msg?.type === "aiFilter:test") { @@ -45,7 +45,7 @@ browser.runtime.onMessage.addListener((msg) => { try { logger.aiLog("Calling browser.aiFilter.classify()", {debug: true}); - const result = browser.aiFilter.classify(text, criterion); + const result = await browser.aiFilter.classify(text, criterion); logger.aiLog("classify() returned", {debug: true}, result); return { match: result }; } diff --git a/experiment/api.js b/experiment/api.js index c225779..55a0b8b 100644 --- a/experiment/api.js +++ b/experiment/api.js @@ -70,10 +70,10 @@ var aiFilter = class extends ExtensionCommon.ExtensionAPI { aiLog("[api] failed to apply config", {level: 'error'}, err); } }, - classify: (text, criterion) => { + classify: async (text, criterion) => { aiLog("[api] classify() called", {debug: true}, text, criterion); try { - return AiClassifier.classifyTextSync(text, criterion); + return await AiClassifier.classifyText(text, criterion); } catch (err) { aiLog("[api] error in classify()", {level: 'error'}, err); diff --git a/modules/AiClassifier.jsm b/modules/AiClassifier.jsm index eb399c4..204bf7a 100644 --- a/modules/AiClassifier.jsm +++ b/modules/AiClassifier.jsm @@ -158,17 +158,47 @@ function buildPrompt(body, criterion) { return template.replace(/{{\s*(\w+)\s*}}/g, (m, key) => data[key] || ""); } -function classifyTextSync(text, criterion, cacheKey = null) { +function getCachedResult(cacheKey) { loadCache(); if (cacheKey && gCache.has(cacheKey)) { aiLog(`[AiClassifier] Cache hit for key: ${cacheKey}`, {debug: true}); return gCache.get(cacheKey); } + return null; +} +function buildPayload(text, criterion) { let payloadObj = Object.assign({ prompt: buildPrompt(text, criterion) }, gAiParams); - let payload = JSON.stringify(payloadObj); + return JSON.stringify(payloadObj); +} + +function parseMatch(result) { + const rawText = result.choices?.[0]?.text || ""; + const thinkText = rawText.match(/[\s\S]*?<\/think>/gi)?.join('') || ''; + aiLog('[AiClassifier] ⮡ Reasoning:', {debug: true}, thinkText); + const cleanedText = rawText.replace(/[\s\S]*?<\/think>/gi, "").trim(); + aiLog('[AiClassifier] ⮡ Cleaned Response Text:', {debug: true}, cleanedText); + const obj = JSON.parse(cleanedText); + return obj.matched === true || obj.match === true; +} + +function cacheResult(cacheKey, matched) { + if (cacheKey) { + aiLog(`[AiClassifier] Caching entry '${cacheKey}' → ${matched}`, {debug: true}); + gCache.set(cacheKey, matched); + saveCache(cacheKey, matched); + } +} + +function classifyTextSync(text, criterion, cacheKey = null) { + const cached = getCachedResult(cacheKey); + if (cached !== null) { + return cached; + } + + const payload = buildPayload(text, criterion); aiLog(`[AiClassifier] Sending classification request to ${gEndpoint}`, {debug: true}); @@ -179,23 +209,13 @@ function classifyTextSync(text, criterion, cacheKey = null) { xhr.setRequestHeader("Content-Type", "application/json"); xhr.send(payload); - if (xhr.status < 200 || xhr.status >= 300) { - aiLog(`HTTP status ${xhr.status}`, {level: 'warn'}); - } else { + if (xhr.status >= 200 && xhr.status < 300) { const result = JSON.parse(xhr.responseText); aiLog(`[AiClassifier] Received response:`, {debug: true}, result); - const rawText = result.choices?.[0]?.text || ""; - const thinkText = rawText.match(/[\s\S]*?<\/think>/gi)?.join('') || ''; - aiLog('[AiClassifier] ⮡ Reasoning:', {debug: true}, thinkText); - const cleanedText = rawText.replace(/[\s\S]*?<\/think>/gi, "").trim(); - aiLog('[AiClassifier] ⮡ Cleaned Response Text:', {debug: true}, cleanedText); - const obj = JSON.parse(cleanedText); - matched = obj.matched === true || obj.match === true; - if (cacheKey) { - aiLog(`[AiClassifier] Caching entry '${cacheKey}' → ${matched}`, {debug: true}); - gCache.set(cacheKey, matched); - saveCache(cacheKey, matched); - } + matched = parseMatch(result); + cacheResult(cacheKey, matched); + } else { + aiLog(`HTTP status ${xhr.status}`, {level: 'warn'}); } } catch (e) { aiLog(`HTTP request failed`, {level: 'error'}, e); @@ -205,7 +225,36 @@ function classifyTextSync(text, criterion, cacheKey = null) { } async function classifyText(text, criterion, cacheKey = null) { - return classifyTextSync(text, criterion, cacheKey); + const cached = getCachedResult(cacheKey); + if (cached !== null) { + return cached; + } + + const payload = buildPayload(text, criterion); + + aiLog(`[AiClassifier] Sending classification request to ${gEndpoint}`, {debug: true}); + + try { + const response = await fetch(gEndpoint, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: payload, + }); + + if (!response.ok) { + aiLog(`HTTP status ${response.status}`, {level: 'warn'}); + return false; + } + + const result = await response.json(); + aiLog(`[AiClassifier] Received response:`, {debug: true}, result); + const matched = parseMatch(result); + cacheResult(cacheKey, matched); + return matched; + } catch (e) { + aiLog(`HTTP request failed`, {level: 'error'}, e); + return false; + } } var AiClassifier = { classifyText, classifyTextSync, setConfig }; From 1c052a7090ec244cb71efba251809849523c47d8 Mon Sep 17 00:00:00 2001 From: Jordan Wages Date: Tue, 24 Jun 2025 17:31:03 -0500 Subject: [PATCH 013/148] Handle new mail classification --- background.js | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/background.js b/background.js index c28a265..acbe79c 100644 --- a/background.js +++ b/background.js @@ -11,10 +11,17 @@ "use strict"; let logger; +let AiClassifier; // Startup (async () => { logger = await import(browser.runtime.getURL("logger.js")); logger.aiLog("background.js loaded – ready to classify", {debug: true}); + try { + ({ AiClassifier } = ChromeUtils.import("resource://aifilter/modules/AiClassifier.jsm")); + logger.aiLog("AiClassifier imported", {debug: true}); + } catch (e) { + logger.aiLog("failed to import AiClassifier", {level: 'error'}, e); + } try { const store = await browser.storage.local.get(["endpoint", "templateName", "customTemplate", "customSystemPrompt", "aiParams", "debugLogging"]); logger.setDebug(store.debugLogging); @@ -60,6 +67,25 @@ browser.runtime.onMessage.addListener(async (msg) => { } }); +// Automatically classify new messages +browser.messages.onNewMailReceived.addListener(async (folder, messages) => { + logger.aiLog("onNewMailReceived", {debug: true}, messages); + for (const msg of (messages?.messages || messages || [])) { + const id = msg.id ?? msg; + try { + const full = await browser.messages.getFull(id); + const text = full?.parts?.[0]?.body || ""; + const criterion = (await browser.storage.local.get("autoCriterion")).autoCriterion || ""; + const matched = await AiClassifier.classifyText(text, criterion); + if (matched) { + await browser.messages.update(id, {tags: ["$label1"]}); + } + } catch (e) { + logger.aiLog("failed to classify new mail", {level: 'error'}, e); + } + } +}); + // Catch any unhandled rejections window.addEventListener("unhandledrejection", ev => { logger.aiLog("Unhandled promise rejection", {level: 'error'}, ev.reason); From f699fd5709cd6d02692e0470c7558efda6e8e6a8 Mon Sep 17 00:00:00 2001 From: Jordan Wages Date: Tue, 24 Jun 2025 21:00:13 -0500 Subject: [PATCH 014/148] fix resource import timing --- experiment/api.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/experiment/api.js b/experiment/api.js index 55a0b8b..714d4fa 100644 --- a/experiment/api.js +++ b/experiment/api.js @@ -1,7 +1,7 @@ var { ExtensionCommon } = ChromeUtils.importESModule("resource://gre/modules/ExtensionCommon.sys.mjs"); var { Services } = globalThis || ChromeUtils.importESModule("resource://gre/modules/Services.sys.mjs"); var { MailServices } = ChromeUtils.importESModule("resource:///modules/MailServices.sys.mjs"); -var { AiClassifier } = ChromeUtils.import("resource://aifilter/modules/AiClassifier.jsm"); +var AiClassifier; var aiLog = (...args) => console.log("[ai-filter][api]", ...args); var setDebug = () => {}; @@ -34,6 +34,9 @@ var aiFilter = class extends ExtensionCommon.ExtensionAPI { let loggerMod = ChromeUtils.import("resource://aifilter/modules/logger.jsm"); aiLog = loggerMod.aiLog; setDebug = loggerMod.setDebug; + + // Now that the resource URL is registered, import the classifier + ({ AiClassifier } = ChromeUtils.import("resource://aifilter/modules/AiClassifier.jsm")); aiLog("[api] onStartup()", {debug: true}); From 1dc9f5c90ef5ac33a34f482c3863f7af99d79a03 Mon Sep 17 00:00:00 2001 From: Jordan Wages Date: Tue, 24 Jun 2025 22:41:22 -0500 Subject: [PATCH 015/148] Fix messages API usage --- background.js | 42 +++++++++++++++++++++++++----------------- 1 file changed, 25 insertions(+), 17 deletions(-) diff --git a/background.js b/background.js index acbe79c..b05809f 100644 --- a/background.js +++ b/background.js @@ -17,8 +17,12 @@ let AiClassifier; logger = await import(browser.runtime.getURL("logger.js")); logger.aiLog("background.js loaded – ready to classify", {debug: true}); try { - ({ AiClassifier } = ChromeUtils.import("resource://aifilter/modules/AiClassifier.jsm")); - logger.aiLog("AiClassifier imported", {debug: true}); + if (typeof ChromeUtils !== "undefined") { + ({ AiClassifier } = ChromeUtils.import("resource://aifilter/modules/AiClassifier.jsm")); + logger.aiLog("AiClassifier imported", {debug: true}); + } else { + logger.aiLog("ChromeUtils is undefined, skipping AiClassifier import", {level: 'warn'}); + } } catch (e) { logger.aiLog("failed to import AiClassifier", {level: 'error'}, e); } @@ -68,23 +72,27 @@ browser.runtime.onMessage.addListener(async (msg) => { }); // Automatically classify new messages -browser.messages.onNewMailReceived.addListener(async (folder, messages) => { - logger.aiLog("onNewMailReceived", {debug: true}, messages); - for (const msg of (messages?.messages || messages || [])) { - const id = msg.id ?? msg; - try { - const full = await browser.messages.getFull(id); - const text = full?.parts?.[0]?.body || ""; - const criterion = (await browser.storage.local.get("autoCriterion")).autoCriterion || ""; - const matched = await AiClassifier.classifyText(text, criterion); - if (matched) { - await browser.messages.update(id, {tags: ["$label1"]}); +if (typeof messenger !== "undefined" && messenger.messages?.onNewMailReceived) { + messenger.messages.onNewMailReceived.addListener(async (folder, messages) => { + logger.aiLog("onNewMailReceived", {debug: true}, messages); + for (const msg of (messages?.messages || messages || [])) { + const id = msg.id ?? msg; + try { + const full = await messenger.messages.getFull(id); + const text = full?.parts?.[0]?.body || ""; + const criterion = (await browser.storage.local.get("autoCriterion")).autoCriterion || ""; + const matched = await AiClassifier.classifyText(text, criterion); + if (matched) { + await messenger.messages.update(id, {tags: ["$label1"]}); + } + } catch (e) { + logger.aiLog("failed to classify new mail", {level: 'error'}, e); } - } catch (e) { - logger.aiLog("failed to classify new mail", {level: 'error'}, e); } - } -}); + }); +} else { + logger.aiLog("messenger.messages API unavailable, skipping new mail listener", {level: 'warn'}); +} // Catch any unhandled rejections window.addEventListener("unhandledrejection", ev => { From 6891b9d594ba02bea4d4dd1a8e3d2003d8a786db Mon Sep 17 00:00:00 2001 From: Jordan Wages Date: Tue, 24 Jun 2025 23:26:45 -0500 Subject: [PATCH 016/148] Add AGENTS guidelines --- AGENTS.md | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 AGENTS.md diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..77eb722 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,40 @@ +# AGENTS Guidelines for Sortana + +This file provides guidelines for codex agents contributing to the Sortana project. It describes the repository structure, the expected coding conventions, and testing commands. If a section is not applicable yet, you may leave it blank or provide placeholders. + +## Repository Overview + +- `background.js`: Handles startup tasks and message passing between the extension and experiment APIs. +- `experiment/`: Contains the privileged API scripts used by Thunderbird. +- `modules/`: Holds reusable JavaScript modules for the extension. +- `content/`: Scripts for modifying Thunderbird windows (e.g., the filter editor). +- `options/`: The options page HTML and JavaScript. +- `resources/`: Images and other static files. +- `prompt_templates/`: Prompt template files for the AI service. +- `build-xpi.ps1`: PowerShell script to package the extension. + +## Coding Style + +- Use **modern JavaScript** (ES6 or later). Prefer `const` and `let` over `var`. +- Keep functions small and focused. Aim for clear naming and concise comments when necessary. +- Use template literals for string interpolation. +- Avoid trailing whitespace and ensure files end with a newline. + +## Commit Guidelines + +- Group related changes together. Each commit should have a clear purpose. +- Use descriptive commit messages in the imperative mood (e.g., "Add filter editor patch"). +- Run `git status` before committing to verify only intended files are staged. + +## Testing + +There are currently no automated tests for this project. If you add tests in the future, specify the commands to run them here. For now, verify the extension manually in Thunderbird. + +## Documentation + +Additional documentation might exist outside this repository. Replace the placeholders below with the correct URLs if available. + +- Development guide: +- Issue tracker: +- Extension homepage: + From c3ebf5f53016c6e40246885d18790ba93aa86d84 Mon Sep 17 00:00:00 2001 From: Jordan Wages Date: Tue, 24 Jun 2025 23:34:59 -0500 Subject: [PATCH 017/148] Update AGENTS.md Fill in specifics. --- AGENTS.md | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 77eb722..94919e9 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,6 +1,6 @@ # AGENTS Guidelines for Sortana -This file provides guidelines for codex agents contributing to the Sortana project. It describes the repository structure, the expected coding conventions, and testing commands. If a section is not applicable yet, you may leave it blank or provide placeholders. +This file provides guidelines for codex agents contributing to the Sortana project. It describes the repository structure, the expected coding conventions, and testing commands. If you make changes to Sortana, make sure to update this document and the README.md if applicable. ## Repository Overview @@ -28,13 +28,14 @@ This file provides guidelines for codex agents contributing to the Sortana proje ## Testing -There are currently no automated tests for this project. If you add tests in the future, specify the commands to run them here. For now, verify the extension manually in Thunderbird. +There are currently no automated tests for this project. If you add tests in the future, specify the commands to run them here. For now, verification must happen manually in Thunderbird. ## Documentation -Additional documentation might exist outside this repository. Replace the placeholders below with the correct URLs if available. +Additional documentation exists outside this repository. -- Development guide: -- Issue tracker: -- Extension homepage: +- Development guide: [Webextention-API for Thunderbird](https://webextension-api.thunderbird.net/en/stable/) + - [Messages API](https://webextension-api.thunderbird.net/en/stable/messages.html) + - [Storage API](https://webextension-api.thunderbird.net/en/stable/storage.html) +- Issue tracker: [Thunderbird tracker on Bugzilla](https://bugzilla.mozilla.org/describecomponents.cgi?product=Thunderbird) From a7d2aca60f2d291fb6c71fdaa53cfc7110c6ec95 Mon Sep 17 00:00:00 2001 From: Jordan Wages Date: Tue, 24 Jun 2025 23:35:45 -0500 Subject: [PATCH 018/148] Update manifest.json --- manifest.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/manifest.json b/manifest.json index bea687f..0764b49 100644 --- a/manifest.json +++ b/manifest.json @@ -1,13 +1,13 @@ { "manifest_version": 2, "name": "Sortana", - "version": "1.2.2", + "version": "1.3.0", "default_locale": "en-US", "applications": { "gecko": { "id": "ai-filter@jordanwages", "strict_min_version": "128.0", - "strict_max_version": "139.*" + "strict_max_version": "*" } }, "icons": { @@ -42,5 +42,5 @@ "page": "options/options.html", "open_in_tab": true }, - "permissions": [ "storage" ] + "permissions": [ "storage", "messagesRead" ] } From 83166c8c4f185c151489d61113b980ab61013e49 Mon Sep 17 00:00:00 2001 From: Jordan Wages Date: Wed, 25 Jun 2025 00:24:59 -0500 Subject: [PATCH 019/148] Convert AiClassifier to ES module --- background.js | 8 +- experiment/api.js | 2 +- modules/{AiClassifier.jsm => AiClassifier.js} | 132 +++++++++--------- modules/ExpressionSearchFilter.jsm | 2 +- options/options.js | 2 + 5 files changed, 69 insertions(+), 77 deletions(-) rename modules/{AiClassifier.jsm => AiClassifier.js} (64%) diff --git a/background.js b/background.js index b05809f..56b0096 100644 --- a/background.js +++ b/background.js @@ -17,12 +17,8 @@ let AiClassifier; logger = await import(browser.runtime.getURL("logger.js")); logger.aiLog("background.js loaded – ready to classify", {debug: true}); try { - if (typeof ChromeUtils !== "undefined") { - ({ AiClassifier } = ChromeUtils.import("resource://aifilter/modules/AiClassifier.jsm")); - logger.aiLog("AiClassifier imported", {debug: true}); - } else { - logger.aiLog("ChromeUtils is undefined, skipping AiClassifier import", {level: 'warn'}); - } + AiClassifier = await import(browser.runtime.getURL('modules/AiClassifier.js')); + logger.aiLog("AiClassifier imported", {debug: true}); } catch (e) { logger.aiLog("failed to import AiClassifier", {level: 'error'}, e); } diff --git a/experiment/api.js b/experiment/api.js index 714d4fa..0523193 100644 --- a/experiment/api.js +++ b/experiment/api.js @@ -36,7 +36,7 @@ var aiFilter = class extends ExtensionCommon.ExtensionAPI { setDebug = loggerMod.setDebug; // Now that the resource URL is registered, import the classifier - ({ AiClassifier } = ChromeUtils.import("resource://aifilter/modules/AiClassifier.jsm")); + AiClassifier = ChromeUtils.importESModule("resource://aifilter/modules/AiClassifier.js"); aiLog("[api] onStartup()", {debug: true}); diff --git a/modules/AiClassifier.jsm b/modules/AiClassifier.js similarity index 64% rename from modules/AiClassifier.jsm rename to modules/AiClassifier.js index 204bf7a..039d244 100644 --- a/modules/AiClassifier.jsm +++ b/modules/AiClassifier.js @@ -1,10 +1,6 @@ "use strict"; -var { Services } = globalThis || ChromeUtils.importESModule("resource://gre/modules/Services.sys.mjs"); -var { NetUtil } = ChromeUtils.importESModule("resource://gre/modules/NetUtil.sys.mjs"); -var { FileUtils } = ChromeUtils.importESModule("resource://gre/modules/FileUtils.sys.mjs"); -var { aiLog, setDebug } = ChromeUtils.import("resource://aifilter/modules/logger.jsm"); - -var EXPORTED_SYMBOLS = ["AiClassifier"]; +import { aiLog, setDebug } from "../logger.js"; +const { Services } = globalThis || ChromeUtils.importESModule("resource://gre/modules/Services.sys.mjs"); const SYSTEM_PREFIX = `You are an email-classification assistant. Read the email below and the classification criterion provided by the user. @@ -41,36 +37,22 @@ let gAiParams = { let gCache = new Map(); let gCacheLoaded = false; -let gCacheFile; -function ensureCacheFile() { - if (!gCacheFile) { - gCacheFile = Services.dirsvc.get("ProfD", Ci.nsIFile); - gCacheFile.append("aifilter_cache.json"); - } -} - -function loadCache() { +async function loadCache() { if (gCacheLoaded) { return; } - ensureCacheFile(); - aiLog(`[AiClassifier] Loading cache from ${gCacheFile.path}`, {debug: true}); + aiLog(`[AiClassifier] Loading cache`, {debug: true}); try { - if (gCacheFile.exists()) { - let stream = Cc["@mozilla.org/network/file-input-stream;1"].createInstance(Ci.nsIFileInputStream); - stream.init(gCacheFile, -1, 0, 0); - let data = NetUtil.readInputStreamToString(stream, stream.available()); - stream.close(); - aiLog(`[AiClassifier] Cache file contents: ${data}`, {debug: true}); - let obj = JSON.parse(data); - for (let [k, v] of Object.entries(obj)) { + const { aiCache } = await browser.storage.local.get("aiCache"); + if (aiCache) { + for (let [k, v] of Object.entries(aiCache)) { aiLog(`[AiClassifier] ⮡ Loaded entry '${k}' → ${v}`, {debug: true}); gCache.set(k, v); } aiLog(`[AiClassifier] Loaded ${gCache.size} cache entries`, {debug: true}); } else { - aiLog(`[AiClassifier] Cache file does not exist`, {debug: true}); + aiLog(`[AiClassifier] Cache is empty`, {debug: true}); } } catch (e) { aiLog(`Failed to load cache`, {level: 'error'}, e); @@ -78,36 +60,33 @@ function loadCache() { gCacheLoaded = true; } -function saveCache(updatedKey, updatedValue) { - ensureCacheFile(); - aiLog(`[AiClassifier] Saving cache to ${gCacheFile.path}`, {debug: true}); +function loadCacheSync() { + if (!gCacheLoaded) { + let done = false; + loadCache().finally(() => { done = true; }); + Services.tm.spinEventLoopUntil(() => done); + } +} + +async function saveCache(updatedKey, updatedValue) { if (typeof updatedKey !== "undefined") { aiLog(`[AiClassifier] ⮡ Persisting entry '${updatedKey}' → ${updatedValue}`, {debug: true}); } try { - let obj = Object.fromEntries(gCache); - let data = JSON.stringify(obj); - let stream = Cc["@mozilla.org/network/file-output-stream;1"].createInstance(Ci.nsIFileOutputStream); - stream.init(gCacheFile, - FileUtils.MODE_WRONLY | FileUtils.MODE_CREATE | FileUtils.MODE_TRUNCATE, - FileUtils.PERMS_FILE, - 0); - stream.write(data, data.length); - stream.close(); + await browser.storage.local.set({ aiCache: Object.fromEntries(gCache) }); } catch (e) { aiLog(`Failed to save cache`, {level: 'error'}, e); } } -function loadTemplate(name) { +async function loadTemplate(name) { try { - let url = `resource://aifilter/prompt_templates/${name}.txt`; - let xhr = new XMLHttpRequest(); - xhr.open("GET", url, false); - xhr.overrideMimeType("text/plain"); - xhr.send(); - if (xhr.status === 0 || xhr.status === 200) { - return xhr.responseText; + const url = typeof browser !== "undefined" && browser.runtime?.getURL + ? browser.runtime.getURL(`prompt_templates/${name}.txt`) + : `resource://aifilter/prompt_templates/${name}.txt`; + const res = await fetch(url); + if (res.ok) { + return await res.text(); } } catch (e) { aiLog(`Failed to load template '${name}':`, {level: 'error'}, e); @@ -115,6 +94,14 @@ function loadTemplate(name) { return ""; } +function loadTemplateSync(name) { + let text = ""; + let done = false; + loadTemplate(name).then(t => { text = t; }).catch(() => {}).finally(() => { done = true; }); + Services.tm.spinEventLoopUntil(() => done); + return text; +} + function setConfig(config = {}) { if (config.endpoint) { gEndpoint = config.endpoint; @@ -138,7 +125,7 @@ function setConfig(config = {}) { if (typeof config.debugLogging === "boolean") { setDebug(config.debugLogging); } - gTemplateText = gTemplateName === "custom" ? gCustomTemplate : loadTemplate(gTemplateName); + gTemplateText = gTemplateName === "custom" ? gCustomTemplate : loadTemplateSync(gTemplateName); aiLog(`[AiClassifier] Endpoint set to ${gEndpoint}`, {debug: true}); aiLog(`[AiClassifier] Template set to ${gTemplateName}`, {debug: true}); } @@ -154,12 +141,12 @@ function buildPrompt(body, criterion) { email: body, query: criterion, }; - let template = gTemplateText || loadTemplate(gTemplateName); + let template = gTemplateText || loadTemplateSync(gTemplateName); return template.replace(/{{\s*(\w+)\s*}}/g, (m, key) => data[key] || ""); } function getCachedResult(cacheKey) { - loadCache(); + loadCacheSync(); if (cacheKey && gCache.has(cacheKey)) { aiLog(`[AiClassifier] Cache hit for key: ${cacheKey}`, {debug: true}); return gCache.get(cacheKey); @@ -202,26 +189,33 @@ function classifyTextSync(text, criterion, cacheKey = null) { aiLog(`[AiClassifier] Sending classification request to ${gEndpoint}`, {debug: true}); - let matched = false; - try { - let xhr = new XMLHttpRequest(); - xhr.open("POST", gEndpoint, false); - xhr.setRequestHeader("Content-Type", "application/json"); - xhr.send(payload); - - if (xhr.status >= 200 && xhr.status < 300) { - const result = JSON.parse(xhr.responseText); - aiLog(`[AiClassifier] Received response:`, {debug: true}, result); - matched = parseMatch(result); - cacheResult(cacheKey, matched); - } else { - aiLog(`HTTP status ${xhr.status}`, {level: 'warn'}); + let result; + let done = false; + (async () => { + try { + const response = await fetch(gEndpoint, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: payload, + }); + if (response.ok) { + const json = await response.json(); + aiLog(`[AiClassifier] Received response:`, {debug: true}, json); + result = parseMatch(json); + cacheResult(cacheKey, result); + } else { + aiLog(`HTTP status ${response.status}`, {level: 'warn'}); + result = false; + } + } catch (e) { + aiLog(`HTTP request failed`, {level: 'error'}, e); + result = false; + } finally { + done = true; } - } catch (e) { - aiLog(`HTTP request failed`, {level: 'error'}, e); - } - - return matched; + })(); + Services.tm.spinEventLoopUntil(() => done); + return result; } async function classifyText(text, criterion, cacheKey = null) { @@ -257,4 +251,4 @@ async function classifyText(text, criterion, cacheKey = null) { } } -var AiClassifier = { classifyText, classifyTextSync, setConfig }; +export { classifyText, classifyTextSync, setConfig }; diff --git a/modules/ExpressionSearchFilter.jsm b/modules/ExpressionSearchFilter.jsm index c50dd59..66e19ab 100644 --- a/modules/ExpressionSearchFilter.jsm +++ b/modules/ExpressionSearchFilter.jsm @@ -3,7 +3,7 @@ var { ExtensionParent } = ChromeUtils.importESModule("resource://gre/modules/Ext var { MailServices } = ChromeUtils.importESModule("resource:///modules/MailServices.sys.mjs"); var { Services } = globalThis || ChromeUtils.importESModule("resource://gre/modules/Services.sys.mjs"); var { aiLog } = ChromeUtils.import("resource://aifilter/modules/logger.jsm"); -var { AiClassifier } = ChromeUtils.import("resource://aifilter/modules/AiClassifier.jsm"); +var AiClassifier = ChromeUtils.importESModule("resource://aifilter/modules/AiClassifier.js"); var { getPlainText } = ChromeUtils.import("resource://aifilter/modules/messageUtils.jsm"); function sha256Hex(str) { diff --git a/options/options.js b/options/options.js index f21d9ee..a1bf0e5 100644 --- a/options/options.js +++ b/options/options.js @@ -1,5 +1,6 @@ document.addEventListener('DOMContentLoaded', async () => { const logger = await import(browser.runtime.getURL('logger.js')); + const AiClassifier = await import(browser.runtime.getURL('modules/AiClassifier.js')); const defaults = await browser.storage.local.get([ 'endpoint', 'templateName', @@ -88,6 +89,7 @@ document.addEventListener('DOMContentLoaded', async () => { await browser.storage.local.set({ endpoint, templateName, customTemplate: customTemplateText, customSystemPrompt, aiParams: aiParamsSave, debugLogging }); try { await browser.aiFilter.initConfig({ endpoint, templateName, customTemplate: customTemplateText, customSystemPrompt, aiParams: aiParamsSave, debugLogging }); + AiClassifier.setConfig({ endpoint, templateName, customTemplate: customTemplateText, customSystemPrompt, aiParams: aiParamsSave, debugLogging }); logger.setDebug(debugLogging); } catch (e) { logger.aiLog('[options] failed to apply config', {level: 'error'}, e); From f4103c4100f1d1bc15149985bf3353d0beb4e855 Mon Sep 17 00:00:00 2001 From: Jordan Wages Date: Wed, 25 Jun 2025 00:36:46 -0500 Subject: [PATCH 020/148] Remove experiment APIs and content script --- background.js | 15 +--- content/filterEditor.js | 50 ----------- experiment/DomContentScript/implementation.js | 80 ----------------- experiment/DomContentScript/schema.json | 25 ------ experiment/api.js | 89 ------------------- experiment/schema.json | 25 ------ manifest.json | 19 ---- options/options.js | 1 - 8 files changed, 3 insertions(+), 301 deletions(-) delete mode 100644 content/filterEditor.js delete mode 100644 experiment/DomContentScript/implementation.js delete mode 100644 experiment/DomContentScript/schema.json delete mode 100644 experiment/api.js delete mode 100644 experiment/schema.json diff --git a/background.js b/background.js index 56b0096..a3577b7 100644 --- a/background.js +++ b/background.js @@ -25,17 +25,8 @@ let AiClassifier; try { const store = await browser.storage.local.get(["endpoint", "templateName", "customTemplate", "customSystemPrompt", "aiParams", "debugLogging"]); logger.setDebug(store.debugLogging); - await browser.aiFilter.initConfig(store); + AiClassifier.setConfig(store); logger.aiLog("configuration loaded", {debug: true}, store); - try { - await browser.DomContentScript.registerWindow( - "chrome://messenger/content/FilterEditor.xhtml", - "resource://aifilter/content/filterEditor.js" - ); - logger.aiLog("registered FilterEditor content script", {debug: true}); - } catch (e) { - logger.aiLog("failed to register content script", {level: 'error'}, e); - } } catch (err) { logger.aiLog("failed to load config", {level: 'error'}, err); } @@ -51,8 +42,8 @@ browser.runtime.onMessage.addListener(async (msg) => { logger.aiLog("aiFilter:test – criterion", {debug: true}, criterion); try { - logger.aiLog("Calling browser.aiFilter.classify()", {debug: true}); - const result = await browser.aiFilter.classify(text, criterion); + logger.aiLog("Calling AiClassifier.classifyText()", {debug: true}); + const result = await AiClassifier.classifyText(text, criterion); logger.aiLog("classify() returned", {debug: true}, result); return { match: result }; } diff --git a/content/filterEditor.js b/content/filterEditor.js deleted file mode 100644 index cbd56bd..0000000 --- a/content/filterEditor.js +++ /dev/null @@ -1,50 +0,0 @@ -(function() { - function patch(container) { - if (!container || container.getAttribute("ai-filter-patched") === "true") { - return; - } - while (container.firstChild) { - container.firstChild.remove(); - } - let frag = window.MozXULElement.parseXULToFragment( - ` - ` - ); - container.appendChild(frag); - if (container.hasAttribute("value")) { - container.firstChild.value = container.getAttribute("value"); - } - container.classList.add("flexelementcontainer"); - container.setAttribute("ai-filter-patched", "true"); - } - - function check(node) { - if (!(node instanceof Element)) { - return; - } - if ( - node.classList.contains("search-value-custom") && - node.getAttribute("searchAttribute") === "aifilter#classification" - ) { - patch(node); - } - node - .querySelectorAll('.search-value-custom[searchAttribute="aifilter#classification"]') - .forEach(patch); - } - - const observer = new MutationObserver(mutations => { - for (let mutation of mutations) { - if (mutation.type === "childList") { - mutation.addedNodes.forEach(check); - } else if (mutation.type === "attributes") { - check(mutation.target); - } - } - }); - - const termList = document.getElementById("searchTermList") || document; - observer.observe(termList, { childList: true, attributes: true, subtree: true }); - check(termList); -})(); diff --git a/experiment/DomContentScript/implementation.js b/experiment/DomContentScript/implementation.js deleted file mode 100644 index 541facd..0000000 --- a/experiment/DomContentScript/implementation.js +++ /dev/null @@ -1,80 +0,0 @@ - - -var { AppConstants } = ChromeUtils.importESModule("resource://gre/modules/AppConstants.sys.mjs"); -var DomContent_ESM = parseInt(AppConstants.MOZ_APP_VERSION, 10) >= 128; - -var { ExtensionCommon } = ChromeUtils.importESModule( - "resource://gre/modules/ExtensionCommon.sys.mjs" -); - -var { ExtensionUtils } = DomContent_ESM - ? ChromeUtils.importESModule("resource://gre/modules/ExtensionUtils.sys.mjs") - : ChromeUtils.import("resource://gre/modules/ExtensionUtils.jsm"); - -var { ExtensionError } = ExtensionUtils; - -var registeredWindows = new Map(); - -var DomContentScript = class extends ExtensionCommon.ExtensionAPI { - constructor(extension) { - super(extension); - - this._windowListener = { - // nsIWindowMediatorListener functions - onOpenWindow(appWindow) { - // A new window has opened. - let domWindow = appWindow.docShell.domWindow; - - /** - * Set up listeners to run the callbacks on the given window. - * - * @param aWindow {nsIDOMWindow} The window to set up. - * @param aID {String} Optional. ID of the new caller that has registered right now. - */ - domWindow.addEventListener( - "DOMContentLoaded", - function() { - // do stuff - let windowChromeURL = domWindow.document.location.href; - if (registeredWindows.has(windowChromeURL)) { - let jsPath = registeredWindows.get(windowChromeURL); - Services.scriptloader.loadSubScript(jsPath, domWindow, "UTF-8"); - } - }, - { once: true } - ); - }, - - onCloseWindow(appWindow) { - // One of the windows has closed. - let domWindow = appWindow.docShell.domWindow; // we don't need to do anything (script only loads once) - }, - }; - - Services.wm.addListener(this._windowListener); - - } - - - - - - onShutdown(isAppShutdown) { - if (isAppShutdown) { - return; // the application gets unloaded anyway - } - Services.wm.removeListener(this._windowListener); - } - - getAPI(context) { - /** API IMPLEMENTATION **/ - return { - DomContentScript: { - // only returns something, if a user pref value is set - registerWindow: async function (windowUrl,jsPath) { - registeredWindows.set(windowUrl,jsPath); - } - }, - }; - } -}; diff --git a/experiment/DomContentScript/schema.json b/experiment/DomContentScript/schema.json deleted file mode 100644 index 32d779c..0000000 --- a/experiment/DomContentScript/schema.json +++ /dev/null @@ -1,25 +0,0 @@ -[ - { - "namespace": "DomContentScript", - "functions": [ - { - "name": "registerWindow", - "type": "function", - "async": true, - "description": "Register a script for onDOMContentLoaded", - "parameters": [ - { - "name": "windowUrl", - "type": "string", - "description": "chrome URL of the window " - }, - { - "name": "jsPath", - "type": "string", - "description": "chrome URL of the script" - } - ] - } - ] - } -] diff --git a/experiment/api.js b/experiment/api.js deleted file mode 100644 index 0523193..0000000 --- a/experiment/api.js +++ /dev/null @@ -1,89 +0,0 @@ -var { ExtensionCommon } = ChromeUtils.importESModule("resource://gre/modules/ExtensionCommon.sys.mjs"); -var { Services } = globalThis || ChromeUtils.importESModule("resource://gre/modules/Services.sys.mjs"); -var { MailServices } = ChromeUtils.importESModule("resource:///modules/MailServices.sys.mjs"); -var AiClassifier; - -var aiLog = (...args) => console.log("[ai-filter][api]", ...args); -var setDebug = () => {}; - -console.log("[ai-filter][api] Experiment API module loading"); - -var resProto = Cc["@mozilla.org/network/protocol;1?name=resource"] - .getService(Ci.nsISubstitutingProtocolHandler); - -function registerResourceUrl(extension, namespace) { - aiLog(`[api] registerResourceUrl called for namespace="${namespace}"`, {debug: true}); - if (resProto.hasSubstitution(namespace)) { - aiLog(`[api] namespace="${namespace}" already registered, skipping`, {debug: true}); - return; - } - let uri = Services.io.newURI(".", null, extension.rootURI); - aiLog(`[api] setting substitution for "${namespace}" → ${uri.spec}`, {debug: true}); - resProto.setSubstitutionWithFlags(namespace, uri, resProto.ALLOW_CONTENT_ACCESS); -} - -var AIFilterMod; - -var aiFilter = class extends ExtensionCommon.ExtensionAPI { - async onStartup() { - let { extension } = this; - - registerResourceUrl(extension, "aifilter"); - - // Import logger using the resource URL we just registered - let loggerMod = ChromeUtils.import("resource://aifilter/modules/logger.jsm"); - aiLog = loggerMod.aiLog; - setDebug = loggerMod.setDebug; - - // Now that the resource URL is registered, import the classifier - AiClassifier = ChromeUtils.importESModule("resource://aifilter/modules/AiClassifier.js"); - aiLog("[api] onStartup()", {debug: true}); - - - try { - aiLog("[api] importing ExpressionSearchFilter.jsm", {debug: true}); - AIFilterMod = ChromeUtils.import("resource://aifilter/modules/ExpressionSearchFilter.jsm"); - aiLog("[api] ExpressionSearchFilter.jsm import succeeded", {debug: true}); - } - catch (err) { - aiLog("[api] failed to import ExpressionSearchFilter.jsm", {level: 'error'}, err); - } - } - - onShutdown(isAppShutdown) { - aiLog("[api] onShutdown()", {debug: true}, isAppShutdown); - if (!isAppShutdown && resProto.hasSubstitution("aifilter")) { - aiLog("[api] removing substitution for namespace='aifilter'", {debug: true}); - resProto.setSubstitution("aifilter", null); - } - } - - getAPI(context) { - aiLog("[api] getAPI()", {debug: true}); - return { - aiFilter: { - initConfig: async (config) => { - try { - AiClassifier.setConfig(config); - if (typeof config.debugLogging === "boolean") { - setDebug(config.debugLogging); - } - aiLog("[api] configuration applied", {debug: true}, config); - } catch (err) { - aiLog("[api] failed to apply config", {level: 'error'}, err); - } - }, - classify: async (text, criterion) => { - aiLog("[api] classify() called", {debug: true}, text, criterion); - try { - return await AiClassifier.classifyText(text, criterion); - } - catch (err) { - aiLog("[api] error in classify()", {level: 'error'}, err); - throw err; - } - } - } - }; - } -}; diff --git a/experiment/schema.json b/experiment/schema.json deleted file mode 100644 index 991abc4..0000000 --- a/experiment/schema.json +++ /dev/null @@ -1,25 +0,0 @@ -[ - { - "namespace": "aiFilter", - "functions": [ - { - "name": "initConfig", - "type": "function", - "async": true, - "parameters": [ - { "name": "config", "type": "any" } - ] - }, - { - "name": "classify", - "type": "function", - "parameters": [ - { - "name": "msg", - "type": "any" - } - ] - } - ] - } -] diff --git a/manifest.json b/manifest.json index 0764b49..12430c7 100644 --- a/manifest.json +++ b/manifest.json @@ -19,25 +19,6 @@ "128": "resources/img/logo128.png" }, "background": { "scripts": [ "background.js" ] }, - "experiment_apis": { - "aiFilter": { - "schema": "experiment/schema.json", - "parent": { - "scopes": [ "addon_parent" ], - "paths": [ [ "aiFilter" ] ], - "script": "experiment/api.js", - "events": [ "startup" ] - } - }, - "DomContentScript": { - "schema": "experiment/DomContentScript/schema.json", - "parent": { - "scopes": [ "addon_parent" ], - "paths": [ [ "DomContentScript" ] ], - "script": "experiment/DomContentScript/implementation.js" - } - } - }, "options_ui": { "page": "options/options.html", "open_in_tab": true diff --git a/options/options.js b/options/options.js index a1bf0e5..dfc3bd9 100644 --- a/options/options.js +++ b/options/options.js @@ -88,7 +88,6 @@ document.addEventListener('DOMContentLoaded', async () => { const debugLogging = debugToggle.checked; await browser.storage.local.set({ endpoint, templateName, customTemplate: customTemplateText, customSystemPrompt, aiParams: aiParamsSave, debugLogging }); try { - await browser.aiFilter.initConfig({ endpoint, templateName, customTemplate: customTemplateText, customSystemPrompt, aiParams: aiParamsSave, debugLogging }); AiClassifier.setConfig({ endpoint, templateName, customTemplate: customTemplateText, customSystemPrompt, aiParams: aiParamsSave, debugLogging }); logger.setDebug(debugLogging); } catch (e) { From c364238f54d823a8a23f827e53e8a14c083ce781 Mon Sep 17 00:00:00 2001 From: Jordan Wages Date: Wed, 25 Jun 2025 00:44:15 -0500 Subject: [PATCH 021/148] Add rule management UI and automatic classification --- README.md | 3 ++- background.js | 28 ++++++++++++++++---- options/options.html | 22 +++++++++++++++- options/options.js | 63 ++++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 107 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index e6b8e41..bda2023 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,7 @@ message meets a specified criterion. - **Persistent result caching** – classification results are saved to disk so messages aren't re-evaluated across restarts. - **Advanced parameters** – tune generation settings like temperature, top‑p and more from the options page. - **Debug logging** – optional colorized logs help troubleshoot interactions with the AI service. +- **Automatic rules** – create rules that tag or move new messages based on AI classification. - **Packaging script** – `build-xpi.ps1` builds an XPI ready for installation. ## Architecture Overview @@ -45,7 +46,7 @@ APIs: | `modules/ExpressionSearchFilter.jsm` | Custom filter term and AI request logic. | | `experiment/api.js` | Bridges WebExtension code with privileged APIs.| | `content/filterEditor.js` | Patches the filter editor interface. | -| `options/options.html` and `options.js` | Endpoint configuration UI. | +| `options/options.html` and `options.js` | Endpoint and rule configuration UI. | | `logger.js` and `modules/logger.jsm` | Colorized logging with optional debug mode. | ## Building diff --git a/background.js b/background.js index a3577b7..a51028a 100644 --- a/background.js +++ b/background.js @@ -12,6 +12,12 @@ let logger; let AiClassifier; +let aiRules = []; + +async function sha256Hex(str) { + const buf = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(str)); + return Array.from(new Uint8Array(buf), b => b.toString(16).padStart(2, '0')).join(''); +} // Startup (async () => { logger = await import(browser.runtime.getURL("logger.js")); @@ -23,9 +29,10 @@ let AiClassifier; logger.aiLog("failed to import AiClassifier", {level: 'error'}, e); } try { - const store = await browser.storage.local.get(["endpoint", "templateName", "customTemplate", "customSystemPrompt", "aiParams", "debugLogging"]); + const store = await browser.storage.local.get(["endpoint", "templateName", "customTemplate", "customSystemPrompt", "aiParams", "debugLogging", "aiRules"]); logger.setDebug(store.debugLogging); AiClassifier.setConfig(store); + aiRules = Array.isArray(store.aiRules) ? store.aiRules : []; logger.aiLog("configuration loaded", {debug: true}, store); } catch (err) { logger.aiLog("failed to load config", {level: 'error'}, err); @@ -62,15 +69,26 @@ browser.runtime.onMessage.addListener(async (msg) => { if (typeof messenger !== "undefined" && messenger.messages?.onNewMailReceived) { messenger.messages.onNewMailReceived.addListener(async (folder, messages) => { logger.aiLog("onNewMailReceived", {debug: true}, messages); + if (!aiRules.length) { + const { aiRules: stored } = await browser.storage.local.get("aiRules"); + aiRules = Array.isArray(stored) ? stored : []; + } for (const msg of (messages?.messages || messages || [])) { const id = msg.id ?? msg; try { const full = await messenger.messages.getFull(id); const text = full?.parts?.[0]?.body || ""; - const criterion = (await browser.storage.local.get("autoCriterion")).autoCriterion || ""; - const matched = await AiClassifier.classifyText(text, criterion); - if (matched) { - await messenger.messages.update(id, {tags: ["$label1"]}); + for (const rule of aiRules) { + const cacheKey = await sha256Hex(`${id}|${rule.criterion}`); + const matched = await AiClassifier.classifyText(text, rule.criterion, cacheKey); + if (matched) { + if (rule.tag) { + await messenger.messages.update(id, {tags: [rule.tag]}); + } + if (rule.moveTo) { + await messenger.messages.move([id], rule.moveTo); + } + } } } catch (e) { logger.aiLog("failed to classify new mail", {level: 'error'}, e); diff --git a/options/options.html b/options/options.html index b758309..ed239cd 100644 --- a/options/options.html +++ b/options/options.html @@ -78,6 +78,21 @@ flex-wrap: wrap; } + #rules-container { + margin-top: 10px; + } + + .rule { + border: 1px solid #ccc; + padding: 10px; + margin-bottom: 10px; + border-radius: 4px; + } + + .rule-actions { + margin-top: 10px; + } + button { padding: 10px 20px; border: none; @@ -197,8 +212,13 @@ + +


+

Classification Rules

+
+ - \ No newline at end of file + diff --git a/options/options.js b/options/options.js index dfc3bd9..aaa86a8 100644 --- a/options/options.js +++ b/options/options.js @@ -7,7 +7,8 @@ document.addEventListener('DOMContentLoaded', async () => { 'customTemplate', 'customSystemPrompt', 'aiParams', - 'debugLogging' + 'debugLogging', + 'aiRules' ]); logger.setDebug(defaults.debugLogging === true); const DEFAULT_AI_PARAMS = { @@ -72,6 +73,59 @@ document.addEventListener('DOMContentLoaded', async () => { systemBox.value = DEFAULT_SYSTEM; }); + const rulesContainer = document.getElementById('rules-container'); + const addRuleBtn = document.getElementById('add-rule'); + + function renderRules(rules = []) { + rulesContainer.innerHTML = ''; + for (const rule of rules) { + const div = document.createElement('div'); + div.className = 'rule'; + + const critInput = document.createElement('input'); + critInput.type = 'text'; + critInput.placeholder = 'Criterion'; + critInput.value = rule.criterion || ''; + + const tagInput = document.createElement('input'); + tagInput.type = 'text'; + tagInput.placeholder = 'Tag (e.g. $label1)'; + tagInput.value = rule.tag || ''; + + const moveInput = document.createElement('input'); + moveInput.type = 'text'; + moveInput.placeholder = 'Folder URL'; + moveInput.value = rule.moveTo || ''; + + const actionsDiv = document.createElement('div'); + actionsDiv.className = 'rule-actions'; + + const delBtn = document.createElement('button'); + delBtn.textContent = 'Delete'; + delBtn.type = 'button'; + delBtn.addEventListener('click', () => div.remove()); + + actionsDiv.appendChild(delBtn); + + div.appendChild(critInput); + div.appendChild(tagInput); + div.appendChild(moveInput); + div.appendChild(actionsDiv); + + rulesContainer.appendChild(div); + } + } + + addRuleBtn.addEventListener('click', () => { + renderRules([...rulesContainer.querySelectorAll('.rule')].map(el => ({ + criterion: el.children[0].value, + tag: el.children[1].value, + moveTo: el.children[2].value + })).concat([{ criterion: '', tag: '', moveTo: '' }])); + }); + + renderRules(defaults.aiRules || []); + document.getElementById('save').addEventListener('click', async () => { const endpoint = document.getElementById('endpoint').value; const templateName = templateSelect.value; @@ -86,7 +140,12 @@ document.addEventListener('DOMContentLoaded', async () => { } } const debugLogging = debugToggle.checked; - await browser.storage.local.set({ endpoint, templateName, customTemplate: customTemplateText, customSystemPrompt, aiParams: aiParamsSave, debugLogging }); + const rules = [...rulesContainer.querySelectorAll('.rule')].map(el => ({ + criterion: el.children[0].value, + tag: el.children[1].value, + moveTo: el.children[2].value + })).filter(r => r.criterion); + await browser.storage.local.set({ endpoint, templateName, customTemplate: customTemplateText, customSystemPrompt, aiParams: aiParamsSave, debugLogging, aiRules: rules }); try { AiClassifier.setConfig({ endpoint, templateName, customTemplate: customTemplateText, customSystemPrompt, aiParams: aiParamsSave, debugLogging }); logger.setDebug(debugLogging); From 2c9a0677b49e8e6d4a464667e86e2fd707a09c7c Mon Sep 17 00:00:00 2001 From: Jordan Wages Date: Wed, 25 Jun 2025 00:58:32 -0500 Subject: [PATCH 022/148] Update README usage and permissions --- README.md | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index bda2023..b6fdcf2 100644 --- a/README.md +++ b/README.md @@ -24,17 +24,13 @@ message meets a specified criterion. ## Architecture Overview -The extension relies on both WebExtension scripts and Thunderbird's experiment -APIs: +Sortana is implemented entirely with WebExtension scripts: -- `background.js` loads the saved endpoint, registers the UI patching script, - and listens for test messages. -- `experiment/api.js` exposes the `aiFilter` namespace. It loads - `modules/ExpressionSearchFilter.jsm` which implements the custom filter term - and performs the HTTP request. -- `experiment/DomContentScript/` registers content scripts for Thunderbird - windows; `content/filterEditor.js` modifies the filter editor UI. -- `options/` contains the HTML and JavaScript for the options page. +- `background.js` loads saved settings and listens for new messages. +- `modules/ExpressionSearchFilter.jsm` implements the AI filter and performs the + HTTP request. +- `options/` contains the HTML and JavaScript for configuring the endpoint and + rules. - `_locales/` holds localized strings used throughout the UI. ### Key Files @@ -61,11 +57,10 @@ the version from `manifest.json` and creates an XPI in the `release` folder. ## Usage 1. Open the add-on's options and set the URL of your classification service. -2. Create or edit a filter in Thunderbird and choose the **AI classification** - term. Enter the desired criterion (for example, a short description of the - messages you want to match). -3. When the filter runs, the add-on sends the message text to the service and - checks the JSON response for a match. +2. Use the **Classification Rules** section to add a criterion and optional + actions such as tagging or moving a message when it matches. +3. Save your settings. New mail will be evaluated automatically using the + configured rules. ### Example Filters @@ -92,7 +87,16 @@ Here are some useful and fun example criteria you can use in your filters. Filte - **"Would I roll my eyes reading this email?"** For when you're ready to filter based on vibes. -You can define as many filters as you'd like, each using a different prompt and triggering tags, moves, or actions based on the model's classification. +You can define as many filters as you'd like, each using a different prompt and +triggering tags, moves, or actions based on the model's classification. + +## Required Permissions + +Sortana requests the following Thunderbird permissions: + +- `storage` – store configuration and cached classification results. +- `messagesRead` – read message contents for classification. +- `messagesMove` – move messages when a rule specifies a target folder. ## License From a7670547fd9146ed9fc90520eeadf048957de287 Mon Sep 17 00:00:00 2001 From: Jordan Wages Date: Wed, 25 Jun 2025 01:51:31 -0500 Subject: [PATCH 023/148] Fix initialization and remove Services dependency --- background.js | 32 ++++++++++++++++++-------------- modules/AiClassifier.js | 31 ++++++++++++++++++++++++++++--- options/options.js | 2 +- 3 files changed, 47 insertions(+), 18 deletions(-) diff --git a/background.js b/background.js index a51028a..bd6f28d 100644 --- a/background.js +++ b/background.js @@ -18,30 +18,32 @@ async function sha256Hex(str) { const buf = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(str)); return Array.from(new Uint8Array(buf), b => b.toString(16).padStart(2, '0')).join(''); } -// Startup + (async () => { logger = await import(browser.runtime.getURL("logger.js")); - logger.aiLog("background.js loaded – ready to classify", {debug: true}); try { - AiClassifier = await import(browser.runtime.getURL('modules/AiClassifier.js')); + AiClassifier = await import(browser.runtime.getURL("modules/AiClassifier.js")); logger.aiLog("AiClassifier imported", {debug: true}); } catch (e) { - logger.aiLog("failed to import AiClassifier", {level: 'error'}, e); + console.error("failed to import AiClassifier", e); + return; } + try { const store = await browser.storage.local.get(["endpoint", "templateName", "customTemplate", "customSystemPrompt", "aiParams", "debugLogging", "aiRules"]); logger.setDebug(store.debugLogging); - AiClassifier.setConfig(store); + await AiClassifier.setConfig(store); aiRules = Array.isArray(store.aiRules) ? store.aiRules : []; logger.aiLog("configuration loaded", {debug: true}, store); } catch (err) { logger.aiLog("failed to load config", {level: 'error'}, err); } -})(); -// Listen for messages from UI/devtools -browser.runtime.onMessage.addListener(async (msg) => { - logger.aiLog("onMessage received", {debug: true}, msg); + logger.aiLog("background.js loaded – ready to classify", {debug: true}); + + // Listen for messages from UI/devtools + browser.runtime.onMessage.addListener(async (msg) => { + logger.aiLog("onMessage received", {debug: true}, msg); if (msg?.type === "aiFilter:test") { const { text = "", criterion = "" } = msg; @@ -104,8 +106,10 @@ window.addEventListener("unhandledrejection", ev => { logger.aiLog("Unhandled promise rejection", {level: 'error'}, ev.reason); }); -browser.runtime.onInstalled.addListener(async ({ reason }) => { - if (reason === "install") { - await browser.runtime.openOptionsPage(); - } -}); + browser.runtime.onInstalled.addListener(async ({ reason }) => { + if (reason === "install") { + await browser.runtime.openOptionsPage(); + } + }); + +})(); diff --git a/modules/AiClassifier.js b/modules/AiClassifier.js index 039d244..fbb0a36 100644 --- a/modules/AiClassifier.js +++ b/modules/AiClassifier.js @@ -1,6 +1,16 @@ "use strict"; import { aiLog, setDebug } from "../logger.js"; -const { Services } = globalThis || ChromeUtils.importESModule("resource://gre/modules/Services.sys.mjs"); + +let Services; +try { + if (typeof globalThis !== "undefined" && globalThis.Services) { + Services = globalThis.Services; + } else if (typeof ChromeUtils !== "undefined" && ChromeUtils.importESModule) { + ({ Services } = ChromeUtils.importESModule("resource://gre/modules/Services.sys.mjs")); + } +} catch (e) { + Services = undefined; +} const SYSTEM_PREFIX = `You are an email-classification assistant. Read the email below and the classification criterion provided by the user. @@ -62,6 +72,9 @@ async function loadCache() { function loadCacheSync() { if (!gCacheLoaded) { + if (!Services?.tm?.spinEventLoopUntil) { + throw new Error("loadCacheSync requires Services"); + } let done = false; loadCache().finally(() => { done = true; }); Services.tm.spinEventLoopUntil(() => done); @@ -95,6 +108,9 @@ async function loadTemplate(name) { } function loadTemplateSync(name) { + if (!Services?.tm?.spinEventLoopUntil) { + throw new Error("loadTemplateSync requires Services"); + } let text = ""; let done = false; loadTemplate(name).then(t => { text = t; }).catch(() => {}).finally(() => { done = true; }); @@ -102,7 +118,7 @@ function loadTemplateSync(name) { return text; } -function setConfig(config = {}) { +async function setConfig(config = {}) { if (config.endpoint) { gEndpoint = config.endpoint; } @@ -125,7 +141,13 @@ function setConfig(config = {}) { if (typeof config.debugLogging === "boolean") { setDebug(config.debugLogging); } - gTemplateText = gTemplateName === "custom" ? gCustomTemplate : loadTemplateSync(gTemplateName); + if (gTemplateName === "custom") { + gTemplateText = gCustomTemplate; + } else if (Services?.tm?.spinEventLoopUntil) { + gTemplateText = loadTemplateSync(gTemplateName); + } else { + gTemplateText = await loadTemplate(gTemplateName); + } aiLog(`[AiClassifier] Endpoint set to ${gEndpoint}`, {debug: true}); aiLog(`[AiClassifier] Template set to ${gTemplateName}`, {debug: true}); } @@ -180,6 +202,9 @@ function cacheResult(cacheKey, matched) { } function classifyTextSync(text, criterion, cacheKey = null) { + if (!Services?.tm?.spinEventLoopUntil) { + throw new Error("classifyTextSync requires Services"); + } const cached = getCachedResult(cacheKey); if (cached !== null) { return cached; diff --git a/options/options.js b/options/options.js index aaa86a8..ecca4a5 100644 --- a/options/options.js +++ b/options/options.js @@ -147,7 +147,7 @@ document.addEventListener('DOMContentLoaded', async () => { })).filter(r => r.criterion); await browser.storage.local.set({ endpoint, templateName, customTemplate: customTemplateText, customSystemPrompt, aiParams: aiParamsSave, debugLogging, aiRules: rules }); try { - AiClassifier.setConfig({ endpoint, templateName, customTemplate: customTemplateText, customSystemPrompt, aiParams: aiParamsSave, debugLogging }); + await AiClassifier.setConfig({ endpoint, templateName, customTemplate: customTemplateText, customSystemPrompt, aiParams: aiParamsSave, debugLogging }); logger.setDebug(debugLogging); } catch (e) { logger.aiLog('[options] failed to apply config', {level: 'error'}, e); From b23d6016377c2a4f865b864db9f418b00b6449af Mon Sep 17 00:00:00 2001 From: Jordan Wages Date: Wed, 25 Jun 2025 03:02:46 -0500 Subject: [PATCH 024/148] Adding persmission. --- AGENTS.md | 1 + background.js | 2 +- manifest.json | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 94919e9..3737e80 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -36,6 +36,7 @@ Additional documentation exists outside this repository. - Development guide: [Webextention-API for Thunderbird](https://webextension-api.thunderbird.net/en/stable/) - [Messages API](https://webextension-api.thunderbird.net/en/stable/messages.html) + - [Message Tags API](https://webextension-api.thunderbird.net/en/stable/messages.tags.html) - [Storage API](https://webextension-api.thunderbird.net/en/stable/storage.html) - Issue tracker: [Thunderbird tracker on Bugzilla](https://bugzilla.mozilla.org/describecomponents.cgi?product=Thunderbird) diff --git a/background.js b/background.js index bd6f28d..20a2573 100644 --- a/background.js +++ b/background.js @@ -98,7 +98,7 @@ if (typeof messenger !== "undefined" && messenger.messages?.onNewMailReceived) { } }); } else { - logger.aiLog("messenger.messages API unavailable, skipping new mail listener", {level: 'warn'}); + logger.aiLog("messenger.messages API unavailable, skipping new mail listener", { level: 'warn' }); } // Catch any unhandled rejections diff --git a/manifest.json b/manifest.json index 12430c7..bf9dda7 100644 --- a/manifest.json +++ b/manifest.json @@ -23,5 +23,5 @@ "page": "options/options.html", "open_in_tab": true }, - "permissions": [ "storage", "messagesRead" ] + "permissions": [ "storage", "messagesRead", "accountsRead" ] } From 74fb932b45cb4064fe08519f511da10155ab92a4 Mon Sep 17 00:00:00 2001 From: Jordan Wages Date: Wed, 25 Jun 2025 03:23:13 -0500 Subject: [PATCH 025/148] Add multi-action rules UI --- README.md | 3 + background.js | 29 +++++-- manifest.json | 9 ++- options/options.html | 29 ++++++- options/options.js | 178 ++++++++++++++++++++++++++++++++++++------- 5 files changed, 212 insertions(+), 36 deletions(-) diff --git a/README.md b/README.md index b6fdcf2..7b23f1c 100644 --- a/README.md +++ b/README.md @@ -97,6 +97,9 @@ Sortana requests the following Thunderbird permissions: - `storage` – store configuration and cached classification results. - `messagesRead` – read message contents for classification. - `messagesMove` – move messages when a rule specifies a target folder. +- `messagesUpdate` – change message properties such as tags and junk status. +- `messagesTagsList` – retrieve existing message tags for rule actions. +- `accountsRead` – list accounts and folders for move actions. ## License diff --git a/background.js b/background.js index 20a2573..b2182d6 100644 --- a/background.js +++ b/background.js @@ -33,7 +33,13 @@ async function sha256Hex(str) { const store = await browser.storage.local.get(["endpoint", "templateName", "customTemplate", "customSystemPrompt", "aiParams", "debugLogging", "aiRules"]); logger.setDebug(store.debugLogging); await AiClassifier.setConfig(store); - aiRules = Array.isArray(store.aiRules) ? store.aiRules : []; + aiRules = Array.isArray(store.aiRules) ? store.aiRules.map(r => { + if (r.actions) return r; + const actions = []; + if (r.tag) actions.push({ type: 'tag', tagKey: r.tag }); + if (r.moveTo) actions.push({ type: 'move', folder: r.moveTo }); + return { criterion: r.criterion, actions }; + }) : []; logger.aiLog("configuration loaded", {debug: true}, store); } catch (err) { logger.aiLog("failed to load config", {level: 'error'}, err); @@ -73,7 +79,13 @@ if (typeof messenger !== "undefined" && messenger.messages?.onNewMailReceived) { logger.aiLog("onNewMailReceived", {debug: true}, messages); if (!aiRules.length) { const { aiRules: stored } = await browser.storage.local.get("aiRules"); - aiRules = Array.isArray(stored) ? stored : []; + aiRules = Array.isArray(stored) ? stored.map(r => { + if (r.actions) return r; + const actions = []; + if (r.tag) actions.push({ type: 'tag', tagKey: r.tag }); + if (r.moveTo) actions.push({ type: 'move', folder: r.moveTo }); + return { criterion: r.criterion, actions }; + }) : []; } for (const msg of (messages?.messages || messages || [])) { const id = msg.id ?? msg; @@ -84,11 +96,14 @@ if (typeof messenger !== "undefined" && messenger.messages?.onNewMailReceived) { const cacheKey = await sha256Hex(`${id}|${rule.criterion}`); const matched = await AiClassifier.classifyText(text, rule.criterion, cacheKey); if (matched) { - if (rule.tag) { - await messenger.messages.update(id, {tags: [rule.tag]}); - } - if (rule.moveTo) { - await messenger.messages.move([id], rule.moveTo); + for (const act of (rule.actions || [])) { + if (act.type === 'tag' && act.tagKey) { + await messenger.messages.update(id, {tags: [act.tagKey]}); + } else if (act.type === 'move' && act.folder) { + await messenger.messages.move([id], act.folder); + } else if (act.type === 'junk') { + await messenger.messages.update(id, {junk: !!act.junk}); + } } } } diff --git a/manifest.json b/manifest.json index bf9dda7..ba4f8c4 100644 --- a/manifest.json +++ b/manifest.json @@ -23,5 +23,12 @@ "page": "options/options.html", "open_in_tab": true }, - "permissions": [ "storage", "messagesRead", "accountsRead" ] + "permissions": [ + "storage", + "messagesRead", + "messagesMove", + "messagesUpdate", + "messagesTagsList", + "accountsRead" + ] } diff --git a/options/options.html b/options/options.html index ed239cd..17af47a 100644 --- a/options/options.html +++ b/options/options.html @@ -78,6 +78,19 @@ flex-wrap: wrap; } + .tab-button { + background: #e0e0e0; + } + + .tab-button.active { + background: #007acc; + color: #fff; + } + + .tab { + margin-top: 20px; + } + #rules-container { margin-top: 10px; } @@ -93,6 +106,10 @@ margin-top: 10px; } + .action-row { + margin-bottom: 5px; + } + button { padding: 10px 20px; border: none; @@ -132,7 +149,13 @@ AI Filter Logo + +
+
@@ -213,10 +236,14 @@
-
+ + + +
diff --git a/options/options.js b/options/options.js index ecca4a5..9c3ff00 100644 --- a/options/options.js +++ b/options/options.js @@ -10,6 +10,16 @@ document.addEventListener('DOMContentLoaded', async () => { 'debugLogging', 'aiRules' ]); + const tabButtons = document.querySelectorAll('.tab-button'); + const tabs = document.querySelectorAll('.tab'); + tabButtons.forEach(btn => btn.addEventListener('click', () => { + tabButtons.forEach(b => b.classList.remove('active')); + btn.classList.add('active'); + tabs.forEach(tab => { + tab.style.display = tab.id === `${btn.dataset.tab}-tab` ? 'block' : 'none'; + }); + })); + tabButtons[0]?.click(); logger.setDebug(defaults.debugLogging === true); const DEFAULT_AI_PARAMS = { max_tokens: 4096, @@ -66,6 +76,26 @@ document.addEventListener('DOMContentLoaded', async () => { if (el) el.value = val; } + let tagList = []; + let folderList = []; + try { + tagList = await messenger.messages.tags.list(); + } catch (e) { + logger.aiLog('failed to list tags', {level:'error'}, e); + } + try { + const accounts = await messenger.accounts.list(true); + const collect = (f, prefix='') => { + folderList.push({ id: f.id ?? f.path, name: prefix + f.name }); + (f.subFolders || []).forEach(sf => collect(sf, prefix + f.name + '/')); + }; + for (const acct of accounts) { + (acct.folders || []).forEach(f => collect(f, `${acct.name}/`)); + } + } catch (e) { + logger.aiLog('failed to list folders', {level:'error'}, e); + } + const DEFAULT_SYSTEM = 'Determine whether the email satisfies the user\'s criterion.'; const systemBox = document.getElementById('system-instructions'); systemBox.value = defaults.customSystemPrompt || DEFAULT_SYSTEM; @@ -76,6 +106,70 @@ document.addEventListener('DOMContentLoaded', async () => { const rulesContainer = document.getElementById('rules-container'); const addRuleBtn = document.getElementById('add-rule'); + function createActionRow(action = {type: 'tag'}) { + const row = document.createElement('div'); + row.className = 'action-row'; + + const typeSelect = document.createElement('select'); + ['tag','move','junk'].forEach(t => { + const opt = document.createElement('option'); + opt.value = t; + opt.textContent = t; + typeSelect.appendChild(opt); + }); + typeSelect.value = action.type; + + const paramSpan = document.createElement('span'); + + function updateParams() { + paramSpan.innerHTML = ''; + if (typeSelect.value === 'tag') { + const sel = document.createElement('select'); + sel.className = 'tag-select'; + for (const t of tagList) { + const opt = document.createElement('option'); + opt.value = t.key; + opt.textContent = t.tag; + sel.appendChild(opt); + } + sel.value = action.tagKey || ''; + paramSpan.appendChild(sel); + } else if (typeSelect.value === 'move') { + const sel = document.createElement('select'); + sel.className = 'folder-select'; + for (const f of folderList) { + const opt = document.createElement('option'); + opt.value = f.id; + opt.textContent = f.name; + sel.appendChild(opt); + } + sel.value = action.folder || ''; + paramSpan.appendChild(sel); + } else if (typeSelect.value === 'junk') { + const sel = document.createElement('select'); + sel.className = 'junk-select'; + sel.appendChild(new Option('mark junk','true')); + sel.appendChild(new Option('mark not junk','false')); + sel.value = String(action.junk ?? true); + paramSpan.appendChild(sel); + } + } + + typeSelect.addEventListener('change', updateParams); + updateParams(); + + const removeBtn = document.createElement('button'); + removeBtn.textContent = 'Remove'; + removeBtn.type = 'button'; + removeBtn.addEventListener('click', () => row.remove()); + + row.appendChild(typeSelect); + row.appendChild(paramSpan); + row.appendChild(removeBtn); + + return row; + } + function renderRules(rules = []) { rulesContainer.innerHTML = ''; for (const rule of rules) { @@ -86,45 +180,63 @@ document.addEventListener('DOMContentLoaded', async () => { critInput.type = 'text'; critInput.placeholder = 'Criterion'; critInput.value = rule.criterion || ''; + critInput.className = 'criterion'; - const tagInput = document.createElement('input'); - tagInput.type = 'text'; - tagInput.placeholder = 'Tag (e.g. $label1)'; - tagInput.value = rule.tag || ''; + const actionsContainer = document.createElement('div'); + actionsContainer.className = 'rule-actions'; - const moveInput = document.createElement('input'); - moveInput.type = 'text'; - moveInput.placeholder = 'Folder URL'; - moveInput.value = rule.moveTo || ''; + for (const act of (rule.actions || [])) { + actionsContainer.appendChild(createActionRow(act)); + } - const actionsDiv = document.createElement('div'); - actionsDiv.className = 'rule-actions'; + const addAction = document.createElement('button'); + addAction.textContent = 'Add Action'; + addAction.type = 'button'; + addAction.addEventListener('click', () => actionsContainer.appendChild(createActionRow())); const delBtn = document.createElement('button'); - delBtn.textContent = 'Delete'; + delBtn.textContent = 'Delete Rule'; delBtn.type = 'button'; delBtn.addEventListener('click', () => div.remove()); - actionsDiv.appendChild(delBtn); - div.appendChild(critInput); - div.appendChild(tagInput); - div.appendChild(moveInput); - div.appendChild(actionsDiv); + div.appendChild(actionsContainer); + div.appendChild(addAction); + div.appendChild(delBtn); rulesContainer.appendChild(div); } } addRuleBtn.addEventListener('click', () => { - renderRules([...rulesContainer.querySelectorAll('.rule')].map(el => ({ - criterion: el.children[0].value, - tag: el.children[1].value, - moveTo: el.children[2].value - })).concat([{ criterion: '', tag: '', moveTo: '' }])); + const data = [...rulesContainer.querySelectorAll('.rule')].map(ruleEl => { + const criterion = ruleEl.querySelector('.criterion').value; + const actions = [...ruleEl.querySelectorAll('.action-row')].map(row => { + const type = row.querySelector('select').value; + if (type === 'tag') { + return { type, tagKey: row.querySelector('.tag-select').value }; + } + if (type === 'move') { + return { type, folder: row.querySelector('.folder-select').value }; + } + if (type === 'junk') { + return { type, junk: row.querySelector('.junk-select').value === 'true' }; + } + return { type }; + }); + return { criterion, actions }; + }); + data.push({ criterion: '', actions: [] }); + renderRules(data); }); - renderRules(defaults.aiRules || []); + renderRules((defaults.aiRules || []).map(r => { + if (r.actions) return r; + const actions = []; + if (r.tag) actions.push({ type: 'tag', tagKey: r.tag }); + if (r.moveTo) actions.push({ type: 'move', folder: r.moveTo }); + return { criterion: r.criterion, actions }; + })); document.getElementById('save').addEventListener('click', async () => { const endpoint = document.getElementById('endpoint').value; @@ -140,11 +252,23 @@ document.addEventListener('DOMContentLoaded', async () => { } } const debugLogging = debugToggle.checked; - const rules = [...rulesContainer.querySelectorAll('.rule')].map(el => ({ - criterion: el.children[0].value, - tag: el.children[1].value, - moveTo: el.children[2].value - })).filter(r => r.criterion); + const rules = [...rulesContainer.querySelectorAll('.rule')].map(ruleEl => { + const criterion = ruleEl.querySelector('.criterion').value; + const actions = [...ruleEl.querySelectorAll('.action-row')].map(row => { + const type = row.querySelector('select').value; + if (type === 'tag') { + return { type, tagKey: row.querySelector('.tag-select').value }; + } + if (type === 'move') { + return { type, folder: row.querySelector('.folder-select').value }; + } + if (type === 'junk') { + return { type, junk: row.querySelector('.junk-select').value === 'true' }; + } + return { type }; + }); + return { criterion, actions }; + }).filter(r => r.criterion); await browser.storage.local.set({ endpoint, templateName, customTemplate: customTemplateText, customSystemPrompt, aiParams: aiParamsSave, debugLogging, aiRules: rules }); try { await AiClassifier.setConfig({ endpoint, templateName, customTemplate: customTemplateText, customSystemPrompt, aiParams: aiParamsSave, debugLogging }); From dceebe48de159e27039f54fb5cff79f488c88023 Mon Sep 17 00:00:00 2001 From: Jordan Wages Date: Wed, 25 Jun 2025 14:15:09 -0500 Subject: [PATCH 026/148] Add context menu for applying AI rules --- README.md | 2 ++ background.js | 95 +++++++++++++++++++++++++++++++++------------------ manifest.json | 3 +- 3 files changed, 65 insertions(+), 35 deletions(-) diff --git a/README.md b/README.md index 7b23f1c..32eaa67 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,7 @@ message meets a specified criterion. - **Advanced parameters** – tune generation settings like temperature, top‑p and more from the options page. - **Debug logging** – optional colorized logs help troubleshoot interactions with the AI service. - **Automatic rules** – create rules that tag or move new messages based on AI classification. +- **Context menu** – apply AI rules to selected messages from the message list or display. - **Packaging script** – `build-xpi.ps1` builds an XPI ready for installation. ## Architecture Overview @@ -100,6 +101,7 @@ Sortana requests the following Thunderbird permissions: - `messagesUpdate` – change message properties such as tags and junk status. - `messagesTagsList` – retrieve existing message tags for rule actions. - `accountsRead` – list accounts and folders for move actions. +- `menus` – add context menu commands. ## License diff --git a/background.js b/background.js index b2182d6..3ffa635 100644 --- a/background.js +++ b/background.js @@ -19,6 +19,47 @@ async function sha256Hex(str) { return Array.from(new Uint8Array(buf), b => b.toString(16).padStart(2, '0')).join(''); } +async function applyAiRules(idsInput) { + const ids = Array.isArray(idsInput) ? idsInput : [idsInput]; + if (!ids.length) return; + + if (!aiRules.length) { + const { aiRules: stored } = await browser.storage.local.get("aiRules"); + aiRules = Array.isArray(stored) ? stored.map(r => { + if (r.actions) return r; + const actions = []; + if (r.tag) actions.push({ type: 'tag', tagKey: r.tag }); + if (r.moveTo) actions.push({ type: 'move', folder: r.moveTo }); + return { criterion: r.criterion, actions }; + }) : []; + } + + for (const msg of ids) { + const id = msg?.id ?? msg; + try { + const full = await messenger.messages.getFull(id); + const text = full?.parts?.[0]?.body || ""; + for (const rule of aiRules) { + const cacheKey = await sha256Hex(`${id}|${rule.criterion}`); + const matched = await AiClassifier.classifyText(text, rule.criterion, cacheKey); + if (matched) { + for (const act of (rule.actions || [])) { + if (act.type === 'tag' && act.tagKey) { + await messenger.messages.update(id, { tags: [act.tagKey] }); + } else if (act.type === 'move' && act.folder) { + await messenger.messages.move([id], act.folder); + } else if (act.type === 'junk') { + await messenger.messages.update(id, { junk: !!act.junk }); + } + } + } + } + } catch (e) { + logger.aiLog("failed to apply AI rules", { level: 'error' }, e); + } + } +} + (async () => { logger = await import(browser.runtime.getURL("logger.js")); try { @@ -47,6 +88,24 @@ async function sha256Hex(str) { logger.aiLog("background.js loaded – ready to classify", {debug: true}); + browser.menus.create({ + id: "apply-ai-rules-list", + title: "Apply AI Rules", + contexts: ["message_list"], + }); + browser.menus.create({ + id: "apply-ai-rules-display", + title: "Apply AI Rules", + contexts: ["message_display"], + }); + + browser.menus.onClicked.addListener(async info => { + if (info.menuItemId === "apply-ai-rules-list" || info.menuItemId === "apply-ai-rules-display") { + const ids = info.selectedMessages?.ids || (info.messageId ? [info.messageId] : []); + await applyAiRules(ids); + } + }); + // Listen for messages from UI/devtools browser.runtime.onMessage.addListener(async (msg) => { logger.aiLog("onMessage received", {debug: true}, msg); @@ -77,40 +136,8 @@ async function sha256Hex(str) { if (typeof messenger !== "undefined" && messenger.messages?.onNewMailReceived) { messenger.messages.onNewMailReceived.addListener(async (folder, messages) => { logger.aiLog("onNewMailReceived", {debug: true}, messages); - if (!aiRules.length) { - const { aiRules: stored } = await browser.storage.local.get("aiRules"); - aiRules = Array.isArray(stored) ? stored.map(r => { - if (r.actions) return r; - const actions = []; - if (r.tag) actions.push({ type: 'tag', tagKey: r.tag }); - if (r.moveTo) actions.push({ type: 'move', folder: r.moveTo }); - return { criterion: r.criterion, actions }; - }) : []; - } - for (const msg of (messages?.messages || messages || [])) { - const id = msg.id ?? msg; - try { - const full = await messenger.messages.getFull(id); - const text = full?.parts?.[0]?.body || ""; - for (const rule of aiRules) { - const cacheKey = await sha256Hex(`${id}|${rule.criterion}`); - const matched = await AiClassifier.classifyText(text, rule.criterion, cacheKey); - if (matched) { - for (const act of (rule.actions || [])) { - if (act.type === 'tag' && act.tagKey) { - await messenger.messages.update(id, {tags: [act.tagKey]}); - } else if (act.type === 'move' && act.folder) { - await messenger.messages.move([id], act.folder); - } else if (act.type === 'junk') { - await messenger.messages.update(id, {junk: !!act.junk}); - } - } - } - } - } catch (e) { - logger.aiLog("failed to classify new mail", {level: 'error'}, e); - } - } + const ids = (messages?.messages || messages || []).map(m => m.id ?? m); + await applyAiRules(ids); }); } else { logger.aiLog("messenger.messages API unavailable, skipping new mail listener", { level: 'warn' }); diff --git a/manifest.json b/manifest.json index ba4f8c4..cb30d19 100644 --- a/manifest.json +++ b/manifest.json @@ -29,6 +29,7 @@ "messagesMove", "messagesUpdate", "messagesTagsList", - "accountsRead" + "accountsRead", + "menus" ] } From 2341b7e475f44534593c9026028072048e015e4f Mon Sep 17 00:00:00 2001 From: Jordan Wages Date: Wed, 25 Jun 2025 14:23:53 -0500 Subject: [PATCH 027/148] Update README to remove obsolete path references --- README.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/README.md b/README.md index 32eaa67..49d436a 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ message meets a specified criterion. ## Architecture Overview -Sortana is implemented entirely with WebExtension scripts: +Sortana is implemented entirely with standard WebExtension scripts—no custom experiment code is required: - `background.js` loads saved settings and listens for new messages. - `modules/ExpressionSearchFilter.jsm` implements the AI filter and performs the @@ -41,8 +41,6 @@ Sortana is implemented entirely with WebExtension scripts: | `manifest.json` | Extension manifest and entry points. | | `background.js` | Startup tasks and message handling. | | `modules/ExpressionSearchFilter.jsm` | Custom filter term and AI request logic. | -| `experiment/api.js` | Bridges WebExtension code with privileged APIs.| -| `content/filterEditor.js` | Patches the filter editor interface. | | `options/options.html` and `options.js` | Endpoint and rule configuration UI. | | `logger.js` and `modules/logger.jsm` | Colorized logging with optional debug mode. | From a58b8f3632866addcdc02f2c6125e6f40263f6b8 Mon Sep 17 00:00:00 2001 From: Jordan Wages Date: Wed, 25 Jun 2025 14:53:19 -0500 Subject: [PATCH 028/148] Remove placeholder status icons --- README.md | 1 + background.js | 66 +++++++++++++++++++++++++++++++++++++-------------- manifest.json | 6 +++++ 3 files changed, 55 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 49d436a..f07ee24 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,7 @@ message meets a specified criterion. - **Debug logging** – optional colorized logs help troubleshoot interactions with the AI service. - **Automatic rules** – create rules that tag or move new messages based on AI classification. - **Context menu** – apply AI rules to selected messages from the message list or display. +- **Status icons** – toolbar icons indicate when messages are queued or being classified. - **Packaging script** – `build-xpi.ps1` builds an XPI ready for installation. ## Architecture Overview diff --git a/background.js b/background.js index 3ffa635..57ee75b 100644 --- a/background.js +++ b/background.js @@ -13,6 +13,24 @@ let logger; let AiClassifier; let aiRules = []; +let queue = Promise.resolve(); +let queuedCount = 0; +let processing = false; + +function updateActionIcon() { + let path = "resources/img/logo32.png"; + if (processing) { + path = "resources/img/status-classifying.png"; + } else if (queuedCount > 0) { + path = "resources/img/status-queued.png"; + } + if (browser.browserAction) { + browser.browserAction.setIcon({ path }); + } + if (browser.messageDisplayAction) { + browser.messageDisplayAction.setIcon({ path }); + } +} async function sha256Hex(str) { const buf = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(str)); @@ -21,7 +39,7 @@ async function sha256Hex(str) { async function applyAiRules(idsInput) { const ids = Array.isArray(idsInput) ? idsInput : [idsInput]; - if (!ids.length) return; + if (!ids.length) return queue; if (!aiRules.length) { const { aiRules: stored } = await browser.storage.local.get("aiRules"); @@ -36,28 +54,40 @@ async function applyAiRules(idsInput) { for (const msg of ids) { const id = msg?.id ?? msg; - try { - const full = await messenger.messages.getFull(id); - const text = full?.parts?.[0]?.body || ""; - for (const rule of aiRules) { - const cacheKey = await sha256Hex(`${id}|${rule.criterion}`); - const matched = await AiClassifier.classifyText(text, rule.criterion, cacheKey); - if (matched) { - for (const act of (rule.actions || [])) { - if (act.type === 'tag' && act.tagKey) { - await messenger.messages.update(id, { tags: [act.tagKey] }); - } else if (act.type === 'move' && act.folder) { - await messenger.messages.move([id], act.folder); - } else if (act.type === 'junk') { - await messenger.messages.update(id, { junk: !!act.junk }); + queuedCount++; + updateActionIcon(); + queue = queue.then(async () => { + processing = true; + queuedCount--; + updateActionIcon(); + try { + const full = await messenger.messages.getFull(id); + const text = full?.parts?.[0]?.body || ""; + for (const rule of aiRules) { + const cacheKey = await sha256Hex(`${id}|${rule.criterion}`); + const matched = await AiClassifier.classifyText(text, rule.criterion, cacheKey); + if (matched) { + for (const act of (rule.actions || [])) { + if (act.type === 'tag' && act.tagKey) { + await messenger.messages.update(id, { tags: [act.tagKey] }); + } else if (act.type === 'move' && act.folder) { + await messenger.messages.move([id], act.folder); + } else if (act.type === 'junk') { + await messenger.messages.update(id, { junk: !!act.junk }); + } } } } + } catch (e) { + logger.aiLog("failed to apply AI rules", { level: 'error' }, e); + } finally { + processing = false; + updateActionIcon(); } - } catch (e) { - logger.aiLog("failed to apply AI rules", { level: 'error' }, e); - } + }); } + + return queue; } (async () => { diff --git a/manifest.json b/manifest.json index cb30d19..1245a83 100644 --- a/manifest.json +++ b/manifest.json @@ -18,6 +18,12 @@ "96": "resources/img/logo96.png", "128": "resources/img/logo128.png" }, + "browser_action": { + "default_icon": "resources/img/logo32.png" + }, + "message_display_action": { + "default_icon": "resources/img/logo32.png" + }, "background": { "scripts": [ "background.js" ] }, "options_ui": { "page": "options/options.html", From fed850fe13b555519a61525ccc4d98a3ae531ff8 Mon Sep 17 00:00:00 2001 From: Jordan Wages Date: Wed, 25 Jun 2025 15:10:30 -0500 Subject: [PATCH 029/148] Update menu context for message display --- README.md | 2 +- background.js | 14 +++++++++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f07ee24..6550542 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ message meets a specified criterion. - **Advanced parameters** – tune generation settings like temperature, top‑p and more from the options page. - **Debug logging** – optional colorized logs help troubleshoot interactions with the AI service. - **Automatic rules** – create rules that tag or move new messages based on AI classification. -- **Context menu** – apply AI rules to selected messages from the message list or display. +- **Context menu** – apply AI rules from the message list or the message display action button. - **Status icons** – toolbar icons indicate when messages are queued or being classified. - **Packaging script** – `build-xpi.ps1` builds an XPI ready for installation. diff --git a/background.js b/background.js index 57ee75b..576fc9e 100644 --- a/background.js +++ b/background.js @@ -126,9 +126,21 @@ async function applyAiRules(idsInput) { browser.menus.create({ id: "apply-ai-rules-display", title: "Apply AI Rules", - contexts: ["message_display"], + contexts: ["message_display_action"], }); + if (browser.messageDisplayAction) { + browser.messageDisplayAction.onClicked.addListener(async (tab) => { + try { + const msgs = await browser.messageDisplay.getDisplayedMessages(tab.id); + const ids = msgs.map(m => m.id); + await applyAiRules(ids); + } catch (e) { + logger.aiLog("failed to apply AI rules from action", { level: 'error' }, e); + } + }); + } + browser.menus.onClicked.addListener(async info => { if (info.menuItemId === "apply-ai-rules-list" || info.menuItemId === "apply-ai-rules-display") { const ids = info.selectedMessages?.ids || (info.messageId ? [info.messageId] : []); From acff8f72db01399c7af3880fe7bfb2aa100716f8 Mon Sep 17 00:00:00 2001 From: Jordan Wages Date: Wed, 25 Jun 2025 22:00:56 -0500 Subject: [PATCH 030/148] Remove experiment references --- AGENTS.md | 3 +-- ai-filter.sln | 14 -------------- 2 files changed, 1 insertion(+), 16 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 3737e80..c74d3f4 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -4,8 +4,7 @@ This file provides guidelines for codex agents contributing to the Sortana proje ## Repository Overview -- `background.js`: Handles startup tasks and message passing between the extension and experiment APIs. -- `experiment/`: Contains the privileged API scripts used by Thunderbird. +- `background.js`: Handles startup tasks and coordinates message passing within the extension. - `modules/`: Holds reusable JavaScript modules for the extension. - `content/`: Scripts for modifying Thunderbird windows (e.g., the filter editor). - `options/`: The options page HTML and JavaScript. diff --git a/ai-filter.sln b/ai-filter.sln index f5fa952..05fa5be 100644 --- a/ai-filter.sln +++ b/ai-filter.sln @@ -14,12 +14,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Q_5_4Users_4Jordan_4Documents_4Gitea_4thunderbird-ai-filter_4src_4manifest_1json__JsonSchema = EndProjectSection EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "experiment", "experiment", "{F2C8C786-FA23-4B63-934C-8CAA39D9BF95}" - ProjectSection(SolutionItems) = preProject - experiment\api.js = experiment\api.js - experiment\schema.json = experiment\schema.json - EndProjectSection -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "options", "options", "{7372FCA6-B0BC-4968-A748-7ABB17A7929A}" ProjectSection(SolutionItems) = preProject options\options.html = options\options.html @@ -39,12 +33,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "en-US", "en-US", "{8BEA7793 _locales\en-US\messages.json = _locales\en-US\messages.json EndProjectSection EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "DomContentScript", "DomContentScript", "{B334FFB0-4BD2-496E-BDC4-786620E019DA}" - ProjectSection(SolutionItems) = preProject - experiment\DomContentScript\implementation.js = experiment\DomContentScript\implementation.js - experiment\DomContentScript\schema.json = experiment\DomContentScript\schema.json - EndProjectSection -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "content", "content", "{028FDA4B-AC3E-4A0E-9291-978E213F9B78}" ProjectSection(SolutionItems) = preProject content\filterEditor.js = content\filterEditor.js @@ -76,12 +64,10 @@ Global HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution - {F2C8C786-FA23-4B63-934C-8CAA39D9BF95} = {BCC6E6D2-343B-4C48-854D-5FE3BBC3CB70} {7372FCA6-B0BC-4968-A748-7ABB17A7929A} = {BCC6E6D2-343B-4C48-854D-5FE3BBC3CB70} {75ED3C1E-D3C7-4546-9F2E-AC85859DDF4B} = {BCC6E6D2-343B-4C48-854D-5FE3BBC3CB70} {D446E5C6-BDDE-4091-BD1A-EC57170003CF} = {BCC6E6D2-343B-4C48-854D-5FE3BBC3CB70} {8BEA7793-3336-40ED-AB96-7FFB09FEB0F6} = {D446E5C6-BDDE-4091-BD1A-EC57170003CF} - {B334FFB0-4BD2-496E-BDC4-786620E019DA} = {F2C8C786-FA23-4B63-934C-8CAA39D9BF95} {028FDA4B-AC3E-4A0E-9291-978E213F9B78} = {BCC6E6D2-343B-4C48-854D-5FE3BBC3CB70} {86516D53-50D4-4FE2-9D8A-977A8F5EBDBD} = {BCC6E6D2-343B-4C48-854D-5FE3BBC3CB70} {68A87938-5C2B-49F5-8AAA-8A34FBBFD854} = {BCC6E6D2-343B-4C48-854D-5FE3BBC3CB70} From bf2743d131eb60875084c404381dd6730e34fcc6 Mon Sep 17 00:00:00 2001 From: Jordan Wages Date: Wed, 25 Jun 2025 22:09:15 -0500 Subject: [PATCH 031/148] Handle cache loading without Services --- modules/AiClassifier.js | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/modules/AiClassifier.js b/modules/AiClassifier.js index fbb0a36..4c966d9 100644 --- a/modules/AiClassifier.js +++ b/modules/AiClassifier.js @@ -168,7 +168,14 @@ function buildPrompt(body, criterion) { } function getCachedResult(cacheKey) { - loadCacheSync(); + if (!gCacheLoaded) { + if (Services?.tm?.spinEventLoopUntil) { + loadCacheSync(); + } else { + // In non-privileged contexts we can't block, so bail out early. + return null; + } + } if (cacheKey && gCache.has(cacheKey)) { aiLog(`[AiClassifier] Cache hit for key: ${cacheKey}`, {debug: true}); return gCache.get(cacheKey); @@ -244,6 +251,9 @@ function classifyTextSync(text, criterion, cacheKey = null) { } async function classifyText(text, criterion, cacheKey = null) { + if (!gCacheLoaded) { + await loadCache(); + } const cached = getCachedResult(cacheKey); if (cached !== null) { return cached; From 848f5b7a8bd28a574a4858c787801b31a340972d Mon Sep 17 00:00:00 2001 From: Jordan Wages Date: Wed, 25 Jun 2025 23:17:03 -0500 Subject: [PATCH 032/148] Remove unused Services import --- background.js | 6 ++++-- modules/AiClassifier.js | 6 ++++-- modules/ExpressionSearchFilter.jsm | 1 - options/options.js | 5 +++-- 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/background.js b/background.js index 576fc9e..5ca824b 100644 --- a/background.js +++ b/background.js @@ -10,6 +10,8 @@ "use strict"; +const storage = (globalThis.messenger ?? browser).storage; + let logger; let AiClassifier; let aiRules = []; @@ -42,7 +44,7 @@ async function applyAiRules(idsInput) { if (!ids.length) return queue; if (!aiRules.length) { - const { aiRules: stored } = await browser.storage.local.get("aiRules"); + const { aiRules: stored } = await storage.local.get("aiRules"); aiRules = Array.isArray(stored) ? stored.map(r => { if (r.actions) return r; const actions = []; @@ -101,7 +103,7 @@ async function applyAiRules(idsInput) { } try { - const store = await browser.storage.local.get(["endpoint", "templateName", "customTemplate", "customSystemPrompt", "aiParams", "debugLogging", "aiRules"]); + const store = await storage.local.get(["endpoint", "templateName", "customTemplate", "customSystemPrompt", "aiParams", "debugLogging", "aiRules"]); logger.setDebug(store.debugLogging); await AiClassifier.setConfig(store); aiRules = Array.isArray(store.aiRules) ? store.aiRules.map(r => { diff --git a/modules/AiClassifier.js b/modules/AiClassifier.js index 4c966d9..d2cae3a 100644 --- a/modules/AiClassifier.js +++ b/modules/AiClassifier.js @@ -1,6 +1,8 @@ "use strict"; import { aiLog, setDebug } from "../logger.js"; +const storage = (globalThis.messenger ?? globalThis.browser).storage; + let Services; try { if (typeof globalThis !== "undefined" && globalThis.Services) { @@ -54,7 +56,7 @@ async function loadCache() { } aiLog(`[AiClassifier] Loading cache`, {debug: true}); try { - const { aiCache } = await browser.storage.local.get("aiCache"); + const { aiCache } = await storage.local.get("aiCache"); if (aiCache) { for (let [k, v] of Object.entries(aiCache)) { aiLog(`[AiClassifier] ⮡ Loaded entry '${k}' → ${v}`, {debug: true}); @@ -86,7 +88,7 @@ async function saveCache(updatedKey, updatedValue) { aiLog(`[AiClassifier] ⮡ Persisting entry '${updatedKey}' → ${updatedValue}`, {debug: true}); } try { - await browser.storage.local.set({ aiCache: Object.fromEntries(gCache) }); + await storage.local.set({ aiCache: Object.fromEntries(gCache) }); } catch (e) { aiLog(`Failed to save cache`, {level: 'error'}, e); } diff --git a/modules/ExpressionSearchFilter.jsm b/modules/ExpressionSearchFilter.jsm index 66e19ab..791c181 100644 --- a/modules/ExpressionSearchFilter.jsm +++ b/modules/ExpressionSearchFilter.jsm @@ -1,7 +1,6 @@ "use strict"; var { ExtensionParent } = ChromeUtils.importESModule("resource://gre/modules/ExtensionParent.sys.mjs"); var { MailServices } = ChromeUtils.importESModule("resource:///modules/MailServices.sys.mjs"); -var { Services } = globalThis || ChromeUtils.importESModule("resource://gre/modules/Services.sys.mjs"); var { aiLog } = ChromeUtils.import("resource://aifilter/modules/logger.jsm"); var AiClassifier = ChromeUtils.importESModule("resource://aifilter/modules/AiClassifier.js"); var { getPlainText } = ChromeUtils.import("resource://aifilter/modules/messageUtils.jsm"); diff --git a/options/options.js b/options/options.js index 9c3ff00..90eea50 100644 --- a/options/options.js +++ b/options/options.js @@ -1,7 +1,8 @@ document.addEventListener('DOMContentLoaded', async () => { + const storage = (globalThis.messenger ?? browser).storage; const logger = await import(browser.runtime.getURL('logger.js')); const AiClassifier = await import(browser.runtime.getURL('modules/AiClassifier.js')); - const defaults = await browser.storage.local.get([ + const defaults = await storage.local.get([ 'endpoint', 'templateName', 'customTemplate', @@ -269,7 +270,7 @@ document.addEventListener('DOMContentLoaded', async () => { }); return { criterion, actions }; }).filter(r => r.criterion); - await browser.storage.local.set({ endpoint, templateName, customTemplate: customTemplateText, customSystemPrompt, aiParams: aiParamsSave, debugLogging, aiRules: rules }); + await storage.local.set({ endpoint, templateName, customTemplate: customTemplateText, customSystemPrompt, aiParams: aiParamsSave, debugLogging, aiRules: rules }); try { await AiClassifier.setConfig({ endpoint, templateName, customTemplate: customTemplateText, customSystemPrompt, aiParams: aiParamsSave, debugLogging }); logger.setDebug(debugLogging); From 5007a96ba8463d75831f3c2f76daf70f9acc1dbe Mon Sep 17 00:00:00 2001 From: Jordan Wages Date: Thu, 26 Jun 2025 00:02:38 -0500 Subject: [PATCH 033/148] Update AGENTS.md --- AGENTS.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/AGENTS.md b/AGENTS.md index c74d3f4..3683f2c 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -37,5 +37,9 @@ Additional documentation exists outside this repository. - [Messages API](https://webextension-api.thunderbird.net/en/stable/messages.html) - [Message Tags API](https://webextension-api.thunderbird.net/en/stable/messages.tags.html) - [Storage API](https://webextension-api.thunderbird.net/en/stable/storage.html) +- Thunderbird Add-on Store Policies + - [Third Party Library Usage](https://extensionworkshop.com/documentation/publish/third-party-library-usage/) +- Third Party Libraries + - [Bulma.css](https://github.com/jgthms/bulma) - Issue tracker: [Thunderbird tracker on Bugzilla](https://bugzilla.mozilla.org/describecomponents.cgi?product=Thunderbird) From 37ac69a82a7a342dcb9aa7a0e70179941c8e6d71 Mon Sep 17 00:00:00 2001 From: Jordan Wages Date: Thu, 26 Jun 2025 00:28:57 -0500 Subject: [PATCH 034/148] Remove npm usage and reference static Bulma --- README.md | 8 +- options/options.html | 360 ++++++++++++++++--------------------------- options/options.js | 31 ++-- 3 files changed, 157 insertions(+), 242 deletions(-) diff --git a/README.md b/README.md index 6550542..b46b5d3 100644 --- a/README.md +++ b/README.md @@ -49,9 +49,11 @@ Sortana is implemented entirely with standard WebExtension scripts—no custom e 1. Ensure PowerShell is available (for Windows) or adapt the script for other environments. -2. Run `powershell ./build-xpi.ps1` from the repository root. The script reads -the version from `manifest.json` and creates an XPI in the `release` folder. -3. Install the generated XPI in Thunderbird via the Add-ons Manager. During +2. Ensure the Bulma stylesheet (v1.0.4) is saved as `options/bulma.css`. You can + download it from . +3. Run `powershell ./build-xpi.ps1` from the repository root. The script reads + the version from `manifest.json` and creates an XPI in the `release` folder. +4. Install the generated XPI in Thunderbird via the Add-ons Manager. During development you can also load the directory as a temporary add-on. ## Usage diff --git a/options/options.html b/options/options.html index 17af47a..d53d70c 100644 --- a/options/options.html +++ b/options/options.html @@ -4,248 +4,148 @@ AI Filter Options - + -
- AI Filter Logo -
+
+
+
+ AI Filter Logo +
- +
+
+
+ +
+
+
+ +
+
-
-
-
- - -
+
+
+ +
+ +
+
-
- - -
+
+ +
+
+ +
+
+
- + -
- - -
+
+ +
+ +
+
-
- - - -
+
+ + +
- - - - -
- +
diff --git a/options/options.js b/options/options.js index 90eea50..93440c7 100644 --- a/options/options.js +++ b/options/options.js @@ -11,16 +11,24 @@ document.addEventListener('DOMContentLoaded', async () => { 'debugLogging', 'aiRules' ]); - const tabButtons = document.querySelectorAll('.tab-button'); - const tabs = document.querySelectorAll('.tab'); + const tabButtons = document.querySelectorAll('#main-tabs li'); + const tabs = document.querySelectorAll('.tab-content'); tabButtons.forEach(btn => btn.addEventListener('click', () => { - tabButtons.forEach(b => b.classList.remove('active')); - btn.classList.add('active'); + tabButtons.forEach(b => b.classList.remove('is-active')); + btn.classList.add('is-active'); tabs.forEach(tab => { - tab.style.display = tab.id === `${btn.dataset.tab}-tab` ? 'block' : 'none'; + tab.classList.toggle('is-hidden', tab.id !== `${btn.dataset.tab}-tab`); }); })); tabButtons[0]?.click(); + + const saveBtn = document.getElementById('save'); + let initialized = false; + function markDirty() { + if (initialized) saveBtn.disabled = false; + } + document.addEventListener('input', markDirty, true); + document.addEventListener('change', markDirty, true); logger.setDebug(defaults.debugLogging === true); const DEFAULT_AI_PARAMS = { max_tokens: 4096, @@ -57,7 +65,7 @@ document.addEventListener('DOMContentLoaded', async () => { customTemplate.value = defaults.customTemplate || ''; function updateVisibility() { - customBox.style.display = templateSelect.value === 'custom' ? 'block' : 'none'; + customBox.classList.toggle('is-hidden', templateSelect.value !== 'custom'); } templateSelect.addEventListener('change', updateVisibility); updateVisibility(); @@ -65,7 +73,7 @@ document.addEventListener('DOMContentLoaded', async () => { const advancedBox = document.getElementById('advanced-options'); const advancedBtn = document.getElementById('toggle-advanced'); advancedBtn.addEventListener('click', () => { - advancedBox.style.display = advancedBox.style.display === 'none' ? 'block' : 'none'; + advancedBox.classList.toggle('is-hidden'); }); const debugToggle = document.getElementById('debug-logging'); @@ -109,7 +117,7 @@ document.addEventListener('DOMContentLoaded', async () => { function createActionRow(action = {type: 'tag'}) { const row = document.createElement('div'); - row.className = 'action-row'; + row.className = 'action-row field is-grouped'; const typeSelect = document.createElement('select'); ['tag','move','junk'].forEach(t => { @@ -162,6 +170,7 @@ document.addEventListener('DOMContentLoaded', async () => { const removeBtn = document.createElement('button'); removeBtn.textContent = 'Remove'; removeBtn.type = 'button'; + removeBtn.className = 'button is-small is-danger is-light'; removeBtn.addEventListener('click', () => row.remove()); row.appendChild(typeSelect); @@ -175,7 +184,7 @@ document.addEventListener('DOMContentLoaded', async () => { rulesContainer.innerHTML = ''; for (const rule of rules) { const div = document.createElement('div'); - div.className = 'rule'; + div.className = 'rule box'; const critInput = document.createElement('input'); critInput.type = 'text'; @@ -193,11 +202,13 @@ document.addEventListener('DOMContentLoaded', async () => { const addAction = document.createElement('button'); addAction.textContent = 'Add Action'; addAction.type = 'button'; + addAction.className = 'button is-small'; addAction.addEventListener('click', () => actionsContainer.appendChild(createActionRow())); const delBtn = document.createElement('button'); delBtn.textContent = 'Delete Rule'; delBtn.type = 'button'; + delBtn.className = 'button is-small is-danger'; delBtn.addEventListener('click', () => div.remove()); div.appendChild(critInput); @@ -238,6 +249,7 @@ document.addEventListener('DOMContentLoaded', async () => { if (r.moveTo) actions.push({ type: 'move', folder: r.moveTo }); return { criterion: r.criterion, actions }; })); + initialized = true; document.getElementById('save').addEventListener('click', async () => { const endpoint = document.getElementById('endpoint').value; @@ -277,5 +289,6 @@ document.addEventListener('DOMContentLoaded', async () => { } catch (e) { logger.aiLog('[options] failed to apply config', {level: 'error'}, e); } + saveBtn.disabled = true; }); }); From dd831e89b4c52f76a7deabdcd7d1a33afea71997 Mon Sep 17 00:00:00 2001 From: Jordan Wages Date: Thu, 26 Jun 2025 01:57:24 -0500 Subject: [PATCH 035/148] Fix rule handling and add priority UI --- README.md | 4 +++- background.js | 29 ++++++++++++++++++++++++++--- options/options.js | 40 ++++++++++++++++++++++++++++++++++++---- 3 files changed, 65 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index b46b5d3..97fe5e8 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,7 @@ message meets a specified criterion. - **Advanced parameters** – tune generation settings like temperature, top‑p and more from the options page. - **Debug logging** – optional colorized logs help troubleshoot interactions with the AI service. - **Automatic rules** – create rules that tag or move new messages based on AI classification. +- **Rule ordering** – drag rules to prioritize them and optionally stop processing after a match. - **Context menu** – apply AI rules from the message list or the message display action button. - **Status icons** – toolbar icons indicate when messages are queued or being classified. - **Packaging script** – `build-xpi.ps1` builds an XPI ready for installation. @@ -60,7 +61,8 @@ Sortana is implemented entirely with standard WebExtension scripts—no custom e 1. Open the add-on's options and set the URL of your classification service. 2. Use the **Classification Rules** section to add a criterion and optional - actions such as tagging or moving a message when it matches. + actions such as tagging or moving a message when it matches. Drag rules to + reorder them and check *Stop after match* to halt further processing. 3. Save your settings. New mail will be evaluated automatically using the configured rules. diff --git a/background.js b/background.js index 5ca824b..0df9f72 100644 --- a/background.js +++ b/background.js @@ -50,7 +50,9 @@ async function applyAiRules(idsInput) { const actions = []; if (r.tag) actions.push({ type: 'tag', tagKey: r.tag }); if (r.moveTo) actions.push({ type: 'move', folder: r.moveTo }); - return { criterion: r.criterion, actions }; + const rule = { criterion: r.criterion, actions }; + if (r.stopProcessing) rule.stopProcessing = true; + return rule; }) : []; } @@ -78,6 +80,9 @@ async function applyAiRules(idsInput) { await messenger.messages.update(id, { junk: !!act.junk }); } } + if (rule.stopProcessing) { + break; + } } } } catch (e) { @@ -111,9 +116,26 @@ async function applyAiRules(idsInput) { const actions = []; if (r.tag) actions.push({ type: 'tag', tagKey: r.tag }); if (r.moveTo) actions.push({ type: 'move', folder: r.moveTo }); - return { criterion: r.criterion, actions }; + const rule = { criterion: r.criterion, actions }; + if (r.stopProcessing) rule.stopProcessing = true; + return rule; }) : []; logger.aiLog("configuration loaded", {debug: true}, store); + storage.onChanged.addListener(async changes => { + if (changes.aiRules) { + const newRules = changes.aiRules.newValue || []; + aiRules = newRules.map(r => { + if (r.actions) return r; + const actions = []; + if (r.tag) actions.push({ type: 'tag', tagKey: r.tag }); + if (r.moveTo) actions.push({ type: 'move', folder: r.moveTo }); + const rule = { criterion: r.criterion, actions }; + if (r.stopProcessing) rule.stopProcessing = true; + return rule; + }); + logger.aiLog("aiRules updated from storage change", {debug: true}, aiRules); + } + }); } catch (err) { logger.aiLog("failed to load config", {level: 'error'}, err); } @@ -145,7 +167,8 @@ async function applyAiRules(idsInput) { browser.menus.onClicked.addListener(async info => { if (info.menuItemId === "apply-ai-rules-list" || info.menuItemId === "apply-ai-rules-display") { - const ids = info.selectedMessages?.ids || (info.messageId ? [info.messageId] : []); + const ids = info.selectedMessages?.messages?.map(m => m.id) || + (info.messageId ? [info.messageId] : []); await applyAiRules(ids); } }); diff --git a/options/options.js b/options/options.js index 93440c7..d21cfbe 100644 --- a/options/options.js +++ b/options/options.js @@ -24,6 +24,7 @@ document.addEventListener('DOMContentLoaded', async () => { const saveBtn = document.getElementById('save'); let initialized = false; + let dragRule = null; function markDirty() { if (initialized) saveBtn.disabled = false; } @@ -185,6 +186,23 @@ document.addEventListener('DOMContentLoaded', async () => { for (const rule of rules) { const div = document.createElement('div'); div.className = 'rule box'; + div.draggable = true; + div.addEventListener('dragstart', ev => { dragRule = div; ev.dataTransfer.setData('text/plain', ''); }); + div.addEventListener('dragover', ev => ev.preventDefault()); + div.addEventListener('drop', ev => { + ev.preventDefault(); + if (dragRule && dragRule !== div) { + const children = Array.from(rulesContainer.children); + const dragIndex = children.indexOf(dragRule); + const dropIndex = children.indexOf(div); + if (dragIndex < dropIndex) { + rulesContainer.insertBefore(dragRule, div.nextSibling); + } else { + rulesContainer.insertBefore(dragRule, div); + } + markDirty(); + } + }); const critInput = document.createElement('input'); critInput.type = 'text'; @@ -205,6 +223,15 @@ document.addEventListener('DOMContentLoaded', async () => { addAction.className = 'button is-small'; addAction.addEventListener('click', () => actionsContainer.appendChild(createActionRow())); + const stopLabel = document.createElement('label'); + stopLabel.className = 'checkbox ml-2'; + const stopCheck = document.createElement('input'); + stopCheck.type = 'checkbox'; + stopCheck.className = 'stop-processing'; + stopCheck.checked = rule.stopProcessing === true; + stopLabel.appendChild(stopCheck); + stopLabel.append(' Stop after match'); + const delBtn = document.createElement('button'); delBtn.textContent = 'Delete Rule'; delBtn.type = 'button'; @@ -214,6 +241,7 @@ document.addEventListener('DOMContentLoaded', async () => { div.appendChild(critInput); div.appendChild(actionsContainer); div.appendChild(addAction); + div.appendChild(stopLabel); div.appendChild(delBtn); rulesContainer.appendChild(div); @@ -236,9 +264,10 @@ document.addEventListener('DOMContentLoaded', async () => { } return { type }; }); - return { criterion, actions }; + const stopProcessing = ruleEl.querySelector('.stop-processing')?.checked; + return { criterion, actions, stopProcessing }; }); - data.push({ criterion: '', actions: [] }); + data.push({ criterion: '', actions: [], stopProcessing: false }); renderRules(data); }); @@ -247,7 +276,9 @@ document.addEventListener('DOMContentLoaded', async () => { const actions = []; if (r.tag) actions.push({ type: 'tag', tagKey: r.tag }); if (r.moveTo) actions.push({ type: 'move', folder: r.moveTo }); - return { criterion: r.criterion, actions }; + const rule = { criterion: r.criterion, actions }; + if (r.stopProcessing) rule.stopProcessing = true; + return rule; })); initialized = true; @@ -280,7 +311,8 @@ document.addEventListener('DOMContentLoaded', async () => { } return { type }; }); - return { criterion, actions }; + const stopProcessing = ruleEl.querySelector('.stop-processing')?.checked; + return { criterion, actions, stopProcessing }; }).filter(r => r.criterion); await storage.local.set({ endpoint, templateName, customTemplate: customTemplateText, customSystemPrompt, aiParams: aiParamsSave, debugLogging, aiRules: rules }); try { From 540677d4584e38e98ab19ef6de67f6f55d7f75ec Mon Sep 17 00:00:00 2001 From: Jordan Wages Date: Thu, 26 Jun 2025 02:10:52 -0500 Subject: [PATCH 036/148] Add Bulma classes to new rules --- options/options.js | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/options/options.js b/options/options.js index d21cfbe..3cea8ee 100644 --- a/options/options.js +++ b/options/options.js @@ -118,9 +118,10 @@ document.addEventListener('DOMContentLoaded', async () => { function createActionRow(action = {type: 'tag'}) { const row = document.createElement('div'); - row.className = 'action-row field is-grouped'; + row.className = 'action-row field is-grouped mb-2'; const typeSelect = document.createElement('select'); + typeSelect.className = 'select is-small'; ['tag','move','junk'].forEach(t => { const opt = document.createElement('option'); opt.value = t; @@ -135,7 +136,7 @@ document.addEventListener('DOMContentLoaded', async () => { paramSpan.innerHTML = ''; if (typeSelect.value === 'tag') { const sel = document.createElement('select'); - sel.className = 'tag-select'; + sel.className = 'select is-small tag-select'; for (const t of tagList) { const opt = document.createElement('option'); opt.value = t.key; @@ -146,7 +147,7 @@ document.addEventListener('DOMContentLoaded', async () => { paramSpan.appendChild(sel); } else if (typeSelect.value === 'move') { const sel = document.createElement('select'); - sel.className = 'folder-select'; + sel.className = 'select is-small folder-select'; for (const f of folderList) { const opt = document.createElement('option'); opt.value = f.id; @@ -157,7 +158,7 @@ document.addEventListener('DOMContentLoaded', async () => { paramSpan.appendChild(sel); } else if (typeSelect.value === 'junk') { const sel = document.createElement('select'); - sel.className = 'junk-select'; + sel.className = 'select is-small junk-select'; sel.appendChild(new Option('mark junk','true')); sel.appendChild(new Option('mark not junk','false')); sel.value = String(action.junk ?? true); @@ -185,7 +186,7 @@ document.addEventListener('DOMContentLoaded', async () => { rulesContainer.innerHTML = ''; for (const rule of rules) { const div = document.createElement('div'); - div.className = 'rule box'; + div.className = 'rule box mb-4'; div.draggable = true; div.addEventListener('dragstart', ev => { dragRule = div; ev.dataTransfer.setData('text/plain', ''); }); div.addEventListener('dragover', ev => ev.preventDefault()); @@ -208,10 +209,10 @@ document.addEventListener('DOMContentLoaded', async () => { critInput.type = 'text'; critInput.placeholder = 'Criterion'; critInput.value = rule.criterion || ''; - critInput.className = 'criterion'; + critInput.className = 'input criterion mb-2'; const actionsContainer = document.createElement('div'); - actionsContainer.className = 'rule-actions'; + actionsContainer.className = 'rule-actions mb-2'; for (const act of (rule.actions || [])) { actionsContainer.appendChild(createActionRow(act)); @@ -220,11 +221,11 @@ document.addEventListener('DOMContentLoaded', async () => { const addAction = document.createElement('button'); addAction.textContent = 'Add Action'; addAction.type = 'button'; - addAction.className = 'button is-small'; + addAction.className = 'button is-small mb-2'; addAction.addEventListener('click', () => actionsContainer.appendChild(createActionRow())); const stopLabel = document.createElement('label'); - stopLabel.className = 'checkbox ml-2'; + stopLabel.className = 'checkbox ml-2 mb-2'; const stopCheck = document.createElement('input'); stopCheck.type = 'checkbox'; stopCheck.className = 'stop-processing'; From 9c5134b797e96c2a4355457e217ac26971eb34b9 Mon Sep 17 00:00:00 2001 From: Jordan Wages Date: Thu, 26 Jun 2025 02:13:36 -0500 Subject: [PATCH 037/148] Added themeing --- ai-filter.sln | 5 + manifest.json | 2 +- options/bulma.css | 21559 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 21565 insertions(+), 1 deletion(-) create mode 100644 options/bulma.css diff --git a/ai-filter.sln b/ai-filter.sln index 05fa5be..6aeca89 100644 --- a/ai-filter.sln +++ b/ai-filter.sln @@ -5,10 +5,14 @@ VisualStudioVersion = 17.12.35707.178 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{BCC6E6D2-343B-4C48-854D-5FE3BBC3CB70}" ProjectSection(SolutionItems) = preProject + .gitignore = .gitignore + AGENTS.md = AGENTS.md background.js = background.js build-xpi.ps1 = build-xpi.ps1 + LICENSE = LICENSE logger.js = logger.js manifest.json = manifest.json + README.md = README.md EndProjectSection ProjectSection(FolderGlobals) = preProject Q_5_4Users_4Jordan_4Documents_4Gitea_4thunderbird-ai-filter_4src_4manifest_1json__JsonSchema = @@ -16,6 +20,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "options", "options", "{7372FCA6-B0BC-4968-A748-7ABB17A7929A}" ProjectSection(SolutionItems) = preProject + options\bulma.css = options\bulma.css options\options.html = options\options.html options\options.js = options\options.js EndProjectSection diff --git a/manifest.json b/manifest.json index 1245a83..1610453 100644 --- a/manifest.json +++ b/manifest.json @@ -1,7 +1,7 @@ { "manifest_version": 2, "name": "Sortana", - "version": "1.3.0", + "version": "2.0.0", "default_locale": "en-US", "applications": { "gecko": { diff --git a/options/bulma.css b/options/bulma.css new file mode 100644 index 0000000..60abac6 --- /dev/null +++ b/options/bulma.css @@ -0,0 +1,21559 @@ +@charset "UTF-8"; +/*! bulma.io v1.0.3 | MIT License | github.com/jgthms/bulma */ +/* Bulma Utilities */ +:root { + --bulma-control-radius: var(--bulma-radius); + --bulma-control-radius-small: var(--bulma-radius-small); + --bulma-control-border-width: 1px; + --bulma-control-height: 2.5em; + --bulma-control-line-height: 1.5; + --bulma-control-padding-vertical: calc(0.5em - 1px); + --bulma-control-padding-horizontal: calc(0.75em - 1px); + --bulma-control-size: var(--bulma-size-normal); + --bulma-control-focus-shadow-l: 50%; +} + +/* Bulma Themes */ +:root { + --bulma-scheme-h: 221; + --bulma-scheme-s: 14%; + --bulma-light-l: 90%; + --bulma-light-invert-l: 20%; + --bulma-dark-l: 20%; + --bulma-dark-invert-l: 90%; + --bulma-soft-l: 90%; + --bulma-bold-l: 20%; + --bulma-soft-invert-l: 20%; + --bulma-bold-invert-l: 90%; + --bulma-hover-background-l-delta: -5%; + --bulma-active-background-l-delta: -10%; + --bulma-hover-border-l-delta: -10%; + --bulma-active-border-l-delta: -20%; + --bulma-hover-color-l-delta: -5%; + --bulma-active-color-l-delta: -10%; + --bulma-hover-shadow-a-delta: -0.05; + --bulma-active-shadow-a-delta: -0.1; + --bulma-scheme-brightness: light; + --bulma-scheme-main-l: 100%; + --bulma-scheme-main-bis-l: 98%; + --bulma-scheme-main-ter-l: 96%; + --bulma-background-l: 96%; + --bulma-border-weak-l: 93%; + --bulma-border-l: 86%; + --bulma-text-weak-l: 48%; + --bulma-text-l: 29%; + --bulma-text-strong-l: 21%; + --bulma-text-title-l: 14%; + --bulma-scheme-invert-ter-l: 14%; + --bulma-scheme-invert-bis-l: 7%; + --bulma-scheme-invert-l: 4%; + --bulma-family-primary: Inter, SF Pro, Segoe UI, Roboto, Oxygen, Ubuntu, Helvetica Neue, Helvetica, Arial, sans-serif; + --bulma-family-secondary: Inter, SF Pro, Segoe UI, Roboto, Oxygen, Ubuntu, Helvetica Neue, Helvetica, Arial, sans-serif; + --bulma-family-code: Inconsolata, Hack, SF Mono, Roboto Mono, Source Code Pro, Ubuntu Mono, monospace; + --bulma-size-small: 0.75rem; + --bulma-size-normal: 1rem; + --bulma-size-medium: 1.25rem; + --bulma-size-large: 1.5rem; + --bulma-weight-light: 300; + --bulma-weight-normal: 400; + --bulma-weight-medium: 500; + --bulma-weight-semibold: 600; + --bulma-weight-bold: 700; + --bulma-weight-extrabold: 800; + --bulma-block-spacing: 1.5rem; + --bulma-duration: 294ms; + --bulma-easing: ease-out; + --bulma-radius-small: 0.25rem; + --bulma-radius: 0.375rem; + --bulma-radius-medium: 0.5em; + --bulma-radius-large: 0.75rem; + --bulma-radius-rounded: 9999px; + --bulma-speed: 86ms; + --bulma-arrow-color: var(--bulma-link); + --bulma-loading-color: var(--bulma-border); + --bulma-burger-h: var(--bulma-link-h); + --bulma-burger-s: var(--bulma-link-s); + --bulma-burger-l: var(--bulma-link-l); + --bulma-burger-border-radius: 0.5em; + --bulma-burger-gap: 5px; + --bulma-burger-item-height: 2px; + --bulma-burger-item-width: 20px; + --bulma-white: hsla(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-l), 1); + --bulma-white-base: hsla(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-l), 1); + --bulma-white-rgb: 255, 255, 255; + --bulma-white-h: 221deg; + --bulma-white-s: 14%; + --bulma-white-l: 100%; + --bulma-white-invert-l: 4%; + --bulma-white-invert: hsl(221, 14%, 4%); + --bulma-white-on-scheme-l: 35%; + --bulma-white-on-scheme: hsla(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-on-scheme-l), 1); + --bulma-black: hsla(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-l), 1); + --bulma-black-base: hsla(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-l), 1); + --bulma-black-rgb: 8.772, 9.6764, 11.628; + --bulma-black-h: 221deg; + --bulma-black-s: 14%; + --bulma-black-l: 4%; + --bulma-black-invert-l: 100%; + --bulma-black-invert: hsl(221, 14%, 100%); + --bulma-black-on-scheme-l: 4%; + --bulma-black-on-scheme: hsla(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-on-scheme-l), 1); + --bulma-light: hsla(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-l), 1); + --bulma-light-base: hsla(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-l), 1); + --bulma-light-rgb: 243.372, 244.2764, 246.228; + --bulma-light-h: 221deg; + --bulma-light-s: 14%; + --bulma-light-l: 96%; + --bulma-light-invert-l: 21%; + --bulma-light-invert: hsl(221, 14%, 21%); + --bulma-light-on-scheme-l: 36%; + --bulma-light-on-scheme: hsla(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-on-scheme-l), 1); + --bulma-dark: hsla(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-l), 1); + --bulma-dark-base: hsla(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-l), 1); + --bulma-dark-rgb: 46.053, 50.8011, 61.047; + --bulma-dark-h: 221deg; + --bulma-dark-s: 14%; + --bulma-dark-l: 21%; + --bulma-dark-invert-l: 96%; + --bulma-dark-invert: hsl(221, 14%, 96%); + --bulma-dark-on-scheme-l: 21%; + --bulma-dark-on-scheme: hsla(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-on-scheme-l), 1); + --bulma-text: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-l), 1); + --bulma-text-base: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-l), 1); + --bulma-text-rgb: 63.597, 70.1539, 84.303; + --bulma-text-h: 221deg; + --bulma-text-s: 14%; + --bulma-text-l: 29%; + --bulma-text-00-l: 0%; + --bulma-text-05-l: 4%; + --bulma-text-10-l: 9%; + --bulma-text-15-l: 14%; + --bulma-text-20-l: 19%; + --bulma-text-25-l: 24%; + --bulma-text-30-l: 29%; + --bulma-text-35-l: 34%; + --bulma-text-40-l: 39%; + --bulma-text-45-l: 44%; + --bulma-text-50-l: 49%; + --bulma-text-55-l: 54%; + --bulma-text-60-l: 59%; + --bulma-text-65-l: 64%; + --bulma-text-70-l: 69%; + --bulma-text-75-l: 74%; + --bulma-text-80-l: 79%; + --bulma-text-85-l: 84%; + --bulma-text-90-l: 89%; + --bulma-text-95-l: 94%; + --bulma-text-100-l: 99%; + --bulma-text-00: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-00-l), 1); + --bulma-text-00-invert-l: var(--bulma-text-60-l); + --bulma-text-00-invert: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-00-invert-l), 1); + --bulma-text-05: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-05-l), 1); + --bulma-text-05-invert-l: var(--bulma-text-60-l); + --bulma-text-05-invert: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-05-invert-l), 1); + --bulma-text-10: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-10-l), 1); + --bulma-text-10-invert-l: var(--bulma-text-70-l); + --bulma-text-10-invert: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-10-invert-l), 1); + --bulma-text-15: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-15-l), 1); + --bulma-text-15-invert-l: var(--bulma-text-75-l); + --bulma-text-15-invert: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-15-invert-l), 1); + --bulma-text-20: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-20-l), 1); + --bulma-text-20-invert-l: var(--bulma-text-85-l); + --bulma-text-20-invert: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-20-invert-l), 1); + --bulma-text-25: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-25-l), 1); + --bulma-text-25-invert-l: var(--bulma-text-95-l); + --bulma-text-25-invert: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-25-invert-l), 1); + --bulma-text-30: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-30-l), 1); + --bulma-text-30-invert-l: var(--bulma-text-100-l); + --bulma-text-30-invert: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-30-invert-l), 1); + --bulma-text-35: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-35-l), 1); + --bulma-text-35-invert-l: var(--bulma-text-100-l); + --bulma-text-35-invert: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-35-invert-l), 1); + --bulma-text-40: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-40-l), 1); + --bulma-text-40-invert-l: var(--bulma-text-100-l); + --bulma-text-40-invert: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-40-invert-l), 1); + --bulma-text-45: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-45-l), 1); + --bulma-text-45-invert-l: var(--bulma-text-100-l); + --bulma-text-45-invert: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-45-invert-l), 1); + --bulma-text-50: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-50-l), 1); + --bulma-text-50-invert-l: var(--bulma-text-100-l); + --bulma-text-50-invert: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-50-invert-l), 1); + --bulma-text-55: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-55-l), 1); + --bulma-text-55-invert-l: var(--bulma-text-100-l); + --bulma-text-55-invert: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-55-invert-l), 1); + --bulma-text-60: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-60-l), 1); + --bulma-text-60-invert-l: var(--bulma-text-05-l); + --bulma-text-60-invert: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-60-invert-l), 1); + --bulma-text-65: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-65-l), 1); + --bulma-text-65-invert-l: var(--bulma-text-05-l); + --bulma-text-65-invert: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-65-invert-l), 1); + --bulma-text-70: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-70-l), 1); + --bulma-text-70-invert-l: var(--bulma-text-10-l); + --bulma-text-70-invert: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-70-invert-l), 1); + --bulma-text-75: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-75-l), 1); + --bulma-text-75-invert-l: var(--bulma-text-15-l); + --bulma-text-75-invert: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-75-invert-l), 1); + --bulma-text-80: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-80-l), 1); + --bulma-text-80-invert-l: var(--bulma-text-15-l); + --bulma-text-80-invert: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-80-invert-l), 1); + --bulma-text-85: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-85-l), 1); + --bulma-text-85-invert-l: var(--bulma-text-20-l); + --bulma-text-85-invert: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-85-invert-l), 1); + --bulma-text-90: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-90-l), 1); + --bulma-text-90-invert-l: var(--bulma-text-20-l); + --bulma-text-90-invert: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-90-invert-l), 1); + --bulma-text-95: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-95-l), 1); + --bulma-text-95-invert-l: var(--bulma-text-25-l); + --bulma-text-95-invert: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-95-invert-l), 1); + --bulma-text-100: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-100-l), 1); + --bulma-text-100-invert-l: var(--bulma-text-25-l); + --bulma-text-100-invert: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-100-invert-l), 1); + --bulma-text-invert-l: var(--bulma-text-100-l); + --bulma-text-invert: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-invert-l), 1); + --bulma-text-light-l: var(--bulma-text-90-l); + --bulma-text-light: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-light-l), 1); + --bulma-text-light-invert-l: var(--bulma-text-20-l); + --bulma-text-light-invert: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-light-invert-l), 1); + --bulma-text-dark-l: var(--bulma-text-10-l); + --bulma-text-dark: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-dark-l), 1); + --bulma-text-dark-invert-l: var(--bulma-text-70-l); + --bulma-text-dark-invert: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-dark-invert-l), 1); + --bulma-text-soft: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-soft-l), 1); + --bulma-text-bold: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-bold-l), 1); + --bulma-text-soft-invert: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-soft-invert-l), 1); + --bulma-text-bold-invert: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-bold-invert-l), 1); + --bulma-text-on-scheme-l: 29%; + --bulma-text-on-scheme: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-on-scheme-l), 1); + --bulma-primary: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-l), 1); + --bulma-primary-base: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-l), 1); + --bulma-primary-rgb: 0, 209.1, 177.735; + --bulma-primary-h: 171deg; + --bulma-primary-s: 100%; + --bulma-primary-l: 41%; + --bulma-primary-00-l: 1%; + --bulma-primary-05-l: 6%; + --bulma-primary-10-l: 11%; + --bulma-primary-15-l: 16%; + --bulma-primary-20-l: 21%; + --bulma-primary-25-l: 26%; + --bulma-primary-30-l: 31%; + --bulma-primary-35-l: 36%; + --bulma-primary-40-l: 41%; + --bulma-primary-45-l: 46%; + --bulma-primary-50-l: 51%; + --bulma-primary-55-l: 56%; + --bulma-primary-60-l: 61%; + --bulma-primary-65-l: 66%; + --bulma-primary-70-l: 71%; + --bulma-primary-75-l: 76%; + --bulma-primary-80-l: 81%; + --bulma-primary-85-l: 86%; + --bulma-primary-90-l: 91%; + --bulma-primary-95-l: 96%; + --bulma-primary-100-l: 100%; + --bulma-primary-00: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-00-l), 1); + --bulma-primary-00-invert-l: var(--bulma-primary-30-l); + --bulma-primary-00-invert: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-00-invert-l), 1); + --bulma-primary-05: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-05-l), 1); + --bulma-primary-05-invert-l: var(--bulma-primary-40-l); + --bulma-primary-05-invert: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-05-invert-l), 1); + --bulma-primary-10: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-10-l), 1); + --bulma-primary-10-invert-l: var(--bulma-primary-50-l); + --bulma-primary-10-invert: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-10-invert-l), 1); + --bulma-primary-15: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-15-l), 1); + --bulma-primary-15-invert-l: var(--bulma-primary-100-l); + --bulma-primary-15-invert: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-15-invert-l), 1); + --bulma-primary-20: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-20-l), 1); + --bulma-primary-20-invert-l: var(--bulma-primary-100-l); + --bulma-primary-20-invert: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-20-invert-l), 1); + --bulma-primary-25: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-25-l), 1); + --bulma-primary-25-invert-l: var(--bulma-primary-100-l); + --bulma-primary-25-invert: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-25-invert-l), 1); + --bulma-primary-30: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-30-l), 1); + --bulma-primary-30-invert-l: var(--bulma-primary-00-l); + --bulma-primary-30-invert: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-30-invert-l), 1); + --bulma-primary-35: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-35-l), 1); + --bulma-primary-35-invert-l: var(--bulma-primary-00-l); + --bulma-primary-35-invert: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-35-invert-l), 1); + --bulma-primary-40: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-40-l), 1); + --bulma-primary-40-invert-l: var(--bulma-primary-05-l); + --bulma-primary-40-invert: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-40-invert-l), 1); + --bulma-primary-45: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-45-l), 1); + --bulma-primary-45-invert-l: var(--bulma-primary-05-l); + --bulma-primary-45-invert: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-45-invert-l), 1); + --bulma-primary-50: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-50-l), 1); + --bulma-primary-50-invert-l: var(--bulma-primary-10-l); + --bulma-primary-50-invert: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-50-invert-l), 1); + --bulma-primary-55: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-55-l), 1); + --bulma-primary-55-invert-l: var(--bulma-primary-10-l); + --bulma-primary-55-invert: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-55-invert-l), 1); + --bulma-primary-60: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-60-l), 1); + --bulma-primary-60-invert-l: var(--bulma-primary-10-l); + --bulma-primary-60-invert: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-60-invert-l), 1); + --bulma-primary-65: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-65-l), 1); + --bulma-primary-65-invert-l: var(--bulma-primary-10-l); + --bulma-primary-65-invert: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-65-invert-l), 1); + --bulma-primary-70: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-70-l), 1); + --bulma-primary-70-invert-l: var(--bulma-primary-10-l); + --bulma-primary-70-invert: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-70-invert-l), 1); + --bulma-primary-75: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-75-l), 1); + --bulma-primary-75-invert-l: var(--bulma-primary-10-l); + --bulma-primary-75-invert: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-75-invert-l), 1); + --bulma-primary-80: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-80-l), 1); + --bulma-primary-80-invert-l: var(--bulma-primary-10-l); + --bulma-primary-80-invert: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-80-invert-l), 1); + --bulma-primary-85: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-85-l), 1); + --bulma-primary-85-invert-l: var(--bulma-primary-10-l); + --bulma-primary-85-invert: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-85-invert-l), 1); + --bulma-primary-90: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-90-l), 1); + --bulma-primary-90-invert-l: var(--bulma-primary-10-l); + --bulma-primary-90-invert: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-90-invert-l), 1); + --bulma-primary-95: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-95-l), 1); + --bulma-primary-95-invert-l: var(--bulma-primary-10-l); + --bulma-primary-95-invert: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-95-invert-l), 1); + --bulma-primary-100: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-100-l), 1); + --bulma-primary-100-invert-l: var(--bulma-primary-15-l); + --bulma-primary-100-invert: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-100-invert-l), 1); + --bulma-primary-invert-l: var(--bulma-primary-05-l); + --bulma-primary-invert: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-invert-l), 1); + --bulma-primary-light-l: var(--bulma-primary-90-l); + --bulma-primary-light: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-light-l), 1); + --bulma-primary-light-invert-l: var(--bulma-primary-10-l); + --bulma-primary-light-invert: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-light-invert-l), 1); + --bulma-primary-dark-l: var(--bulma-primary-10-l); + --bulma-primary-dark: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-dark-l), 1); + --bulma-primary-dark-invert-l: var(--bulma-primary-50-l); + --bulma-primary-dark-invert: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-dark-invert-l), 1); + --bulma-primary-soft: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-soft-l), 1); + --bulma-primary-bold: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-bold-l), 1); + --bulma-primary-soft-invert: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-soft-invert-l), 1); + --bulma-primary-bold-invert: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-bold-invert-l), 1); + --bulma-primary-on-scheme-l: 21%; + --bulma-primary-on-scheme: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-on-scheme-l), 1); + --bulma-link: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-l), 1); + --bulma-link-base: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-l), 1); + --bulma-link-rgb: 66.3, 88.315, 255; + --bulma-link-h: 233deg; + --bulma-link-s: 100%; + --bulma-link-l: 63%; + --bulma-link-00-l: 0%; + --bulma-link-05-l: 3%; + --bulma-link-10-l: 8%; + --bulma-link-15-l: 13%; + --bulma-link-20-l: 18%; + --bulma-link-25-l: 23%; + --bulma-link-30-l: 28%; + --bulma-link-35-l: 33%; + --bulma-link-40-l: 38%; + --bulma-link-45-l: 43%; + --bulma-link-50-l: 48%; + --bulma-link-55-l: 53%; + --bulma-link-60-l: 58%; + --bulma-link-65-l: 63%; + --bulma-link-70-l: 68%; + --bulma-link-75-l: 73%; + --bulma-link-80-l: 78%; + --bulma-link-85-l: 83%; + --bulma-link-90-l: 88%; + --bulma-link-95-l: 93%; + --bulma-link-100-l: 98%; + --bulma-link-00: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-00-l), 1); + --bulma-link-00-invert-l: var(--bulma-link-75-l); + --bulma-link-00-invert: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-00-invert-l), 1); + --bulma-link-05: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-05-l), 1); + --bulma-link-05-invert-l: var(--bulma-link-75-l); + --bulma-link-05-invert: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-05-invert-l), 1); + --bulma-link-10: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-10-l), 1); + --bulma-link-10-invert-l: var(--bulma-link-75-l); + --bulma-link-10-invert: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-10-invert-l), 1); + --bulma-link-15: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-15-l), 1); + --bulma-link-15-invert-l: var(--bulma-link-80-l); + --bulma-link-15-invert: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-15-invert-l), 1); + --bulma-link-20: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-20-l), 1); + --bulma-link-20-invert-l: var(--bulma-link-80-l); + --bulma-link-20-invert: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-20-invert-l), 1); + --bulma-link-25: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-25-l), 1); + --bulma-link-25-invert-l: var(--bulma-link-85-l); + --bulma-link-25-invert: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-25-invert-l), 1); + --bulma-link-30: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-30-l), 1); + --bulma-link-30-invert-l: var(--bulma-link-90-l); + --bulma-link-30-invert: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-30-invert-l), 1); + --bulma-link-35: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-35-l), 1); + --bulma-link-35-invert-l: var(--bulma-link-90-l); + --bulma-link-35-invert: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-35-invert-l), 1); + --bulma-link-40: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-40-l), 1); + --bulma-link-40-invert-l: var(--bulma-link-95-l); + --bulma-link-40-invert: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-40-invert-l), 1); + --bulma-link-45: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-45-l), 1); + --bulma-link-45-invert-l: var(--bulma-link-95-l); + --bulma-link-45-invert: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-45-invert-l), 1); + --bulma-link-50: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-50-l), 1); + --bulma-link-50-invert-l: var(--bulma-link-100-l); + --bulma-link-50-invert: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-50-invert-l), 1); + --bulma-link-55: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-55-l), 1); + --bulma-link-55-invert-l: var(--bulma-link-100-l); + --bulma-link-55-invert: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-55-invert-l), 1); + --bulma-link-60: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-60-l), 1); + --bulma-link-60-invert-l: var(--bulma-link-100-l); + --bulma-link-60-invert: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-60-invert-l), 1); + --bulma-link-65: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-65-l), 1); + --bulma-link-65-invert-l: var(--bulma-link-100-l); + --bulma-link-65-invert: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-65-invert-l), 1); + --bulma-link-70: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-70-l), 1); + --bulma-link-70-invert-l: var(--bulma-link-100-l); + --bulma-link-70-invert: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-70-invert-l), 1); + --bulma-link-75: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-75-l), 1); + --bulma-link-75-invert-l: var(--bulma-link-10-l); + --bulma-link-75-invert: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-75-invert-l), 1); + --bulma-link-80: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-80-l), 1); + --bulma-link-80-invert-l: var(--bulma-link-20-l); + --bulma-link-80-invert: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-80-invert-l), 1); + --bulma-link-85: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-85-l), 1); + --bulma-link-85-invert-l: var(--bulma-link-25-l); + --bulma-link-85-invert: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-85-invert-l), 1); + --bulma-link-90: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-90-l), 1); + --bulma-link-90-invert-l: var(--bulma-link-35-l); + --bulma-link-90-invert: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-90-invert-l), 1); + --bulma-link-95: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-95-l), 1); + --bulma-link-95-invert-l: var(--bulma-link-45-l); + --bulma-link-95-invert: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-95-invert-l), 1); + --bulma-link-100: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-100-l), 1); + --bulma-link-100-invert-l: var(--bulma-link-50-l); + --bulma-link-100-invert: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-100-invert-l), 1); + --bulma-link-invert-l: var(--bulma-link-100-l); + --bulma-link-invert: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-invert-l), 1); + --bulma-link-light-l: var(--bulma-link-90-l); + --bulma-link-light: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-light-l), 1); + --bulma-link-light-invert-l: var(--bulma-link-35-l); + --bulma-link-light-invert: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-light-invert-l), 1); + --bulma-link-dark-l: var(--bulma-link-10-l); + --bulma-link-dark: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-dark-l), 1); + --bulma-link-dark-invert-l: var(--bulma-link-75-l); + --bulma-link-dark-invert: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-dark-invert-l), 1); + --bulma-link-soft: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-soft-l), 1); + --bulma-link-bold: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-bold-l), 1); + --bulma-link-soft-invert: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-soft-invert-l), 1); + --bulma-link-bold-invert: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-bold-invert-l), 1); + --bulma-link-on-scheme-l: 58%; + --bulma-link-on-scheme: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-on-scheme-l), 1); + --bulma-info: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-l), 1); + --bulma-info-base: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-l), 1); + --bulma-info-rgb: 102, 209.1, 255; + --bulma-info-h: 198deg; + --bulma-info-s: 100%; + --bulma-info-l: 70%; + --bulma-info-00-l: 0%; + --bulma-info-05-l: 5%; + --bulma-info-10-l: 10%; + --bulma-info-15-l: 15%; + --bulma-info-20-l: 20%; + --bulma-info-25-l: 25%; + --bulma-info-30-l: 30%; + --bulma-info-35-l: 35%; + --bulma-info-40-l: 40%; + --bulma-info-45-l: 45%; + --bulma-info-50-l: 50%; + --bulma-info-55-l: 55%; + --bulma-info-60-l: 60%; + --bulma-info-65-l: 65%; + --bulma-info-70-l: 70%; + --bulma-info-75-l: 75%; + --bulma-info-80-l: 80%; + --bulma-info-85-l: 85%; + --bulma-info-90-l: 90%; + --bulma-info-95-l: 95%; + --bulma-info-100-l: 100%; + --bulma-info-00: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-00-l), 1); + --bulma-info-00-invert-l: var(--bulma-info-45-l); + --bulma-info-00-invert: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-00-invert-l), 1); + --bulma-info-05: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-05-l), 1); + --bulma-info-05-invert-l: var(--bulma-info-50-l); + --bulma-info-05-invert: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-05-invert-l), 1); + --bulma-info-10: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-10-l), 1); + --bulma-info-10-invert-l: var(--bulma-info-60-l); + --bulma-info-10-invert: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-10-invert-l), 1); + --bulma-info-15: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-15-l), 1); + --bulma-info-15-invert-l: var(--bulma-info-80-l); + --bulma-info-15-invert: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-15-invert-l), 1); + --bulma-info-20: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-20-l), 1); + --bulma-info-20-invert-l: var(--bulma-info-95-l); + --bulma-info-20-invert: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-20-invert-l), 1); + --bulma-info-25: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-25-l), 1); + --bulma-info-25-invert-l: var(--bulma-info-100-l); + --bulma-info-25-invert: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-25-invert-l), 1); + --bulma-info-30: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-30-l), 1); + --bulma-info-30-invert-l: var(--bulma-info-100-l); + --bulma-info-30-invert: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-30-invert-l), 1); + --bulma-info-35: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-35-l), 1); + --bulma-info-35-invert-l: var(--bulma-info-100-l); + --bulma-info-35-invert: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-35-invert-l), 1); + --bulma-info-40: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-40-l), 1); + --bulma-info-40-invert-l: var(--bulma-info-100-l); + --bulma-info-40-invert: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-40-invert-l), 1); + --bulma-info-45: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-45-l), 1); + --bulma-info-45-invert-l: var(--bulma-info-00-l); + --bulma-info-45-invert: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-45-invert-l), 1); + --bulma-info-50: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-50-l), 1); + --bulma-info-50-invert-l: var(--bulma-info-05-l); + --bulma-info-50-invert: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-50-invert-l), 1); + --bulma-info-55: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-55-l), 1); + --bulma-info-55-invert-l: var(--bulma-info-05-l); + --bulma-info-55-invert: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-55-invert-l), 1); + --bulma-info-60: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-60-l), 1); + --bulma-info-60-invert-l: var(--bulma-info-10-l); + --bulma-info-60-invert: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-60-invert-l), 1); + --bulma-info-65: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-65-l), 1); + --bulma-info-65-invert-l: var(--bulma-info-10-l); + --bulma-info-65-invert: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-65-invert-l), 1); + --bulma-info-70: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-70-l), 1); + --bulma-info-70-invert-l: var(--bulma-info-10-l); + --bulma-info-70-invert: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-70-invert-l), 1); + --bulma-info-75: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-75-l), 1); + --bulma-info-75-invert-l: var(--bulma-info-10-l); + --bulma-info-75-invert: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-75-invert-l), 1); + --bulma-info-80: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-80-l), 1); + --bulma-info-80-invert-l: var(--bulma-info-15-l); + --bulma-info-80-invert: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-80-invert-l), 1); + --bulma-info-85: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-85-l), 1); + --bulma-info-85-invert-l: var(--bulma-info-15-l); + --bulma-info-85-invert: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-85-invert-l), 1); + --bulma-info-90: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-90-l), 1); + --bulma-info-90-invert-l: var(--bulma-info-15-l); + --bulma-info-90-invert: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-90-invert-l), 1); + --bulma-info-95: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-95-l), 1); + --bulma-info-95-invert-l: var(--bulma-info-20-l); + --bulma-info-95-invert: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-95-invert-l), 1); + --bulma-info-100: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-100-l), 1); + --bulma-info-100-invert-l: var(--bulma-info-20-l); + --bulma-info-100-invert: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-100-invert-l), 1); + --bulma-info-invert-l: var(--bulma-info-10-l); + --bulma-info-invert: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-invert-l), 1); + --bulma-info-light-l: var(--bulma-info-90-l); + --bulma-info-light: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-light-l), 1); + --bulma-info-light-invert-l: var(--bulma-info-15-l); + --bulma-info-light-invert: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-light-invert-l), 1); + --bulma-info-dark-l: var(--bulma-info-10-l); + --bulma-info-dark: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-dark-l), 1); + --bulma-info-dark-invert-l: var(--bulma-info-60-l); + --bulma-info-dark-invert: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-dark-invert-l), 1); + --bulma-info-soft: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-soft-l), 1); + --bulma-info-bold: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-bold-l), 1); + --bulma-info-soft-invert: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-soft-invert-l), 1); + --bulma-info-bold-invert: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-bold-invert-l), 1); + --bulma-info-on-scheme-l: 25%; + --bulma-info-on-scheme: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-on-scheme-l), 1); + --bulma-success: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-l), 1); + --bulma-success-base: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-l), 1); + --bulma-success-rgb: 71.6295, 198.6705, 141.50205; + --bulma-success-h: 153deg; + --bulma-success-s: 53%; + --bulma-success-l: 53%; + --bulma-success-00-l: 0%; + --bulma-success-05-l: 3%; + --bulma-success-10-l: 8%; + --bulma-success-15-l: 13%; + --bulma-success-20-l: 18%; + --bulma-success-25-l: 23%; + --bulma-success-30-l: 28%; + --bulma-success-35-l: 33%; + --bulma-success-40-l: 38%; + --bulma-success-45-l: 43%; + --bulma-success-50-l: 48%; + --bulma-success-55-l: 53%; + --bulma-success-60-l: 58%; + --bulma-success-65-l: 63%; + --bulma-success-70-l: 68%; + --bulma-success-75-l: 73%; + --bulma-success-80-l: 78%; + --bulma-success-85-l: 83%; + --bulma-success-90-l: 88%; + --bulma-success-95-l: 93%; + --bulma-success-100-l: 98%; + --bulma-success-00: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-00-l), 1); + --bulma-success-00-invert-l: var(--bulma-success-45-l); + --bulma-success-00-invert: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-00-invert-l), 1); + --bulma-success-05: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-05-l), 1); + --bulma-success-05-invert-l: var(--bulma-success-45-l); + --bulma-success-05-invert: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-05-invert-l), 1); + --bulma-success-10: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-10-l), 1); + --bulma-success-10-invert-l: var(--bulma-success-55-l); + --bulma-success-10-invert: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-10-invert-l), 1); + --bulma-success-15: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-15-l), 1); + --bulma-success-15-invert-l: var(--bulma-success-75-l); + --bulma-success-15-invert: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-15-invert-l), 1); + --bulma-success-20: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-20-l), 1); + --bulma-success-20-invert-l: var(--bulma-success-95-l); + --bulma-success-20-invert: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-20-invert-l), 1); + --bulma-success-25: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-25-l), 1); + --bulma-success-25-invert-l: var(--bulma-success-100-l); + --bulma-success-25-invert: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-25-invert-l), 1); + --bulma-success-30: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-30-l), 1); + --bulma-success-30-invert-l: var(--bulma-success-100-l); + --bulma-success-30-invert: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-30-invert-l), 1); + --bulma-success-35: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-35-l), 1); + --bulma-success-35-invert-l: var(--bulma-success-100-l); + --bulma-success-35-invert: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-35-invert-l), 1); + --bulma-success-40: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-40-l), 1); + --bulma-success-40-invert-l: var(--bulma-success-100-l); + --bulma-success-40-invert: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-40-invert-l), 1); + --bulma-success-45: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-45-l), 1); + --bulma-success-45-invert-l: var(--bulma-success-05-l); + --bulma-success-45-invert: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-45-invert-l), 1); + --bulma-success-50: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-50-l), 1); + --bulma-success-50-invert-l: var(--bulma-success-05-l); + --bulma-success-50-invert: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-50-invert-l), 1); + --bulma-success-55: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-55-l), 1); + --bulma-success-55-invert-l: var(--bulma-success-10-l); + --bulma-success-55-invert: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-55-invert-l), 1); + --bulma-success-60: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-60-l), 1); + --bulma-success-60-invert-l: var(--bulma-success-10-l); + --bulma-success-60-invert: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-60-invert-l), 1); + --bulma-success-65: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-65-l), 1); + --bulma-success-65-invert-l: var(--bulma-success-10-l); + --bulma-success-65-invert: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-65-invert-l), 1); + --bulma-success-70: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-70-l), 1); + --bulma-success-70-invert-l: var(--bulma-success-10-l); + --bulma-success-70-invert: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-70-invert-l), 1); + --bulma-success-75: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-75-l), 1); + --bulma-success-75-invert-l: var(--bulma-success-15-l); + --bulma-success-75-invert: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-75-invert-l), 1); + --bulma-success-80: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-80-l), 1); + --bulma-success-80-invert-l: var(--bulma-success-15-l); + --bulma-success-80-invert: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-80-invert-l), 1); + --bulma-success-85: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-85-l), 1); + --bulma-success-85-invert-l: var(--bulma-success-15-l); + --bulma-success-85-invert: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-85-invert-l), 1); + --bulma-success-90: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-90-l), 1); + --bulma-success-90-invert-l: var(--bulma-success-15-l); + --bulma-success-90-invert: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-90-invert-l), 1); + --bulma-success-95: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-95-l), 1); + --bulma-success-95-invert-l: var(--bulma-success-20-l); + --bulma-success-95-invert: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-95-invert-l), 1); + --bulma-success-100: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-100-l), 1); + --bulma-success-100-invert-l: var(--bulma-success-20-l); + --bulma-success-100-invert: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-100-invert-l), 1); + --bulma-success-invert-l: var(--bulma-success-10-l); + --bulma-success-invert: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-invert-l), 1); + --bulma-success-light-l: var(--bulma-success-90-l); + --bulma-success-light: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-light-l), 1); + --bulma-success-light-invert-l: var(--bulma-success-15-l); + --bulma-success-light-invert: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-light-invert-l), 1); + --bulma-success-dark-l: var(--bulma-success-10-l); + --bulma-success-dark: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-dark-l), 1); + --bulma-success-dark-invert-l: var(--bulma-success-55-l); + --bulma-success-dark-invert: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-dark-invert-l), 1); + --bulma-success-soft: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-soft-l), 1); + --bulma-success-bold: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-bold-l), 1); + --bulma-success-soft-invert: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-soft-invert-l), 1); + --bulma-success-bold-invert: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-bold-invert-l), 1); + --bulma-success-on-scheme-l: 23%; + --bulma-success-on-scheme: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-on-scheme-l), 1); + --bulma-warning: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-l), 1); + --bulma-warning-base: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-l), 1); + --bulma-warning-rgb: 255, 183.09, 15.3; + --bulma-warning-h: 42deg; + --bulma-warning-s: 100%; + --bulma-warning-l: 53%; + --bulma-warning-00-l: 0%; + --bulma-warning-05-l: 3%; + --bulma-warning-10-l: 8%; + --bulma-warning-15-l: 13%; + --bulma-warning-20-l: 18%; + --bulma-warning-25-l: 23%; + --bulma-warning-30-l: 28%; + --bulma-warning-35-l: 33%; + --bulma-warning-40-l: 38%; + --bulma-warning-45-l: 43%; + --bulma-warning-50-l: 48%; + --bulma-warning-55-l: 53%; + --bulma-warning-60-l: 58%; + --bulma-warning-65-l: 63%; + --bulma-warning-70-l: 68%; + --bulma-warning-75-l: 73%; + --bulma-warning-80-l: 78%; + --bulma-warning-85-l: 83%; + --bulma-warning-90-l: 88%; + --bulma-warning-95-l: 93%; + --bulma-warning-100-l: 98%; + --bulma-warning-00: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-00-l), 1); + --bulma-warning-00-invert-l: var(--bulma-warning-40-l); + --bulma-warning-00-invert: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-00-invert-l), 1); + --bulma-warning-05: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-05-l), 1); + --bulma-warning-05-invert-l: var(--bulma-warning-45-l); + --bulma-warning-05-invert: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-05-invert-l), 1); + --bulma-warning-10: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-10-l), 1); + --bulma-warning-10-invert-l: var(--bulma-warning-50-l); + --bulma-warning-10-invert: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-10-invert-l), 1); + --bulma-warning-15: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-15-l), 1); + --bulma-warning-15-invert-l: var(--bulma-warning-70-l); + --bulma-warning-15-invert: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-15-invert-l), 1); + --bulma-warning-20: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-20-l), 1); + --bulma-warning-20-invert-l: var(--bulma-warning-100-l); + --bulma-warning-20-invert: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-20-invert-l), 1); + --bulma-warning-25: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-25-l), 1); + --bulma-warning-25-invert-l: var(--bulma-warning-100-l); + --bulma-warning-25-invert: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-25-invert-l), 1); + --bulma-warning-30: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-30-l), 1); + --bulma-warning-30-invert-l: var(--bulma-warning-100-l); + --bulma-warning-30-invert: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-30-invert-l), 1); + --bulma-warning-35: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-35-l), 1); + --bulma-warning-35-invert-l: var(--bulma-warning-100-l); + --bulma-warning-35-invert: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-35-invert-l), 1); + --bulma-warning-40: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-40-l), 1); + --bulma-warning-40-invert-l: var(--bulma-warning-00-l); + --bulma-warning-40-invert: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-40-invert-l), 1); + --bulma-warning-45: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-45-l), 1); + --bulma-warning-45-invert-l: var(--bulma-warning-05-l); + --bulma-warning-45-invert: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-45-invert-l), 1); + --bulma-warning-50: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-50-l), 1); + --bulma-warning-50-invert-l: var(--bulma-warning-10-l); + --bulma-warning-50-invert: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-50-invert-l), 1); + --bulma-warning-55: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-55-l), 1); + --bulma-warning-55-invert-l: var(--bulma-warning-10-l); + --bulma-warning-55-invert: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-55-invert-l), 1); + --bulma-warning-60: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-60-l), 1); + --bulma-warning-60-invert-l: var(--bulma-warning-10-l); + --bulma-warning-60-invert: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-60-invert-l), 1); + --bulma-warning-65: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-65-l), 1); + --bulma-warning-65-invert-l: var(--bulma-warning-10-l); + --bulma-warning-65-invert: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-65-invert-l), 1); + --bulma-warning-70: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-70-l), 1); + --bulma-warning-70-invert-l: var(--bulma-warning-15-l); + --bulma-warning-70-invert: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-70-invert-l), 1); + --bulma-warning-75: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-75-l), 1); + --bulma-warning-75-invert-l: var(--bulma-warning-15-l); + --bulma-warning-75-invert: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-75-invert-l), 1); + --bulma-warning-80: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-80-l), 1); + --bulma-warning-80-invert-l: var(--bulma-warning-15-l); + --bulma-warning-80-invert: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-80-invert-l), 1); + --bulma-warning-85: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-85-l), 1); + --bulma-warning-85-invert-l: var(--bulma-warning-15-l); + --bulma-warning-85-invert: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-85-invert-l), 1); + --bulma-warning-90: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-90-l), 1); + --bulma-warning-90-invert-l: var(--bulma-warning-15-l); + --bulma-warning-90-invert: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-90-invert-l), 1); + --bulma-warning-95: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-95-l), 1); + --bulma-warning-95-invert-l: var(--bulma-warning-15-l); + --bulma-warning-95-invert: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-95-invert-l), 1); + --bulma-warning-100: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-100-l), 1); + --bulma-warning-100-invert-l: var(--bulma-warning-20-l); + --bulma-warning-100-invert: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-100-invert-l), 1); + --bulma-warning-invert-l: var(--bulma-warning-10-l); + --bulma-warning-invert: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-invert-l), 1); + --bulma-warning-light-l: var(--bulma-warning-90-l); + --bulma-warning-light: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-light-l), 1); + --bulma-warning-light-invert-l: var(--bulma-warning-15-l); + --bulma-warning-light-invert: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-light-invert-l), 1); + --bulma-warning-dark-l: var(--bulma-warning-10-l); + --bulma-warning-dark: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-dark-l), 1); + --bulma-warning-dark-invert-l: var(--bulma-warning-50-l); + --bulma-warning-dark-invert: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-dark-invert-l), 1); + --bulma-warning-soft: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-soft-l), 1); + --bulma-warning-bold: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-bold-l), 1); + --bulma-warning-soft-invert: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-soft-invert-l), 1); + --bulma-warning-bold-invert: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-bold-invert-l), 1); + --bulma-warning-on-scheme-l: 23%; + --bulma-warning-on-scheme: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-on-scheme-l), 1); + --bulma-danger: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-l), 1); + --bulma-danger-base: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-l), 1); + --bulma-danger-rgb: 255, 102, 132.6; + --bulma-danger-h: 348deg; + --bulma-danger-s: 100%; + --bulma-danger-l: 70%; + --bulma-danger-00-l: 0%; + --bulma-danger-05-l: 5%; + --bulma-danger-10-l: 10%; + --bulma-danger-15-l: 15%; + --bulma-danger-20-l: 20%; + --bulma-danger-25-l: 25%; + --bulma-danger-30-l: 30%; + --bulma-danger-35-l: 35%; + --bulma-danger-40-l: 40%; + --bulma-danger-45-l: 45%; + --bulma-danger-50-l: 50%; + --bulma-danger-55-l: 55%; + --bulma-danger-60-l: 60%; + --bulma-danger-65-l: 65%; + --bulma-danger-70-l: 70%; + --bulma-danger-75-l: 75%; + --bulma-danger-80-l: 80%; + --bulma-danger-85-l: 85%; + --bulma-danger-90-l: 90%; + --bulma-danger-95-l: 95%; + --bulma-danger-100-l: 100%; + --bulma-danger-00: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-00-l), 1); + --bulma-danger-00-invert-l: var(--bulma-danger-65-l); + --bulma-danger-00-invert: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-00-invert-l), 1); + --bulma-danger-05: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-05-l), 1); + --bulma-danger-05-invert-l: var(--bulma-danger-70-l); + --bulma-danger-05-invert: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-05-invert-l), 1); + --bulma-danger-10: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-10-l), 1); + --bulma-danger-10-invert-l: var(--bulma-danger-75-l); + --bulma-danger-10-invert: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-10-invert-l), 1); + --bulma-danger-15: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-15-l), 1); + --bulma-danger-15-invert-l: var(--bulma-danger-80-l); + --bulma-danger-15-invert: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-15-invert-l), 1); + --bulma-danger-20: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-20-l), 1); + --bulma-danger-20-invert-l: var(--bulma-danger-85-l); + --bulma-danger-20-invert: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-20-invert-l), 1); + --bulma-danger-25: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-25-l), 1); + --bulma-danger-25-invert-l: var(--bulma-danger-90-l); + --bulma-danger-25-invert: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-25-invert-l), 1); + --bulma-danger-30: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-30-l), 1); + --bulma-danger-30-invert-l: var(--bulma-danger-100-l); + --bulma-danger-30-invert: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-30-invert-l), 1); + --bulma-danger-35: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-35-l), 1); + --bulma-danger-35-invert-l: var(--bulma-danger-100-l); + --bulma-danger-35-invert: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-35-invert-l), 1); + --bulma-danger-40: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-40-l), 1); + --bulma-danger-40-invert-l: var(--bulma-danger-100-l); + --bulma-danger-40-invert: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-40-invert-l), 1); + --bulma-danger-45: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-45-l), 1); + --bulma-danger-45-invert-l: var(--bulma-danger-100-l); + --bulma-danger-45-invert: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-45-invert-l), 1); + --bulma-danger-50: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-50-l), 1); + --bulma-danger-50-invert-l: var(--bulma-danger-100-l); + --bulma-danger-50-invert: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-50-invert-l), 1); + --bulma-danger-55: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-55-l), 1); + --bulma-danger-55-invert-l: var(--bulma-danger-100-l); + --bulma-danger-55-invert: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-55-invert-l), 1); + --bulma-danger-60: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-60-l), 1); + --bulma-danger-60-invert-l: var(--bulma-danger-100-l); + --bulma-danger-60-invert: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-60-invert-l), 1); + --bulma-danger-65: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-65-l), 1); + --bulma-danger-65-invert-l: var(--bulma-danger-00-l); + --bulma-danger-65-invert: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-65-invert-l), 1); + --bulma-danger-70: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-70-l), 1); + --bulma-danger-70-invert-l: var(--bulma-danger-05-l); + --bulma-danger-70-invert: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-70-invert-l), 1); + --bulma-danger-75: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-75-l), 1); + --bulma-danger-75-invert-l: var(--bulma-danger-10-l); + --bulma-danger-75-invert: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-75-invert-l), 1); + --bulma-danger-80: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-80-l), 1); + --bulma-danger-80-invert-l: var(--bulma-danger-15-l); + --bulma-danger-80-invert: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-80-invert-l), 1); + --bulma-danger-85: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-85-l), 1); + --bulma-danger-85-invert-l: var(--bulma-danger-20-l); + --bulma-danger-85-invert: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-85-invert-l), 1); + --bulma-danger-90: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-90-l), 1); + --bulma-danger-90-invert-l: var(--bulma-danger-25-l); + --bulma-danger-90-invert: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-90-invert-l), 1); + --bulma-danger-95: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-95-l), 1); + --bulma-danger-95-invert-l: var(--bulma-danger-25-l); + --bulma-danger-95-invert: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-95-invert-l), 1); + --bulma-danger-100: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-100-l), 1); + --bulma-danger-100-invert-l: var(--bulma-danger-30-l); + --bulma-danger-100-invert: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-100-invert-l), 1); + --bulma-danger-invert-l: var(--bulma-danger-05-l); + --bulma-danger-invert: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-invert-l), 1); + --bulma-danger-light-l: var(--bulma-danger-90-l); + --bulma-danger-light: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-light-l), 1); + --bulma-danger-light-invert-l: var(--bulma-danger-25-l); + --bulma-danger-light-invert: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-light-invert-l), 1); + --bulma-danger-dark-l: var(--bulma-danger-10-l); + --bulma-danger-dark: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-dark-l), 1); + --bulma-danger-dark-invert-l: var(--bulma-danger-75-l); + --bulma-danger-dark-invert: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-dark-invert-l), 1); + --bulma-danger-soft: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-soft-l), 1); + --bulma-danger-bold: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-bold-l), 1); + --bulma-danger-soft-invert: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-soft-invert-l), 1); + --bulma-danger-bold-invert: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-bold-invert-l), 1); + --bulma-danger-on-scheme-l: 40%; + --bulma-danger-on-scheme: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-on-scheme-l), 1); + --bulma-black-bis: hsl(221, 14%, 9%); + --bulma-black-ter: hsl(221, 14%, 14%); + --bulma-grey-darker: hsl(221, 14%, 21%); + --bulma-grey-dark: hsl(221, 14%, 29%); + --bulma-grey: hsl(221, 14%, 48%); + --bulma-grey-light: hsl(221, 14%, 71%); + --bulma-grey-lighter: hsl(221, 14%, 86%); + --bulma-white-ter: hsl(221, 14%, 96%); + --bulma-white-bis: hsl(221, 14%, 98%); + --bulma-shadow-h: 221deg; + --bulma-shadow-s: 14%; + --bulma-shadow-l: 4%; + --bulma-size-1: 3rem; + --bulma-size-2: 2.5rem; + --bulma-size-3: 2rem; + --bulma-size-4: 1.5rem; + --bulma-size-5: 1.25rem; + --bulma-size-6: 1rem; + --bulma-size-7: 0.75rem; + --bulma-scheme-main: hsl(var(--bulma-scheme-h), var(--bulma-scheme-s), var(--bulma-scheme-main-l)); + --bulma-scheme-main-bis: hsl(var(--bulma-scheme-h), var(--bulma-scheme-s), var(--bulma-scheme-main-bis-l)); + --bulma-scheme-main-ter: hsl(var(--bulma-scheme-h), var(--bulma-scheme-s), var(--bulma-scheme-main-ter-l)); + --bulma-background: hsl(var(--bulma-scheme-h), var(--bulma-scheme-s), var(--bulma-background-l)); + --bulma-background-hover: hsl(var(--bulma-scheme-h), var(--bulma-scheme-s), calc(var(--bulma-background-l) + var(--bulma-hover-background-l-delta))); + --bulma-background-active: hsl(var(--bulma-scheme-h), var(--bulma-scheme-s), calc(var(--bulma-background-l) + var(--bulma-active-background-l-delta))); + --bulma-border-weak: hsl(var(--bulma-scheme-h), var(--bulma-scheme-s), var(--bulma-border-weak-l)); + --bulma-border: hsl(var(--bulma-scheme-h), var(--bulma-scheme-s), var(--bulma-border-l)); + --bulma-border-hover: hsl(var(--bulma-scheme-h), var(--bulma-scheme-s), calc(var(--bulma-border-l) + var(--bulma-hover-border-l-delta))); + --bulma-border-active: hsl(var(--bulma-scheme-h), var(--bulma-scheme-s), calc(var(--bulma-border-l) + var(--bulma-active-border-l-delta))); + --bulma-text-weak: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-weak-l)); + --bulma-text: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-l)); + --bulma-text-strong: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-strong-l)); + --bulma-scheme-invert-ter: hsl(var(--bulma-scheme-h), var(--bulma-scheme-s), var(--bulma-scheme-invert-ter-l)); + --bulma-scheme-invert-bis: hsl(var(--bulma-scheme-h), var(--bulma-scheme-s), var(--bulma-scheme-invert-bis-l)); + --bulma-scheme-invert: hsl(var(--bulma-scheme-h), var(--bulma-scheme-s), var(--bulma-scheme-invert-l)); + --bulma-link: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-l)); + --bulma-link-text: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-on-scheme-l)); + --bulma-link-text-hover: hsl(var(--bulma-link-h), var(--bulma-link-s), calc(var(--bulma-link-on-scheme-l) + var(--bulma-hover-color-l-delta))); + --bulma-link-text-active: hsl(var(--bulma-link-h), var(--bulma-link-s), calc(var(--bulma-link-on-scheme-l) + var(--bulma-active-color-l-delta))); + --bulma-focus-h: var(--bulma-link-h); + --bulma-focus-s: var(--bulma-link-s); + --bulma-focus-l: var(--bulma-link-l); + --bulma-focus-offset: 1px; + --bulma-focus-style: solid; + --bulma-focus-width: 2px; + --bulma-focus-shadow-size: 0 0 0 0.1875em; + --bulma-focus-shadow-alpha: 0.25; + --bulma-code: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-on-scheme-l)); + --bulma-code-background: var(--bulma-background); + --bulma-pre: var(--bulma-text); + --bulma-pre-background: var(--bulma-background); + --bulma-shadow: 0 0.5em 1em -0.125em hsla(var(--bulma-shadow-h), var(--bulma-shadow-s), var(--bulma-shadow-l), 0.1), 0 0px 0 1px hsla(var(--bulma-shadow-h), var(--bulma-shadow-s), var(--bulma-shadow-l), 0.02); +} + +@media (prefers-color-scheme: light) { + :root { + --bulma-scheme-h: 221; + --bulma-scheme-s: 14%; + --bulma-light-l: 90%; + --bulma-light-invert-l: 20%; + --bulma-dark-l: 20%; + --bulma-dark-invert-l: 90%; + --bulma-soft-l: 90%; + --bulma-bold-l: 20%; + --bulma-soft-invert-l: 20%; + --bulma-bold-invert-l: 90%; + --bulma-hover-background-l-delta: -5%; + --bulma-active-background-l-delta: -10%; + --bulma-hover-border-l-delta: -10%; + --bulma-active-border-l-delta: -20%; + --bulma-hover-color-l-delta: -5%; + --bulma-active-color-l-delta: -10%; + --bulma-hover-shadow-a-delta: -0.05; + --bulma-active-shadow-a-delta: -0.1; + --bulma-scheme-brightness: light; + --bulma-scheme-main-l: 100%; + --bulma-scheme-main-bis-l: 98%; + --bulma-scheme-main-ter-l: 96%; + --bulma-background-l: 96%; + --bulma-border-weak-l: 93%; + --bulma-border-l: 86%; + --bulma-text-weak-l: 48%; + --bulma-text-l: 29%; + --bulma-text-strong-l: 21%; + --bulma-text-title-l: 14%; + --bulma-scheme-invert-ter-l: 14%; + --bulma-scheme-invert-bis-l: 7%; + --bulma-scheme-invert-l: 4%; + --bulma-family-primary: Inter, SF Pro, Segoe UI, Roboto, Oxygen, Ubuntu, Helvetica Neue, Helvetica, Arial, sans-serif; + --bulma-family-secondary: Inter, SF Pro, Segoe UI, Roboto, Oxygen, Ubuntu, Helvetica Neue, Helvetica, Arial, sans-serif; + --bulma-family-code: Inconsolata, Hack, SF Mono, Roboto Mono, Source Code Pro, Ubuntu Mono, monospace; + --bulma-size-small: 0.75rem; + --bulma-size-normal: 1rem; + --bulma-size-medium: 1.25rem; + --bulma-size-large: 1.5rem; + --bulma-weight-light: 300; + --bulma-weight-normal: 400; + --bulma-weight-medium: 500; + --bulma-weight-semibold: 600; + --bulma-weight-bold: 700; + --bulma-weight-extrabold: 800; + --bulma-block-spacing: 1.5rem; + --bulma-duration: 294ms; + --bulma-easing: ease-out; + --bulma-radius-small: 0.25rem; + --bulma-radius: 0.375rem; + --bulma-radius-medium: 0.5em; + --bulma-radius-large: 0.75rem; + --bulma-radius-rounded: 9999px; + --bulma-speed: 86ms; + --bulma-arrow-color: var(--bulma-link); + --bulma-loading-color: var(--bulma-border); + --bulma-burger-h: var(--bulma-link-h); + --bulma-burger-s: var(--bulma-link-s); + --bulma-burger-l: var(--bulma-link-l); + --bulma-burger-border-radius: 0.5em; + --bulma-burger-gap: 5px; + --bulma-burger-item-height: 2px; + --bulma-burger-item-width: 20px; + --bulma-white: hsla(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-l), 1); + --bulma-white-base: hsla(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-l), 1); + --bulma-white-rgb: 255, 255, 255; + --bulma-white-h: 221deg; + --bulma-white-s: 14%; + --bulma-white-l: 100%; + --bulma-white-invert-l: 4%; + --bulma-white-invert: hsl(221, 14%, 4%); + --bulma-white-on-scheme-l: 35%; + --bulma-white-on-scheme: hsla(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-on-scheme-l), 1); + --bulma-black: hsla(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-l), 1); + --bulma-black-base: hsla(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-l), 1); + --bulma-black-rgb: 8.772, 9.6764, 11.628; + --bulma-black-h: 221deg; + --bulma-black-s: 14%; + --bulma-black-l: 4%; + --bulma-black-invert-l: 100%; + --bulma-black-invert: hsl(221, 14%, 100%); + --bulma-black-on-scheme-l: 4%; + --bulma-black-on-scheme: hsla(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-on-scheme-l), 1); + --bulma-light: hsla(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-l), 1); + --bulma-light-base: hsla(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-l), 1); + --bulma-light-rgb: 243.372, 244.2764, 246.228; + --bulma-light-h: 221deg; + --bulma-light-s: 14%; + --bulma-light-l: 96%; + --bulma-light-invert-l: 21%; + --bulma-light-invert: hsl(221, 14%, 21%); + --bulma-light-on-scheme-l: 36%; + --bulma-light-on-scheme: hsla(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-on-scheme-l), 1); + --bulma-dark: hsla(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-l), 1); + --bulma-dark-base: hsla(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-l), 1); + --bulma-dark-rgb: 46.053, 50.8011, 61.047; + --bulma-dark-h: 221deg; + --bulma-dark-s: 14%; + --bulma-dark-l: 21%; + --bulma-dark-invert-l: 96%; + --bulma-dark-invert: hsl(221, 14%, 96%); + --bulma-dark-on-scheme-l: 21%; + --bulma-dark-on-scheme: hsla(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-on-scheme-l), 1); + --bulma-text: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-l), 1); + --bulma-text-base: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-l), 1); + --bulma-text-rgb: 63.597, 70.1539, 84.303; + --bulma-text-h: 221deg; + --bulma-text-s: 14%; + --bulma-text-l: 29%; + --bulma-text-00-l: 0%; + --bulma-text-05-l: 4%; + --bulma-text-10-l: 9%; + --bulma-text-15-l: 14%; + --bulma-text-20-l: 19%; + --bulma-text-25-l: 24%; + --bulma-text-30-l: 29%; + --bulma-text-35-l: 34%; + --bulma-text-40-l: 39%; + --bulma-text-45-l: 44%; + --bulma-text-50-l: 49%; + --bulma-text-55-l: 54%; + --bulma-text-60-l: 59%; + --bulma-text-65-l: 64%; + --bulma-text-70-l: 69%; + --bulma-text-75-l: 74%; + --bulma-text-80-l: 79%; + --bulma-text-85-l: 84%; + --bulma-text-90-l: 89%; + --bulma-text-95-l: 94%; + --bulma-text-100-l: 99%; + --bulma-text-00: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-00-l), 1); + --bulma-text-00-invert-l: var(--bulma-text-60-l); + --bulma-text-00-invert: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-00-invert-l), 1); + --bulma-text-05: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-05-l), 1); + --bulma-text-05-invert-l: var(--bulma-text-60-l); + --bulma-text-05-invert: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-05-invert-l), 1); + --bulma-text-10: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-10-l), 1); + --bulma-text-10-invert-l: var(--bulma-text-70-l); + --bulma-text-10-invert: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-10-invert-l), 1); + --bulma-text-15: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-15-l), 1); + --bulma-text-15-invert-l: var(--bulma-text-75-l); + --bulma-text-15-invert: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-15-invert-l), 1); + --bulma-text-20: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-20-l), 1); + --bulma-text-20-invert-l: var(--bulma-text-85-l); + --bulma-text-20-invert: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-20-invert-l), 1); + --bulma-text-25: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-25-l), 1); + --bulma-text-25-invert-l: var(--bulma-text-95-l); + --bulma-text-25-invert: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-25-invert-l), 1); + --bulma-text-30: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-30-l), 1); + --bulma-text-30-invert-l: var(--bulma-text-100-l); + --bulma-text-30-invert: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-30-invert-l), 1); + --bulma-text-35: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-35-l), 1); + --bulma-text-35-invert-l: var(--bulma-text-100-l); + --bulma-text-35-invert: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-35-invert-l), 1); + --bulma-text-40: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-40-l), 1); + --bulma-text-40-invert-l: var(--bulma-text-100-l); + --bulma-text-40-invert: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-40-invert-l), 1); + --bulma-text-45: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-45-l), 1); + --bulma-text-45-invert-l: var(--bulma-text-100-l); + --bulma-text-45-invert: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-45-invert-l), 1); + --bulma-text-50: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-50-l), 1); + --bulma-text-50-invert-l: var(--bulma-text-100-l); + --bulma-text-50-invert: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-50-invert-l), 1); + --bulma-text-55: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-55-l), 1); + --bulma-text-55-invert-l: var(--bulma-text-100-l); + --bulma-text-55-invert: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-55-invert-l), 1); + --bulma-text-60: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-60-l), 1); + --bulma-text-60-invert-l: var(--bulma-text-05-l); + --bulma-text-60-invert: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-60-invert-l), 1); + --bulma-text-65: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-65-l), 1); + --bulma-text-65-invert-l: var(--bulma-text-05-l); + --bulma-text-65-invert: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-65-invert-l), 1); + --bulma-text-70: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-70-l), 1); + --bulma-text-70-invert-l: var(--bulma-text-10-l); + --bulma-text-70-invert: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-70-invert-l), 1); + --bulma-text-75: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-75-l), 1); + --bulma-text-75-invert-l: var(--bulma-text-15-l); + --bulma-text-75-invert: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-75-invert-l), 1); + --bulma-text-80: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-80-l), 1); + --bulma-text-80-invert-l: var(--bulma-text-15-l); + --bulma-text-80-invert: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-80-invert-l), 1); + --bulma-text-85: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-85-l), 1); + --bulma-text-85-invert-l: var(--bulma-text-20-l); + --bulma-text-85-invert: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-85-invert-l), 1); + --bulma-text-90: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-90-l), 1); + --bulma-text-90-invert-l: var(--bulma-text-20-l); + --bulma-text-90-invert: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-90-invert-l), 1); + --bulma-text-95: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-95-l), 1); + --bulma-text-95-invert-l: var(--bulma-text-25-l); + --bulma-text-95-invert: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-95-invert-l), 1); + --bulma-text-100: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-100-l), 1); + --bulma-text-100-invert-l: var(--bulma-text-25-l); + --bulma-text-100-invert: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-100-invert-l), 1); + --bulma-text-invert-l: var(--bulma-text-100-l); + --bulma-text-invert: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-invert-l), 1); + --bulma-text-light-l: var(--bulma-text-90-l); + --bulma-text-light: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-light-l), 1); + --bulma-text-light-invert-l: var(--bulma-text-20-l); + --bulma-text-light-invert: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-light-invert-l), 1); + --bulma-text-dark-l: var(--bulma-text-10-l); + --bulma-text-dark: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-dark-l), 1); + --bulma-text-dark-invert-l: var(--bulma-text-70-l); + --bulma-text-dark-invert: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-dark-invert-l), 1); + --bulma-text-soft: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-soft-l), 1); + --bulma-text-bold: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-bold-l), 1); + --bulma-text-soft-invert: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-soft-invert-l), 1); + --bulma-text-bold-invert: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-bold-invert-l), 1); + --bulma-text-on-scheme-l: 29%; + --bulma-text-on-scheme: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-on-scheme-l), 1); + --bulma-primary: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-l), 1); + --bulma-primary-base: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-l), 1); + --bulma-primary-rgb: 0, 209.1, 177.735; + --bulma-primary-h: 171deg; + --bulma-primary-s: 100%; + --bulma-primary-l: 41%; + --bulma-primary-00-l: 1%; + --bulma-primary-05-l: 6%; + --bulma-primary-10-l: 11%; + --bulma-primary-15-l: 16%; + --bulma-primary-20-l: 21%; + --bulma-primary-25-l: 26%; + --bulma-primary-30-l: 31%; + --bulma-primary-35-l: 36%; + --bulma-primary-40-l: 41%; + --bulma-primary-45-l: 46%; + --bulma-primary-50-l: 51%; + --bulma-primary-55-l: 56%; + --bulma-primary-60-l: 61%; + --bulma-primary-65-l: 66%; + --bulma-primary-70-l: 71%; + --bulma-primary-75-l: 76%; + --bulma-primary-80-l: 81%; + --bulma-primary-85-l: 86%; + --bulma-primary-90-l: 91%; + --bulma-primary-95-l: 96%; + --bulma-primary-100-l: 100%; + --bulma-primary-00: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-00-l), 1); + --bulma-primary-00-invert-l: var(--bulma-primary-30-l); + --bulma-primary-00-invert: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-00-invert-l), 1); + --bulma-primary-05: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-05-l), 1); + --bulma-primary-05-invert-l: var(--bulma-primary-40-l); + --bulma-primary-05-invert: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-05-invert-l), 1); + --bulma-primary-10: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-10-l), 1); + --bulma-primary-10-invert-l: var(--bulma-primary-50-l); + --bulma-primary-10-invert: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-10-invert-l), 1); + --bulma-primary-15: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-15-l), 1); + --bulma-primary-15-invert-l: var(--bulma-primary-100-l); + --bulma-primary-15-invert: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-15-invert-l), 1); + --bulma-primary-20: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-20-l), 1); + --bulma-primary-20-invert-l: var(--bulma-primary-100-l); + --bulma-primary-20-invert: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-20-invert-l), 1); + --bulma-primary-25: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-25-l), 1); + --bulma-primary-25-invert-l: var(--bulma-primary-100-l); + --bulma-primary-25-invert: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-25-invert-l), 1); + --bulma-primary-30: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-30-l), 1); + --bulma-primary-30-invert-l: var(--bulma-primary-00-l); + --bulma-primary-30-invert: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-30-invert-l), 1); + --bulma-primary-35: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-35-l), 1); + --bulma-primary-35-invert-l: var(--bulma-primary-00-l); + --bulma-primary-35-invert: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-35-invert-l), 1); + --bulma-primary-40: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-40-l), 1); + --bulma-primary-40-invert-l: var(--bulma-primary-05-l); + --bulma-primary-40-invert: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-40-invert-l), 1); + --bulma-primary-45: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-45-l), 1); + --bulma-primary-45-invert-l: var(--bulma-primary-05-l); + --bulma-primary-45-invert: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-45-invert-l), 1); + --bulma-primary-50: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-50-l), 1); + --bulma-primary-50-invert-l: var(--bulma-primary-10-l); + --bulma-primary-50-invert: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-50-invert-l), 1); + --bulma-primary-55: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-55-l), 1); + --bulma-primary-55-invert-l: var(--bulma-primary-10-l); + --bulma-primary-55-invert: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-55-invert-l), 1); + --bulma-primary-60: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-60-l), 1); + --bulma-primary-60-invert-l: var(--bulma-primary-10-l); + --bulma-primary-60-invert: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-60-invert-l), 1); + --bulma-primary-65: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-65-l), 1); + --bulma-primary-65-invert-l: var(--bulma-primary-10-l); + --bulma-primary-65-invert: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-65-invert-l), 1); + --bulma-primary-70: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-70-l), 1); + --bulma-primary-70-invert-l: var(--bulma-primary-10-l); + --bulma-primary-70-invert: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-70-invert-l), 1); + --bulma-primary-75: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-75-l), 1); + --bulma-primary-75-invert-l: var(--bulma-primary-10-l); + --bulma-primary-75-invert: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-75-invert-l), 1); + --bulma-primary-80: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-80-l), 1); + --bulma-primary-80-invert-l: var(--bulma-primary-10-l); + --bulma-primary-80-invert: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-80-invert-l), 1); + --bulma-primary-85: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-85-l), 1); + --bulma-primary-85-invert-l: var(--bulma-primary-10-l); + --bulma-primary-85-invert: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-85-invert-l), 1); + --bulma-primary-90: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-90-l), 1); + --bulma-primary-90-invert-l: var(--bulma-primary-10-l); + --bulma-primary-90-invert: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-90-invert-l), 1); + --bulma-primary-95: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-95-l), 1); + --bulma-primary-95-invert-l: var(--bulma-primary-10-l); + --bulma-primary-95-invert: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-95-invert-l), 1); + --bulma-primary-100: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-100-l), 1); + --bulma-primary-100-invert-l: var(--bulma-primary-15-l); + --bulma-primary-100-invert: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-100-invert-l), 1); + --bulma-primary-invert-l: var(--bulma-primary-05-l); + --bulma-primary-invert: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-invert-l), 1); + --bulma-primary-light-l: var(--bulma-primary-90-l); + --bulma-primary-light: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-light-l), 1); + --bulma-primary-light-invert-l: var(--bulma-primary-10-l); + --bulma-primary-light-invert: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-light-invert-l), 1); + --bulma-primary-dark-l: var(--bulma-primary-10-l); + --bulma-primary-dark: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-dark-l), 1); + --bulma-primary-dark-invert-l: var(--bulma-primary-50-l); + --bulma-primary-dark-invert: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-dark-invert-l), 1); + --bulma-primary-soft: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-soft-l), 1); + --bulma-primary-bold: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-bold-l), 1); + --bulma-primary-soft-invert: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-soft-invert-l), 1); + --bulma-primary-bold-invert: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-bold-invert-l), 1); + --bulma-primary-on-scheme-l: 21%; + --bulma-primary-on-scheme: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-on-scheme-l), 1); + --bulma-link: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-l), 1); + --bulma-link-base: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-l), 1); + --bulma-link-rgb: 66.3, 88.315, 255; + --bulma-link-h: 233deg; + --bulma-link-s: 100%; + --bulma-link-l: 63%; + --bulma-link-00-l: 0%; + --bulma-link-05-l: 3%; + --bulma-link-10-l: 8%; + --bulma-link-15-l: 13%; + --bulma-link-20-l: 18%; + --bulma-link-25-l: 23%; + --bulma-link-30-l: 28%; + --bulma-link-35-l: 33%; + --bulma-link-40-l: 38%; + --bulma-link-45-l: 43%; + --bulma-link-50-l: 48%; + --bulma-link-55-l: 53%; + --bulma-link-60-l: 58%; + --bulma-link-65-l: 63%; + --bulma-link-70-l: 68%; + --bulma-link-75-l: 73%; + --bulma-link-80-l: 78%; + --bulma-link-85-l: 83%; + --bulma-link-90-l: 88%; + --bulma-link-95-l: 93%; + --bulma-link-100-l: 98%; + --bulma-link-00: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-00-l), 1); + --bulma-link-00-invert-l: var(--bulma-link-75-l); + --bulma-link-00-invert: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-00-invert-l), 1); + --bulma-link-05: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-05-l), 1); + --bulma-link-05-invert-l: var(--bulma-link-75-l); + --bulma-link-05-invert: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-05-invert-l), 1); + --bulma-link-10: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-10-l), 1); + --bulma-link-10-invert-l: var(--bulma-link-75-l); + --bulma-link-10-invert: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-10-invert-l), 1); + --bulma-link-15: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-15-l), 1); + --bulma-link-15-invert-l: var(--bulma-link-80-l); + --bulma-link-15-invert: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-15-invert-l), 1); + --bulma-link-20: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-20-l), 1); + --bulma-link-20-invert-l: var(--bulma-link-80-l); + --bulma-link-20-invert: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-20-invert-l), 1); + --bulma-link-25: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-25-l), 1); + --bulma-link-25-invert-l: var(--bulma-link-85-l); + --bulma-link-25-invert: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-25-invert-l), 1); + --bulma-link-30: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-30-l), 1); + --bulma-link-30-invert-l: var(--bulma-link-90-l); + --bulma-link-30-invert: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-30-invert-l), 1); + --bulma-link-35: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-35-l), 1); + --bulma-link-35-invert-l: var(--bulma-link-90-l); + --bulma-link-35-invert: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-35-invert-l), 1); + --bulma-link-40: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-40-l), 1); + --bulma-link-40-invert-l: var(--bulma-link-95-l); + --bulma-link-40-invert: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-40-invert-l), 1); + --bulma-link-45: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-45-l), 1); + --bulma-link-45-invert-l: var(--bulma-link-95-l); + --bulma-link-45-invert: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-45-invert-l), 1); + --bulma-link-50: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-50-l), 1); + --bulma-link-50-invert-l: var(--bulma-link-100-l); + --bulma-link-50-invert: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-50-invert-l), 1); + --bulma-link-55: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-55-l), 1); + --bulma-link-55-invert-l: var(--bulma-link-100-l); + --bulma-link-55-invert: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-55-invert-l), 1); + --bulma-link-60: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-60-l), 1); + --bulma-link-60-invert-l: var(--bulma-link-100-l); + --bulma-link-60-invert: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-60-invert-l), 1); + --bulma-link-65: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-65-l), 1); + --bulma-link-65-invert-l: var(--bulma-link-100-l); + --bulma-link-65-invert: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-65-invert-l), 1); + --bulma-link-70: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-70-l), 1); + --bulma-link-70-invert-l: var(--bulma-link-100-l); + --bulma-link-70-invert: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-70-invert-l), 1); + --bulma-link-75: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-75-l), 1); + --bulma-link-75-invert-l: var(--bulma-link-10-l); + --bulma-link-75-invert: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-75-invert-l), 1); + --bulma-link-80: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-80-l), 1); + --bulma-link-80-invert-l: var(--bulma-link-20-l); + --bulma-link-80-invert: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-80-invert-l), 1); + --bulma-link-85: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-85-l), 1); + --bulma-link-85-invert-l: var(--bulma-link-25-l); + --bulma-link-85-invert: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-85-invert-l), 1); + --bulma-link-90: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-90-l), 1); + --bulma-link-90-invert-l: var(--bulma-link-35-l); + --bulma-link-90-invert: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-90-invert-l), 1); + --bulma-link-95: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-95-l), 1); + --bulma-link-95-invert-l: var(--bulma-link-45-l); + --bulma-link-95-invert: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-95-invert-l), 1); + --bulma-link-100: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-100-l), 1); + --bulma-link-100-invert-l: var(--bulma-link-50-l); + --bulma-link-100-invert: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-100-invert-l), 1); + --bulma-link-invert-l: var(--bulma-link-100-l); + --bulma-link-invert: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-invert-l), 1); + --bulma-link-light-l: var(--bulma-link-90-l); + --bulma-link-light: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-light-l), 1); + --bulma-link-light-invert-l: var(--bulma-link-35-l); + --bulma-link-light-invert: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-light-invert-l), 1); + --bulma-link-dark-l: var(--bulma-link-10-l); + --bulma-link-dark: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-dark-l), 1); + --bulma-link-dark-invert-l: var(--bulma-link-75-l); + --bulma-link-dark-invert: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-dark-invert-l), 1); + --bulma-link-soft: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-soft-l), 1); + --bulma-link-bold: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-bold-l), 1); + --bulma-link-soft-invert: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-soft-invert-l), 1); + --bulma-link-bold-invert: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-bold-invert-l), 1); + --bulma-link-on-scheme-l: 58%; + --bulma-link-on-scheme: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-on-scheme-l), 1); + --bulma-info: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-l), 1); + --bulma-info-base: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-l), 1); + --bulma-info-rgb: 102, 209.1, 255; + --bulma-info-h: 198deg; + --bulma-info-s: 100%; + --bulma-info-l: 70%; + --bulma-info-00-l: 0%; + --bulma-info-05-l: 5%; + --bulma-info-10-l: 10%; + --bulma-info-15-l: 15%; + --bulma-info-20-l: 20%; + --bulma-info-25-l: 25%; + --bulma-info-30-l: 30%; + --bulma-info-35-l: 35%; + --bulma-info-40-l: 40%; + --bulma-info-45-l: 45%; + --bulma-info-50-l: 50%; + --bulma-info-55-l: 55%; + --bulma-info-60-l: 60%; + --bulma-info-65-l: 65%; + --bulma-info-70-l: 70%; + --bulma-info-75-l: 75%; + --bulma-info-80-l: 80%; + --bulma-info-85-l: 85%; + --bulma-info-90-l: 90%; + --bulma-info-95-l: 95%; + --bulma-info-100-l: 100%; + --bulma-info-00: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-00-l), 1); + --bulma-info-00-invert-l: var(--bulma-info-45-l); + --bulma-info-00-invert: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-00-invert-l), 1); + --bulma-info-05: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-05-l), 1); + --bulma-info-05-invert-l: var(--bulma-info-50-l); + --bulma-info-05-invert: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-05-invert-l), 1); + --bulma-info-10: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-10-l), 1); + --bulma-info-10-invert-l: var(--bulma-info-60-l); + --bulma-info-10-invert: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-10-invert-l), 1); + --bulma-info-15: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-15-l), 1); + --bulma-info-15-invert-l: var(--bulma-info-80-l); + --bulma-info-15-invert: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-15-invert-l), 1); + --bulma-info-20: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-20-l), 1); + --bulma-info-20-invert-l: var(--bulma-info-95-l); + --bulma-info-20-invert: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-20-invert-l), 1); + --bulma-info-25: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-25-l), 1); + --bulma-info-25-invert-l: var(--bulma-info-100-l); + --bulma-info-25-invert: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-25-invert-l), 1); + --bulma-info-30: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-30-l), 1); + --bulma-info-30-invert-l: var(--bulma-info-100-l); + --bulma-info-30-invert: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-30-invert-l), 1); + --bulma-info-35: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-35-l), 1); + --bulma-info-35-invert-l: var(--bulma-info-100-l); + --bulma-info-35-invert: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-35-invert-l), 1); + --bulma-info-40: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-40-l), 1); + --bulma-info-40-invert-l: var(--bulma-info-100-l); + --bulma-info-40-invert: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-40-invert-l), 1); + --bulma-info-45: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-45-l), 1); + --bulma-info-45-invert-l: var(--bulma-info-00-l); + --bulma-info-45-invert: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-45-invert-l), 1); + --bulma-info-50: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-50-l), 1); + --bulma-info-50-invert-l: var(--bulma-info-05-l); + --bulma-info-50-invert: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-50-invert-l), 1); + --bulma-info-55: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-55-l), 1); + --bulma-info-55-invert-l: var(--bulma-info-05-l); + --bulma-info-55-invert: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-55-invert-l), 1); + --bulma-info-60: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-60-l), 1); + --bulma-info-60-invert-l: var(--bulma-info-10-l); + --bulma-info-60-invert: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-60-invert-l), 1); + --bulma-info-65: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-65-l), 1); + --bulma-info-65-invert-l: var(--bulma-info-10-l); + --bulma-info-65-invert: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-65-invert-l), 1); + --bulma-info-70: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-70-l), 1); + --bulma-info-70-invert-l: var(--bulma-info-10-l); + --bulma-info-70-invert: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-70-invert-l), 1); + --bulma-info-75: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-75-l), 1); + --bulma-info-75-invert-l: var(--bulma-info-10-l); + --bulma-info-75-invert: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-75-invert-l), 1); + --bulma-info-80: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-80-l), 1); + --bulma-info-80-invert-l: var(--bulma-info-15-l); + --bulma-info-80-invert: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-80-invert-l), 1); + --bulma-info-85: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-85-l), 1); + --bulma-info-85-invert-l: var(--bulma-info-15-l); + --bulma-info-85-invert: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-85-invert-l), 1); + --bulma-info-90: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-90-l), 1); + --bulma-info-90-invert-l: var(--bulma-info-15-l); + --bulma-info-90-invert: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-90-invert-l), 1); + --bulma-info-95: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-95-l), 1); + --bulma-info-95-invert-l: var(--bulma-info-20-l); + --bulma-info-95-invert: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-95-invert-l), 1); + --bulma-info-100: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-100-l), 1); + --bulma-info-100-invert-l: var(--bulma-info-20-l); + --bulma-info-100-invert: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-100-invert-l), 1); + --bulma-info-invert-l: var(--bulma-info-10-l); + --bulma-info-invert: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-invert-l), 1); + --bulma-info-light-l: var(--bulma-info-90-l); + --bulma-info-light: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-light-l), 1); + --bulma-info-light-invert-l: var(--bulma-info-15-l); + --bulma-info-light-invert: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-light-invert-l), 1); + --bulma-info-dark-l: var(--bulma-info-10-l); + --bulma-info-dark: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-dark-l), 1); + --bulma-info-dark-invert-l: var(--bulma-info-60-l); + --bulma-info-dark-invert: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-dark-invert-l), 1); + --bulma-info-soft: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-soft-l), 1); + --bulma-info-bold: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-bold-l), 1); + --bulma-info-soft-invert: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-soft-invert-l), 1); + --bulma-info-bold-invert: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-bold-invert-l), 1); + --bulma-info-on-scheme-l: 25%; + --bulma-info-on-scheme: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-on-scheme-l), 1); + --bulma-success: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-l), 1); + --bulma-success-base: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-l), 1); + --bulma-success-rgb: 71.6295, 198.6705, 141.50205; + --bulma-success-h: 153deg; + --bulma-success-s: 53%; + --bulma-success-l: 53%; + --bulma-success-00-l: 0%; + --bulma-success-05-l: 3%; + --bulma-success-10-l: 8%; + --bulma-success-15-l: 13%; + --bulma-success-20-l: 18%; + --bulma-success-25-l: 23%; + --bulma-success-30-l: 28%; + --bulma-success-35-l: 33%; + --bulma-success-40-l: 38%; + --bulma-success-45-l: 43%; + --bulma-success-50-l: 48%; + --bulma-success-55-l: 53%; + --bulma-success-60-l: 58%; + --bulma-success-65-l: 63%; + --bulma-success-70-l: 68%; + --bulma-success-75-l: 73%; + --bulma-success-80-l: 78%; + --bulma-success-85-l: 83%; + --bulma-success-90-l: 88%; + --bulma-success-95-l: 93%; + --bulma-success-100-l: 98%; + --bulma-success-00: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-00-l), 1); + --bulma-success-00-invert-l: var(--bulma-success-45-l); + --bulma-success-00-invert: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-00-invert-l), 1); + --bulma-success-05: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-05-l), 1); + --bulma-success-05-invert-l: var(--bulma-success-45-l); + --bulma-success-05-invert: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-05-invert-l), 1); + --bulma-success-10: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-10-l), 1); + --bulma-success-10-invert-l: var(--bulma-success-55-l); + --bulma-success-10-invert: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-10-invert-l), 1); + --bulma-success-15: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-15-l), 1); + --bulma-success-15-invert-l: var(--bulma-success-75-l); + --bulma-success-15-invert: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-15-invert-l), 1); + --bulma-success-20: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-20-l), 1); + --bulma-success-20-invert-l: var(--bulma-success-95-l); + --bulma-success-20-invert: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-20-invert-l), 1); + --bulma-success-25: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-25-l), 1); + --bulma-success-25-invert-l: var(--bulma-success-100-l); + --bulma-success-25-invert: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-25-invert-l), 1); + --bulma-success-30: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-30-l), 1); + --bulma-success-30-invert-l: var(--bulma-success-100-l); + --bulma-success-30-invert: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-30-invert-l), 1); + --bulma-success-35: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-35-l), 1); + --bulma-success-35-invert-l: var(--bulma-success-100-l); + --bulma-success-35-invert: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-35-invert-l), 1); + --bulma-success-40: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-40-l), 1); + --bulma-success-40-invert-l: var(--bulma-success-100-l); + --bulma-success-40-invert: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-40-invert-l), 1); + --bulma-success-45: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-45-l), 1); + --bulma-success-45-invert-l: var(--bulma-success-05-l); + --bulma-success-45-invert: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-45-invert-l), 1); + --bulma-success-50: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-50-l), 1); + --bulma-success-50-invert-l: var(--bulma-success-05-l); + --bulma-success-50-invert: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-50-invert-l), 1); + --bulma-success-55: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-55-l), 1); + --bulma-success-55-invert-l: var(--bulma-success-10-l); + --bulma-success-55-invert: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-55-invert-l), 1); + --bulma-success-60: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-60-l), 1); + --bulma-success-60-invert-l: var(--bulma-success-10-l); + --bulma-success-60-invert: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-60-invert-l), 1); + --bulma-success-65: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-65-l), 1); + --bulma-success-65-invert-l: var(--bulma-success-10-l); + --bulma-success-65-invert: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-65-invert-l), 1); + --bulma-success-70: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-70-l), 1); + --bulma-success-70-invert-l: var(--bulma-success-10-l); + --bulma-success-70-invert: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-70-invert-l), 1); + --bulma-success-75: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-75-l), 1); + --bulma-success-75-invert-l: var(--bulma-success-15-l); + --bulma-success-75-invert: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-75-invert-l), 1); + --bulma-success-80: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-80-l), 1); + --bulma-success-80-invert-l: var(--bulma-success-15-l); + --bulma-success-80-invert: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-80-invert-l), 1); + --bulma-success-85: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-85-l), 1); + --bulma-success-85-invert-l: var(--bulma-success-15-l); + --bulma-success-85-invert: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-85-invert-l), 1); + --bulma-success-90: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-90-l), 1); + --bulma-success-90-invert-l: var(--bulma-success-15-l); + --bulma-success-90-invert: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-90-invert-l), 1); + --bulma-success-95: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-95-l), 1); + --bulma-success-95-invert-l: var(--bulma-success-20-l); + --bulma-success-95-invert: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-95-invert-l), 1); + --bulma-success-100: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-100-l), 1); + --bulma-success-100-invert-l: var(--bulma-success-20-l); + --bulma-success-100-invert: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-100-invert-l), 1); + --bulma-success-invert-l: var(--bulma-success-10-l); + --bulma-success-invert: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-invert-l), 1); + --bulma-success-light-l: var(--bulma-success-90-l); + --bulma-success-light: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-light-l), 1); + --bulma-success-light-invert-l: var(--bulma-success-15-l); + --bulma-success-light-invert: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-light-invert-l), 1); + --bulma-success-dark-l: var(--bulma-success-10-l); + --bulma-success-dark: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-dark-l), 1); + --bulma-success-dark-invert-l: var(--bulma-success-55-l); + --bulma-success-dark-invert: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-dark-invert-l), 1); + --bulma-success-soft: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-soft-l), 1); + --bulma-success-bold: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-bold-l), 1); + --bulma-success-soft-invert: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-soft-invert-l), 1); + --bulma-success-bold-invert: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-bold-invert-l), 1); + --bulma-success-on-scheme-l: 23%; + --bulma-success-on-scheme: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-on-scheme-l), 1); + --bulma-warning: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-l), 1); + --bulma-warning-base: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-l), 1); + --bulma-warning-rgb: 255, 183.09, 15.3; + --bulma-warning-h: 42deg; + --bulma-warning-s: 100%; + --bulma-warning-l: 53%; + --bulma-warning-00-l: 0%; + --bulma-warning-05-l: 3%; + --bulma-warning-10-l: 8%; + --bulma-warning-15-l: 13%; + --bulma-warning-20-l: 18%; + --bulma-warning-25-l: 23%; + --bulma-warning-30-l: 28%; + --bulma-warning-35-l: 33%; + --bulma-warning-40-l: 38%; + --bulma-warning-45-l: 43%; + --bulma-warning-50-l: 48%; + --bulma-warning-55-l: 53%; + --bulma-warning-60-l: 58%; + --bulma-warning-65-l: 63%; + --bulma-warning-70-l: 68%; + --bulma-warning-75-l: 73%; + --bulma-warning-80-l: 78%; + --bulma-warning-85-l: 83%; + --bulma-warning-90-l: 88%; + --bulma-warning-95-l: 93%; + --bulma-warning-100-l: 98%; + --bulma-warning-00: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-00-l), 1); + --bulma-warning-00-invert-l: var(--bulma-warning-40-l); + --bulma-warning-00-invert: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-00-invert-l), 1); + --bulma-warning-05: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-05-l), 1); + --bulma-warning-05-invert-l: var(--bulma-warning-45-l); + --bulma-warning-05-invert: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-05-invert-l), 1); + --bulma-warning-10: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-10-l), 1); + --bulma-warning-10-invert-l: var(--bulma-warning-50-l); + --bulma-warning-10-invert: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-10-invert-l), 1); + --bulma-warning-15: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-15-l), 1); + --bulma-warning-15-invert-l: var(--bulma-warning-70-l); + --bulma-warning-15-invert: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-15-invert-l), 1); + --bulma-warning-20: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-20-l), 1); + --bulma-warning-20-invert-l: var(--bulma-warning-100-l); + --bulma-warning-20-invert: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-20-invert-l), 1); + --bulma-warning-25: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-25-l), 1); + --bulma-warning-25-invert-l: var(--bulma-warning-100-l); + --bulma-warning-25-invert: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-25-invert-l), 1); + --bulma-warning-30: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-30-l), 1); + --bulma-warning-30-invert-l: var(--bulma-warning-100-l); + --bulma-warning-30-invert: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-30-invert-l), 1); + --bulma-warning-35: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-35-l), 1); + --bulma-warning-35-invert-l: var(--bulma-warning-100-l); + --bulma-warning-35-invert: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-35-invert-l), 1); + --bulma-warning-40: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-40-l), 1); + --bulma-warning-40-invert-l: var(--bulma-warning-00-l); + --bulma-warning-40-invert: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-40-invert-l), 1); + --bulma-warning-45: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-45-l), 1); + --bulma-warning-45-invert-l: var(--bulma-warning-05-l); + --bulma-warning-45-invert: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-45-invert-l), 1); + --bulma-warning-50: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-50-l), 1); + --bulma-warning-50-invert-l: var(--bulma-warning-10-l); + --bulma-warning-50-invert: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-50-invert-l), 1); + --bulma-warning-55: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-55-l), 1); + --bulma-warning-55-invert-l: var(--bulma-warning-10-l); + --bulma-warning-55-invert: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-55-invert-l), 1); + --bulma-warning-60: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-60-l), 1); + --bulma-warning-60-invert-l: var(--bulma-warning-10-l); + --bulma-warning-60-invert: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-60-invert-l), 1); + --bulma-warning-65: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-65-l), 1); + --bulma-warning-65-invert-l: var(--bulma-warning-10-l); + --bulma-warning-65-invert: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-65-invert-l), 1); + --bulma-warning-70: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-70-l), 1); + --bulma-warning-70-invert-l: var(--bulma-warning-15-l); + --bulma-warning-70-invert: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-70-invert-l), 1); + --bulma-warning-75: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-75-l), 1); + --bulma-warning-75-invert-l: var(--bulma-warning-15-l); + --bulma-warning-75-invert: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-75-invert-l), 1); + --bulma-warning-80: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-80-l), 1); + --bulma-warning-80-invert-l: var(--bulma-warning-15-l); + --bulma-warning-80-invert: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-80-invert-l), 1); + --bulma-warning-85: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-85-l), 1); + --bulma-warning-85-invert-l: var(--bulma-warning-15-l); + --bulma-warning-85-invert: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-85-invert-l), 1); + --bulma-warning-90: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-90-l), 1); + --bulma-warning-90-invert-l: var(--bulma-warning-15-l); + --bulma-warning-90-invert: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-90-invert-l), 1); + --bulma-warning-95: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-95-l), 1); + --bulma-warning-95-invert-l: var(--bulma-warning-15-l); + --bulma-warning-95-invert: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-95-invert-l), 1); + --bulma-warning-100: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-100-l), 1); + --bulma-warning-100-invert-l: var(--bulma-warning-20-l); + --bulma-warning-100-invert: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-100-invert-l), 1); + --bulma-warning-invert-l: var(--bulma-warning-10-l); + --bulma-warning-invert: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-invert-l), 1); + --bulma-warning-light-l: var(--bulma-warning-90-l); + --bulma-warning-light: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-light-l), 1); + --bulma-warning-light-invert-l: var(--bulma-warning-15-l); + --bulma-warning-light-invert: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-light-invert-l), 1); + --bulma-warning-dark-l: var(--bulma-warning-10-l); + --bulma-warning-dark: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-dark-l), 1); + --bulma-warning-dark-invert-l: var(--bulma-warning-50-l); + --bulma-warning-dark-invert: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-dark-invert-l), 1); + --bulma-warning-soft: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-soft-l), 1); + --bulma-warning-bold: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-bold-l), 1); + --bulma-warning-soft-invert: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-soft-invert-l), 1); + --bulma-warning-bold-invert: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-bold-invert-l), 1); + --bulma-warning-on-scheme-l: 23%; + --bulma-warning-on-scheme: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-on-scheme-l), 1); + --bulma-danger: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-l), 1); + --bulma-danger-base: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-l), 1); + --bulma-danger-rgb: 255, 102, 132.6; + --bulma-danger-h: 348deg; + --bulma-danger-s: 100%; + --bulma-danger-l: 70%; + --bulma-danger-00-l: 0%; + --bulma-danger-05-l: 5%; + --bulma-danger-10-l: 10%; + --bulma-danger-15-l: 15%; + --bulma-danger-20-l: 20%; + --bulma-danger-25-l: 25%; + --bulma-danger-30-l: 30%; + --bulma-danger-35-l: 35%; + --bulma-danger-40-l: 40%; + --bulma-danger-45-l: 45%; + --bulma-danger-50-l: 50%; + --bulma-danger-55-l: 55%; + --bulma-danger-60-l: 60%; + --bulma-danger-65-l: 65%; + --bulma-danger-70-l: 70%; + --bulma-danger-75-l: 75%; + --bulma-danger-80-l: 80%; + --bulma-danger-85-l: 85%; + --bulma-danger-90-l: 90%; + --bulma-danger-95-l: 95%; + --bulma-danger-100-l: 100%; + --bulma-danger-00: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-00-l), 1); + --bulma-danger-00-invert-l: var(--bulma-danger-65-l); + --bulma-danger-00-invert: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-00-invert-l), 1); + --bulma-danger-05: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-05-l), 1); + --bulma-danger-05-invert-l: var(--bulma-danger-70-l); + --bulma-danger-05-invert: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-05-invert-l), 1); + --bulma-danger-10: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-10-l), 1); + --bulma-danger-10-invert-l: var(--bulma-danger-75-l); + --bulma-danger-10-invert: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-10-invert-l), 1); + --bulma-danger-15: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-15-l), 1); + --bulma-danger-15-invert-l: var(--bulma-danger-80-l); + --bulma-danger-15-invert: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-15-invert-l), 1); + --bulma-danger-20: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-20-l), 1); + --bulma-danger-20-invert-l: var(--bulma-danger-85-l); + --bulma-danger-20-invert: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-20-invert-l), 1); + --bulma-danger-25: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-25-l), 1); + --bulma-danger-25-invert-l: var(--bulma-danger-90-l); + --bulma-danger-25-invert: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-25-invert-l), 1); + --bulma-danger-30: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-30-l), 1); + --bulma-danger-30-invert-l: var(--bulma-danger-100-l); + --bulma-danger-30-invert: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-30-invert-l), 1); + --bulma-danger-35: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-35-l), 1); + --bulma-danger-35-invert-l: var(--bulma-danger-100-l); + --bulma-danger-35-invert: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-35-invert-l), 1); + --bulma-danger-40: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-40-l), 1); + --bulma-danger-40-invert-l: var(--bulma-danger-100-l); + --bulma-danger-40-invert: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-40-invert-l), 1); + --bulma-danger-45: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-45-l), 1); + --bulma-danger-45-invert-l: var(--bulma-danger-100-l); + --bulma-danger-45-invert: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-45-invert-l), 1); + --bulma-danger-50: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-50-l), 1); + --bulma-danger-50-invert-l: var(--bulma-danger-100-l); + --bulma-danger-50-invert: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-50-invert-l), 1); + --bulma-danger-55: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-55-l), 1); + --bulma-danger-55-invert-l: var(--bulma-danger-100-l); + --bulma-danger-55-invert: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-55-invert-l), 1); + --bulma-danger-60: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-60-l), 1); + --bulma-danger-60-invert-l: var(--bulma-danger-100-l); + --bulma-danger-60-invert: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-60-invert-l), 1); + --bulma-danger-65: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-65-l), 1); + --bulma-danger-65-invert-l: var(--bulma-danger-00-l); + --bulma-danger-65-invert: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-65-invert-l), 1); + --bulma-danger-70: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-70-l), 1); + --bulma-danger-70-invert-l: var(--bulma-danger-05-l); + --bulma-danger-70-invert: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-70-invert-l), 1); + --bulma-danger-75: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-75-l), 1); + --bulma-danger-75-invert-l: var(--bulma-danger-10-l); + --bulma-danger-75-invert: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-75-invert-l), 1); + --bulma-danger-80: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-80-l), 1); + --bulma-danger-80-invert-l: var(--bulma-danger-15-l); + --bulma-danger-80-invert: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-80-invert-l), 1); + --bulma-danger-85: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-85-l), 1); + --bulma-danger-85-invert-l: var(--bulma-danger-20-l); + --bulma-danger-85-invert: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-85-invert-l), 1); + --bulma-danger-90: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-90-l), 1); + --bulma-danger-90-invert-l: var(--bulma-danger-25-l); + --bulma-danger-90-invert: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-90-invert-l), 1); + --bulma-danger-95: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-95-l), 1); + --bulma-danger-95-invert-l: var(--bulma-danger-25-l); + --bulma-danger-95-invert: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-95-invert-l), 1); + --bulma-danger-100: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-100-l), 1); + --bulma-danger-100-invert-l: var(--bulma-danger-30-l); + --bulma-danger-100-invert: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-100-invert-l), 1); + --bulma-danger-invert-l: var(--bulma-danger-05-l); + --bulma-danger-invert: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-invert-l), 1); + --bulma-danger-light-l: var(--bulma-danger-90-l); + --bulma-danger-light: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-light-l), 1); + --bulma-danger-light-invert-l: var(--bulma-danger-25-l); + --bulma-danger-light-invert: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-light-invert-l), 1); + --bulma-danger-dark-l: var(--bulma-danger-10-l); + --bulma-danger-dark: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-dark-l), 1); + --bulma-danger-dark-invert-l: var(--bulma-danger-75-l); + --bulma-danger-dark-invert: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-dark-invert-l), 1); + --bulma-danger-soft: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-soft-l), 1); + --bulma-danger-bold: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-bold-l), 1); + --bulma-danger-soft-invert: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-soft-invert-l), 1); + --bulma-danger-bold-invert: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-bold-invert-l), 1); + --bulma-danger-on-scheme-l: 40%; + --bulma-danger-on-scheme: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-on-scheme-l), 1); + --bulma-black-bis: hsl(221, 14%, 9%); + --bulma-black-ter: hsl(221, 14%, 14%); + --bulma-grey-darker: hsl(221, 14%, 21%); + --bulma-grey-dark: hsl(221, 14%, 29%); + --bulma-grey: hsl(221, 14%, 48%); + --bulma-grey-light: hsl(221, 14%, 71%); + --bulma-grey-lighter: hsl(221, 14%, 86%); + --bulma-white-ter: hsl(221, 14%, 96%); + --bulma-white-bis: hsl(221, 14%, 98%); + --bulma-shadow-h: 221deg; + --bulma-shadow-s: 14%; + --bulma-shadow-l: 4%; + --bulma-size-1: 3rem; + --bulma-size-2: 2.5rem; + --bulma-size-3: 2rem; + --bulma-size-4: 1.5rem; + --bulma-size-5: 1.25rem; + --bulma-size-6: 1rem; + --bulma-size-7: 0.75rem; + } +} +@media (prefers-color-scheme: dark) { + :root { + --bulma-white-on-scheme-l: 100%; + --bulma-white-on-scheme: hsla(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-on-scheme-l), 1); + --bulma-black-on-scheme-l: -51%; + --bulma-black-on-scheme: hsla(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-on-scheme-l), 1); + --bulma-light-on-scheme-l: 96%; + --bulma-light-on-scheme: hsla(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-on-scheme-l), 1); + --bulma-dark-on-scheme-l: 56%; + --bulma-dark-on-scheme: hsla(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-on-scheme-l), 1); + --bulma-text-on-scheme-l: 54%; + --bulma-text-on-scheme: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-on-scheme-l), 1); + --bulma-primary-on-scheme-l: 41%; + --bulma-primary-on-scheme: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-on-scheme-l), 1); + --bulma-link-on-scheme-l: 73%; + --bulma-link-on-scheme: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-on-scheme-l), 1); + --bulma-info-on-scheme-l: 70%; + --bulma-info-on-scheme: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-on-scheme-l), 1); + --bulma-success-on-scheme-l: 53%; + --bulma-success-on-scheme: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-on-scheme-l), 1); + --bulma-warning-on-scheme-l: 53%; + --bulma-warning-on-scheme: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-on-scheme-l), 1); + --bulma-danger-on-scheme-l: 70%; + --bulma-danger-on-scheme: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-on-scheme-l), 1); + --bulma-scheme-brightness: dark; + --bulma-scheme-main-l: 9%; + --bulma-scheme-main-bis-l: 11%; + --bulma-scheme-main-ter-l: 13%; + --bulma-soft-l: 20%; + --bulma-bold-l: 90%; + --bulma-soft-invert-l: 90%; + --bulma-bold-invert-l: 20%; + --bulma-background-l: 14%; + --bulma-border-weak-l: 21%; + --bulma-border-l: 24%; + --bulma-text-weak-l: 53%; + --bulma-text-l: 71%; + --bulma-text-strong-l: 93%; + --bulma-text-title-l: 100%; + --bulma-hover-background-l-delta: 5%; + --bulma-active-background-l-delta: 10%; + --bulma-hover-border-l-delta: 10%; + --bulma-active-border-l-delta: 20%; + --bulma-hover-color-l-delta: 5%; + --bulma-active-color-l-delta: 10%; + --bulma-shadow-h: 0deg; + --bulma-shadow-s: 0%; + --bulma-shadow-l: 100%; + } +} +[data-theme=light], +.theme-light { + --bulma-scheme-h: 221; + --bulma-scheme-s: 14%; + --bulma-light-l: 90%; + --bulma-light-invert-l: 20%; + --bulma-dark-l: 20%; + --bulma-dark-invert-l: 90%; + --bulma-soft-l: 90%; + --bulma-bold-l: 20%; + --bulma-soft-invert-l: 20%; + --bulma-bold-invert-l: 90%; + --bulma-hover-background-l-delta: -5%; + --bulma-active-background-l-delta: -10%; + --bulma-hover-border-l-delta: -10%; + --bulma-active-border-l-delta: -20%; + --bulma-hover-color-l-delta: -5%; + --bulma-active-color-l-delta: -10%; + --bulma-hover-shadow-a-delta: -0.05; + --bulma-active-shadow-a-delta: -0.1; + --bulma-scheme-brightness: light; + --bulma-scheme-main-l: 100%; + --bulma-scheme-main-bis-l: 98%; + --bulma-scheme-main-ter-l: 96%; + --bulma-background-l: 96%; + --bulma-border-weak-l: 93%; + --bulma-border-l: 86%; + --bulma-text-weak-l: 48%; + --bulma-text-l: 29%; + --bulma-text-strong-l: 21%; + --bulma-text-title-l: 14%; + --bulma-scheme-invert-ter-l: 14%; + --bulma-scheme-invert-bis-l: 7%; + --bulma-scheme-invert-l: 4%; + --bulma-family-primary: Inter, SF Pro, Segoe UI, Roboto, Oxygen, Ubuntu, Helvetica Neue, Helvetica, Arial, sans-serif; + --bulma-family-secondary: Inter, SF Pro, Segoe UI, Roboto, Oxygen, Ubuntu, Helvetica Neue, Helvetica, Arial, sans-serif; + --bulma-family-code: Inconsolata, Hack, SF Mono, Roboto Mono, Source Code Pro, Ubuntu Mono, monospace; + --bulma-size-small: 0.75rem; + --bulma-size-normal: 1rem; + --bulma-size-medium: 1.25rem; + --bulma-size-large: 1.5rem; + --bulma-weight-light: 300; + --bulma-weight-normal: 400; + --bulma-weight-medium: 500; + --bulma-weight-semibold: 600; + --bulma-weight-bold: 700; + --bulma-weight-extrabold: 800; + --bulma-block-spacing: 1.5rem; + --bulma-duration: 294ms; + --bulma-easing: ease-out; + --bulma-radius-small: 0.25rem; + --bulma-radius: 0.375rem; + --bulma-radius-medium: 0.5em; + --bulma-radius-large: 0.75rem; + --bulma-radius-rounded: 9999px; + --bulma-speed: 86ms; + --bulma-arrow-color: var(--bulma-link); + --bulma-loading-color: var(--bulma-border); + --bulma-burger-h: var(--bulma-link-h); + --bulma-burger-s: var(--bulma-link-s); + --bulma-burger-l: var(--bulma-link-l); + --bulma-burger-border-radius: 0.5em; + --bulma-burger-gap: 5px; + --bulma-burger-item-height: 2px; + --bulma-burger-item-width: 20px; + --bulma-white: hsla(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-l), 1); + --bulma-white-base: hsla(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-l), 1); + --bulma-white-rgb: 255, 255, 255; + --bulma-white-h: 221deg; + --bulma-white-s: 14%; + --bulma-white-l: 100%; + --bulma-white-invert-l: 4%; + --bulma-white-invert: hsl(221, 14%, 4%); + --bulma-white-on-scheme-l: 35%; + --bulma-white-on-scheme: hsla(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-on-scheme-l), 1); + --bulma-black: hsla(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-l), 1); + --bulma-black-base: hsla(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-l), 1); + --bulma-black-rgb: 8.772, 9.6764, 11.628; + --bulma-black-h: 221deg; + --bulma-black-s: 14%; + --bulma-black-l: 4%; + --bulma-black-invert-l: 100%; + --bulma-black-invert: hsl(221, 14%, 100%); + --bulma-black-on-scheme-l: 4%; + --bulma-black-on-scheme: hsla(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-on-scheme-l), 1); + --bulma-light: hsla(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-l), 1); + --bulma-light-base: hsla(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-l), 1); + --bulma-light-rgb: 243.372, 244.2764, 246.228; + --bulma-light-h: 221deg; + --bulma-light-s: 14%; + --bulma-light-l: 96%; + --bulma-light-invert-l: 21%; + --bulma-light-invert: hsl(221, 14%, 21%); + --bulma-light-on-scheme-l: 36%; + --bulma-light-on-scheme: hsla(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-on-scheme-l), 1); + --bulma-dark: hsla(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-l), 1); + --bulma-dark-base: hsla(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-l), 1); + --bulma-dark-rgb: 46.053, 50.8011, 61.047; + --bulma-dark-h: 221deg; + --bulma-dark-s: 14%; + --bulma-dark-l: 21%; + --bulma-dark-invert-l: 96%; + --bulma-dark-invert: hsl(221, 14%, 96%); + --bulma-dark-on-scheme-l: 21%; + --bulma-dark-on-scheme: hsla(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-on-scheme-l), 1); + --bulma-text: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-l), 1); + --bulma-text-base: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-l), 1); + --bulma-text-rgb: 63.597, 70.1539, 84.303; + --bulma-text-h: 221deg; + --bulma-text-s: 14%; + --bulma-text-l: 29%; + --bulma-text-00-l: 0%; + --bulma-text-05-l: 4%; + --bulma-text-10-l: 9%; + --bulma-text-15-l: 14%; + --bulma-text-20-l: 19%; + --bulma-text-25-l: 24%; + --bulma-text-30-l: 29%; + --bulma-text-35-l: 34%; + --bulma-text-40-l: 39%; + --bulma-text-45-l: 44%; + --bulma-text-50-l: 49%; + --bulma-text-55-l: 54%; + --bulma-text-60-l: 59%; + --bulma-text-65-l: 64%; + --bulma-text-70-l: 69%; + --bulma-text-75-l: 74%; + --bulma-text-80-l: 79%; + --bulma-text-85-l: 84%; + --bulma-text-90-l: 89%; + --bulma-text-95-l: 94%; + --bulma-text-100-l: 99%; + --bulma-text-00: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-00-l), 1); + --bulma-text-00-invert-l: var(--bulma-text-60-l); + --bulma-text-00-invert: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-00-invert-l), 1); + --bulma-text-05: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-05-l), 1); + --bulma-text-05-invert-l: var(--bulma-text-60-l); + --bulma-text-05-invert: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-05-invert-l), 1); + --bulma-text-10: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-10-l), 1); + --bulma-text-10-invert-l: var(--bulma-text-70-l); + --bulma-text-10-invert: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-10-invert-l), 1); + --bulma-text-15: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-15-l), 1); + --bulma-text-15-invert-l: var(--bulma-text-75-l); + --bulma-text-15-invert: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-15-invert-l), 1); + --bulma-text-20: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-20-l), 1); + --bulma-text-20-invert-l: var(--bulma-text-85-l); + --bulma-text-20-invert: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-20-invert-l), 1); + --bulma-text-25: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-25-l), 1); + --bulma-text-25-invert-l: var(--bulma-text-95-l); + --bulma-text-25-invert: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-25-invert-l), 1); + --bulma-text-30: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-30-l), 1); + --bulma-text-30-invert-l: var(--bulma-text-100-l); + --bulma-text-30-invert: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-30-invert-l), 1); + --bulma-text-35: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-35-l), 1); + --bulma-text-35-invert-l: var(--bulma-text-100-l); + --bulma-text-35-invert: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-35-invert-l), 1); + --bulma-text-40: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-40-l), 1); + --bulma-text-40-invert-l: var(--bulma-text-100-l); + --bulma-text-40-invert: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-40-invert-l), 1); + --bulma-text-45: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-45-l), 1); + --bulma-text-45-invert-l: var(--bulma-text-100-l); + --bulma-text-45-invert: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-45-invert-l), 1); + --bulma-text-50: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-50-l), 1); + --bulma-text-50-invert-l: var(--bulma-text-100-l); + --bulma-text-50-invert: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-50-invert-l), 1); + --bulma-text-55: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-55-l), 1); + --bulma-text-55-invert-l: var(--bulma-text-100-l); + --bulma-text-55-invert: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-55-invert-l), 1); + --bulma-text-60: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-60-l), 1); + --bulma-text-60-invert-l: var(--bulma-text-05-l); + --bulma-text-60-invert: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-60-invert-l), 1); + --bulma-text-65: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-65-l), 1); + --bulma-text-65-invert-l: var(--bulma-text-05-l); + --bulma-text-65-invert: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-65-invert-l), 1); + --bulma-text-70: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-70-l), 1); + --bulma-text-70-invert-l: var(--bulma-text-10-l); + --bulma-text-70-invert: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-70-invert-l), 1); + --bulma-text-75: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-75-l), 1); + --bulma-text-75-invert-l: var(--bulma-text-15-l); + --bulma-text-75-invert: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-75-invert-l), 1); + --bulma-text-80: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-80-l), 1); + --bulma-text-80-invert-l: var(--bulma-text-15-l); + --bulma-text-80-invert: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-80-invert-l), 1); + --bulma-text-85: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-85-l), 1); + --bulma-text-85-invert-l: var(--bulma-text-20-l); + --bulma-text-85-invert: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-85-invert-l), 1); + --bulma-text-90: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-90-l), 1); + --bulma-text-90-invert-l: var(--bulma-text-20-l); + --bulma-text-90-invert: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-90-invert-l), 1); + --bulma-text-95: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-95-l), 1); + --bulma-text-95-invert-l: var(--bulma-text-25-l); + --bulma-text-95-invert: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-95-invert-l), 1); + --bulma-text-100: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-100-l), 1); + --bulma-text-100-invert-l: var(--bulma-text-25-l); + --bulma-text-100-invert: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-100-invert-l), 1); + --bulma-text-invert-l: var(--bulma-text-100-l); + --bulma-text-invert: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-invert-l), 1); + --bulma-text-light-l: var(--bulma-text-90-l); + --bulma-text-light: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-light-l), 1); + --bulma-text-light-invert-l: var(--bulma-text-20-l); + --bulma-text-light-invert: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-light-invert-l), 1); + --bulma-text-dark-l: var(--bulma-text-10-l); + --bulma-text-dark: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-dark-l), 1); + --bulma-text-dark-invert-l: var(--bulma-text-70-l); + --bulma-text-dark-invert: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-dark-invert-l), 1); + --bulma-text-soft: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-soft-l), 1); + --bulma-text-bold: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-bold-l), 1); + --bulma-text-soft-invert: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-soft-invert-l), 1); + --bulma-text-bold-invert: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-bold-invert-l), 1); + --bulma-text-on-scheme-l: 29%; + --bulma-text-on-scheme: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-on-scheme-l), 1); + --bulma-primary: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-l), 1); + --bulma-primary-base: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-l), 1); + --bulma-primary-rgb: 0, 209.1, 177.735; + --bulma-primary-h: 171deg; + --bulma-primary-s: 100%; + --bulma-primary-l: 41%; + --bulma-primary-00-l: 1%; + --bulma-primary-05-l: 6%; + --bulma-primary-10-l: 11%; + --bulma-primary-15-l: 16%; + --bulma-primary-20-l: 21%; + --bulma-primary-25-l: 26%; + --bulma-primary-30-l: 31%; + --bulma-primary-35-l: 36%; + --bulma-primary-40-l: 41%; + --bulma-primary-45-l: 46%; + --bulma-primary-50-l: 51%; + --bulma-primary-55-l: 56%; + --bulma-primary-60-l: 61%; + --bulma-primary-65-l: 66%; + --bulma-primary-70-l: 71%; + --bulma-primary-75-l: 76%; + --bulma-primary-80-l: 81%; + --bulma-primary-85-l: 86%; + --bulma-primary-90-l: 91%; + --bulma-primary-95-l: 96%; + --bulma-primary-100-l: 100%; + --bulma-primary-00: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-00-l), 1); + --bulma-primary-00-invert-l: var(--bulma-primary-30-l); + --bulma-primary-00-invert: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-00-invert-l), 1); + --bulma-primary-05: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-05-l), 1); + --bulma-primary-05-invert-l: var(--bulma-primary-40-l); + --bulma-primary-05-invert: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-05-invert-l), 1); + --bulma-primary-10: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-10-l), 1); + --bulma-primary-10-invert-l: var(--bulma-primary-50-l); + --bulma-primary-10-invert: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-10-invert-l), 1); + --bulma-primary-15: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-15-l), 1); + --bulma-primary-15-invert-l: var(--bulma-primary-100-l); + --bulma-primary-15-invert: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-15-invert-l), 1); + --bulma-primary-20: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-20-l), 1); + --bulma-primary-20-invert-l: var(--bulma-primary-100-l); + --bulma-primary-20-invert: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-20-invert-l), 1); + --bulma-primary-25: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-25-l), 1); + --bulma-primary-25-invert-l: var(--bulma-primary-100-l); + --bulma-primary-25-invert: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-25-invert-l), 1); + --bulma-primary-30: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-30-l), 1); + --bulma-primary-30-invert-l: var(--bulma-primary-00-l); + --bulma-primary-30-invert: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-30-invert-l), 1); + --bulma-primary-35: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-35-l), 1); + --bulma-primary-35-invert-l: var(--bulma-primary-00-l); + --bulma-primary-35-invert: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-35-invert-l), 1); + --bulma-primary-40: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-40-l), 1); + --bulma-primary-40-invert-l: var(--bulma-primary-05-l); + --bulma-primary-40-invert: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-40-invert-l), 1); + --bulma-primary-45: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-45-l), 1); + --bulma-primary-45-invert-l: var(--bulma-primary-05-l); + --bulma-primary-45-invert: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-45-invert-l), 1); + --bulma-primary-50: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-50-l), 1); + --bulma-primary-50-invert-l: var(--bulma-primary-10-l); + --bulma-primary-50-invert: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-50-invert-l), 1); + --bulma-primary-55: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-55-l), 1); + --bulma-primary-55-invert-l: var(--bulma-primary-10-l); + --bulma-primary-55-invert: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-55-invert-l), 1); + --bulma-primary-60: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-60-l), 1); + --bulma-primary-60-invert-l: var(--bulma-primary-10-l); + --bulma-primary-60-invert: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-60-invert-l), 1); + --bulma-primary-65: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-65-l), 1); + --bulma-primary-65-invert-l: var(--bulma-primary-10-l); + --bulma-primary-65-invert: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-65-invert-l), 1); + --bulma-primary-70: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-70-l), 1); + --bulma-primary-70-invert-l: var(--bulma-primary-10-l); + --bulma-primary-70-invert: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-70-invert-l), 1); + --bulma-primary-75: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-75-l), 1); + --bulma-primary-75-invert-l: var(--bulma-primary-10-l); + --bulma-primary-75-invert: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-75-invert-l), 1); + --bulma-primary-80: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-80-l), 1); + --bulma-primary-80-invert-l: var(--bulma-primary-10-l); + --bulma-primary-80-invert: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-80-invert-l), 1); + --bulma-primary-85: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-85-l), 1); + --bulma-primary-85-invert-l: var(--bulma-primary-10-l); + --bulma-primary-85-invert: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-85-invert-l), 1); + --bulma-primary-90: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-90-l), 1); + --bulma-primary-90-invert-l: var(--bulma-primary-10-l); + --bulma-primary-90-invert: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-90-invert-l), 1); + --bulma-primary-95: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-95-l), 1); + --bulma-primary-95-invert-l: var(--bulma-primary-10-l); + --bulma-primary-95-invert: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-95-invert-l), 1); + --bulma-primary-100: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-100-l), 1); + --bulma-primary-100-invert-l: var(--bulma-primary-15-l); + --bulma-primary-100-invert: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-100-invert-l), 1); + --bulma-primary-invert-l: var(--bulma-primary-05-l); + --bulma-primary-invert: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-invert-l), 1); + --bulma-primary-light-l: var(--bulma-primary-90-l); + --bulma-primary-light: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-light-l), 1); + --bulma-primary-light-invert-l: var(--bulma-primary-10-l); + --bulma-primary-light-invert: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-light-invert-l), 1); + --bulma-primary-dark-l: var(--bulma-primary-10-l); + --bulma-primary-dark: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-dark-l), 1); + --bulma-primary-dark-invert-l: var(--bulma-primary-50-l); + --bulma-primary-dark-invert: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-dark-invert-l), 1); + --bulma-primary-soft: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-soft-l), 1); + --bulma-primary-bold: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-bold-l), 1); + --bulma-primary-soft-invert: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-soft-invert-l), 1); + --bulma-primary-bold-invert: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-bold-invert-l), 1); + --bulma-primary-on-scheme-l: 21%; + --bulma-primary-on-scheme: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-on-scheme-l), 1); + --bulma-link: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-l), 1); + --bulma-link-base: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-l), 1); + --bulma-link-rgb: 66.3, 88.315, 255; + --bulma-link-h: 233deg; + --bulma-link-s: 100%; + --bulma-link-l: 63%; + --bulma-link-00-l: 0%; + --bulma-link-05-l: 3%; + --bulma-link-10-l: 8%; + --bulma-link-15-l: 13%; + --bulma-link-20-l: 18%; + --bulma-link-25-l: 23%; + --bulma-link-30-l: 28%; + --bulma-link-35-l: 33%; + --bulma-link-40-l: 38%; + --bulma-link-45-l: 43%; + --bulma-link-50-l: 48%; + --bulma-link-55-l: 53%; + --bulma-link-60-l: 58%; + --bulma-link-65-l: 63%; + --bulma-link-70-l: 68%; + --bulma-link-75-l: 73%; + --bulma-link-80-l: 78%; + --bulma-link-85-l: 83%; + --bulma-link-90-l: 88%; + --bulma-link-95-l: 93%; + --bulma-link-100-l: 98%; + --bulma-link-00: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-00-l), 1); + --bulma-link-00-invert-l: var(--bulma-link-75-l); + --bulma-link-00-invert: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-00-invert-l), 1); + --bulma-link-05: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-05-l), 1); + --bulma-link-05-invert-l: var(--bulma-link-75-l); + --bulma-link-05-invert: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-05-invert-l), 1); + --bulma-link-10: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-10-l), 1); + --bulma-link-10-invert-l: var(--bulma-link-75-l); + --bulma-link-10-invert: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-10-invert-l), 1); + --bulma-link-15: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-15-l), 1); + --bulma-link-15-invert-l: var(--bulma-link-80-l); + --bulma-link-15-invert: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-15-invert-l), 1); + --bulma-link-20: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-20-l), 1); + --bulma-link-20-invert-l: var(--bulma-link-80-l); + --bulma-link-20-invert: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-20-invert-l), 1); + --bulma-link-25: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-25-l), 1); + --bulma-link-25-invert-l: var(--bulma-link-85-l); + --bulma-link-25-invert: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-25-invert-l), 1); + --bulma-link-30: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-30-l), 1); + --bulma-link-30-invert-l: var(--bulma-link-90-l); + --bulma-link-30-invert: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-30-invert-l), 1); + --bulma-link-35: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-35-l), 1); + --bulma-link-35-invert-l: var(--bulma-link-90-l); + --bulma-link-35-invert: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-35-invert-l), 1); + --bulma-link-40: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-40-l), 1); + --bulma-link-40-invert-l: var(--bulma-link-95-l); + --bulma-link-40-invert: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-40-invert-l), 1); + --bulma-link-45: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-45-l), 1); + --bulma-link-45-invert-l: var(--bulma-link-95-l); + --bulma-link-45-invert: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-45-invert-l), 1); + --bulma-link-50: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-50-l), 1); + --bulma-link-50-invert-l: var(--bulma-link-100-l); + --bulma-link-50-invert: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-50-invert-l), 1); + --bulma-link-55: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-55-l), 1); + --bulma-link-55-invert-l: var(--bulma-link-100-l); + --bulma-link-55-invert: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-55-invert-l), 1); + --bulma-link-60: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-60-l), 1); + --bulma-link-60-invert-l: var(--bulma-link-100-l); + --bulma-link-60-invert: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-60-invert-l), 1); + --bulma-link-65: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-65-l), 1); + --bulma-link-65-invert-l: var(--bulma-link-100-l); + --bulma-link-65-invert: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-65-invert-l), 1); + --bulma-link-70: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-70-l), 1); + --bulma-link-70-invert-l: var(--bulma-link-100-l); + --bulma-link-70-invert: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-70-invert-l), 1); + --bulma-link-75: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-75-l), 1); + --bulma-link-75-invert-l: var(--bulma-link-10-l); + --bulma-link-75-invert: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-75-invert-l), 1); + --bulma-link-80: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-80-l), 1); + --bulma-link-80-invert-l: var(--bulma-link-20-l); + --bulma-link-80-invert: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-80-invert-l), 1); + --bulma-link-85: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-85-l), 1); + --bulma-link-85-invert-l: var(--bulma-link-25-l); + --bulma-link-85-invert: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-85-invert-l), 1); + --bulma-link-90: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-90-l), 1); + --bulma-link-90-invert-l: var(--bulma-link-35-l); + --bulma-link-90-invert: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-90-invert-l), 1); + --bulma-link-95: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-95-l), 1); + --bulma-link-95-invert-l: var(--bulma-link-45-l); + --bulma-link-95-invert: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-95-invert-l), 1); + --bulma-link-100: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-100-l), 1); + --bulma-link-100-invert-l: var(--bulma-link-50-l); + --bulma-link-100-invert: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-100-invert-l), 1); + --bulma-link-invert-l: var(--bulma-link-100-l); + --bulma-link-invert: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-invert-l), 1); + --bulma-link-light-l: var(--bulma-link-90-l); + --bulma-link-light: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-light-l), 1); + --bulma-link-light-invert-l: var(--bulma-link-35-l); + --bulma-link-light-invert: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-light-invert-l), 1); + --bulma-link-dark-l: var(--bulma-link-10-l); + --bulma-link-dark: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-dark-l), 1); + --bulma-link-dark-invert-l: var(--bulma-link-75-l); + --bulma-link-dark-invert: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-dark-invert-l), 1); + --bulma-link-soft: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-soft-l), 1); + --bulma-link-bold: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-bold-l), 1); + --bulma-link-soft-invert: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-soft-invert-l), 1); + --bulma-link-bold-invert: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-bold-invert-l), 1); + --bulma-link-on-scheme-l: 58%; + --bulma-link-on-scheme: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-on-scheme-l), 1); + --bulma-info: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-l), 1); + --bulma-info-base: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-l), 1); + --bulma-info-rgb: 102, 209.1, 255; + --bulma-info-h: 198deg; + --bulma-info-s: 100%; + --bulma-info-l: 70%; + --bulma-info-00-l: 0%; + --bulma-info-05-l: 5%; + --bulma-info-10-l: 10%; + --bulma-info-15-l: 15%; + --bulma-info-20-l: 20%; + --bulma-info-25-l: 25%; + --bulma-info-30-l: 30%; + --bulma-info-35-l: 35%; + --bulma-info-40-l: 40%; + --bulma-info-45-l: 45%; + --bulma-info-50-l: 50%; + --bulma-info-55-l: 55%; + --bulma-info-60-l: 60%; + --bulma-info-65-l: 65%; + --bulma-info-70-l: 70%; + --bulma-info-75-l: 75%; + --bulma-info-80-l: 80%; + --bulma-info-85-l: 85%; + --bulma-info-90-l: 90%; + --bulma-info-95-l: 95%; + --bulma-info-100-l: 100%; + --bulma-info-00: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-00-l), 1); + --bulma-info-00-invert-l: var(--bulma-info-45-l); + --bulma-info-00-invert: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-00-invert-l), 1); + --bulma-info-05: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-05-l), 1); + --bulma-info-05-invert-l: var(--bulma-info-50-l); + --bulma-info-05-invert: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-05-invert-l), 1); + --bulma-info-10: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-10-l), 1); + --bulma-info-10-invert-l: var(--bulma-info-60-l); + --bulma-info-10-invert: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-10-invert-l), 1); + --bulma-info-15: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-15-l), 1); + --bulma-info-15-invert-l: var(--bulma-info-80-l); + --bulma-info-15-invert: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-15-invert-l), 1); + --bulma-info-20: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-20-l), 1); + --bulma-info-20-invert-l: var(--bulma-info-95-l); + --bulma-info-20-invert: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-20-invert-l), 1); + --bulma-info-25: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-25-l), 1); + --bulma-info-25-invert-l: var(--bulma-info-100-l); + --bulma-info-25-invert: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-25-invert-l), 1); + --bulma-info-30: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-30-l), 1); + --bulma-info-30-invert-l: var(--bulma-info-100-l); + --bulma-info-30-invert: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-30-invert-l), 1); + --bulma-info-35: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-35-l), 1); + --bulma-info-35-invert-l: var(--bulma-info-100-l); + --bulma-info-35-invert: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-35-invert-l), 1); + --bulma-info-40: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-40-l), 1); + --bulma-info-40-invert-l: var(--bulma-info-100-l); + --bulma-info-40-invert: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-40-invert-l), 1); + --bulma-info-45: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-45-l), 1); + --bulma-info-45-invert-l: var(--bulma-info-00-l); + --bulma-info-45-invert: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-45-invert-l), 1); + --bulma-info-50: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-50-l), 1); + --bulma-info-50-invert-l: var(--bulma-info-05-l); + --bulma-info-50-invert: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-50-invert-l), 1); + --bulma-info-55: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-55-l), 1); + --bulma-info-55-invert-l: var(--bulma-info-05-l); + --bulma-info-55-invert: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-55-invert-l), 1); + --bulma-info-60: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-60-l), 1); + --bulma-info-60-invert-l: var(--bulma-info-10-l); + --bulma-info-60-invert: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-60-invert-l), 1); + --bulma-info-65: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-65-l), 1); + --bulma-info-65-invert-l: var(--bulma-info-10-l); + --bulma-info-65-invert: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-65-invert-l), 1); + --bulma-info-70: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-70-l), 1); + --bulma-info-70-invert-l: var(--bulma-info-10-l); + --bulma-info-70-invert: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-70-invert-l), 1); + --bulma-info-75: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-75-l), 1); + --bulma-info-75-invert-l: var(--bulma-info-10-l); + --bulma-info-75-invert: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-75-invert-l), 1); + --bulma-info-80: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-80-l), 1); + --bulma-info-80-invert-l: var(--bulma-info-15-l); + --bulma-info-80-invert: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-80-invert-l), 1); + --bulma-info-85: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-85-l), 1); + --bulma-info-85-invert-l: var(--bulma-info-15-l); + --bulma-info-85-invert: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-85-invert-l), 1); + --bulma-info-90: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-90-l), 1); + --bulma-info-90-invert-l: var(--bulma-info-15-l); + --bulma-info-90-invert: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-90-invert-l), 1); + --bulma-info-95: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-95-l), 1); + --bulma-info-95-invert-l: var(--bulma-info-20-l); + --bulma-info-95-invert: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-95-invert-l), 1); + --bulma-info-100: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-100-l), 1); + --bulma-info-100-invert-l: var(--bulma-info-20-l); + --bulma-info-100-invert: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-100-invert-l), 1); + --bulma-info-invert-l: var(--bulma-info-10-l); + --bulma-info-invert: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-invert-l), 1); + --bulma-info-light-l: var(--bulma-info-90-l); + --bulma-info-light: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-light-l), 1); + --bulma-info-light-invert-l: var(--bulma-info-15-l); + --bulma-info-light-invert: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-light-invert-l), 1); + --bulma-info-dark-l: var(--bulma-info-10-l); + --bulma-info-dark: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-dark-l), 1); + --bulma-info-dark-invert-l: var(--bulma-info-60-l); + --bulma-info-dark-invert: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-dark-invert-l), 1); + --bulma-info-soft: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-soft-l), 1); + --bulma-info-bold: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-bold-l), 1); + --bulma-info-soft-invert: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-soft-invert-l), 1); + --bulma-info-bold-invert: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-bold-invert-l), 1); + --bulma-info-on-scheme-l: 25%; + --bulma-info-on-scheme: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-on-scheme-l), 1); + --bulma-success: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-l), 1); + --bulma-success-base: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-l), 1); + --bulma-success-rgb: 71.6295, 198.6705, 141.50205; + --bulma-success-h: 153deg; + --bulma-success-s: 53%; + --bulma-success-l: 53%; + --bulma-success-00-l: 0%; + --bulma-success-05-l: 3%; + --bulma-success-10-l: 8%; + --bulma-success-15-l: 13%; + --bulma-success-20-l: 18%; + --bulma-success-25-l: 23%; + --bulma-success-30-l: 28%; + --bulma-success-35-l: 33%; + --bulma-success-40-l: 38%; + --bulma-success-45-l: 43%; + --bulma-success-50-l: 48%; + --bulma-success-55-l: 53%; + --bulma-success-60-l: 58%; + --bulma-success-65-l: 63%; + --bulma-success-70-l: 68%; + --bulma-success-75-l: 73%; + --bulma-success-80-l: 78%; + --bulma-success-85-l: 83%; + --bulma-success-90-l: 88%; + --bulma-success-95-l: 93%; + --bulma-success-100-l: 98%; + --bulma-success-00: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-00-l), 1); + --bulma-success-00-invert-l: var(--bulma-success-45-l); + --bulma-success-00-invert: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-00-invert-l), 1); + --bulma-success-05: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-05-l), 1); + --bulma-success-05-invert-l: var(--bulma-success-45-l); + --bulma-success-05-invert: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-05-invert-l), 1); + --bulma-success-10: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-10-l), 1); + --bulma-success-10-invert-l: var(--bulma-success-55-l); + --bulma-success-10-invert: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-10-invert-l), 1); + --bulma-success-15: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-15-l), 1); + --bulma-success-15-invert-l: var(--bulma-success-75-l); + --bulma-success-15-invert: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-15-invert-l), 1); + --bulma-success-20: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-20-l), 1); + --bulma-success-20-invert-l: var(--bulma-success-95-l); + --bulma-success-20-invert: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-20-invert-l), 1); + --bulma-success-25: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-25-l), 1); + --bulma-success-25-invert-l: var(--bulma-success-100-l); + --bulma-success-25-invert: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-25-invert-l), 1); + --bulma-success-30: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-30-l), 1); + --bulma-success-30-invert-l: var(--bulma-success-100-l); + --bulma-success-30-invert: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-30-invert-l), 1); + --bulma-success-35: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-35-l), 1); + --bulma-success-35-invert-l: var(--bulma-success-100-l); + --bulma-success-35-invert: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-35-invert-l), 1); + --bulma-success-40: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-40-l), 1); + --bulma-success-40-invert-l: var(--bulma-success-100-l); + --bulma-success-40-invert: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-40-invert-l), 1); + --bulma-success-45: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-45-l), 1); + --bulma-success-45-invert-l: var(--bulma-success-05-l); + --bulma-success-45-invert: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-45-invert-l), 1); + --bulma-success-50: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-50-l), 1); + --bulma-success-50-invert-l: var(--bulma-success-05-l); + --bulma-success-50-invert: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-50-invert-l), 1); + --bulma-success-55: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-55-l), 1); + --bulma-success-55-invert-l: var(--bulma-success-10-l); + --bulma-success-55-invert: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-55-invert-l), 1); + --bulma-success-60: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-60-l), 1); + --bulma-success-60-invert-l: var(--bulma-success-10-l); + --bulma-success-60-invert: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-60-invert-l), 1); + --bulma-success-65: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-65-l), 1); + --bulma-success-65-invert-l: var(--bulma-success-10-l); + --bulma-success-65-invert: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-65-invert-l), 1); + --bulma-success-70: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-70-l), 1); + --bulma-success-70-invert-l: var(--bulma-success-10-l); + --bulma-success-70-invert: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-70-invert-l), 1); + --bulma-success-75: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-75-l), 1); + --bulma-success-75-invert-l: var(--bulma-success-15-l); + --bulma-success-75-invert: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-75-invert-l), 1); + --bulma-success-80: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-80-l), 1); + --bulma-success-80-invert-l: var(--bulma-success-15-l); + --bulma-success-80-invert: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-80-invert-l), 1); + --bulma-success-85: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-85-l), 1); + --bulma-success-85-invert-l: var(--bulma-success-15-l); + --bulma-success-85-invert: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-85-invert-l), 1); + --bulma-success-90: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-90-l), 1); + --bulma-success-90-invert-l: var(--bulma-success-15-l); + --bulma-success-90-invert: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-90-invert-l), 1); + --bulma-success-95: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-95-l), 1); + --bulma-success-95-invert-l: var(--bulma-success-20-l); + --bulma-success-95-invert: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-95-invert-l), 1); + --bulma-success-100: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-100-l), 1); + --bulma-success-100-invert-l: var(--bulma-success-20-l); + --bulma-success-100-invert: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-100-invert-l), 1); + --bulma-success-invert-l: var(--bulma-success-10-l); + --bulma-success-invert: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-invert-l), 1); + --bulma-success-light-l: var(--bulma-success-90-l); + --bulma-success-light: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-light-l), 1); + --bulma-success-light-invert-l: var(--bulma-success-15-l); + --bulma-success-light-invert: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-light-invert-l), 1); + --bulma-success-dark-l: var(--bulma-success-10-l); + --bulma-success-dark: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-dark-l), 1); + --bulma-success-dark-invert-l: var(--bulma-success-55-l); + --bulma-success-dark-invert: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-dark-invert-l), 1); + --bulma-success-soft: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-soft-l), 1); + --bulma-success-bold: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-bold-l), 1); + --bulma-success-soft-invert: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-soft-invert-l), 1); + --bulma-success-bold-invert: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-bold-invert-l), 1); + --bulma-success-on-scheme-l: 23%; + --bulma-success-on-scheme: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-on-scheme-l), 1); + --bulma-warning: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-l), 1); + --bulma-warning-base: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-l), 1); + --bulma-warning-rgb: 255, 183.09, 15.3; + --bulma-warning-h: 42deg; + --bulma-warning-s: 100%; + --bulma-warning-l: 53%; + --bulma-warning-00-l: 0%; + --bulma-warning-05-l: 3%; + --bulma-warning-10-l: 8%; + --bulma-warning-15-l: 13%; + --bulma-warning-20-l: 18%; + --bulma-warning-25-l: 23%; + --bulma-warning-30-l: 28%; + --bulma-warning-35-l: 33%; + --bulma-warning-40-l: 38%; + --bulma-warning-45-l: 43%; + --bulma-warning-50-l: 48%; + --bulma-warning-55-l: 53%; + --bulma-warning-60-l: 58%; + --bulma-warning-65-l: 63%; + --bulma-warning-70-l: 68%; + --bulma-warning-75-l: 73%; + --bulma-warning-80-l: 78%; + --bulma-warning-85-l: 83%; + --bulma-warning-90-l: 88%; + --bulma-warning-95-l: 93%; + --bulma-warning-100-l: 98%; + --bulma-warning-00: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-00-l), 1); + --bulma-warning-00-invert-l: var(--bulma-warning-40-l); + --bulma-warning-00-invert: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-00-invert-l), 1); + --bulma-warning-05: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-05-l), 1); + --bulma-warning-05-invert-l: var(--bulma-warning-45-l); + --bulma-warning-05-invert: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-05-invert-l), 1); + --bulma-warning-10: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-10-l), 1); + --bulma-warning-10-invert-l: var(--bulma-warning-50-l); + --bulma-warning-10-invert: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-10-invert-l), 1); + --bulma-warning-15: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-15-l), 1); + --bulma-warning-15-invert-l: var(--bulma-warning-70-l); + --bulma-warning-15-invert: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-15-invert-l), 1); + --bulma-warning-20: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-20-l), 1); + --bulma-warning-20-invert-l: var(--bulma-warning-100-l); + --bulma-warning-20-invert: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-20-invert-l), 1); + --bulma-warning-25: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-25-l), 1); + --bulma-warning-25-invert-l: var(--bulma-warning-100-l); + --bulma-warning-25-invert: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-25-invert-l), 1); + --bulma-warning-30: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-30-l), 1); + --bulma-warning-30-invert-l: var(--bulma-warning-100-l); + --bulma-warning-30-invert: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-30-invert-l), 1); + --bulma-warning-35: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-35-l), 1); + --bulma-warning-35-invert-l: var(--bulma-warning-100-l); + --bulma-warning-35-invert: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-35-invert-l), 1); + --bulma-warning-40: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-40-l), 1); + --bulma-warning-40-invert-l: var(--bulma-warning-00-l); + --bulma-warning-40-invert: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-40-invert-l), 1); + --bulma-warning-45: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-45-l), 1); + --bulma-warning-45-invert-l: var(--bulma-warning-05-l); + --bulma-warning-45-invert: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-45-invert-l), 1); + --bulma-warning-50: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-50-l), 1); + --bulma-warning-50-invert-l: var(--bulma-warning-10-l); + --bulma-warning-50-invert: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-50-invert-l), 1); + --bulma-warning-55: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-55-l), 1); + --bulma-warning-55-invert-l: var(--bulma-warning-10-l); + --bulma-warning-55-invert: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-55-invert-l), 1); + --bulma-warning-60: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-60-l), 1); + --bulma-warning-60-invert-l: var(--bulma-warning-10-l); + --bulma-warning-60-invert: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-60-invert-l), 1); + --bulma-warning-65: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-65-l), 1); + --bulma-warning-65-invert-l: var(--bulma-warning-10-l); + --bulma-warning-65-invert: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-65-invert-l), 1); + --bulma-warning-70: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-70-l), 1); + --bulma-warning-70-invert-l: var(--bulma-warning-15-l); + --bulma-warning-70-invert: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-70-invert-l), 1); + --bulma-warning-75: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-75-l), 1); + --bulma-warning-75-invert-l: var(--bulma-warning-15-l); + --bulma-warning-75-invert: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-75-invert-l), 1); + --bulma-warning-80: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-80-l), 1); + --bulma-warning-80-invert-l: var(--bulma-warning-15-l); + --bulma-warning-80-invert: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-80-invert-l), 1); + --bulma-warning-85: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-85-l), 1); + --bulma-warning-85-invert-l: var(--bulma-warning-15-l); + --bulma-warning-85-invert: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-85-invert-l), 1); + --bulma-warning-90: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-90-l), 1); + --bulma-warning-90-invert-l: var(--bulma-warning-15-l); + --bulma-warning-90-invert: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-90-invert-l), 1); + --bulma-warning-95: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-95-l), 1); + --bulma-warning-95-invert-l: var(--bulma-warning-15-l); + --bulma-warning-95-invert: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-95-invert-l), 1); + --bulma-warning-100: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-100-l), 1); + --bulma-warning-100-invert-l: var(--bulma-warning-20-l); + --bulma-warning-100-invert: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-100-invert-l), 1); + --bulma-warning-invert-l: var(--bulma-warning-10-l); + --bulma-warning-invert: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-invert-l), 1); + --bulma-warning-light-l: var(--bulma-warning-90-l); + --bulma-warning-light: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-light-l), 1); + --bulma-warning-light-invert-l: var(--bulma-warning-15-l); + --bulma-warning-light-invert: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-light-invert-l), 1); + --bulma-warning-dark-l: var(--bulma-warning-10-l); + --bulma-warning-dark: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-dark-l), 1); + --bulma-warning-dark-invert-l: var(--bulma-warning-50-l); + --bulma-warning-dark-invert: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-dark-invert-l), 1); + --bulma-warning-soft: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-soft-l), 1); + --bulma-warning-bold: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-bold-l), 1); + --bulma-warning-soft-invert: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-soft-invert-l), 1); + --bulma-warning-bold-invert: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-bold-invert-l), 1); + --bulma-warning-on-scheme-l: 23%; + --bulma-warning-on-scheme: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-on-scheme-l), 1); + --bulma-danger: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-l), 1); + --bulma-danger-base: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-l), 1); + --bulma-danger-rgb: 255, 102, 132.6; + --bulma-danger-h: 348deg; + --bulma-danger-s: 100%; + --bulma-danger-l: 70%; + --bulma-danger-00-l: 0%; + --bulma-danger-05-l: 5%; + --bulma-danger-10-l: 10%; + --bulma-danger-15-l: 15%; + --bulma-danger-20-l: 20%; + --bulma-danger-25-l: 25%; + --bulma-danger-30-l: 30%; + --bulma-danger-35-l: 35%; + --bulma-danger-40-l: 40%; + --bulma-danger-45-l: 45%; + --bulma-danger-50-l: 50%; + --bulma-danger-55-l: 55%; + --bulma-danger-60-l: 60%; + --bulma-danger-65-l: 65%; + --bulma-danger-70-l: 70%; + --bulma-danger-75-l: 75%; + --bulma-danger-80-l: 80%; + --bulma-danger-85-l: 85%; + --bulma-danger-90-l: 90%; + --bulma-danger-95-l: 95%; + --bulma-danger-100-l: 100%; + --bulma-danger-00: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-00-l), 1); + --bulma-danger-00-invert-l: var(--bulma-danger-65-l); + --bulma-danger-00-invert: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-00-invert-l), 1); + --bulma-danger-05: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-05-l), 1); + --bulma-danger-05-invert-l: var(--bulma-danger-70-l); + --bulma-danger-05-invert: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-05-invert-l), 1); + --bulma-danger-10: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-10-l), 1); + --bulma-danger-10-invert-l: var(--bulma-danger-75-l); + --bulma-danger-10-invert: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-10-invert-l), 1); + --bulma-danger-15: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-15-l), 1); + --bulma-danger-15-invert-l: var(--bulma-danger-80-l); + --bulma-danger-15-invert: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-15-invert-l), 1); + --bulma-danger-20: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-20-l), 1); + --bulma-danger-20-invert-l: var(--bulma-danger-85-l); + --bulma-danger-20-invert: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-20-invert-l), 1); + --bulma-danger-25: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-25-l), 1); + --bulma-danger-25-invert-l: var(--bulma-danger-90-l); + --bulma-danger-25-invert: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-25-invert-l), 1); + --bulma-danger-30: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-30-l), 1); + --bulma-danger-30-invert-l: var(--bulma-danger-100-l); + --bulma-danger-30-invert: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-30-invert-l), 1); + --bulma-danger-35: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-35-l), 1); + --bulma-danger-35-invert-l: var(--bulma-danger-100-l); + --bulma-danger-35-invert: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-35-invert-l), 1); + --bulma-danger-40: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-40-l), 1); + --bulma-danger-40-invert-l: var(--bulma-danger-100-l); + --bulma-danger-40-invert: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-40-invert-l), 1); + --bulma-danger-45: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-45-l), 1); + --bulma-danger-45-invert-l: var(--bulma-danger-100-l); + --bulma-danger-45-invert: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-45-invert-l), 1); + --bulma-danger-50: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-50-l), 1); + --bulma-danger-50-invert-l: var(--bulma-danger-100-l); + --bulma-danger-50-invert: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-50-invert-l), 1); + --bulma-danger-55: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-55-l), 1); + --bulma-danger-55-invert-l: var(--bulma-danger-100-l); + --bulma-danger-55-invert: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-55-invert-l), 1); + --bulma-danger-60: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-60-l), 1); + --bulma-danger-60-invert-l: var(--bulma-danger-100-l); + --bulma-danger-60-invert: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-60-invert-l), 1); + --bulma-danger-65: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-65-l), 1); + --bulma-danger-65-invert-l: var(--bulma-danger-00-l); + --bulma-danger-65-invert: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-65-invert-l), 1); + --bulma-danger-70: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-70-l), 1); + --bulma-danger-70-invert-l: var(--bulma-danger-05-l); + --bulma-danger-70-invert: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-70-invert-l), 1); + --bulma-danger-75: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-75-l), 1); + --bulma-danger-75-invert-l: var(--bulma-danger-10-l); + --bulma-danger-75-invert: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-75-invert-l), 1); + --bulma-danger-80: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-80-l), 1); + --bulma-danger-80-invert-l: var(--bulma-danger-15-l); + --bulma-danger-80-invert: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-80-invert-l), 1); + --bulma-danger-85: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-85-l), 1); + --bulma-danger-85-invert-l: var(--bulma-danger-20-l); + --bulma-danger-85-invert: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-85-invert-l), 1); + --bulma-danger-90: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-90-l), 1); + --bulma-danger-90-invert-l: var(--bulma-danger-25-l); + --bulma-danger-90-invert: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-90-invert-l), 1); + --bulma-danger-95: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-95-l), 1); + --bulma-danger-95-invert-l: var(--bulma-danger-25-l); + --bulma-danger-95-invert: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-95-invert-l), 1); + --bulma-danger-100: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-100-l), 1); + --bulma-danger-100-invert-l: var(--bulma-danger-30-l); + --bulma-danger-100-invert: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-100-invert-l), 1); + --bulma-danger-invert-l: var(--bulma-danger-05-l); + --bulma-danger-invert: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-invert-l), 1); + --bulma-danger-light-l: var(--bulma-danger-90-l); + --bulma-danger-light: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-light-l), 1); + --bulma-danger-light-invert-l: var(--bulma-danger-25-l); + --bulma-danger-light-invert: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-light-invert-l), 1); + --bulma-danger-dark-l: var(--bulma-danger-10-l); + --bulma-danger-dark: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-dark-l), 1); + --bulma-danger-dark-invert-l: var(--bulma-danger-75-l); + --bulma-danger-dark-invert: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-dark-invert-l), 1); + --bulma-danger-soft: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-soft-l), 1); + --bulma-danger-bold: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-bold-l), 1); + --bulma-danger-soft-invert: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-soft-invert-l), 1); + --bulma-danger-bold-invert: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-bold-invert-l), 1); + --bulma-danger-on-scheme-l: 40%; + --bulma-danger-on-scheme: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-on-scheme-l), 1); + --bulma-black-bis: hsl(221, 14%, 9%); + --bulma-black-ter: hsl(221, 14%, 14%); + --bulma-grey-darker: hsl(221, 14%, 21%); + --bulma-grey-dark: hsl(221, 14%, 29%); + --bulma-grey: hsl(221, 14%, 48%); + --bulma-grey-light: hsl(221, 14%, 71%); + --bulma-grey-lighter: hsl(221, 14%, 86%); + --bulma-white-ter: hsl(221, 14%, 96%); + --bulma-white-bis: hsl(221, 14%, 98%); + --bulma-shadow-h: 221deg; + --bulma-shadow-s: 14%; + --bulma-shadow-l: 4%; + --bulma-size-1: 3rem; + --bulma-size-2: 2.5rem; + --bulma-size-3: 2rem; + --bulma-size-4: 1.5rem; + --bulma-size-5: 1.25rem; + --bulma-size-6: 1rem; + --bulma-size-7: 0.75rem; + --bulma-scheme-main: hsl(var(--bulma-scheme-h), var(--bulma-scheme-s), var(--bulma-scheme-main-l)); + --bulma-scheme-main-bis: hsl(var(--bulma-scheme-h), var(--bulma-scheme-s), var(--bulma-scheme-main-bis-l)); + --bulma-scheme-main-ter: hsl(var(--bulma-scheme-h), var(--bulma-scheme-s), var(--bulma-scheme-main-ter-l)); + --bulma-background: hsl(var(--bulma-scheme-h), var(--bulma-scheme-s), var(--bulma-background-l)); + --bulma-background-hover: hsl(var(--bulma-scheme-h), var(--bulma-scheme-s), calc(var(--bulma-background-l) + var(--bulma-hover-background-l-delta))); + --bulma-background-active: hsl(var(--bulma-scheme-h), var(--bulma-scheme-s), calc(var(--bulma-background-l) + var(--bulma-active-background-l-delta))); + --bulma-border-weak: hsl(var(--bulma-scheme-h), var(--bulma-scheme-s), var(--bulma-border-weak-l)); + --bulma-border: hsl(var(--bulma-scheme-h), var(--bulma-scheme-s), var(--bulma-border-l)); + --bulma-border-hover: hsl(var(--bulma-scheme-h), var(--bulma-scheme-s), calc(var(--bulma-border-l) + var(--bulma-hover-border-l-delta))); + --bulma-border-active: hsl(var(--bulma-scheme-h), var(--bulma-scheme-s), calc(var(--bulma-border-l) + var(--bulma-active-border-l-delta))); + --bulma-text-weak: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-weak-l)); + --bulma-text: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-l)); + --bulma-text-strong: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-strong-l)); + --bulma-scheme-invert-ter: hsl(var(--bulma-scheme-h), var(--bulma-scheme-s), var(--bulma-scheme-invert-ter-l)); + --bulma-scheme-invert-bis: hsl(var(--bulma-scheme-h), var(--bulma-scheme-s), var(--bulma-scheme-invert-bis-l)); + --bulma-scheme-invert: hsl(var(--bulma-scheme-h), var(--bulma-scheme-s), var(--bulma-scheme-invert-l)); + --bulma-link: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-l)); + --bulma-link-text: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-on-scheme-l)); + --bulma-link-text-hover: hsl(var(--bulma-link-h), var(--bulma-link-s), calc(var(--bulma-link-on-scheme-l) + var(--bulma-hover-color-l-delta))); + --bulma-link-text-active: hsl(var(--bulma-link-h), var(--bulma-link-s), calc(var(--bulma-link-on-scheme-l) + var(--bulma-active-color-l-delta))); + --bulma-focus-h: var(--bulma-link-h); + --bulma-focus-s: var(--bulma-link-s); + --bulma-focus-l: var(--bulma-link-l); + --bulma-focus-offset: 1px; + --bulma-focus-style: solid; + --bulma-focus-width: 2px; + --bulma-focus-shadow-size: 0 0 0 0.1875em; + --bulma-focus-shadow-alpha: 0.25; + --bulma-code: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-on-scheme-l)); + --bulma-code-background: var(--bulma-background); + --bulma-pre: var(--bulma-text); + --bulma-pre-background: var(--bulma-background); + --bulma-shadow: 0 0.5em 1em -0.125em hsla(var(--bulma-shadow-h), var(--bulma-shadow-s), var(--bulma-shadow-l), 0.1), 0 0px 0 1px hsla(var(--bulma-shadow-h), var(--bulma-shadow-s), var(--bulma-shadow-l), 0.02); +} + +[data-theme=dark], +.theme-dark { + --bulma-white-on-scheme-l: 100%; + --bulma-white-on-scheme: hsla(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-on-scheme-l), 1); + --bulma-black-on-scheme-l: -51%; + --bulma-black-on-scheme: hsla(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-on-scheme-l), 1); + --bulma-light-on-scheme-l: 96%; + --bulma-light-on-scheme: hsla(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-on-scheme-l), 1); + --bulma-dark-on-scheme-l: 56%; + --bulma-dark-on-scheme: hsla(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-on-scheme-l), 1); + --bulma-text-on-scheme-l: 54%; + --bulma-text-on-scheme: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-on-scheme-l), 1); + --bulma-primary-on-scheme-l: 41%; + --bulma-primary-on-scheme: hsla(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-on-scheme-l), 1); + --bulma-link-on-scheme-l: 73%; + --bulma-link-on-scheme: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-on-scheme-l), 1); + --bulma-info-on-scheme-l: 70%; + --bulma-info-on-scheme: hsla(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-on-scheme-l), 1); + --bulma-success-on-scheme-l: 53%; + --bulma-success-on-scheme: hsla(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-on-scheme-l), 1); + --bulma-warning-on-scheme-l: 53%; + --bulma-warning-on-scheme: hsla(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-on-scheme-l), 1); + --bulma-danger-on-scheme-l: 70%; + --bulma-danger-on-scheme: hsla(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-on-scheme-l), 1); + --bulma-scheme-brightness: dark; + --bulma-scheme-main-l: 9%; + --bulma-scheme-main-bis-l: 11%; + --bulma-scheme-main-ter-l: 13%; + --bulma-soft-l: 20%; + --bulma-bold-l: 90%; + --bulma-soft-invert-l: 90%; + --bulma-bold-invert-l: 20%; + --bulma-background-l: 14%; + --bulma-border-weak-l: 21%; + --bulma-border-l: 24%; + --bulma-text-weak-l: 53%; + --bulma-text-l: 71%; + --bulma-text-strong-l: 93%; + --bulma-text-title-l: 100%; + --bulma-hover-background-l-delta: 5%; + --bulma-active-background-l-delta: 10%; + --bulma-hover-border-l-delta: 10%; + --bulma-active-border-l-delta: 20%; + --bulma-hover-color-l-delta: 5%; + --bulma-active-color-l-delta: 10%; + --bulma-shadow-h: 0deg; + --bulma-shadow-s: 0%; + --bulma-shadow-l: 100%; + --bulma-scheme-main: hsl(var(--bulma-scheme-h), var(--bulma-scheme-s), var(--bulma-scheme-main-l)); + --bulma-scheme-main-bis: hsl(var(--bulma-scheme-h), var(--bulma-scheme-s), var(--bulma-scheme-main-bis-l)); + --bulma-scheme-main-ter: hsl(var(--bulma-scheme-h), var(--bulma-scheme-s), var(--bulma-scheme-main-ter-l)); + --bulma-background: hsl(var(--bulma-scheme-h), var(--bulma-scheme-s), var(--bulma-background-l)); + --bulma-background-hover: hsl(var(--bulma-scheme-h), var(--bulma-scheme-s), calc(var(--bulma-background-l) + var(--bulma-hover-background-l-delta))); + --bulma-background-active: hsl(var(--bulma-scheme-h), var(--bulma-scheme-s), calc(var(--bulma-background-l) + var(--bulma-active-background-l-delta))); + --bulma-border-weak: hsl(var(--bulma-scheme-h), var(--bulma-scheme-s), var(--bulma-border-weak-l)); + --bulma-border: hsl(var(--bulma-scheme-h), var(--bulma-scheme-s), var(--bulma-border-l)); + --bulma-border-hover: hsl(var(--bulma-scheme-h), var(--bulma-scheme-s), calc(var(--bulma-border-l) + var(--bulma-hover-border-l-delta))); + --bulma-border-active: hsl(var(--bulma-scheme-h), var(--bulma-scheme-s), calc(var(--bulma-border-l) + var(--bulma-active-border-l-delta))); + --bulma-text-weak: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-weak-l)); + --bulma-text: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-l)); + --bulma-text-strong: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-strong-l)); + --bulma-scheme-invert-ter: hsl(var(--bulma-scheme-h), var(--bulma-scheme-s), var(--bulma-scheme-invert-ter-l)); + --bulma-scheme-invert-bis: hsl(var(--bulma-scheme-h), var(--bulma-scheme-s), var(--bulma-scheme-invert-bis-l)); + --bulma-scheme-invert: hsl(var(--bulma-scheme-h), var(--bulma-scheme-s), var(--bulma-scheme-invert-l)); + --bulma-link: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-l)); + --bulma-link-text: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-on-scheme-l)); + --bulma-link-text-hover: hsl(var(--bulma-link-h), var(--bulma-link-s), calc(var(--bulma-link-on-scheme-l) + var(--bulma-hover-color-l-delta))); + --bulma-link-text-active: hsl(var(--bulma-link-h), var(--bulma-link-s), calc(var(--bulma-link-on-scheme-l) + var(--bulma-active-color-l-delta))); + --bulma-focus-h: var(--bulma-link-h); + --bulma-focus-s: var(--bulma-link-s); + --bulma-focus-l: var(--bulma-link-l); + --bulma-focus-offset: 1px; + --bulma-focus-style: solid; + --bulma-focus-width: 2px; + --bulma-focus-shadow-size: 0 0 0 0.1875em; + --bulma-focus-shadow-alpha: 0.25; + --bulma-code: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-on-scheme-l)); + --bulma-code-background: var(--bulma-background); + --bulma-pre: var(--bulma-text); + --bulma-pre-background: var(--bulma-background); + --bulma-shadow: 0 0.5em 1em -0.125em hsla(var(--bulma-shadow-h), var(--bulma-shadow-s), var(--bulma-shadow-l), 0.1), 0 0px 0 1px hsla(var(--bulma-shadow-h), var(--bulma-shadow-s), var(--bulma-shadow-l), 0.02); +} + +/* Bulma Base */ +/*! minireset.css v0.0.6 | MIT License | github.com/jgthms/minireset.css */ +html, +body, +p, +ol, +ul, +li, +dl, +dt, +dd, +blockquote, +figure, +fieldset, +legend, +textarea, +pre, +iframe, +hr, +h1, +h2, +h3, +h4, +h5, +h6 { + margin: 0; + padding: 0; +} + +h1, +h2, +h3, +h4, +h5, +h6 { + font-size: 100%; + font-weight: normal; +} + +ul { + list-style: none; +} + +button, +input, +select, +textarea { + margin: 0; +} + +html { + box-sizing: border-box; +} + +*, *::before, *::after { + box-sizing: inherit; +} + +img, +video { + height: auto; + max-width: 100%; +} + +iframe { + border: 0; +} + +table { + border-collapse: collapse; + border-spacing: 0; +} + +td, +th { + padding: 0; +} +td:not([align]), +th:not([align]) { + text-align: inherit; +} + +:root { + --bulma-body-background-color: var(--bulma-scheme-main); + --bulma-body-size: 1em; + --bulma-body-min-width: 300px; + --bulma-body-rendering: optimizeLegibility; + --bulma-body-family: var(--bulma-family-primary); + --bulma-body-overflow-x: hidden; + --bulma-body-overflow-y: scroll; + --bulma-body-color: var(--bulma-text); + --bulma-body-font-size: 1em; + --bulma-body-weight: var(--bulma-weight-normal); + --bulma-body-line-height: 1.5; + --bulma-code-family: var(--bulma-family-code); + --bulma-code-padding: 0.25em 0.5em 0.25em; + --bulma-code-weight: normal; + --bulma-code-size: 0.875em; + --bulma-small-font-size: 0.875em; + --bulma-hr-background-color: var(--bulma-background); + --bulma-hr-height: 2px; + --bulma-hr-margin: 1.5rem 0; + --bulma-strong-color: var(--bulma-text-strong); + --bulma-strong-weight: var(--bulma-weight-semibold); + --bulma-pre-font-size: 0.875em; + --bulma-pre-padding: 1.25rem 1.5rem; + --bulma-pre-code-font-size: 1em; +} + +html { + background-color: var(--bulma-body-background-color); + font-size: var(--bulma-body-size); + -moz-osx-font-smoothing: grayscale; + -webkit-font-smoothing: antialiased; + min-width: var(--bulma-body-min-width); + overflow-x: var(--bulma-body-overflow-x); + overflow-y: var(--bulma-body-overflow-y); + text-rendering: var(--bulma-body-rendering); + text-size-adjust: 100%; +} + +article, +aside, +figure, +footer, +header, +hgroup, +section { + display: block; +} + +body, +button, +input, +optgroup, +select, +textarea { + font-family: var(--bulma-body-family); +} + +code, +pre { + -moz-osx-font-smoothing: auto; + -webkit-font-smoothing: auto; + font-family: var(--bulma-code-family); +} + +body { + color: var(--bulma-body-color); + font-size: var(--bulma-body-font-size); + font-weight: var(--bulma-body-weight); + line-height: var(--bulma-body-line-height); +} + +a, +button { + cursor: pointer; +} +a:focus-visible, +button:focus-visible { + outline-color: hsl(var(--bulma-focus-h), var(--bulma-focus-s), var(--bulma-focus-l)); + outline-offset: var(--bulma-focus-offset); + outline-style: var(--bulma-focus-style); + outline-width: var(--bulma-focus-width); +} +a:focus-visible:active, +button:focus-visible:active { + outline-width: 1px; +} +a:active, +button:active { + outline-width: 1px; +} + +a { + color: var(--bulma-link-text); + cursor: pointer; + text-decoration: none; + transition-duration: var(--bulma-duration); + transition-property: background-color, border-color, color; +} +a strong { + color: currentColor; +} + +button { + appearance: none; + background: none; + border: none; + color: inherit; + font-family: inherit; + font-size: 1em; + margin: 0; + padding: 0; + transition-duration: var(--bulma-duration); + transition-property: background-color, border-color, color; +} + +code { + background-color: var(--bulma-code-background); + border-radius: 0.5em; + color: var(--bulma-code); + font-size: var(--bulma-code-size); + font-weight: var(--bulma-code-weight); + padding: var(--bulma-code-padding); +} + +hr { + background-color: var(--bulma-hr-background-color); + border: none; + display: block; + height: var(--bulma-hr-height); + margin: var(--bulma-hr-margin); +} + +img { + height: auto; + max-width: 100%; +} + +input[type=checkbox], +input[type=radio] { + vertical-align: baseline; +} + +small { + font-size: var(--bulma-small-font-size); +} + +span { + font-style: inherit; + font-weight: inherit; +} + +strong { + color: var(--bulma-strong-color); + font-weight: var(--bulma-strong-weight); +} + +svg { + height: auto; + width: auto; +} + +fieldset { + border: none; +} + +pre { + -webkit-overflow-scrolling: touch; + background-color: var(--bulma-pre-background); + color: var(--bulma-pre); + font-size: var(--bulma-pre-font-size); + overflow-x: auto; + padding: var(--bulma-pre-padding); + white-space: pre; + word-wrap: normal; +} +pre code { + background-color: transparent; + color: currentColor; + font-size: var(--bulma-pre-code-font-size); + padding: 0; +} + +table td, +table th { + vertical-align: top; +} +table td:not([align]), +table th:not([align]) { + text-align: inherit; +} +table th { + color: var(--bulma-text-strong); +} + +@keyframes spinAround { + from { + transform: rotate(0deg); + } + to { + transform: rotate(359deg); + } +} +@keyframes pulsate { + 50% { + opacity: 0.5; + } +} +/* Bulma Elements */ +.navbar-link:not(.is-arrowless)::after, .select:not(.is-multiple):not(.is-loading)::after { + border: 0.125em solid var(--bulma-arrow-color); + border-right: 0; + border-top: 0; + content: " "; + display: block; + height: 0.625em; + margin-top: -0.4375em; + pointer-events: none; + position: absolute; + top: 50%; + transform: rotate(-45deg); + transform-origin: center; + transition-duration: var(--bulma-duration); + transition-property: border-color; + width: 0.625em; +} + +.skeleton-block:not(:last-child), .media:not(:last-child), .level:not(:last-child), .fixed-grid:not(:last-child), .grid:not(:last-child), .tabs:not(:last-child), .pagination:not(:last-child), .message:not(:last-child), .card:not(:last-child), .breadcrumb:not(:last-child), .field:not(:last-child), .file:not(:last-child), .title:not(:last-child), +.subtitle:not(:last-child), .tags:not(:last-child), .table:not(:last-child), .table-container:not(:last-child), .progress:not(:last-child), .notification:not(:last-child), .content:not(:last-child), .buttons:not(:last-child), .box:not(:last-child), .block:not(:last-child) { + margin-bottom: var(--bulma-block-spacing); +} + +.pagination-previous, +.pagination-next, +.pagination-link, +.pagination-ellipsis, .file-cta, +.file-name, .select select, .input, .textarea, .button { + align-items: center; + appearance: none; + border-color: transparent; + border-style: solid; + border-width: var(--bulma-control-border-width); + border-radius: var(--bulma-control-radius); + box-shadow: none; + display: inline-flex; + font-size: var(--bulma-control-size); + height: var(--bulma-control-height); + justify-content: flex-start; + line-height: var(--bulma-control-line-height); + padding-bottom: var(--bulma-control-padding-vertical); + padding-left: var(--bulma-control-padding-horizontal); + padding-right: var(--bulma-control-padding-horizontal); + padding-top: var(--bulma-control-padding-vertical); + position: relative; + transition-duration: var(--bulma-duration); + transition-property: background-color, border-color, box-shadow, color; + vertical-align: top; +} +.pagination-previous:focus, +.pagination-next:focus, +.pagination-link:focus, +.pagination-ellipsis:focus, .file-cta:focus, +.file-name:focus, .select select:focus, .input:focus, .textarea:focus, .button:focus, .pagination-previous:focus-visible, +.pagination-next:focus-visible, +.pagination-link:focus-visible, +.pagination-ellipsis:focus-visible, .file-cta:focus-visible, +.file-name:focus-visible, .select select:focus-visible, .input:focus-visible, .textarea:focus-visible, .button:focus-visible, .pagination-previous:focus-within, +.pagination-next:focus-within, +.pagination-link:focus-within, +.pagination-ellipsis:focus-within, .file-cta:focus-within, +.file-name:focus-within, .select select:focus-within, .input:focus-within, .textarea:focus-within, .button:focus-within, .is-focused.pagination-previous, +.is-focused.pagination-next, +.is-focused.pagination-link, +.is-focused.pagination-ellipsis, .is-focused.file-cta, +.is-focused.file-name, .select select.is-focused, .is-focused.input, .is-focused.textarea, .is-focused.button, .pagination-previous:active, +.pagination-next:active, +.pagination-link:active, +.pagination-ellipsis:active, .file-cta:active, +.file-name:active, .select select:active, .input:active, .textarea:active, .button:active, .is-active.pagination-previous, +.is-active.pagination-next, +.is-active.pagination-link, +.is-active.pagination-ellipsis, .is-active.file-cta, +.is-active.file-name, .select select.is-active, .is-active.input, .is-active.textarea, .is-active.button { + outline: none; +} +[disabled].pagination-previous, +[disabled].pagination-next, +[disabled].pagination-link, +[disabled].pagination-ellipsis, [disabled].file-cta, +[disabled].file-name, .select select[disabled], [disabled].input, [disabled].textarea, [disabled].button, fieldset[disabled] .pagination-previous, +fieldset[disabled] .pagination-next, +fieldset[disabled] .pagination-link, +fieldset[disabled] .pagination-ellipsis, fieldset[disabled] .file-cta, +fieldset[disabled] .file-name, fieldset[disabled] .select select, .select fieldset[disabled] select, fieldset[disabled] .input, fieldset[disabled] .textarea, fieldset[disabled] .button { + cursor: not-allowed; +} + +.modal-close { + --bulma-delete-dimensions: 1.25rem; + --bulma-delete-background-l: 0%; + --bulma-delete-background-alpha: 0.5; + --bulma-delete-color: var(--bulma-white); + appearance: none; + background-color: hsla(var(--bulma-scheme-h), var(--bulma-scheme-s), var(--bulma-delete-background-l), var(--bulma-delete-background-alpha)); + border: none; + border-radius: var(--bulma-radius-rounded); + cursor: pointer; + pointer-events: auto; + display: inline-flex; + flex-grow: 0; + flex-shrink: 0; + font-size: 1em; + height: var(--bulma-delete-dimensions); + max-height: var(--bulma-delete-dimensions); + max-width: var(--bulma-delete-dimensions); + min-height: var(--bulma-delete-dimensions); + min-width: var(--bulma-delete-dimensions); + outline: none; + position: relative; + vertical-align: top; + width: var(--bulma-delete-dimensions); +} +.modal-close::before, .modal-close::after { + background-color: var(--bulma-delete-color); + content: ""; + display: block; + left: 50%; + position: absolute; + top: 50%; + transform: translateX(-50%) translateY(-50%) rotate(45deg); + transform-origin: center center; +} +.modal-close::before { + height: 2px; + width: 50%; +} +.modal-close::after { + height: 50%; + width: 2px; +} +.modal-close:hover, .modal-close:focus { + --bulma-delete-background-alpha: 0.4; +} +.modal-close:active { + --bulma-delete-background-alpha: 0.5; +} +.is-small.modal-close { + --bulma-delete-dimensions: 1rem; +} +.is-medium.modal-close { + --bulma-delete-dimensions: 1.5rem; +} +.is-large.modal-close { + --bulma-delete-dimensions: 2rem; +} + +.control.is-loading::after, .select.is-loading::after, .button.is-loading::after { + animation: spinAround 500ms infinite linear; + border: 2px solid var(--bulma-loading-color); + border-radius: var(--bulma-radius-rounded); + border-right-color: transparent; + border-top-color: transparent; + content: ""; + display: block; + height: 1em; + position: relative; + width: 1em; +} + +.is-overlay, .hero-video, .modal, .modal-background { + bottom: 0; + left: 0; + position: absolute; + right: 0; + top: 0; +} + +.navbar-burger, .menu-list a, +.menu-list button, +.menu-list .menu-item { + appearance: none; + background: none; + border: none; + color: inherit; + font-family: inherit; + font-size: 1em; + margin: 0; + padding: 0; +} + +.is-unselectable, .tabs, .pagination-previous, +.pagination-next, +.pagination-link, +.pagination-ellipsis, .breadcrumb, .file, .button { + -webkit-touch-callout: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.box { + --bulma-box-background-color: var(--bulma-scheme-main); + --bulma-box-color: var(--bulma-text); + --bulma-box-radius: var(--bulma-radius-large); + --bulma-box-shadow: var(--bulma-shadow); + --bulma-box-padding: 1.25rem; + --bulma-box-link-hover-shadow: 0 0.5em 1em -0.125em hsla(var(--bulma-scheme-h), var(--bulma-scheme-s), var(--bulma-scheme-invert-l), 0.1), 0 0 0 1px var(--bulma-link); + --bulma-box-link-active-shadow: inset 0 1px 2px hsla(var(--bulma-scheme-h), var(--bulma-scheme-s), var(--bulma-scheme-invert-l), 0.2), 0 0 0 1px var(--bulma-link); +} + +.box { + background-color: var(--bulma-box-background-color); + border-radius: var(--bulma-box-radius); + box-shadow: var(--bulma-box-shadow); + color: var(--bulma-box-color); + display: block; + padding: var(--bulma-box-padding); +} + +a.box:hover, a.box:focus { + box-shadow: var(--bulma-box-link-hover-shadow); +} +a.box:active { + box-shadow: var(--bulma-box-link-active-shadow); +} + +.button { + --bulma-button-family: false; + --bulma-button-weight: var(--bulma-weight-medium); + --bulma-button-border-color: var(--bulma-border); + --bulma-button-border-style: solid; + --bulma-button-border-width: var(--bulma-control-border-width); + --bulma-button-padding-vertical: 0.5em; + --bulma-button-padding-horizontal: 1em; + --bulma-button-focus-border-color: var(--bulma-link-focus-border); + --bulma-button-focus-box-shadow-size: 0 0 0 0.125em; + --bulma-button-focus-box-shadow-color: hsla(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-on-scheme-l), 0.25); + --bulma-button-active-color: var(--bulma-link-active); + --bulma-button-active-border-color: var(--bulma-link-active-border); + --bulma-button-text-color: var(--bulma-text); + --bulma-button-text-decoration: underline; + --bulma-button-text-hover-background-color: var(--bulma-background); + --bulma-button-text-hover-color: var(--bulma-text-strong); + --bulma-button-ghost-background: none; + --bulma-button-ghost-border-color: transparent; + --bulma-button-ghost-color: var(--bulma-link-text); + --bulma-button-ghost-decoration: none; + --bulma-button-ghost-hover-color: var(--bulma-link); + --bulma-button-ghost-hover-decoration: underline; + --bulma-button-disabled-background-color: var(--bulma-scheme-main); + --bulma-button-disabled-border-color: var(--bulma-border); + --bulma-button-disabled-shadow: none; + --bulma-button-disabled-opacity: 0.5; + --bulma-button-static-color: var(--bulma-text-weak); + --bulma-button-static-background-color: var(--bulma-scheme-main-ter); + --bulma-button-static-border-color: var(--bulma-border); +} + +.button { + --bulma-button-h: var(--bulma-scheme-h); + --bulma-button-s: var(--bulma-scheme-s); + --bulma-button-l: var(--bulma-scheme-main-l); + --bulma-button-background-l: var(--bulma-scheme-main-l); + --bulma-button-background-l-delta: 0%; + --bulma-button-hover-background-l-delta: var(--bulma-hover-background-l-delta); + --bulma-button-active-background-l-delta: var(--bulma-active-background-l-delta); + --bulma-button-color-l: var(--bulma-text-strong-l); + --bulma-button-border-l: var(--bulma-border-l); + --bulma-button-border-l-delta: 0%; + --bulma-button-hover-border-l-delta: var(--bulma-hover-border-l-delta); + --bulma-button-active-border-l-delta: var(--bulma-active-border-l-delta); + --bulma-button-focus-border-l-delta: var(--bulma-focus-border-l-delta); + --bulma-button-outer-shadow-h: 0; + --bulma-button-outer-shadow-s: 0%; + --bulma-button-outer-shadow-l: 20%; + --bulma-button-outer-shadow-a: 0.05; + --bulma-loading-color: hsl(var(--bulma-button-h), var(--bulma-button-s), var(--bulma-button-color-l)); + background-color: hsl(var(--bulma-button-h), var(--bulma-button-s), calc(var(--bulma-button-background-l) + var(--bulma-button-background-l-delta))); + border-color: hsl(var(--bulma-button-h), var(--bulma-button-s), calc(var(--bulma-button-border-l) + var(--bulma-button-border-l-delta))); + border-style: var(--bulma-button-border-style); + border-width: var(--bulma-button-border-width); + box-shadow: 0px 0.0625em 0.125em hsla(var(--bulma-button-outer-shadow-h), var(--bulma-button-outer-shadow-s), var(--bulma-button-outer-shadow-l), var(--bulma-button-outer-shadow-a)), 0px 0.125em 0.25em hsla(var(--bulma-button-outer-shadow-h), var(--bulma-button-outer-shadow-s), var(--bulma-button-outer-shadow-l), var(--bulma-button-outer-shadow-a)); + color: hsl(var(--bulma-button-h), var(--bulma-button-s), var(--bulma-button-color-l)); + cursor: pointer; + font-weight: var(--bulma-button-weight); + height: auto; + justify-content: center; + padding-bottom: calc(var(--bulma-button-padding-vertical) - var(--bulma-button-border-width)); + padding-left: calc(var(--bulma-button-padding-horizontal) - var(--bulma-button-border-width)); + padding-right: calc(var(--bulma-button-padding-horizontal) - var(--bulma-button-border-width)); + padding-top: calc(var(--bulma-button-padding-vertical) - var(--bulma-button-border-width)); + text-align: center; + white-space: nowrap; +} +.button strong { + color: inherit; +} +.button .icon, .button .icon.is-small, .button .icon.is-medium, .button .icon.is-large { + height: 1.5em; + width: 1.5em; +} +.button .icon:first-child:not(:last-child) { + margin-inline-start: calc(-0.5 * var(--bulma-button-padding-horizontal)); + margin-inline-end: calc(var(--bulma-button-padding-horizontal) * 0.25); +} +.button .icon:last-child:not(:first-child) { + margin-inline-start: calc(var(--bulma-button-padding-horizontal) * 0.25); + margin-inline-end: calc(-0.5 * var(--bulma-button-padding-horizontal)); +} +.button .icon:first-child:last-child { + margin-inline-start: calc(-0.5 * var(--bulma-button-padding-horizontal)); + margin-inline-end: calc(-0.5 * var(--bulma-button-padding-horizontal)); +} +.button:hover, .button.is-hovered { + --bulma-button-background-l-delta: var(--bulma-button-hover-background-l-delta); + --bulma-button-border-l-delta: var(--bulma-button-hover-border-l-delta); +} +.button:focus-visible, .button.is-focused { + --bulma-button-border-width: 1px; + border-color: hsl(var(--bulma-focus-h), var(--bulma-focus-s), var(--bulma-focus-l)); + box-shadow: var(--bulma-focus-shadow-size) hsla(var(--bulma-focus-h), var(--bulma-focus-s), var(--bulma-focus-l), var(--bulma-focus-shadow-alpha)); +} +.button:active, .button.is-active { + --bulma-button-background-l-delta: var(--bulma-button-active-background-l-delta); + --bulma-button-border-l-delta: var(--bulma-button-active-border-l-delta); + --bulma-button-outer-shadow-a: 0; +} +.button[disabled], fieldset[disabled] .button { + background-color: var(--bulma-button-disabled-background-color); + border-color: var(--bulma-button-disabled-border-color); + box-shadow: var(--bulma-button-disabled-shadow); + opacity: var(--bulma-button-disabled-opacity); +} +.button.is-white { + --bulma-button-h: var(--bulma-white-h); + --bulma-button-s: var(--bulma-white-s); + --bulma-button-l: var(--bulma-white-l); + --bulma-button-background-l: var(--bulma-white-l); + --bulma-button-border-l: var(--bulma-white-l); + --bulma-button-border-width: 0px; + --bulma-button-color-l: var(--bulma-white-invert-l); + --bulma-button-outer-shadow-a: 0; +} +.button.is-white:focus-visible, .button.is-white.is-focused { + --bulma-button-border-width: 1px; +} +.button.is-white.is-soft { + --bulma-button-background-l: var(--bulma-soft-l); + --bulma-button-color-l: var(--bulma-soft-invert-l); +} +.button.is-white.is-bold { + --bulma-button-background-l: var(--bulma-bold-l); + --bulma-button-color-l: var(--bulma-bold-invert-l); +} +.button.is-white[disabled], fieldset[disabled] .button.is-white { + background-color: var(--bulma-white); + border-color: var(--bulma-white); + box-shadow: none; +} +.button.is-black { + --bulma-button-h: var(--bulma-black-h); + --bulma-button-s: var(--bulma-black-s); + --bulma-button-l: var(--bulma-black-l); + --bulma-button-background-l: var(--bulma-black-l); + --bulma-button-border-l: var(--bulma-black-l); + --bulma-button-border-width: 0px; + --bulma-button-color-l: var(--bulma-black-invert-l); + --bulma-button-outer-shadow-a: 0; +} +.button.is-black:focus-visible, .button.is-black.is-focused { + --bulma-button-border-width: 1px; +} +.button.is-black.is-soft { + --bulma-button-background-l: var(--bulma-soft-l); + --bulma-button-color-l: var(--bulma-soft-invert-l); +} +.button.is-black.is-bold { + --bulma-button-background-l: var(--bulma-bold-l); + --bulma-button-color-l: var(--bulma-bold-invert-l); +} +.button.is-black[disabled], fieldset[disabled] .button.is-black { + background-color: var(--bulma-black); + border-color: var(--bulma-black); + box-shadow: none; +} +.button.is-light { + --bulma-button-h: var(--bulma-light-h); + --bulma-button-s: var(--bulma-light-s); + --bulma-button-l: var(--bulma-light-l); + --bulma-button-background-l: var(--bulma-light-l); + --bulma-button-border-l: var(--bulma-light-l); + --bulma-button-border-width: 0px; + --bulma-button-color-l: var(--bulma-light-invert-l); + --bulma-button-outer-shadow-a: 0; +} +.button.is-light:focus-visible, .button.is-light.is-focused { + --bulma-button-border-width: 1px; +} +.button.is-light.is-soft { + --bulma-button-background-l: var(--bulma-soft-l); + --bulma-button-color-l: var(--bulma-soft-invert-l); +} +.button.is-light.is-bold { + --bulma-button-background-l: var(--bulma-bold-l); + --bulma-button-color-l: var(--bulma-bold-invert-l); +} +.button.is-light[disabled], fieldset[disabled] .button.is-light { + background-color: var(--bulma-light); + border-color: var(--bulma-light); + box-shadow: none; +} +.button.is-dark { + --bulma-button-h: var(--bulma-dark-h); + --bulma-button-s: var(--bulma-dark-s); + --bulma-button-l: var(--bulma-dark-l); + --bulma-button-background-l: var(--bulma-dark-l); + --bulma-button-border-l: var(--bulma-dark-l); + --bulma-button-border-width: 0px; + --bulma-button-color-l: var(--bulma-dark-invert-l); + --bulma-button-outer-shadow-a: 0; +} +.button.is-dark:focus-visible, .button.is-dark.is-focused { + --bulma-button-border-width: 1px; +} +.button.is-dark.is-soft { + --bulma-button-background-l: var(--bulma-soft-l); + --bulma-button-color-l: var(--bulma-soft-invert-l); +} +.button.is-dark.is-bold { + --bulma-button-background-l: var(--bulma-bold-l); + --bulma-button-color-l: var(--bulma-bold-invert-l); +} +.button.is-dark[disabled], fieldset[disabled] .button.is-dark { + background-color: var(--bulma-dark); + border-color: var(--bulma-dark); + box-shadow: none; +} +.button.is-text { + --bulma-button-h: var(--bulma-text-h); + --bulma-button-s: var(--bulma-text-s); + --bulma-button-l: var(--bulma-text-l); + --bulma-button-background-l: var(--bulma-text-l); + --bulma-button-border-l: var(--bulma-text-l); + --bulma-button-border-width: 0px; + --bulma-button-color-l: var(--bulma-text-invert-l); + --bulma-button-outer-shadow-a: 0; +} +.button.is-text:focus-visible, .button.is-text.is-focused { + --bulma-button-border-width: 1px; +} +.button.is-text.is-light { + --bulma-button-background-l: var(--bulma-light-l); + --bulma-button-color-l: var(--bulma-text-light-invert-l); +} +.button.is-text.is-dark { + --bulma-button-background-l: var(--bulma-dark-l); + --bulma-button-color-l: var(--bulma-text-dark-invert-l); +} +.button.is-text.is-soft { + --bulma-button-background-l: var(--bulma-soft-l); + --bulma-button-color-l: var(--bulma-soft-invert-l); +} +.button.is-text.is-bold { + --bulma-button-background-l: var(--bulma-bold-l); + --bulma-button-color-l: var(--bulma-bold-invert-l); +} +.button.is-text[disabled], fieldset[disabled] .button.is-text { + background-color: var(--bulma-text); + border-color: var(--bulma-text); + box-shadow: none; +} +.button.is-primary { + --bulma-button-h: var(--bulma-primary-h); + --bulma-button-s: var(--bulma-primary-s); + --bulma-button-l: var(--bulma-primary-l); + --bulma-button-background-l: var(--bulma-primary-l); + --bulma-button-border-l: var(--bulma-primary-l); + --bulma-button-border-width: 0px; + --bulma-button-color-l: var(--bulma-primary-invert-l); + --bulma-button-outer-shadow-a: 0; +} +.button.is-primary:focus-visible, .button.is-primary.is-focused { + --bulma-button-border-width: 1px; +} +.button.is-primary.is-light { + --bulma-button-background-l: var(--bulma-light-l); + --bulma-button-color-l: var(--bulma-primary-light-invert-l); +} +.button.is-primary.is-dark { + --bulma-button-background-l: var(--bulma-dark-l); + --bulma-button-color-l: var(--bulma-primary-dark-invert-l); +} +.button.is-primary.is-soft { + --bulma-button-background-l: var(--bulma-soft-l); + --bulma-button-color-l: var(--bulma-soft-invert-l); +} +.button.is-primary.is-bold { + --bulma-button-background-l: var(--bulma-bold-l); + --bulma-button-color-l: var(--bulma-bold-invert-l); +} +.button.is-primary[disabled], fieldset[disabled] .button.is-primary { + background-color: var(--bulma-primary); + border-color: var(--bulma-primary); + box-shadow: none; +} +.button.is-link { + --bulma-button-h: var(--bulma-link-h); + --bulma-button-s: var(--bulma-link-s); + --bulma-button-l: var(--bulma-link-l); + --bulma-button-background-l: var(--bulma-link-l); + --bulma-button-border-l: var(--bulma-link-l); + --bulma-button-border-width: 0px; + --bulma-button-color-l: var(--bulma-link-invert-l); + --bulma-button-outer-shadow-a: 0; +} +.button.is-link:focus-visible, .button.is-link.is-focused { + --bulma-button-border-width: 1px; +} +.button.is-link.is-light { + --bulma-button-background-l: var(--bulma-light-l); + --bulma-button-color-l: var(--bulma-link-light-invert-l); +} +.button.is-link.is-dark { + --bulma-button-background-l: var(--bulma-dark-l); + --bulma-button-color-l: var(--bulma-link-dark-invert-l); +} +.button.is-link.is-soft { + --bulma-button-background-l: var(--bulma-soft-l); + --bulma-button-color-l: var(--bulma-soft-invert-l); +} +.button.is-link.is-bold { + --bulma-button-background-l: var(--bulma-bold-l); + --bulma-button-color-l: var(--bulma-bold-invert-l); +} +.button.is-link[disabled], fieldset[disabled] .button.is-link { + background-color: var(--bulma-link); + border-color: var(--bulma-link); + box-shadow: none; +} +.button.is-info { + --bulma-button-h: var(--bulma-info-h); + --bulma-button-s: var(--bulma-info-s); + --bulma-button-l: var(--bulma-info-l); + --bulma-button-background-l: var(--bulma-info-l); + --bulma-button-border-l: var(--bulma-info-l); + --bulma-button-border-width: 0px; + --bulma-button-color-l: var(--bulma-info-invert-l); + --bulma-button-outer-shadow-a: 0; +} +.button.is-info:focus-visible, .button.is-info.is-focused { + --bulma-button-border-width: 1px; +} +.button.is-info.is-light { + --bulma-button-background-l: var(--bulma-light-l); + --bulma-button-color-l: var(--bulma-info-light-invert-l); +} +.button.is-info.is-dark { + --bulma-button-background-l: var(--bulma-dark-l); + --bulma-button-color-l: var(--bulma-info-dark-invert-l); +} +.button.is-info.is-soft { + --bulma-button-background-l: var(--bulma-soft-l); + --bulma-button-color-l: var(--bulma-soft-invert-l); +} +.button.is-info.is-bold { + --bulma-button-background-l: var(--bulma-bold-l); + --bulma-button-color-l: var(--bulma-bold-invert-l); +} +.button.is-info[disabled], fieldset[disabled] .button.is-info { + background-color: var(--bulma-info); + border-color: var(--bulma-info); + box-shadow: none; +} +.button.is-success { + --bulma-button-h: var(--bulma-success-h); + --bulma-button-s: var(--bulma-success-s); + --bulma-button-l: var(--bulma-success-l); + --bulma-button-background-l: var(--bulma-success-l); + --bulma-button-border-l: var(--bulma-success-l); + --bulma-button-border-width: 0px; + --bulma-button-color-l: var(--bulma-success-invert-l); + --bulma-button-outer-shadow-a: 0; +} +.button.is-success:focus-visible, .button.is-success.is-focused { + --bulma-button-border-width: 1px; +} +.button.is-success.is-light { + --bulma-button-background-l: var(--bulma-light-l); + --bulma-button-color-l: var(--bulma-success-light-invert-l); +} +.button.is-success.is-dark { + --bulma-button-background-l: var(--bulma-dark-l); + --bulma-button-color-l: var(--bulma-success-dark-invert-l); +} +.button.is-success.is-soft { + --bulma-button-background-l: var(--bulma-soft-l); + --bulma-button-color-l: var(--bulma-soft-invert-l); +} +.button.is-success.is-bold { + --bulma-button-background-l: var(--bulma-bold-l); + --bulma-button-color-l: var(--bulma-bold-invert-l); +} +.button.is-success[disabled], fieldset[disabled] .button.is-success { + background-color: var(--bulma-success); + border-color: var(--bulma-success); + box-shadow: none; +} +.button.is-warning { + --bulma-button-h: var(--bulma-warning-h); + --bulma-button-s: var(--bulma-warning-s); + --bulma-button-l: var(--bulma-warning-l); + --bulma-button-background-l: var(--bulma-warning-l); + --bulma-button-border-l: var(--bulma-warning-l); + --bulma-button-border-width: 0px; + --bulma-button-color-l: var(--bulma-warning-invert-l); + --bulma-button-outer-shadow-a: 0; +} +.button.is-warning:focus-visible, .button.is-warning.is-focused { + --bulma-button-border-width: 1px; +} +.button.is-warning.is-light { + --bulma-button-background-l: var(--bulma-light-l); + --bulma-button-color-l: var(--bulma-warning-light-invert-l); +} +.button.is-warning.is-dark { + --bulma-button-background-l: var(--bulma-dark-l); + --bulma-button-color-l: var(--bulma-warning-dark-invert-l); +} +.button.is-warning.is-soft { + --bulma-button-background-l: var(--bulma-soft-l); + --bulma-button-color-l: var(--bulma-soft-invert-l); +} +.button.is-warning.is-bold { + --bulma-button-background-l: var(--bulma-bold-l); + --bulma-button-color-l: var(--bulma-bold-invert-l); +} +.button.is-warning[disabled], fieldset[disabled] .button.is-warning { + background-color: var(--bulma-warning); + border-color: var(--bulma-warning); + box-shadow: none; +} +.button.is-danger { + --bulma-button-h: var(--bulma-danger-h); + --bulma-button-s: var(--bulma-danger-s); + --bulma-button-l: var(--bulma-danger-l); + --bulma-button-background-l: var(--bulma-danger-l); + --bulma-button-border-l: var(--bulma-danger-l); + --bulma-button-border-width: 0px; + --bulma-button-color-l: var(--bulma-danger-invert-l); + --bulma-button-outer-shadow-a: 0; +} +.button.is-danger:focus-visible, .button.is-danger.is-focused { + --bulma-button-border-width: 1px; +} +.button.is-danger.is-light { + --bulma-button-background-l: var(--bulma-light-l); + --bulma-button-color-l: var(--bulma-danger-light-invert-l); +} +.button.is-danger.is-dark { + --bulma-button-background-l: var(--bulma-dark-l); + --bulma-button-color-l: var(--bulma-danger-dark-invert-l); +} +.button.is-danger.is-soft { + --bulma-button-background-l: var(--bulma-soft-l); + --bulma-button-color-l: var(--bulma-soft-invert-l); +} +.button.is-danger.is-bold { + --bulma-button-background-l: var(--bulma-bold-l); + --bulma-button-color-l: var(--bulma-bold-invert-l); +} +.button.is-danger[disabled], fieldset[disabled] .button.is-danger { + background-color: var(--bulma-danger); + border-color: var(--bulma-danger); + box-shadow: none; +} +.button.is-outlined { + --bulma-button-border-width: max(1px, 0.0625em); + background-color: transparent; + border-color: hsl(var(--bulma-button-h), var(--bulma-button-s), var(--bulma-button-l)); + color: hsl(var(--bulma-button-h), var(--bulma-button-s), var(--bulma-button-l)); +} +.button.is-outlined:hover { + --bulma-button-border-width: max(2px, 0.125em); + --bulma-button-outer-shadow-alpha: 1; +} +.button.is-outlined[disabled], fieldset[disabled] .button.is-outlined { + background-color: transparent; + box-shadow: none; +} +.button.is-inverted { + background-color: hsl(var(--bulma-button-h), var(--bulma-button-s), calc(var(--bulma-button-color-l) + var(--bulma-button-background-l-delta))); + color: hsl(var(--bulma-button-h), var(--bulma-button-s), var(--bulma-button-background-l)); +} +.button.is-text { + background-color: transparent; + border-color: transparent; + color: var(--bulma-button-text-color); + text-decoration: var(--bulma-button-text-decoration); +} +.button.is-text:hover, .button.is-text.is-hovered { + background-color: var(--bulma-button-text-hover-background-color); + color: var(--bulma-button-text-hover-color); +} +.button.is-text:active, .button.is-text.is-active { + color: var(--bulma-button-text-hover-color); +} +.button.is-text[disabled], fieldset[disabled] .button.is-text { + background-color: transparent; + border-color: transparent; + box-shadow: none; +} +.button.is-ghost { + background: var(--bulma-button-ghost-background); + border-color: var(--bulma-button-ghost-border-color); + box-shadow: none; + color: var(--bulma-button-ghost-color); + text-decoration: var(--bulma-button-ghost-decoration); +} +.button.is-ghost:hover, .button.is-ghost.is-hovered { + color: var(--bulma-button-ghost-hover-color); + text-decoration: var(--bulma-button-ghost-hover-decoration); +} +.button.is-small { + --bulma-control-size: var(--bulma-size-small); + --bulma-control-radius: var(--bulma-radius-small); +} +.button.is-normal { + --bulma-control-size: var(--bulma-size-normal); + --bulma-control-radius: var(--bulma-radius); +} +.button.is-medium { + --bulma-control-size: var(--bulma-size-medium); + --bulma-control-radius: var(--bulma-radius-medium); +} +.button.is-large { + --bulma-control-size: var(--bulma-size-large); + --bulma-control-radius: var(--bulma-radius-medium); +} +.button.is-fullwidth { + display: flex; + width: 100%; +} +.button.is-loading { + box-shadow: none; + color: transparent !important; + pointer-events: none; +} +.button.is-loading::after { + position: absolute; + left: calc(50% - 1em * 0.5); + top: calc(50% - 1em * 0.5); + position: absolute !important; +} +.button.is-static { + background-color: var(--bulma-button-static-background-color); + border-color: var(--bulma-button-static-border-color); + color: var(--bulma-button-static-color); + box-shadow: none; + pointer-events: none; +} +.button.is-rounded { + border-radius: var(--bulma-radius-rounded); + padding-left: calc(var(--bulma-button-padding-horizontal) + 0.25em - var(--bulma-button-border-width)); + padding-right: calc(var(--bulma-button-padding-horizontal) + 0.25em - var(--bulma-button-border-width)); +} + +.buttons { + align-items: center; + display: flex; + flex-wrap: wrap; + gap: 0.75rem; + justify-content: flex-start; +} +.buttons.are-small { + --bulma-control-size: var(--bulma-size-small); + --bulma-control-radius: var(--bulma-radius-small); +} +.buttons.are-medium { + --bulma-control-size: var(--bulma-size-medium); + --bulma-control-radius: var(--bulma-radius-medium); +} +.buttons.are-large { + --bulma-control-size: var(--bulma-size-large); + --bulma-control-radius: var(--bulma-radius-large); +} +.buttons.has-addons { + gap: 0; +} +.buttons.has-addons .button:not(:first-child) { + border-end-start-radius: 0; + border-start-start-radius: 0; +} +.buttons.has-addons .button:not(:last-child) { + border-end-end-radius: 0; + border-start-end-radius: 0; + margin-inline-end: -1px; +} +.buttons.has-addons .button:hover, .buttons.has-addons .button.is-hovered { + z-index: 2; +} +.buttons.has-addons .button:focus, .buttons.has-addons .button.is-focused, .buttons.has-addons .button:active, .buttons.has-addons .button.is-active, .buttons.has-addons .button.is-selected { + z-index: 3; +} +.buttons.has-addons .button:focus:hover, .buttons.has-addons .button.is-focused:hover, .buttons.has-addons .button:active:hover, .buttons.has-addons .button.is-active:hover, .buttons.has-addons .button.is-selected:hover { + z-index: 4; +} +.buttons.has-addons .button.is-expanded { + flex-grow: 1; + flex-shrink: 1; +} +.buttons.is-centered { + justify-content: center; +} +.buttons.is-right { + justify-content: flex-end; +} + +@media screen and (max-width: 768px) { + .button.is-responsive.is-small { + font-size: calc(var(--bulma-size-small) * 0.75); + } + .button.is-responsive, + .button.is-responsive.is-normal { + font-size: calc(var(--bulma-size-small) * 0.875); + } + .button.is-responsive.is-medium { + font-size: var(--bulma-size-small); + } + .button.is-responsive.is-large { + font-size: var(--bulma-size-normal); + } +} +@media screen and (min-width: 769px) and (max-width: 1023px) { + .button.is-responsive.is-small { + font-size: calc(var(--bulma-size-small) * 0.875); + } + .button.is-responsive, + .button.is-responsive.is-normal { + font-size: var(--bulma-size-small); + } + .button.is-responsive.is-medium { + font-size: var(--bulma-size-normal); + } + .button.is-responsive.is-large { + font-size: var(--bulma-size-medium); + } +} +.content { + --bulma-content-heading-color: var(--bulma-text-strong); + --bulma-content-heading-weight: var(--bulma-weight-extrabold); + --bulma-content-heading-line-height: 1.125; + --bulma-content-block-margin-bottom: 1em; + --bulma-content-blockquote-background-color: var(--bulma-background); + --bulma-content-blockquote-border-left: 5px solid var(--bulma-border); + --bulma-content-blockquote-padding: 1.25em 1.5em; + --bulma-content-pre-padding: 1.25em 1.5em; + --bulma-content-table-cell-border: 1px solid var(--bulma-border); + --bulma-content-table-cell-border-width: 0 0 1px; + --bulma-content-table-cell-padding: 0.5em 0.75em; + --bulma-content-table-cell-heading-color: var(--bulma-text-strong); + --bulma-content-table-head-cell-border-width: 0 0 2px; + --bulma-content-table-head-cell-color: var(--bulma-text-strong); + --bulma-content-table-body-last-row-cell-border-bottom-width: 0; + --bulma-content-table-foot-cell-border-width: 2px 0 0; + --bulma-content-table-foot-cell-color: var(--bulma-text-strong); +} + +.content li + li { + margin-top: 0.25em; +} +.content p:not(:last-child), +.content dl:not(:last-child), +.content ol:not(:last-child), +.content ul:not(:last-child), +.content blockquote:not(:last-child), +.content pre:not(:last-child), +.content table:not(:last-child) { + margin-bottom: var(--bulma-content-block-margin-bottom); +} +.content h1, +.content h2, +.content h3, +.content h4, +.content h5, +.content h6 { + color: var(--bulma-content-heading-color); + font-weight: var(--bulma-content-heading-weight); + line-height: var(--bulma-content-heading-line-height); +} +.content h1 { + font-size: 2em; + margin-bottom: 0.5em; +} +.content h1:not(:first-child) { + margin-top: 1em; +} +.content h2 { + font-size: 1.75em; + margin-bottom: 0.5714em; +} +.content h2:not(:first-child) { + margin-top: 1.1428em; +} +.content h3 { + font-size: 1.5em; + margin-bottom: 0.6666em; +} +.content h3:not(:first-child) { + margin-top: 1.3333em; +} +.content h4 { + font-size: 1.25em; + margin-bottom: 0.8em; +} +.content h5 { + font-size: 1.125em; + margin-bottom: 0.8888em; +} +.content h6 { + font-size: 1em; + margin-bottom: 1em; +} +.content blockquote { + background-color: var(--bulma-content-blockquote-background-color); + border-inline-start: var(--bulma-content-blockquote-border-left); + padding: var(--bulma-content-blockquote-padding); +} +.content ol { + list-style-position: outside; + margin-inline-start: 2em; +} +.content ol:not(:first-child) { + margin-top: 1em; +} +.content ol:not([type]) { + list-style-type: decimal; +} +.content ol:not([type]).is-lower-alpha { + list-style-type: lower-alpha; +} +.content ol:not([type]).is-lower-roman { + list-style-type: lower-roman; +} +.content ol:not([type]).is-upper-alpha { + list-style-type: upper-alpha; +} +.content ol:not([type]).is-upper-roman { + list-style-type: upper-roman; +} +.content ul { + list-style: disc outside; + margin-inline-start: 2em; +} +.content ul:not(:first-child) { + margin-top: 1em; +} +.content ul ul { + list-style-type: circle; + margin-bottom: 0.25em; + margin-top: 0.25em; +} +.content ul ul ul { + list-style-type: square; +} +.content dd { + margin-inline-start: 2em; +} +.content figure:not([class]) { + margin-left: 2em; + margin-right: 2em; + text-align: center; +} +.content figure:not([class]):not(:first-child) { + margin-top: 2em; +} +.content figure:not([class]):not(:last-child) { + margin-bottom: 2em; +} +.content figure:not([class]) img { + display: inline-block; +} +.content figure:not([class]) figcaption { + font-style: italic; +} +.content pre { + -webkit-overflow-scrolling: touch; + overflow-x: auto; + padding: var(--bulma-content-pre-padding); + white-space: pre; + word-wrap: normal; +} +.content sup, +.content sub { + font-size: 75%; +} +.content table td, +.content table th { + border: var(--bulma-content-table-cell-border); + border-width: var(--bulma-content-table-cell-border-width); + padding: var(--bulma-content-table-cell-padding); + vertical-align: top; +} +.content table th { + color: var(--bulma-content-table-cell-heading-color); +} +.content table th:not([align]) { + text-align: inherit; +} +.content table thead td, +.content table thead th { + border-width: var(--bulma-content-table-head-cell-border-width); + color: var(--bulma-content-table-head-cell-color); +} +.content table tfoot td, +.content table tfoot th { + border-width: var(--bulma-content-table-foot-cell-border-width); + color: var(--bulma-content-table-foot-cell-color); +} +.content table tbody tr:last-child td, +.content table tbody tr:last-child th { + border-bottom-width: var(--bulma-content-table-body-last-row-cell-border-bottom-width); +} +.content .tabs li + li { + margin-top: 0; +} +.content.is-small { + font-size: var(--bulma-size-small); +} +.content.is-normal { + font-size: var(--bulma-size-normal); +} +.content.is-medium { + font-size: var(--bulma-size-medium); +} +.content.is-large { + font-size: var(--bulma-size-large); +} + +.delete { + --bulma-delete-dimensions: 1.25rem; + --bulma-delete-background-l: 0%; + --bulma-delete-background-alpha: 0.5; + --bulma-delete-color: var(--bulma-white); + appearance: none; + background-color: hsla(var(--bulma-scheme-h), var(--bulma-scheme-s), var(--bulma-delete-background-l), var(--bulma-delete-background-alpha)); + border: none; + border-radius: var(--bulma-radius-rounded); + cursor: pointer; + pointer-events: auto; + display: inline-flex; + flex-grow: 0; + flex-shrink: 0; + font-size: 1em; + height: var(--bulma-delete-dimensions); + max-height: var(--bulma-delete-dimensions); + max-width: var(--bulma-delete-dimensions); + min-height: var(--bulma-delete-dimensions); + min-width: var(--bulma-delete-dimensions); + outline: none; + position: relative; + vertical-align: top; + width: var(--bulma-delete-dimensions); +} +.delete::before, .delete::after { + background-color: var(--bulma-delete-color); + content: ""; + display: block; + left: 50%; + position: absolute; + top: 50%; + transform: translateX(-50%) translateY(-50%) rotate(45deg); + transform-origin: center center; +} +.delete::before { + height: 2px; + width: 50%; +} +.delete::after { + height: 50%; + width: 2px; +} +.delete:hover, .delete:focus { + --bulma-delete-background-alpha: 0.4; +} +.delete:active { + --bulma-delete-background-alpha: 0.5; +} +.delete.is-small { + --bulma-delete-dimensions: 1rem; +} +.delete.is-medium { + --bulma-delete-dimensions: 1.5rem; +} +.delete.is-large { + --bulma-delete-dimensions: 2rem; +} + +.icon, +.icon-text { + --bulma-icon-dimensions: 1.5rem; + --bulma-icon-dimensions-small: 1rem; + --bulma-icon-dimensions-medium: 2rem; + --bulma-icon-dimensions-large: 3rem; + --bulma-icon-text-spacing: 0.25em; +} + +.icon { + align-items: center; + display: inline-flex; + flex-shrink: 0; + justify-content: center; + height: var(--bulma-icon-dimensions); + transition-duration: var(--bulma-duration); + transition-property: color; + width: var(--bulma-icon-dimensions); +} +.icon.is-small { + height: var(--bulma-icon-dimensions-small); + width: var(--bulma-icon-dimensions-small); +} +.icon.is-medium { + height: var(--bulma-icon-dimensions-medium); + width: var(--bulma-icon-dimensions-medium); +} +.icon.is-large { + height: var(--bulma-icon-dimensions-large); + width: var(--bulma-icon-dimensions-large); +} + +.icon-text { + align-items: flex-start; + color: inherit; + display: inline-flex; + flex-wrap: wrap; + gap: var(--bulma-icon-text-spacing); + line-height: var(--bulma-icon-dimensions); + vertical-align: top; +} +.icon-text .icon { + flex-grow: 0; + flex-shrink: 0; +} + +div.icon-text { + display: flex; +} + +.image { + display: block; + position: relative; +} +.image img { + display: block; + height: auto; + width: 100%; +} +.image img.is-rounded { + border-radius: var(--bulma-radius-rounded); +} +.image.is-fullwidth { + width: 100%; +} +.image.is-square img, +.image.is-square .has-ratio { + bottom: 0; + left: 0; + position: absolute; + right: 0; + top: 0; + height: 100%; + width: 100%; +} +.image.is-square { + aspect-ratio: 1; +} +.image.is-1by1 { + aspect-ratio: 1/1; +} +.image.is-1by1 img, +.image.is-1by1 .has-ratio { + bottom: 0; + left: 0; + position: absolute; + right: 0; + top: 0; + height: 100%; + width: 100%; +} +.image.is-5by4 { + aspect-ratio: 5/4; +} +.image.is-5by4 img, +.image.is-5by4 .has-ratio { + bottom: 0; + left: 0; + position: absolute; + right: 0; + top: 0; + height: 100%; + width: 100%; +} +.image.is-4by3 { + aspect-ratio: 4/3; +} +.image.is-4by3 img, +.image.is-4by3 .has-ratio { + bottom: 0; + left: 0; + position: absolute; + right: 0; + top: 0; + height: 100%; + width: 100%; +} +.image.is-3by2 { + aspect-ratio: 3/2; +} +.image.is-3by2 img, +.image.is-3by2 .has-ratio { + bottom: 0; + left: 0; + position: absolute; + right: 0; + top: 0; + height: 100%; + width: 100%; +} +.image.is-5by3 { + aspect-ratio: 5/3; +} +.image.is-5by3 img, +.image.is-5by3 .has-ratio { + bottom: 0; + left: 0; + position: absolute; + right: 0; + top: 0; + height: 100%; + width: 100%; +} +.image.is-16by9 { + aspect-ratio: 16/9; +} +.image.is-16by9 img, +.image.is-16by9 .has-ratio { + bottom: 0; + left: 0; + position: absolute; + right: 0; + top: 0; + height: 100%; + width: 100%; +} +.image.is-2by1 { + aspect-ratio: 2/1; +} +.image.is-2by1 img, +.image.is-2by1 .has-ratio { + bottom: 0; + left: 0; + position: absolute; + right: 0; + top: 0; + height: 100%; + width: 100%; +} +.image.is-3by1 { + aspect-ratio: 3/1; +} +.image.is-3by1 img, +.image.is-3by1 .has-ratio { + bottom: 0; + left: 0; + position: absolute; + right: 0; + top: 0; + height: 100%; + width: 100%; +} +.image.is-4by5 { + aspect-ratio: 4/5; +} +.image.is-4by5 img, +.image.is-4by5 .has-ratio { + bottom: 0; + left: 0; + position: absolute; + right: 0; + top: 0; + height: 100%; + width: 100%; +} +.image.is-3by4 { + aspect-ratio: 3/4; +} +.image.is-3by4 img, +.image.is-3by4 .has-ratio { + bottom: 0; + left: 0; + position: absolute; + right: 0; + top: 0; + height: 100%; + width: 100%; +} +.image.is-2by3 { + aspect-ratio: 2/3; +} +.image.is-2by3 img, +.image.is-2by3 .has-ratio { + bottom: 0; + left: 0; + position: absolute; + right: 0; + top: 0; + height: 100%; + width: 100%; +} +.image.is-3by5 { + aspect-ratio: 3/5; +} +.image.is-3by5 img, +.image.is-3by5 .has-ratio { + bottom: 0; + left: 0; + position: absolute; + right: 0; + top: 0; + height: 100%; + width: 100%; +} +.image.is-9by16 { + aspect-ratio: 9/16; +} +.image.is-9by16 img, +.image.is-9by16 .has-ratio { + bottom: 0; + left: 0; + position: absolute; + right: 0; + top: 0; + height: 100%; + width: 100%; +} +.image.is-1by2 { + aspect-ratio: 1/2; +} +.image.is-1by2 img, +.image.is-1by2 .has-ratio { + bottom: 0; + left: 0; + position: absolute; + right: 0; + top: 0; + height: 100%; + width: 100%; +} +.image.is-1by3 { + aspect-ratio: 1/3; +} +.image.is-1by3 img, +.image.is-1by3 .has-ratio { + bottom: 0; + left: 0; + position: absolute; + right: 0; + top: 0; + height: 100%; + width: 100%; +} +.image.is-16x16 { + height: 16px; + width: 16px; +} +.image.is-24x24 { + height: 24px; + width: 24px; +} +.image.is-32x32 { + height: 32px; + width: 32px; +} +.image.is-48x48 { + height: 48px; + width: 48px; +} +.image.is-64x64 { + height: 64px; + width: 64px; +} +.image.is-96x96 { + height: 96px; + width: 96px; +} +.image.is-128x128 { + height: 128px; + width: 128px; +} + +.loader { + animation: spinAround 500ms infinite linear; + border: 2px solid var(--bulma-border); + border-radius: var(--bulma-radius-rounded); + border-right-color: transparent; + border-top-color: transparent; + content: ""; + display: block; + height: 1em; + position: relative; + width: 1em; +} + +.notification { + --bulma-notification-h: var(--bulma-scheme-h); + --bulma-notification-s: var(--bulma-scheme-s); + --bulma-notification-background-l: var(--bulma-background-l); + --bulma-notification-color-l: var(--bulma-text-strong-l); + --bulma-notification-code-background-color: var(--bulma-scheme-main); + --bulma-notification-radius: var(--bulma-radius); + --bulma-notification-padding: 1.375em 1.5em; +} + +.notification { + background-color: hsl(var(--bulma-notification-h), var(--bulma-notification-s), var(--bulma-notification-background-l)); + border-radius: var(--bulma-notification-radius); + color: hsl(var(--bulma-notification-h), var(--bulma-notification-s), var(--bulma-notification-color-l)); + padding: var(--bulma-notification-padding); + position: relative; +} +.notification a:not(.button):not(.dropdown-item) { + color: currentColor; + text-decoration: underline; +} +.notification strong { + color: currentColor; +} +.notification code, +.notification pre { + background: var(--bulma-notification-code-background-color); +} +.notification pre code { + background: transparent; +} +.notification > .delete { + position: absolute; + inset-inline-end: 1rem; + top: 1rem; +} +.notification .title, +.notification .subtitle, +.notification .content { + color: currentColor; +} +.notification.is-white { + --bulma-notification-h: var(--bulma-white-h); + --bulma-notification-s: var(--bulma-white-s); + --bulma-notification-background-l: var(--bulma-white-l); + --bulma-notification-color-l: var(--bulma-white-invert-l); +} +.notification.is-white.is-light { + --bulma-notification-background-l: 90%; + --bulma-notification-color-l: var(--bulma-white-light-invert-l); +} +.notification.is-white.is-dark { + --bulma-notification-background-l: 20%; + --bulma-notification-color-l: var(--bulma-white-dark-invert-l); +} +.notification.is-black { + --bulma-notification-h: var(--bulma-black-h); + --bulma-notification-s: var(--bulma-black-s); + --bulma-notification-background-l: var(--bulma-black-l); + --bulma-notification-color-l: var(--bulma-black-invert-l); +} +.notification.is-black.is-light { + --bulma-notification-background-l: 90%; + --bulma-notification-color-l: var(--bulma-black-light-invert-l); +} +.notification.is-black.is-dark { + --bulma-notification-background-l: 20%; + --bulma-notification-color-l: var(--bulma-black-dark-invert-l); +} +.notification.is-light { + --bulma-notification-h: var(--bulma-light-h); + --bulma-notification-s: var(--bulma-light-s); + --bulma-notification-background-l: var(--bulma-light-l); + --bulma-notification-color-l: var(--bulma-light-invert-l); +} +.notification.is-light.is-light { + --bulma-notification-background-l: 90%; + --bulma-notification-color-l: var(--bulma-light-light-invert-l); +} +.notification.is-light.is-dark { + --bulma-notification-background-l: 20%; + --bulma-notification-color-l: var(--bulma-light-dark-invert-l); +} +.notification.is-dark { + --bulma-notification-h: var(--bulma-dark-h); + --bulma-notification-s: var(--bulma-dark-s); + --bulma-notification-background-l: var(--bulma-dark-l); + --bulma-notification-color-l: var(--bulma-dark-invert-l); +} +.notification.is-dark.is-light { + --bulma-notification-background-l: 90%; + --bulma-notification-color-l: var(--bulma-dark-light-invert-l); +} +.notification.is-dark.is-dark { + --bulma-notification-background-l: 20%; + --bulma-notification-color-l: var(--bulma-dark-dark-invert-l); +} +.notification.is-text { + --bulma-notification-h: var(--bulma-text-h); + --bulma-notification-s: var(--bulma-text-s); + --bulma-notification-background-l: var(--bulma-text-l); + --bulma-notification-color-l: var(--bulma-text-invert-l); +} +.notification.is-text.is-light { + --bulma-notification-background-l: 90%; + --bulma-notification-color-l: var(--bulma-text-light-invert-l); +} +.notification.is-text.is-dark { + --bulma-notification-background-l: 20%; + --bulma-notification-color-l: var(--bulma-text-dark-invert-l); +} +.notification.is-primary { + --bulma-notification-h: var(--bulma-primary-h); + --bulma-notification-s: var(--bulma-primary-s); + --bulma-notification-background-l: var(--bulma-primary-l); + --bulma-notification-color-l: var(--bulma-primary-invert-l); +} +.notification.is-primary.is-light { + --bulma-notification-background-l: 90%; + --bulma-notification-color-l: var(--bulma-primary-light-invert-l); +} +.notification.is-primary.is-dark { + --bulma-notification-background-l: 20%; + --bulma-notification-color-l: var(--bulma-primary-dark-invert-l); +} +.notification.is-link { + --bulma-notification-h: var(--bulma-link-h); + --bulma-notification-s: var(--bulma-link-s); + --bulma-notification-background-l: var(--bulma-link-l); + --bulma-notification-color-l: var(--bulma-link-invert-l); +} +.notification.is-link.is-light { + --bulma-notification-background-l: 90%; + --bulma-notification-color-l: var(--bulma-link-light-invert-l); +} +.notification.is-link.is-dark { + --bulma-notification-background-l: 20%; + --bulma-notification-color-l: var(--bulma-link-dark-invert-l); +} +.notification.is-info { + --bulma-notification-h: var(--bulma-info-h); + --bulma-notification-s: var(--bulma-info-s); + --bulma-notification-background-l: var(--bulma-info-l); + --bulma-notification-color-l: var(--bulma-info-invert-l); +} +.notification.is-info.is-light { + --bulma-notification-background-l: 90%; + --bulma-notification-color-l: var(--bulma-info-light-invert-l); +} +.notification.is-info.is-dark { + --bulma-notification-background-l: 20%; + --bulma-notification-color-l: var(--bulma-info-dark-invert-l); +} +.notification.is-success { + --bulma-notification-h: var(--bulma-success-h); + --bulma-notification-s: var(--bulma-success-s); + --bulma-notification-background-l: var(--bulma-success-l); + --bulma-notification-color-l: var(--bulma-success-invert-l); +} +.notification.is-success.is-light { + --bulma-notification-background-l: 90%; + --bulma-notification-color-l: var(--bulma-success-light-invert-l); +} +.notification.is-success.is-dark { + --bulma-notification-background-l: 20%; + --bulma-notification-color-l: var(--bulma-success-dark-invert-l); +} +.notification.is-warning { + --bulma-notification-h: var(--bulma-warning-h); + --bulma-notification-s: var(--bulma-warning-s); + --bulma-notification-background-l: var(--bulma-warning-l); + --bulma-notification-color-l: var(--bulma-warning-invert-l); +} +.notification.is-warning.is-light { + --bulma-notification-background-l: 90%; + --bulma-notification-color-l: var(--bulma-warning-light-invert-l); +} +.notification.is-warning.is-dark { + --bulma-notification-background-l: 20%; + --bulma-notification-color-l: var(--bulma-warning-dark-invert-l); +} +.notification.is-danger { + --bulma-notification-h: var(--bulma-danger-h); + --bulma-notification-s: var(--bulma-danger-s); + --bulma-notification-background-l: var(--bulma-danger-l); + --bulma-notification-color-l: var(--bulma-danger-invert-l); +} +.notification.is-danger.is-light { + --bulma-notification-background-l: 90%; + --bulma-notification-color-l: var(--bulma-danger-light-invert-l); +} +.notification.is-danger.is-dark { + --bulma-notification-background-l: 20%; + --bulma-notification-color-l: var(--bulma-danger-dark-invert-l); +} + +.progress { + --bulma-progress-border-radius: var(--bulma-radius-rounded); + --bulma-progress-bar-background-color: var(--bulma-border-weak); + --bulma-progress-value-background-color: var(--bulma-text); + --bulma-progress-indeterminate-duration: 1.5s; +} + +.progress { + appearance: none; + border: none; + border-radius: var(--bulma-progress-border-radius); + display: block; + height: var(--bulma-size-normal); + overflow: hidden; + padding: 0; + width: 100%; +} +.progress::-webkit-progress-bar { + background-color: var(--bulma-progress-bar-background-color); +} +.progress::-webkit-progress-value { + background-color: var(--bulma-progress-value-background-color); +} +.progress::-moz-progress-bar { + background-color: var(--bulma-progress-value-background-color); +} +.progress::-ms-fill { + background-color: var(--bulma-progress-value-background-color); + border: none; +} +.progress.is-white { + --bulma-progress-value-background-color: var(--bulma-white); +} +.progress.is-black { + --bulma-progress-value-background-color: var(--bulma-black); +} +.progress.is-light { + --bulma-progress-value-background-color: var(--bulma-light); +} +.progress.is-dark { + --bulma-progress-value-background-color: var(--bulma-dark); +} +.progress.is-text { + --bulma-progress-value-background-color: var(--bulma-text); +} +.progress.is-primary { + --bulma-progress-value-background-color: var(--bulma-primary); +} +.progress.is-link { + --bulma-progress-value-background-color: var(--bulma-link); +} +.progress.is-info { + --bulma-progress-value-background-color: var(--bulma-info); +} +.progress.is-success { + --bulma-progress-value-background-color: var(--bulma-success); +} +.progress.is-warning { + --bulma-progress-value-background-color: var(--bulma-warning); +} +.progress.is-danger { + --bulma-progress-value-background-color: var(--bulma-danger); +} +.progress:indeterminate { + animation-duration: var(--bulma-progress-indeterminate-duration); + animation-iteration-count: infinite; + animation-name: moveIndeterminate; + animation-timing-function: linear; + background-color: var(--bulma-progress-bar-background-color); + background-image: linear-gradient(to right, var(--bulma-progress-value-background-color) 30%, var(--bulma-progress-bar-background-color) 30%); + background-position: top left; + background-repeat: no-repeat; + background-size: 150% 150%; +} +.progress:indeterminate::-webkit-progress-bar { + background-color: transparent; +} +.progress:indeterminate::-moz-progress-bar { + background-color: transparent; +} +.progress:indeterminate::-ms-fill { + animation-name: none; +} +.progress.is-small { + height: var(--bulma-size-small); +} +.progress.is-medium { + height: var(--bulma-size-medium); +} +.progress.is-large { + height: var(--bulma-size-large); +} + +@keyframes moveIndeterminate { + from { + background-position: 200% 0; + } + to { + background-position: -200% 0; + } +} +.table { + --bulma-table-color: var(--bulma-text-strong); + --bulma-table-background-color: var(--bulma-scheme-main); + --bulma-table-cell-border-color: var(--bulma-border); + --bulma-table-cell-border-style: solid; + --bulma-table-cell-border-width: 0 0 1px; + --bulma-table-cell-padding: 0.5em 0.75em; + --bulma-table-cell-heading-color: var(--bulma-text-strong); + --bulma-table-cell-text-align: left; + --bulma-table-head-cell-border-width: 0 0 2px; + --bulma-table-head-cell-color: var(--bulma-text-strong); + --bulma-table-foot-cell-border-width: 2px 0 0; + --bulma-table-foot-cell-color: var(--bulma-text-strong); + --bulma-table-head-background-color: transparent; + --bulma-table-body-background-color: transparent; + --bulma-table-foot-background-color: transparent; + --bulma-table-row-hover-background-color: var(--bulma-scheme-main-bis); + --bulma-table-row-active-background-color: var(--bulma-primary); + --bulma-table-row-active-color: var(--bulma-primary-invert); + --bulma-table-striped-row-even-background-color: var(--bulma-scheme-main-bis); + --bulma-table-striped-row-even-hover-background-color: var(--bulma-scheme-main-ter); +} + +.table { + background-color: var(--bulma-table-background-color); + color: var(--bulma-table-color); +} +.table td, +.table th { + background-color: var(--bulma-table-cell-background-color); + border-color: var(--bulma-table-cell-border-color); + border-style: var(--bulma-table-cell-border-style); + border-width: var(--bulma-table-cell-border-width); + color: var(--bulma-table-color); + padding: var(--bulma-table-cell-padding); + vertical-align: top; +} +.table td.is-white, +.table th.is-white { + --bulma-table-color: var(--bulma-white-invert); + --bulma-table-cell-heading-color: var(--bulma-white-invert); + --bulma-table-cell-background-color: var(--bulma-white); + --bulma-table-cell-border-color: var(--bulma-white); +} +.table td.is-black, +.table th.is-black { + --bulma-table-color: var(--bulma-black-invert); + --bulma-table-cell-heading-color: var(--bulma-black-invert); + --bulma-table-cell-background-color: var(--bulma-black); + --bulma-table-cell-border-color: var(--bulma-black); +} +.table td.is-light, +.table th.is-light { + --bulma-table-color: var(--bulma-light-invert); + --bulma-table-cell-heading-color: var(--bulma-light-invert); + --bulma-table-cell-background-color: var(--bulma-light); + --bulma-table-cell-border-color: var(--bulma-light); +} +.table td.is-dark, +.table th.is-dark { + --bulma-table-color: var(--bulma-dark-invert); + --bulma-table-cell-heading-color: var(--bulma-dark-invert); + --bulma-table-cell-background-color: var(--bulma-dark); + --bulma-table-cell-border-color: var(--bulma-dark); +} +.table td.is-text, +.table th.is-text { + --bulma-table-color: var(--bulma-text-invert); + --bulma-table-cell-heading-color: var(--bulma-text-invert); + --bulma-table-cell-background-color: var(--bulma-text); + --bulma-table-cell-border-color: var(--bulma-text); +} +.table td.is-primary, +.table th.is-primary { + --bulma-table-color: var(--bulma-primary-invert); + --bulma-table-cell-heading-color: var(--bulma-primary-invert); + --bulma-table-cell-background-color: var(--bulma-primary); + --bulma-table-cell-border-color: var(--bulma-primary); +} +.table td.is-link, +.table th.is-link { + --bulma-table-color: var(--bulma-link-invert); + --bulma-table-cell-heading-color: var(--bulma-link-invert); + --bulma-table-cell-background-color: var(--bulma-link); + --bulma-table-cell-border-color: var(--bulma-link); +} +.table td.is-info, +.table th.is-info { + --bulma-table-color: var(--bulma-info-invert); + --bulma-table-cell-heading-color: var(--bulma-info-invert); + --bulma-table-cell-background-color: var(--bulma-info); + --bulma-table-cell-border-color: var(--bulma-info); +} +.table td.is-success, +.table th.is-success { + --bulma-table-color: var(--bulma-success-invert); + --bulma-table-cell-heading-color: var(--bulma-success-invert); + --bulma-table-cell-background-color: var(--bulma-success); + --bulma-table-cell-border-color: var(--bulma-success); +} +.table td.is-warning, +.table th.is-warning { + --bulma-table-color: var(--bulma-warning-invert); + --bulma-table-cell-heading-color: var(--bulma-warning-invert); + --bulma-table-cell-background-color: var(--bulma-warning); + --bulma-table-cell-border-color: var(--bulma-warning); +} +.table td.is-danger, +.table th.is-danger { + --bulma-table-color: var(--bulma-danger-invert); + --bulma-table-cell-heading-color: var(--bulma-danger-invert); + --bulma-table-cell-background-color: var(--bulma-danger); + --bulma-table-cell-border-color: var(--bulma-danger); +} +.table td.is-narrow, +.table th.is-narrow { + white-space: nowrap; + width: 1%; +} +.table td.is-selected, +.table th.is-selected { + background-color: var(--bulma-table-row-active-background-color); + color: var(--bulma-table-row-active-color); +} +.table td.is-selected a, +.table td.is-selected strong, +.table th.is-selected a, +.table th.is-selected strong { + color: currentColor; +} +.table td.is-vcentered, +.table th.is-vcentered { + vertical-align: middle; +} +.table th { + color: var(--bulma-table-cell-heading-color); +} +.table th:not([align]) { + text-align: var(--bulma-table-cell-text-align); +} +.table tr.is-selected { + background-color: var(--bulma-table-row-active-background-color); + color: var(--bulma-table-row-active-color); +} +.table tr.is-selected a, +.table tr.is-selected strong { + color: currentColor; +} +.table tr.is-selected td, +.table tr.is-selected th { + border-color: var(--bulma-table-row-active-color); + color: currentColor; +} +.table tr.is-white { + --bulma-table-color: var(--bulma-white-invert); + --bulma-table-cell-heading-color: var(--bulma-white-invert); + --bulma-table-cell-background-color: var(--bulma-white); + --bulma-table-cell-border-color: var(--bulma-white); +} +.table tr.is-black { + --bulma-table-color: var(--bulma-black-invert); + --bulma-table-cell-heading-color: var(--bulma-black-invert); + --bulma-table-cell-background-color: var(--bulma-black); + --bulma-table-cell-border-color: var(--bulma-black); +} +.table tr.is-light { + --bulma-table-color: var(--bulma-light-invert); + --bulma-table-cell-heading-color: var(--bulma-light-invert); + --bulma-table-cell-background-color: var(--bulma-light); + --bulma-table-cell-border-color: var(--bulma-light); +} +.table tr.is-dark { + --bulma-table-color: var(--bulma-dark-invert); + --bulma-table-cell-heading-color: var(--bulma-dark-invert); + --bulma-table-cell-background-color: var(--bulma-dark); + --bulma-table-cell-border-color: var(--bulma-dark); +} +.table tr.is-text { + --bulma-table-color: var(--bulma-text-invert); + --bulma-table-cell-heading-color: var(--bulma-text-invert); + --bulma-table-cell-background-color: var(--bulma-text); + --bulma-table-cell-border-color: var(--bulma-text); +} +.table tr.is-primary { + --bulma-table-color: var(--bulma-primary-invert); + --bulma-table-cell-heading-color: var(--bulma-primary-invert); + --bulma-table-cell-background-color: var(--bulma-primary); + --bulma-table-cell-border-color: var(--bulma-primary); +} +.table tr.is-link { + --bulma-table-color: var(--bulma-link-invert); + --bulma-table-cell-heading-color: var(--bulma-link-invert); + --bulma-table-cell-background-color: var(--bulma-link); + --bulma-table-cell-border-color: var(--bulma-link); +} +.table tr.is-info { + --bulma-table-color: var(--bulma-info-invert); + --bulma-table-cell-heading-color: var(--bulma-info-invert); + --bulma-table-cell-background-color: var(--bulma-info); + --bulma-table-cell-border-color: var(--bulma-info); +} +.table tr.is-success { + --bulma-table-color: var(--bulma-success-invert); + --bulma-table-cell-heading-color: var(--bulma-success-invert); + --bulma-table-cell-background-color: var(--bulma-success); + --bulma-table-cell-border-color: var(--bulma-success); +} +.table tr.is-warning { + --bulma-table-color: var(--bulma-warning-invert); + --bulma-table-cell-heading-color: var(--bulma-warning-invert); + --bulma-table-cell-background-color: var(--bulma-warning); + --bulma-table-cell-border-color: var(--bulma-warning); +} +.table tr.is-danger { + --bulma-table-color: var(--bulma-danger-invert); + --bulma-table-cell-heading-color: var(--bulma-danger-invert); + --bulma-table-cell-background-color: var(--bulma-danger); + --bulma-table-cell-border-color: var(--bulma-danger); +} +.table thead { + background-color: var(--bulma-table-head-background-color); +} +.table thead td, +.table thead th { + border-width: var(--bulma-table-head-cell-border-width); + color: var(--bulma-table-head-cell-color); +} +.table tfoot { + background-color: var(--bulma-table-foot-background-color); +} +.table tfoot td, +.table tfoot th { + border-width: var(--bulma-table-foot-cell-border-width); + color: var(--bulma-table-foot-cell-color); +} +.table tbody { + background-color: var(--bulma-table-body-background-color); +} +.table tbody tr:last-child td, +.table tbody tr:last-child th { + border-bottom-width: 0; +} +.table.is-bordered td, +.table.is-bordered th { + border-width: 1px; +} +.table.is-bordered tr:last-child td, +.table.is-bordered tr:last-child th { + border-bottom-width: 1px; +} +.table.is-fullwidth { + width: 100%; +} +.table.is-hoverable tbody tr:not(.is-selected):hover { + background-color: var(--bulma-table-row-hover-background-color); +} +.table.is-hoverable.is-striped tbody tr:not(.is-selected):hover { + background-color: var(--bulma-table-row-hover-background-color); +} +.table.is-hoverable.is-striped tbody tr:not(.is-selected):hover:nth-child(even) { + background-color: var(--bulma-table-striped-row-even-hover-background-color); +} +.table.is-narrow td, +.table.is-narrow th { + padding: 0.25em 0.5em; +} +.table.is-striped tbody tr:not(.is-selected):nth-child(even) { + background-color: var(--bulma-table-striped-row-even-background-color); +} + +.table-container { + -webkit-overflow-scrolling: touch; + overflow: auto; + overflow-y: hidden; + max-width: 100%; +} + +.tags { + align-items: center; + color: hsl(var(--bulma-tag-h), var(--bulma-tag-s), var(--bulma-tag-color-l)); + display: flex; + flex-wrap: wrap; + gap: 0.5rem; + justify-content: flex-start; +} +.tags.are-medium .tag:not(.is-normal):not(.is-large) { + font-size: var(--bulma-size-normal); +} +.tags.are-large .tag:not(.is-normal):not(.is-medium) { + font-size: var(--bulma-size-medium); +} +.tags.is-centered { + gap: 0.25rem; + justify-content: center; +} +.tags.is-right { + justify-content: flex-end; +} +.tags.has-addons { + gap: 0; +} +.tags.has-addons .tag:not(:first-child) { + border-start-start-radius: 0; + border-end-start-radius: 0; +} +.tags.has-addons .tag:not(:last-child) { + border-start-end-radius: 0; + border-end-end-radius: 0; +} + +.tag { + --bulma-tag-h: var(--bulma-scheme-h); + --bulma-tag-s: var(--bulma-scheme-s); + --bulma-tag-background-l: var(--bulma-background-l); + --bulma-tag-background-l-delta: 0%; + --bulma-tag-hover-background-l-delta: var(--bulma-hover-background-l-delta); + --bulma-tag-active-background-l-delta: var(--bulma-active-background-l-delta); + --bulma-tag-color-l: var(--bulma-text-l); + --bulma-tag-radius: var(--bulma-radius); + --bulma-tag-delete-margin: 1px; + align-items: center; + background-color: hsl(var(--bulma-tag-h), var(--bulma-tag-s), calc(var(--bulma-tag-background-l) + var(--bulma-tag-background-l-delta))); + border-radius: var(--bulma-radius); + color: hsl(var(--bulma-tag-h), var(--bulma-tag-s), var(--bulma-tag-color-l)); + display: inline-flex; + font-size: var(--bulma-size-small); + height: 2em; + justify-content: center; + line-height: 1.5; + padding-left: 0.75em; + padding-right: 0.75em; + white-space: nowrap; +} +.tag .delete { + margin-inline-start: 0.25rem; + margin-inline-end: -0.375rem; +} +.tag.is-white { + --bulma-tag-h: var(--bulma-white-h); + --bulma-tag-s: var(--bulma-white-s); + --bulma-tag-background-l: var(--bulma-white-l); + --bulma-tag-color-l: var(--bulma-white-invert-l); +} +.tag.is-white.is-light { + --bulma-tag-background-l: var(--bulma-light-l); + --bulma-tag-color-l: var(--bulma-white-light-invert-l); +} +.tag.is-black { + --bulma-tag-h: var(--bulma-black-h); + --bulma-tag-s: var(--bulma-black-s); + --bulma-tag-background-l: var(--bulma-black-l); + --bulma-tag-color-l: var(--bulma-black-invert-l); +} +.tag.is-black.is-light { + --bulma-tag-background-l: var(--bulma-light-l); + --bulma-tag-color-l: var(--bulma-black-light-invert-l); +} +.tag.is-light { + --bulma-tag-h: var(--bulma-light-h); + --bulma-tag-s: var(--bulma-light-s); + --bulma-tag-background-l: var(--bulma-light-l); + --bulma-tag-color-l: var(--bulma-light-invert-l); +} +.tag.is-light.is-light { + --bulma-tag-background-l: var(--bulma-light-l); + --bulma-tag-color-l: var(--bulma-light-light-invert-l); +} +.tag.is-dark { + --bulma-tag-h: var(--bulma-dark-h); + --bulma-tag-s: var(--bulma-dark-s); + --bulma-tag-background-l: var(--bulma-dark-l); + --bulma-tag-color-l: var(--bulma-dark-invert-l); +} +.tag.is-dark.is-light { + --bulma-tag-background-l: var(--bulma-light-l); + --bulma-tag-color-l: var(--bulma-dark-light-invert-l); +} +.tag.is-text { + --bulma-tag-h: var(--bulma-text-h); + --bulma-tag-s: var(--bulma-text-s); + --bulma-tag-background-l: var(--bulma-text-l); + --bulma-tag-color-l: var(--bulma-text-invert-l); +} +.tag.is-text.is-light { + --bulma-tag-background-l: var(--bulma-light-l); + --bulma-tag-color-l: var(--bulma-text-light-invert-l); +} +.tag.is-primary { + --bulma-tag-h: var(--bulma-primary-h); + --bulma-tag-s: var(--bulma-primary-s); + --bulma-tag-background-l: var(--bulma-primary-l); + --bulma-tag-color-l: var(--bulma-primary-invert-l); +} +.tag.is-primary.is-light { + --bulma-tag-background-l: var(--bulma-light-l); + --bulma-tag-color-l: var(--bulma-primary-light-invert-l); +} +.tag.is-link { + --bulma-tag-h: var(--bulma-link-h); + --bulma-tag-s: var(--bulma-link-s); + --bulma-tag-background-l: var(--bulma-link-l); + --bulma-tag-color-l: var(--bulma-link-invert-l); +} +.tag.is-link.is-light { + --bulma-tag-background-l: var(--bulma-light-l); + --bulma-tag-color-l: var(--bulma-link-light-invert-l); +} +.tag.is-info { + --bulma-tag-h: var(--bulma-info-h); + --bulma-tag-s: var(--bulma-info-s); + --bulma-tag-background-l: var(--bulma-info-l); + --bulma-tag-color-l: var(--bulma-info-invert-l); +} +.tag.is-info.is-light { + --bulma-tag-background-l: var(--bulma-light-l); + --bulma-tag-color-l: var(--bulma-info-light-invert-l); +} +.tag.is-success { + --bulma-tag-h: var(--bulma-success-h); + --bulma-tag-s: var(--bulma-success-s); + --bulma-tag-background-l: var(--bulma-success-l); + --bulma-tag-color-l: var(--bulma-success-invert-l); +} +.tag.is-success.is-light { + --bulma-tag-background-l: var(--bulma-light-l); + --bulma-tag-color-l: var(--bulma-success-light-invert-l); +} +.tag.is-warning { + --bulma-tag-h: var(--bulma-warning-h); + --bulma-tag-s: var(--bulma-warning-s); + --bulma-tag-background-l: var(--bulma-warning-l); + --bulma-tag-color-l: var(--bulma-warning-invert-l); +} +.tag.is-warning.is-light { + --bulma-tag-background-l: var(--bulma-light-l); + --bulma-tag-color-l: var(--bulma-warning-light-invert-l); +} +.tag.is-danger { + --bulma-tag-h: var(--bulma-danger-h); + --bulma-tag-s: var(--bulma-danger-s); + --bulma-tag-background-l: var(--bulma-danger-l); + --bulma-tag-color-l: var(--bulma-danger-invert-l); +} +.tag.is-danger.is-light { + --bulma-tag-background-l: var(--bulma-light-l); + --bulma-tag-color-l: var(--bulma-danger-light-invert-l); +} +.tag.is-normal { + font-size: var(--bulma-size-small); +} +.tag.is-medium { + font-size: var(--bulma-size-normal); +} +.tag.is-large { + font-size: var(--bulma-size-medium); +} +.tag .icon:first-child:not(:last-child) { + margin-inline-start: -0.375em; + margin-inline-end: 0.1875em; +} +.tag .icon:last-child:not(:first-child) { + margin-inline-start: 0.1875em; + margin-inline-end: -0.375em; +} +.tag .icon:first-child:last-child { + margin-inline-start: -0.375em; + margin-inline-end: -0.375em; +} +.tag.is-delete { + margin-inline-start: var(--bulma-tag-delete-margin); + padding: 0; + position: relative; + width: 2em; +} +.tag.is-delete::before, .tag.is-delete::after { + background-color: currentColor; + content: ""; + display: block; + left: 50%; + position: absolute; + top: 50%; + transform: translateX(-50%) translateY(-50%) rotate(45deg); + transform-origin: center center; +} +.tag.is-delete::before { + height: 1px; + width: 50%; +} +.tag.is-delete::after { + height: 50%; + width: 1px; +} +.tag.is-rounded { + border-radius: var(--bulma-radius-rounded); +} + +a.tag, +button.tag, +.tag.is-hoverable { + cursor: pointer; +} +a.tag:hover, +button.tag:hover, +.tag.is-hoverable:hover { + --bulma-tag-background-l-delta: var(--bulma-tag-hover-background-l-delta); +} +a.tag:active, +button.tag:active, +.tag.is-hoverable:active { + --bulma-tag-background-l-delta: var(--bulma-tag-active-background-l-delta); +} + +.title, +.subtitle { + --bulma-title-color: var(--bulma-text-strong); + --bulma-title-family: false; + --bulma-title-size: var(--bulma-size-3); + --bulma-title-weight: var(--bulma-weight-extrabold); + --bulma-title-line-height: 1.125; + --bulma-title-strong-color: inherit; + --bulma-title-strong-weight: inherit; + --bulma-title-sub-size: 0.75em; + --bulma-title-sup-size: 0.75em; + --bulma-subtitle-color: var(--bulma-text); + --bulma-subtitle-family: false; + --bulma-subtitle-size: var(--bulma-size-5); + --bulma-subtitle-weight: var(--bulma-weight-normal); + --bulma-subtitle-line-height: 1.25; + --bulma-subtitle-strong-color: var(--bulma-text-strong); + --bulma-subtitle-strong-weight: var(--bulma-weight-semibold); +} + +.title, +.subtitle { + word-break: break-word; +} +.title em, +.title span, +.subtitle em, +.subtitle span { + font-weight: inherit; +} +.title sub, +.subtitle sub { + font-size: var(--bulma-title-sub-size); +} +.title sup, +.subtitle sup { + font-size: var(--bulma-title-sup-size); +} +.title .tag, +.subtitle .tag { + vertical-align: middle; +} + +.title { + color: var(--bulma-title-color); + font-size: var(--bulma-title-size); + font-weight: var(--bulma-title-weight); + line-height: var(--bulma-title-line-height); +} +.title strong { + color: var(--bulma-title-strong-color); + font-weight: var(--bulma-title-strong-weight); +} +.title:not(.is-spaced):has(+ .subtitle) { + margin-bottom: 0; +} +.title.is-1 { + font-size: 3rem; +} +.title.is-2 { + font-size: 2.5rem; +} +.title.is-3 { + font-size: 2rem; +} +.title.is-4 { + font-size: 1.5rem; +} +.title.is-5 { + font-size: 1.25rem; +} +.title.is-6 { + font-size: 1rem; +} +.title.is-7 { + font-size: 0.75rem; +} + +.subtitle { + color: var(--bulma-subtitle-color); + font-size: var(--bulma-subtitle-size); + font-weight: var(--bulma-subtitle-weight); + line-height: var(--bulma-subtitle-line-height); +} +.subtitle strong { + color: var(--bulma-subtitle-strong-color); + font-weight: var(--bulma-subtitle-strong-weight); +} +.subtitle:not(.is-spaced):has(+ .title) { + margin-bottom: 0; +} +.subtitle.is-1 { + font-size: 3rem; +} +.subtitle.is-2 { + font-size: 2.5rem; +} +.subtitle.is-3 { + font-size: 2rem; +} +.subtitle.is-4 { + font-size: 1.5rem; +} +.subtitle.is-5 { + font-size: 1.25rem; +} +.subtitle.is-6 { + font-size: 1rem; +} +.subtitle.is-7 { + font-size: 0.75rem; +} + +/* Bulma Form */ +.control, +.input, +.textarea, +.select { + --bulma-input-h: var(--bulma-scheme-h); + --bulma-input-s: var(--bulma-scheme-s); + --bulma-input-l: var(--bulma-scheme-main-l); + --bulma-input-border-style: solid; + --bulma-input-border-width: var(--bulma-control-border-width); + --bulma-input-border-l: var(--bulma-border-l); + --bulma-input-border-l-delta: 0%; + --bulma-input-border-color: hsl(var(--bulma-input-h), var(--bulma-input-s), calc(var(--bulma-input-border-l) + var(--bulma-input-border-l-delta))); + --bulma-input-hover-border-l-delta: var(--bulma-hover-border-l-delta); + --bulma-input-active-border-l-delta: var(--bulma-active-border-l-delta); + --bulma-input-focus-h: var(--bulma-focus-h); + --bulma-input-focus-s: var(--bulma-focus-s); + --bulma-input-focus-l: var(--bulma-focus-l); + --bulma-input-focus-shadow-size: var(--bulma-focus-shadow-size); + --bulma-input-focus-shadow-alpha: var(--bulma-focus-shadow-alpha); + --bulma-input-color-l: var(--bulma-text-strong-l); + --bulma-input-background-l: var(--bulma-scheme-main-l); + --bulma-input-background-l-delta: 0%; + --bulma-input-height: var(--bulma-control-height); + --bulma-input-shadow: inset 0 0.0625em 0.125em hsla(var(--bulma-scheme-h), var(--bulma-scheme-s), var(--bulma-scheme-invert-l), 0.05); + --bulma-input-placeholder-color: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-strong-l), 0.3); + --bulma-input-disabled-color: var(--bulma-text-weak); + --bulma-input-disabled-background-color: var(--bulma-background); + --bulma-input-disabled-border-color: var(--bulma-background); + --bulma-input-disabled-placeholder-color: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-weak-l), 0.3); + --bulma-input-arrow: var(--bulma-link); + --bulma-input-icon-color: var(--bulma-text-light); + --bulma-input-icon-hover-color: var(--bulma-text-weak); + --bulma-input-icon-focus-color: var(--bulma-link); + --bulma-input-radius: var(--bulma-radius); +} + +.select select, .input, .textarea { + background-color: hsl(var(--bulma-input-h), var(--bulma-input-s), calc(var(--bulma-input-background-l) + var(--bulma-input-background-l-delta))); + border-color: var(--bulma-input-border-color); + border-radius: var(--bulma-input-radius); + color: hsl(var(--bulma-input-h), var(--bulma-input-s), var(--bulma-input-color-l)); +} +.select select::-moz-placeholder, .input::-moz-placeholder, .textarea::-moz-placeholder { + color: var(--bulma-input-placeholder-color); +} +.select select::-webkit-input-placeholder, .input::-webkit-input-placeholder, .textarea::-webkit-input-placeholder { + color: var(--bulma-input-placeholder-color); +} +.select select:-moz-placeholder, .input:-moz-placeholder, .textarea:-moz-placeholder { + color: var(--bulma-input-placeholder-color); +} +.select select:-ms-input-placeholder, .input:-ms-input-placeholder, .textarea:-ms-input-placeholder { + color: var(--bulma-input-placeholder-color); +} +.select select:hover, .input:hover, .textarea:hover, .select select.is-hovered, .is-hovered.input, .is-hovered.textarea { + --bulma-input-border-l-delta: var(--bulma-input-hover-border-l-delta); +} +.select select:active, .input:active, .textarea:active, .select select.is-active, .is-active.input, .is-active.textarea { + --bulma-input-border-l-delta: var(--bulma-input-active-border-l-delta); +} +.select select:focus, .input:focus, .textarea:focus, .select select:focus-within, .input:focus-within, .textarea:focus-within, .select select.is-focused, .is-focused.input, .is-focused.textarea { + border-color: hsl(var(--bulma-input-focus-h), var(--bulma-input-focus-s), var(--bulma-input-focus-l)); + box-shadow: var(--bulma-input-focus-shadow-size) hsla(var(--bulma-input-focus-h), var(--bulma-input-focus-s), var(--bulma-input-focus-l), var(--bulma-input-focus-shadow-alpha)); +} +.select select[disabled], [disabled].input, [disabled].textarea, fieldset[disabled] .select select, .select fieldset[disabled] select, fieldset[disabled] .input, fieldset[disabled] .textarea { + background-color: var(--bulma-input-disabled-background-color); + border-color: var(--bulma-input-disabled-border-color); + box-shadow: none; + color: var(--bulma-input-disabled-color); +} +.select select[disabled]::-moz-placeholder, [disabled].input::-moz-placeholder, [disabled].textarea::-moz-placeholder, fieldset[disabled] .select select::-moz-placeholder, .select fieldset[disabled] select::-moz-placeholder, fieldset[disabled] .input::-moz-placeholder, fieldset[disabled] .textarea::-moz-placeholder { + color: var(--bulma-input-disabled-placeholder-color); +} +.select select[disabled]::-webkit-input-placeholder, [disabled].input::-webkit-input-placeholder, [disabled].textarea::-webkit-input-placeholder, fieldset[disabled] .select select::-webkit-input-placeholder, .select fieldset[disabled] select::-webkit-input-placeholder, fieldset[disabled] .input::-webkit-input-placeholder, fieldset[disabled] .textarea::-webkit-input-placeholder { + color: var(--bulma-input-disabled-placeholder-color); +} +.select select[disabled]:-moz-placeholder, [disabled].input:-moz-placeholder, [disabled].textarea:-moz-placeholder, fieldset[disabled] .select select:-moz-placeholder, .select fieldset[disabled] select:-moz-placeholder, fieldset[disabled] .input:-moz-placeholder, fieldset[disabled] .textarea:-moz-placeholder { + color: var(--bulma-input-disabled-placeholder-color); +} +.select select[disabled]:-ms-input-placeholder, [disabled].input:-ms-input-placeholder, [disabled].textarea:-ms-input-placeholder, fieldset[disabled] .select select:-ms-input-placeholder, .select fieldset[disabled] select:-ms-input-placeholder, fieldset[disabled] .input:-ms-input-placeholder, fieldset[disabled] .textarea:-ms-input-placeholder { + color: var(--bulma-input-disabled-placeholder-color); +} + +/* Bulma Form */ +.textarea, .input { + box-shadow: inset 0 0.0625em 0.125em hsla(var(--bulma-scheme-h), var(--bulma-scheme-s), var(--bulma-scheme-invert-l), 0.05); + max-width: 100%; + width: 100%; +} +[readonly].textarea, [readonly].input { + box-shadow: none; +} +.is-white.textarea, .is-white.input { + --bulma-input-h: var(--bulma-white-h); + --bulma-input-s: var(--bulma-white-s); + --bulma-input-l: var(--bulma-white-l); + --bulma-input-focus-h: var(--bulma-white-h); + --bulma-input-focus-s: var(--bulma-white-s); + --bulma-input-focus-l: var(--bulma-white-l); + --bulma-input-border-l: var(--bulma-white-l); +} +.is-black.textarea, .is-black.input { + --bulma-input-h: var(--bulma-black-h); + --bulma-input-s: var(--bulma-black-s); + --bulma-input-l: var(--bulma-black-l); + --bulma-input-focus-h: var(--bulma-black-h); + --bulma-input-focus-s: var(--bulma-black-s); + --bulma-input-focus-l: var(--bulma-black-l); + --bulma-input-border-l: var(--bulma-black-l); +} +.is-light.textarea, .is-light.input { + --bulma-input-h: var(--bulma-light-h); + --bulma-input-s: var(--bulma-light-s); + --bulma-input-l: var(--bulma-light-l); + --bulma-input-focus-h: var(--bulma-light-h); + --bulma-input-focus-s: var(--bulma-light-s); + --bulma-input-focus-l: var(--bulma-light-l); + --bulma-input-border-l: var(--bulma-light-l); +} +.is-dark.textarea, .is-dark.input { + --bulma-input-h: var(--bulma-dark-h); + --bulma-input-s: var(--bulma-dark-s); + --bulma-input-l: var(--bulma-dark-l); + --bulma-input-focus-h: var(--bulma-dark-h); + --bulma-input-focus-s: var(--bulma-dark-s); + --bulma-input-focus-l: var(--bulma-dark-l); + --bulma-input-border-l: var(--bulma-dark-l); +} +.is-text.textarea, .is-text.input { + --bulma-input-h: var(--bulma-text-h); + --bulma-input-s: var(--bulma-text-s); + --bulma-input-l: var(--bulma-text-l); + --bulma-input-focus-h: var(--bulma-text-h); + --bulma-input-focus-s: var(--bulma-text-s); + --bulma-input-focus-l: var(--bulma-text-l); + --bulma-input-border-l: var(--bulma-text-l); +} +.is-primary.textarea, .is-primary.input { + --bulma-input-h: var(--bulma-primary-h); + --bulma-input-s: var(--bulma-primary-s); + --bulma-input-l: var(--bulma-primary-l); + --bulma-input-focus-h: var(--bulma-primary-h); + --bulma-input-focus-s: var(--bulma-primary-s); + --bulma-input-focus-l: var(--bulma-primary-l); + --bulma-input-border-l: var(--bulma-primary-l); +} +.is-link.textarea, .is-link.input { + --bulma-input-h: var(--bulma-link-h); + --bulma-input-s: var(--bulma-link-s); + --bulma-input-l: var(--bulma-link-l); + --bulma-input-focus-h: var(--bulma-link-h); + --bulma-input-focus-s: var(--bulma-link-s); + --bulma-input-focus-l: var(--bulma-link-l); + --bulma-input-border-l: var(--bulma-link-l); +} +.is-info.textarea, .is-info.input { + --bulma-input-h: var(--bulma-info-h); + --bulma-input-s: var(--bulma-info-s); + --bulma-input-l: var(--bulma-info-l); + --bulma-input-focus-h: var(--bulma-info-h); + --bulma-input-focus-s: var(--bulma-info-s); + --bulma-input-focus-l: var(--bulma-info-l); + --bulma-input-border-l: var(--bulma-info-l); +} +.is-success.textarea, .is-success.input { + --bulma-input-h: var(--bulma-success-h); + --bulma-input-s: var(--bulma-success-s); + --bulma-input-l: var(--bulma-success-l); + --bulma-input-focus-h: var(--bulma-success-h); + --bulma-input-focus-s: var(--bulma-success-s); + --bulma-input-focus-l: var(--bulma-success-l); + --bulma-input-border-l: var(--bulma-success-l); +} +.is-warning.textarea, .is-warning.input { + --bulma-input-h: var(--bulma-warning-h); + --bulma-input-s: var(--bulma-warning-s); + --bulma-input-l: var(--bulma-warning-l); + --bulma-input-focus-h: var(--bulma-warning-h); + --bulma-input-focus-s: var(--bulma-warning-s); + --bulma-input-focus-l: var(--bulma-warning-l); + --bulma-input-border-l: var(--bulma-warning-l); +} +.is-danger.textarea, .is-danger.input { + --bulma-input-h: var(--bulma-danger-h); + --bulma-input-s: var(--bulma-danger-s); + --bulma-input-l: var(--bulma-danger-l); + --bulma-input-focus-h: var(--bulma-danger-h); + --bulma-input-focus-s: var(--bulma-danger-s); + --bulma-input-focus-l: var(--bulma-danger-l); + --bulma-input-border-l: var(--bulma-danger-l); +} +.is-small.textarea, .is-small.input { + border-radius: var(--bulma-radius-small); + font-size: var(--bulma-size-small); +} +.is-medium.textarea, .is-medium.input { + font-size: var(--bulma-size-medium); +} +.is-large.textarea, .is-large.input { + font-size: var(--bulma-size-large); +} +.is-fullwidth.textarea, .is-fullwidth.input { + display: block; + width: 100%; +} +.is-inline.textarea, .is-inline.input { + display: inline; + width: auto; +} + +.input.is-rounded { + border-radius: var(--bulma-radius-rounded); + padding-left: calc(calc(0.75em - 1px) + 0.375em); + padding-right: calc(calc(0.75em - 1px) + 0.375em); +} +.input.is-static { + background-color: transparent; + border-color: transparent; + box-shadow: none; + padding-left: 0; + padding-right: 0; +} + +.textarea { + --bulma-textarea-padding: var(--bulma-control-padding-horizontal); + --bulma-textarea-max-height: 40em; + --bulma-textarea-min-height: 8em; + display: block; + max-width: 100%; + min-width: 100%; + padding: var(--bulma-textarea-padding); + resize: vertical; +} +.textarea:not([rows]) { + max-height: var(--bulma-textarea-max-height); + min-height: var(--bulma-textarea-min-height); +} +.textarea[rows] { + height: initial; +} +.textarea.has-fixed-size { + resize: none; +} + +/* Bulma Form */ +.radio, .checkbox { + cursor: pointer; + display: inline-block; + line-height: 1.25; + position: relative; +} +.radio input, .checkbox input { + cursor: pointer; +} +[disabled].radio, [disabled].checkbox, fieldset[disabled] .radio, fieldset[disabled] .checkbox, +.radio input[disabled], +.checkbox input[disabled] { + color: var(--bulma-text-weak); + cursor: not-allowed; +} + +.checkboxes, +.radios { + display: flex; + flex-wrap: wrap; + column-gap: 1em; + row-gap: 0.5em; +} + +/* Bulma Form */ +.select { + --bulma-input-h: var(--bulma-scheme-h); + --bulma-input-s: var(--bulma-scheme-s); + --bulma-input-border-style: solid; + --bulma-input-border-width: 1px; + --bulma-input-border-l: var(--bulma-border-l); + display: inline-block; + max-width: 100%; + position: relative; + vertical-align: top; +} +.select:not(.is-multiple) { + height: var(--bulma-control-height); +} +.select:not(.is-multiple):not(.is-loading)::after { + inset-inline-end: 1.125em; + z-index: 4; +} +.select.is-rounded select { + border-radius: var(--bulma-radius-rounded); + padding-inline-start: 1em; +} +.select select { + cursor: pointer; + display: block; + font-size: 1em; + max-width: 100%; + outline: none; +} +.select select::-ms-expand { + display: none; +} +.select select[disabled]:hover, fieldset[disabled] .select select:hover { + border-color: var(--bulma-background); +} +.select select:not([multiple]) { + padding-inline-end: 2.5em; +} +.select select[multiple] { + height: auto; + padding: 0; +} +.select select[multiple] option { + padding: 0.5em 1em; +} +.select.is-white { + --bulma-input-h: var(--bulma-white-h); + --bulma-input-s: var(--bulma-white-s); + --bulma-input-l: var(--bulma-white-l); + --bulma-input-focus-h: var(--bulma-white-h); + --bulma-input-focus-s: var(--bulma-white-s); + --bulma-input-focus-l: var(--bulma-white-l); + --bulma-input-border-l: var(--bulma-white-l); + --bulma-arrow-color: var(--bulma-white); +} +.select.is-black { + --bulma-input-h: var(--bulma-black-h); + --bulma-input-s: var(--bulma-black-s); + --bulma-input-l: var(--bulma-black-l); + --bulma-input-focus-h: var(--bulma-black-h); + --bulma-input-focus-s: var(--bulma-black-s); + --bulma-input-focus-l: var(--bulma-black-l); + --bulma-input-border-l: var(--bulma-black-l); + --bulma-arrow-color: var(--bulma-black); +} +.select.is-light { + --bulma-input-h: var(--bulma-light-h); + --bulma-input-s: var(--bulma-light-s); + --bulma-input-l: var(--bulma-light-l); + --bulma-input-focus-h: var(--bulma-light-h); + --bulma-input-focus-s: var(--bulma-light-s); + --bulma-input-focus-l: var(--bulma-light-l); + --bulma-input-border-l: var(--bulma-light-l); + --bulma-arrow-color: var(--bulma-light); +} +.select.is-dark { + --bulma-input-h: var(--bulma-dark-h); + --bulma-input-s: var(--bulma-dark-s); + --bulma-input-l: var(--bulma-dark-l); + --bulma-input-focus-h: var(--bulma-dark-h); + --bulma-input-focus-s: var(--bulma-dark-s); + --bulma-input-focus-l: var(--bulma-dark-l); + --bulma-input-border-l: var(--bulma-dark-l); + --bulma-arrow-color: var(--bulma-dark); +} +.select.is-text { + --bulma-input-h: var(--bulma-text-h); + --bulma-input-s: var(--bulma-text-s); + --bulma-input-l: var(--bulma-text-l); + --bulma-input-focus-h: var(--bulma-text-h); + --bulma-input-focus-s: var(--bulma-text-s); + --bulma-input-focus-l: var(--bulma-text-l); + --bulma-input-border-l: var(--bulma-text-l); + --bulma-arrow-color: var(--bulma-text); +} +.select.is-primary { + --bulma-input-h: var(--bulma-primary-h); + --bulma-input-s: var(--bulma-primary-s); + --bulma-input-l: var(--bulma-primary-l); + --bulma-input-focus-h: var(--bulma-primary-h); + --bulma-input-focus-s: var(--bulma-primary-s); + --bulma-input-focus-l: var(--bulma-primary-l); + --bulma-input-border-l: var(--bulma-primary-l); + --bulma-arrow-color: var(--bulma-primary); +} +.select.is-link { + --bulma-input-h: var(--bulma-link-h); + --bulma-input-s: var(--bulma-link-s); + --bulma-input-l: var(--bulma-link-l); + --bulma-input-focus-h: var(--bulma-link-h); + --bulma-input-focus-s: var(--bulma-link-s); + --bulma-input-focus-l: var(--bulma-link-l); + --bulma-input-border-l: var(--bulma-link-l); + --bulma-arrow-color: var(--bulma-link); +} +.select.is-info { + --bulma-input-h: var(--bulma-info-h); + --bulma-input-s: var(--bulma-info-s); + --bulma-input-l: var(--bulma-info-l); + --bulma-input-focus-h: var(--bulma-info-h); + --bulma-input-focus-s: var(--bulma-info-s); + --bulma-input-focus-l: var(--bulma-info-l); + --bulma-input-border-l: var(--bulma-info-l); + --bulma-arrow-color: var(--bulma-info); +} +.select.is-success { + --bulma-input-h: var(--bulma-success-h); + --bulma-input-s: var(--bulma-success-s); + --bulma-input-l: var(--bulma-success-l); + --bulma-input-focus-h: var(--bulma-success-h); + --bulma-input-focus-s: var(--bulma-success-s); + --bulma-input-focus-l: var(--bulma-success-l); + --bulma-input-border-l: var(--bulma-success-l); + --bulma-arrow-color: var(--bulma-success); +} +.select.is-warning { + --bulma-input-h: var(--bulma-warning-h); + --bulma-input-s: var(--bulma-warning-s); + --bulma-input-l: var(--bulma-warning-l); + --bulma-input-focus-h: var(--bulma-warning-h); + --bulma-input-focus-s: var(--bulma-warning-s); + --bulma-input-focus-l: var(--bulma-warning-l); + --bulma-input-border-l: var(--bulma-warning-l); + --bulma-arrow-color: var(--bulma-warning); +} +.select.is-danger { + --bulma-input-h: var(--bulma-danger-h); + --bulma-input-s: var(--bulma-danger-s); + --bulma-input-l: var(--bulma-danger-l); + --bulma-input-focus-h: var(--bulma-danger-h); + --bulma-input-focus-s: var(--bulma-danger-s); + --bulma-input-focus-l: var(--bulma-danger-l); + --bulma-input-border-l: var(--bulma-danger-l); + --bulma-arrow-color: var(--bulma-danger); +} +.select.is-small { + border-radius: var(--bulma-radius-small); + font-size: var(--bulma-size-small); +} +.select.is-medium { + font-size: var(--bulma-size-medium); +} +.select.is-large { + font-size: var(--bulma-size-large); +} +.select.is-disabled::after { + border-color: var(--bulma-text-weak) !important; + opacity: 0.5; +} +.select.is-fullwidth { + width: 100%; +} +.select.is-fullwidth select { + width: 100%; +} +.select.is-loading::after { + inset-inline-end: 0.625em; + margin-top: 0; + position: absolute; + top: 0.625em; + transform: none; +} +.select.is-loading.is-small:after { + font-size: var(--bulma-size-small); +} +.select.is-loading.is-medium:after { + font-size: var(--bulma-size-medium); +} +.select.is-loading.is-large:after { + font-size: var(--bulma-size-large); +} + +/* Bulma Form */ +.file { + --bulma-file-radius: var(--bulma-radius); + --bulma-file-name-border-color: var(--bulma-border); + --bulma-file-name-border-style: solid; + --bulma-file-name-border-width: 1px 1px 1px 0; + --bulma-file-name-max-width: 16em; + --bulma-file-h: var(--bulma-scheme-h); + --bulma-file-s: var(--bulma-scheme-s); + --bulma-file-background-l: var(--bulma-scheme-main-ter-l); + --bulma-file-background-l-delta: 0%; + --bulma-file-hover-background-l-delta: -5%; + --bulma-file-active-background-l-delta: -10%; + --bulma-file-border-l: var(--bulma-border-l); + --bulma-file-border-l-delta: 0%; + --bulma-file-hover-border-l-delta: -10%; + --bulma-file-active-border-l-delta: -20%; + --bulma-file-cta-color-l: var(--bulma-text-strong-l); + --bulma-file-name-color-l: var(--bulma-text-strong-l); + --bulma-file-color-l-delta: 0%; + --bulma-file-hover-color-l-delta: -5%; + --bulma-file-active-color-l-delta: -10%; + align-items: stretch; + display: flex; + justify-content: flex-start; + position: relative; +} +.file.is-white { + --bulma-file-h: var(--bulma-white-h); + --bulma-file-s: var(--bulma-white-s); + --bulma-file-background-l: var(--bulma-white-l); + --bulma-file-border-l: var(--bulma-white-l); + --bulma-file-cta-color-l: var(--bulma-white-invert-l); + --bulma-file-name-color-l: var(--bulma-white-on-scheme-l); +} +.file.is-black { + --bulma-file-h: var(--bulma-black-h); + --bulma-file-s: var(--bulma-black-s); + --bulma-file-background-l: var(--bulma-black-l); + --bulma-file-border-l: var(--bulma-black-l); + --bulma-file-cta-color-l: var(--bulma-black-invert-l); + --bulma-file-name-color-l: var(--bulma-black-on-scheme-l); +} +.file.is-light { + --bulma-file-h: var(--bulma-light-h); + --bulma-file-s: var(--bulma-light-s); + --bulma-file-background-l: var(--bulma-light-l); + --bulma-file-border-l: var(--bulma-light-l); + --bulma-file-cta-color-l: var(--bulma-light-invert-l); + --bulma-file-name-color-l: var(--bulma-light-on-scheme-l); +} +.file.is-dark { + --bulma-file-h: var(--bulma-dark-h); + --bulma-file-s: var(--bulma-dark-s); + --bulma-file-background-l: var(--bulma-dark-l); + --bulma-file-border-l: var(--bulma-dark-l); + --bulma-file-cta-color-l: var(--bulma-dark-invert-l); + --bulma-file-name-color-l: var(--bulma-dark-on-scheme-l); +} +.file.is-text { + --bulma-file-h: var(--bulma-text-h); + --bulma-file-s: var(--bulma-text-s); + --bulma-file-background-l: var(--bulma-text-l); + --bulma-file-border-l: var(--bulma-text-l); + --bulma-file-cta-color-l: var(--bulma-text-invert-l); + --bulma-file-name-color-l: var(--bulma-text-on-scheme-l); +} +.file.is-primary { + --bulma-file-h: var(--bulma-primary-h); + --bulma-file-s: var(--bulma-primary-s); + --bulma-file-background-l: var(--bulma-primary-l); + --bulma-file-border-l: var(--bulma-primary-l); + --bulma-file-cta-color-l: var(--bulma-primary-invert-l); + --bulma-file-name-color-l: var(--bulma-primary-on-scheme-l); +} +.file.is-link { + --bulma-file-h: var(--bulma-link-h); + --bulma-file-s: var(--bulma-link-s); + --bulma-file-background-l: var(--bulma-link-l); + --bulma-file-border-l: var(--bulma-link-l); + --bulma-file-cta-color-l: var(--bulma-link-invert-l); + --bulma-file-name-color-l: var(--bulma-link-on-scheme-l); +} +.file.is-info { + --bulma-file-h: var(--bulma-info-h); + --bulma-file-s: var(--bulma-info-s); + --bulma-file-background-l: var(--bulma-info-l); + --bulma-file-border-l: var(--bulma-info-l); + --bulma-file-cta-color-l: var(--bulma-info-invert-l); + --bulma-file-name-color-l: var(--bulma-info-on-scheme-l); +} +.file.is-success { + --bulma-file-h: var(--bulma-success-h); + --bulma-file-s: var(--bulma-success-s); + --bulma-file-background-l: var(--bulma-success-l); + --bulma-file-border-l: var(--bulma-success-l); + --bulma-file-cta-color-l: var(--bulma-success-invert-l); + --bulma-file-name-color-l: var(--bulma-success-on-scheme-l); +} +.file.is-warning { + --bulma-file-h: var(--bulma-warning-h); + --bulma-file-s: var(--bulma-warning-s); + --bulma-file-background-l: var(--bulma-warning-l); + --bulma-file-border-l: var(--bulma-warning-l); + --bulma-file-cta-color-l: var(--bulma-warning-invert-l); + --bulma-file-name-color-l: var(--bulma-warning-on-scheme-l); +} +.file.is-danger { + --bulma-file-h: var(--bulma-danger-h); + --bulma-file-s: var(--bulma-danger-s); + --bulma-file-background-l: var(--bulma-danger-l); + --bulma-file-border-l: var(--bulma-danger-l); + --bulma-file-cta-color-l: var(--bulma-danger-invert-l); + --bulma-file-name-color-l: var(--bulma-danger-on-scheme-l); +} +.file.is-small { + font-size: var(--bulma-size-small); +} +.file.is-normal { + font-size: var(--bulma-size-normal); +} +.file.is-medium { + font-size: var(--bulma-size-medium); +} +.file.is-medium .file-icon .fa { + font-size: 1.5rem; +} +.file.is-large { + font-size: var(--bulma-size-large); +} +.file.is-large .file-icon .fa { + font-size: 2rem; +} +.file.has-name .file-cta { + border-end-end-radius: 0; + border-start-end-radius: 0; +} +.file.has-name .file-name { + border-end-start-radius: 0; + border-start-start-radius: 0; +} +.file.has-name.is-empty .file-cta { + border-radius: var(--bulma-file-radius); +} +.file.has-name.is-empty .file-name { + display: none; +} +.file.is-boxed .file-label { + flex-direction: column; +} +.file.is-boxed .file-cta { + flex-direction: column; + height: auto; + padding: 1em 3em; +} +.file.is-boxed .file-name { + border-width: 0 1px 1px; +} +.file.is-boxed .file-icon { + height: 1.5em; + width: 1.5em; +} +.file.is-boxed .file-icon .fa { + font-size: 1.5rem; +} +.file.is-boxed.is-small .file-icon .fa { + font-size: 1rem; +} +.file.is-boxed.is-medium .file-icon .fa { + font-size: 2rem; +} +.file.is-boxed.is-large .file-icon .fa { + font-size: 2.5rem; +} +.file.is-boxed.has-name .file-cta { + border-end-end-radius: 0; + border-end-start-radius: 0; + border-start-end-radius: var(--bulma-file-radius); + border-start-start-radius: var(--bulma-file-radius); +} +.file.is-boxed.has-name .file-name { + border-end-end-radius: var(--bulma-file-radius); + border-end-start-radius: var(--bulma-file-radius); + border-start-end-radius: 0; + border-start-start-radius: 0; + border-width: 0 1px 1px; +} +.file.is-centered { + justify-content: center; +} +.file.is-fullwidth .file-label { + width: 100%; +} +.file.is-fullwidth .file-name { + flex-grow: 1; + max-width: none; +} +.file.is-right { + justify-content: flex-end; +} +.file.is-right .file-cta { + border-radius: 0 var(--bulma-file-radius) var(--bulma-file-radius) 0; +} +.file.is-right .file-name { + border-radius: var(--bulma-file-radius) 0 0 var(--bulma-file-radius); + border-width: 1px 0 1px 1px; + order: -1; +} + +.file-label { + align-items: stretch; + display: flex; + cursor: pointer; + justify-content: flex-start; + overflow: hidden; + position: relative; +} +.file-label:hover { + --bulma-file-background-l-delta: var(--bulma-file-hover-background-l-delta); + --bulma-file-border-l-delta: var(--bulma-file-hover-border-l-delta); + --bulma-file-color-l-delta: var(--bulma-file-hover-color-l-delta); +} +.file-label:active { + --bulma-file-background-l-delta: var(--bulma-file-active-background-l-delta); + --bulma-file-border-l-delta: var(--bulma-file-active-border-l-delta); + --bulma-file-color-l-delta: var(--bulma-file-active-color-l-delta); +} + +.file-input { + height: 100%; + left: 0; + opacity: 0; + outline: none; + position: absolute; + top: 0; + width: 100%; +} + +.file-cta, +.file-name { + border-color: hsl(var(--bulma-file-h), var(--bulma-file-s), calc(var(--bulma-file-border-l) + var(--bulma-file-border-l-delta))); + border-radius: var(--bulma-file-radius); + font-size: 1em; + padding-left: 1em; + padding-right: 1em; + white-space: nowrap; +} + +.file-cta { + background-color: hsl(var(--bulma-file-h), var(--bulma-file-s), calc(var(--bulma-file-background-l) + var(--bulma-file-background-l-delta))); + color: hsl(var(--bulma-file-h), var(--bulma-file-s), calc(var(--bulma-file-cta-color-l) + var(--bulma-file-color-l-delta))); +} + +.file-name { + border-color: hsl(var(--bulma-file-h), var(--bulma-file-s), calc(var(--bulma-file-border-l) + var(--bulma-file-color-l-delta))); + border-style: var(--bulma-file-name-border-style); + border-width: var(--bulma-file-name-border-width); + color: hsl(var(--bulma-file-h), var(--bulma-file-s), calc(var(--bulma-file-name-color-l) + var(--bulma-file-color-l-delta))); + display: block; + max-width: var(--bulma-file-name-max-width); + overflow: hidden; + text-align: inherit; + text-overflow: ellipsis; +} + +.file-icon { + align-items: center; + display: flex; + height: 1em; + justify-content: center; + margin-inline-end: 0.5em; + width: 1em; +} +.file-icon .fa { + font-size: 1rem; +} + +/* Bulma Form */ +:root { + --bulma-label-color: var(--bulma-text-strong); + --bulma-label-spacing: 0.5em; + --bulma-label-weight: var(--bulma-weight-semibold); + --bulma-help-size: var(--bulma-size-small); + --bulma-field-block-spacing: 0.75rem; +} + +.label { + color: var(--bulma-label-color); + display: block; + font-size: var(--bulma-size-normal); + font-weight: var(--bulma-weight-semibold); +} +.label:not(:last-child) { + margin-bottom: var(--bulma-label-spacing); +} +.label.is-small { + font-size: var(--bulma-size-small); +} +.label.is-medium { + font-size: var(--bulma-size-medium); +} +.label.is-large { + font-size: var(--bulma-size-large); +} + +.help { + display: block; + font-size: var(--bulma-help-size); + margin-top: 0.25rem; +} +.help.is-white { + color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-on-scheme-l)); +} +.help.is-black { + color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-on-scheme-l)); +} +.help.is-light { + color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-on-scheme-l)); +} +.help.is-dark { + color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-on-scheme-l)); +} +.help.is-text { + color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-on-scheme-l)); +} +.help.is-primary { + color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-on-scheme-l)); +} +.help.is-link { + color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-on-scheme-l)); +} +.help.is-info { + color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-on-scheme-l)); +} +.help.is-success { + color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-on-scheme-l)); +} +.help.is-warning { + color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-on-scheme-l)); +} +.help.is-danger { + color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-on-scheme-l)); +} + +.field { + --bulma-block-spacing: var(--bulma-field-block-spacing); +} +.field.has-addons { + display: flex; + justify-content: flex-start; +} +.field.has-addons .control:not(:last-child) { + margin-inline-end: -1px; +} +.field.has-addons .control:not(:first-child):not(:last-child) .button, +.field.has-addons .control:not(:first-child):not(:last-child) .input, +.field.has-addons .control:not(:first-child):not(:last-child) .select select { + border-radius: 0; +} +.field.has-addons .control:first-child:not(:only-child) .button, +.field.has-addons .control:first-child:not(:only-child) .input, +.field.has-addons .control:first-child:not(:only-child) .select select { + border-start-end-radius: 0; + border-end-end-radius: 0; +} +.field.has-addons .control:last-child:not(:only-child) .button, +.field.has-addons .control:last-child:not(:only-child) .input, +.field.has-addons .control:last-child:not(:only-child) .select select { + border-start-start-radius: 0; + border-end-start-radius: 0; +} +.field.has-addons .control .button:not([disabled]):hover, .field.has-addons .control .button:not([disabled]).is-hovered, +.field.has-addons .control .input:not([disabled]):hover, +.field.has-addons .control .input:not([disabled]).is-hovered, +.field.has-addons .control .select select:not([disabled]):hover, +.field.has-addons .control .select select:not([disabled]).is-hovered { + z-index: 2; +} +.field.has-addons .control .button:not([disabled]):focus, .field.has-addons .control .button:not([disabled]).is-focused, .field.has-addons .control .button:not([disabled]):active, .field.has-addons .control .button:not([disabled]).is-active, +.field.has-addons .control .input:not([disabled]):focus, +.field.has-addons .control .input:not([disabled]).is-focused, +.field.has-addons .control .input:not([disabled]):active, +.field.has-addons .control .input:not([disabled]).is-active, +.field.has-addons .control .select select:not([disabled]):focus, +.field.has-addons .control .select select:not([disabled]).is-focused, +.field.has-addons .control .select select:not([disabled]):active, +.field.has-addons .control .select select:not([disabled]).is-active { + z-index: 3; +} +.field.has-addons .control .button:not([disabled]):focus:hover, .field.has-addons .control .button:not([disabled]).is-focused:hover, .field.has-addons .control .button:not([disabled]):active:hover, .field.has-addons .control .button:not([disabled]).is-active:hover, +.field.has-addons .control .input:not([disabled]):focus:hover, +.field.has-addons .control .input:not([disabled]).is-focused:hover, +.field.has-addons .control .input:not([disabled]):active:hover, +.field.has-addons .control .input:not([disabled]).is-active:hover, +.field.has-addons .control .select select:not([disabled]):focus:hover, +.field.has-addons .control .select select:not([disabled]).is-focused:hover, +.field.has-addons .control .select select:not([disabled]):active:hover, +.field.has-addons .control .select select:not([disabled]).is-active:hover { + z-index: 4; +} +.field.has-addons .control.is-expanded { + flex-grow: 1; + flex-shrink: 1; +} +.field.has-addons.has-addons-centered { + justify-content: center; +} +.field.has-addons.has-addons-right { + justify-content: flex-end; +} +.field.has-addons.has-addons-fullwidth .control { + flex-grow: 1; + flex-shrink: 0; +} +.field.is-grouped { + display: flex; + gap: 0.75rem; + justify-content: flex-start; +} +.field.is-grouped > .control { + flex-shrink: 0; +} +.field.is-grouped > .control.is-expanded { + flex-grow: 1; + flex-shrink: 1; +} +.field.is-grouped.is-grouped-centered { + justify-content: center; +} +.field.is-grouped.is-grouped-right { + justify-content: flex-end; +} +.field.is-grouped.is-grouped-multiline { + flex-wrap: wrap; +} +@media screen and (min-width: 769px), print { + .field.is-horizontal { + display: flex; + } +} + +.field-label .label { + font-size: inherit; +} +@media screen and (max-width: 768px) { + .field-label { + margin-bottom: 0.5rem; + } +} +@media screen and (min-width: 769px), print { + .field-label { + flex-basis: 0; + flex-grow: 1; + flex-shrink: 0; + margin-inline-end: 1.5rem; + text-align: right; + } + .field-label.is-small { + font-size: var(--bulma-size-small); + padding-top: 0.375em; + } + .field-label.is-normal { + padding-top: 0.375em; + } + .field-label.is-medium { + font-size: var(--bulma-size-medium); + padding-top: 0.375em; + } + .field-label.is-large { + font-size: var(--bulma-size-large); + padding-top: 0.375em; + } +} + +.field-body .field .field { + margin-bottom: 0; +} +@media screen and (min-width: 769px), print { + .field-body { + display: flex; + flex-basis: 0; + flex-grow: 5; + flex-shrink: 1; + } + .field-body .field { + margin-bottom: 0; + } + .field-body > .field { + flex-shrink: 1; + } + .field-body > .field:not(.is-narrow) { + flex-grow: 1; + } + .field-body > .field:not(:last-child) { + margin-inline-end: 0.75rem; + } +} + +.control { + box-sizing: border-box; + clear: both; + font-size: var(--bulma-size-normal); + position: relative; + text-align: inherit; +} +.control.has-icons-left .input:hover ~ .icon, +.control.has-icons-left .select:hover ~ .icon, .control.has-icons-right .input:hover ~ .icon, +.control.has-icons-right .select:hover ~ .icon { + color: var(--bulma-input-icon-hover-color); +} +.control.has-icons-left .input:focus ~ .icon, +.control.has-icons-left .select:focus ~ .icon, .control.has-icons-right .input:focus ~ .icon, +.control.has-icons-right .select:focus ~ .icon { + color: var(--bulma-input-icon-focus-color); +} +.control.has-icons-left .input.is-small ~ .icon, +.control.has-icons-left .select.is-small ~ .icon, .control.has-icons-right .input.is-small ~ .icon, +.control.has-icons-right .select.is-small ~ .icon { + font-size: var(--bulma-size-small); +} +.control.has-icons-left .input.is-medium ~ .icon, +.control.has-icons-left .select.is-medium ~ .icon, .control.has-icons-right .input.is-medium ~ .icon, +.control.has-icons-right .select.is-medium ~ .icon { + font-size: var(--bulma-size-medium); +} +.control.has-icons-left .input.is-large ~ .icon, +.control.has-icons-left .select.is-large ~ .icon, .control.has-icons-right .input.is-large ~ .icon, +.control.has-icons-right .select.is-large ~ .icon { + font-size: var(--bulma-size-large); +} +.control.has-icons-left .icon, .control.has-icons-right .icon { + color: var(--bulma-input-icon-color); + height: var(--bulma-input-height); + pointer-events: none; + position: absolute; + top: 0; + width: var(--bulma-input-height); + z-index: 4; +} +.control.has-icons-left .input, +.control.has-icons-left .select select { + padding-left: var(--bulma-input-height); +} +.control.has-icons-left .icon.is-left { + left: 0; +} +.control.has-icons-right .input, +.control.has-icons-right .select select { + padding-right: var(--bulma-input-height); +} +.control.has-icons-right .icon.is-right { + right: 0; +} +.control.is-loading::after { + inset-inline-end: 0.75em; + position: absolute !important; + top: 0.75em; + z-index: 4; +} +.control.is-loading.is-small:after { + font-size: var(--bulma-size-small); +} +.control.is-loading.is-medium:after { + font-size: var(--bulma-size-medium); +} +.control.is-loading.is-large:after { + font-size: var(--bulma-size-large); +} + +/* Bulma Components */ +.breadcrumb { + --bulma-breadcrumb-item-color: var(--bulma-link-text); + --bulma-breadcrumb-item-hover-color: var(--bulma-link-text-hover); + --bulma-breadcrumb-item-active-color: var(--bulma-link-text-active); + --bulma-breadcrumb-item-padding-vertical: 0; + --bulma-breadcrumb-item-padding-horizontal: 0.75em; + --bulma-breadcrumb-item-separator-color: var(--bulma-border); +} + +.breadcrumb { + font-size: var(--bulma-size-normal); + white-space: nowrap; +} +.breadcrumb a { + align-items: center; + color: var(--bulma-breadcrumb-item-color); + display: flex; + justify-content: center; + padding: var(--bulma-breadcrumb-item-padding-vertical) var(--bulma-breadcrumb-item-padding-horizontal); +} +.breadcrumb a:hover { + color: var(--bulma-breadcrumb-item-hover-color); +} +.breadcrumb li { + align-items: center; + display: flex; +} +.breadcrumb li:first-child a { + padding-inline-start: 0; +} +.breadcrumb li.is-active a { + color: var(--bulma-breadcrumb-item-active-color); + cursor: default; + pointer-events: none; +} +.breadcrumb li + li::before { + color: var(--bulma-breadcrumb-item-separator-color); + content: "/"; +} +.breadcrumb ul, +.breadcrumb ol { + align-items: flex-start; + display: flex; + flex-wrap: wrap; + justify-content: flex-start; +} +.breadcrumb .icon:first-child { + margin-inline-end: 0.5em; +} +.breadcrumb .icon:last-child { + margin-inline-start: 0.5em; +} +.breadcrumb.is-centered ol, +.breadcrumb.is-centered ul { + justify-content: center; +} +.breadcrumb.is-right ol, +.breadcrumb.is-right ul { + justify-content: flex-end; +} +.breadcrumb.is-small { + font-size: var(--bulma-size-small); +} +.breadcrumb.is-medium { + font-size: var(--bulma-size-medium); +} +.breadcrumb.is-large { + font-size: var(--bulma-size-large); +} +.breadcrumb.has-arrow-separator li + li::before { + content: "→"; +} +.breadcrumb.has-bullet-separator li + li::before { + content: "•"; +} +.breadcrumb.has-dot-separator li + li::before { + content: "·"; +} +.breadcrumb.has-succeeds-separator li + li::before { + content: "≻"; +} + +.card { + --bulma-card-color: var(--bulma-text); + --bulma-card-background-color: var(--bulma-scheme-main); + --bulma-card-shadow: var(--bulma-shadow); + --bulma-card-radius: 0.75rem; + --bulma-card-header-background-color: transparent; + --bulma-card-header-color: var(--bulma-text-strong); + --bulma-card-header-padding: 0.75rem 1rem; + --bulma-card-header-shadow: 0 0.125em 0.25em hsla(var(--bulma-scheme-h), var(--bulma-scheme-s), var(--bulma-scheme-invert-l), 0.1); + --bulma-card-header-weight: var(--bulma-weight-bold); + --bulma-card-content-background-color: transparent; + --bulma-card-content-padding: 1.5rem; + --bulma-card-footer-background-color: transparent; + --bulma-card-footer-border-top: 1px solid var(--bulma-border-weak); + --bulma-card-footer-padding: 0.75rem; + --bulma-card-media-margin: var(--bulma-block-spacing); +} + +.card { + background-color: var(--bulma-card-background-color); + border-radius: var(--bulma-card-radius); + box-shadow: var(--bulma-card-shadow); + color: var(--bulma-card-color); + max-width: 100%; + position: relative; +} + +.card-footer:first-child, .card-content:first-child, .card-header:first-child { + border-start-start-radius: var(--bulma-card-radius); + border-start-end-radius: var(--bulma-card-radius); +} +.card-footer:last-child, .card-content:last-child, .card-header:last-child { + border-end-start-radius: var(--bulma-card-radius); + border-end-end-radius: var(--bulma-card-radius); +} + +.card-header { + background-color: var(--bulma-card-header-background-color); + align-items: stretch; + box-shadow: var(--bulma-card-header-shadow); + display: flex; +} + +.card-header-title { + align-items: center; + color: var(--bulma-card-header-color); + display: flex; + flex-grow: 1; + font-weight: var(--bulma-card-header-weight); + padding: var(--bulma-card-header-padding); +} +.card-header-title.is-centered { + justify-content: center; +} + +.card-header-icon { + appearance: none; + background: none; + border: none; + color: inherit; + font-family: inherit; + font-size: 1em; + margin: 0; + padding: 0; + align-items: center; + cursor: pointer; + display: flex; + justify-content: center; + padding: var(--bulma-card-header-padding); +} + +.card-image { + display: block; + position: relative; +} +.card-image:first-child img { + border-start-start-radius: var(--bulma-card-radius); + border-start-end-radius: var(--bulma-card-radius); +} +.card-image:last-child img { + border-end-start-radius: var(--bulma-card-radius); + border-end-end-radius: var(--bulma-card-radius); +} + +.card-content { + background-color: var(--bulma-card-content-background-color); + padding: var(--bulma-card-content-padding); +} + +.card-footer { + background-color: var(--bulma-card-footer-background-color); + border-top: var(--bulma-card-footer-border-top); + align-items: stretch; + display: flex; +} + +.card-footer-item { + align-items: center; + display: flex; + flex-basis: 0; + flex-grow: 1; + flex-shrink: 0; + justify-content: center; + padding: var(--bulma-card-footer-padding); +} +.card-footer-item:not(:last-child) { + border-inline-end: var(--bulma-card-footer-border-top); +} + +.card .media:not(:last-child) { + margin-bottom: var(--bulma-card-media-margin); +} + +.dropdown { + --bulma-dropdown-menu-min-width: 12rem; + --bulma-dropdown-content-background-color: var(--bulma-scheme-main); + --bulma-dropdown-content-offset: 0.25rem; + --bulma-dropdown-content-padding-bottom: 0.5rem; + --bulma-dropdown-content-padding-top: 0.5rem; + --bulma-dropdown-content-radius: var(--bulma-radius); + --bulma-dropdown-content-shadow: var(--bulma-shadow); + --bulma-dropdown-content-z: 20; + --bulma-dropdown-item-h: var(--bulma-scheme-h); + --bulma-dropdown-item-s: var(--bulma-scheme-s); + --bulma-dropdown-item-l: var(--bulma-scheme-main-l); + --bulma-dropdown-item-background-l: var(--bulma-scheme-main-l); + --bulma-dropdown-item-background-l-delta: 0%; + --bulma-dropdown-item-hover-background-l-delta: var(--bulma-hover-background-l-delta); + --bulma-dropdown-item-active-background-l-delta: var(--bulma-active-background-l-delta); + --bulma-dropdown-item-color-l: var(--bulma-text-strong-l); + --bulma-dropdown-item-selected-h: var(--bulma-link-h); + --bulma-dropdown-item-selected-s: var(--bulma-link-s); + --bulma-dropdown-item-selected-l: var(--bulma-link-l); + --bulma-dropdown-item-selected-background-l: var(--bulma-link-l); + --bulma-dropdown-item-selected-color-l: var(--bulma-link-invert-l); + --bulma-dropdown-divider-background-color: var(--bulma-border-weak); +} + +.dropdown { + display: inline-flex; + position: relative; + vertical-align: top; +} +.dropdown.is-active .dropdown-menu, .dropdown.is-hoverable:hover .dropdown-menu { + display: block; +} +.dropdown.is-right .dropdown-menu { + left: auto; + right: 0; +} +.dropdown.is-up .dropdown-menu { + bottom: 100%; + padding-bottom: var(--bulma-dropdown-content-offset); + padding-top: initial; + top: auto; +} + +.dropdown-menu { + display: none; + left: 0; + min-width: var(--bulma-dropdown-menu-min-width); + padding-top: var(--bulma-dropdown-content-offset); + position: absolute; + top: 100%; + z-index: var(--bulma-dropdown-content-z); +} + +.dropdown-content { + background-color: var(--bulma-dropdown-content-background-color); + border-radius: var(--bulma-dropdown-content-radius); + box-shadow: var(--bulma-dropdown-content-shadow); + padding-bottom: var(--bulma-dropdown-content-padding-bottom); + padding-top: var(--bulma-dropdown-content-padding-top); +} + +.dropdown-item { + color: hsl(var(--bulma-dropdown-item-h), var(--bulma-dropdown-item-s), var(--bulma-dropdown-item-color-l)); + display: block; + font-size: 0.875rem; + line-height: 1.5; + padding: 0.375rem 1rem; +} + +a.dropdown-item, +button.dropdown-item { + background-color: hsl(var(--bulma-dropdown-item-h), var(--bulma-dropdown-item-s), calc(var(--bulma-dropdown-item-background-l) + var(--bulma-dropdown-item-background-l-delta))); + padding-inline-end: 3rem; + text-align: inherit; + white-space: nowrap; + width: 100%; +} +a.dropdown-item:hover, +button.dropdown-item:hover { + --bulma-dropdown-item-background-l-delta: var(--bulma-dropdown-item-hover-background-l-delta); + --bulma-dropdown-item-border-l-delta: var(--bulma-dropdown-item-hover-border-l-delta); +} +a.dropdown-item:active, +button.dropdown-item:active { + --bulma-dropdown-item-background-l-delta: var(--bulma-dropdown-item-active-background-l-delta); + --bulma-dropdown-item-border-l-delta: var(--bulma-dropdown-item-active-border-l-delta); +} +a.dropdown-item.is-active, a.dropdown-item.is-selected, +button.dropdown-item.is-active, +button.dropdown-item.is-selected { + --bulma-dropdown-item-h: var(--bulma-dropdown-item-selected-h); + --bulma-dropdown-item-s: var(--bulma-dropdown-item-selected-s); + --bulma-dropdown-item-l: var(--bulma-dropdown-item-selected-l); + --bulma-dropdown-item-background-l: var(--bulma-dropdown-item-selected-background-l); + --bulma-dropdown-item-color-l: var(--bulma-dropdown-item-selected-color-l); +} + +.dropdown-divider { + background-color: var(--bulma-dropdown-divider-background-color); + border: none; + display: block; + height: 1px; + margin: 0.5rem 0; +} + +.menu { + --bulma-menu-item-h: var(--bulma-scheme-h); + --bulma-menu-item-s: var(--bulma-scheme-s); + --bulma-menu-item-l: var(--bulma-scheme-main-l); + --bulma-menu-item-background-l: var(--bulma-scheme-main-l); + --bulma-menu-item-background-l-delta: 0%; + --bulma-menu-item-hover-background-l-delta: var(--bulma-hover-background-l-delta); + --bulma-menu-item-active-background-l-delta: var(--bulma-active-background-l-delta); + --bulma-menu-item-color-l: var(--bulma-text-l); + --bulma-menu-item-radius: var(--bulma-radius-small); + --bulma-menu-item-selected-h: var(--bulma-link-h); + --bulma-menu-item-selected-s: var(--bulma-link-s); + --bulma-menu-item-selected-l: var(--bulma-link-l); + --bulma-menu-item-selected-background-l: var(--bulma-link-l); + --bulma-menu-item-selected-color-l: var(--bulma-link-invert-l); + --bulma-menu-list-border-left: 1px solid var(--bulma-border); + --bulma-menu-list-line-height: 1.25; + --bulma-menu-list-link-padding: 0.5em 0.75em; + --bulma-menu-nested-list-margin: 0.75em; + --bulma-menu-nested-list-padding-left: 0.75em; + --bulma-menu-label-color: var(--bulma-text-weak); + --bulma-menu-label-font-size: 0.75em; + --bulma-menu-label-letter-spacing: 0.1em; + --bulma-menu-label-spacing: 1em; +} + +.menu { + font-size: var(--bulma-size-normal); +} +.menu.is-small { + font-size: var(--bulma-size-small); +} +.menu.is-medium { + font-size: var(--bulma-size-medium); +} +.menu.is-large { + font-size: var(--bulma-size-large); +} + +.menu-list { + line-height: var(--bulma-menu-list-line-height); +} +.menu-list a, +.menu-list button, +.menu-list .menu-item { + background-color: hsl(var(--bulma-menu-item-h), var(--bulma-menu-item-s), calc(var(--bulma-menu-item-background-l) + var(--bulma-menu-item-background-l-delta))); + border-radius: var(--bulma-menu-item-radius); + color: hsl(var(--bulma-menu-item-h), var(--bulma-menu-item-s), var(--bulma-menu-item-color-l)); + display: block; + padding: var(--bulma-menu-list-link-padding); + text-align: left; + width: 100%; +} +.menu-list a:hover, +.menu-list button:hover, +.menu-list .menu-item:hover { + --bulma-menu-item-background-l-delta: var(--bulma-menu-item-hover-background-l-delta); +} +.menu-list a:active, +.menu-list button:active, +.menu-list .menu-item:active { + --bulma-menu-item-background-l-delta: var(--bulma-menu-item-active-background-l-delta); +} +.menu-list a.is-active, .menu-list a.is-selected, +.menu-list button.is-active, +.menu-list button.is-selected, +.menu-list .menu-item.is-active, +.menu-list .menu-item.is-selected { + --bulma-menu-item-h: var(--bulma-menu-item-selected-h); + --bulma-menu-item-s: var(--bulma-menu-item-selected-s); + --bulma-menu-item-l: var(--bulma-menu-item-selected-l); + --bulma-menu-item-background-l: var(--bulma-menu-item-selected-background-l); + --bulma-menu-item-color-l: var(--bulma-menu-item-selected-color-l); +} +.menu-list li ul { + border-inline-start: var(--bulma-menu-list-border-left); + margin: var(--bulma-menu-nested-list-margin); + padding-inline-start: var(--bulma-menu-nested-list-padding-left); +} + +.menu-label { + color: var(--bulma-menu-label-color); + font-size: var(--bulma-menu-label-font-size); + letter-spacing: var(--bulma-menu-label-letter-spacing); + text-transform: uppercase; +} +.menu-label:not(:first-child) { + margin-top: var(--bulma-menu-label-spacing); +} +.menu-label:not(:last-child) { + margin-bottom: var(--bulma-menu-label-spacing); +} + +.message { + --bulma-message-border-l-delta: -20%; + --bulma-message-radius: var(--bulma-radius); + --bulma-message-header-weight: var(--bulma-weight-semibold); + --bulma-message-header-padding: 1em 1.25em; + --bulma-message-header-radius: var(--bulma-radius); + --bulma-message-body-border-width: 0 0 0 4px; + --bulma-message-body-color: var(--bulma-text); + --bulma-message-body-padding: 1.25em 1.5em; + --bulma-message-body-radius: var(--bulma-radius-small); + --bulma-message-body-pre-code-background-color: transparent; + --bulma-message-header-body-border-width: 0; + --bulma-message-h: var(--bulma-scheme-h); + --bulma-message-s: var(--bulma-scheme-s); + --bulma-message-background-l: var(--bulma-background-l); + --bulma-message-border-l: var(--bulma-border-l); + --bulma-message-border-style: solid; + --bulma-message-border-width: 0.25em; + --bulma-message-color-l: var(--bulma-text-l); + --bulma-message-header-background-l: var(--bulma-dark-l); + --bulma-message-header-color-l: var(--bulma-text-dark-invert-l); +} + +.message { + border-radius: var(--bulma-message-radius); + color: hsl(var(--bulma-message-h), var(--bulma-message-s), var(--bulma-message-color-l)); + font-size: var(--bulma-size-normal); +} +.message strong { + color: currentColor; +} +.message a:not(.button):not(.tag):not(.dropdown-item) { + color: currentColor; + text-decoration: underline; +} +.message.is-small { + font-size: var(--bulma-size-small); +} +.message.is-medium { + font-size: var(--bulma-size-medium); +} +.message.is-large { + font-size: var(--bulma-size-large); +} +.message.is-white { + --bulma-message-h: var(--bulma-white-h); + --bulma-message-s: var(--bulma-white-s); + --bulma-message-border-l: calc(var(--bulma-white-l) + var(--bulma-message-border-l-delta)); + --bulma-message-color-l: var(--bulma-white-on-scheme-l); + --bulma-message-header-background-l: var(--bulma-white-l); + --bulma-message-header-color-l: var(--bulma-white-invert-l); +} +.message.is-black { + --bulma-message-h: var(--bulma-black-h); + --bulma-message-s: var(--bulma-black-s); + --bulma-message-border-l: calc(var(--bulma-black-l) + var(--bulma-message-border-l-delta)); + --bulma-message-color-l: var(--bulma-black-on-scheme-l); + --bulma-message-header-background-l: var(--bulma-black-l); + --bulma-message-header-color-l: var(--bulma-black-invert-l); +} +.message.is-light { + --bulma-message-h: var(--bulma-light-h); + --bulma-message-s: var(--bulma-light-s); + --bulma-message-border-l: calc(var(--bulma-light-l) + var(--bulma-message-border-l-delta)); + --bulma-message-color-l: var(--bulma-light-on-scheme-l); + --bulma-message-header-background-l: var(--bulma-light-l); + --bulma-message-header-color-l: var(--bulma-light-invert-l); +} +.message.is-dark { + --bulma-message-h: var(--bulma-dark-h); + --bulma-message-s: var(--bulma-dark-s); + --bulma-message-border-l: calc(var(--bulma-dark-l) + var(--bulma-message-border-l-delta)); + --bulma-message-color-l: var(--bulma-dark-on-scheme-l); + --bulma-message-header-background-l: var(--bulma-dark-l); + --bulma-message-header-color-l: var(--bulma-dark-invert-l); +} +.message.is-text { + --bulma-message-h: var(--bulma-text-h); + --bulma-message-s: var(--bulma-text-s); + --bulma-message-border-l: calc(var(--bulma-text-l) + var(--bulma-message-border-l-delta)); + --bulma-message-color-l: var(--bulma-text-on-scheme-l); + --bulma-message-header-background-l: var(--bulma-text-l); + --bulma-message-header-color-l: var(--bulma-text-invert-l); +} +.message.is-primary { + --bulma-message-h: var(--bulma-primary-h); + --bulma-message-s: var(--bulma-primary-s); + --bulma-message-border-l: calc(var(--bulma-primary-l) + var(--bulma-message-border-l-delta)); + --bulma-message-color-l: var(--bulma-primary-on-scheme-l); + --bulma-message-header-background-l: var(--bulma-primary-l); + --bulma-message-header-color-l: var(--bulma-primary-invert-l); +} +.message.is-link { + --bulma-message-h: var(--bulma-link-h); + --bulma-message-s: var(--bulma-link-s); + --bulma-message-border-l: calc(var(--bulma-link-l) + var(--bulma-message-border-l-delta)); + --bulma-message-color-l: var(--bulma-link-on-scheme-l); + --bulma-message-header-background-l: var(--bulma-link-l); + --bulma-message-header-color-l: var(--bulma-link-invert-l); +} +.message.is-info { + --bulma-message-h: var(--bulma-info-h); + --bulma-message-s: var(--bulma-info-s); + --bulma-message-border-l: calc(var(--bulma-info-l) + var(--bulma-message-border-l-delta)); + --bulma-message-color-l: var(--bulma-info-on-scheme-l); + --bulma-message-header-background-l: var(--bulma-info-l); + --bulma-message-header-color-l: var(--bulma-info-invert-l); +} +.message.is-success { + --bulma-message-h: var(--bulma-success-h); + --bulma-message-s: var(--bulma-success-s); + --bulma-message-border-l: calc(var(--bulma-success-l) + var(--bulma-message-border-l-delta)); + --bulma-message-color-l: var(--bulma-success-on-scheme-l); + --bulma-message-header-background-l: var(--bulma-success-l); + --bulma-message-header-color-l: var(--bulma-success-invert-l); +} +.message.is-warning { + --bulma-message-h: var(--bulma-warning-h); + --bulma-message-s: var(--bulma-warning-s); + --bulma-message-border-l: calc(var(--bulma-warning-l) + var(--bulma-message-border-l-delta)); + --bulma-message-color-l: var(--bulma-warning-on-scheme-l); + --bulma-message-header-background-l: var(--bulma-warning-l); + --bulma-message-header-color-l: var(--bulma-warning-invert-l); +} +.message.is-danger { + --bulma-message-h: var(--bulma-danger-h); + --bulma-message-s: var(--bulma-danger-s); + --bulma-message-border-l: calc(var(--bulma-danger-l) + var(--bulma-message-border-l-delta)); + --bulma-message-color-l: var(--bulma-danger-on-scheme-l); + --bulma-message-header-background-l: var(--bulma-danger-l); + --bulma-message-header-color-l: var(--bulma-danger-invert-l); +} + +.message-header { + align-items: center; + background-color: hsl(var(--bulma-message-h), var(--bulma-message-s), var(--bulma-message-header-background-l)); + border-start-start-radius: var(--bulma-message-header-radius); + border-start-end-radius: var(--bulma-message-header-radius); + color: hsl(var(--bulma-message-h), var(--bulma-message-s), var(--bulma-message-header-color-l)); + display: flex; + font-weight: var(--bulma-message-header-weight); + justify-content: space-between; + line-height: 1.25; + padding: var(--bulma-message-header-padding); + position: relative; +} +.message-header .delete { + flex-grow: 0; + flex-shrink: 0; + margin-inline-start: 0.75em; +} +.message-header + .message-body { + border-width: var(--bulma-message-header-body-border-width); + border-start-start-radius: 0; + border-start-end-radius: 0; +} + +.message-body { + background-color: hsl(var(--bulma-message-h), var(--bulma-message-s), var(--bulma-message-background-l)); + border-inline-start-color: hsl(var(--bulma-message-h), var(--bulma-message-s), var(--bulma-message-border-l)); + border-inline-start-style: var(--bulma-message-border-style); + border-inline-start-width: var(--bulma-message-border-width); + border-radius: var(--bulma-message-body-radius); + padding: var(--bulma-message-body-padding); +} +.message-body code, +.message-body pre { + background-color: hsl(var(--bulma-message-h), var(--bulma-message-s), var(--bulma-message-header-color-l)); + color: hsl(var(--bulma-message-h), var(--bulma-message-s), var(--bulma-message-header-background-l)); +} +.message-body pre code { + background-color: var(--bulma-message-body-pre-code-background-color); +} + +.modal { + --bulma-modal-z: 40; + --bulma-modal-background-background-color: hsla(var(--bulma-scheme-h), var(--bulma-scheme-s), var(--bulma-scheme-invert-l), 0.86); + --bulma-modal-content-width: 40rem; + --bulma-modal-content-margin-mobile: 1.25rem; + --bulma-modal-content-spacing-mobile: 10rem; + --bulma-modal-content-spacing-tablet: 2.5rem; + --bulma-modal-close-dimensions: 2.5rem; + --bulma-modal-close-right: 1.25rem; + --bulma-modal-close-top: 1.25rem; + --bulma-modal-card-spacing: 2.5rem; + --bulma-modal-card-head-background-color: var(--bulma-scheme-main); + --bulma-modal-card-head-padding: 2rem; + --bulma-modal-card-head-radius: var(--bulma-radius-large); + --bulma-modal-card-title-color: var(--bulma-text-strong); + --bulma-modal-card-title-line-height: 1; + --bulma-modal-card-title-size: var(--bulma-size-4); + --bulma-modal-card-foot-background-color: var(--bulma-scheme-main-bis); + --bulma-modal-card-foot-radius: var(--bulma-radius-large); + --bulma-modal-card-body-background-color: var(--bulma-scheme-main); + --bulma-modal-card-body-padding: 2rem; +} + +.modal { + align-items: center; + display: none; + flex-direction: column; + justify-content: center; + overflow: hidden; + position: fixed; + z-index: var(--bulma-modal-z); +} +.modal.is-active { + display: flex; +} + +.modal-background { + background-color: var(--bulma-modal-background-background-color); +} + +.modal-content, +.modal-card { + margin: 0 var(--bulma-modal-content-margin-mobile); + max-height: calc(100vh - var(--bulma-modal-content-spacing-mobile)); + overflow: auto; + position: relative; + width: 100%; +} +@media screen and (min-width: 769px) { + .modal-content, + .modal-card { + margin: 0 auto; + max-height: calc(100vh - var(--bulma-modal-content-spacing-tablet)); + width: var(--bulma-modal-content-width); + } +} + +.modal-close { + background: none; + height: var(--bulma-modal-close-dimensions); + inset-inline-end: var(--bulma-modal-close-right); + position: fixed; + top: var(--bulma-modal-close-top); + width: var(--bulma-modal-close-dimensions); +} + +.modal-card { + display: flex; + flex-direction: column; + max-height: calc(100vh - var(--bulma-modal-card-spacing)); + overflow: hidden; + overflow-y: visible; +} + +.modal-card-head, +.modal-card-foot { + align-items: center; + display: flex; + flex-shrink: 0; + justify-content: flex-start; + padding: var(--bulma-modal-card-head-padding); + position: relative; +} + +.modal-card-head { + background-color: var(--bulma-modal-card-head-background-color); + border-start-start-radius: var(--bulma-modal-card-head-radius); + border-start-end-radius: var(--bulma-modal-card-head-radius); + box-shadow: var(--bulma-shadow); +} + +.modal-card-title { + color: var(--bulma-modal-card-title-color); + flex-grow: 1; + flex-shrink: 0; + font-size: var(--bulma-modal-card-title-size); + line-height: var(--bulma-modal-card-title-line-height); +} + +.modal-card-foot { + background-color: var(--bulma-modal-card-foot-background-color); + border-end-start-radius: var(--bulma-modal-card-foot-radius); + border-end-end-radius: var(--bulma-modal-card-foot-radius); +} + +.modal-card-body { + -webkit-overflow-scrolling: touch; + background-color: var(--bulma-modal-card-body-background-color); + flex-grow: 1; + flex-shrink: 1; + overflow: auto; + padding: var(--bulma-modal-card-body-padding); +} + +:root { + --bulma-navbar-height: 3.25rem; +} + +.navbar { + --bulma-navbar-h: var(--bulma-scheme-h); + --bulma-navbar-s: var(--bulma-scheme-s); + --bulma-navbar-l: var(--bulma-scheme-main-l); + --bulma-navbar-background-color: var(--bulma-scheme-main); + --bulma-navbar-box-shadow-size: 0 0.125em 0 0; + --bulma-navbar-box-shadow-color: var(--bulma-background); + --bulma-navbar-padding-vertical: 1rem; + --bulma-navbar-padding-horizontal: 2rem; + --bulma-navbar-z: 30; + --bulma-navbar-fixed-z: 30; + --bulma-navbar-item-background-a: 0; + --bulma-navbar-item-background-l: var(--bulma-scheme-main-l); + --bulma-navbar-item-background-l-delta: 0%; + --bulma-navbar-item-hover-background-l-delta: var(--bulma-hover-background-l-delta); + --bulma-navbar-item-active-background-l-delta: var(--bulma-active-background-l-delta); + --bulma-navbar-item-color-l: var(--bulma-text-l); + --bulma-navbar-item-color: hsl(var(--bulma-navbar-h), var(--bulma-navbar-s), var(--bulma-navbar-item-color-l)); + --bulma-navbar-item-selected-h: var(--bulma-link-h); + --bulma-navbar-item-selected-s: var(--bulma-link-s); + --bulma-navbar-item-selected-l: var(--bulma-link-l); + --bulma-navbar-item-selected-background-l: var(--bulma-link-l); + --bulma-navbar-item-selected-color-l: var(--bulma-link-invert-l); + --bulma-navbar-item-img-max-height: 1.75rem; + --bulma-navbar-burger-color: var(--bulma-link); + --bulma-navbar-tab-hover-background-color: transparent; + --bulma-navbar-tab-hover-border-bottom-color: var(--bulma-link); + --bulma-navbar-tab-active-color: var(--bulma-link); + --bulma-navbar-tab-active-background-color: transparent; + --bulma-navbar-tab-active-border-bottom-color: var(--bulma-link); + --bulma-navbar-tab-active-border-bottom-style: solid; + --bulma-navbar-tab-active-border-bottom-width: 0.1875em; + --bulma-navbar-dropdown-background-color: var(--bulma-scheme-main); + --bulma-navbar-dropdown-border-l: var(--bulma-border-l); + --bulma-navbar-dropdown-border-color: hsl(var(--bulma-navbar-h), var(--bulma-navbar-s), var(--bulma-navbar-dropdown-border-l)); + --bulma-navbar-dropdown-border-style: solid; + --bulma-navbar-dropdown-border-width: 0.125em; + --bulma-navbar-dropdown-offset: -0.25em; + --bulma-navbar-dropdown-arrow: var(--bulma-link); + --bulma-navbar-dropdown-radius: var(--bulma-radius-large); + --bulma-navbar-dropdown-z: 20; + --bulma-navbar-dropdown-boxed-radius: var(--bulma-radius-large); + --bulma-navbar-dropdown-boxed-shadow: 0 0.5em 0.5em hsla(var(--bulma-scheme-h), var(--bulma-scheme-s), var(--bulma-scheme-invert-l), 0.1), 0 0 0 1px hsla(var(--bulma-scheme-h), var(--bulma-scheme-s), var(--bulma-scheme-invert-l), 0.1); + --bulma-navbar-dropdown-item-h: var(--bulma-scheme-h); + --bulma-navbar-dropdown-item-s: var(--bulma-scheme-s); + --bulma-navbar-dropdown-item-l: var(--bulma-scheme-main-l); + --bulma-navbar-dropdown-item-background-l: var(--bulma-scheme-main-l); + --bulma-navbar-dropdown-item-color-l: var(--bulma-text-l); + --bulma-navbar-divider-background-l: var(--bulma-background-l); + --bulma-navbar-divider-height: 0.125em; + --bulma-navbar-bottom-box-shadow-size: 0 -0.125em 0 0; +} + +.navbar { + background-color: var(--bulma-navbar-background-color); + min-height: var(--bulma-navbar-height); + position: relative; + z-index: var(--bulma-navbar-z); +} +.navbar.is-white { + --bulma-navbar-h: var(--bulma-white-h); + --bulma-navbar-s: var(--bulma-white-s); + --bulma-navbar-l: var(--bulma-white-l); + --bulma-burger-h: var(--bulma-white-h); + --bulma-burger-s: var(--bulma-white-s); + --bulma-burger-l: var(--bulma-white-invert-l); + --bulma-navbar-background-color: var(--bulma-white); + --bulma-navbar-item-background-l: var(--bulma-white-l); + --bulma-navbar-item-color-l: var(--bulma-white-invert-l); + --bulma-navbar-item-selected-h: var(--bulma-white-h); + --bulma-navbar-item-selected-s: var(--bulma-white-s); + --bulma-navbar-item-selected-l: var(--bulma-white-l); + --bulma-navbar-item-selected-background-l: var(--bulma-white-l); + --bulma-navbar-item-selected-color-l: var(--bulma-white-invert-l); + --bulma-navbar-dropdown-arrow: var(--bulma-white-invert-l); + --bulma-navbar-dropdown-background-color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-navbar-dropdown-item-background-l)); + --bulma-navbar-dropdown-item-h: var(--bulma-white-h); + --bulma-navbar-dropdown-item-s: var(--bulma-white-s); +} +.navbar.is-black { + --bulma-navbar-h: var(--bulma-black-h); + --bulma-navbar-s: var(--bulma-black-s); + --bulma-navbar-l: var(--bulma-black-l); + --bulma-burger-h: var(--bulma-black-h); + --bulma-burger-s: var(--bulma-black-s); + --bulma-burger-l: var(--bulma-black-invert-l); + --bulma-navbar-background-color: var(--bulma-black); + --bulma-navbar-item-background-l: var(--bulma-black-l); + --bulma-navbar-item-color-l: var(--bulma-black-invert-l); + --bulma-navbar-item-selected-h: var(--bulma-black-h); + --bulma-navbar-item-selected-s: var(--bulma-black-s); + --bulma-navbar-item-selected-l: var(--bulma-black-l); + --bulma-navbar-item-selected-background-l: var(--bulma-black-l); + --bulma-navbar-item-selected-color-l: var(--bulma-black-invert-l); + --bulma-navbar-dropdown-arrow: var(--bulma-black-invert-l); + --bulma-navbar-dropdown-background-color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-navbar-dropdown-item-background-l)); + --bulma-navbar-dropdown-item-h: var(--bulma-black-h); + --bulma-navbar-dropdown-item-s: var(--bulma-black-s); +} +.navbar.is-light { + --bulma-navbar-h: var(--bulma-light-h); + --bulma-navbar-s: var(--bulma-light-s); + --bulma-navbar-l: var(--bulma-light-l); + --bulma-burger-h: var(--bulma-light-h); + --bulma-burger-s: var(--bulma-light-s); + --bulma-burger-l: var(--bulma-light-invert-l); + --bulma-navbar-background-color: var(--bulma-light); + --bulma-navbar-item-background-l: var(--bulma-light-l); + --bulma-navbar-item-color-l: var(--bulma-light-invert-l); + --bulma-navbar-item-selected-h: var(--bulma-light-h); + --bulma-navbar-item-selected-s: var(--bulma-light-s); + --bulma-navbar-item-selected-l: var(--bulma-light-l); + --bulma-navbar-item-selected-background-l: var(--bulma-light-l); + --bulma-navbar-item-selected-color-l: var(--bulma-light-invert-l); + --bulma-navbar-dropdown-arrow: var(--bulma-light-invert-l); + --bulma-navbar-dropdown-background-color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-navbar-dropdown-item-background-l)); + --bulma-navbar-dropdown-item-h: var(--bulma-light-h); + --bulma-navbar-dropdown-item-s: var(--bulma-light-s); +} +.navbar.is-dark { + --bulma-navbar-h: var(--bulma-dark-h); + --bulma-navbar-s: var(--bulma-dark-s); + --bulma-navbar-l: var(--bulma-dark-l); + --bulma-burger-h: var(--bulma-dark-h); + --bulma-burger-s: var(--bulma-dark-s); + --bulma-burger-l: var(--bulma-dark-invert-l); + --bulma-navbar-background-color: var(--bulma-dark); + --bulma-navbar-item-background-l: var(--bulma-dark-l); + --bulma-navbar-item-color-l: var(--bulma-dark-invert-l); + --bulma-navbar-item-selected-h: var(--bulma-dark-h); + --bulma-navbar-item-selected-s: var(--bulma-dark-s); + --bulma-navbar-item-selected-l: var(--bulma-dark-l); + --bulma-navbar-item-selected-background-l: var(--bulma-dark-l); + --bulma-navbar-item-selected-color-l: var(--bulma-dark-invert-l); + --bulma-navbar-dropdown-arrow: var(--bulma-dark-invert-l); + --bulma-navbar-dropdown-background-color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-navbar-dropdown-item-background-l)); + --bulma-navbar-dropdown-item-h: var(--bulma-dark-h); + --bulma-navbar-dropdown-item-s: var(--bulma-dark-s); +} +.navbar.is-text { + --bulma-navbar-h: var(--bulma-text-h); + --bulma-navbar-s: var(--bulma-text-s); + --bulma-navbar-l: var(--bulma-text-l); + --bulma-burger-h: var(--bulma-text-h); + --bulma-burger-s: var(--bulma-text-s); + --bulma-burger-l: var(--bulma-text-invert-l); + --bulma-navbar-background-color: var(--bulma-text); + --bulma-navbar-item-background-l: var(--bulma-text-l); + --bulma-navbar-item-color-l: var(--bulma-text-invert-l); + --bulma-navbar-item-selected-h: var(--bulma-text-h); + --bulma-navbar-item-selected-s: var(--bulma-text-s); + --bulma-navbar-item-selected-l: var(--bulma-text-l); + --bulma-navbar-item-selected-background-l: var(--bulma-text-l); + --bulma-navbar-item-selected-color-l: var(--bulma-text-invert-l); + --bulma-navbar-dropdown-arrow: var(--bulma-text-invert-l); + --bulma-navbar-dropdown-background-color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-navbar-dropdown-item-background-l)); + --bulma-navbar-dropdown-item-h: var(--bulma-text-h); + --bulma-navbar-dropdown-item-s: var(--bulma-text-s); +} +.navbar.is-primary { + --bulma-navbar-h: var(--bulma-primary-h); + --bulma-navbar-s: var(--bulma-primary-s); + --bulma-navbar-l: var(--bulma-primary-l); + --bulma-burger-h: var(--bulma-primary-h); + --bulma-burger-s: var(--bulma-primary-s); + --bulma-burger-l: var(--bulma-primary-invert-l); + --bulma-navbar-background-color: var(--bulma-primary); + --bulma-navbar-item-background-l: var(--bulma-primary-l); + --bulma-navbar-item-color-l: var(--bulma-primary-invert-l); + --bulma-navbar-item-selected-h: var(--bulma-primary-h); + --bulma-navbar-item-selected-s: var(--bulma-primary-s); + --bulma-navbar-item-selected-l: var(--bulma-primary-l); + --bulma-navbar-item-selected-background-l: var(--bulma-primary-l); + --bulma-navbar-item-selected-color-l: var(--bulma-primary-invert-l); + --bulma-navbar-dropdown-arrow: var(--bulma-primary-invert-l); + --bulma-navbar-dropdown-background-color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-navbar-dropdown-item-background-l)); + --bulma-navbar-dropdown-item-h: var(--bulma-primary-h); + --bulma-navbar-dropdown-item-s: var(--bulma-primary-s); +} +.navbar.is-link { + --bulma-navbar-h: var(--bulma-link-h); + --bulma-navbar-s: var(--bulma-link-s); + --bulma-navbar-l: var(--bulma-link-l); + --bulma-burger-h: var(--bulma-link-h); + --bulma-burger-s: var(--bulma-link-s); + --bulma-burger-l: var(--bulma-link-invert-l); + --bulma-navbar-background-color: var(--bulma-link); + --bulma-navbar-item-background-l: var(--bulma-link-l); + --bulma-navbar-item-color-l: var(--bulma-link-invert-l); + --bulma-navbar-item-selected-h: var(--bulma-link-h); + --bulma-navbar-item-selected-s: var(--bulma-link-s); + --bulma-navbar-item-selected-l: var(--bulma-link-l); + --bulma-navbar-item-selected-background-l: var(--bulma-link-l); + --bulma-navbar-item-selected-color-l: var(--bulma-link-invert-l); + --bulma-navbar-dropdown-arrow: var(--bulma-link-invert-l); + --bulma-navbar-dropdown-background-color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-navbar-dropdown-item-background-l)); + --bulma-navbar-dropdown-item-h: var(--bulma-link-h); + --bulma-navbar-dropdown-item-s: var(--bulma-link-s); +} +.navbar.is-info { + --bulma-navbar-h: var(--bulma-info-h); + --bulma-navbar-s: var(--bulma-info-s); + --bulma-navbar-l: var(--bulma-info-l); + --bulma-burger-h: var(--bulma-info-h); + --bulma-burger-s: var(--bulma-info-s); + --bulma-burger-l: var(--bulma-info-invert-l); + --bulma-navbar-background-color: var(--bulma-info); + --bulma-navbar-item-background-l: var(--bulma-info-l); + --bulma-navbar-item-color-l: var(--bulma-info-invert-l); + --bulma-navbar-item-selected-h: var(--bulma-info-h); + --bulma-navbar-item-selected-s: var(--bulma-info-s); + --bulma-navbar-item-selected-l: var(--bulma-info-l); + --bulma-navbar-item-selected-background-l: var(--bulma-info-l); + --bulma-navbar-item-selected-color-l: var(--bulma-info-invert-l); + --bulma-navbar-dropdown-arrow: var(--bulma-info-invert-l); + --bulma-navbar-dropdown-background-color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-navbar-dropdown-item-background-l)); + --bulma-navbar-dropdown-item-h: var(--bulma-info-h); + --bulma-navbar-dropdown-item-s: var(--bulma-info-s); +} +.navbar.is-success { + --bulma-navbar-h: var(--bulma-success-h); + --bulma-navbar-s: var(--bulma-success-s); + --bulma-navbar-l: var(--bulma-success-l); + --bulma-burger-h: var(--bulma-success-h); + --bulma-burger-s: var(--bulma-success-s); + --bulma-burger-l: var(--bulma-success-invert-l); + --bulma-navbar-background-color: var(--bulma-success); + --bulma-navbar-item-background-l: var(--bulma-success-l); + --bulma-navbar-item-color-l: var(--bulma-success-invert-l); + --bulma-navbar-item-selected-h: var(--bulma-success-h); + --bulma-navbar-item-selected-s: var(--bulma-success-s); + --bulma-navbar-item-selected-l: var(--bulma-success-l); + --bulma-navbar-item-selected-background-l: var(--bulma-success-l); + --bulma-navbar-item-selected-color-l: var(--bulma-success-invert-l); + --bulma-navbar-dropdown-arrow: var(--bulma-success-invert-l); + --bulma-navbar-dropdown-background-color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-navbar-dropdown-item-background-l)); + --bulma-navbar-dropdown-item-h: var(--bulma-success-h); + --bulma-navbar-dropdown-item-s: var(--bulma-success-s); +} +.navbar.is-warning { + --bulma-navbar-h: var(--bulma-warning-h); + --bulma-navbar-s: var(--bulma-warning-s); + --bulma-navbar-l: var(--bulma-warning-l); + --bulma-burger-h: var(--bulma-warning-h); + --bulma-burger-s: var(--bulma-warning-s); + --bulma-burger-l: var(--bulma-warning-invert-l); + --bulma-navbar-background-color: var(--bulma-warning); + --bulma-navbar-item-background-l: var(--bulma-warning-l); + --bulma-navbar-item-color-l: var(--bulma-warning-invert-l); + --bulma-navbar-item-selected-h: var(--bulma-warning-h); + --bulma-navbar-item-selected-s: var(--bulma-warning-s); + --bulma-navbar-item-selected-l: var(--bulma-warning-l); + --bulma-navbar-item-selected-background-l: var(--bulma-warning-l); + --bulma-navbar-item-selected-color-l: var(--bulma-warning-invert-l); + --bulma-navbar-dropdown-arrow: var(--bulma-warning-invert-l); + --bulma-navbar-dropdown-background-color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-navbar-dropdown-item-background-l)); + --bulma-navbar-dropdown-item-h: var(--bulma-warning-h); + --bulma-navbar-dropdown-item-s: var(--bulma-warning-s); +} +.navbar.is-danger { + --bulma-navbar-h: var(--bulma-danger-h); + --bulma-navbar-s: var(--bulma-danger-s); + --bulma-navbar-l: var(--bulma-danger-l); + --bulma-burger-h: var(--bulma-danger-h); + --bulma-burger-s: var(--bulma-danger-s); + --bulma-burger-l: var(--bulma-danger-invert-l); + --bulma-navbar-background-color: var(--bulma-danger); + --bulma-navbar-item-background-l: var(--bulma-danger-l); + --bulma-navbar-item-color-l: var(--bulma-danger-invert-l); + --bulma-navbar-item-selected-h: var(--bulma-danger-h); + --bulma-navbar-item-selected-s: var(--bulma-danger-s); + --bulma-navbar-item-selected-l: var(--bulma-danger-l); + --bulma-navbar-item-selected-background-l: var(--bulma-danger-l); + --bulma-navbar-item-selected-color-l: var(--bulma-danger-invert-l); + --bulma-navbar-dropdown-arrow: var(--bulma-danger-invert-l); + --bulma-navbar-dropdown-background-color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-navbar-dropdown-item-background-l)); + --bulma-navbar-dropdown-item-h: var(--bulma-danger-h); + --bulma-navbar-dropdown-item-s: var(--bulma-danger-s); +} +.navbar > .container { + align-items: stretch; + display: flex; + min-height: var(--bulma-navbar-height); + width: 100%; +} +.navbar.has-shadow { + box-shadow: var(--bulma-navbar-box-shadow-size) var(--bulma-navbar-box-shadow-color); +} +.navbar.is-fixed-bottom, .navbar.is-fixed-top { + left: 0; + position: fixed; + right: 0; + z-index: var(--bulma-navbar-fixed-z); +} +.navbar.is-fixed-bottom { + bottom: 0; +} +.navbar.is-fixed-bottom.has-shadow { + box-shadow: var(--bulma-navbar-bottom-box-shadow-size) var(--bulma-navbar-box-shadow-color); +} +.navbar.is-fixed-top { + top: 0; +} + +html.has-navbar-fixed-top, +body.has-navbar-fixed-top { + padding-top: var(--bulma-navbar-height); +} +html.has-navbar-fixed-bottom, +body.has-navbar-fixed-bottom { + padding-bottom: var(--bulma-navbar-height); +} + +.navbar-brand, +.navbar-tabs { + align-items: stretch; + display: flex; + flex-shrink: 0; + min-height: var(--bulma-navbar-height); +} + +.navbar-tabs { + -webkit-overflow-scrolling: touch; + max-width: 100vw; + overflow-x: auto; + overflow-y: hidden; +} + +.navbar-burger { + align-items: center; + appearance: none; + background: none; + border: none; + border-radius: var(--bulma-burger-border-radius); + color: hsl(var(--bulma-burger-h), var(--bulma-burger-s), var(--bulma-burger-l)); + cursor: pointer; + display: inline-flex; + flex-direction: column; + flex-shrink: 0; + height: 2.5rem; + justify-content: center; + position: relative; + vertical-align: top; + width: 2.5rem; +} +.navbar-burger span { + background-color: currentColor; + display: block; + height: var(--bulma-burger-item-height); + left: calc(50% - (var(--bulma-burger-item-width)) / 2); + position: absolute; + transform-origin: center; + transition-duration: var(--bulma-duration); + transition-property: background-color, color, opacity, transform; + transition-timing-function: var(--bulma-easing); + width: var(--bulma-burger-item-width); +} +.navbar-burger span:nth-child(1), .navbar-burger span:nth-child(2) { + top: calc(50% - (var(--bulma-burger-item-height)) / 2); +} +.navbar-burger span:nth-child(3) { + bottom: calc(50% + var(--bulma-burger-gap)); +} +.navbar-burger span:nth-child(4) { + top: calc(50% + var(--bulma-burger-gap)); +} +.navbar-burger:hover { + background-color: hsla(var(--bulma-burger-h), var(--bulma-burger-s), var(--bulma-burger-l), 0.1); +} +.navbar-burger:active { + background-color: hsla(var(--bulma-burger-h), var(--bulma-burger-s), var(--bulma-burger-l), 0.2); +} +.navbar-burger.is-active span:nth-child(1) { + transform: rotate(-45deg); +} +.navbar-burger.is-active span:nth-child(2) { + transform: rotate(45deg); +} +.navbar-burger.is-active span:nth-child(3), .navbar-burger.is-active span:nth-child(4) { + opacity: 0; +} +.navbar-burger { + align-self: center; + color: var(--bulma-navbar-burger-color); + margin-inline-start: auto; + margin-inline-end: 0.375rem; +} + +.navbar-menu { + display: none; +} + +.navbar-item, +.navbar-link { + color: var(--bulma-navbar-item-color); + display: block; + gap: 0.75rem; + line-height: 1.5; + padding: 0.5rem 0.75rem; + position: relative; +} +.navbar-item .icon:only-child, +.navbar-link .icon:only-child { + margin-left: -0.25rem; + margin-right: -0.25rem; +} + +a.navbar-item, +.navbar-link { + background-color: hsla(var(--bulma-navbar-h), var(--bulma-navbar-s), calc(var(--bulma-navbar-item-background-l) + var(--bulma-navbar-item-background-l-delta)), var(--bulma-navbar-item-background-a)); + cursor: pointer; +} +a.navbar-item:focus, a.navbar-item:focus-within, a.navbar-item:hover, +.navbar-link:focus, +.navbar-link:focus-within, +.navbar-link:hover { + --bulma-navbar-item-background-l-delta: var(--bulma-navbar-item-hover-background-l-delta); + --bulma-navbar-item-background-a: 1; +} +a.navbar-item:active, +.navbar-link:active { + --bulma-navbar-item-background-l-delta: var(--bulma-navbar-item-active-background-l-delta); + --bulma-navbar-item-background-a: 1; +} +a.navbar-item.is-active, a.navbar-item.is-selected, +.navbar-link.is-active, +.navbar-link.is-selected { + --bulma-navbar-h: var(--bulma-navbar-item-selected-h); + --bulma-navbar-s: var(--bulma-navbar-item-selected-s); + --bulma-navbar-l: var(--bulma-navbar-item-selected-l); + --bulma-navbar-item-background-l: var(--bulma-navbar-item-selected-background-l); + --bulma-navbar-item-background-a: 1; + --bulma-navbar-item-color-l: var(--bulma-navbar-item-selected-color-l); +} + +.navbar-item { + flex-grow: 0; + flex-shrink: 0; +} +.navbar-item img, +.navbar-item svg { + max-height: var(--bulma-navbar-item-img-max-height); +} +.navbar-item.has-dropdown { + padding: 0; +} +.navbar-item.is-expanded { + flex-grow: 1; + flex-shrink: 1; +} +.navbar-item.is-tab { + border-bottom: 1px solid transparent; + min-height: var(--bulma-navbar-height); + padding-bottom: calc(0.5rem - 1px); +} +.navbar-item.is-tab:focus, .navbar-item.is-tab:hover { + background-color: var(--bulma-navbar-tab-hover-background-color); + border-bottom-color: var(--bulma-navbar-tab-hover-border-bottom-color); +} +.navbar-item.is-tab.is-active { + background-color: var(--bulma-navbar-tab-active-background-color); + border-bottom-color: var(--bulma-navbar-tab-active-border-bottom-color); + border-bottom-style: var(--bulma-navbar-tab-active-border-bottom-style); + border-bottom-width: var(--bulma-navbar-tab-active-border-bottom-width); + color: var(--bulma-navbar-tab-active-color); + padding-bottom: calc(0.5rem - var(--bulma-navbar-tab-active-border-bottom-width)); +} + +.navbar-content { + flex-grow: 1; + flex-shrink: 1; +} + +.navbar-link:not(.is-arrowless) { + padding-inline-end: 2.5em; +} +.navbar-link:not(.is-arrowless)::after { + border-color: var(--bulma-navbar-dropdown-arrow); + margin-top: -0.375em; + inset-inline-end: 1.125em; +} + +.navbar-dropdown { + font-size: 0.875rem; + padding-bottom: 0.75rem; + padding-top: 0.5rem; +} +.navbar-dropdown .navbar-item { + padding-left: 1.5rem; + padding-right: 1.5rem; +} +.navbar-dropdown .navbar-item:not(.is-active, .is-selected) { + background-color: hsl(var(--bulma-navbar-dropdown-item-h), var(--bulma-navbar-dropdown-item-s), calc(var(--bulma-navbar-dropdown-item-background-l) + var(--bulma-navbar-item-background-l-delta))); + color: hsl(var(--bulma-navbar-dropdown-item-h), var(--bulma-navbar-dropdown-item-s), var(--bulma-navbar-dropdown-item-color-l)); +} + +.navbar-divider { + background-color: hsl(var(--bulma-navbar-h), var(--bulma-navbar-s), var(--bulma-navbar-divider-background-l)); + border: none; + display: none; + height: var(--bulma-navbar-divider-height); + margin: 0.5rem 0; +} + +@media screen and (max-width: 1023px) { + .navbar > .container { + display: block; + } + .navbar-brand .navbar-item, + .navbar-tabs .navbar-item { + align-items: center; + display: flex; + } + .navbar-link::after { + display: none; + } + .navbar-menu { + background-color: var(--bulma-navbar-background-color); + box-shadow: 0 0.5em 1em hsla(var(--bulma-scheme-h), var(--bulma-scheme-s), var(--bulma-scheme-invert-l), 0.1); + padding: 0.5rem 0; + } + .navbar-menu.is-active { + display: block; + } + .navbar.is-fixed-bottom-touch, .navbar.is-fixed-top-touch { + left: 0; + position: fixed; + right: 0; + z-index: var(--bulma-navbar-fixed-z); + } + .navbar.is-fixed-bottom-touch { + bottom: 0; + } + .navbar.is-fixed-bottom-touch.has-shadow { + box-shadow: 0 -0.125em 0.1875em hsla(var(--bulma-scheme-h), var(--bulma-scheme-s), var(--bulma-scheme-invert-l), 0.1); + } + .navbar.is-fixed-top-touch { + top: 0; + } + .navbar.is-fixed-top .navbar-menu, .navbar.is-fixed-top-touch .navbar-menu { + -webkit-overflow-scrolling: touch; + max-height: calc(100vh - var(--bulma-navbar-height)); + overflow: auto; + } + html.has-navbar-fixed-top-touch, + body.has-navbar-fixed-top-touch { + padding-top: var(--bulma-navbar-height); + } + html.has-navbar-fixed-bottom-touch, + body.has-navbar-fixed-bottom-touch { + padding-bottom: var(--bulma-navbar-height); + } +} +@media screen and (min-width: 1024px) { + .navbar, + .navbar-menu, + .navbar-start, + .navbar-end { + align-items: stretch; + display: flex; + } + .navbar { + min-height: var(--bulma-navbar-height); + } + .navbar.is-spaced { + padding: var(--bulma-navbar-padding-vertical) var(--bulma-navbar-padding-horizontal); + } + .navbar.is-spaced .navbar-start, + .navbar.is-spaced .navbar-end { + align-items: center; + } + .navbar.is-spaced a.navbar-item, + .navbar.is-spaced .navbar-link { + border-radius: var(--bulma-radius); + } + .navbar.is-transparent { + --bulma-navbar-item-background-a: 0; + } + .navbar.is-transparent .navbar-dropdown a.navbar-item { + background-color: hsl(var(--bulma-navbar-h), var(--bulma-navbar-s), calc(var(--bulma-navbar-item-background-l) + var(--bulma-navbar-item-background-l-delta))); + } + .navbar.is-transparent .navbar-dropdown a.navbar-item.is-active, .navbar.is-transparent .navbar-dropdown a.navbar-item.is-selected { + --bulma-navbar-h: var(--bulma-navbar-item-selected-h); + --bulma-navbar-s: var(--bulma-navbar-item-selected-s); + --bulma-navbar-l: var(--bulma-navbar-item-selected-l); + --bulma-navbar-item-background-l: var(--bulma-navbar-item-selected-background-l); + --bulma-navbar-item-color-l: var(--bulma-navbar-item-selected-color-l); + } + .navbar-burger { + display: none; + } + .navbar-item, + .navbar-link { + align-items: center; + display: flex; + } + .navbar-item.has-dropdown { + align-items: stretch; + } + .navbar-item.has-dropdown-up .navbar-link::after { + transform: rotate(135deg) translate(0.25em, -0.25em); + } + .navbar-item.has-dropdown-up .navbar-dropdown { + border-bottom-color: var(--bulma-navbar-dropdown-border-color); + border-bottom-style: var(--bulma-navbar-dropdown-border-style); + border-bottom-width: var(--bulma-navbar-dropdown-border-width); + border-radius: var(--bulma-navbar-dropdown-radius) var(--bulma-navbar-dropdown-radius) 0 0; + border-top: none; + bottom: 100%; + box-shadow: 0 -0.5em 0.5em hsla(var(--bulma-scheme-h), var(--bulma-scheme-s), var(--bulma-scheme-invert-l), 0.1); + top: auto; + } + .navbar-item.is-active .navbar-dropdown, .navbar-item.is-hoverable:focus .navbar-dropdown, .navbar-item.is-hoverable:focus-within .navbar-dropdown, .navbar-item.is-hoverable:hover .navbar-dropdown { + display: block; + } + .navbar.is-spaced .navbar-item.is-active .navbar-dropdown, .navbar-item.is-active .navbar-dropdown.is-boxed, .navbar.is-spaced .navbar-item.is-hoverable:focus .navbar-dropdown, .navbar-item.is-hoverable:focus .navbar-dropdown.is-boxed, .navbar.is-spaced .navbar-item.is-hoverable:focus-within .navbar-dropdown, .navbar-item.is-hoverable:focus-within .navbar-dropdown.is-boxed, .navbar.is-spaced .navbar-item.is-hoverable:hover .navbar-dropdown, .navbar-item.is-hoverable:hover .navbar-dropdown.is-boxed { + opacity: 1; + pointer-events: auto; + transform: translateY(0); + } + .navbar-menu { + flex-grow: 1; + flex-shrink: 0; + } + .navbar-start { + justify-content: flex-start; + margin-inline-end: auto; + } + .navbar-end { + justify-content: flex-end; + margin-inline-start: auto; + } + .navbar-dropdown { + background-color: var(--bulma-navbar-dropdown-background-color); + border-end-start-radius: var(--bulma-navbar-dropdown-radius); + border-end-end-radius: var(--bulma-navbar-dropdown-radius); + border-top-color: var(--bulma-navbar-dropdown-border-color); + border-top-style: var(--bulma-navbar-dropdown-border-style); + border-top-width: var(--bulma-navbar-dropdown-border-width); + box-shadow: 0 0.5em 0.5em hsla(var(--bulma-scheme-h), var(--bulma-scheme-s), var(--bulma-scheme-invert-l), 0.1); + display: none; + font-size: 0.875rem; + inset-inline-start: 0; + min-width: 100%; + position: absolute; + top: 100%; + z-index: var(--bulma-navbar-dropdown-z); + } + .navbar-dropdown .navbar-item { + padding: 0.375rem 1rem; + white-space: nowrap; + } + .navbar-dropdown a.navbar-item { + padding-inline-end: 3rem; + } + .navbar-dropdown a.navbar-item:not(.is-active, .is-selected) { + background-color: hsl(var(--bulma-navbar-dropdown-item-h), var(--bulma-navbar-dropdown-item-s), calc(var(--bulma-navbar-dropdown-item-background-l) + var(--bulma-navbar-item-background-l-delta))); + color: hsl(var(--bulma-navbar-dropdown-item-h), var(--bulma-navbar-dropdown-item-s), var(--bulma-navbar-dropdown-item-color-l)); + } + .navbar.is-spaced .navbar-dropdown, .navbar-dropdown.is-boxed { + border-radius: var(--bulma-navbar-dropdown-boxed-radius); + border-top: none; + box-shadow: var(--bulma-navbar-dropdown-boxed-shadow); + display: block; + opacity: 0; + pointer-events: none; + top: calc(100% + (var(--bulma-navbar-dropdown-offset))); + transform: translateY(-5px); + transition-duration: var(--bulma-duration); + transition-property: opacity, transform; + } + .navbar-dropdown.is-right { + left: auto; + right: 0; + } + .navbar-divider { + display: block; + } + .navbar > .container .navbar-brand, + .container > .navbar .navbar-brand { + margin-inline-start: -0.75rem; + } + .navbar > .container .navbar-menu, + .container > .navbar .navbar-menu { + margin-inline-end: -0.75rem; + } + .navbar.is-fixed-bottom-desktop, .navbar.is-fixed-top-desktop { + left: 0; + position: fixed; + right: 0; + z-index: var(--bulma-navbar-fixed-z); + } + .navbar.is-fixed-bottom-desktop { + bottom: 0; + } + .navbar.is-fixed-bottom-desktop.has-shadow { + box-shadow: 0 -0.125em 0.1875em hsla(var(--bulma-scheme-h), var(--bulma-scheme-s), var(--bulma-scheme-invert-l), 0.1); + } + .navbar.is-fixed-top-desktop { + top: 0; + } + html.has-navbar-fixed-top-desktop, + body.has-navbar-fixed-top-desktop { + padding-top: var(--bulma-navbar-height); + } + html.has-navbar-fixed-bottom-desktop, + body.has-navbar-fixed-bottom-desktop { + padding-bottom: var(--bulma-navbar-height); + } + html.has-spaced-navbar-fixed-top, + body.has-spaced-navbar-fixed-top { + padding-top: calc(var(--bulma-navbar-height) + var(--bulma-navbar-padding-vertical) * 2); + } + html.has-spaced-navbar-fixed-bottom, + body.has-spaced-navbar-fixed-bottom { + padding-bottom: calc(var(--bulma-navbar-height) + var(--bulma-navbar-padding-vertical) * 2); + } +} +.hero.is-fullheight-with-navbar { + min-height: calc(100vh - var(--bulma-navbar-height)); +} + +.pagination { + --bulma-pagination-margin: -0.25rem; + --bulma-pagination-min-width: var(--bulma-control-height); + --bulma-pagination-item-h: var(--bulma-scheme-h); + --bulma-pagination-item-s: var(--bulma-scheme-s); + --bulma-pagination-item-l: var(--bulma-scheme-main-l); + --bulma-pagination-item-background-l-delta: 0%; + --bulma-pagination-item-hover-background-l-delta: var(--bulma-hover-background-l-delta); + --bulma-pagination-item-active-background-l-delta: var(--bulma-active-background-l-delta); + --bulma-pagination-item-border-style: solid; + --bulma-pagination-item-border-width: var(--bulma-control-border-width); + --bulma-pagination-item-border-l: var(--bulma-border-l); + --bulma-pagination-item-border-l-delta: 0%; + --bulma-pagination-item-hover-border-l-delta: var(--bulma-hover-border-l-delta); + --bulma-pagination-item-active-border-l-delta: var(--bulma-active-border-l-delta); + --bulma-pagination-item-focus-border-l-delta: var(--bulma-focus-border-l-delta); + --bulma-pagination-item-color-l: var(--bulma-text-strong-l); + --bulma-pagination-item-font-size: 1em; + --bulma-pagination-item-margin: 0.25rem; + --bulma-pagination-item-padding-left: 0.5em; + --bulma-pagination-item-padding-right: 0.5em; + --bulma-pagination-item-outer-shadow-h: 0; + --bulma-pagination-item-outer-shadow-s: 0%; + --bulma-pagination-item-outer-shadow-l: 20%; + --bulma-pagination-item-outer-shadow-a: 0.05; + --bulma-pagination-nav-padding-left: 0.75em; + --bulma-pagination-nav-padding-right: 0.75em; + --bulma-pagination-disabled-color: var(--bulma-text-weak); + --bulma-pagination-disabled-background-color: var(--bulma-border); + --bulma-pagination-disabled-border-color: var(--bulma-border); + --bulma-pagination-current-color: var(--bulma-link-invert); + --bulma-pagination-current-background-color: var(--bulma-link); + --bulma-pagination-current-border-color: var(--bulma-link); + --bulma-pagination-ellipsis-color: var(--bulma-text-weak); + --bulma-pagination-shadow-inset: inset 0 0.0625em 0.125em hsla(var(--bulma-scheme-h), var(--bulma-scheme-s), var(--bulma-scheme-invert-l), 0.2); + --bulma-pagination-selected-item-h: var(--bulma-link-h); + --bulma-pagination-selected-item-s: var(--bulma-link-s); + --bulma-pagination-selected-item-l: var(--bulma-link-l); + --bulma-pagination-selected-item-background-l: var(--bulma-link-l); + --bulma-pagination-selected-item-border-l: var(--bulma-link-l); + --bulma-pagination-selected-item-color-l: var(--bulma-link-invert-l); +} + +.pagination { + font-size: var(--bulma-size-normal); + margin: var(--bulma-pagination-margin); +} +.pagination.is-small { + font-size: var(--bulma-size-small); +} +.pagination.is-medium { + font-size: var(--bulma-size-medium); +} +.pagination.is-large { + font-size: var(--bulma-size-large); +} +.pagination.is-rounded .pagination-previous, +.pagination.is-rounded .pagination-next { + padding-left: 1em; + padding-right: 1em; + border-radius: var(--bulma-radius-rounded); +} +.pagination.is-rounded .pagination-link { + border-radius: var(--bulma-radius-rounded); +} + +.pagination, +.pagination-list { + align-items: center; + display: flex; + justify-content: center; + text-align: center; +} + +.pagination-previous, +.pagination-next, +.pagination-link, +.pagination-ellipsis { + color: hsl(var(--bulma-pagination-item-h), var(--bulma-pagination-item-s), var(--bulma-pagination-item-color-l)); + font-size: var(--bulma-pagination-item-font-size); + justify-content: center; + margin: var(--bulma-pagination-item-margin); + padding-left: var(--bulma-pagination-item-padding-left); + padding-right: var(--bulma-pagination-item-padding-right); + text-align: center; +} + +.pagination-previous, +.pagination-next, +.pagination-link { + background-color: hsl(var(--bulma-pagination-item-h), var(--bulma-pagination-item-s), calc(var(--bulma-pagination-item-background-l) + var(--bulma-pagination-item-background-l-delta))); + border-color: hsl(var(--bulma-pagination-item-h), var(--bulma-pagination-item-s), calc(var(--bulma-pagination-item-border-l) + var(--bulma-pagination-item-border-l-delta))); + border-style: var(--bulma-pagination-item-border-style); + border-width: var(--bulma-pagination-item-border-width); + box-shadow: 0px 0.0625em 0.125em hsla(var(--bulma-pagination-item-outer-shadow-h), var(--bulma-pagination-item-outer-shadow-s), var(--bulma-pagination-item-outer-shadow-l), var(--bulma-pagination-item-outer-shadow-a)), 0px 0.125em 0.25em hsla(var(--bulma-pagination-item-outer-shadow-h), var(--bulma-pagination-item-outer-shadow-s), var(--bulma-pagination-item-outer-shadow-l), var(--bulma-pagination-item-outer-shadow-a)); + color: hsl(var(--bulma-pagination-item-h), var(--bulma-pagination-item-s), var(--bulma-pagination-item-color-l)); + min-width: var(--bulma-pagination-min-width); + transition-duration: var(--bulma-duration); + transition-property: background-color, border-color, box-shadow, color; +} +.pagination-previous:hover, +.pagination-next:hover, +.pagination-link:hover { + --bulma-pagination-item-background-l-delta: var(--bulma-pagination-item-hover-background-l-delta); + --bulma-pagination-item-border-l-delta: var(--bulma-pagination-item-hover-border-l-delta); +} +.pagination-previous:focus, +.pagination-next:focus, +.pagination-link:focus { + --bulma-pagination-item-background-l-delta: var(--bulma-pagination-item-hover-background-l-delta); + --bulma-pagination-item-border-l-delta: var(--bulma-pagination-item-hover-border-l-delta); +} +.pagination-previous:active, +.pagination-next:active, +.pagination-link:active { + box-shadow: var(--bulma-pagination-shadow-inset); +} +.pagination-previous[disabled], .pagination-previous.is-disabled, +.pagination-next[disabled], +.pagination-next.is-disabled, +.pagination-link[disabled], +.pagination-link.is-disabled { + background-color: var(--bulma-pagination-disabled-background-color); + border-color: var(--bulma-pagination-disabled-border-color); + box-shadow: none; + color: var(--bulma-pagination-disabled-color); + opacity: 0.5; +} + +.pagination-previous, +.pagination-next { + padding-left: var(--bulma-pagination-nav-padding-left); + padding-right: var(--bulma-pagination-nav-padding-right); + white-space: nowrap; +} + +.pagination-link.is-current, .pagination-link.is-selected { + --bulma-pagination-item-h: var(--bulma-pagination-selected-item-h); + --bulma-pagination-item-s: var(--bulma-pagination-selected-item-s); + --bulma-pagination-item-l: var(--bulma-pagination-selected-item-l); + --bulma-pagination-item-background-l: var(--bulma-pagination-selected-item-background-l); + --bulma-pagination-item-border-l: var(--bulma-pagination-selected-item-border-l); + --bulma-pagination-item-color-l: var(--bulma-pagination-selected-item-color-l); +} + +.pagination-ellipsis { + color: var(--bulma-pagination-ellipsis-color); + pointer-events: none; +} + +.pagination-list { + flex-wrap: wrap; +} +.pagination-list li { + list-style: none; +} + +@media screen and (max-width: 768px) { + .pagination { + flex-wrap: wrap; + } + .pagination-previous, + .pagination-next { + flex-grow: 1; + flex-shrink: 1; + } + .pagination-list li { + flex-grow: 1; + flex-shrink: 1; + } +} +@media screen and (min-width: 769px), print { + .pagination-list { + flex-grow: 1; + flex-shrink: 1; + justify-content: flex-start; + order: 1; + } + .pagination-previous, + .pagination-next, + .pagination-link, + .pagination-ellipsis { + margin-bottom: 0; + margin-top: 0; + } + .pagination-previous { + order: 2; + } + .pagination-next { + order: 3; + } + .pagination { + justify-content: space-between; + margin-bottom: 0; + margin-top: 0; + } + .pagination.is-centered .pagination-previous { + order: 1; + } + .pagination.is-centered .pagination-list { + justify-content: center; + order: 2; + } + .pagination.is-centered .pagination-next { + order: 3; + } + .pagination.is-right .pagination-previous { + order: 1; + } + .pagination.is-right .pagination-next { + order: 2; + } + .pagination.is-right .pagination-list { + justify-content: flex-end; + order: 3; + } +} +.panel { + --bulma-panel-margin: var(--bulma-block-spacing); + --bulma-panel-item-border: 1px solid var(--bulma-border-weak); + --bulma-panel-radius: var(--bulma-radius-large); + --bulma-panel-shadow: var(--bulma-shadow); + --bulma-panel-heading-line-height: 1.25; + --bulma-panel-heading-padding: 1em 1.25em; + --bulma-panel-heading-radius: var(--bulma-radius); + --bulma-panel-heading-size: 1.25em; + --bulma-panel-heading-weight: var(--bulma-weight-bold); + --bulma-panel-tabs-font-size: 1em; + --bulma-panel-tab-border-bottom-color: var(--bulma-border); + --bulma-panel-tab-border-bottom-style: solid; + --bulma-panel-tab-border-bottom-width: 1px; + --bulma-panel-tab-active-color: var(--bulma-link-active); + --bulma-panel-list-item-color: var(--bulma-text); + --bulma-panel-list-item-hover-color: var(--bulma-link); + --bulma-panel-block-color: var(--bulma-text-strong); + --bulma-panel-block-hover-background-color: var(--bulma-background); + --bulma-panel-block-active-border-left-color: var(--bulma-link); + --bulma-panel-block-active-color: var(--bulma-link-active); + --bulma-panel-block-active-icon-color: var(--bulma-link); + --bulma-panel-icon-color: var(--bulma-text-weak); +} + +.panel { + --bulma-panel-h: var(--bulma-scheme-h); + --bulma-panel-s: var(--bulma-scheme-s); + --bulma-panel-color-l: var(--bulma-text-l); + --bulma-panel-heading-background-l: var(--bulma-text-l); + --bulma-panel-heading-color-l: var(--bulma-text-invert-l); + border-radius: var(--bulma-panel-radius); + box-shadow: var(--bulma-panel-shadow); + font-size: var(--bulma-size-normal); +} +.panel:not(:last-child) { + margin-bottom: var(--bulma-panel-margin); +} +.panel.is-white { + --bulma-panel-h: var(--bulma-white-h); + --bulma-panel-s: var(--bulma-white-s); + --bulma-panel-color-l: var(--bulma-white-l); + --bulma-panel-heading-background-l: var(--bulma-white-l); + --bulma-panel-heading-color-l: var(--bulma-white-invert-l); +} +.panel.is-black { + --bulma-panel-h: var(--bulma-black-h); + --bulma-panel-s: var(--bulma-black-s); + --bulma-panel-color-l: var(--bulma-black-l); + --bulma-panel-heading-background-l: var(--bulma-black-l); + --bulma-panel-heading-color-l: var(--bulma-black-invert-l); +} +.panel.is-light { + --bulma-panel-h: var(--bulma-light-h); + --bulma-panel-s: var(--bulma-light-s); + --bulma-panel-color-l: var(--bulma-light-l); + --bulma-panel-heading-background-l: var(--bulma-light-l); + --bulma-panel-heading-color-l: var(--bulma-light-invert-l); +} +.panel.is-dark { + --bulma-panel-h: var(--bulma-dark-h); + --bulma-panel-s: var(--bulma-dark-s); + --bulma-panel-color-l: var(--bulma-dark-l); + --bulma-panel-heading-background-l: var(--bulma-dark-l); + --bulma-panel-heading-color-l: var(--bulma-dark-invert-l); +} +.panel.is-text { + --bulma-panel-h: var(--bulma-text-h); + --bulma-panel-s: var(--bulma-text-s); + --bulma-panel-color-l: var(--bulma-text-l); + --bulma-panel-heading-background-l: var(--bulma-text-l); + --bulma-panel-heading-color-l: var(--bulma-text-invert-l); +} +.panel.is-primary { + --bulma-panel-h: var(--bulma-primary-h); + --bulma-panel-s: var(--bulma-primary-s); + --bulma-panel-color-l: var(--bulma-primary-l); + --bulma-panel-heading-background-l: var(--bulma-primary-l); + --bulma-panel-heading-color-l: var(--bulma-primary-invert-l); +} +.panel.is-link { + --bulma-panel-h: var(--bulma-link-h); + --bulma-panel-s: var(--bulma-link-s); + --bulma-panel-color-l: var(--bulma-link-l); + --bulma-panel-heading-background-l: var(--bulma-link-l); + --bulma-panel-heading-color-l: var(--bulma-link-invert-l); +} +.panel.is-info { + --bulma-panel-h: var(--bulma-info-h); + --bulma-panel-s: var(--bulma-info-s); + --bulma-panel-color-l: var(--bulma-info-l); + --bulma-panel-heading-background-l: var(--bulma-info-l); + --bulma-panel-heading-color-l: var(--bulma-info-invert-l); +} +.panel.is-success { + --bulma-panel-h: var(--bulma-success-h); + --bulma-panel-s: var(--bulma-success-s); + --bulma-panel-color-l: var(--bulma-success-l); + --bulma-panel-heading-background-l: var(--bulma-success-l); + --bulma-panel-heading-color-l: var(--bulma-success-invert-l); +} +.panel.is-warning { + --bulma-panel-h: var(--bulma-warning-h); + --bulma-panel-s: var(--bulma-warning-s); + --bulma-panel-color-l: var(--bulma-warning-l); + --bulma-panel-heading-background-l: var(--bulma-warning-l); + --bulma-panel-heading-color-l: var(--bulma-warning-invert-l); +} +.panel.is-danger { + --bulma-panel-h: var(--bulma-danger-h); + --bulma-panel-s: var(--bulma-danger-s); + --bulma-panel-color-l: var(--bulma-danger-l); + --bulma-panel-heading-background-l: var(--bulma-danger-l); + --bulma-panel-heading-color-l: var(--bulma-danger-invert-l); +} + +.panel-tabs:not(:last-child), +.panel-block:not(:last-child) { + border-bottom: var(--bulma-panel-item-border); +} + +.panel-heading { + background-color: hsl(var(--bulma-panel-h), var(--bulma-panel-s), var(--bulma-panel-heading-background-l)); + border-radius: var(--bulma-panel-radius) var(--bulma-panel-radius) 0 0; + color: hsl(var(--bulma-panel-h), var(--bulma-panel-s), var(--bulma-panel-heading-color-l)); + font-size: var(--bulma-panel-heading-size); + font-weight: var(--bulma-panel-heading-weight); + line-height: var(--bulma-panel-heading-line-height); + padding: var(--bulma-panel-heading-padding); +} + +.panel-tabs { + align-items: flex-end; + display: flex; + font-size: var(--bulma-panel-tabs-font-size); + justify-content: center; +} +.panel-tabs a { + border-bottom-color: var(--bulma-panel-tab-border-bottom-color); + border-bottom-style: var(--bulma-panel-tab-border-bottom-style); + border-bottom-width: var(--bulma-panel-tab-border-bottom-width); + margin-bottom: calc(-1 * 1px); + padding: 0.75em; +} +.panel-tabs a.is-active { + border-bottom-color: hsl(var(--bulma-panel-h), var(--bulma-panel-s), var(--bulma-panel-color-l)); + color: var(--bulma-panel-tab-active-color); +} + +.panel-list a { + color: var(--bulma-panel-list-item-color); +} +.panel-list a:hover { + color: var(--bulma-panel-list-item-hover-color); +} + +.panel-block { + align-items: center; + color: var(--bulma-panel-block-color); + display: flex; + justify-content: flex-start; + padding: 0.75em 1em; +} +.panel-block input[type=checkbox] { + margin-inline-end: 0.75em; +} +.panel-block > .control { + flex-grow: 1; + flex-shrink: 1; + width: 100%; +} +.panel-block.is-wrapped { + flex-wrap: wrap; +} +.panel-block.is-active { + border-left-color: var(--bulma-panel-block-active-border-left-color); + color: var(--bulma-panel-block-active-color); +} +.panel-block.is-active .panel-icon { + color: hsl(var(--bulma-panel-h), var(--bulma-panel-s), var(--bulma-panel-color-l)); +} +.panel-block:last-child { + border-end-start-radius: var(--bulma-panel-radius); + border-end-end-radius: var(--bulma-panel-radius); +} + +a.panel-block, +label.panel-block { + cursor: pointer; +} +a.panel-block:hover, +label.panel-block:hover { + background-color: var(--bulma-panel-block-hover-background-color); +} + +.panel-icon { + display: inline-block; + font-size: 1em; + height: 1em; + line-height: 1em; + text-align: center; + vertical-align: top; + width: 1em; + color: var(--bulma-panel-icon-color); + margin-inline-end: 0.75em; +} +.panel-icon .fa { + font-size: inherit; + line-height: inherit; +} + +.tabs { + --bulma-tabs-border-bottom-color: var(--bulma-border); + --bulma-tabs-border-bottom-style: solid; + --bulma-tabs-border-bottom-width: 1px; + --bulma-tabs-link-color: var(--bulma-text); + --bulma-tabs-link-hover-border-bottom-color: var(--bulma-text-strong); + --bulma-tabs-link-hover-color: var(--bulma-text-strong); + --bulma-tabs-link-active-border-bottom-color: var(--bulma-link-text); + --bulma-tabs-link-active-color: var(--bulma-link-text); + --bulma-tabs-link-padding: 0.5em 1em; + --bulma-tabs-boxed-link-radius: var(--bulma-radius); + --bulma-tabs-boxed-link-hover-background-color: var(--bulma-background); + --bulma-tabs-boxed-link-hover-border-bottom-color: var(--bulma-border); + --bulma-tabs-boxed-link-active-background-color: var(--bulma-scheme-main); + --bulma-tabs-boxed-link-active-border-color: var(--bulma-border); + --bulma-tabs-boxed-link-active-border-bottom-color: transparent; + --bulma-tabs-toggle-link-border-color: var(--bulma-border); + --bulma-tabs-toggle-link-border-style: solid; + --bulma-tabs-toggle-link-border-width: 1px; + --bulma-tabs-toggle-link-hover-background-color: var(--bulma-background); + --bulma-tabs-toggle-link-hover-border-color: var(--bulma-border-hover); + --bulma-tabs-toggle-link-radius: var(--bulma-radius); + --bulma-tabs-toggle-link-active-background-color: var(--bulma-link); + --bulma-tabs-toggle-link-active-border-color: var(--bulma-link); + --bulma-tabs-toggle-link-active-color: var(--bulma-link-invert); +} + +.tabs { + -webkit-overflow-scrolling: touch; + align-items: stretch; + display: flex; + font-size: var(--bulma-size-normal); + justify-content: space-between; + overflow: hidden; + overflow-x: auto; + white-space: nowrap; +} +.tabs a { + align-items: center; + border-bottom-color: var(--bulma-tabs-border-bottom-color); + border-bottom-style: var(--bulma-tabs-border-bottom-style); + border-bottom-width: var(--bulma-tabs-border-bottom-width); + color: var(--bulma-tabs-link-color); + display: flex; + justify-content: center; + margin-bottom: calc(-1 * var(--bulma-tabs-border-bottom-width)); + padding: var(--bulma-tabs-link-padding); + transition-duration: var(--bulma-duration); + transition-property: background-color, border-color, color; + vertical-align: top; +} +.tabs a:hover { + border-bottom-color: var(--bulma-tabs-link-hover-border-bottom-color); + color: var(--bulma-tabs-link-hover-color); +} +.tabs li { + display: block; +} +.tabs li.is-active a { + border-bottom-color: var(--bulma-tabs-link-active-border-bottom-color); + color: var(--bulma-tabs-link-active-color); +} +.tabs ul { + align-items: center; + border-bottom-color: var(--bulma-tabs-border-bottom-color); + border-bottom-style: var(--bulma-tabs-border-bottom-style); + border-bottom-width: var(--bulma-tabs-border-bottom-width); + display: flex; + flex-grow: 1; + flex-shrink: 0; + justify-content: flex-start; +} +.tabs ul.is-left { + padding-right: 0.75em; +} +.tabs ul.is-center { + flex: none; + justify-content: center; + padding-left: 0.75em; + padding-right: 0.75em; +} +.tabs ul.is-right { + justify-content: flex-end; + padding-left: 0.75em; +} +.tabs .icon:first-child { + margin-inline-end: 0.5em; +} +.tabs .icon:last-child { + margin-inline-start: 0.5em; +} +.tabs.is-centered ul { + justify-content: center; +} +.tabs.is-right ul { + justify-content: flex-end; +} +.tabs.is-boxed a { + border: 1px solid transparent; + border-start-start-radius: var(--bulma-tabs-boxed-link-radius); + border-start-end-radius: var(--bulma-tabs-boxed-link-radius); +} +.tabs.is-boxed a:hover { + background-color: var(--bulma-tabs-boxed-link-hover-background-color); + border-bottom-color: var(--bulma-tabs-boxed-link-hover-border-bottom-color); +} +.tabs.is-boxed li.is-active a { + background-color: var(--bulma-tabs-boxed-link-active-background-color); + border-color: var(--bulma-tabs-boxed-link-active-border-color); + border-bottom-color: var(--bulma-tabs-boxed-link-active-border-bottom-color) !important; +} +.tabs.is-fullwidth li { + flex-grow: 1; + flex-shrink: 0; +} +.tabs.is-toggle a { + border-color: var(--bulma-tabs-toggle-link-border-color); + border-style: var(--bulma-tabs-toggle-link-border-style); + border-width: var(--bulma-tabs-toggle-link-border-width); + margin-bottom: 0; + position: relative; +} +.tabs.is-toggle a:hover { + background-color: var(--bulma-tabs-toggle-link-hover-background-color); + border-color: var(--bulma-tabs-toggle-link-hover-border-color); + z-index: 2; +} +.tabs.is-toggle li + li { + margin-inline-start: calc(-1 * var(--bulma-tabs-toggle-link-border-width)); +} +.tabs.is-toggle li:first-child a { + border-start-start-radius: var(--bulma-tabs-toggle-link-radius); + border-end-start-radius: var(--bulma-tabs-toggle-link-radius); +} +.tabs.is-toggle li:last-child a { + border-start-end-radius: var(--bulma-tabs-toggle-link-radius); + border-end-end-radius: var(--bulma-tabs-toggle-link-radius); +} +.tabs.is-toggle li.is-active a { + background-color: var(--bulma-tabs-toggle-link-active-background-color); + border-color: var(--bulma-tabs-toggle-link-active-border-color); + color: var(--bulma-tabs-toggle-link-active-color); + z-index: 1; +} +.tabs.is-toggle ul { + border-bottom: none; +} +.tabs.is-toggle.is-toggle-rounded li:first-child a { + border-start-start-radius: var(--bulma-radius-rounded); + border-end-start-radius: var(--bulma-radius-rounded); + padding-inline-start: 1.25em; +} +.tabs.is-toggle.is-toggle-rounded li:last-child a { + border-start-end-radius: var(--bulma-radius-rounded); + border-end-end-radius: var(--bulma-radius-rounded); + padding-inline-end: 1.25em; +} +.tabs.is-small { + font-size: var(--bulma-size-small); +} +.tabs.is-medium { + font-size: var(--bulma-size-medium); +} +.tabs.is-large { + font-size: var(--bulma-size-large); +} + +/* Bulma Grid */ +:root { + --bulma-column-gap: 0.75rem; +} + +.column { + display: block; + flex-basis: 0; + flex-grow: 1; + flex-shrink: 1; + padding: var(--bulma-column-gap); +} +.columns.is-mobile > .column.is-narrow { + flex: none; + width: unset; +} +.columns.is-mobile > .column.is-full { + flex: none; + width: 100%; +} +.columns.is-mobile > .column.is-three-quarters { + flex: none; + width: 75%; +} +.columns.is-mobile > .column.is-two-thirds { + flex: none; + width: 66.6666%; +} +.columns.is-mobile > .column.is-half { + flex: none; + width: 50%; +} +.columns.is-mobile > .column.is-one-third { + flex: none; + width: 33.3333%; +} +.columns.is-mobile > .column.is-one-quarter { + flex: none; + width: 25%; +} +.columns.is-mobile > .column.is-one-fifth { + flex: none; + width: 20%; +} +.columns.is-mobile > .column.is-two-fifths { + flex: none; + width: 40%; +} +.columns.is-mobile > .column.is-three-fifths { + flex: none; + width: 60%; +} +.columns.is-mobile > .column.is-four-fifths { + flex: none; + width: 80%; +} +.columns.is-mobile > .column.is-offset-three-quarters { + margin-inline-start: 75%; +} +.columns.is-mobile > .column.is-offset-two-thirds { + margin-inline-start: 66.6666%; +} +.columns.is-mobile > .column.is-offset-half { + margin-inline-start: 50%; +} +.columns.is-mobile > .column.is-offset-one-third { + margin-inline-start: 0.3333%; +} +.columns.is-mobile > .column.is-offset-one-quarter { + margin-inline-start: 25%; +} +.columns.is-mobile > .column.is-offset-one-fifth { + margin-inline-start: 20%; +} +.columns.is-mobile > .column.is-offset-two-fifths { + margin-inline-start: 40%; +} +.columns.is-mobile > .column.is-offset-three-fifths { + margin-inline-start: 60%; +} +.columns.is-mobile > .column.is-offset-four-fifths { + margin-inline-start: 80%; +} +.columns.is-mobile > .column.is-0 { + flex: none; + width: 0%; +} +.columns.is-mobile > .column.is-offset-0 { + margin-inline-start: 0%; +} +.columns.is-mobile > .column.is-1 { + flex: none; + width: 8.3333333333%; +} +.columns.is-mobile > .column.is-offset-1 { + margin-inline-start: 8.3333333333%; +} +.columns.is-mobile > .column.is-2 { + flex: none; + width: 16.6666666667%; +} +.columns.is-mobile > .column.is-offset-2 { + margin-inline-start: 16.6666666667%; +} +.columns.is-mobile > .column.is-3 { + flex: none; + width: 25%; +} +.columns.is-mobile > .column.is-offset-3 { + margin-inline-start: 25%; +} +.columns.is-mobile > .column.is-4 { + flex: none; + width: 33.3333333333%; +} +.columns.is-mobile > .column.is-offset-4 { + margin-inline-start: 33.3333333333%; +} +.columns.is-mobile > .column.is-5 { + flex: none; + width: 41.6666666667%; +} +.columns.is-mobile > .column.is-offset-5 { + margin-inline-start: 41.6666666667%; +} +.columns.is-mobile > .column.is-6 { + flex: none; + width: 50%; +} +.columns.is-mobile > .column.is-offset-6 { + margin-inline-start: 50%; +} +.columns.is-mobile > .column.is-7 { + flex: none; + width: 58.3333333333%; +} +.columns.is-mobile > .column.is-offset-7 { + margin-inline-start: 58.3333333333%; +} +.columns.is-mobile > .column.is-8 { + flex: none; + width: 66.6666666667%; +} +.columns.is-mobile > .column.is-offset-8 { + margin-inline-start: 66.6666666667%; +} +.columns.is-mobile > .column.is-9 { + flex: none; + width: 75%; +} +.columns.is-mobile > .column.is-offset-9 { + margin-inline-start: 75%; +} +.columns.is-mobile > .column.is-10 { + flex: none; + width: 83.3333333333%; +} +.columns.is-mobile > .column.is-offset-10 { + margin-inline-start: 83.3333333333%; +} +.columns.is-mobile > .column.is-11 { + flex: none; + width: 91.6666666667%; +} +.columns.is-mobile > .column.is-offset-11 { + margin-inline-start: 91.6666666667%; +} +.columns.is-mobile > .column.is-12 { + flex: none; + width: 100%; +} +.columns.is-mobile > .column.is-offset-12 { + margin-inline-start: 100%; +} +@media screen and (max-width: 768px) { + .column.is-narrow-mobile { + flex: none; + width: unset; + } + .column.is-full-mobile { + flex: none; + width: 100%; + } + .column.is-three-quarters-mobile { + flex: none; + width: 75%; + } + .column.is-two-thirds-mobile { + flex: none; + width: 66.6666%; + } + .column.is-half-mobile { + flex: none; + width: 50%; + } + .column.is-one-third-mobile { + flex: none; + width: 33.3333%; + } + .column.is-one-quarter-mobile { + flex: none; + width: 25%; + } + .column.is-one-fifth-mobile { + flex: none; + width: 20%; + } + .column.is-two-fifths-mobile { + flex: none; + width: 40%; + } + .column.is-three-fifths-mobile { + flex: none; + width: 60%; + } + .column.is-four-fifths-mobile { + flex: none; + width: 80%; + } + .column.is-offset-three-quarters-mobile { + margin-inline-start: 75%; + } + .column.is-offset-two-thirds-mobile { + margin-inline-start: 66.6666%; + } + .column.is-offset-half-mobile { + margin-inline-start: 50%; + } + .column.is-offset-one-third-mobile { + margin-inline-start: 0.3333%; + } + .column.is-offset-one-quarter-mobile { + margin-inline-start: 25%; + } + .column.is-offset-one-fifth-mobile { + margin-inline-start: 20%; + } + .column.is-offset-two-fifths-mobile { + margin-inline-start: 40%; + } + .column.is-offset-three-fifths-mobile { + margin-inline-start: 60%; + } + .column.is-offset-four-fifths-mobile { + margin-inline-start: 80%; + } + .column.is-0-mobile { + flex: none; + width: 0%; + } + .column.is-offset-0-mobile { + margin-inline-start: 0%; + } + .column.is-1-mobile { + flex: none; + width: 8.3333333333%; + } + .column.is-offset-1-mobile { + margin-inline-start: 8.3333333333%; + } + .column.is-2-mobile { + flex: none; + width: 16.6666666667%; + } + .column.is-offset-2-mobile { + margin-inline-start: 16.6666666667%; + } + .column.is-3-mobile { + flex: none; + width: 25%; + } + .column.is-offset-3-mobile { + margin-inline-start: 25%; + } + .column.is-4-mobile { + flex: none; + width: 33.3333333333%; + } + .column.is-offset-4-mobile { + margin-inline-start: 33.3333333333%; + } + .column.is-5-mobile { + flex: none; + width: 41.6666666667%; + } + .column.is-offset-5-mobile { + margin-inline-start: 41.6666666667%; + } + .column.is-6-mobile { + flex: none; + width: 50%; + } + .column.is-offset-6-mobile { + margin-inline-start: 50%; + } + .column.is-7-mobile { + flex: none; + width: 58.3333333333%; + } + .column.is-offset-7-mobile { + margin-inline-start: 58.3333333333%; + } + .column.is-8-mobile { + flex: none; + width: 66.6666666667%; + } + .column.is-offset-8-mobile { + margin-inline-start: 66.6666666667%; + } + .column.is-9-mobile { + flex: none; + width: 75%; + } + .column.is-offset-9-mobile { + margin-inline-start: 75%; + } + .column.is-10-mobile { + flex: none; + width: 83.3333333333%; + } + .column.is-offset-10-mobile { + margin-inline-start: 83.3333333333%; + } + .column.is-11-mobile { + flex: none; + width: 91.6666666667%; + } + .column.is-offset-11-mobile { + margin-inline-start: 91.6666666667%; + } + .column.is-12-mobile { + flex: none; + width: 100%; + } + .column.is-offset-12-mobile { + margin-inline-start: 100%; + } +} +@media screen and (min-width: 769px), print { + .column.is-narrow, .column.is-narrow-tablet { + flex: none; + width: unset; + } + .column.is-full, .column.is-full-tablet { + flex: none; + width: 100%; + } + .column.is-three-quarters, .column.is-three-quarters-tablet { + flex: none; + width: 75%; + } + .column.is-two-thirds, .column.is-two-thirds-tablet { + flex: none; + width: 66.6666%; + } + .column.is-half, .column.is-half-tablet { + flex: none; + width: 50%; + } + .column.is-one-third, .column.is-one-third-tablet { + flex: none; + width: 33.3333%; + } + .column.is-one-quarter, .column.is-one-quarter-tablet { + flex: none; + width: 25%; + } + .column.is-one-fifth, .column.is-one-fifth-tablet { + flex: none; + width: 20%; + } + .column.is-two-fifths, .column.is-two-fifths-tablet { + flex: none; + width: 40%; + } + .column.is-three-fifths, .column.is-three-fifths-tablet { + flex: none; + width: 60%; + } + .column.is-four-fifths, .column.is-four-fifths-tablet { + flex: none; + width: 80%; + } + .column.is-offset-three-quarters, .column.is-offset-three-quarters-tablet { + margin-inline-start: 75%; + } + .column.is-offset-two-thirds, .column.is-offset-two-thirds-tablet { + margin-inline-start: 66.6666%; + } + .column.is-offset-half, .column.is-offset-half-tablet { + margin-inline-start: 50%; + } + .column.is-offset-one-third, .column.is-offset-one-third-tablet { + margin-inline-start: 0.3333%; + } + .column.is-offset-one-quarter, .column.is-offset-one-quarter-tablet { + margin-inline-start: 25%; + } + .column.is-offset-one-fifth, .column.is-offset-one-fifth-tablet { + margin-inline-start: 20%; + } + .column.is-offset-two-fifths, .column.is-offset-two-fifths-tablet { + margin-inline-start: 40%; + } + .column.is-offset-three-fifths, .column.is-offset-three-fifths-tablet { + margin-inline-start: 60%; + } + .column.is-offset-four-fifths, .column.is-offset-four-fifths-tablet { + margin-inline-start: 80%; + } + .column.is-0, .column.is-0-tablet { + flex: none; + width: 0%; + } + .column.is-offset-0, .column.is-offset-0-tablet { + margin-inline-start: 0%; + } + .column.is-1, .column.is-1-tablet { + flex: none; + width: 8.3333333333%; + } + .column.is-offset-1, .column.is-offset-1-tablet { + margin-inline-start: 8.3333333333%; + } + .column.is-2, .column.is-2-tablet { + flex: none; + width: 16.6666666667%; + } + .column.is-offset-2, .column.is-offset-2-tablet { + margin-inline-start: 16.6666666667%; + } + .column.is-3, .column.is-3-tablet { + flex: none; + width: 25%; + } + .column.is-offset-3, .column.is-offset-3-tablet { + margin-inline-start: 25%; + } + .column.is-4, .column.is-4-tablet { + flex: none; + width: 33.3333333333%; + } + .column.is-offset-4, .column.is-offset-4-tablet { + margin-inline-start: 33.3333333333%; + } + .column.is-5, .column.is-5-tablet { + flex: none; + width: 41.6666666667%; + } + .column.is-offset-5, .column.is-offset-5-tablet { + margin-inline-start: 41.6666666667%; + } + .column.is-6, .column.is-6-tablet { + flex: none; + width: 50%; + } + .column.is-offset-6, .column.is-offset-6-tablet { + margin-inline-start: 50%; + } + .column.is-7, .column.is-7-tablet { + flex: none; + width: 58.3333333333%; + } + .column.is-offset-7, .column.is-offset-7-tablet { + margin-inline-start: 58.3333333333%; + } + .column.is-8, .column.is-8-tablet { + flex: none; + width: 66.6666666667%; + } + .column.is-offset-8, .column.is-offset-8-tablet { + margin-inline-start: 66.6666666667%; + } + .column.is-9, .column.is-9-tablet { + flex: none; + width: 75%; + } + .column.is-offset-9, .column.is-offset-9-tablet { + margin-inline-start: 75%; + } + .column.is-10, .column.is-10-tablet { + flex: none; + width: 83.3333333333%; + } + .column.is-offset-10, .column.is-offset-10-tablet { + margin-inline-start: 83.3333333333%; + } + .column.is-11, .column.is-11-tablet { + flex: none; + width: 91.6666666667%; + } + .column.is-offset-11, .column.is-offset-11-tablet { + margin-inline-start: 91.6666666667%; + } + .column.is-12, .column.is-12-tablet { + flex: none; + width: 100%; + } + .column.is-offset-12, .column.is-offset-12-tablet { + margin-inline-start: 100%; + } +} +@media screen and (max-width: 1023px) { + .column.is-narrow-touch { + flex: none; + width: unset; + } + .column.is-full-touch { + flex: none; + width: 100%; + } + .column.is-three-quarters-touch { + flex: none; + width: 75%; + } + .column.is-two-thirds-touch { + flex: none; + width: 66.6666%; + } + .column.is-half-touch { + flex: none; + width: 50%; + } + .column.is-one-third-touch { + flex: none; + width: 33.3333%; + } + .column.is-one-quarter-touch { + flex: none; + width: 25%; + } + .column.is-one-fifth-touch { + flex: none; + width: 20%; + } + .column.is-two-fifths-touch { + flex: none; + width: 40%; + } + .column.is-three-fifths-touch { + flex: none; + width: 60%; + } + .column.is-four-fifths-touch { + flex: none; + width: 80%; + } + .column.is-offset-three-quarters-touch { + margin-inline-start: 75%; + } + .column.is-offset-two-thirds-touch { + margin-inline-start: 66.6666%; + } + .column.is-offset-half-touch { + margin-inline-start: 50%; + } + .column.is-offset-one-third-touch { + margin-inline-start: 0.3333%; + } + .column.is-offset-one-quarter-touch { + margin-inline-start: 25%; + } + .column.is-offset-one-fifth-touch { + margin-inline-start: 20%; + } + .column.is-offset-two-fifths-touch { + margin-inline-start: 40%; + } + .column.is-offset-three-fifths-touch { + margin-inline-start: 60%; + } + .column.is-offset-four-fifths-touch { + margin-inline-start: 80%; + } + .column.is-0-touch { + flex: none; + width: 0%; + } + .column.is-offset-0-touch { + margin-inline-start: 0%; + } + .column.is-1-touch { + flex: none; + width: 8.3333333333%; + } + .column.is-offset-1-touch { + margin-inline-start: 8.3333333333%; + } + .column.is-2-touch { + flex: none; + width: 16.6666666667%; + } + .column.is-offset-2-touch { + margin-inline-start: 16.6666666667%; + } + .column.is-3-touch { + flex: none; + width: 25%; + } + .column.is-offset-3-touch { + margin-inline-start: 25%; + } + .column.is-4-touch { + flex: none; + width: 33.3333333333%; + } + .column.is-offset-4-touch { + margin-inline-start: 33.3333333333%; + } + .column.is-5-touch { + flex: none; + width: 41.6666666667%; + } + .column.is-offset-5-touch { + margin-inline-start: 41.6666666667%; + } + .column.is-6-touch { + flex: none; + width: 50%; + } + .column.is-offset-6-touch { + margin-inline-start: 50%; + } + .column.is-7-touch { + flex: none; + width: 58.3333333333%; + } + .column.is-offset-7-touch { + margin-inline-start: 58.3333333333%; + } + .column.is-8-touch { + flex: none; + width: 66.6666666667%; + } + .column.is-offset-8-touch { + margin-inline-start: 66.6666666667%; + } + .column.is-9-touch { + flex: none; + width: 75%; + } + .column.is-offset-9-touch { + margin-inline-start: 75%; + } + .column.is-10-touch { + flex: none; + width: 83.3333333333%; + } + .column.is-offset-10-touch { + margin-inline-start: 83.3333333333%; + } + .column.is-11-touch { + flex: none; + width: 91.6666666667%; + } + .column.is-offset-11-touch { + margin-inline-start: 91.6666666667%; + } + .column.is-12-touch { + flex: none; + width: 100%; + } + .column.is-offset-12-touch { + margin-inline-start: 100%; + } +} +@media screen and (min-width: 1024px) { + .column.is-narrow-desktop { + flex: none; + width: unset; + } + .column.is-full-desktop { + flex: none; + width: 100%; + } + .column.is-three-quarters-desktop { + flex: none; + width: 75%; + } + .column.is-two-thirds-desktop { + flex: none; + width: 66.6666%; + } + .column.is-half-desktop { + flex: none; + width: 50%; + } + .column.is-one-third-desktop { + flex: none; + width: 33.3333%; + } + .column.is-one-quarter-desktop { + flex: none; + width: 25%; + } + .column.is-one-fifth-desktop { + flex: none; + width: 20%; + } + .column.is-two-fifths-desktop { + flex: none; + width: 40%; + } + .column.is-three-fifths-desktop { + flex: none; + width: 60%; + } + .column.is-four-fifths-desktop { + flex: none; + width: 80%; + } + .column.is-offset-three-quarters-desktop { + margin-inline-start: 75%; + } + .column.is-offset-two-thirds-desktop { + margin-inline-start: 66.6666%; + } + .column.is-offset-half-desktop { + margin-inline-start: 50%; + } + .column.is-offset-one-third-desktop { + margin-inline-start: 0.3333%; + } + .column.is-offset-one-quarter-desktop { + margin-inline-start: 25%; + } + .column.is-offset-one-fifth-desktop { + margin-inline-start: 20%; + } + .column.is-offset-two-fifths-desktop { + margin-inline-start: 40%; + } + .column.is-offset-three-fifths-desktop { + margin-inline-start: 60%; + } + .column.is-offset-four-fifths-desktop { + margin-inline-start: 80%; + } + .column.is-0-desktop { + flex: none; + width: 0%; + } + .column.is-offset-0-desktop { + margin-inline-start: 0%; + } + .column.is-1-desktop { + flex: none; + width: 8.3333333333%; + } + .column.is-offset-1-desktop { + margin-inline-start: 8.3333333333%; + } + .column.is-2-desktop { + flex: none; + width: 16.6666666667%; + } + .column.is-offset-2-desktop { + margin-inline-start: 16.6666666667%; + } + .column.is-3-desktop { + flex: none; + width: 25%; + } + .column.is-offset-3-desktop { + margin-inline-start: 25%; + } + .column.is-4-desktop { + flex: none; + width: 33.3333333333%; + } + .column.is-offset-4-desktop { + margin-inline-start: 33.3333333333%; + } + .column.is-5-desktop { + flex: none; + width: 41.6666666667%; + } + .column.is-offset-5-desktop { + margin-inline-start: 41.6666666667%; + } + .column.is-6-desktop { + flex: none; + width: 50%; + } + .column.is-offset-6-desktop { + margin-inline-start: 50%; + } + .column.is-7-desktop { + flex: none; + width: 58.3333333333%; + } + .column.is-offset-7-desktop { + margin-inline-start: 58.3333333333%; + } + .column.is-8-desktop { + flex: none; + width: 66.6666666667%; + } + .column.is-offset-8-desktop { + margin-inline-start: 66.6666666667%; + } + .column.is-9-desktop { + flex: none; + width: 75%; + } + .column.is-offset-9-desktop { + margin-inline-start: 75%; + } + .column.is-10-desktop { + flex: none; + width: 83.3333333333%; + } + .column.is-offset-10-desktop { + margin-inline-start: 83.3333333333%; + } + .column.is-11-desktop { + flex: none; + width: 91.6666666667%; + } + .column.is-offset-11-desktop { + margin-inline-start: 91.6666666667%; + } + .column.is-12-desktop { + flex: none; + width: 100%; + } + .column.is-offset-12-desktop { + margin-inline-start: 100%; + } +} +@media screen and (min-width: 1216px) { + .column.is-narrow-widescreen { + flex: none; + width: unset; + } + .column.is-full-widescreen { + flex: none; + width: 100%; + } + .column.is-three-quarters-widescreen { + flex: none; + width: 75%; + } + .column.is-two-thirds-widescreen { + flex: none; + width: 66.6666%; + } + .column.is-half-widescreen { + flex: none; + width: 50%; + } + .column.is-one-third-widescreen { + flex: none; + width: 33.3333%; + } + .column.is-one-quarter-widescreen { + flex: none; + width: 25%; + } + .column.is-one-fifth-widescreen { + flex: none; + width: 20%; + } + .column.is-two-fifths-widescreen { + flex: none; + width: 40%; + } + .column.is-three-fifths-widescreen { + flex: none; + width: 60%; + } + .column.is-four-fifths-widescreen { + flex: none; + width: 80%; + } + .column.is-offset-three-quarters-widescreen { + margin-inline-start: 75%; + } + .column.is-offset-two-thirds-widescreen { + margin-inline-start: 66.6666%; + } + .column.is-offset-half-widescreen { + margin-inline-start: 50%; + } + .column.is-offset-one-third-widescreen { + margin-inline-start: 0.3333%; + } + .column.is-offset-one-quarter-widescreen { + margin-inline-start: 25%; + } + .column.is-offset-one-fifth-widescreen { + margin-inline-start: 20%; + } + .column.is-offset-two-fifths-widescreen { + margin-inline-start: 40%; + } + .column.is-offset-three-fifths-widescreen { + margin-inline-start: 60%; + } + .column.is-offset-four-fifths-widescreen { + margin-inline-start: 80%; + } + .column.is-0-widescreen { + flex: none; + width: 0%; + } + .column.is-offset-0-widescreen { + margin-inline-start: 0%; + } + .column.is-1-widescreen { + flex: none; + width: 8.3333333333%; + } + .column.is-offset-1-widescreen { + margin-inline-start: 8.3333333333%; + } + .column.is-2-widescreen { + flex: none; + width: 16.6666666667%; + } + .column.is-offset-2-widescreen { + margin-inline-start: 16.6666666667%; + } + .column.is-3-widescreen { + flex: none; + width: 25%; + } + .column.is-offset-3-widescreen { + margin-inline-start: 25%; + } + .column.is-4-widescreen { + flex: none; + width: 33.3333333333%; + } + .column.is-offset-4-widescreen { + margin-inline-start: 33.3333333333%; + } + .column.is-5-widescreen { + flex: none; + width: 41.6666666667%; + } + .column.is-offset-5-widescreen { + margin-inline-start: 41.6666666667%; + } + .column.is-6-widescreen { + flex: none; + width: 50%; + } + .column.is-offset-6-widescreen { + margin-inline-start: 50%; + } + .column.is-7-widescreen { + flex: none; + width: 58.3333333333%; + } + .column.is-offset-7-widescreen { + margin-inline-start: 58.3333333333%; + } + .column.is-8-widescreen { + flex: none; + width: 66.6666666667%; + } + .column.is-offset-8-widescreen { + margin-inline-start: 66.6666666667%; + } + .column.is-9-widescreen { + flex: none; + width: 75%; + } + .column.is-offset-9-widescreen { + margin-inline-start: 75%; + } + .column.is-10-widescreen { + flex: none; + width: 83.3333333333%; + } + .column.is-offset-10-widescreen { + margin-inline-start: 83.3333333333%; + } + .column.is-11-widescreen { + flex: none; + width: 91.6666666667%; + } + .column.is-offset-11-widescreen { + margin-inline-start: 91.6666666667%; + } + .column.is-12-widescreen { + flex: none; + width: 100%; + } + .column.is-offset-12-widescreen { + margin-inline-start: 100%; + } +} +@media screen and (min-width: 1408px) { + .column.is-narrow-fullhd { + flex: none; + width: unset; + } + .column.is-full-fullhd { + flex: none; + width: 100%; + } + .column.is-three-quarters-fullhd { + flex: none; + width: 75%; + } + .column.is-two-thirds-fullhd { + flex: none; + width: 66.6666%; + } + .column.is-half-fullhd { + flex: none; + width: 50%; + } + .column.is-one-third-fullhd { + flex: none; + width: 33.3333%; + } + .column.is-one-quarter-fullhd { + flex: none; + width: 25%; + } + .column.is-one-fifth-fullhd { + flex: none; + width: 20%; + } + .column.is-two-fifths-fullhd { + flex: none; + width: 40%; + } + .column.is-three-fifths-fullhd { + flex: none; + width: 60%; + } + .column.is-four-fifths-fullhd { + flex: none; + width: 80%; + } + .column.is-offset-three-quarters-fullhd { + margin-inline-start: 75%; + } + .column.is-offset-two-thirds-fullhd { + margin-inline-start: 66.6666%; + } + .column.is-offset-half-fullhd { + margin-inline-start: 50%; + } + .column.is-offset-one-third-fullhd { + margin-inline-start: 33.3333%; + } + .column.is-offset-one-quarter-fullhd { + margin-inline-start: 25%; + } + .column.is-offset-one-fifth-fullhd { + margin-inline-start: 20%; + } + .column.is-offset-two-fifths-fullhd { + margin-inline-start: 40%; + } + .column.is-offset-three-fifths-fullhd { + margin-inline-start: 60%; + } + .column.is-offset-four-fifths-fullhd { + margin-inline-start: 80%; + } + .column.is-0-fullhd { + flex: none; + width: 0%; + } + .column.is-offset-0-fullhd { + margin-inline-start: 0%; + } + .column.is-1-fullhd { + flex: none; + width: 8.3333333333%; + } + .column.is-offset-1-fullhd { + margin-inline-start: 8.3333333333%; + } + .column.is-2-fullhd { + flex: none; + width: 16.6666666667%; + } + .column.is-offset-2-fullhd { + margin-inline-start: 16.6666666667%; + } + .column.is-3-fullhd { + flex: none; + width: 25%; + } + .column.is-offset-3-fullhd { + margin-inline-start: 25%; + } + .column.is-4-fullhd { + flex: none; + width: 33.3333333333%; + } + .column.is-offset-4-fullhd { + margin-inline-start: 33.3333333333%; + } + .column.is-5-fullhd { + flex: none; + width: 41.6666666667%; + } + .column.is-offset-5-fullhd { + margin-inline-start: 41.6666666667%; + } + .column.is-6-fullhd { + flex: none; + width: 50%; + } + .column.is-offset-6-fullhd { + margin-inline-start: 50%; + } + .column.is-7-fullhd { + flex: none; + width: 58.3333333333%; + } + .column.is-offset-7-fullhd { + margin-inline-start: 58.3333333333%; + } + .column.is-8-fullhd { + flex: none; + width: 66.6666666667%; + } + .column.is-offset-8-fullhd { + margin-inline-start: 66.6666666667%; + } + .column.is-9-fullhd { + flex: none; + width: 75%; + } + .column.is-offset-9-fullhd { + margin-inline-start: 75%; + } + .column.is-10-fullhd { + flex: none; + width: 83.3333333333%; + } + .column.is-offset-10-fullhd { + margin-inline-start: 83.3333333333%; + } + .column.is-11-fullhd { + flex: none; + width: 91.6666666667%; + } + .column.is-offset-11-fullhd { + margin-inline-start: 91.6666666667%; + } + .column.is-12-fullhd { + flex: none; + width: 100%; + } + .column.is-offset-12-fullhd { + margin-inline-start: 100%; + } +} + +.columns { + margin-inline-start: calc(-1 * var(--bulma-column-gap)); + margin-inline-end: calc(-1 * var(--bulma-column-gap)); + margin-top: calc(-1 * var(--bulma-column-gap)); +} +.columns:last-child { + margin-bottom: calc(-1 * var(--bulma-column-gap)); +} +.columns:not(:last-child) { + margin-bottom: calc(var(--bulma-block-spacing) - var(--bulma-column-gap)); +} +.columns.is-centered { + justify-content: center; +} +.columns.is-gapless { + margin-inline-start: 0; + margin-inline-end: 0; + margin-top: 0; +} +.columns.is-gapless > .column { + margin: 0; + padding: 0 !important; +} +.columns.is-gapless:not(:last-child) { + margin-bottom: 1.5rem; +} +.columns.is-gapless:last-child { + margin-bottom: 0; +} +.columns.is-mobile { + display: flex; +} +.columns.is-multiline { + flex-wrap: wrap; +} +.columns.is-vcentered { + align-items: center; +} +@media screen and (min-width: 769px), print { + .columns:not(.is-desktop) { + display: flex; + } +} +@media screen and (min-width: 1024px) { + .columns.is-desktop { + display: flex; + } +} +.columns.is-0 { + --bulma-column-gap: 0rem; +} +@media screen and (max-width: 768px) { + .columns.is-0-mobile { + --bulma-column-gap: 0rem; + } +} +@media screen and (min-width: 769px), print { + .columns.is-0-tablet { + --bulma-column-gap: 0rem; + } +} +@media screen and (min-width: 769px) and (max-width: 1023px) { + .columns.is-0-tablet-only { + --bulma-column-gap: 0rem; + } +} +@media screen and (max-width: 1023px) { + .columns.is-0-touch { + --bulma-column-gap: 0rem; + } +} +@media screen and (min-width: 1024px) { + .columns.is-0-desktop { + --bulma-column-gap: 0rem; + } +} +@media screen and (min-width: 1024px) and (max-width: 1215px) { + .columns.is-0-desktop-only { + --bulma-column-gap: 0rem; + } +} +@media screen and (min-width: 1216px) { + .columns.is-0-widescreen { + --bulma-column-gap: 0rem; + } +} +@media screen and (min-width: 1216px) and (max-width: 1407px) { + .columns.is-0-widescreen-only { + --bulma-column-gap: 0rem; + } +} +@media screen and (min-width: 1408px) { + .columns.is-0-fullhd { + --bulma-column-gap: 0rem; + } +} +.columns.is-1 { + --bulma-column-gap: 0.25rem; +} +@media screen and (max-width: 768px) { + .columns.is-1-mobile { + --bulma-column-gap: 0.25rem; + } +} +@media screen and (min-width: 769px), print { + .columns.is-1-tablet { + --bulma-column-gap: 0.25rem; + } +} +@media screen and (min-width: 769px) and (max-width: 1023px) { + .columns.is-1-tablet-only { + --bulma-column-gap: 0.25rem; + } +} +@media screen and (max-width: 1023px) { + .columns.is-1-touch { + --bulma-column-gap: 0.25rem; + } +} +@media screen and (min-width: 1024px) { + .columns.is-1-desktop { + --bulma-column-gap: 0.25rem; + } +} +@media screen and (min-width: 1024px) and (max-width: 1215px) { + .columns.is-1-desktop-only { + --bulma-column-gap: 0.25rem; + } +} +@media screen and (min-width: 1216px) { + .columns.is-1-widescreen { + --bulma-column-gap: 0.25rem; + } +} +@media screen and (min-width: 1216px) and (max-width: 1407px) { + .columns.is-1-widescreen-only { + --bulma-column-gap: 0.25rem; + } +} +@media screen and (min-width: 1408px) { + .columns.is-1-fullhd { + --bulma-column-gap: 0.25rem; + } +} +.columns.is-2 { + --bulma-column-gap: 0.5rem; +} +@media screen and (max-width: 768px) { + .columns.is-2-mobile { + --bulma-column-gap: 0.5rem; + } +} +@media screen and (min-width: 769px), print { + .columns.is-2-tablet { + --bulma-column-gap: 0.5rem; + } +} +@media screen and (min-width: 769px) and (max-width: 1023px) { + .columns.is-2-tablet-only { + --bulma-column-gap: 0.5rem; + } +} +@media screen and (max-width: 1023px) { + .columns.is-2-touch { + --bulma-column-gap: 0.5rem; + } +} +@media screen and (min-width: 1024px) { + .columns.is-2-desktop { + --bulma-column-gap: 0.5rem; + } +} +@media screen and (min-width: 1024px) and (max-width: 1215px) { + .columns.is-2-desktop-only { + --bulma-column-gap: 0.5rem; + } +} +@media screen and (min-width: 1216px) { + .columns.is-2-widescreen { + --bulma-column-gap: 0.5rem; + } +} +@media screen and (min-width: 1216px) and (max-width: 1407px) { + .columns.is-2-widescreen-only { + --bulma-column-gap: 0.5rem; + } +} +@media screen and (min-width: 1408px) { + .columns.is-2-fullhd { + --bulma-column-gap: 0.5rem; + } +} +.columns.is-3 { + --bulma-column-gap: 0.75rem; +} +@media screen and (max-width: 768px) { + .columns.is-3-mobile { + --bulma-column-gap: 0.75rem; + } +} +@media screen and (min-width: 769px), print { + .columns.is-3-tablet { + --bulma-column-gap: 0.75rem; + } +} +@media screen and (min-width: 769px) and (max-width: 1023px) { + .columns.is-3-tablet-only { + --bulma-column-gap: 0.75rem; + } +} +@media screen and (max-width: 1023px) { + .columns.is-3-touch { + --bulma-column-gap: 0.75rem; + } +} +@media screen and (min-width: 1024px) { + .columns.is-3-desktop { + --bulma-column-gap: 0.75rem; + } +} +@media screen and (min-width: 1024px) and (max-width: 1215px) { + .columns.is-3-desktop-only { + --bulma-column-gap: 0.75rem; + } +} +@media screen and (min-width: 1216px) { + .columns.is-3-widescreen { + --bulma-column-gap: 0.75rem; + } +} +@media screen and (min-width: 1216px) and (max-width: 1407px) { + .columns.is-3-widescreen-only { + --bulma-column-gap: 0.75rem; + } +} +@media screen and (min-width: 1408px) { + .columns.is-3-fullhd { + --bulma-column-gap: 0.75rem; + } +} +.columns.is-4 { + --bulma-column-gap: 1rem; +} +@media screen and (max-width: 768px) { + .columns.is-4-mobile { + --bulma-column-gap: 1rem; + } +} +@media screen and (min-width: 769px), print { + .columns.is-4-tablet { + --bulma-column-gap: 1rem; + } +} +@media screen and (min-width: 769px) and (max-width: 1023px) { + .columns.is-4-tablet-only { + --bulma-column-gap: 1rem; + } +} +@media screen and (max-width: 1023px) { + .columns.is-4-touch { + --bulma-column-gap: 1rem; + } +} +@media screen and (min-width: 1024px) { + .columns.is-4-desktop { + --bulma-column-gap: 1rem; + } +} +@media screen and (min-width: 1024px) and (max-width: 1215px) { + .columns.is-4-desktop-only { + --bulma-column-gap: 1rem; + } +} +@media screen and (min-width: 1216px) { + .columns.is-4-widescreen { + --bulma-column-gap: 1rem; + } +} +@media screen and (min-width: 1216px) and (max-width: 1407px) { + .columns.is-4-widescreen-only { + --bulma-column-gap: 1rem; + } +} +@media screen and (min-width: 1408px) { + .columns.is-4-fullhd { + --bulma-column-gap: 1rem; + } +} +.columns.is-5 { + --bulma-column-gap: 1.25rem; +} +@media screen and (max-width: 768px) { + .columns.is-5-mobile { + --bulma-column-gap: 1.25rem; + } +} +@media screen and (min-width: 769px), print { + .columns.is-5-tablet { + --bulma-column-gap: 1.25rem; + } +} +@media screen and (min-width: 769px) and (max-width: 1023px) { + .columns.is-5-tablet-only { + --bulma-column-gap: 1.25rem; + } +} +@media screen and (max-width: 1023px) { + .columns.is-5-touch { + --bulma-column-gap: 1.25rem; + } +} +@media screen and (min-width: 1024px) { + .columns.is-5-desktop { + --bulma-column-gap: 1.25rem; + } +} +@media screen and (min-width: 1024px) and (max-width: 1215px) { + .columns.is-5-desktop-only { + --bulma-column-gap: 1.25rem; + } +} +@media screen and (min-width: 1216px) { + .columns.is-5-widescreen { + --bulma-column-gap: 1.25rem; + } +} +@media screen and (min-width: 1216px) and (max-width: 1407px) { + .columns.is-5-widescreen-only { + --bulma-column-gap: 1.25rem; + } +} +@media screen and (min-width: 1408px) { + .columns.is-5-fullhd { + --bulma-column-gap: 1.25rem; + } +} +.columns.is-6 { + --bulma-column-gap: 1.5rem; +} +@media screen and (max-width: 768px) { + .columns.is-6-mobile { + --bulma-column-gap: 1.5rem; + } +} +@media screen and (min-width: 769px), print { + .columns.is-6-tablet { + --bulma-column-gap: 1.5rem; + } +} +@media screen and (min-width: 769px) and (max-width: 1023px) { + .columns.is-6-tablet-only { + --bulma-column-gap: 1.5rem; + } +} +@media screen and (max-width: 1023px) { + .columns.is-6-touch { + --bulma-column-gap: 1.5rem; + } +} +@media screen and (min-width: 1024px) { + .columns.is-6-desktop { + --bulma-column-gap: 1.5rem; + } +} +@media screen and (min-width: 1024px) and (max-width: 1215px) { + .columns.is-6-desktop-only { + --bulma-column-gap: 1.5rem; + } +} +@media screen and (min-width: 1216px) { + .columns.is-6-widescreen { + --bulma-column-gap: 1.5rem; + } +} +@media screen and (min-width: 1216px) and (max-width: 1407px) { + .columns.is-6-widescreen-only { + --bulma-column-gap: 1.5rem; + } +} +@media screen and (min-width: 1408px) { + .columns.is-6-fullhd { + --bulma-column-gap: 1.5rem; + } +} +.columns.is-7 { + --bulma-column-gap: 1.75rem; +} +@media screen and (max-width: 768px) { + .columns.is-7-mobile { + --bulma-column-gap: 1.75rem; + } +} +@media screen and (min-width: 769px), print { + .columns.is-7-tablet { + --bulma-column-gap: 1.75rem; + } +} +@media screen and (min-width: 769px) and (max-width: 1023px) { + .columns.is-7-tablet-only { + --bulma-column-gap: 1.75rem; + } +} +@media screen and (max-width: 1023px) { + .columns.is-7-touch { + --bulma-column-gap: 1.75rem; + } +} +@media screen and (min-width: 1024px) { + .columns.is-7-desktop { + --bulma-column-gap: 1.75rem; + } +} +@media screen and (min-width: 1024px) and (max-width: 1215px) { + .columns.is-7-desktop-only { + --bulma-column-gap: 1.75rem; + } +} +@media screen and (min-width: 1216px) { + .columns.is-7-widescreen { + --bulma-column-gap: 1.75rem; + } +} +@media screen and (min-width: 1216px) and (max-width: 1407px) { + .columns.is-7-widescreen-only { + --bulma-column-gap: 1.75rem; + } +} +@media screen and (min-width: 1408px) { + .columns.is-7-fullhd { + --bulma-column-gap: 1.75rem; + } +} +.columns.is-8 { + --bulma-column-gap: 2rem; +} +@media screen and (max-width: 768px) { + .columns.is-8-mobile { + --bulma-column-gap: 2rem; + } +} +@media screen and (min-width: 769px), print { + .columns.is-8-tablet { + --bulma-column-gap: 2rem; + } +} +@media screen and (min-width: 769px) and (max-width: 1023px) { + .columns.is-8-tablet-only { + --bulma-column-gap: 2rem; + } +} +@media screen and (max-width: 1023px) { + .columns.is-8-touch { + --bulma-column-gap: 2rem; + } +} +@media screen and (min-width: 1024px) { + .columns.is-8-desktop { + --bulma-column-gap: 2rem; + } +} +@media screen and (min-width: 1024px) and (max-width: 1215px) { + .columns.is-8-desktop-only { + --bulma-column-gap: 2rem; + } +} +@media screen and (min-width: 1216px) { + .columns.is-8-widescreen { + --bulma-column-gap: 2rem; + } +} +@media screen and (min-width: 1216px) and (max-width: 1407px) { + .columns.is-8-widescreen-only { + --bulma-column-gap: 2rem; + } +} +@media screen and (min-width: 1408px) { + .columns.is-8-fullhd { + --bulma-column-gap: 2rem; + } +} + +.fixed-grid { + container-name: bulma-fixed-grid; + container-type: inline-size; +} +.fixed-grid > .grid { + --bulma-grid-gap-count: calc(var(--bulma-grid-column-count) - 1); + --bulma-grid-column-count: 2; + grid-template-columns: repeat(var(--bulma-grid-column-count), 1fr); +} +.fixed-grid.has-1-cols > .grid { + --bulma-grid-column-count: 1; +} +.fixed-grid.has-2-cols > .grid { + --bulma-grid-column-count: 2; +} +.fixed-grid.has-3-cols > .grid { + --bulma-grid-column-count: 3; +} +.fixed-grid.has-4-cols > .grid { + --bulma-grid-column-count: 4; +} +.fixed-grid.has-5-cols > .grid { + --bulma-grid-column-count: 5; +} +.fixed-grid.has-6-cols > .grid { + --bulma-grid-column-count: 6; +} +.fixed-grid.has-7-cols > .grid { + --bulma-grid-column-count: 7; +} +.fixed-grid.has-8-cols > .grid { + --bulma-grid-column-count: 8; +} +.fixed-grid.has-9-cols > .grid { + --bulma-grid-column-count: 9; +} +.fixed-grid.has-10-cols > .grid { + --bulma-grid-column-count: 10; +} +.fixed-grid.has-11-cols > .grid { + --bulma-grid-column-count: 11; +} +.fixed-grid.has-12-cols > .grid { + --bulma-grid-column-count: 12; +} +@container bulma-fixed-grid (max-width: 768px) { + .fixed-grid.has-1-cols-mobile > .grid { + --bulma-grid-column-count: 1; + } + .fixed-grid.has-2-cols-mobile > .grid { + --bulma-grid-column-count: 2; + } + .fixed-grid.has-3-cols-mobile > .grid { + --bulma-grid-column-count: 3; + } + .fixed-grid.has-4-cols-mobile > .grid { + --bulma-grid-column-count: 4; + } + .fixed-grid.has-5-cols-mobile > .grid { + --bulma-grid-column-count: 5; + } + .fixed-grid.has-6-cols-mobile > .grid { + --bulma-grid-column-count: 6; + } + .fixed-grid.has-7-cols-mobile > .grid { + --bulma-grid-column-count: 7; + } + .fixed-grid.has-8-cols-mobile > .grid { + --bulma-grid-column-count: 8; + } + .fixed-grid.has-9-cols-mobile > .grid { + --bulma-grid-column-count: 9; + } + .fixed-grid.has-10-cols-mobile > .grid { + --bulma-grid-column-count: 10; + } + .fixed-grid.has-11-cols-mobile > .grid { + --bulma-grid-column-count: 11; + } + .fixed-grid.has-12-cols-mobile > .grid { + --bulma-grid-column-count: 12; + } +} +@container bulma-fixed-grid (min-width: 769px) { + .fixed-grid.has-1-cols-tablet > .grid { + --bulma-grid-column-count: 1; + } + .fixed-grid.has-2-cols-tablet > .grid { + --bulma-grid-column-count: 2; + } + .fixed-grid.has-3-cols-tablet > .grid { + --bulma-grid-column-count: 3; + } + .fixed-grid.has-4-cols-tablet > .grid { + --bulma-grid-column-count: 4; + } + .fixed-grid.has-5-cols-tablet > .grid { + --bulma-grid-column-count: 5; + } + .fixed-grid.has-6-cols-tablet > .grid { + --bulma-grid-column-count: 6; + } + .fixed-grid.has-7-cols-tablet > .grid { + --bulma-grid-column-count: 7; + } + .fixed-grid.has-8-cols-tablet > .grid { + --bulma-grid-column-count: 8; + } + .fixed-grid.has-9-cols-tablet > .grid { + --bulma-grid-column-count: 9; + } + .fixed-grid.has-10-cols-tablet > .grid { + --bulma-grid-column-count: 10; + } + .fixed-grid.has-11-cols-tablet > .grid { + --bulma-grid-column-count: 11; + } + .fixed-grid.has-12-cols-tablet > .grid { + --bulma-grid-column-count: 12; + } +} +@container bulma-fixed-grid (min-width: 1024px) { + .fixed-grid.has-1-cols-desktop > .grid { + --bulma-grid-column-count: 1; + } + .fixed-grid.has-2-cols-desktop > .grid { + --bulma-grid-column-count: 2; + } + .fixed-grid.has-3-cols-desktop > .grid { + --bulma-grid-column-count: 3; + } + .fixed-grid.has-4-cols-desktop > .grid { + --bulma-grid-column-count: 4; + } + .fixed-grid.has-5-cols-desktop > .grid { + --bulma-grid-column-count: 5; + } + .fixed-grid.has-6-cols-desktop > .grid { + --bulma-grid-column-count: 6; + } + .fixed-grid.has-7-cols-desktop > .grid { + --bulma-grid-column-count: 7; + } + .fixed-grid.has-8-cols-desktop > .grid { + --bulma-grid-column-count: 8; + } + .fixed-grid.has-9-cols-desktop > .grid { + --bulma-grid-column-count: 9; + } + .fixed-grid.has-10-cols-desktop > .grid { + --bulma-grid-column-count: 10; + } + .fixed-grid.has-11-cols-desktop > .grid { + --bulma-grid-column-count: 11; + } + .fixed-grid.has-12-cols-desktop > .grid { + --bulma-grid-column-count: 12; + } +} +@container bulma-fixed-grid (min-width: 1216px) { + .fixed-grid.has-1-cols-widescreen > .grid { + --bulma-grid-column-count: 1; + } + .fixed-grid.has-2-cols-widescreen > .grid { + --bulma-grid-column-count: 2; + } + .fixed-grid.has-3-cols-widescreen > .grid { + --bulma-grid-column-count: 3; + } + .fixed-grid.has-4-cols-widescreen > .grid { + --bulma-grid-column-count: 4; + } + .fixed-grid.has-5-cols-widescreen > .grid { + --bulma-grid-column-count: 5; + } + .fixed-grid.has-6-cols-widescreen > .grid { + --bulma-grid-column-count: 6; + } + .fixed-grid.has-7-cols-widescreen > .grid { + --bulma-grid-column-count: 7; + } + .fixed-grid.has-8-cols-widescreen > .grid { + --bulma-grid-column-count: 8; + } + .fixed-grid.has-9-cols-widescreen > .grid { + --bulma-grid-column-count: 9; + } + .fixed-grid.has-10-cols-widescreen > .grid { + --bulma-grid-column-count: 10; + } + .fixed-grid.has-11-cols-widescreen > .grid { + --bulma-grid-column-count: 11; + } + .fixed-grid.has-12-cols-widescreen > .grid { + --bulma-grid-column-count: 12; + } +} +@container bulma-fixed-grid (min-width: 1408px) { + .fixed-grid.has-1-cols-fullhd > .grid { + --bulma-grid-column-count: 1; + } + .fixed-grid.has-2-cols-fullhd > .grid { + --bulma-grid-column-count: 2; + } + .fixed-grid.has-3-cols-fullhd > .grid { + --bulma-grid-column-count: 3; + } + .fixed-grid.has-4-cols-fullhd > .grid { + --bulma-grid-column-count: 4; + } + .fixed-grid.has-5-cols-fullhd > .grid { + --bulma-grid-column-count: 5; + } + .fixed-grid.has-6-cols-fullhd > .grid { + --bulma-grid-column-count: 6; + } + .fixed-grid.has-7-cols-fullhd > .grid { + --bulma-grid-column-count: 7; + } + .fixed-grid.has-8-cols-fullhd > .grid { + --bulma-grid-column-count: 8; + } + .fixed-grid.has-9-cols-fullhd > .grid { + --bulma-grid-column-count: 9; + } + .fixed-grid.has-10-cols-fullhd > .grid { + --bulma-grid-column-count: 10; + } + .fixed-grid.has-11-cols-fullhd > .grid { + --bulma-grid-column-count: 11; + } + .fixed-grid.has-12-cols-fullhd > .grid { + --bulma-grid-column-count: 12; + } +} +@container bulma-fixed-grid (max-width: 768px) { + .fixed-grid.has-auto-count .grid { + --bulma-grid-column-count: 2; + } +} +@container bulma-fixed-grid (min-width: 769px) { + .fixed-grid.has-auto-count .grid { + --bulma-grid-column-count: 4; + } +} +@container bulma-fixed-grid (min-width: 1024px) { + .fixed-grid.has-auto-count .grid { + --bulma-grid-column-count: 8; + } +} +@container bulma-fixed-grid (min-width: 1216px) { + .fixed-grid.has-auto-count .grid { + --bulma-grid-column-count: 12; + } +} +@container bulma-fixed-grid (min-width: 1408px) { + .fixed-grid.has-auto-count .grid { + --bulma-grid-column-count: 16; + } +} + +.grid { + --bulma-grid-gap: 0.75rem; + --bulma-grid-column-min: 9rem; + --bulma-grid-cell-column-span: 1; + --bulma-grid-cell-row-span: 1; + display: grid; + gap: var(--bulma-grid-gap); + column-gap: var(--bulma-grid-column-gap, var(--bulma-grid-gap)); + row-gap: var(--bulma-grid-row-gap, var(--bulma-grid-gap)); + grid-template-columns: repeat(auto-fit, minmax(var(--bulma-grid-column-min), 1fr)); + grid-template-rows: auto; +} +.grid.is-auto-fill { + grid-template-columns: repeat(auto-fill, minmax(var(--bulma-grid-column-min), 1fr)); +} +.grid.is-col-min-1 { + --bulma-grid-column-min: 1.5rem; +} +.grid.is-col-min-2 { + --bulma-grid-column-min: 3rem; +} +.grid.is-col-min-3 { + --bulma-grid-column-min: 4.5rem; +} +.grid.is-col-min-4 { + --bulma-grid-column-min: 6rem; +} +.grid.is-col-min-5 { + --bulma-grid-column-min: 7.5rem; +} +.grid.is-col-min-6 { + --bulma-grid-column-min: 9rem; +} +.grid.is-col-min-7 { + --bulma-grid-column-min: 10.5rem; +} +.grid.is-col-min-8 { + --bulma-grid-column-min: 12rem; +} +.grid.is-col-min-9 { + --bulma-grid-column-min: 13.5rem; +} +.grid.is-col-min-10 { + --bulma-grid-column-min: 15rem; +} +.grid.is-col-min-11 { + --bulma-grid-column-min: 16.5rem; +} +.grid.is-col-min-12 { + --bulma-grid-column-min: 18rem; +} +.grid.is-col-min-13 { + --bulma-grid-column-min: 19.5rem; +} +.grid.is-col-min-14 { + --bulma-grid-column-min: 21rem; +} +.grid.is-col-min-15 { + --bulma-grid-column-min: 22.5rem; +} +.grid.is-col-min-16 { + --bulma-grid-column-min: 24rem; +} +.grid.is-col-min-17 { + --bulma-grid-column-min: 25.5rem; +} +.grid.is-col-min-18 { + --bulma-grid-column-min: 27rem; +} +.grid.is-col-min-19 { + --bulma-grid-column-min: 28.5rem; +} +.grid.is-col-min-20 { + --bulma-grid-column-min: 30rem; +} +.grid.is-col-min-21 { + --bulma-grid-column-min: 31.5rem; +} +.grid.is-col-min-22 { + --bulma-grid-column-min: 33rem; +} +.grid.is-col-min-23 { + --bulma-grid-column-min: 34.5rem; +} +.grid.is-col-min-24 { + --bulma-grid-column-min: 36rem; +} +.grid.is-col-min-25 { + --bulma-grid-column-min: 37.5rem; +} +.grid.is-col-min-26 { + --bulma-grid-column-min: 39rem; +} +.grid.is-col-min-27 { + --bulma-grid-column-min: 40.5rem; +} +.grid.is-col-min-28 { + --bulma-grid-column-min: 42rem; +} +.grid.is-col-min-29 { + --bulma-grid-column-min: 43.5rem; +} +.grid.is-col-min-30 { + --bulma-grid-column-min: 45rem; +} +.grid.is-col-min-31 { + --bulma-grid-column-min: 46.5rem; +} +.grid.is-col-min-32 { + --bulma-grid-column-min: 48rem; +} + +.cell { + grid-column-end: span var(--bulma-grid-cell-column-span); + grid-column-start: var(--bulma-grid-cell-column-start); + grid-row-end: span var(--bulma-grid-cell-row-span); + grid-row-start: var(--bulma-grid-cell-row-start); +} +.cell.is-col-start-end { + --bulma-grid-cell-column-start: -1; +} +.cell.is-row-start-end { + --bulma-grid-cell-row-start: -1; +} +.cell.is-col-start-1 { + --bulma-grid-cell-column-start: 1; +} +.cell.is-col-end-1 { + --bulma-grid-cell-column-end: 1; +} +.cell.is-col-from-end-1 { + --bulma-grid-cell-column-start: -1; +} +.cell.is-col-span-1 { + --bulma-grid-cell-column-span: 1; +} +.cell.is-row-start-1 { + --bulma-grid-cell-row-start: 1; +} +.cell.is-row-end-1 { + --bulma-grid-cell-row-end: 1; +} +.cell.is-row-from-end-1 { + --bulma-grid-cell-row-start: -1; +} +.cell.is-row-span-1 { + --bulma-grid-cell-row-span: 1; +} +.cell.is-col-start-2 { + --bulma-grid-cell-column-start: 2; +} +.cell.is-col-end-2 { + --bulma-grid-cell-column-end: 2; +} +.cell.is-col-from-end-2 { + --bulma-grid-cell-column-start: -2; +} +.cell.is-col-span-2 { + --bulma-grid-cell-column-span: 2; +} +.cell.is-row-start-2 { + --bulma-grid-cell-row-start: 2; +} +.cell.is-row-end-2 { + --bulma-grid-cell-row-end: 2; +} +.cell.is-row-from-end-2 { + --bulma-grid-cell-row-start: -2; +} +.cell.is-row-span-2 { + --bulma-grid-cell-row-span: 2; +} +.cell.is-col-start-3 { + --bulma-grid-cell-column-start: 3; +} +.cell.is-col-end-3 { + --bulma-grid-cell-column-end: 3; +} +.cell.is-col-from-end-3 { + --bulma-grid-cell-column-start: -3; +} +.cell.is-col-span-3 { + --bulma-grid-cell-column-span: 3; +} +.cell.is-row-start-3 { + --bulma-grid-cell-row-start: 3; +} +.cell.is-row-end-3 { + --bulma-grid-cell-row-end: 3; +} +.cell.is-row-from-end-3 { + --bulma-grid-cell-row-start: -3; +} +.cell.is-row-span-3 { + --bulma-grid-cell-row-span: 3; +} +.cell.is-col-start-4 { + --bulma-grid-cell-column-start: 4; +} +.cell.is-col-end-4 { + --bulma-grid-cell-column-end: 4; +} +.cell.is-col-from-end-4 { + --bulma-grid-cell-column-start: -4; +} +.cell.is-col-span-4 { + --bulma-grid-cell-column-span: 4; +} +.cell.is-row-start-4 { + --bulma-grid-cell-row-start: 4; +} +.cell.is-row-end-4 { + --bulma-grid-cell-row-end: 4; +} +.cell.is-row-from-end-4 { + --bulma-grid-cell-row-start: -4; +} +.cell.is-row-span-4 { + --bulma-grid-cell-row-span: 4; +} +.cell.is-col-start-5 { + --bulma-grid-cell-column-start: 5; +} +.cell.is-col-end-5 { + --bulma-grid-cell-column-end: 5; +} +.cell.is-col-from-end-5 { + --bulma-grid-cell-column-start: -5; +} +.cell.is-col-span-5 { + --bulma-grid-cell-column-span: 5; +} +.cell.is-row-start-5 { + --bulma-grid-cell-row-start: 5; +} +.cell.is-row-end-5 { + --bulma-grid-cell-row-end: 5; +} +.cell.is-row-from-end-5 { + --bulma-grid-cell-row-start: -5; +} +.cell.is-row-span-5 { + --bulma-grid-cell-row-span: 5; +} +.cell.is-col-start-6 { + --bulma-grid-cell-column-start: 6; +} +.cell.is-col-end-6 { + --bulma-grid-cell-column-end: 6; +} +.cell.is-col-from-end-6 { + --bulma-grid-cell-column-start: -6; +} +.cell.is-col-span-6 { + --bulma-grid-cell-column-span: 6; +} +.cell.is-row-start-6 { + --bulma-grid-cell-row-start: 6; +} +.cell.is-row-end-6 { + --bulma-grid-cell-row-end: 6; +} +.cell.is-row-from-end-6 { + --bulma-grid-cell-row-start: -6; +} +.cell.is-row-span-6 { + --bulma-grid-cell-row-span: 6; +} +.cell.is-col-start-7 { + --bulma-grid-cell-column-start: 7; +} +.cell.is-col-end-7 { + --bulma-grid-cell-column-end: 7; +} +.cell.is-col-from-end-7 { + --bulma-grid-cell-column-start: -7; +} +.cell.is-col-span-7 { + --bulma-grid-cell-column-span: 7; +} +.cell.is-row-start-7 { + --bulma-grid-cell-row-start: 7; +} +.cell.is-row-end-7 { + --bulma-grid-cell-row-end: 7; +} +.cell.is-row-from-end-7 { + --bulma-grid-cell-row-start: -7; +} +.cell.is-row-span-7 { + --bulma-grid-cell-row-span: 7; +} +.cell.is-col-start-8 { + --bulma-grid-cell-column-start: 8; +} +.cell.is-col-end-8 { + --bulma-grid-cell-column-end: 8; +} +.cell.is-col-from-end-8 { + --bulma-grid-cell-column-start: -8; +} +.cell.is-col-span-8 { + --bulma-grid-cell-column-span: 8; +} +.cell.is-row-start-8 { + --bulma-grid-cell-row-start: 8; +} +.cell.is-row-end-8 { + --bulma-grid-cell-row-end: 8; +} +.cell.is-row-from-end-8 { + --bulma-grid-cell-row-start: -8; +} +.cell.is-row-span-8 { + --bulma-grid-cell-row-span: 8; +} +.cell.is-col-start-9 { + --bulma-grid-cell-column-start: 9; +} +.cell.is-col-end-9 { + --bulma-grid-cell-column-end: 9; +} +.cell.is-col-from-end-9 { + --bulma-grid-cell-column-start: -9; +} +.cell.is-col-span-9 { + --bulma-grid-cell-column-span: 9; +} +.cell.is-row-start-9 { + --bulma-grid-cell-row-start: 9; +} +.cell.is-row-end-9 { + --bulma-grid-cell-row-end: 9; +} +.cell.is-row-from-end-9 { + --bulma-grid-cell-row-start: -9; +} +.cell.is-row-span-9 { + --bulma-grid-cell-row-span: 9; +} +.cell.is-col-start-10 { + --bulma-grid-cell-column-start: 10; +} +.cell.is-col-end-10 { + --bulma-grid-cell-column-end: 10; +} +.cell.is-col-from-end-10 { + --bulma-grid-cell-column-start: -10; +} +.cell.is-col-span-10 { + --bulma-grid-cell-column-span: 10; +} +.cell.is-row-start-10 { + --bulma-grid-cell-row-start: 10; +} +.cell.is-row-end-10 { + --bulma-grid-cell-row-end: 10; +} +.cell.is-row-from-end-10 { + --bulma-grid-cell-row-start: -10; +} +.cell.is-row-span-10 { + --bulma-grid-cell-row-span: 10; +} +.cell.is-col-start-11 { + --bulma-grid-cell-column-start: 11; +} +.cell.is-col-end-11 { + --bulma-grid-cell-column-end: 11; +} +.cell.is-col-from-end-11 { + --bulma-grid-cell-column-start: -11; +} +.cell.is-col-span-11 { + --bulma-grid-cell-column-span: 11; +} +.cell.is-row-start-11 { + --bulma-grid-cell-row-start: 11; +} +.cell.is-row-end-11 { + --bulma-grid-cell-row-end: 11; +} +.cell.is-row-from-end-11 { + --bulma-grid-cell-row-start: -11; +} +.cell.is-row-span-11 { + --bulma-grid-cell-row-span: 11; +} +.cell.is-col-start-12 { + --bulma-grid-cell-column-start: 12; +} +.cell.is-col-end-12 { + --bulma-grid-cell-column-end: 12; +} +.cell.is-col-from-end-12 { + --bulma-grid-cell-column-start: -12; +} +.cell.is-col-span-12 { + --bulma-grid-cell-column-span: 12; +} +.cell.is-row-start-12 { + --bulma-grid-cell-row-start: 12; +} +.cell.is-row-end-12 { + --bulma-grid-cell-row-end: 12; +} +.cell.is-row-from-end-12 { + --bulma-grid-cell-row-start: -12; +} +.cell.is-row-span-12 { + --bulma-grid-cell-row-span: 12; +} +@media screen and (max-width: 768px) { + .cell.is-col-start-1-mobile { + --bulma-grid-cell-column-start: 1; + } + .cell.is-col-end-1-mobile { + --bulma-grid-cell-column-end: 1; + } + .cell.is-col-from-end-1-mobile { + --bulma-grid-cell-column-start: -1; + } + .cell.is-col-span-1-mobile { + --bulma-grid-cell-column-span: 1; + } + .cell.is-row-start-1-mobile { + --bulma-grid-cell-row-start: 1; + } + .cell.is-row-end-1-mobile { + --bulma-grid-cell-row-end: 1; + } + .cell.is-row-from-end-1-mobile { + --bulma-grid-cell-row-start: -1; + } + .cell.is-row-span-1-mobile { + --bulma-grid-cell-row-span: 1; + } + .cell.is-col-start-2-mobile { + --bulma-grid-cell-column-start: 2; + } + .cell.is-col-end-2-mobile { + --bulma-grid-cell-column-end: 2; + } + .cell.is-col-from-end-2-mobile { + --bulma-grid-cell-column-start: -2; + } + .cell.is-col-span-2-mobile { + --bulma-grid-cell-column-span: 2; + } + .cell.is-row-start-2-mobile { + --bulma-grid-cell-row-start: 2; + } + .cell.is-row-end-2-mobile { + --bulma-grid-cell-row-end: 2; + } + .cell.is-row-from-end-2-mobile { + --bulma-grid-cell-row-start: -2; + } + .cell.is-row-span-2-mobile { + --bulma-grid-cell-row-span: 2; + } + .cell.is-col-start-3-mobile { + --bulma-grid-cell-column-start: 3; + } + .cell.is-col-end-3-mobile { + --bulma-grid-cell-column-end: 3; + } + .cell.is-col-from-end-3-mobile { + --bulma-grid-cell-column-start: -3; + } + .cell.is-col-span-3-mobile { + --bulma-grid-cell-column-span: 3; + } + .cell.is-row-start-3-mobile { + --bulma-grid-cell-row-start: 3; + } + .cell.is-row-end-3-mobile { + --bulma-grid-cell-row-end: 3; + } + .cell.is-row-from-end-3-mobile { + --bulma-grid-cell-row-start: -3; + } + .cell.is-row-span-3-mobile { + --bulma-grid-cell-row-span: 3; + } + .cell.is-col-start-4-mobile { + --bulma-grid-cell-column-start: 4; + } + .cell.is-col-end-4-mobile { + --bulma-grid-cell-column-end: 4; + } + .cell.is-col-from-end-4-mobile { + --bulma-grid-cell-column-start: -4; + } + .cell.is-col-span-4-mobile { + --bulma-grid-cell-column-span: 4; + } + .cell.is-row-start-4-mobile { + --bulma-grid-cell-row-start: 4; + } + .cell.is-row-end-4-mobile { + --bulma-grid-cell-row-end: 4; + } + .cell.is-row-from-end-4-mobile { + --bulma-grid-cell-row-start: -4; + } + .cell.is-row-span-4-mobile { + --bulma-grid-cell-row-span: 4; + } + .cell.is-col-start-5-mobile { + --bulma-grid-cell-column-start: 5; + } + .cell.is-col-end-5-mobile { + --bulma-grid-cell-column-end: 5; + } + .cell.is-col-from-end-5-mobile { + --bulma-grid-cell-column-start: -5; + } + .cell.is-col-span-5-mobile { + --bulma-grid-cell-column-span: 5; + } + .cell.is-row-start-5-mobile { + --bulma-grid-cell-row-start: 5; + } + .cell.is-row-end-5-mobile { + --bulma-grid-cell-row-end: 5; + } + .cell.is-row-from-end-5-mobile { + --bulma-grid-cell-row-start: -5; + } + .cell.is-row-span-5-mobile { + --bulma-grid-cell-row-span: 5; + } + .cell.is-col-start-6-mobile { + --bulma-grid-cell-column-start: 6; + } + .cell.is-col-end-6-mobile { + --bulma-grid-cell-column-end: 6; + } + .cell.is-col-from-end-6-mobile { + --bulma-grid-cell-column-start: -6; + } + .cell.is-col-span-6-mobile { + --bulma-grid-cell-column-span: 6; + } + .cell.is-row-start-6-mobile { + --bulma-grid-cell-row-start: 6; + } + .cell.is-row-end-6-mobile { + --bulma-grid-cell-row-end: 6; + } + .cell.is-row-from-end-6-mobile { + --bulma-grid-cell-row-start: -6; + } + .cell.is-row-span-6-mobile { + --bulma-grid-cell-row-span: 6; + } + .cell.is-col-start-7-mobile { + --bulma-grid-cell-column-start: 7; + } + .cell.is-col-end-7-mobile { + --bulma-grid-cell-column-end: 7; + } + .cell.is-col-from-end-7-mobile { + --bulma-grid-cell-column-start: -7; + } + .cell.is-col-span-7-mobile { + --bulma-grid-cell-column-span: 7; + } + .cell.is-row-start-7-mobile { + --bulma-grid-cell-row-start: 7; + } + .cell.is-row-end-7-mobile { + --bulma-grid-cell-row-end: 7; + } + .cell.is-row-from-end-7-mobile { + --bulma-grid-cell-row-start: -7; + } + .cell.is-row-span-7-mobile { + --bulma-grid-cell-row-span: 7; + } + .cell.is-col-start-8-mobile { + --bulma-grid-cell-column-start: 8; + } + .cell.is-col-end-8-mobile { + --bulma-grid-cell-column-end: 8; + } + .cell.is-col-from-end-8-mobile { + --bulma-grid-cell-column-start: -8; + } + .cell.is-col-span-8-mobile { + --bulma-grid-cell-column-span: 8; + } + .cell.is-row-start-8-mobile { + --bulma-grid-cell-row-start: 8; + } + .cell.is-row-end-8-mobile { + --bulma-grid-cell-row-end: 8; + } + .cell.is-row-from-end-8-mobile { + --bulma-grid-cell-row-start: -8; + } + .cell.is-row-span-8-mobile { + --bulma-grid-cell-row-span: 8; + } + .cell.is-col-start-9-mobile { + --bulma-grid-cell-column-start: 9; + } + .cell.is-col-end-9-mobile { + --bulma-grid-cell-column-end: 9; + } + .cell.is-col-from-end-9-mobile { + --bulma-grid-cell-column-start: -9; + } + .cell.is-col-span-9-mobile { + --bulma-grid-cell-column-span: 9; + } + .cell.is-row-start-9-mobile { + --bulma-grid-cell-row-start: 9; + } + .cell.is-row-end-9-mobile { + --bulma-grid-cell-row-end: 9; + } + .cell.is-row-from-end-9-mobile { + --bulma-grid-cell-row-start: -9; + } + .cell.is-row-span-9-mobile { + --bulma-grid-cell-row-span: 9; + } + .cell.is-col-start-10-mobile { + --bulma-grid-cell-column-start: 10; + } + .cell.is-col-end-10-mobile { + --bulma-grid-cell-column-end: 10; + } + .cell.is-col-from-end-10-mobile { + --bulma-grid-cell-column-start: -10; + } + .cell.is-col-span-10-mobile { + --bulma-grid-cell-column-span: 10; + } + .cell.is-row-start-10-mobile { + --bulma-grid-cell-row-start: 10; + } + .cell.is-row-end-10-mobile { + --bulma-grid-cell-row-end: 10; + } + .cell.is-row-from-end-10-mobile { + --bulma-grid-cell-row-start: -10; + } + .cell.is-row-span-10-mobile { + --bulma-grid-cell-row-span: 10; + } + .cell.is-col-start-11-mobile { + --bulma-grid-cell-column-start: 11; + } + .cell.is-col-end-11-mobile { + --bulma-grid-cell-column-end: 11; + } + .cell.is-col-from-end-11-mobile { + --bulma-grid-cell-column-start: -11; + } + .cell.is-col-span-11-mobile { + --bulma-grid-cell-column-span: 11; + } + .cell.is-row-start-11-mobile { + --bulma-grid-cell-row-start: 11; + } + .cell.is-row-end-11-mobile { + --bulma-grid-cell-row-end: 11; + } + .cell.is-row-from-end-11-mobile { + --bulma-grid-cell-row-start: -11; + } + .cell.is-row-span-11-mobile { + --bulma-grid-cell-row-span: 11; + } + .cell.is-col-start-12-mobile { + --bulma-grid-cell-column-start: 12; + } + .cell.is-col-end-12-mobile { + --bulma-grid-cell-column-end: 12; + } + .cell.is-col-from-end-12-mobile { + --bulma-grid-cell-column-start: -12; + } + .cell.is-col-span-12-mobile { + --bulma-grid-cell-column-span: 12; + } + .cell.is-row-start-12-mobile { + --bulma-grid-cell-row-start: 12; + } + .cell.is-row-end-12-mobile { + --bulma-grid-cell-row-end: 12; + } + .cell.is-row-from-end-12-mobile { + --bulma-grid-cell-row-start: -12; + } + .cell.is-row-span-12-mobile { + --bulma-grid-cell-row-span: 12; + } +} +@media screen and (min-width: 769px), print { + .cell.is-col-start-1-tablet { + --bulma-grid-cell-column-start: 1; + } + .cell.is-col-end-1-tablet { + --bulma-grid-cell-column-end: 1; + } + .cell.is-col-from-end-1-tablet { + --bulma-grid-cell-column-start: -1; + } + .cell.is-col-span-1-tablet { + --bulma-grid-cell-column-span: 1; + } + .cell.is-row-start-1-tablet { + --bulma-grid-cell-row-start: 1; + } + .cell.is-row-end-1-tablet { + --bulma-grid-cell-row-end: 1; + } + .cell.is-row-from-end-1-tablet { + --bulma-grid-cell-row-start: -1; + } + .cell.is-row-span-1-tablet { + --bulma-grid-cell-row-span: 1; + } + .cell.is-col-start-2-tablet { + --bulma-grid-cell-column-start: 2; + } + .cell.is-col-end-2-tablet { + --bulma-grid-cell-column-end: 2; + } + .cell.is-col-from-end-2-tablet { + --bulma-grid-cell-column-start: -2; + } + .cell.is-col-span-2-tablet { + --bulma-grid-cell-column-span: 2; + } + .cell.is-row-start-2-tablet { + --bulma-grid-cell-row-start: 2; + } + .cell.is-row-end-2-tablet { + --bulma-grid-cell-row-end: 2; + } + .cell.is-row-from-end-2-tablet { + --bulma-grid-cell-row-start: -2; + } + .cell.is-row-span-2-tablet { + --bulma-grid-cell-row-span: 2; + } + .cell.is-col-start-3-tablet { + --bulma-grid-cell-column-start: 3; + } + .cell.is-col-end-3-tablet { + --bulma-grid-cell-column-end: 3; + } + .cell.is-col-from-end-3-tablet { + --bulma-grid-cell-column-start: -3; + } + .cell.is-col-span-3-tablet { + --bulma-grid-cell-column-span: 3; + } + .cell.is-row-start-3-tablet { + --bulma-grid-cell-row-start: 3; + } + .cell.is-row-end-3-tablet { + --bulma-grid-cell-row-end: 3; + } + .cell.is-row-from-end-3-tablet { + --bulma-grid-cell-row-start: -3; + } + .cell.is-row-span-3-tablet { + --bulma-grid-cell-row-span: 3; + } + .cell.is-col-start-4-tablet { + --bulma-grid-cell-column-start: 4; + } + .cell.is-col-end-4-tablet { + --bulma-grid-cell-column-end: 4; + } + .cell.is-col-from-end-4-tablet { + --bulma-grid-cell-column-start: -4; + } + .cell.is-col-span-4-tablet { + --bulma-grid-cell-column-span: 4; + } + .cell.is-row-start-4-tablet { + --bulma-grid-cell-row-start: 4; + } + .cell.is-row-end-4-tablet { + --bulma-grid-cell-row-end: 4; + } + .cell.is-row-from-end-4-tablet { + --bulma-grid-cell-row-start: -4; + } + .cell.is-row-span-4-tablet { + --bulma-grid-cell-row-span: 4; + } + .cell.is-col-start-5-tablet { + --bulma-grid-cell-column-start: 5; + } + .cell.is-col-end-5-tablet { + --bulma-grid-cell-column-end: 5; + } + .cell.is-col-from-end-5-tablet { + --bulma-grid-cell-column-start: -5; + } + .cell.is-col-span-5-tablet { + --bulma-grid-cell-column-span: 5; + } + .cell.is-row-start-5-tablet { + --bulma-grid-cell-row-start: 5; + } + .cell.is-row-end-5-tablet { + --bulma-grid-cell-row-end: 5; + } + .cell.is-row-from-end-5-tablet { + --bulma-grid-cell-row-start: -5; + } + .cell.is-row-span-5-tablet { + --bulma-grid-cell-row-span: 5; + } + .cell.is-col-start-6-tablet { + --bulma-grid-cell-column-start: 6; + } + .cell.is-col-end-6-tablet { + --bulma-grid-cell-column-end: 6; + } + .cell.is-col-from-end-6-tablet { + --bulma-grid-cell-column-start: -6; + } + .cell.is-col-span-6-tablet { + --bulma-grid-cell-column-span: 6; + } + .cell.is-row-start-6-tablet { + --bulma-grid-cell-row-start: 6; + } + .cell.is-row-end-6-tablet { + --bulma-grid-cell-row-end: 6; + } + .cell.is-row-from-end-6-tablet { + --bulma-grid-cell-row-start: -6; + } + .cell.is-row-span-6-tablet { + --bulma-grid-cell-row-span: 6; + } + .cell.is-col-start-7-tablet { + --bulma-grid-cell-column-start: 7; + } + .cell.is-col-end-7-tablet { + --bulma-grid-cell-column-end: 7; + } + .cell.is-col-from-end-7-tablet { + --bulma-grid-cell-column-start: -7; + } + .cell.is-col-span-7-tablet { + --bulma-grid-cell-column-span: 7; + } + .cell.is-row-start-7-tablet { + --bulma-grid-cell-row-start: 7; + } + .cell.is-row-end-7-tablet { + --bulma-grid-cell-row-end: 7; + } + .cell.is-row-from-end-7-tablet { + --bulma-grid-cell-row-start: -7; + } + .cell.is-row-span-7-tablet { + --bulma-grid-cell-row-span: 7; + } + .cell.is-col-start-8-tablet { + --bulma-grid-cell-column-start: 8; + } + .cell.is-col-end-8-tablet { + --bulma-grid-cell-column-end: 8; + } + .cell.is-col-from-end-8-tablet { + --bulma-grid-cell-column-start: -8; + } + .cell.is-col-span-8-tablet { + --bulma-grid-cell-column-span: 8; + } + .cell.is-row-start-8-tablet { + --bulma-grid-cell-row-start: 8; + } + .cell.is-row-end-8-tablet { + --bulma-grid-cell-row-end: 8; + } + .cell.is-row-from-end-8-tablet { + --bulma-grid-cell-row-start: -8; + } + .cell.is-row-span-8-tablet { + --bulma-grid-cell-row-span: 8; + } + .cell.is-col-start-9-tablet { + --bulma-grid-cell-column-start: 9; + } + .cell.is-col-end-9-tablet { + --bulma-grid-cell-column-end: 9; + } + .cell.is-col-from-end-9-tablet { + --bulma-grid-cell-column-start: -9; + } + .cell.is-col-span-9-tablet { + --bulma-grid-cell-column-span: 9; + } + .cell.is-row-start-9-tablet { + --bulma-grid-cell-row-start: 9; + } + .cell.is-row-end-9-tablet { + --bulma-grid-cell-row-end: 9; + } + .cell.is-row-from-end-9-tablet { + --bulma-grid-cell-row-start: -9; + } + .cell.is-row-span-9-tablet { + --bulma-grid-cell-row-span: 9; + } + .cell.is-col-start-10-tablet { + --bulma-grid-cell-column-start: 10; + } + .cell.is-col-end-10-tablet { + --bulma-grid-cell-column-end: 10; + } + .cell.is-col-from-end-10-tablet { + --bulma-grid-cell-column-start: -10; + } + .cell.is-col-span-10-tablet { + --bulma-grid-cell-column-span: 10; + } + .cell.is-row-start-10-tablet { + --bulma-grid-cell-row-start: 10; + } + .cell.is-row-end-10-tablet { + --bulma-grid-cell-row-end: 10; + } + .cell.is-row-from-end-10-tablet { + --bulma-grid-cell-row-start: -10; + } + .cell.is-row-span-10-tablet { + --bulma-grid-cell-row-span: 10; + } + .cell.is-col-start-11-tablet { + --bulma-grid-cell-column-start: 11; + } + .cell.is-col-end-11-tablet { + --bulma-grid-cell-column-end: 11; + } + .cell.is-col-from-end-11-tablet { + --bulma-grid-cell-column-start: -11; + } + .cell.is-col-span-11-tablet { + --bulma-grid-cell-column-span: 11; + } + .cell.is-row-start-11-tablet { + --bulma-grid-cell-row-start: 11; + } + .cell.is-row-end-11-tablet { + --bulma-grid-cell-row-end: 11; + } + .cell.is-row-from-end-11-tablet { + --bulma-grid-cell-row-start: -11; + } + .cell.is-row-span-11-tablet { + --bulma-grid-cell-row-span: 11; + } + .cell.is-col-start-12-tablet { + --bulma-grid-cell-column-start: 12; + } + .cell.is-col-end-12-tablet { + --bulma-grid-cell-column-end: 12; + } + .cell.is-col-from-end-12-tablet { + --bulma-grid-cell-column-start: -12; + } + .cell.is-col-span-12-tablet { + --bulma-grid-cell-column-span: 12; + } + .cell.is-row-start-12-tablet { + --bulma-grid-cell-row-start: 12; + } + .cell.is-row-end-12-tablet { + --bulma-grid-cell-row-end: 12; + } + .cell.is-row-from-end-12-tablet { + --bulma-grid-cell-row-start: -12; + } + .cell.is-row-span-12-tablet { + --bulma-grid-cell-row-span: 12; + } +} +@media screen and (min-width: 769px) and (max-width: 1023px) { + .cell.is-col-start-1-tablet-only { + --bulma-grid-cell-column-start: 1; + } + .cell.is-col-end-1-tablet-only { + --bulma-grid-cell-column-end: 1; + } + .cell.is-col-from-end-1-tablet-only { + --bulma-grid-cell-column-start: -1; + } + .cell.is-col-span-1-tablet-only { + --bulma-grid-cell-column-span: 1; + } + .cell.is-row-start-1-tablet-only { + --bulma-grid-cell-row-start: 1; + } + .cell.is-row-end-1-tablet-only { + --bulma-grid-cell-row-end: 1; + } + .cell.is-row-from-end-1-tablet-only { + --bulma-grid-cell-row-start: -1; + } + .cell.is-row-span-1-tablet-only { + --bulma-grid-cell-row-span: 1; + } + .cell.is-col-start-2-tablet-only { + --bulma-grid-cell-column-start: 2; + } + .cell.is-col-end-2-tablet-only { + --bulma-grid-cell-column-end: 2; + } + .cell.is-col-from-end-2-tablet-only { + --bulma-grid-cell-column-start: -2; + } + .cell.is-col-span-2-tablet-only { + --bulma-grid-cell-column-span: 2; + } + .cell.is-row-start-2-tablet-only { + --bulma-grid-cell-row-start: 2; + } + .cell.is-row-end-2-tablet-only { + --bulma-grid-cell-row-end: 2; + } + .cell.is-row-from-end-2-tablet-only { + --bulma-grid-cell-row-start: -2; + } + .cell.is-row-span-2-tablet-only { + --bulma-grid-cell-row-span: 2; + } + .cell.is-col-start-3-tablet-only { + --bulma-grid-cell-column-start: 3; + } + .cell.is-col-end-3-tablet-only { + --bulma-grid-cell-column-end: 3; + } + .cell.is-col-from-end-3-tablet-only { + --bulma-grid-cell-column-start: -3; + } + .cell.is-col-span-3-tablet-only { + --bulma-grid-cell-column-span: 3; + } + .cell.is-row-start-3-tablet-only { + --bulma-grid-cell-row-start: 3; + } + .cell.is-row-end-3-tablet-only { + --bulma-grid-cell-row-end: 3; + } + .cell.is-row-from-end-3-tablet-only { + --bulma-grid-cell-row-start: -3; + } + .cell.is-row-span-3-tablet-only { + --bulma-grid-cell-row-span: 3; + } + .cell.is-col-start-4-tablet-only { + --bulma-grid-cell-column-start: 4; + } + .cell.is-col-end-4-tablet-only { + --bulma-grid-cell-column-end: 4; + } + .cell.is-col-from-end-4-tablet-only { + --bulma-grid-cell-column-start: -4; + } + .cell.is-col-span-4-tablet-only { + --bulma-grid-cell-column-span: 4; + } + .cell.is-row-start-4-tablet-only { + --bulma-grid-cell-row-start: 4; + } + .cell.is-row-end-4-tablet-only { + --bulma-grid-cell-row-end: 4; + } + .cell.is-row-from-end-4-tablet-only { + --bulma-grid-cell-row-start: -4; + } + .cell.is-row-span-4-tablet-only { + --bulma-grid-cell-row-span: 4; + } + .cell.is-col-start-5-tablet-only { + --bulma-grid-cell-column-start: 5; + } + .cell.is-col-end-5-tablet-only { + --bulma-grid-cell-column-end: 5; + } + .cell.is-col-from-end-5-tablet-only { + --bulma-grid-cell-column-start: -5; + } + .cell.is-col-span-5-tablet-only { + --bulma-grid-cell-column-span: 5; + } + .cell.is-row-start-5-tablet-only { + --bulma-grid-cell-row-start: 5; + } + .cell.is-row-end-5-tablet-only { + --bulma-grid-cell-row-end: 5; + } + .cell.is-row-from-end-5-tablet-only { + --bulma-grid-cell-row-start: -5; + } + .cell.is-row-span-5-tablet-only { + --bulma-grid-cell-row-span: 5; + } + .cell.is-col-start-6-tablet-only { + --bulma-grid-cell-column-start: 6; + } + .cell.is-col-end-6-tablet-only { + --bulma-grid-cell-column-end: 6; + } + .cell.is-col-from-end-6-tablet-only { + --bulma-grid-cell-column-start: -6; + } + .cell.is-col-span-6-tablet-only { + --bulma-grid-cell-column-span: 6; + } + .cell.is-row-start-6-tablet-only { + --bulma-grid-cell-row-start: 6; + } + .cell.is-row-end-6-tablet-only { + --bulma-grid-cell-row-end: 6; + } + .cell.is-row-from-end-6-tablet-only { + --bulma-grid-cell-row-start: -6; + } + .cell.is-row-span-6-tablet-only { + --bulma-grid-cell-row-span: 6; + } + .cell.is-col-start-7-tablet-only { + --bulma-grid-cell-column-start: 7; + } + .cell.is-col-end-7-tablet-only { + --bulma-grid-cell-column-end: 7; + } + .cell.is-col-from-end-7-tablet-only { + --bulma-grid-cell-column-start: -7; + } + .cell.is-col-span-7-tablet-only { + --bulma-grid-cell-column-span: 7; + } + .cell.is-row-start-7-tablet-only { + --bulma-grid-cell-row-start: 7; + } + .cell.is-row-end-7-tablet-only { + --bulma-grid-cell-row-end: 7; + } + .cell.is-row-from-end-7-tablet-only { + --bulma-grid-cell-row-start: -7; + } + .cell.is-row-span-7-tablet-only { + --bulma-grid-cell-row-span: 7; + } + .cell.is-col-start-8-tablet-only { + --bulma-grid-cell-column-start: 8; + } + .cell.is-col-end-8-tablet-only { + --bulma-grid-cell-column-end: 8; + } + .cell.is-col-from-end-8-tablet-only { + --bulma-grid-cell-column-start: -8; + } + .cell.is-col-span-8-tablet-only { + --bulma-grid-cell-column-span: 8; + } + .cell.is-row-start-8-tablet-only { + --bulma-grid-cell-row-start: 8; + } + .cell.is-row-end-8-tablet-only { + --bulma-grid-cell-row-end: 8; + } + .cell.is-row-from-end-8-tablet-only { + --bulma-grid-cell-row-start: -8; + } + .cell.is-row-span-8-tablet-only { + --bulma-grid-cell-row-span: 8; + } + .cell.is-col-start-9-tablet-only { + --bulma-grid-cell-column-start: 9; + } + .cell.is-col-end-9-tablet-only { + --bulma-grid-cell-column-end: 9; + } + .cell.is-col-from-end-9-tablet-only { + --bulma-grid-cell-column-start: -9; + } + .cell.is-col-span-9-tablet-only { + --bulma-grid-cell-column-span: 9; + } + .cell.is-row-start-9-tablet-only { + --bulma-grid-cell-row-start: 9; + } + .cell.is-row-end-9-tablet-only { + --bulma-grid-cell-row-end: 9; + } + .cell.is-row-from-end-9-tablet-only { + --bulma-grid-cell-row-start: -9; + } + .cell.is-row-span-9-tablet-only { + --bulma-grid-cell-row-span: 9; + } + .cell.is-col-start-10-tablet-only { + --bulma-grid-cell-column-start: 10; + } + .cell.is-col-end-10-tablet-only { + --bulma-grid-cell-column-end: 10; + } + .cell.is-col-from-end-10-tablet-only { + --bulma-grid-cell-column-start: -10; + } + .cell.is-col-span-10-tablet-only { + --bulma-grid-cell-column-span: 10; + } + .cell.is-row-start-10-tablet-only { + --bulma-grid-cell-row-start: 10; + } + .cell.is-row-end-10-tablet-only { + --bulma-grid-cell-row-end: 10; + } + .cell.is-row-from-end-10-tablet-only { + --bulma-grid-cell-row-start: -10; + } + .cell.is-row-span-10-tablet-only { + --bulma-grid-cell-row-span: 10; + } + .cell.is-col-start-11-tablet-only { + --bulma-grid-cell-column-start: 11; + } + .cell.is-col-end-11-tablet-only { + --bulma-grid-cell-column-end: 11; + } + .cell.is-col-from-end-11-tablet-only { + --bulma-grid-cell-column-start: -11; + } + .cell.is-col-span-11-tablet-only { + --bulma-grid-cell-column-span: 11; + } + .cell.is-row-start-11-tablet-only { + --bulma-grid-cell-row-start: 11; + } + .cell.is-row-end-11-tablet-only { + --bulma-grid-cell-row-end: 11; + } + .cell.is-row-from-end-11-tablet-only { + --bulma-grid-cell-row-start: -11; + } + .cell.is-row-span-11-tablet-only { + --bulma-grid-cell-row-span: 11; + } + .cell.is-col-start-12-tablet-only { + --bulma-grid-cell-column-start: 12; + } + .cell.is-col-end-12-tablet-only { + --bulma-grid-cell-column-end: 12; + } + .cell.is-col-from-end-12-tablet-only { + --bulma-grid-cell-column-start: -12; + } + .cell.is-col-span-12-tablet-only { + --bulma-grid-cell-column-span: 12; + } + .cell.is-row-start-12-tablet-only { + --bulma-grid-cell-row-start: 12; + } + .cell.is-row-end-12-tablet-only { + --bulma-grid-cell-row-end: 12; + } + .cell.is-row-from-end-12-tablet-only { + --bulma-grid-cell-row-start: -12; + } + .cell.is-row-span-12-tablet-only { + --bulma-grid-cell-row-span: 12; + } +} +@media screen and (min-width: 1024px) { + .cell.is-col-start-1-desktop { + --bulma-grid-cell-column-start: 1; + } + .cell.is-col-end-1-desktop { + --bulma-grid-cell-column-end: 1; + } + .cell.is-col-from-end-1-desktop { + --bulma-grid-cell-column-start: -1; + } + .cell.is-col-span-1-desktop { + --bulma-grid-cell-column-span: 1; + } + .cell.is-row-start-1-desktop { + --bulma-grid-cell-row-start: 1; + } + .cell.is-row-end-1-desktop { + --bulma-grid-cell-row-end: 1; + } + .cell.is-row-from-end-1-desktop { + --bulma-grid-cell-row-start: -1; + } + .cell.is-row-span-1-desktop { + --bulma-grid-cell-row-span: 1; + } + .cell.is-col-start-2-desktop { + --bulma-grid-cell-column-start: 2; + } + .cell.is-col-end-2-desktop { + --bulma-grid-cell-column-end: 2; + } + .cell.is-col-from-end-2-desktop { + --bulma-grid-cell-column-start: -2; + } + .cell.is-col-span-2-desktop { + --bulma-grid-cell-column-span: 2; + } + .cell.is-row-start-2-desktop { + --bulma-grid-cell-row-start: 2; + } + .cell.is-row-end-2-desktop { + --bulma-grid-cell-row-end: 2; + } + .cell.is-row-from-end-2-desktop { + --bulma-grid-cell-row-start: -2; + } + .cell.is-row-span-2-desktop { + --bulma-grid-cell-row-span: 2; + } + .cell.is-col-start-3-desktop { + --bulma-grid-cell-column-start: 3; + } + .cell.is-col-end-3-desktop { + --bulma-grid-cell-column-end: 3; + } + .cell.is-col-from-end-3-desktop { + --bulma-grid-cell-column-start: -3; + } + .cell.is-col-span-3-desktop { + --bulma-grid-cell-column-span: 3; + } + .cell.is-row-start-3-desktop { + --bulma-grid-cell-row-start: 3; + } + .cell.is-row-end-3-desktop { + --bulma-grid-cell-row-end: 3; + } + .cell.is-row-from-end-3-desktop { + --bulma-grid-cell-row-start: -3; + } + .cell.is-row-span-3-desktop { + --bulma-grid-cell-row-span: 3; + } + .cell.is-col-start-4-desktop { + --bulma-grid-cell-column-start: 4; + } + .cell.is-col-end-4-desktop { + --bulma-grid-cell-column-end: 4; + } + .cell.is-col-from-end-4-desktop { + --bulma-grid-cell-column-start: -4; + } + .cell.is-col-span-4-desktop { + --bulma-grid-cell-column-span: 4; + } + .cell.is-row-start-4-desktop { + --bulma-grid-cell-row-start: 4; + } + .cell.is-row-end-4-desktop { + --bulma-grid-cell-row-end: 4; + } + .cell.is-row-from-end-4-desktop { + --bulma-grid-cell-row-start: -4; + } + .cell.is-row-span-4-desktop { + --bulma-grid-cell-row-span: 4; + } + .cell.is-col-start-5-desktop { + --bulma-grid-cell-column-start: 5; + } + .cell.is-col-end-5-desktop { + --bulma-grid-cell-column-end: 5; + } + .cell.is-col-from-end-5-desktop { + --bulma-grid-cell-column-start: -5; + } + .cell.is-col-span-5-desktop { + --bulma-grid-cell-column-span: 5; + } + .cell.is-row-start-5-desktop { + --bulma-grid-cell-row-start: 5; + } + .cell.is-row-end-5-desktop { + --bulma-grid-cell-row-end: 5; + } + .cell.is-row-from-end-5-desktop { + --bulma-grid-cell-row-start: -5; + } + .cell.is-row-span-5-desktop { + --bulma-grid-cell-row-span: 5; + } + .cell.is-col-start-6-desktop { + --bulma-grid-cell-column-start: 6; + } + .cell.is-col-end-6-desktop { + --bulma-grid-cell-column-end: 6; + } + .cell.is-col-from-end-6-desktop { + --bulma-grid-cell-column-start: -6; + } + .cell.is-col-span-6-desktop { + --bulma-grid-cell-column-span: 6; + } + .cell.is-row-start-6-desktop { + --bulma-grid-cell-row-start: 6; + } + .cell.is-row-end-6-desktop { + --bulma-grid-cell-row-end: 6; + } + .cell.is-row-from-end-6-desktop { + --bulma-grid-cell-row-start: -6; + } + .cell.is-row-span-6-desktop { + --bulma-grid-cell-row-span: 6; + } + .cell.is-col-start-7-desktop { + --bulma-grid-cell-column-start: 7; + } + .cell.is-col-end-7-desktop { + --bulma-grid-cell-column-end: 7; + } + .cell.is-col-from-end-7-desktop { + --bulma-grid-cell-column-start: -7; + } + .cell.is-col-span-7-desktop { + --bulma-grid-cell-column-span: 7; + } + .cell.is-row-start-7-desktop { + --bulma-grid-cell-row-start: 7; + } + .cell.is-row-end-7-desktop { + --bulma-grid-cell-row-end: 7; + } + .cell.is-row-from-end-7-desktop { + --bulma-grid-cell-row-start: -7; + } + .cell.is-row-span-7-desktop { + --bulma-grid-cell-row-span: 7; + } + .cell.is-col-start-8-desktop { + --bulma-grid-cell-column-start: 8; + } + .cell.is-col-end-8-desktop { + --bulma-grid-cell-column-end: 8; + } + .cell.is-col-from-end-8-desktop { + --bulma-grid-cell-column-start: -8; + } + .cell.is-col-span-8-desktop { + --bulma-grid-cell-column-span: 8; + } + .cell.is-row-start-8-desktop { + --bulma-grid-cell-row-start: 8; + } + .cell.is-row-end-8-desktop { + --bulma-grid-cell-row-end: 8; + } + .cell.is-row-from-end-8-desktop { + --bulma-grid-cell-row-start: -8; + } + .cell.is-row-span-8-desktop { + --bulma-grid-cell-row-span: 8; + } + .cell.is-col-start-9-desktop { + --bulma-grid-cell-column-start: 9; + } + .cell.is-col-end-9-desktop { + --bulma-grid-cell-column-end: 9; + } + .cell.is-col-from-end-9-desktop { + --bulma-grid-cell-column-start: -9; + } + .cell.is-col-span-9-desktop { + --bulma-grid-cell-column-span: 9; + } + .cell.is-row-start-9-desktop { + --bulma-grid-cell-row-start: 9; + } + .cell.is-row-end-9-desktop { + --bulma-grid-cell-row-end: 9; + } + .cell.is-row-from-end-9-desktop { + --bulma-grid-cell-row-start: -9; + } + .cell.is-row-span-9-desktop { + --bulma-grid-cell-row-span: 9; + } + .cell.is-col-start-10-desktop { + --bulma-grid-cell-column-start: 10; + } + .cell.is-col-end-10-desktop { + --bulma-grid-cell-column-end: 10; + } + .cell.is-col-from-end-10-desktop { + --bulma-grid-cell-column-start: -10; + } + .cell.is-col-span-10-desktop { + --bulma-grid-cell-column-span: 10; + } + .cell.is-row-start-10-desktop { + --bulma-grid-cell-row-start: 10; + } + .cell.is-row-end-10-desktop { + --bulma-grid-cell-row-end: 10; + } + .cell.is-row-from-end-10-desktop { + --bulma-grid-cell-row-start: -10; + } + .cell.is-row-span-10-desktop { + --bulma-grid-cell-row-span: 10; + } + .cell.is-col-start-11-desktop { + --bulma-grid-cell-column-start: 11; + } + .cell.is-col-end-11-desktop { + --bulma-grid-cell-column-end: 11; + } + .cell.is-col-from-end-11-desktop { + --bulma-grid-cell-column-start: -11; + } + .cell.is-col-span-11-desktop { + --bulma-grid-cell-column-span: 11; + } + .cell.is-row-start-11-desktop { + --bulma-grid-cell-row-start: 11; + } + .cell.is-row-end-11-desktop { + --bulma-grid-cell-row-end: 11; + } + .cell.is-row-from-end-11-desktop { + --bulma-grid-cell-row-start: -11; + } + .cell.is-row-span-11-desktop { + --bulma-grid-cell-row-span: 11; + } + .cell.is-col-start-12-desktop { + --bulma-grid-cell-column-start: 12; + } + .cell.is-col-end-12-desktop { + --bulma-grid-cell-column-end: 12; + } + .cell.is-col-from-end-12-desktop { + --bulma-grid-cell-column-start: -12; + } + .cell.is-col-span-12-desktop { + --bulma-grid-cell-column-span: 12; + } + .cell.is-row-start-12-desktop { + --bulma-grid-cell-row-start: 12; + } + .cell.is-row-end-12-desktop { + --bulma-grid-cell-row-end: 12; + } + .cell.is-row-from-end-12-desktop { + --bulma-grid-cell-row-start: -12; + } + .cell.is-row-span-12-desktop { + --bulma-grid-cell-row-span: 12; + } +} +@media screen and (min-width: 1024px) and (max-width: 1215px) { + .cell.is-col-start-1-desktop-only { + --bulma-grid-cell-column-start: 1; + } + .cell.is-col-end-1-desktop-only { + --bulma-grid-cell-column-end: 1; + } + .cell.is-col-from-end-1-desktop-only { + --bulma-grid-cell-column-start: -1; + } + .cell.is-col-span-1-desktop-only { + --bulma-grid-cell-column-span: 1; + } + .cell.is-row-start-1-desktop-only { + --bulma-grid-cell-row-start: 1; + } + .cell.is-row-end-1-desktop-only { + --bulma-grid-cell-row-end: 1; + } + .cell.is-row-from-end-1-desktop-only { + --bulma-grid-cell-row-start: -1; + } + .cell.is-row-span-1-desktop-only { + --bulma-grid-cell-row-span: 1; + } + .cell.is-col-start-2-desktop-only { + --bulma-grid-cell-column-start: 2; + } + .cell.is-col-end-2-desktop-only { + --bulma-grid-cell-column-end: 2; + } + .cell.is-col-from-end-2-desktop-only { + --bulma-grid-cell-column-start: -2; + } + .cell.is-col-span-2-desktop-only { + --bulma-grid-cell-column-span: 2; + } + .cell.is-row-start-2-desktop-only { + --bulma-grid-cell-row-start: 2; + } + .cell.is-row-end-2-desktop-only { + --bulma-grid-cell-row-end: 2; + } + .cell.is-row-from-end-2-desktop-only { + --bulma-grid-cell-row-start: -2; + } + .cell.is-row-span-2-desktop-only { + --bulma-grid-cell-row-span: 2; + } + .cell.is-col-start-3-desktop-only { + --bulma-grid-cell-column-start: 3; + } + .cell.is-col-end-3-desktop-only { + --bulma-grid-cell-column-end: 3; + } + .cell.is-col-from-end-3-desktop-only { + --bulma-grid-cell-column-start: -3; + } + .cell.is-col-span-3-desktop-only { + --bulma-grid-cell-column-span: 3; + } + .cell.is-row-start-3-desktop-only { + --bulma-grid-cell-row-start: 3; + } + .cell.is-row-end-3-desktop-only { + --bulma-grid-cell-row-end: 3; + } + .cell.is-row-from-end-3-desktop-only { + --bulma-grid-cell-row-start: -3; + } + .cell.is-row-span-3-desktop-only { + --bulma-grid-cell-row-span: 3; + } + .cell.is-col-start-4-desktop-only { + --bulma-grid-cell-column-start: 4; + } + .cell.is-col-end-4-desktop-only { + --bulma-grid-cell-column-end: 4; + } + .cell.is-col-from-end-4-desktop-only { + --bulma-grid-cell-column-start: -4; + } + .cell.is-col-span-4-desktop-only { + --bulma-grid-cell-column-span: 4; + } + .cell.is-row-start-4-desktop-only { + --bulma-grid-cell-row-start: 4; + } + .cell.is-row-end-4-desktop-only { + --bulma-grid-cell-row-end: 4; + } + .cell.is-row-from-end-4-desktop-only { + --bulma-grid-cell-row-start: -4; + } + .cell.is-row-span-4-desktop-only { + --bulma-grid-cell-row-span: 4; + } + .cell.is-col-start-5-desktop-only { + --bulma-grid-cell-column-start: 5; + } + .cell.is-col-end-5-desktop-only { + --bulma-grid-cell-column-end: 5; + } + .cell.is-col-from-end-5-desktop-only { + --bulma-grid-cell-column-start: -5; + } + .cell.is-col-span-5-desktop-only { + --bulma-grid-cell-column-span: 5; + } + .cell.is-row-start-5-desktop-only { + --bulma-grid-cell-row-start: 5; + } + .cell.is-row-end-5-desktop-only { + --bulma-grid-cell-row-end: 5; + } + .cell.is-row-from-end-5-desktop-only { + --bulma-grid-cell-row-start: -5; + } + .cell.is-row-span-5-desktop-only { + --bulma-grid-cell-row-span: 5; + } + .cell.is-col-start-6-desktop-only { + --bulma-grid-cell-column-start: 6; + } + .cell.is-col-end-6-desktop-only { + --bulma-grid-cell-column-end: 6; + } + .cell.is-col-from-end-6-desktop-only { + --bulma-grid-cell-column-start: -6; + } + .cell.is-col-span-6-desktop-only { + --bulma-grid-cell-column-span: 6; + } + .cell.is-row-start-6-desktop-only { + --bulma-grid-cell-row-start: 6; + } + .cell.is-row-end-6-desktop-only { + --bulma-grid-cell-row-end: 6; + } + .cell.is-row-from-end-6-desktop-only { + --bulma-grid-cell-row-start: -6; + } + .cell.is-row-span-6-desktop-only { + --bulma-grid-cell-row-span: 6; + } + .cell.is-col-start-7-desktop-only { + --bulma-grid-cell-column-start: 7; + } + .cell.is-col-end-7-desktop-only { + --bulma-grid-cell-column-end: 7; + } + .cell.is-col-from-end-7-desktop-only { + --bulma-grid-cell-column-start: -7; + } + .cell.is-col-span-7-desktop-only { + --bulma-grid-cell-column-span: 7; + } + .cell.is-row-start-7-desktop-only { + --bulma-grid-cell-row-start: 7; + } + .cell.is-row-end-7-desktop-only { + --bulma-grid-cell-row-end: 7; + } + .cell.is-row-from-end-7-desktop-only { + --bulma-grid-cell-row-start: -7; + } + .cell.is-row-span-7-desktop-only { + --bulma-grid-cell-row-span: 7; + } + .cell.is-col-start-8-desktop-only { + --bulma-grid-cell-column-start: 8; + } + .cell.is-col-end-8-desktop-only { + --bulma-grid-cell-column-end: 8; + } + .cell.is-col-from-end-8-desktop-only { + --bulma-grid-cell-column-start: -8; + } + .cell.is-col-span-8-desktop-only { + --bulma-grid-cell-column-span: 8; + } + .cell.is-row-start-8-desktop-only { + --bulma-grid-cell-row-start: 8; + } + .cell.is-row-end-8-desktop-only { + --bulma-grid-cell-row-end: 8; + } + .cell.is-row-from-end-8-desktop-only { + --bulma-grid-cell-row-start: -8; + } + .cell.is-row-span-8-desktop-only { + --bulma-grid-cell-row-span: 8; + } + .cell.is-col-start-9-desktop-only { + --bulma-grid-cell-column-start: 9; + } + .cell.is-col-end-9-desktop-only { + --bulma-grid-cell-column-end: 9; + } + .cell.is-col-from-end-9-desktop-only { + --bulma-grid-cell-column-start: -9; + } + .cell.is-col-span-9-desktop-only { + --bulma-grid-cell-column-span: 9; + } + .cell.is-row-start-9-desktop-only { + --bulma-grid-cell-row-start: 9; + } + .cell.is-row-end-9-desktop-only { + --bulma-grid-cell-row-end: 9; + } + .cell.is-row-from-end-9-desktop-only { + --bulma-grid-cell-row-start: -9; + } + .cell.is-row-span-9-desktop-only { + --bulma-grid-cell-row-span: 9; + } + .cell.is-col-start-10-desktop-only { + --bulma-grid-cell-column-start: 10; + } + .cell.is-col-end-10-desktop-only { + --bulma-grid-cell-column-end: 10; + } + .cell.is-col-from-end-10-desktop-only { + --bulma-grid-cell-column-start: -10; + } + .cell.is-col-span-10-desktop-only { + --bulma-grid-cell-column-span: 10; + } + .cell.is-row-start-10-desktop-only { + --bulma-grid-cell-row-start: 10; + } + .cell.is-row-end-10-desktop-only { + --bulma-grid-cell-row-end: 10; + } + .cell.is-row-from-end-10-desktop-only { + --bulma-grid-cell-row-start: -10; + } + .cell.is-row-span-10-desktop-only { + --bulma-grid-cell-row-span: 10; + } + .cell.is-col-start-11-desktop-only { + --bulma-grid-cell-column-start: 11; + } + .cell.is-col-end-11-desktop-only { + --bulma-grid-cell-column-end: 11; + } + .cell.is-col-from-end-11-desktop-only { + --bulma-grid-cell-column-start: -11; + } + .cell.is-col-span-11-desktop-only { + --bulma-grid-cell-column-span: 11; + } + .cell.is-row-start-11-desktop-only { + --bulma-grid-cell-row-start: 11; + } + .cell.is-row-end-11-desktop-only { + --bulma-grid-cell-row-end: 11; + } + .cell.is-row-from-end-11-desktop-only { + --bulma-grid-cell-row-start: -11; + } + .cell.is-row-span-11-desktop-only { + --bulma-grid-cell-row-span: 11; + } + .cell.is-col-start-12-desktop-only { + --bulma-grid-cell-column-start: 12; + } + .cell.is-col-end-12-desktop-only { + --bulma-grid-cell-column-end: 12; + } + .cell.is-col-from-end-12-desktop-only { + --bulma-grid-cell-column-start: -12; + } + .cell.is-col-span-12-desktop-only { + --bulma-grid-cell-column-span: 12; + } + .cell.is-row-start-12-desktop-only { + --bulma-grid-cell-row-start: 12; + } + .cell.is-row-end-12-desktop-only { + --bulma-grid-cell-row-end: 12; + } + .cell.is-row-from-end-12-desktop-only { + --bulma-grid-cell-row-start: -12; + } + .cell.is-row-span-12-desktop-only { + --bulma-grid-cell-row-span: 12; + } +} +@media screen and (min-width: 1216px) { + .cell.is-col-start-1-widescreen { + --bulma-grid-cell-column-start: 1; + } + .cell.is-col-end-1-widescreen { + --bulma-grid-cell-column-end: 1; + } + .cell.is-col-from-end-1-widescreen { + --bulma-grid-cell-column-start: -1; + } + .cell.is-col-span-1-widescreen { + --bulma-grid-cell-column-span: 1; + } + .cell.is-row-start-1-widescreen { + --bulma-grid-cell-row-start: 1; + } + .cell.is-row-end-1-widescreen { + --bulma-grid-cell-row-end: 1; + } + .cell.is-row-from-end-1-widescreen { + --bulma-grid-cell-row-start: -1; + } + .cell.is-row-span-1-widescreen { + --bulma-grid-cell-row-span: 1; + } + .cell.is-col-start-2-widescreen { + --bulma-grid-cell-column-start: 2; + } + .cell.is-col-end-2-widescreen { + --bulma-grid-cell-column-end: 2; + } + .cell.is-col-from-end-2-widescreen { + --bulma-grid-cell-column-start: -2; + } + .cell.is-col-span-2-widescreen { + --bulma-grid-cell-column-span: 2; + } + .cell.is-row-start-2-widescreen { + --bulma-grid-cell-row-start: 2; + } + .cell.is-row-end-2-widescreen { + --bulma-grid-cell-row-end: 2; + } + .cell.is-row-from-end-2-widescreen { + --bulma-grid-cell-row-start: -2; + } + .cell.is-row-span-2-widescreen { + --bulma-grid-cell-row-span: 2; + } + .cell.is-col-start-3-widescreen { + --bulma-grid-cell-column-start: 3; + } + .cell.is-col-end-3-widescreen { + --bulma-grid-cell-column-end: 3; + } + .cell.is-col-from-end-3-widescreen { + --bulma-grid-cell-column-start: -3; + } + .cell.is-col-span-3-widescreen { + --bulma-grid-cell-column-span: 3; + } + .cell.is-row-start-3-widescreen { + --bulma-grid-cell-row-start: 3; + } + .cell.is-row-end-3-widescreen { + --bulma-grid-cell-row-end: 3; + } + .cell.is-row-from-end-3-widescreen { + --bulma-grid-cell-row-start: -3; + } + .cell.is-row-span-3-widescreen { + --bulma-grid-cell-row-span: 3; + } + .cell.is-col-start-4-widescreen { + --bulma-grid-cell-column-start: 4; + } + .cell.is-col-end-4-widescreen { + --bulma-grid-cell-column-end: 4; + } + .cell.is-col-from-end-4-widescreen { + --bulma-grid-cell-column-start: -4; + } + .cell.is-col-span-4-widescreen { + --bulma-grid-cell-column-span: 4; + } + .cell.is-row-start-4-widescreen { + --bulma-grid-cell-row-start: 4; + } + .cell.is-row-end-4-widescreen { + --bulma-grid-cell-row-end: 4; + } + .cell.is-row-from-end-4-widescreen { + --bulma-grid-cell-row-start: -4; + } + .cell.is-row-span-4-widescreen { + --bulma-grid-cell-row-span: 4; + } + .cell.is-col-start-5-widescreen { + --bulma-grid-cell-column-start: 5; + } + .cell.is-col-end-5-widescreen { + --bulma-grid-cell-column-end: 5; + } + .cell.is-col-from-end-5-widescreen { + --bulma-grid-cell-column-start: -5; + } + .cell.is-col-span-5-widescreen { + --bulma-grid-cell-column-span: 5; + } + .cell.is-row-start-5-widescreen { + --bulma-grid-cell-row-start: 5; + } + .cell.is-row-end-5-widescreen { + --bulma-grid-cell-row-end: 5; + } + .cell.is-row-from-end-5-widescreen { + --bulma-grid-cell-row-start: -5; + } + .cell.is-row-span-5-widescreen { + --bulma-grid-cell-row-span: 5; + } + .cell.is-col-start-6-widescreen { + --bulma-grid-cell-column-start: 6; + } + .cell.is-col-end-6-widescreen { + --bulma-grid-cell-column-end: 6; + } + .cell.is-col-from-end-6-widescreen { + --bulma-grid-cell-column-start: -6; + } + .cell.is-col-span-6-widescreen { + --bulma-grid-cell-column-span: 6; + } + .cell.is-row-start-6-widescreen { + --bulma-grid-cell-row-start: 6; + } + .cell.is-row-end-6-widescreen { + --bulma-grid-cell-row-end: 6; + } + .cell.is-row-from-end-6-widescreen { + --bulma-grid-cell-row-start: -6; + } + .cell.is-row-span-6-widescreen { + --bulma-grid-cell-row-span: 6; + } + .cell.is-col-start-7-widescreen { + --bulma-grid-cell-column-start: 7; + } + .cell.is-col-end-7-widescreen { + --bulma-grid-cell-column-end: 7; + } + .cell.is-col-from-end-7-widescreen { + --bulma-grid-cell-column-start: -7; + } + .cell.is-col-span-7-widescreen { + --bulma-grid-cell-column-span: 7; + } + .cell.is-row-start-7-widescreen { + --bulma-grid-cell-row-start: 7; + } + .cell.is-row-end-7-widescreen { + --bulma-grid-cell-row-end: 7; + } + .cell.is-row-from-end-7-widescreen { + --bulma-grid-cell-row-start: -7; + } + .cell.is-row-span-7-widescreen { + --bulma-grid-cell-row-span: 7; + } + .cell.is-col-start-8-widescreen { + --bulma-grid-cell-column-start: 8; + } + .cell.is-col-end-8-widescreen { + --bulma-grid-cell-column-end: 8; + } + .cell.is-col-from-end-8-widescreen { + --bulma-grid-cell-column-start: -8; + } + .cell.is-col-span-8-widescreen { + --bulma-grid-cell-column-span: 8; + } + .cell.is-row-start-8-widescreen { + --bulma-grid-cell-row-start: 8; + } + .cell.is-row-end-8-widescreen { + --bulma-grid-cell-row-end: 8; + } + .cell.is-row-from-end-8-widescreen { + --bulma-grid-cell-row-start: -8; + } + .cell.is-row-span-8-widescreen { + --bulma-grid-cell-row-span: 8; + } + .cell.is-col-start-9-widescreen { + --bulma-grid-cell-column-start: 9; + } + .cell.is-col-end-9-widescreen { + --bulma-grid-cell-column-end: 9; + } + .cell.is-col-from-end-9-widescreen { + --bulma-grid-cell-column-start: -9; + } + .cell.is-col-span-9-widescreen { + --bulma-grid-cell-column-span: 9; + } + .cell.is-row-start-9-widescreen { + --bulma-grid-cell-row-start: 9; + } + .cell.is-row-end-9-widescreen { + --bulma-grid-cell-row-end: 9; + } + .cell.is-row-from-end-9-widescreen { + --bulma-grid-cell-row-start: -9; + } + .cell.is-row-span-9-widescreen { + --bulma-grid-cell-row-span: 9; + } + .cell.is-col-start-10-widescreen { + --bulma-grid-cell-column-start: 10; + } + .cell.is-col-end-10-widescreen { + --bulma-grid-cell-column-end: 10; + } + .cell.is-col-from-end-10-widescreen { + --bulma-grid-cell-column-start: -10; + } + .cell.is-col-span-10-widescreen { + --bulma-grid-cell-column-span: 10; + } + .cell.is-row-start-10-widescreen { + --bulma-grid-cell-row-start: 10; + } + .cell.is-row-end-10-widescreen { + --bulma-grid-cell-row-end: 10; + } + .cell.is-row-from-end-10-widescreen { + --bulma-grid-cell-row-start: -10; + } + .cell.is-row-span-10-widescreen { + --bulma-grid-cell-row-span: 10; + } + .cell.is-col-start-11-widescreen { + --bulma-grid-cell-column-start: 11; + } + .cell.is-col-end-11-widescreen { + --bulma-grid-cell-column-end: 11; + } + .cell.is-col-from-end-11-widescreen { + --bulma-grid-cell-column-start: -11; + } + .cell.is-col-span-11-widescreen { + --bulma-grid-cell-column-span: 11; + } + .cell.is-row-start-11-widescreen { + --bulma-grid-cell-row-start: 11; + } + .cell.is-row-end-11-widescreen { + --bulma-grid-cell-row-end: 11; + } + .cell.is-row-from-end-11-widescreen { + --bulma-grid-cell-row-start: -11; + } + .cell.is-row-span-11-widescreen { + --bulma-grid-cell-row-span: 11; + } + .cell.is-col-start-12-widescreen { + --bulma-grid-cell-column-start: 12; + } + .cell.is-col-end-12-widescreen { + --bulma-grid-cell-column-end: 12; + } + .cell.is-col-from-end-12-widescreen { + --bulma-grid-cell-column-start: -12; + } + .cell.is-col-span-12-widescreen { + --bulma-grid-cell-column-span: 12; + } + .cell.is-row-start-12-widescreen { + --bulma-grid-cell-row-start: 12; + } + .cell.is-row-end-12-widescreen { + --bulma-grid-cell-row-end: 12; + } + .cell.is-row-from-end-12-widescreen { + --bulma-grid-cell-row-start: -12; + } + .cell.is-row-span-12-widescreen { + --bulma-grid-cell-row-span: 12; + } +} +@media screen and (min-width: 1216px) and (max-width: 1407px) { + .cell.is-col-start-1-widescreen-only { + --bulma-grid-cell-column-start: 1; + } + .cell.is-col-end-1-widescreen-only { + --bulma-grid-cell-column-end: 1; + } + .cell.is-col-from-end-1-widescreen-only { + --bulma-grid-cell-column-start: -1; + } + .cell.is-col-span-1-widescreen-only { + --bulma-grid-cell-column-span: 1; + } + .cell.is-row-start-1-widescreen-only { + --bulma-grid-cell-row-start: 1; + } + .cell.is-row-end-1-widescreen-only { + --bulma-grid-cell-row-end: 1; + } + .cell.is-row-from-end-1-widescreen-only { + --bulma-grid-cell-row-start: -1; + } + .cell.is-row-span-1-widescreen-only { + --bulma-grid-cell-row-span: 1; + } + .cell.is-col-start-2-widescreen-only { + --bulma-grid-cell-column-start: 2; + } + .cell.is-col-end-2-widescreen-only { + --bulma-grid-cell-column-end: 2; + } + .cell.is-col-from-end-2-widescreen-only { + --bulma-grid-cell-column-start: -2; + } + .cell.is-col-span-2-widescreen-only { + --bulma-grid-cell-column-span: 2; + } + .cell.is-row-start-2-widescreen-only { + --bulma-grid-cell-row-start: 2; + } + .cell.is-row-end-2-widescreen-only { + --bulma-grid-cell-row-end: 2; + } + .cell.is-row-from-end-2-widescreen-only { + --bulma-grid-cell-row-start: -2; + } + .cell.is-row-span-2-widescreen-only { + --bulma-grid-cell-row-span: 2; + } + .cell.is-col-start-3-widescreen-only { + --bulma-grid-cell-column-start: 3; + } + .cell.is-col-end-3-widescreen-only { + --bulma-grid-cell-column-end: 3; + } + .cell.is-col-from-end-3-widescreen-only { + --bulma-grid-cell-column-start: -3; + } + .cell.is-col-span-3-widescreen-only { + --bulma-grid-cell-column-span: 3; + } + .cell.is-row-start-3-widescreen-only { + --bulma-grid-cell-row-start: 3; + } + .cell.is-row-end-3-widescreen-only { + --bulma-grid-cell-row-end: 3; + } + .cell.is-row-from-end-3-widescreen-only { + --bulma-grid-cell-row-start: -3; + } + .cell.is-row-span-3-widescreen-only { + --bulma-grid-cell-row-span: 3; + } + .cell.is-col-start-4-widescreen-only { + --bulma-grid-cell-column-start: 4; + } + .cell.is-col-end-4-widescreen-only { + --bulma-grid-cell-column-end: 4; + } + .cell.is-col-from-end-4-widescreen-only { + --bulma-grid-cell-column-start: -4; + } + .cell.is-col-span-4-widescreen-only { + --bulma-grid-cell-column-span: 4; + } + .cell.is-row-start-4-widescreen-only { + --bulma-grid-cell-row-start: 4; + } + .cell.is-row-end-4-widescreen-only { + --bulma-grid-cell-row-end: 4; + } + .cell.is-row-from-end-4-widescreen-only { + --bulma-grid-cell-row-start: -4; + } + .cell.is-row-span-4-widescreen-only { + --bulma-grid-cell-row-span: 4; + } + .cell.is-col-start-5-widescreen-only { + --bulma-grid-cell-column-start: 5; + } + .cell.is-col-end-5-widescreen-only { + --bulma-grid-cell-column-end: 5; + } + .cell.is-col-from-end-5-widescreen-only { + --bulma-grid-cell-column-start: -5; + } + .cell.is-col-span-5-widescreen-only { + --bulma-grid-cell-column-span: 5; + } + .cell.is-row-start-5-widescreen-only { + --bulma-grid-cell-row-start: 5; + } + .cell.is-row-end-5-widescreen-only { + --bulma-grid-cell-row-end: 5; + } + .cell.is-row-from-end-5-widescreen-only { + --bulma-grid-cell-row-start: -5; + } + .cell.is-row-span-5-widescreen-only { + --bulma-grid-cell-row-span: 5; + } + .cell.is-col-start-6-widescreen-only { + --bulma-grid-cell-column-start: 6; + } + .cell.is-col-end-6-widescreen-only { + --bulma-grid-cell-column-end: 6; + } + .cell.is-col-from-end-6-widescreen-only { + --bulma-grid-cell-column-start: -6; + } + .cell.is-col-span-6-widescreen-only { + --bulma-grid-cell-column-span: 6; + } + .cell.is-row-start-6-widescreen-only { + --bulma-grid-cell-row-start: 6; + } + .cell.is-row-end-6-widescreen-only { + --bulma-grid-cell-row-end: 6; + } + .cell.is-row-from-end-6-widescreen-only { + --bulma-grid-cell-row-start: -6; + } + .cell.is-row-span-6-widescreen-only { + --bulma-grid-cell-row-span: 6; + } + .cell.is-col-start-7-widescreen-only { + --bulma-grid-cell-column-start: 7; + } + .cell.is-col-end-7-widescreen-only { + --bulma-grid-cell-column-end: 7; + } + .cell.is-col-from-end-7-widescreen-only { + --bulma-grid-cell-column-start: -7; + } + .cell.is-col-span-7-widescreen-only { + --bulma-grid-cell-column-span: 7; + } + .cell.is-row-start-7-widescreen-only { + --bulma-grid-cell-row-start: 7; + } + .cell.is-row-end-7-widescreen-only { + --bulma-grid-cell-row-end: 7; + } + .cell.is-row-from-end-7-widescreen-only { + --bulma-grid-cell-row-start: -7; + } + .cell.is-row-span-7-widescreen-only { + --bulma-grid-cell-row-span: 7; + } + .cell.is-col-start-8-widescreen-only { + --bulma-grid-cell-column-start: 8; + } + .cell.is-col-end-8-widescreen-only { + --bulma-grid-cell-column-end: 8; + } + .cell.is-col-from-end-8-widescreen-only { + --bulma-grid-cell-column-start: -8; + } + .cell.is-col-span-8-widescreen-only { + --bulma-grid-cell-column-span: 8; + } + .cell.is-row-start-8-widescreen-only { + --bulma-grid-cell-row-start: 8; + } + .cell.is-row-end-8-widescreen-only { + --bulma-grid-cell-row-end: 8; + } + .cell.is-row-from-end-8-widescreen-only { + --bulma-grid-cell-row-start: -8; + } + .cell.is-row-span-8-widescreen-only { + --bulma-grid-cell-row-span: 8; + } + .cell.is-col-start-9-widescreen-only { + --bulma-grid-cell-column-start: 9; + } + .cell.is-col-end-9-widescreen-only { + --bulma-grid-cell-column-end: 9; + } + .cell.is-col-from-end-9-widescreen-only { + --bulma-grid-cell-column-start: -9; + } + .cell.is-col-span-9-widescreen-only { + --bulma-grid-cell-column-span: 9; + } + .cell.is-row-start-9-widescreen-only { + --bulma-grid-cell-row-start: 9; + } + .cell.is-row-end-9-widescreen-only { + --bulma-grid-cell-row-end: 9; + } + .cell.is-row-from-end-9-widescreen-only { + --bulma-grid-cell-row-start: -9; + } + .cell.is-row-span-9-widescreen-only { + --bulma-grid-cell-row-span: 9; + } + .cell.is-col-start-10-widescreen-only { + --bulma-grid-cell-column-start: 10; + } + .cell.is-col-end-10-widescreen-only { + --bulma-grid-cell-column-end: 10; + } + .cell.is-col-from-end-10-widescreen-only { + --bulma-grid-cell-column-start: -10; + } + .cell.is-col-span-10-widescreen-only { + --bulma-grid-cell-column-span: 10; + } + .cell.is-row-start-10-widescreen-only { + --bulma-grid-cell-row-start: 10; + } + .cell.is-row-end-10-widescreen-only { + --bulma-grid-cell-row-end: 10; + } + .cell.is-row-from-end-10-widescreen-only { + --bulma-grid-cell-row-start: -10; + } + .cell.is-row-span-10-widescreen-only { + --bulma-grid-cell-row-span: 10; + } + .cell.is-col-start-11-widescreen-only { + --bulma-grid-cell-column-start: 11; + } + .cell.is-col-end-11-widescreen-only { + --bulma-grid-cell-column-end: 11; + } + .cell.is-col-from-end-11-widescreen-only { + --bulma-grid-cell-column-start: -11; + } + .cell.is-col-span-11-widescreen-only { + --bulma-grid-cell-column-span: 11; + } + .cell.is-row-start-11-widescreen-only { + --bulma-grid-cell-row-start: 11; + } + .cell.is-row-end-11-widescreen-only { + --bulma-grid-cell-row-end: 11; + } + .cell.is-row-from-end-11-widescreen-only { + --bulma-grid-cell-row-start: -11; + } + .cell.is-row-span-11-widescreen-only { + --bulma-grid-cell-row-span: 11; + } + .cell.is-col-start-12-widescreen-only { + --bulma-grid-cell-column-start: 12; + } + .cell.is-col-end-12-widescreen-only { + --bulma-grid-cell-column-end: 12; + } + .cell.is-col-from-end-12-widescreen-only { + --bulma-grid-cell-column-start: -12; + } + .cell.is-col-span-12-widescreen-only { + --bulma-grid-cell-column-span: 12; + } + .cell.is-row-start-12-widescreen-only { + --bulma-grid-cell-row-start: 12; + } + .cell.is-row-end-12-widescreen-only { + --bulma-grid-cell-row-end: 12; + } + .cell.is-row-from-end-12-widescreen-only { + --bulma-grid-cell-row-start: -12; + } + .cell.is-row-span-12-widescreen-only { + --bulma-grid-cell-row-span: 12; + } +} +@media screen and (min-width: 1408px) { + .cell.is-col-start-1-fullhd { + --bulma-grid-cell-column-start: 1; + } + .cell.is-col-end-1-fullhd { + --bulma-grid-cell-column-end: 1; + } + .cell.is-col-from-end-1-fullhd { + --bulma-grid-cell-column-start: -1; + } + .cell.is-col-span-1-fullhd { + --bulma-grid-cell-column-span: 1; + } + .cell.is-row-start-1-fullhd { + --bulma-grid-cell-row-start: 1; + } + .cell.is-row-end-1-fullhd { + --bulma-grid-cell-row-end: 1; + } + .cell.is-row-from-end-1-fullhd { + --bulma-grid-cell-row-start: -1; + } + .cell.is-row-span-1-fullhd { + --bulma-grid-cell-row-span: 1; + } + .cell.is-col-start-2-fullhd { + --bulma-grid-cell-column-start: 2; + } + .cell.is-col-end-2-fullhd { + --bulma-grid-cell-column-end: 2; + } + .cell.is-col-from-end-2-fullhd { + --bulma-grid-cell-column-start: -2; + } + .cell.is-col-span-2-fullhd { + --bulma-grid-cell-column-span: 2; + } + .cell.is-row-start-2-fullhd { + --bulma-grid-cell-row-start: 2; + } + .cell.is-row-end-2-fullhd { + --bulma-grid-cell-row-end: 2; + } + .cell.is-row-from-end-2-fullhd { + --bulma-grid-cell-row-start: -2; + } + .cell.is-row-span-2-fullhd { + --bulma-grid-cell-row-span: 2; + } + .cell.is-col-start-3-fullhd { + --bulma-grid-cell-column-start: 3; + } + .cell.is-col-end-3-fullhd { + --bulma-grid-cell-column-end: 3; + } + .cell.is-col-from-end-3-fullhd { + --bulma-grid-cell-column-start: -3; + } + .cell.is-col-span-3-fullhd { + --bulma-grid-cell-column-span: 3; + } + .cell.is-row-start-3-fullhd { + --bulma-grid-cell-row-start: 3; + } + .cell.is-row-end-3-fullhd { + --bulma-grid-cell-row-end: 3; + } + .cell.is-row-from-end-3-fullhd { + --bulma-grid-cell-row-start: -3; + } + .cell.is-row-span-3-fullhd { + --bulma-grid-cell-row-span: 3; + } + .cell.is-col-start-4-fullhd { + --bulma-grid-cell-column-start: 4; + } + .cell.is-col-end-4-fullhd { + --bulma-grid-cell-column-end: 4; + } + .cell.is-col-from-end-4-fullhd { + --bulma-grid-cell-column-start: -4; + } + .cell.is-col-span-4-fullhd { + --bulma-grid-cell-column-span: 4; + } + .cell.is-row-start-4-fullhd { + --bulma-grid-cell-row-start: 4; + } + .cell.is-row-end-4-fullhd { + --bulma-grid-cell-row-end: 4; + } + .cell.is-row-from-end-4-fullhd { + --bulma-grid-cell-row-start: -4; + } + .cell.is-row-span-4-fullhd { + --bulma-grid-cell-row-span: 4; + } + .cell.is-col-start-5-fullhd { + --bulma-grid-cell-column-start: 5; + } + .cell.is-col-end-5-fullhd { + --bulma-grid-cell-column-end: 5; + } + .cell.is-col-from-end-5-fullhd { + --bulma-grid-cell-column-start: -5; + } + .cell.is-col-span-5-fullhd { + --bulma-grid-cell-column-span: 5; + } + .cell.is-row-start-5-fullhd { + --bulma-grid-cell-row-start: 5; + } + .cell.is-row-end-5-fullhd { + --bulma-grid-cell-row-end: 5; + } + .cell.is-row-from-end-5-fullhd { + --bulma-grid-cell-row-start: -5; + } + .cell.is-row-span-5-fullhd { + --bulma-grid-cell-row-span: 5; + } + .cell.is-col-start-6-fullhd { + --bulma-grid-cell-column-start: 6; + } + .cell.is-col-end-6-fullhd { + --bulma-grid-cell-column-end: 6; + } + .cell.is-col-from-end-6-fullhd { + --bulma-grid-cell-column-start: -6; + } + .cell.is-col-span-6-fullhd { + --bulma-grid-cell-column-span: 6; + } + .cell.is-row-start-6-fullhd { + --bulma-grid-cell-row-start: 6; + } + .cell.is-row-end-6-fullhd { + --bulma-grid-cell-row-end: 6; + } + .cell.is-row-from-end-6-fullhd { + --bulma-grid-cell-row-start: -6; + } + .cell.is-row-span-6-fullhd { + --bulma-grid-cell-row-span: 6; + } + .cell.is-col-start-7-fullhd { + --bulma-grid-cell-column-start: 7; + } + .cell.is-col-end-7-fullhd { + --bulma-grid-cell-column-end: 7; + } + .cell.is-col-from-end-7-fullhd { + --bulma-grid-cell-column-start: -7; + } + .cell.is-col-span-7-fullhd { + --bulma-grid-cell-column-span: 7; + } + .cell.is-row-start-7-fullhd { + --bulma-grid-cell-row-start: 7; + } + .cell.is-row-end-7-fullhd { + --bulma-grid-cell-row-end: 7; + } + .cell.is-row-from-end-7-fullhd { + --bulma-grid-cell-row-start: -7; + } + .cell.is-row-span-7-fullhd { + --bulma-grid-cell-row-span: 7; + } + .cell.is-col-start-8-fullhd { + --bulma-grid-cell-column-start: 8; + } + .cell.is-col-end-8-fullhd { + --bulma-grid-cell-column-end: 8; + } + .cell.is-col-from-end-8-fullhd { + --bulma-grid-cell-column-start: -8; + } + .cell.is-col-span-8-fullhd { + --bulma-grid-cell-column-span: 8; + } + .cell.is-row-start-8-fullhd { + --bulma-grid-cell-row-start: 8; + } + .cell.is-row-end-8-fullhd { + --bulma-grid-cell-row-end: 8; + } + .cell.is-row-from-end-8-fullhd { + --bulma-grid-cell-row-start: -8; + } + .cell.is-row-span-8-fullhd { + --bulma-grid-cell-row-span: 8; + } + .cell.is-col-start-9-fullhd { + --bulma-grid-cell-column-start: 9; + } + .cell.is-col-end-9-fullhd { + --bulma-grid-cell-column-end: 9; + } + .cell.is-col-from-end-9-fullhd { + --bulma-grid-cell-column-start: -9; + } + .cell.is-col-span-9-fullhd { + --bulma-grid-cell-column-span: 9; + } + .cell.is-row-start-9-fullhd { + --bulma-grid-cell-row-start: 9; + } + .cell.is-row-end-9-fullhd { + --bulma-grid-cell-row-end: 9; + } + .cell.is-row-from-end-9-fullhd { + --bulma-grid-cell-row-start: -9; + } + .cell.is-row-span-9-fullhd { + --bulma-grid-cell-row-span: 9; + } + .cell.is-col-start-10-fullhd { + --bulma-grid-cell-column-start: 10; + } + .cell.is-col-end-10-fullhd { + --bulma-grid-cell-column-end: 10; + } + .cell.is-col-from-end-10-fullhd { + --bulma-grid-cell-column-start: -10; + } + .cell.is-col-span-10-fullhd { + --bulma-grid-cell-column-span: 10; + } + .cell.is-row-start-10-fullhd { + --bulma-grid-cell-row-start: 10; + } + .cell.is-row-end-10-fullhd { + --bulma-grid-cell-row-end: 10; + } + .cell.is-row-from-end-10-fullhd { + --bulma-grid-cell-row-start: -10; + } + .cell.is-row-span-10-fullhd { + --bulma-grid-cell-row-span: 10; + } + .cell.is-col-start-11-fullhd { + --bulma-grid-cell-column-start: 11; + } + .cell.is-col-end-11-fullhd { + --bulma-grid-cell-column-end: 11; + } + .cell.is-col-from-end-11-fullhd { + --bulma-grid-cell-column-start: -11; + } + .cell.is-col-span-11-fullhd { + --bulma-grid-cell-column-span: 11; + } + .cell.is-row-start-11-fullhd { + --bulma-grid-cell-row-start: 11; + } + .cell.is-row-end-11-fullhd { + --bulma-grid-cell-row-end: 11; + } + .cell.is-row-from-end-11-fullhd { + --bulma-grid-cell-row-start: -11; + } + .cell.is-row-span-11-fullhd { + --bulma-grid-cell-row-span: 11; + } + .cell.is-col-start-12-fullhd { + --bulma-grid-cell-column-start: 12; + } + .cell.is-col-end-12-fullhd { + --bulma-grid-cell-column-end: 12; + } + .cell.is-col-from-end-12-fullhd { + --bulma-grid-cell-column-start: -12; + } + .cell.is-col-span-12-fullhd { + --bulma-grid-cell-column-span: 12; + } + .cell.is-row-start-12-fullhd { + --bulma-grid-cell-row-start: 12; + } + .cell.is-row-end-12-fullhd { + --bulma-grid-cell-row-end: 12; + } + .cell.is-row-from-end-12-fullhd { + --bulma-grid-cell-row-start: -12; + } + .cell.is-row-span-12-fullhd { + --bulma-grid-cell-row-span: 12; + } +} + +/* Bulma Components */ +.container { + flex-grow: 1; + margin: 0 auto; + position: relative; + width: 100%; +} +.container.is-fluid { + max-width: none !important; + padding-left: 32px; + padding-right: 32px; + width: 100%; +} +.container.is-max-tablet { + max-width: 705px; +} +@media screen and (min-width: 1024px) { + .container { + max-width: 960px; + } +} +@media screen and (max-width: 1215px) { + .container.is-widescreen:not(.is-max-tablet):not(.is-max-desktop) { + max-width: 1152px; + } +} +@media screen and (max-width: 1407px) { + .container.is-fullhd:not(.is-max-tablet):not(.is-max-desktop):not(.is-max-widescreen) { + max-width: 1344px; + } +} +@media screen and (min-width: 1216px) { + .container:not(.is-max-tablet):not(.is-max-desktop) { + max-width: 1152px; + } +} +@media screen and (min-width: 1408px) { + .container:not(.is-max-tablet):not(.is-max-desktop):not(.is-max-widescreen) { + max-width: 1344px; + } +} + +.footer { + --bulma-footer-background-color: var(--bulma-scheme-main-bis); + --bulma-footer-color: false; + --bulma-footer-padding: 3rem 1.5rem 6rem; + background-color: var(--bulma-footer-background-color); + padding: var(--bulma-footer-padding); +} + +.hero { + --bulma-hero-body-padding: 3rem 1.5rem; + --bulma-hero-body-padding-tablet: 3rem 3rem; + --bulma-hero-body-padding-small: 1.5rem; + --bulma-hero-body-padding-medium: 9rem 4.5rem; + --bulma-hero-body-padding-large: 18rem 6rem; + --bulma-hero-gradient-h-offset: 5deg; + --bulma-hero-gradient-s-offset: 10%; + --bulma-hero-gradient-l-offset: 5%; +} + +.hero { + align-items: stretch; + display: flex; + flex-direction: column; + justify-content: space-between; +} +.hero .navbar { + background: none; +} +.hero .tabs ul { + border-bottom: none; +} +.hero.is-white { + --bulma-hero-h: var(--bulma-white-h); + --bulma-hero-s: var(--bulma-white-s); + --bulma-hero-background-l: var(--bulma-white-l); + --bulma-hero-color-l: var(--bulma-white-invert-l); + background-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-background-l)); + color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); +} +.hero.is-white .navbar { + --bulma-navbar-item-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); + --bulma-navbar-item-hover-background-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); + --bulma-navbar-item-hover-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-background-l)); + --bulma-navbar-item-active-background-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); + --bulma-navbar-item-active-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-background-l)); +} +.hero.is-white .tabs { + --bulma-tabs-link-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); + --bulma-tabs-boxed-link-active-background-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); + --bulma-tabs-boxed-link-active-border-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-background-l)); + --bulma-tabs-link-active-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-background-l)); +} +.hero.is-white .subtitle { + --bulma-subtitle-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); + --bulma-subtitle-strong-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); +} +.hero.is-white .title { + --bulma-title-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); + --bulma-title-strong-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); +} +.hero.is-white.is-bold { + background-image: linear-gradient(141deg, hsl(calc(var(--bulma-hero-h) - 5deg), calc(var(--bulma-hero-s) + 10%), calc(var(--bulma-hero-background-l) + 5%)) 0%, hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-background-l)) 71%, hsl(calc(var(--bulma-hero-h) + 5deg), calc(var(--bulma-hero-s) - 10%), calc(var(--bulma-hero-background-l) - 5%)) 100%); +} +@media screen and (max-width: 768px) { + .hero.is-white.is-bold .navbar-menu { + background-image: linear-gradient(141deg, hsl(calc(var(--bulma-hero-h) - 5deg), calc(var(--bulma-hero-s) + 10%), calc(var(--bulma-hero-background-l) + 5%)) 0%, hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)) 71%, hsl(calc(var(--bulma-hero-h) + 5deg), calc(var(--bulma-hero-s) - 10%), calc(var(--bulma-hero-background-l) - 5%)) 100%); + } +} +.hero.is-black { + --bulma-hero-h: var(--bulma-black-h); + --bulma-hero-s: var(--bulma-black-s); + --bulma-hero-background-l: var(--bulma-black-l); + --bulma-hero-color-l: var(--bulma-black-invert-l); + background-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-background-l)); + color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); +} +.hero.is-black .navbar { + --bulma-navbar-item-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); + --bulma-navbar-item-hover-background-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); + --bulma-navbar-item-hover-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-background-l)); + --bulma-navbar-item-active-background-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); + --bulma-navbar-item-active-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-background-l)); +} +.hero.is-black .tabs { + --bulma-tabs-link-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); + --bulma-tabs-boxed-link-active-background-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); + --bulma-tabs-boxed-link-active-border-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-background-l)); + --bulma-tabs-link-active-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-background-l)); +} +.hero.is-black .subtitle { + --bulma-subtitle-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); + --bulma-subtitle-strong-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); +} +.hero.is-black .title { + --bulma-title-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); + --bulma-title-strong-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); +} +.hero.is-black.is-bold { + background-image: linear-gradient(141deg, hsl(calc(var(--bulma-hero-h) - 5deg), calc(var(--bulma-hero-s) + 10%), calc(var(--bulma-hero-background-l) + 5%)) 0%, hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-background-l)) 71%, hsl(calc(var(--bulma-hero-h) + 5deg), calc(var(--bulma-hero-s) - 10%), calc(var(--bulma-hero-background-l) - 5%)) 100%); +} +@media screen and (max-width: 768px) { + .hero.is-black.is-bold .navbar-menu { + background-image: linear-gradient(141deg, hsl(calc(var(--bulma-hero-h) - 5deg), calc(var(--bulma-hero-s) + 10%), calc(var(--bulma-hero-background-l) + 5%)) 0%, hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)) 71%, hsl(calc(var(--bulma-hero-h) + 5deg), calc(var(--bulma-hero-s) - 10%), calc(var(--bulma-hero-background-l) - 5%)) 100%); + } +} +.hero.is-light { + --bulma-hero-h: var(--bulma-light-h); + --bulma-hero-s: var(--bulma-light-s); + --bulma-hero-background-l: var(--bulma-light-l); + --bulma-hero-color-l: var(--bulma-light-invert-l); + background-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-background-l)); + color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); +} +.hero.is-light .navbar { + --bulma-navbar-item-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); + --bulma-navbar-item-hover-background-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); + --bulma-navbar-item-hover-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-background-l)); + --bulma-navbar-item-active-background-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); + --bulma-navbar-item-active-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-background-l)); +} +.hero.is-light .tabs { + --bulma-tabs-link-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); + --bulma-tabs-boxed-link-active-background-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); + --bulma-tabs-boxed-link-active-border-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-background-l)); + --bulma-tabs-link-active-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-background-l)); +} +.hero.is-light .subtitle { + --bulma-subtitle-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); + --bulma-subtitle-strong-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); +} +.hero.is-light .title { + --bulma-title-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); + --bulma-title-strong-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); +} +.hero.is-light.is-bold { + background-image: linear-gradient(141deg, hsl(calc(var(--bulma-hero-h) - 5deg), calc(var(--bulma-hero-s) + 10%), calc(var(--bulma-hero-background-l) + 5%)) 0%, hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-background-l)) 71%, hsl(calc(var(--bulma-hero-h) + 5deg), calc(var(--bulma-hero-s) - 10%), calc(var(--bulma-hero-background-l) - 5%)) 100%); +} +@media screen and (max-width: 768px) { + .hero.is-light.is-bold .navbar-menu { + background-image: linear-gradient(141deg, hsl(calc(var(--bulma-hero-h) - 5deg), calc(var(--bulma-hero-s) + 10%), calc(var(--bulma-hero-background-l) + 5%)) 0%, hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)) 71%, hsl(calc(var(--bulma-hero-h) + 5deg), calc(var(--bulma-hero-s) - 10%), calc(var(--bulma-hero-background-l) - 5%)) 100%); + } +} +.hero.is-dark { + --bulma-hero-h: var(--bulma-dark-h); + --bulma-hero-s: var(--bulma-dark-s); + --bulma-hero-background-l: var(--bulma-dark-l); + --bulma-hero-color-l: var(--bulma-dark-invert-l); + background-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-background-l)); + color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); +} +.hero.is-dark .navbar { + --bulma-navbar-item-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); + --bulma-navbar-item-hover-background-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); + --bulma-navbar-item-hover-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-background-l)); + --bulma-navbar-item-active-background-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); + --bulma-navbar-item-active-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-background-l)); +} +.hero.is-dark .tabs { + --bulma-tabs-link-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); + --bulma-tabs-boxed-link-active-background-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); + --bulma-tabs-boxed-link-active-border-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-background-l)); + --bulma-tabs-link-active-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-background-l)); +} +.hero.is-dark .subtitle { + --bulma-subtitle-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); + --bulma-subtitle-strong-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); +} +.hero.is-dark .title { + --bulma-title-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); + --bulma-title-strong-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); +} +.hero.is-dark.is-bold { + background-image: linear-gradient(141deg, hsl(calc(var(--bulma-hero-h) - 5deg), calc(var(--bulma-hero-s) + 10%), calc(var(--bulma-hero-background-l) + 5%)) 0%, hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-background-l)) 71%, hsl(calc(var(--bulma-hero-h) + 5deg), calc(var(--bulma-hero-s) - 10%), calc(var(--bulma-hero-background-l) - 5%)) 100%); +} +@media screen and (max-width: 768px) { + .hero.is-dark.is-bold .navbar-menu { + background-image: linear-gradient(141deg, hsl(calc(var(--bulma-hero-h) - 5deg), calc(var(--bulma-hero-s) + 10%), calc(var(--bulma-hero-background-l) + 5%)) 0%, hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)) 71%, hsl(calc(var(--bulma-hero-h) + 5deg), calc(var(--bulma-hero-s) - 10%), calc(var(--bulma-hero-background-l) - 5%)) 100%); + } +} +.hero.is-text { + --bulma-hero-h: var(--bulma-text-h); + --bulma-hero-s: var(--bulma-text-s); + --bulma-hero-background-l: var(--bulma-text-l); + --bulma-hero-color-l: var(--bulma-text-invert-l); + background-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-background-l)); + color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); +} +.hero.is-text .navbar { + --bulma-navbar-item-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); + --bulma-navbar-item-hover-background-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); + --bulma-navbar-item-hover-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-background-l)); + --bulma-navbar-item-active-background-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); + --bulma-navbar-item-active-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-background-l)); +} +.hero.is-text .tabs { + --bulma-tabs-link-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); + --bulma-tabs-boxed-link-active-background-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); + --bulma-tabs-boxed-link-active-border-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-background-l)); + --bulma-tabs-link-active-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-background-l)); +} +.hero.is-text .subtitle { + --bulma-subtitle-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); + --bulma-subtitle-strong-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); +} +.hero.is-text .title { + --bulma-title-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); + --bulma-title-strong-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); +} +.hero.is-text.is-bold { + background-image: linear-gradient(141deg, hsl(calc(var(--bulma-hero-h) - 5deg), calc(var(--bulma-hero-s) + 10%), calc(var(--bulma-hero-background-l) + 5%)) 0%, hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-background-l)) 71%, hsl(calc(var(--bulma-hero-h) + 5deg), calc(var(--bulma-hero-s) - 10%), calc(var(--bulma-hero-background-l) - 5%)) 100%); +} +@media screen and (max-width: 768px) { + .hero.is-text.is-bold .navbar-menu { + background-image: linear-gradient(141deg, hsl(calc(var(--bulma-hero-h) - 5deg), calc(var(--bulma-hero-s) + 10%), calc(var(--bulma-hero-background-l) + 5%)) 0%, hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)) 71%, hsl(calc(var(--bulma-hero-h) + 5deg), calc(var(--bulma-hero-s) - 10%), calc(var(--bulma-hero-background-l) - 5%)) 100%); + } +} +.hero.is-primary { + --bulma-hero-h: var(--bulma-primary-h); + --bulma-hero-s: var(--bulma-primary-s); + --bulma-hero-background-l: var(--bulma-primary-l); + --bulma-hero-color-l: var(--bulma-primary-invert-l); + background-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-background-l)); + color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); +} +.hero.is-primary .navbar { + --bulma-navbar-item-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); + --bulma-navbar-item-hover-background-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); + --bulma-navbar-item-hover-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-background-l)); + --bulma-navbar-item-active-background-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); + --bulma-navbar-item-active-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-background-l)); +} +.hero.is-primary .tabs { + --bulma-tabs-link-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); + --bulma-tabs-boxed-link-active-background-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); + --bulma-tabs-boxed-link-active-border-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-background-l)); + --bulma-tabs-link-active-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-background-l)); +} +.hero.is-primary .subtitle { + --bulma-subtitle-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); + --bulma-subtitle-strong-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); +} +.hero.is-primary .title { + --bulma-title-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); + --bulma-title-strong-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); +} +.hero.is-primary.is-bold { + background-image: linear-gradient(141deg, hsl(calc(var(--bulma-hero-h) - 5deg), calc(var(--bulma-hero-s) + 10%), calc(var(--bulma-hero-background-l) + 5%)) 0%, hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-background-l)) 71%, hsl(calc(var(--bulma-hero-h) + 5deg), calc(var(--bulma-hero-s) - 10%), calc(var(--bulma-hero-background-l) - 5%)) 100%); +} +@media screen and (max-width: 768px) { + .hero.is-primary.is-bold .navbar-menu { + background-image: linear-gradient(141deg, hsl(calc(var(--bulma-hero-h) - 5deg), calc(var(--bulma-hero-s) + 10%), calc(var(--bulma-hero-background-l) + 5%)) 0%, hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)) 71%, hsl(calc(var(--bulma-hero-h) + 5deg), calc(var(--bulma-hero-s) - 10%), calc(var(--bulma-hero-background-l) - 5%)) 100%); + } +} +.hero.is-link { + --bulma-hero-h: var(--bulma-link-h); + --bulma-hero-s: var(--bulma-link-s); + --bulma-hero-background-l: var(--bulma-link-l); + --bulma-hero-color-l: var(--bulma-link-invert-l); + background-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-background-l)); + color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); +} +.hero.is-link .navbar { + --bulma-navbar-item-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); + --bulma-navbar-item-hover-background-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); + --bulma-navbar-item-hover-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-background-l)); + --bulma-navbar-item-active-background-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); + --bulma-navbar-item-active-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-background-l)); +} +.hero.is-link .tabs { + --bulma-tabs-link-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); + --bulma-tabs-boxed-link-active-background-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); + --bulma-tabs-boxed-link-active-border-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-background-l)); + --bulma-tabs-link-active-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-background-l)); +} +.hero.is-link .subtitle { + --bulma-subtitle-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); + --bulma-subtitle-strong-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); +} +.hero.is-link .title { + --bulma-title-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); + --bulma-title-strong-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); +} +.hero.is-link.is-bold { + background-image: linear-gradient(141deg, hsl(calc(var(--bulma-hero-h) - 5deg), calc(var(--bulma-hero-s) + 10%), calc(var(--bulma-hero-background-l) + 5%)) 0%, hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-background-l)) 71%, hsl(calc(var(--bulma-hero-h) + 5deg), calc(var(--bulma-hero-s) - 10%), calc(var(--bulma-hero-background-l) - 5%)) 100%); +} +@media screen and (max-width: 768px) { + .hero.is-link.is-bold .navbar-menu { + background-image: linear-gradient(141deg, hsl(calc(var(--bulma-hero-h) - 5deg), calc(var(--bulma-hero-s) + 10%), calc(var(--bulma-hero-background-l) + 5%)) 0%, hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)) 71%, hsl(calc(var(--bulma-hero-h) + 5deg), calc(var(--bulma-hero-s) - 10%), calc(var(--bulma-hero-background-l) - 5%)) 100%); + } +} +.hero.is-info { + --bulma-hero-h: var(--bulma-info-h); + --bulma-hero-s: var(--bulma-info-s); + --bulma-hero-background-l: var(--bulma-info-l); + --bulma-hero-color-l: var(--bulma-info-invert-l); + background-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-background-l)); + color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); +} +.hero.is-info .navbar { + --bulma-navbar-item-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); + --bulma-navbar-item-hover-background-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); + --bulma-navbar-item-hover-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-background-l)); + --bulma-navbar-item-active-background-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); + --bulma-navbar-item-active-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-background-l)); +} +.hero.is-info .tabs { + --bulma-tabs-link-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); + --bulma-tabs-boxed-link-active-background-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); + --bulma-tabs-boxed-link-active-border-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-background-l)); + --bulma-tabs-link-active-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-background-l)); +} +.hero.is-info .subtitle { + --bulma-subtitle-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); + --bulma-subtitle-strong-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); +} +.hero.is-info .title { + --bulma-title-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); + --bulma-title-strong-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); +} +.hero.is-info.is-bold { + background-image: linear-gradient(141deg, hsl(calc(var(--bulma-hero-h) - 5deg), calc(var(--bulma-hero-s) + 10%), calc(var(--bulma-hero-background-l) + 5%)) 0%, hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-background-l)) 71%, hsl(calc(var(--bulma-hero-h) + 5deg), calc(var(--bulma-hero-s) - 10%), calc(var(--bulma-hero-background-l) - 5%)) 100%); +} +@media screen and (max-width: 768px) { + .hero.is-info.is-bold .navbar-menu { + background-image: linear-gradient(141deg, hsl(calc(var(--bulma-hero-h) - 5deg), calc(var(--bulma-hero-s) + 10%), calc(var(--bulma-hero-background-l) + 5%)) 0%, hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)) 71%, hsl(calc(var(--bulma-hero-h) + 5deg), calc(var(--bulma-hero-s) - 10%), calc(var(--bulma-hero-background-l) - 5%)) 100%); + } +} +.hero.is-success { + --bulma-hero-h: var(--bulma-success-h); + --bulma-hero-s: var(--bulma-success-s); + --bulma-hero-background-l: var(--bulma-success-l); + --bulma-hero-color-l: var(--bulma-success-invert-l); + background-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-background-l)); + color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); +} +.hero.is-success .navbar { + --bulma-navbar-item-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); + --bulma-navbar-item-hover-background-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); + --bulma-navbar-item-hover-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-background-l)); + --bulma-navbar-item-active-background-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); + --bulma-navbar-item-active-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-background-l)); +} +.hero.is-success .tabs { + --bulma-tabs-link-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); + --bulma-tabs-boxed-link-active-background-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); + --bulma-tabs-boxed-link-active-border-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-background-l)); + --bulma-tabs-link-active-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-background-l)); +} +.hero.is-success .subtitle { + --bulma-subtitle-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); + --bulma-subtitle-strong-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); +} +.hero.is-success .title { + --bulma-title-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); + --bulma-title-strong-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); +} +.hero.is-success.is-bold { + background-image: linear-gradient(141deg, hsl(calc(var(--bulma-hero-h) - 5deg), calc(var(--bulma-hero-s) + 10%), calc(var(--bulma-hero-background-l) + 5%)) 0%, hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-background-l)) 71%, hsl(calc(var(--bulma-hero-h) + 5deg), calc(var(--bulma-hero-s) - 10%), calc(var(--bulma-hero-background-l) - 5%)) 100%); +} +@media screen and (max-width: 768px) { + .hero.is-success.is-bold .navbar-menu { + background-image: linear-gradient(141deg, hsl(calc(var(--bulma-hero-h) - 5deg), calc(var(--bulma-hero-s) + 10%), calc(var(--bulma-hero-background-l) + 5%)) 0%, hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)) 71%, hsl(calc(var(--bulma-hero-h) + 5deg), calc(var(--bulma-hero-s) - 10%), calc(var(--bulma-hero-background-l) - 5%)) 100%); + } +} +.hero.is-warning { + --bulma-hero-h: var(--bulma-warning-h); + --bulma-hero-s: var(--bulma-warning-s); + --bulma-hero-background-l: var(--bulma-warning-l); + --bulma-hero-color-l: var(--bulma-warning-invert-l); + background-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-background-l)); + color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); +} +.hero.is-warning .navbar { + --bulma-navbar-item-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); + --bulma-navbar-item-hover-background-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); + --bulma-navbar-item-hover-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-background-l)); + --bulma-navbar-item-active-background-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); + --bulma-navbar-item-active-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-background-l)); +} +.hero.is-warning .tabs { + --bulma-tabs-link-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); + --bulma-tabs-boxed-link-active-background-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); + --bulma-tabs-boxed-link-active-border-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-background-l)); + --bulma-tabs-link-active-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-background-l)); +} +.hero.is-warning .subtitle { + --bulma-subtitle-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); + --bulma-subtitle-strong-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); +} +.hero.is-warning .title { + --bulma-title-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); + --bulma-title-strong-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); +} +.hero.is-warning.is-bold { + background-image: linear-gradient(141deg, hsl(calc(var(--bulma-hero-h) - 5deg), calc(var(--bulma-hero-s) + 10%), calc(var(--bulma-hero-background-l) + 5%)) 0%, hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-background-l)) 71%, hsl(calc(var(--bulma-hero-h) + 5deg), calc(var(--bulma-hero-s) - 10%), calc(var(--bulma-hero-background-l) - 5%)) 100%); +} +@media screen and (max-width: 768px) { + .hero.is-warning.is-bold .navbar-menu { + background-image: linear-gradient(141deg, hsl(calc(var(--bulma-hero-h) - 5deg), calc(var(--bulma-hero-s) + 10%), calc(var(--bulma-hero-background-l) + 5%)) 0%, hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)) 71%, hsl(calc(var(--bulma-hero-h) + 5deg), calc(var(--bulma-hero-s) - 10%), calc(var(--bulma-hero-background-l) - 5%)) 100%); + } +} +.hero.is-danger { + --bulma-hero-h: var(--bulma-danger-h); + --bulma-hero-s: var(--bulma-danger-s); + --bulma-hero-background-l: var(--bulma-danger-l); + --bulma-hero-color-l: var(--bulma-danger-invert-l); + background-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-background-l)); + color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); +} +.hero.is-danger .navbar { + --bulma-navbar-item-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); + --bulma-navbar-item-hover-background-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); + --bulma-navbar-item-hover-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-background-l)); + --bulma-navbar-item-active-background-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); + --bulma-navbar-item-active-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-background-l)); +} +.hero.is-danger .tabs { + --bulma-tabs-link-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); + --bulma-tabs-boxed-link-active-background-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); + --bulma-tabs-boxed-link-active-border-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-background-l)); + --bulma-tabs-link-active-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-background-l)); +} +.hero.is-danger .subtitle { + --bulma-subtitle-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); + --bulma-subtitle-strong-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); +} +.hero.is-danger .title { + --bulma-title-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); + --bulma-title-strong-color: hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)); +} +.hero.is-danger.is-bold { + background-image: linear-gradient(141deg, hsl(calc(var(--bulma-hero-h) - 5deg), calc(var(--bulma-hero-s) + 10%), calc(var(--bulma-hero-background-l) + 5%)) 0%, hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-background-l)) 71%, hsl(calc(var(--bulma-hero-h) + 5deg), calc(var(--bulma-hero-s) - 10%), calc(var(--bulma-hero-background-l) - 5%)) 100%); +} +@media screen and (max-width: 768px) { + .hero.is-danger.is-bold .navbar-menu { + background-image: linear-gradient(141deg, hsl(calc(var(--bulma-hero-h) - 5deg), calc(var(--bulma-hero-s) + 10%), calc(var(--bulma-hero-background-l) + 5%)) 0%, hsl(var(--bulma-hero-h), var(--bulma-hero-s), var(--bulma-hero-color-l)) 71%, hsl(calc(var(--bulma-hero-h) + 5deg), calc(var(--bulma-hero-s) - 10%), calc(var(--bulma-hero-background-l) - 5%)) 100%); + } +} +.hero.is-small .hero-body { + padding: var(--bulma-hero-body-padding-small); +} +@media screen and (min-width: 769px), print { + .hero.is-medium .hero-body { + padding: var(--bulma-hero-body-padding-medium); + } +} +@media screen and (min-width: 769px), print { + .hero.is-large .hero-body { + padding: var(--bulma-hero-body-padding-large); + } +} +.hero.is-halfheight .hero-body, .hero.is-fullheight .hero-body, .hero.is-fullheight-with-navbar .hero-body { + align-items: center; + display: flex; +} +.hero.is-halfheight .hero-body > .container, .hero.is-fullheight .hero-body > .container, .hero.is-fullheight-with-navbar .hero-body > .container { + flex-grow: 1; + flex-shrink: 1; +} +.hero.is-halfheight { + min-height: 50vh; +} +.hero.is-fullheight { + min-height: 100vh; +} + +.hero-video { + overflow: hidden; +} +.hero-video video { + left: 50%; + min-height: 100%; + min-width: 100%; + position: absolute; + top: 50%; + transform: translate3d(-50%, -50%, 0); +} +.hero-video.is-transparent { + opacity: 0.3; +} +@media screen and (max-width: 768px) { + .hero-video { + display: none; + } +} + +.hero-buttons { + margin-top: 1.5rem; +} +@media screen and (max-width: 768px) { + .hero-buttons .button { + display: flex; + } + .hero-buttons .button:not(:last-child) { + margin-bottom: 0.75rem; + } +} +@media screen and (min-width: 769px), print { + .hero-buttons { + display: flex; + justify-content: center; + } + .hero-buttons .button:not(:last-child) { + margin-inline-end: 1.5rem; + } +} + +.hero-head, +.hero-foot { + flex-grow: 0; + flex-shrink: 0; +} + +.hero-body { + flex-grow: 1; + flex-shrink: 0; + padding: var(--bulma-hero-body-padding); +} +@media screen and (min-width: 769px), print { + .hero-body { + padding: var(--bulma-hero-body-padding-tablet); + } +} + +.level { + --bulma-level-item-spacing: calc(var(--bulma-block-spacing) * 0.5); + align-items: center; + display: flex; + flex-direction: column; + justify-content: space-between; + gap: var(--bulma-level-item-spacing); +} +.level code { + border-radius: var(--bulma-radius); +} +.level img { + display: inline-block; + vertical-align: top; +} +.level.is-mobile { + display: flex; + flex-direction: row; +} +.level.is-mobile .level-left, +.level.is-mobile .level-right { + display: flex; +} +.level.is-mobile .level-item:not(.is-narrow) { + flex-grow: 1; +} +@media screen and (min-width: 769px), print { + .level { + display: flex; + flex-direction: row; + } + .level > .level-item:not(.is-narrow) { + flex-grow: 1; + } +} + +.level-item { + align-items: center; + display: flex; + flex-basis: auto; + flex-grow: 0; + flex-shrink: 0; + justify-content: center; +} +.level-item .title, +.level-item .subtitle { + margin-bottom: 0; +} + +.level-left, +.level-right { + flex-basis: auto; + flex-grow: 0; + flex-shrink: 0; + gap: calc(var(--bulma-block-spacing) * 0.5); +} +.level-left .level-item.is-flexible, +.level-right .level-item.is-flexible { + flex-grow: 1; +} + +.level-left { + align-items: center; + display: flex; + flex-direction: column; + justify-content: flex-start; +} +@media screen and (min-width: 769px), print { + .level-left { + flex-direction: row; + } +} + +.level-right { + align-items: center; + display: flex; + flex-direction: column; + justify-content: flex-end; +} +@media screen and (min-width: 769px), print { + .level-right { + flex-direction: row; + } +} + +.media { + --bulma-media-border-color: hsla(var(--bulma-scheme-h), var(--bulma-scheme-s), var(--bulma-border-l), 0.5); + --bulma-media-border-size: 1px; + --bulma-media-spacing: 1rem; + --bulma-media-spacing-large: 1.5rem; + --bulma-media-content-spacing: 0.75rem; + --bulma-media-level-1-spacing: 0.75rem; + --bulma-media-level-1-content-spacing: 0.5rem; + --bulma-media-level-2-spacing: 0.5rem; + align-items: flex-start; + display: flex; + text-align: inherit; +} +.media .content:not(:last-child) { + margin-bottom: var(--bulma-media-content-spacing); +} +.media .media { + border-top-color: var(--bulma-media-border-color); + border-top-style: solid; + border-top-width: var(--bulma-media-border-size); + display: flex; + padding-top: var(--bulma-media-level-1-spacing); +} +.media .media .content:not(:last-child), +.media .media .control:not(:last-child) { + margin-bottom: var(--bulma-media-level-1-content-spacing); +} +.media .media .media { + padding-top: var(--bulma-media-level-2-spacing); +} +.media .media .media + .media { + margin-top: var(--bulma-media-level-2-spacing); +} +.media + .media { + border-top-color: var(--bulma-media-border-color); + border-top-style: solid; + border-top-width: var(--bulma-media-border-size); + margin-top: var(--bulma-media-spacing); + padding-top: var(--bulma-media-spacing); +} +.media.is-large + .media { + margin-top: var(--bulma-media-spacing-large); + padding-top: var(--bulma-media-spacing-large); +} + +.media-left, +.media-right { + flex-basis: auto; + flex-grow: 0; + flex-shrink: 0; +} + +.media-left { + margin-inline-end: var(--bulma-media-spacing); +} + +.media-right { + margin-inline-start: var(--bulma-media-spacing); +} + +.media-content { + flex-basis: auto; + flex-grow: 1; + flex-shrink: 1; + text-align: inherit; +} + +@media screen and (max-width: 768px) { + .media-content { + overflow-x: auto; + } +} +.section { + --bulma-section-padding: 3rem 1.5rem; + --bulma-section-padding-desktop: 3rem 3rem; + --bulma-section-padding-medium: 9rem 4.5rem; + --bulma-section-padding-large: 18rem 6rem; + padding: var(--bulma-section-padding); +} +@media screen and (min-width: 1024px) { + .section { + padding: var(--bulma-section-padding-desktop); + } + .section.is-medium { + padding: var(--bulma-section-padding-medium); + } + .section.is-large { + padding: var(--bulma-section-padding-large); + } +} +.section.is-fullheight { + min-height: 100vh; +} + +:root { + --bulma-skeleton-background: var(--bulma-border); + --bulma-skeleton-radius: var(--bulma-radius-small); + --bulma-skeleton-block-min-height: 4.5em; + --bulma-skeleton-lines-gap: 0.75em; + --bulma-skeleton-line-height: 0.75em; +} + +.skeleton-lines > div, .skeleton-block, .has-skeleton::after, .is-skeleton { + animation-duration: 2s; + animation-iteration-count: infinite; + animation-name: pulsate; + animation-timing-function: cubic-bezier(0.4, 0, 0.6, 1); + background-color: var(--bulma-skeleton-background); + border-radius: var(--bulma-skeleton-radius); + box-shadow: none; + pointer-events: none; +} + +.is-skeleton { + color: transparent !important; +} +.is-skeleton em, +.is-skeleton strong { + color: inherit; +} +.is-skeleton img { + visibility: hidden; +} +.is-skeleton.checkbox input { + opacity: 0; +} +.is-skeleton.delete { + border-radius: var(--bulma-radius-rounded); +} +.is-skeleton.delete::before, .is-skeleton.delete::after { + display: none; +} + +input.is-skeleton, +textarea.is-skeleton { + resize: none; +} +input.is-skeleton::-moz-placeholder, +textarea.is-skeleton::-moz-placeholder { + color: transparent !important; +} +input.is-skeleton::-webkit-input-placeholder, +textarea.is-skeleton::-webkit-input-placeholder { + color: transparent !important; +} +input.is-skeleton:-moz-placeholder, +textarea.is-skeleton:-moz-placeholder { + color: transparent !important; +} +input.is-skeleton:-ms-input-placeholder, +textarea.is-skeleton:-ms-input-placeholder { + color: transparent !important; +} + +.has-skeleton { + color: transparent !important; + position: relative; +} +.has-skeleton::after { + content: ""; + display: block; + height: 100%; + left: 0; + max-width: 100%; + min-width: 10%; + position: absolute; + top: 0; + width: 7em; +} + +.skeleton-block { + color: transparent !important; + min-height: var(--bulma-skeleton-block-min-height); +} + +.skeleton-lines { + color: transparent !important; + display: flex; + flex-direction: column; + gap: var(--bulma-skeleton-lines-gap); + position: relative; +} +.skeleton-lines > div { + height: var(--bulma-skeleton-line-height); +} +.skeleton-lines > div:last-child { + min-width: 4em; + width: 30%; +} + +/* Bulma Helpers */ +.is-aspect-ratio-1by1 { + aspect-ratio: 1/1; +} + +.is-aspect-ratio-5by4 { + aspect-ratio: 5/4; +} + +.is-aspect-ratio-4by3 { + aspect-ratio: 4/3; +} + +.is-aspect-ratio-3by2 { + aspect-ratio: 3/2; +} + +.is-aspect-ratio-5by3 { + aspect-ratio: 5/3; +} + +.is-aspect-ratio-16by9 { + aspect-ratio: 16/9; +} + +.is-aspect-ratio-2by1 { + aspect-ratio: 2/1; +} + +.is-aspect-ratio-3by1 { + aspect-ratio: 3/1; +} + +.is-aspect-ratio-4by5 { + aspect-ratio: 4/5; +} + +.is-aspect-ratio-3by4 { + aspect-ratio: 3/4; +} + +.is-aspect-ratio-2by3 { + aspect-ratio: 2/3; +} + +.is-aspect-ratio-3by5 { + aspect-ratio: 3/5; +} + +.is-aspect-ratio-9by16 { + aspect-ratio: 9/16; +} + +.is-aspect-ratio-1by2 { + aspect-ratio: 1/2; +} + +.is-aspect-ratio-1by3 { + aspect-ratio: 1/3; +} + +.has-radius-small { + border-radius: var(--bulma-radius-small); +} + +.has-radius-normal { + border-radius: var(--bulma-radius); +} + +.has-radius-large { + border-radius: var(--bulma-radius-large); +} + +.has-radius-rounded { + border-radius: var(--bulma-radius-rounded); +} + +.has-background { + background-color: var(--bulma-background); +} + +.has-text-white { + color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-l)) !important; +} + +.has-background-white { + background-color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-l)) !important; +} + +.has-text-white-invert { + color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-invert-l)) !important; +} + +.has-background-white-invert { + background-color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-invert-l)) !important; +} + +.has-text-white-on-scheme { + color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-on-scheme-l)) !important; +} + +.has-background-white-on-scheme { + background-color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-on-scheme-l)) !important; +} + +.has-text-white-light { + color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-light-l)) !important; +} + +.has-background-white-light { + background-color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-light-l)) !important; +} + +.has-text-white-light-invert { + color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-light-invert-l)) !important; +} + +.has-background-white-light-invert { + background-color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-light-invert-l)) !important; +} + +.has-text-white-dark { + color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-dark-l)) !important; +} + +.has-background-white-dark { + background-color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-dark-l)) !important; +} + +.has-text-white-dark-invert { + color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-dark-invert-l)) !important; +} + +.has-background-white-dark-invert { + background-color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-dark-invert-l)) !important; +} + +.has-text-white-soft { + color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-soft-l)) !important; +} + +.has-background-white-soft { + background-color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-soft-l)) !important; +} + +.has-text-white-bold { + color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-bold-l)) !important; +} + +.has-background-white-bold { + background-color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-bold-l)) !important; +} + +.has-text-white-soft-invert { + color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-soft-invert-l)) !important; +} + +.has-background-white-soft-invert { + background-color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-soft-invert-l)) !important; +} + +.has-text-white-bold-invert { + color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-bold-invert-l)) !important; +} + +.has-background-white-bold-invert { + background-color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-bold-invert-l)) !important; +} + +.has-text-white-00 { + color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-00-l)) !important; +} + +.has-background-white-00 { + background-color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-00-l)) !important; +} + +.has-text-white-00-invert { + color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-00-invert-l)) !important; +} + +.has-background-white-00-invert { + background-color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-00-invert-l)) !important; +} + +.has-text-white-05 { + color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-05-l)) !important; +} + +.has-background-white-05 { + background-color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-05-l)) !important; +} + +.has-text-white-05-invert { + color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-05-invert-l)) !important; +} + +.has-background-white-05-invert { + background-color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-05-invert-l)) !important; +} + +.has-text-white-10 { + color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-10-l)) !important; +} + +.has-background-white-10 { + background-color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-10-l)) !important; +} + +.has-text-white-10-invert { + color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-10-invert-l)) !important; +} + +.has-background-white-10-invert { + background-color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-10-invert-l)) !important; +} + +.has-text-white-15 { + color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-15-l)) !important; +} + +.has-background-white-15 { + background-color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-15-l)) !important; +} + +.has-text-white-15-invert { + color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-15-invert-l)) !important; +} + +.has-background-white-15-invert { + background-color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-15-invert-l)) !important; +} + +.has-text-white-20 { + color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-20-l)) !important; +} + +.has-background-white-20 { + background-color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-20-l)) !important; +} + +.has-text-white-20-invert { + color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-20-invert-l)) !important; +} + +.has-background-white-20-invert { + background-color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-20-invert-l)) !important; +} + +.has-text-white-25 { + color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-25-l)) !important; +} + +.has-background-white-25 { + background-color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-25-l)) !important; +} + +.has-text-white-25-invert { + color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-25-invert-l)) !important; +} + +.has-background-white-25-invert { + background-color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-25-invert-l)) !important; +} + +.has-text-white-30 { + color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-30-l)) !important; +} + +.has-background-white-30 { + background-color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-30-l)) !important; +} + +.has-text-white-30-invert { + color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-30-invert-l)) !important; +} + +.has-background-white-30-invert { + background-color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-30-invert-l)) !important; +} + +.has-text-white-35 { + color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-35-l)) !important; +} + +.has-background-white-35 { + background-color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-35-l)) !important; +} + +.has-text-white-35-invert { + color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-35-invert-l)) !important; +} + +.has-background-white-35-invert { + background-color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-35-invert-l)) !important; +} + +.has-text-white-40 { + color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-40-l)) !important; +} + +.has-background-white-40 { + background-color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-40-l)) !important; +} + +.has-text-white-40-invert { + color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-40-invert-l)) !important; +} + +.has-background-white-40-invert { + background-color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-40-invert-l)) !important; +} + +.has-text-white-45 { + color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-45-l)) !important; +} + +.has-background-white-45 { + background-color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-45-l)) !important; +} + +.has-text-white-45-invert { + color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-45-invert-l)) !important; +} + +.has-background-white-45-invert { + background-color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-45-invert-l)) !important; +} + +.has-text-white-50 { + color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-50-l)) !important; +} + +.has-background-white-50 { + background-color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-50-l)) !important; +} + +.has-text-white-50-invert { + color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-50-invert-l)) !important; +} + +.has-background-white-50-invert { + background-color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-50-invert-l)) !important; +} + +.has-text-white-55 { + color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-55-l)) !important; +} + +.has-background-white-55 { + background-color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-55-l)) !important; +} + +.has-text-white-55-invert { + color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-55-invert-l)) !important; +} + +.has-background-white-55-invert { + background-color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-55-invert-l)) !important; +} + +.has-text-white-60 { + color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-60-l)) !important; +} + +.has-background-white-60 { + background-color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-60-l)) !important; +} + +.has-text-white-60-invert { + color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-60-invert-l)) !important; +} + +.has-background-white-60-invert { + background-color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-60-invert-l)) !important; +} + +.has-text-white-65 { + color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-65-l)) !important; +} + +.has-background-white-65 { + background-color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-65-l)) !important; +} + +.has-text-white-65-invert { + color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-65-invert-l)) !important; +} + +.has-background-white-65-invert { + background-color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-65-invert-l)) !important; +} + +.has-text-white-70 { + color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-70-l)) !important; +} + +.has-background-white-70 { + background-color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-70-l)) !important; +} + +.has-text-white-70-invert { + color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-70-invert-l)) !important; +} + +.has-background-white-70-invert { + background-color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-70-invert-l)) !important; +} + +.has-text-white-75 { + color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-75-l)) !important; +} + +.has-background-white-75 { + background-color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-75-l)) !important; +} + +.has-text-white-75-invert { + color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-75-invert-l)) !important; +} + +.has-background-white-75-invert { + background-color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-75-invert-l)) !important; +} + +.has-text-white-80 { + color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-80-l)) !important; +} + +.has-background-white-80 { + background-color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-80-l)) !important; +} + +.has-text-white-80-invert { + color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-80-invert-l)) !important; +} + +.has-background-white-80-invert { + background-color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-80-invert-l)) !important; +} + +.has-text-white-85 { + color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-85-l)) !important; +} + +.has-background-white-85 { + background-color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-85-l)) !important; +} + +.has-text-white-85-invert { + color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-85-invert-l)) !important; +} + +.has-background-white-85-invert { + background-color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-85-invert-l)) !important; +} + +.has-text-white-90 { + color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-90-l)) !important; +} + +.has-background-white-90 { + background-color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-90-l)) !important; +} + +.has-text-white-90-invert { + color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-90-invert-l)) !important; +} + +.has-background-white-90-invert { + background-color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-90-invert-l)) !important; +} + +.has-text-white-95 { + color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-95-l)) !important; +} + +.has-background-white-95 { + background-color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-95-l)) !important; +} + +.has-text-white-95-invert { + color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-95-invert-l)) !important; +} + +.has-background-white-95-invert { + background-color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-95-invert-l)) !important; +} + +.has-text-white-100 { + color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-100-l)) !important; +} + +.has-background-white-100 { + background-color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-100-l)) !important; +} + +.has-text-white-100-invert { + color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-100-invert-l)) !important; +} + +.has-background-white-100-invert { + background-color: hsl(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-100-invert-l)) !important; +} + +a.has-text-white:hover, a.has-text-white:focus-visible, +button.has-text-white:hover, +button.has-text-white:focus-visible, +has-text-white.is-hoverable:hover, +has-text-white.is-hoverable:focus-visible { + color: hsl(var(--bulma-white-h), var(--bulma-white-s), calc(var(--bulma-white-l) + var(--bulma-hover-color-l-delta))) !important; +} +a.has-text-white:active, +button.has-text-white:active, +has-text-white.is-hoverable:active { + color: hsl(var(--bulma-white-h), var(--bulma-white-s), calc(var(--bulma-white-l) + var(--bulma-active-color-l-delta))) !important; +} + +a.has-background-white:hover, a.has-background-white:focus-visible, +button.has-background-white:hover, +button.has-background-white:focus-visible, +has-background-white.is-hoverable:hover, +has-background-white.is-hoverable:focus-visible { + background-color: hsl(var(--bulma-white-h), var(--bulma-white-s), calc(var(--bulma-white-l) + var(--bulma-hover-background-l-delta))) !important; +} +a.has-background-white:active, +button.has-background-white:active, +has-background-white.is-hoverable:active { + background-color: hsl(var(--bulma-white-h), var(--bulma-white-s), calc(var(--bulma-white-l) + var(--bulma-active-background-l-delta))) !important; +} + +.is-palette-white { + --h: var(--bulma-white-h); + --s: var(--bulma-white-s); + --l: var(--bulma-white-l); + --color: hsl(var(--h), var(--s), var(--l)); + --00-l: var(--bulma-white-00-l); + --color-00: hsl(var(--h), var(--s), var(--00-l)); + --05-l: var(--bulma-white-05-l); + --color-05: hsl(var(--h), var(--s), var(--05-l)); + --10-l: var(--bulma-white-10-l); + --color-10: hsl(var(--h), var(--s), var(--10-l)); + --15-l: var(--bulma-white-15-l); + --color-15: hsl(var(--h), var(--s), var(--15-l)); + --20-l: var(--bulma-white-20-l); + --color-20: hsl(var(--h), var(--s), var(--20-l)); + --25-l: var(--bulma-white-25-l); + --color-25: hsl(var(--h), var(--s), var(--25-l)); + --30-l: var(--bulma-white-30-l); + --color-30: hsl(var(--h), var(--s), var(--30-l)); + --35-l: var(--bulma-white-35-l); + --color-35: hsl(var(--h), var(--s), var(--35-l)); + --40-l: var(--bulma-white-40-l); + --color-40: hsl(var(--h), var(--s), var(--40-l)); + --45-l: var(--bulma-white-45-l); + --color-45: hsl(var(--h), var(--s), var(--45-l)); + --50-l: var(--bulma-white-50-l); + --color-50: hsl(var(--h), var(--s), var(--50-l)); + --55-l: var(--bulma-white-55-l); + --color-55: hsl(var(--h), var(--s), var(--55-l)); + --60-l: var(--bulma-white-60-l); + --color-60: hsl(var(--h), var(--s), var(--60-l)); + --65-l: var(--bulma-white-65-l); + --color-65: hsl(var(--h), var(--s), var(--65-l)); + --70-l: var(--bulma-white-70-l); + --color-70: hsl(var(--h), var(--s), var(--70-l)); + --75-l: var(--bulma-white-75-l); + --color-75: hsl(var(--h), var(--s), var(--75-l)); + --80-l: var(--bulma-white-80-l); + --color-80: hsl(var(--h), var(--s), var(--80-l)); + --85-l: var(--bulma-white-85-l); + --color-85: hsl(var(--h), var(--s), var(--85-l)); + --90-l: var(--bulma-white-90-l); + --color-90: hsl(var(--h), var(--s), var(--90-l)); + --95-l: var(--bulma-white-95-l); + --color-95: hsl(var(--h), var(--s), var(--95-l)); + --100-l: var(--bulma-white-100-l); + --color-100: hsl(var(--h), var(--s), var(--100-l)); +} + +.has-text-black { + color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-l)) !important; +} + +.has-background-black { + background-color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-l)) !important; +} + +.has-text-black-invert { + color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-invert-l)) !important; +} + +.has-background-black-invert { + background-color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-invert-l)) !important; +} + +.has-text-black-on-scheme { + color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-on-scheme-l)) !important; +} + +.has-background-black-on-scheme { + background-color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-on-scheme-l)) !important; +} + +.has-text-black-light { + color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-light-l)) !important; +} + +.has-background-black-light { + background-color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-light-l)) !important; +} + +.has-text-black-light-invert { + color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-light-invert-l)) !important; +} + +.has-background-black-light-invert { + background-color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-light-invert-l)) !important; +} + +.has-text-black-dark { + color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-dark-l)) !important; +} + +.has-background-black-dark { + background-color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-dark-l)) !important; +} + +.has-text-black-dark-invert { + color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-dark-invert-l)) !important; +} + +.has-background-black-dark-invert { + background-color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-dark-invert-l)) !important; +} + +.has-text-black-soft { + color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-soft-l)) !important; +} + +.has-background-black-soft { + background-color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-soft-l)) !important; +} + +.has-text-black-bold { + color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-bold-l)) !important; +} + +.has-background-black-bold { + background-color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-bold-l)) !important; +} + +.has-text-black-soft-invert { + color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-soft-invert-l)) !important; +} + +.has-background-black-soft-invert { + background-color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-soft-invert-l)) !important; +} + +.has-text-black-bold-invert { + color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-bold-invert-l)) !important; +} + +.has-background-black-bold-invert { + background-color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-bold-invert-l)) !important; +} + +.has-text-black-00 { + color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-00-l)) !important; +} + +.has-background-black-00 { + background-color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-00-l)) !important; +} + +.has-text-black-00-invert { + color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-00-invert-l)) !important; +} + +.has-background-black-00-invert { + background-color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-00-invert-l)) !important; +} + +.has-text-black-05 { + color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-05-l)) !important; +} + +.has-background-black-05 { + background-color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-05-l)) !important; +} + +.has-text-black-05-invert { + color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-05-invert-l)) !important; +} + +.has-background-black-05-invert { + background-color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-05-invert-l)) !important; +} + +.has-text-black-10 { + color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-10-l)) !important; +} + +.has-background-black-10 { + background-color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-10-l)) !important; +} + +.has-text-black-10-invert { + color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-10-invert-l)) !important; +} + +.has-background-black-10-invert { + background-color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-10-invert-l)) !important; +} + +.has-text-black-15 { + color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-15-l)) !important; +} + +.has-background-black-15 { + background-color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-15-l)) !important; +} + +.has-text-black-15-invert { + color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-15-invert-l)) !important; +} + +.has-background-black-15-invert { + background-color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-15-invert-l)) !important; +} + +.has-text-black-20 { + color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-20-l)) !important; +} + +.has-background-black-20 { + background-color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-20-l)) !important; +} + +.has-text-black-20-invert { + color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-20-invert-l)) !important; +} + +.has-background-black-20-invert { + background-color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-20-invert-l)) !important; +} + +.has-text-black-25 { + color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-25-l)) !important; +} + +.has-background-black-25 { + background-color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-25-l)) !important; +} + +.has-text-black-25-invert { + color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-25-invert-l)) !important; +} + +.has-background-black-25-invert { + background-color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-25-invert-l)) !important; +} + +.has-text-black-30 { + color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-30-l)) !important; +} + +.has-background-black-30 { + background-color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-30-l)) !important; +} + +.has-text-black-30-invert { + color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-30-invert-l)) !important; +} + +.has-background-black-30-invert { + background-color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-30-invert-l)) !important; +} + +.has-text-black-35 { + color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-35-l)) !important; +} + +.has-background-black-35 { + background-color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-35-l)) !important; +} + +.has-text-black-35-invert { + color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-35-invert-l)) !important; +} + +.has-background-black-35-invert { + background-color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-35-invert-l)) !important; +} + +.has-text-black-40 { + color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-40-l)) !important; +} + +.has-background-black-40 { + background-color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-40-l)) !important; +} + +.has-text-black-40-invert { + color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-40-invert-l)) !important; +} + +.has-background-black-40-invert { + background-color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-40-invert-l)) !important; +} + +.has-text-black-45 { + color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-45-l)) !important; +} + +.has-background-black-45 { + background-color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-45-l)) !important; +} + +.has-text-black-45-invert { + color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-45-invert-l)) !important; +} + +.has-background-black-45-invert { + background-color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-45-invert-l)) !important; +} + +.has-text-black-50 { + color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-50-l)) !important; +} + +.has-background-black-50 { + background-color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-50-l)) !important; +} + +.has-text-black-50-invert { + color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-50-invert-l)) !important; +} + +.has-background-black-50-invert { + background-color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-50-invert-l)) !important; +} + +.has-text-black-55 { + color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-55-l)) !important; +} + +.has-background-black-55 { + background-color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-55-l)) !important; +} + +.has-text-black-55-invert { + color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-55-invert-l)) !important; +} + +.has-background-black-55-invert { + background-color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-55-invert-l)) !important; +} + +.has-text-black-60 { + color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-60-l)) !important; +} + +.has-background-black-60 { + background-color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-60-l)) !important; +} + +.has-text-black-60-invert { + color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-60-invert-l)) !important; +} + +.has-background-black-60-invert { + background-color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-60-invert-l)) !important; +} + +.has-text-black-65 { + color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-65-l)) !important; +} + +.has-background-black-65 { + background-color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-65-l)) !important; +} + +.has-text-black-65-invert { + color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-65-invert-l)) !important; +} + +.has-background-black-65-invert { + background-color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-65-invert-l)) !important; +} + +.has-text-black-70 { + color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-70-l)) !important; +} + +.has-background-black-70 { + background-color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-70-l)) !important; +} + +.has-text-black-70-invert { + color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-70-invert-l)) !important; +} + +.has-background-black-70-invert { + background-color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-70-invert-l)) !important; +} + +.has-text-black-75 { + color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-75-l)) !important; +} + +.has-background-black-75 { + background-color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-75-l)) !important; +} + +.has-text-black-75-invert { + color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-75-invert-l)) !important; +} + +.has-background-black-75-invert { + background-color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-75-invert-l)) !important; +} + +.has-text-black-80 { + color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-80-l)) !important; +} + +.has-background-black-80 { + background-color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-80-l)) !important; +} + +.has-text-black-80-invert { + color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-80-invert-l)) !important; +} + +.has-background-black-80-invert { + background-color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-80-invert-l)) !important; +} + +.has-text-black-85 { + color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-85-l)) !important; +} + +.has-background-black-85 { + background-color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-85-l)) !important; +} + +.has-text-black-85-invert { + color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-85-invert-l)) !important; +} + +.has-background-black-85-invert { + background-color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-85-invert-l)) !important; +} + +.has-text-black-90 { + color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-90-l)) !important; +} + +.has-background-black-90 { + background-color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-90-l)) !important; +} + +.has-text-black-90-invert { + color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-90-invert-l)) !important; +} + +.has-background-black-90-invert { + background-color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-90-invert-l)) !important; +} + +.has-text-black-95 { + color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-95-l)) !important; +} + +.has-background-black-95 { + background-color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-95-l)) !important; +} + +.has-text-black-95-invert { + color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-95-invert-l)) !important; +} + +.has-background-black-95-invert { + background-color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-95-invert-l)) !important; +} + +.has-text-black-100 { + color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-100-l)) !important; +} + +.has-background-black-100 { + background-color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-100-l)) !important; +} + +.has-text-black-100-invert { + color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-100-invert-l)) !important; +} + +.has-background-black-100-invert { + background-color: hsl(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-100-invert-l)) !important; +} + +a.has-text-black:hover, a.has-text-black:focus-visible, +button.has-text-black:hover, +button.has-text-black:focus-visible, +has-text-black.is-hoverable:hover, +has-text-black.is-hoverable:focus-visible { + color: hsl(var(--bulma-black-h), var(--bulma-black-s), calc(var(--bulma-black-l) + var(--bulma-hover-color-l-delta))) !important; +} +a.has-text-black:active, +button.has-text-black:active, +has-text-black.is-hoverable:active { + color: hsl(var(--bulma-black-h), var(--bulma-black-s), calc(var(--bulma-black-l) + var(--bulma-active-color-l-delta))) !important; +} + +a.has-background-black:hover, a.has-background-black:focus-visible, +button.has-background-black:hover, +button.has-background-black:focus-visible, +has-background-black.is-hoverable:hover, +has-background-black.is-hoverable:focus-visible { + background-color: hsl(var(--bulma-black-h), var(--bulma-black-s), calc(var(--bulma-black-l) + var(--bulma-hover-background-l-delta))) !important; +} +a.has-background-black:active, +button.has-background-black:active, +has-background-black.is-hoverable:active { + background-color: hsl(var(--bulma-black-h), var(--bulma-black-s), calc(var(--bulma-black-l) + var(--bulma-active-background-l-delta))) !important; +} + +.is-palette-black { + --h: var(--bulma-black-h); + --s: var(--bulma-black-s); + --l: var(--bulma-black-l); + --color: hsl(var(--h), var(--s), var(--l)); + --00-l: var(--bulma-black-00-l); + --color-00: hsl(var(--h), var(--s), var(--00-l)); + --05-l: var(--bulma-black-05-l); + --color-05: hsl(var(--h), var(--s), var(--05-l)); + --10-l: var(--bulma-black-10-l); + --color-10: hsl(var(--h), var(--s), var(--10-l)); + --15-l: var(--bulma-black-15-l); + --color-15: hsl(var(--h), var(--s), var(--15-l)); + --20-l: var(--bulma-black-20-l); + --color-20: hsl(var(--h), var(--s), var(--20-l)); + --25-l: var(--bulma-black-25-l); + --color-25: hsl(var(--h), var(--s), var(--25-l)); + --30-l: var(--bulma-black-30-l); + --color-30: hsl(var(--h), var(--s), var(--30-l)); + --35-l: var(--bulma-black-35-l); + --color-35: hsl(var(--h), var(--s), var(--35-l)); + --40-l: var(--bulma-black-40-l); + --color-40: hsl(var(--h), var(--s), var(--40-l)); + --45-l: var(--bulma-black-45-l); + --color-45: hsl(var(--h), var(--s), var(--45-l)); + --50-l: var(--bulma-black-50-l); + --color-50: hsl(var(--h), var(--s), var(--50-l)); + --55-l: var(--bulma-black-55-l); + --color-55: hsl(var(--h), var(--s), var(--55-l)); + --60-l: var(--bulma-black-60-l); + --color-60: hsl(var(--h), var(--s), var(--60-l)); + --65-l: var(--bulma-black-65-l); + --color-65: hsl(var(--h), var(--s), var(--65-l)); + --70-l: var(--bulma-black-70-l); + --color-70: hsl(var(--h), var(--s), var(--70-l)); + --75-l: var(--bulma-black-75-l); + --color-75: hsl(var(--h), var(--s), var(--75-l)); + --80-l: var(--bulma-black-80-l); + --color-80: hsl(var(--h), var(--s), var(--80-l)); + --85-l: var(--bulma-black-85-l); + --color-85: hsl(var(--h), var(--s), var(--85-l)); + --90-l: var(--bulma-black-90-l); + --color-90: hsl(var(--h), var(--s), var(--90-l)); + --95-l: var(--bulma-black-95-l); + --color-95: hsl(var(--h), var(--s), var(--95-l)); + --100-l: var(--bulma-black-100-l); + --color-100: hsl(var(--h), var(--s), var(--100-l)); +} + +.has-text-light { + color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-l)) !important; +} + +.has-background-light { + background-color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-l)) !important; +} + +.has-text-light-invert { + color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-invert-l)) !important; +} + +.has-background-light-invert { + background-color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-invert-l)) !important; +} + +.has-text-light-on-scheme { + color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-on-scheme-l)) !important; +} + +.has-background-light-on-scheme { + background-color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-on-scheme-l)) !important; +} + +.has-text-light-light { + color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-light-l)) !important; +} + +.has-background-light-light { + background-color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-light-l)) !important; +} + +.has-text-light-light-invert { + color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-light-invert-l)) !important; +} + +.has-background-light-light-invert { + background-color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-light-invert-l)) !important; +} + +.has-text-light-dark { + color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-dark-l)) !important; +} + +.has-background-light-dark { + background-color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-dark-l)) !important; +} + +.has-text-light-dark-invert { + color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-dark-invert-l)) !important; +} + +.has-background-light-dark-invert { + background-color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-dark-invert-l)) !important; +} + +.has-text-light-soft { + color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-soft-l)) !important; +} + +.has-background-light-soft { + background-color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-soft-l)) !important; +} + +.has-text-light-bold { + color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-bold-l)) !important; +} + +.has-background-light-bold { + background-color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-bold-l)) !important; +} + +.has-text-light-soft-invert { + color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-soft-invert-l)) !important; +} + +.has-background-light-soft-invert { + background-color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-soft-invert-l)) !important; +} + +.has-text-light-bold-invert { + color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-bold-invert-l)) !important; +} + +.has-background-light-bold-invert { + background-color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-bold-invert-l)) !important; +} + +.has-text-light-00 { + color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-00-l)) !important; +} + +.has-background-light-00 { + background-color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-00-l)) !important; +} + +.has-text-light-00-invert { + color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-00-invert-l)) !important; +} + +.has-background-light-00-invert { + background-color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-00-invert-l)) !important; +} + +.has-text-light-05 { + color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-05-l)) !important; +} + +.has-background-light-05 { + background-color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-05-l)) !important; +} + +.has-text-light-05-invert { + color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-05-invert-l)) !important; +} + +.has-background-light-05-invert { + background-color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-05-invert-l)) !important; +} + +.has-text-light-10 { + color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-10-l)) !important; +} + +.has-background-light-10 { + background-color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-10-l)) !important; +} + +.has-text-light-10-invert { + color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-10-invert-l)) !important; +} + +.has-background-light-10-invert { + background-color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-10-invert-l)) !important; +} + +.has-text-light-15 { + color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-15-l)) !important; +} + +.has-background-light-15 { + background-color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-15-l)) !important; +} + +.has-text-light-15-invert { + color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-15-invert-l)) !important; +} + +.has-background-light-15-invert { + background-color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-15-invert-l)) !important; +} + +.has-text-light-20 { + color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-20-l)) !important; +} + +.has-background-light-20 { + background-color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-20-l)) !important; +} + +.has-text-light-20-invert { + color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-20-invert-l)) !important; +} + +.has-background-light-20-invert { + background-color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-20-invert-l)) !important; +} + +.has-text-light-25 { + color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-25-l)) !important; +} + +.has-background-light-25 { + background-color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-25-l)) !important; +} + +.has-text-light-25-invert { + color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-25-invert-l)) !important; +} + +.has-background-light-25-invert { + background-color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-25-invert-l)) !important; +} + +.has-text-light-30 { + color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-30-l)) !important; +} + +.has-background-light-30 { + background-color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-30-l)) !important; +} + +.has-text-light-30-invert { + color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-30-invert-l)) !important; +} + +.has-background-light-30-invert { + background-color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-30-invert-l)) !important; +} + +.has-text-light-35 { + color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-35-l)) !important; +} + +.has-background-light-35 { + background-color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-35-l)) !important; +} + +.has-text-light-35-invert { + color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-35-invert-l)) !important; +} + +.has-background-light-35-invert { + background-color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-35-invert-l)) !important; +} + +.has-text-light-40 { + color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-40-l)) !important; +} + +.has-background-light-40 { + background-color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-40-l)) !important; +} + +.has-text-light-40-invert { + color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-40-invert-l)) !important; +} + +.has-background-light-40-invert { + background-color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-40-invert-l)) !important; +} + +.has-text-light-45 { + color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-45-l)) !important; +} + +.has-background-light-45 { + background-color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-45-l)) !important; +} + +.has-text-light-45-invert { + color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-45-invert-l)) !important; +} + +.has-background-light-45-invert { + background-color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-45-invert-l)) !important; +} + +.has-text-light-50 { + color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-50-l)) !important; +} + +.has-background-light-50 { + background-color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-50-l)) !important; +} + +.has-text-light-50-invert { + color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-50-invert-l)) !important; +} + +.has-background-light-50-invert { + background-color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-50-invert-l)) !important; +} + +.has-text-light-55 { + color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-55-l)) !important; +} + +.has-background-light-55 { + background-color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-55-l)) !important; +} + +.has-text-light-55-invert { + color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-55-invert-l)) !important; +} + +.has-background-light-55-invert { + background-color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-55-invert-l)) !important; +} + +.has-text-light-60 { + color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-60-l)) !important; +} + +.has-background-light-60 { + background-color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-60-l)) !important; +} + +.has-text-light-60-invert { + color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-60-invert-l)) !important; +} + +.has-background-light-60-invert { + background-color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-60-invert-l)) !important; +} + +.has-text-light-65 { + color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-65-l)) !important; +} + +.has-background-light-65 { + background-color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-65-l)) !important; +} + +.has-text-light-65-invert { + color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-65-invert-l)) !important; +} + +.has-background-light-65-invert { + background-color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-65-invert-l)) !important; +} + +.has-text-light-70 { + color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-70-l)) !important; +} + +.has-background-light-70 { + background-color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-70-l)) !important; +} + +.has-text-light-70-invert { + color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-70-invert-l)) !important; +} + +.has-background-light-70-invert { + background-color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-70-invert-l)) !important; +} + +.has-text-light-75 { + color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-75-l)) !important; +} + +.has-background-light-75 { + background-color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-75-l)) !important; +} + +.has-text-light-75-invert { + color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-75-invert-l)) !important; +} + +.has-background-light-75-invert { + background-color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-75-invert-l)) !important; +} + +.has-text-light-80 { + color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-80-l)) !important; +} + +.has-background-light-80 { + background-color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-80-l)) !important; +} + +.has-text-light-80-invert { + color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-80-invert-l)) !important; +} + +.has-background-light-80-invert { + background-color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-80-invert-l)) !important; +} + +.has-text-light-85 { + color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-85-l)) !important; +} + +.has-background-light-85 { + background-color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-85-l)) !important; +} + +.has-text-light-85-invert { + color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-85-invert-l)) !important; +} + +.has-background-light-85-invert { + background-color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-85-invert-l)) !important; +} + +.has-text-light-90 { + color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-90-l)) !important; +} + +.has-background-light-90 { + background-color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-90-l)) !important; +} + +.has-text-light-90-invert { + color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-90-invert-l)) !important; +} + +.has-background-light-90-invert { + background-color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-90-invert-l)) !important; +} + +.has-text-light-95 { + color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-95-l)) !important; +} + +.has-background-light-95 { + background-color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-95-l)) !important; +} + +.has-text-light-95-invert { + color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-95-invert-l)) !important; +} + +.has-background-light-95-invert { + background-color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-95-invert-l)) !important; +} + +.has-text-light-100 { + color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-100-l)) !important; +} + +.has-background-light-100 { + background-color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-100-l)) !important; +} + +.has-text-light-100-invert { + color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-100-invert-l)) !important; +} + +.has-background-light-100-invert { + background-color: hsl(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-100-invert-l)) !important; +} + +a.has-text-light:hover, a.has-text-light:focus-visible, +button.has-text-light:hover, +button.has-text-light:focus-visible, +has-text-light.is-hoverable:hover, +has-text-light.is-hoverable:focus-visible { + color: hsl(var(--bulma-light-h), var(--bulma-light-s), calc(var(--bulma-light-l) + var(--bulma-hover-color-l-delta))) !important; +} +a.has-text-light:active, +button.has-text-light:active, +has-text-light.is-hoverable:active { + color: hsl(var(--bulma-light-h), var(--bulma-light-s), calc(var(--bulma-light-l) + var(--bulma-active-color-l-delta))) !important; +} + +a.has-background-light:hover, a.has-background-light:focus-visible, +button.has-background-light:hover, +button.has-background-light:focus-visible, +has-background-light.is-hoverable:hover, +has-background-light.is-hoverable:focus-visible { + background-color: hsl(var(--bulma-light-h), var(--bulma-light-s), calc(var(--bulma-light-l) + var(--bulma-hover-background-l-delta))) !important; +} +a.has-background-light:active, +button.has-background-light:active, +has-background-light.is-hoverable:active { + background-color: hsl(var(--bulma-light-h), var(--bulma-light-s), calc(var(--bulma-light-l) + var(--bulma-active-background-l-delta))) !important; +} + +.is-palette-light { + --h: var(--bulma-light-h); + --s: var(--bulma-light-s); + --l: var(--bulma-light-l); + --color: hsl(var(--h), var(--s), var(--l)); + --00-l: var(--bulma-light-00-l); + --color-00: hsl(var(--h), var(--s), var(--00-l)); + --05-l: var(--bulma-light-05-l); + --color-05: hsl(var(--h), var(--s), var(--05-l)); + --10-l: var(--bulma-light-10-l); + --color-10: hsl(var(--h), var(--s), var(--10-l)); + --15-l: var(--bulma-light-15-l); + --color-15: hsl(var(--h), var(--s), var(--15-l)); + --20-l: var(--bulma-light-20-l); + --color-20: hsl(var(--h), var(--s), var(--20-l)); + --25-l: var(--bulma-light-25-l); + --color-25: hsl(var(--h), var(--s), var(--25-l)); + --30-l: var(--bulma-light-30-l); + --color-30: hsl(var(--h), var(--s), var(--30-l)); + --35-l: var(--bulma-light-35-l); + --color-35: hsl(var(--h), var(--s), var(--35-l)); + --40-l: var(--bulma-light-40-l); + --color-40: hsl(var(--h), var(--s), var(--40-l)); + --45-l: var(--bulma-light-45-l); + --color-45: hsl(var(--h), var(--s), var(--45-l)); + --50-l: var(--bulma-light-50-l); + --color-50: hsl(var(--h), var(--s), var(--50-l)); + --55-l: var(--bulma-light-55-l); + --color-55: hsl(var(--h), var(--s), var(--55-l)); + --60-l: var(--bulma-light-60-l); + --color-60: hsl(var(--h), var(--s), var(--60-l)); + --65-l: var(--bulma-light-65-l); + --color-65: hsl(var(--h), var(--s), var(--65-l)); + --70-l: var(--bulma-light-70-l); + --color-70: hsl(var(--h), var(--s), var(--70-l)); + --75-l: var(--bulma-light-75-l); + --color-75: hsl(var(--h), var(--s), var(--75-l)); + --80-l: var(--bulma-light-80-l); + --color-80: hsl(var(--h), var(--s), var(--80-l)); + --85-l: var(--bulma-light-85-l); + --color-85: hsl(var(--h), var(--s), var(--85-l)); + --90-l: var(--bulma-light-90-l); + --color-90: hsl(var(--h), var(--s), var(--90-l)); + --95-l: var(--bulma-light-95-l); + --color-95: hsl(var(--h), var(--s), var(--95-l)); + --100-l: var(--bulma-light-100-l); + --color-100: hsl(var(--h), var(--s), var(--100-l)); +} + +.has-text-dark { + color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-l)) !important; +} + +.has-background-dark { + background-color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-l)) !important; +} + +.has-text-dark-invert { + color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-invert-l)) !important; +} + +.has-background-dark-invert { + background-color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-invert-l)) !important; +} + +.has-text-dark-on-scheme { + color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-on-scheme-l)) !important; +} + +.has-background-dark-on-scheme { + background-color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-on-scheme-l)) !important; +} + +.has-text-dark-light { + color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-light-l)) !important; +} + +.has-background-dark-light { + background-color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-light-l)) !important; +} + +.has-text-dark-light-invert { + color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-light-invert-l)) !important; +} + +.has-background-dark-light-invert { + background-color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-light-invert-l)) !important; +} + +.has-text-dark-dark { + color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-dark-l)) !important; +} + +.has-background-dark-dark { + background-color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-dark-l)) !important; +} + +.has-text-dark-dark-invert { + color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-dark-invert-l)) !important; +} + +.has-background-dark-dark-invert { + background-color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-dark-invert-l)) !important; +} + +.has-text-dark-soft { + color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-soft-l)) !important; +} + +.has-background-dark-soft { + background-color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-soft-l)) !important; +} + +.has-text-dark-bold { + color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-bold-l)) !important; +} + +.has-background-dark-bold { + background-color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-bold-l)) !important; +} + +.has-text-dark-soft-invert { + color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-soft-invert-l)) !important; +} + +.has-background-dark-soft-invert { + background-color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-soft-invert-l)) !important; +} + +.has-text-dark-bold-invert { + color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-bold-invert-l)) !important; +} + +.has-background-dark-bold-invert { + background-color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-bold-invert-l)) !important; +} + +.has-text-dark-00 { + color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-00-l)) !important; +} + +.has-background-dark-00 { + background-color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-00-l)) !important; +} + +.has-text-dark-00-invert { + color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-00-invert-l)) !important; +} + +.has-background-dark-00-invert { + background-color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-00-invert-l)) !important; +} + +.has-text-dark-05 { + color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-05-l)) !important; +} + +.has-background-dark-05 { + background-color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-05-l)) !important; +} + +.has-text-dark-05-invert { + color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-05-invert-l)) !important; +} + +.has-background-dark-05-invert { + background-color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-05-invert-l)) !important; +} + +.has-text-dark-10 { + color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-10-l)) !important; +} + +.has-background-dark-10 { + background-color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-10-l)) !important; +} + +.has-text-dark-10-invert { + color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-10-invert-l)) !important; +} + +.has-background-dark-10-invert { + background-color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-10-invert-l)) !important; +} + +.has-text-dark-15 { + color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-15-l)) !important; +} + +.has-background-dark-15 { + background-color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-15-l)) !important; +} + +.has-text-dark-15-invert { + color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-15-invert-l)) !important; +} + +.has-background-dark-15-invert { + background-color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-15-invert-l)) !important; +} + +.has-text-dark-20 { + color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-20-l)) !important; +} + +.has-background-dark-20 { + background-color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-20-l)) !important; +} + +.has-text-dark-20-invert { + color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-20-invert-l)) !important; +} + +.has-background-dark-20-invert { + background-color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-20-invert-l)) !important; +} + +.has-text-dark-25 { + color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-25-l)) !important; +} + +.has-background-dark-25 { + background-color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-25-l)) !important; +} + +.has-text-dark-25-invert { + color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-25-invert-l)) !important; +} + +.has-background-dark-25-invert { + background-color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-25-invert-l)) !important; +} + +.has-text-dark-30 { + color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-30-l)) !important; +} + +.has-background-dark-30 { + background-color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-30-l)) !important; +} + +.has-text-dark-30-invert { + color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-30-invert-l)) !important; +} + +.has-background-dark-30-invert { + background-color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-30-invert-l)) !important; +} + +.has-text-dark-35 { + color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-35-l)) !important; +} + +.has-background-dark-35 { + background-color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-35-l)) !important; +} + +.has-text-dark-35-invert { + color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-35-invert-l)) !important; +} + +.has-background-dark-35-invert { + background-color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-35-invert-l)) !important; +} + +.has-text-dark-40 { + color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-40-l)) !important; +} + +.has-background-dark-40 { + background-color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-40-l)) !important; +} + +.has-text-dark-40-invert { + color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-40-invert-l)) !important; +} + +.has-background-dark-40-invert { + background-color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-40-invert-l)) !important; +} + +.has-text-dark-45 { + color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-45-l)) !important; +} + +.has-background-dark-45 { + background-color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-45-l)) !important; +} + +.has-text-dark-45-invert { + color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-45-invert-l)) !important; +} + +.has-background-dark-45-invert { + background-color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-45-invert-l)) !important; +} + +.has-text-dark-50 { + color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-50-l)) !important; +} + +.has-background-dark-50 { + background-color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-50-l)) !important; +} + +.has-text-dark-50-invert { + color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-50-invert-l)) !important; +} + +.has-background-dark-50-invert { + background-color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-50-invert-l)) !important; +} + +.has-text-dark-55 { + color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-55-l)) !important; +} + +.has-background-dark-55 { + background-color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-55-l)) !important; +} + +.has-text-dark-55-invert { + color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-55-invert-l)) !important; +} + +.has-background-dark-55-invert { + background-color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-55-invert-l)) !important; +} + +.has-text-dark-60 { + color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-60-l)) !important; +} + +.has-background-dark-60 { + background-color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-60-l)) !important; +} + +.has-text-dark-60-invert { + color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-60-invert-l)) !important; +} + +.has-background-dark-60-invert { + background-color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-60-invert-l)) !important; +} + +.has-text-dark-65 { + color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-65-l)) !important; +} + +.has-background-dark-65 { + background-color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-65-l)) !important; +} + +.has-text-dark-65-invert { + color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-65-invert-l)) !important; +} + +.has-background-dark-65-invert { + background-color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-65-invert-l)) !important; +} + +.has-text-dark-70 { + color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-70-l)) !important; +} + +.has-background-dark-70 { + background-color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-70-l)) !important; +} + +.has-text-dark-70-invert { + color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-70-invert-l)) !important; +} + +.has-background-dark-70-invert { + background-color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-70-invert-l)) !important; +} + +.has-text-dark-75 { + color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-75-l)) !important; +} + +.has-background-dark-75 { + background-color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-75-l)) !important; +} + +.has-text-dark-75-invert { + color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-75-invert-l)) !important; +} + +.has-background-dark-75-invert { + background-color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-75-invert-l)) !important; +} + +.has-text-dark-80 { + color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-80-l)) !important; +} + +.has-background-dark-80 { + background-color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-80-l)) !important; +} + +.has-text-dark-80-invert { + color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-80-invert-l)) !important; +} + +.has-background-dark-80-invert { + background-color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-80-invert-l)) !important; +} + +.has-text-dark-85 { + color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-85-l)) !important; +} + +.has-background-dark-85 { + background-color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-85-l)) !important; +} + +.has-text-dark-85-invert { + color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-85-invert-l)) !important; +} + +.has-background-dark-85-invert { + background-color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-85-invert-l)) !important; +} + +.has-text-dark-90 { + color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-90-l)) !important; +} + +.has-background-dark-90 { + background-color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-90-l)) !important; +} + +.has-text-dark-90-invert { + color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-90-invert-l)) !important; +} + +.has-background-dark-90-invert { + background-color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-90-invert-l)) !important; +} + +.has-text-dark-95 { + color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-95-l)) !important; +} + +.has-background-dark-95 { + background-color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-95-l)) !important; +} + +.has-text-dark-95-invert { + color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-95-invert-l)) !important; +} + +.has-background-dark-95-invert { + background-color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-95-invert-l)) !important; +} + +.has-text-dark-100 { + color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-100-l)) !important; +} + +.has-background-dark-100 { + background-color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-100-l)) !important; +} + +.has-text-dark-100-invert { + color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-100-invert-l)) !important; +} + +.has-background-dark-100-invert { + background-color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-100-invert-l)) !important; +} + +a.has-text-dark:hover, a.has-text-dark:focus-visible, +button.has-text-dark:hover, +button.has-text-dark:focus-visible, +has-text-dark.is-hoverable:hover, +has-text-dark.is-hoverable:focus-visible { + color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), calc(var(--bulma-dark-l) + var(--bulma-hover-color-l-delta))) !important; +} +a.has-text-dark:active, +button.has-text-dark:active, +has-text-dark.is-hoverable:active { + color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), calc(var(--bulma-dark-l) + var(--bulma-active-color-l-delta))) !important; +} + +a.has-background-dark:hover, a.has-background-dark:focus-visible, +button.has-background-dark:hover, +button.has-background-dark:focus-visible, +has-background-dark.is-hoverable:hover, +has-background-dark.is-hoverable:focus-visible { + background-color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), calc(var(--bulma-dark-l) + var(--bulma-hover-background-l-delta))) !important; +} +a.has-background-dark:active, +button.has-background-dark:active, +has-background-dark.is-hoverable:active { + background-color: hsl(var(--bulma-dark-h), var(--bulma-dark-s), calc(var(--bulma-dark-l) + var(--bulma-active-background-l-delta))) !important; +} + +.is-palette-dark { + --h: var(--bulma-dark-h); + --s: var(--bulma-dark-s); + --l: var(--bulma-dark-l); + --color: hsl(var(--h), var(--s), var(--l)); + --00-l: var(--bulma-dark-00-l); + --color-00: hsl(var(--h), var(--s), var(--00-l)); + --05-l: var(--bulma-dark-05-l); + --color-05: hsl(var(--h), var(--s), var(--05-l)); + --10-l: var(--bulma-dark-10-l); + --color-10: hsl(var(--h), var(--s), var(--10-l)); + --15-l: var(--bulma-dark-15-l); + --color-15: hsl(var(--h), var(--s), var(--15-l)); + --20-l: var(--bulma-dark-20-l); + --color-20: hsl(var(--h), var(--s), var(--20-l)); + --25-l: var(--bulma-dark-25-l); + --color-25: hsl(var(--h), var(--s), var(--25-l)); + --30-l: var(--bulma-dark-30-l); + --color-30: hsl(var(--h), var(--s), var(--30-l)); + --35-l: var(--bulma-dark-35-l); + --color-35: hsl(var(--h), var(--s), var(--35-l)); + --40-l: var(--bulma-dark-40-l); + --color-40: hsl(var(--h), var(--s), var(--40-l)); + --45-l: var(--bulma-dark-45-l); + --color-45: hsl(var(--h), var(--s), var(--45-l)); + --50-l: var(--bulma-dark-50-l); + --color-50: hsl(var(--h), var(--s), var(--50-l)); + --55-l: var(--bulma-dark-55-l); + --color-55: hsl(var(--h), var(--s), var(--55-l)); + --60-l: var(--bulma-dark-60-l); + --color-60: hsl(var(--h), var(--s), var(--60-l)); + --65-l: var(--bulma-dark-65-l); + --color-65: hsl(var(--h), var(--s), var(--65-l)); + --70-l: var(--bulma-dark-70-l); + --color-70: hsl(var(--h), var(--s), var(--70-l)); + --75-l: var(--bulma-dark-75-l); + --color-75: hsl(var(--h), var(--s), var(--75-l)); + --80-l: var(--bulma-dark-80-l); + --color-80: hsl(var(--h), var(--s), var(--80-l)); + --85-l: var(--bulma-dark-85-l); + --color-85: hsl(var(--h), var(--s), var(--85-l)); + --90-l: var(--bulma-dark-90-l); + --color-90: hsl(var(--h), var(--s), var(--90-l)); + --95-l: var(--bulma-dark-95-l); + --color-95: hsl(var(--h), var(--s), var(--95-l)); + --100-l: var(--bulma-dark-100-l); + --color-100: hsl(var(--h), var(--s), var(--100-l)); +} + +.has-text-text { + color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-l)) !important; +} + +.has-background-text { + background-color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-l)) !important; +} + +.has-text-text-invert { + color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-invert-l)) !important; +} + +.has-background-text-invert { + background-color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-invert-l)) !important; +} + +.has-text-text-on-scheme { + color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-on-scheme-l)) !important; +} + +.has-background-text-on-scheme { + background-color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-on-scheme-l)) !important; +} + +.has-text-text-light { + color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-light-l)) !important; +} + +.has-background-text-light { + background-color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-light-l)) !important; +} + +.has-text-text-light-invert { + color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-light-invert-l)) !important; +} + +.has-background-text-light-invert { + background-color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-light-invert-l)) !important; +} + +.has-text-text-dark { + color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-dark-l)) !important; +} + +.has-background-text-dark { + background-color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-dark-l)) !important; +} + +.has-text-text-dark-invert { + color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-dark-invert-l)) !important; +} + +.has-background-text-dark-invert { + background-color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-dark-invert-l)) !important; +} + +.has-text-text-soft { + color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-soft-l)) !important; +} + +.has-background-text-soft { + background-color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-soft-l)) !important; +} + +.has-text-text-bold { + color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-bold-l)) !important; +} + +.has-background-text-bold { + background-color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-bold-l)) !important; +} + +.has-text-text-soft-invert { + color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-soft-invert-l)) !important; +} + +.has-background-text-soft-invert { + background-color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-soft-invert-l)) !important; +} + +.has-text-text-bold-invert { + color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-bold-invert-l)) !important; +} + +.has-background-text-bold-invert { + background-color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-bold-invert-l)) !important; +} + +.has-text-text-00 { + color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-00-l)) !important; +} + +.has-background-text-00 { + background-color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-00-l)) !important; +} + +.has-text-text-00-invert { + color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-00-invert-l)) !important; +} + +.has-background-text-00-invert { + background-color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-00-invert-l)) !important; +} + +.has-text-text-05 { + color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-05-l)) !important; +} + +.has-background-text-05 { + background-color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-05-l)) !important; +} + +.has-text-text-05-invert { + color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-05-invert-l)) !important; +} + +.has-background-text-05-invert { + background-color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-05-invert-l)) !important; +} + +.has-text-text-10 { + color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-10-l)) !important; +} + +.has-background-text-10 { + background-color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-10-l)) !important; +} + +.has-text-text-10-invert { + color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-10-invert-l)) !important; +} + +.has-background-text-10-invert { + background-color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-10-invert-l)) !important; +} + +.has-text-text-15 { + color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-15-l)) !important; +} + +.has-background-text-15 { + background-color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-15-l)) !important; +} + +.has-text-text-15-invert { + color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-15-invert-l)) !important; +} + +.has-background-text-15-invert { + background-color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-15-invert-l)) !important; +} + +.has-text-text-20 { + color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-20-l)) !important; +} + +.has-background-text-20 { + background-color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-20-l)) !important; +} + +.has-text-text-20-invert { + color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-20-invert-l)) !important; +} + +.has-background-text-20-invert { + background-color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-20-invert-l)) !important; +} + +.has-text-text-25 { + color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-25-l)) !important; +} + +.has-background-text-25 { + background-color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-25-l)) !important; +} + +.has-text-text-25-invert { + color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-25-invert-l)) !important; +} + +.has-background-text-25-invert { + background-color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-25-invert-l)) !important; +} + +.has-text-text-30 { + color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-30-l)) !important; +} + +.has-background-text-30 { + background-color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-30-l)) !important; +} + +.has-text-text-30-invert { + color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-30-invert-l)) !important; +} + +.has-background-text-30-invert { + background-color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-30-invert-l)) !important; +} + +.has-text-text-35 { + color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-35-l)) !important; +} + +.has-background-text-35 { + background-color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-35-l)) !important; +} + +.has-text-text-35-invert { + color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-35-invert-l)) !important; +} + +.has-background-text-35-invert { + background-color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-35-invert-l)) !important; +} + +.has-text-text-40 { + color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-40-l)) !important; +} + +.has-background-text-40 { + background-color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-40-l)) !important; +} + +.has-text-text-40-invert { + color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-40-invert-l)) !important; +} + +.has-background-text-40-invert { + background-color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-40-invert-l)) !important; +} + +.has-text-text-45 { + color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-45-l)) !important; +} + +.has-background-text-45 { + background-color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-45-l)) !important; +} + +.has-text-text-45-invert { + color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-45-invert-l)) !important; +} + +.has-background-text-45-invert { + background-color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-45-invert-l)) !important; +} + +.has-text-text-50 { + color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-50-l)) !important; +} + +.has-background-text-50 { + background-color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-50-l)) !important; +} + +.has-text-text-50-invert { + color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-50-invert-l)) !important; +} + +.has-background-text-50-invert { + background-color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-50-invert-l)) !important; +} + +.has-text-text-55 { + color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-55-l)) !important; +} + +.has-background-text-55 { + background-color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-55-l)) !important; +} + +.has-text-text-55-invert { + color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-55-invert-l)) !important; +} + +.has-background-text-55-invert { + background-color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-55-invert-l)) !important; +} + +.has-text-text-60 { + color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-60-l)) !important; +} + +.has-background-text-60 { + background-color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-60-l)) !important; +} + +.has-text-text-60-invert { + color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-60-invert-l)) !important; +} + +.has-background-text-60-invert { + background-color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-60-invert-l)) !important; +} + +.has-text-text-65 { + color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-65-l)) !important; +} + +.has-background-text-65 { + background-color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-65-l)) !important; +} + +.has-text-text-65-invert { + color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-65-invert-l)) !important; +} + +.has-background-text-65-invert { + background-color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-65-invert-l)) !important; +} + +.has-text-text-70 { + color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-70-l)) !important; +} + +.has-background-text-70 { + background-color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-70-l)) !important; +} + +.has-text-text-70-invert { + color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-70-invert-l)) !important; +} + +.has-background-text-70-invert { + background-color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-70-invert-l)) !important; +} + +.has-text-text-75 { + color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-75-l)) !important; +} + +.has-background-text-75 { + background-color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-75-l)) !important; +} + +.has-text-text-75-invert { + color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-75-invert-l)) !important; +} + +.has-background-text-75-invert { + background-color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-75-invert-l)) !important; +} + +.has-text-text-80 { + color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-80-l)) !important; +} + +.has-background-text-80 { + background-color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-80-l)) !important; +} + +.has-text-text-80-invert { + color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-80-invert-l)) !important; +} + +.has-background-text-80-invert { + background-color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-80-invert-l)) !important; +} + +.has-text-text-85 { + color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-85-l)) !important; +} + +.has-background-text-85 { + background-color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-85-l)) !important; +} + +.has-text-text-85-invert { + color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-85-invert-l)) !important; +} + +.has-background-text-85-invert { + background-color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-85-invert-l)) !important; +} + +.has-text-text-90 { + color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-90-l)) !important; +} + +.has-background-text-90 { + background-color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-90-l)) !important; +} + +.has-text-text-90-invert { + color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-90-invert-l)) !important; +} + +.has-background-text-90-invert { + background-color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-90-invert-l)) !important; +} + +.has-text-text-95 { + color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-95-l)) !important; +} + +.has-background-text-95 { + background-color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-95-l)) !important; +} + +.has-text-text-95-invert { + color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-95-invert-l)) !important; +} + +.has-background-text-95-invert { + background-color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-95-invert-l)) !important; +} + +.has-text-text-100 { + color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-100-l)) !important; +} + +.has-background-text-100 { + background-color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-100-l)) !important; +} + +.has-text-text-100-invert { + color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-100-invert-l)) !important; +} + +.has-background-text-100-invert { + background-color: hsl(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-100-invert-l)) !important; +} + +a.has-text-text:hover, a.has-text-text:focus-visible, +button.has-text-text:hover, +button.has-text-text:focus-visible, +has-text-text.is-hoverable:hover, +has-text-text.is-hoverable:focus-visible { + color: hsl(var(--bulma-text-h), var(--bulma-text-s), calc(var(--bulma-text-l) + var(--bulma-hover-color-l-delta))) !important; +} +a.has-text-text:active, +button.has-text-text:active, +has-text-text.is-hoverable:active { + color: hsl(var(--bulma-text-h), var(--bulma-text-s), calc(var(--bulma-text-l) + var(--bulma-active-color-l-delta))) !important; +} + +a.has-background-text:hover, a.has-background-text:focus-visible, +button.has-background-text:hover, +button.has-background-text:focus-visible, +has-background-text.is-hoverable:hover, +has-background-text.is-hoverable:focus-visible { + background-color: hsl(var(--bulma-text-h), var(--bulma-text-s), calc(var(--bulma-text-l) + var(--bulma-hover-background-l-delta))) !important; +} +a.has-background-text:active, +button.has-background-text:active, +has-background-text.is-hoverable:active { + background-color: hsl(var(--bulma-text-h), var(--bulma-text-s), calc(var(--bulma-text-l) + var(--bulma-active-background-l-delta))) !important; +} + +.is-palette-text { + --h: var(--bulma-text-h); + --s: var(--bulma-text-s); + --l: var(--bulma-text-l); + --color: hsl(var(--h), var(--s), var(--l)); + --00-l: var(--bulma-text-00-l); + --color-00: hsl(var(--h), var(--s), var(--00-l)); + --05-l: var(--bulma-text-05-l); + --color-05: hsl(var(--h), var(--s), var(--05-l)); + --10-l: var(--bulma-text-10-l); + --color-10: hsl(var(--h), var(--s), var(--10-l)); + --15-l: var(--bulma-text-15-l); + --color-15: hsl(var(--h), var(--s), var(--15-l)); + --20-l: var(--bulma-text-20-l); + --color-20: hsl(var(--h), var(--s), var(--20-l)); + --25-l: var(--bulma-text-25-l); + --color-25: hsl(var(--h), var(--s), var(--25-l)); + --30-l: var(--bulma-text-30-l); + --color-30: hsl(var(--h), var(--s), var(--30-l)); + --35-l: var(--bulma-text-35-l); + --color-35: hsl(var(--h), var(--s), var(--35-l)); + --40-l: var(--bulma-text-40-l); + --color-40: hsl(var(--h), var(--s), var(--40-l)); + --45-l: var(--bulma-text-45-l); + --color-45: hsl(var(--h), var(--s), var(--45-l)); + --50-l: var(--bulma-text-50-l); + --color-50: hsl(var(--h), var(--s), var(--50-l)); + --55-l: var(--bulma-text-55-l); + --color-55: hsl(var(--h), var(--s), var(--55-l)); + --60-l: var(--bulma-text-60-l); + --color-60: hsl(var(--h), var(--s), var(--60-l)); + --65-l: var(--bulma-text-65-l); + --color-65: hsl(var(--h), var(--s), var(--65-l)); + --70-l: var(--bulma-text-70-l); + --color-70: hsl(var(--h), var(--s), var(--70-l)); + --75-l: var(--bulma-text-75-l); + --color-75: hsl(var(--h), var(--s), var(--75-l)); + --80-l: var(--bulma-text-80-l); + --color-80: hsl(var(--h), var(--s), var(--80-l)); + --85-l: var(--bulma-text-85-l); + --color-85: hsl(var(--h), var(--s), var(--85-l)); + --90-l: var(--bulma-text-90-l); + --color-90: hsl(var(--h), var(--s), var(--90-l)); + --95-l: var(--bulma-text-95-l); + --color-95: hsl(var(--h), var(--s), var(--95-l)); + --100-l: var(--bulma-text-100-l); + --color-100: hsl(var(--h), var(--s), var(--100-l)); +} + +.has-text-primary { + color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-l)) !important; +} + +.has-background-primary { + background-color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-l)) !important; +} + +.has-text-primary-invert { + color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-invert-l)) !important; +} + +.has-background-primary-invert { + background-color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-invert-l)) !important; +} + +.has-text-primary-on-scheme { + color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-on-scheme-l)) !important; +} + +.has-background-primary-on-scheme { + background-color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-on-scheme-l)) !important; +} + +.has-text-primary-light { + color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-light-l)) !important; +} + +.has-background-primary-light { + background-color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-light-l)) !important; +} + +.has-text-primary-light-invert { + color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-light-invert-l)) !important; +} + +.has-background-primary-light-invert { + background-color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-light-invert-l)) !important; +} + +.has-text-primary-dark { + color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-dark-l)) !important; +} + +.has-background-primary-dark { + background-color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-dark-l)) !important; +} + +.has-text-primary-dark-invert { + color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-dark-invert-l)) !important; +} + +.has-background-primary-dark-invert { + background-color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-dark-invert-l)) !important; +} + +.has-text-primary-soft { + color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-soft-l)) !important; +} + +.has-background-primary-soft { + background-color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-soft-l)) !important; +} + +.has-text-primary-bold { + color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-bold-l)) !important; +} + +.has-background-primary-bold { + background-color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-bold-l)) !important; +} + +.has-text-primary-soft-invert { + color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-soft-invert-l)) !important; +} + +.has-background-primary-soft-invert { + background-color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-soft-invert-l)) !important; +} + +.has-text-primary-bold-invert { + color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-bold-invert-l)) !important; +} + +.has-background-primary-bold-invert { + background-color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-bold-invert-l)) !important; +} + +.has-text-primary-00 { + color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-00-l)) !important; +} + +.has-background-primary-00 { + background-color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-00-l)) !important; +} + +.has-text-primary-00-invert { + color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-00-invert-l)) !important; +} + +.has-background-primary-00-invert { + background-color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-00-invert-l)) !important; +} + +.has-text-primary-05 { + color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-05-l)) !important; +} + +.has-background-primary-05 { + background-color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-05-l)) !important; +} + +.has-text-primary-05-invert { + color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-05-invert-l)) !important; +} + +.has-background-primary-05-invert { + background-color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-05-invert-l)) !important; +} + +.has-text-primary-10 { + color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-10-l)) !important; +} + +.has-background-primary-10 { + background-color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-10-l)) !important; +} + +.has-text-primary-10-invert { + color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-10-invert-l)) !important; +} + +.has-background-primary-10-invert { + background-color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-10-invert-l)) !important; +} + +.has-text-primary-15 { + color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-15-l)) !important; +} + +.has-background-primary-15 { + background-color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-15-l)) !important; +} + +.has-text-primary-15-invert { + color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-15-invert-l)) !important; +} + +.has-background-primary-15-invert { + background-color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-15-invert-l)) !important; +} + +.has-text-primary-20 { + color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-20-l)) !important; +} + +.has-background-primary-20 { + background-color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-20-l)) !important; +} + +.has-text-primary-20-invert { + color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-20-invert-l)) !important; +} + +.has-background-primary-20-invert { + background-color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-20-invert-l)) !important; +} + +.has-text-primary-25 { + color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-25-l)) !important; +} + +.has-background-primary-25 { + background-color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-25-l)) !important; +} + +.has-text-primary-25-invert { + color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-25-invert-l)) !important; +} + +.has-background-primary-25-invert { + background-color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-25-invert-l)) !important; +} + +.has-text-primary-30 { + color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-30-l)) !important; +} + +.has-background-primary-30 { + background-color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-30-l)) !important; +} + +.has-text-primary-30-invert { + color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-30-invert-l)) !important; +} + +.has-background-primary-30-invert { + background-color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-30-invert-l)) !important; +} + +.has-text-primary-35 { + color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-35-l)) !important; +} + +.has-background-primary-35 { + background-color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-35-l)) !important; +} + +.has-text-primary-35-invert { + color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-35-invert-l)) !important; +} + +.has-background-primary-35-invert { + background-color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-35-invert-l)) !important; +} + +.has-text-primary-40 { + color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-40-l)) !important; +} + +.has-background-primary-40 { + background-color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-40-l)) !important; +} + +.has-text-primary-40-invert { + color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-40-invert-l)) !important; +} + +.has-background-primary-40-invert { + background-color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-40-invert-l)) !important; +} + +.has-text-primary-45 { + color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-45-l)) !important; +} + +.has-background-primary-45 { + background-color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-45-l)) !important; +} + +.has-text-primary-45-invert { + color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-45-invert-l)) !important; +} + +.has-background-primary-45-invert { + background-color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-45-invert-l)) !important; +} + +.has-text-primary-50 { + color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-50-l)) !important; +} + +.has-background-primary-50 { + background-color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-50-l)) !important; +} + +.has-text-primary-50-invert { + color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-50-invert-l)) !important; +} + +.has-background-primary-50-invert { + background-color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-50-invert-l)) !important; +} + +.has-text-primary-55 { + color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-55-l)) !important; +} + +.has-background-primary-55 { + background-color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-55-l)) !important; +} + +.has-text-primary-55-invert { + color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-55-invert-l)) !important; +} + +.has-background-primary-55-invert { + background-color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-55-invert-l)) !important; +} + +.has-text-primary-60 { + color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-60-l)) !important; +} + +.has-background-primary-60 { + background-color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-60-l)) !important; +} + +.has-text-primary-60-invert { + color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-60-invert-l)) !important; +} + +.has-background-primary-60-invert { + background-color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-60-invert-l)) !important; +} + +.has-text-primary-65 { + color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-65-l)) !important; +} + +.has-background-primary-65 { + background-color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-65-l)) !important; +} + +.has-text-primary-65-invert { + color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-65-invert-l)) !important; +} + +.has-background-primary-65-invert { + background-color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-65-invert-l)) !important; +} + +.has-text-primary-70 { + color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-70-l)) !important; +} + +.has-background-primary-70 { + background-color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-70-l)) !important; +} + +.has-text-primary-70-invert { + color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-70-invert-l)) !important; +} + +.has-background-primary-70-invert { + background-color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-70-invert-l)) !important; +} + +.has-text-primary-75 { + color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-75-l)) !important; +} + +.has-background-primary-75 { + background-color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-75-l)) !important; +} + +.has-text-primary-75-invert { + color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-75-invert-l)) !important; +} + +.has-background-primary-75-invert { + background-color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-75-invert-l)) !important; +} + +.has-text-primary-80 { + color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-80-l)) !important; +} + +.has-background-primary-80 { + background-color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-80-l)) !important; +} + +.has-text-primary-80-invert { + color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-80-invert-l)) !important; +} + +.has-background-primary-80-invert { + background-color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-80-invert-l)) !important; +} + +.has-text-primary-85 { + color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-85-l)) !important; +} + +.has-background-primary-85 { + background-color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-85-l)) !important; +} + +.has-text-primary-85-invert { + color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-85-invert-l)) !important; +} + +.has-background-primary-85-invert { + background-color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-85-invert-l)) !important; +} + +.has-text-primary-90 { + color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-90-l)) !important; +} + +.has-background-primary-90 { + background-color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-90-l)) !important; +} + +.has-text-primary-90-invert { + color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-90-invert-l)) !important; +} + +.has-background-primary-90-invert { + background-color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-90-invert-l)) !important; +} + +.has-text-primary-95 { + color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-95-l)) !important; +} + +.has-background-primary-95 { + background-color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-95-l)) !important; +} + +.has-text-primary-95-invert { + color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-95-invert-l)) !important; +} + +.has-background-primary-95-invert { + background-color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-95-invert-l)) !important; +} + +.has-text-primary-100 { + color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-100-l)) !important; +} + +.has-background-primary-100 { + background-color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-100-l)) !important; +} + +.has-text-primary-100-invert { + color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-100-invert-l)) !important; +} + +.has-background-primary-100-invert { + background-color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), var(--bulma-primary-100-invert-l)) !important; +} + +a.has-text-primary:hover, a.has-text-primary:focus-visible, +button.has-text-primary:hover, +button.has-text-primary:focus-visible, +has-text-primary.is-hoverable:hover, +has-text-primary.is-hoverable:focus-visible { + color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), calc(var(--bulma-primary-l) + var(--bulma-hover-color-l-delta))) !important; +} +a.has-text-primary:active, +button.has-text-primary:active, +has-text-primary.is-hoverable:active { + color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), calc(var(--bulma-primary-l) + var(--bulma-active-color-l-delta))) !important; +} + +a.has-background-primary:hover, a.has-background-primary:focus-visible, +button.has-background-primary:hover, +button.has-background-primary:focus-visible, +has-background-primary.is-hoverable:hover, +has-background-primary.is-hoverable:focus-visible { + background-color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), calc(var(--bulma-primary-l) + var(--bulma-hover-background-l-delta))) !important; +} +a.has-background-primary:active, +button.has-background-primary:active, +has-background-primary.is-hoverable:active { + background-color: hsl(var(--bulma-primary-h), var(--bulma-primary-s), calc(var(--bulma-primary-l) + var(--bulma-active-background-l-delta))) !important; +} + +.is-palette-primary { + --h: var(--bulma-primary-h); + --s: var(--bulma-primary-s); + --l: var(--bulma-primary-l); + --color: hsl(var(--h), var(--s), var(--l)); + --00-l: var(--bulma-primary-00-l); + --color-00: hsl(var(--h), var(--s), var(--00-l)); + --05-l: var(--bulma-primary-05-l); + --color-05: hsl(var(--h), var(--s), var(--05-l)); + --10-l: var(--bulma-primary-10-l); + --color-10: hsl(var(--h), var(--s), var(--10-l)); + --15-l: var(--bulma-primary-15-l); + --color-15: hsl(var(--h), var(--s), var(--15-l)); + --20-l: var(--bulma-primary-20-l); + --color-20: hsl(var(--h), var(--s), var(--20-l)); + --25-l: var(--bulma-primary-25-l); + --color-25: hsl(var(--h), var(--s), var(--25-l)); + --30-l: var(--bulma-primary-30-l); + --color-30: hsl(var(--h), var(--s), var(--30-l)); + --35-l: var(--bulma-primary-35-l); + --color-35: hsl(var(--h), var(--s), var(--35-l)); + --40-l: var(--bulma-primary-40-l); + --color-40: hsl(var(--h), var(--s), var(--40-l)); + --45-l: var(--bulma-primary-45-l); + --color-45: hsl(var(--h), var(--s), var(--45-l)); + --50-l: var(--bulma-primary-50-l); + --color-50: hsl(var(--h), var(--s), var(--50-l)); + --55-l: var(--bulma-primary-55-l); + --color-55: hsl(var(--h), var(--s), var(--55-l)); + --60-l: var(--bulma-primary-60-l); + --color-60: hsl(var(--h), var(--s), var(--60-l)); + --65-l: var(--bulma-primary-65-l); + --color-65: hsl(var(--h), var(--s), var(--65-l)); + --70-l: var(--bulma-primary-70-l); + --color-70: hsl(var(--h), var(--s), var(--70-l)); + --75-l: var(--bulma-primary-75-l); + --color-75: hsl(var(--h), var(--s), var(--75-l)); + --80-l: var(--bulma-primary-80-l); + --color-80: hsl(var(--h), var(--s), var(--80-l)); + --85-l: var(--bulma-primary-85-l); + --color-85: hsl(var(--h), var(--s), var(--85-l)); + --90-l: var(--bulma-primary-90-l); + --color-90: hsl(var(--h), var(--s), var(--90-l)); + --95-l: var(--bulma-primary-95-l); + --color-95: hsl(var(--h), var(--s), var(--95-l)); + --100-l: var(--bulma-primary-100-l); + --color-100: hsl(var(--h), var(--s), var(--100-l)); +} + +.has-text-link { + color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-l)) !important; +} + +.has-background-link { + background-color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-l)) !important; +} + +.has-text-link-invert { + color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-invert-l)) !important; +} + +.has-background-link-invert { + background-color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-invert-l)) !important; +} + +.has-text-link-on-scheme { + color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-on-scheme-l)) !important; +} + +.has-background-link-on-scheme { + background-color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-on-scheme-l)) !important; +} + +.has-text-link-light { + color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-light-l)) !important; +} + +.has-background-link-light { + background-color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-light-l)) !important; +} + +.has-text-link-light-invert { + color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-light-invert-l)) !important; +} + +.has-background-link-light-invert { + background-color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-light-invert-l)) !important; +} + +.has-text-link-dark { + color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-dark-l)) !important; +} + +.has-background-link-dark { + background-color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-dark-l)) !important; +} + +.has-text-link-dark-invert { + color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-dark-invert-l)) !important; +} + +.has-background-link-dark-invert { + background-color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-dark-invert-l)) !important; +} + +.has-text-link-soft { + color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-soft-l)) !important; +} + +.has-background-link-soft { + background-color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-soft-l)) !important; +} + +.has-text-link-bold { + color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-bold-l)) !important; +} + +.has-background-link-bold { + background-color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-bold-l)) !important; +} + +.has-text-link-soft-invert { + color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-soft-invert-l)) !important; +} + +.has-background-link-soft-invert { + background-color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-soft-invert-l)) !important; +} + +.has-text-link-bold-invert { + color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-bold-invert-l)) !important; +} + +.has-background-link-bold-invert { + background-color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-bold-invert-l)) !important; +} + +.has-text-link-00 { + color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-00-l)) !important; +} + +.has-background-link-00 { + background-color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-00-l)) !important; +} + +.has-text-link-00-invert { + color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-00-invert-l)) !important; +} + +.has-background-link-00-invert { + background-color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-00-invert-l)) !important; +} + +.has-text-link-05 { + color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-05-l)) !important; +} + +.has-background-link-05 { + background-color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-05-l)) !important; +} + +.has-text-link-05-invert { + color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-05-invert-l)) !important; +} + +.has-background-link-05-invert { + background-color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-05-invert-l)) !important; +} + +.has-text-link-10 { + color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-10-l)) !important; +} + +.has-background-link-10 { + background-color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-10-l)) !important; +} + +.has-text-link-10-invert { + color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-10-invert-l)) !important; +} + +.has-background-link-10-invert { + background-color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-10-invert-l)) !important; +} + +.has-text-link-15 { + color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-15-l)) !important; +} + +.has-background-link-15 { + background-color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-15-l)) !important; +} + +.has-text-link-15-invert { + color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-15-invert-l)) !important; +} + +.has-background-link-15-invert { + background-color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-15-invert-l)) !important; +} + +.has-text-link-20 { + color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-20-l)) !important; +} + +.has-background-link-20 { + background-color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-20-l)) !important; +} + +.has-text-link-20-invert { + color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-20-invert-l)) !important; +} + +.has-background-link-20-invert { + background-color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-20-invert-l)) !important; +} + +.has-text-link-25 { + color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-25-l)) !important; +} + +.has-background-link-25 { + background-color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-25-l)) !important; +} + +.has-text-link-25-invert { + color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-25-invert-l)) !important; +} + +.has-background-link-25-invert { + background-color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-25-invert-l)) !important; +} + +.has-text-link-30 { + color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-30-l)) !important; +} + +.has-background-link-30 { + background-color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-30-l)) !important; +} + +.has-text-link-30-invert { + color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-30-invert-l)) !important; +} + +.has-background-link-30-invert { + background-color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-30-invert-l)) !important; +} + +.has-text-link-35 { + color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-35-l)) !important; +} + +.has-background-link-35 { + background-color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-35-l)) !important; +} + +.has-text-link-35-invert { + color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-35-invert-l)) !important; +} + +.has-background-link-35-invert { + background-color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-35-invert-l)) !important; +} + +.has-text-link-40 { + color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-40-l)) !important; +} + +.has-background-link-40 { + background-color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-40-l)) !important; +} + +.has-text-link-40-invert { + color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-40-invert-l)) !important; +} + +.has-background-link-40-invert { + background-color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-40-invert-l)) !important; +} + +.has-text-link-45 { + color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-45-l)) !important; +} + +.has-background-link-45 { + background-color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-45-l)) !important; +} + +.has-text-link-45-invert { + color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-45-invert-l)) !important; +} + +.has-background-link-45-invert { + background-color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-45-invert-l)) !important; +} + +.has-text-link-50 { + color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-50-l)) !important; +} + +.has-background-link-50 { + background-color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-50-l)) !important; +} + +.has-text-link-50-invert { + color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-50-invert-l)) !important; +} + +.has-background-link-50-invert { + background-color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-50-invert-l)) !important; +} + +.has-text-link-55 { + color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-55-l)) !important; +} + +.has-background-link-55 { + background-color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-55-l)) !important; +} + +.has-text-link-55-invert { + color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-55-invert-l)) !important; +} + +.has-background-link-55-invert { + background-color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-55-invert-l)) !important; +} + +.has-text-link-60 { + color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-60-l)) !important; +} + +.has-background-link-60 { + background-color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-60-l)) !important; +} + +.has-text-link-60-invert { + color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-60-invert-l)) !important; +} + +.has-background-link-60-invert { + background-color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-60-invert-l)) !important; +} + +.has-text-link-65 { + color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-65-l)) !important; +} + +.has-background-link-65 { + background-color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-65-l)) !important; +} + +.has-text-link-65-invert { + color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-65-invert-l)) !important; +} + +.has-background-link-65-invert { + background-color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-65-invert-l)) !important; +} + +.has-text-link-70 { + color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-70-l)) !important; +} + +.has-background-link-70 { + background-color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-70-l)) !important; +} + +.has-text-link-70-invert { + color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-70-invert-l)) !important; +} + +.has-background-link-70-invert { + background-color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-70-invert-l)) !important; +} + +.has-text-link-75 { + color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-75-l)) !important; +} + +.has-background-link-75 { + background-color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-75-l)) !important; +} + +.has-text-link-75-invert { + color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-75-invert-l)) !important; +} + +.has-background-link-75-invert { + background-color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-75-invert-l)) !important; +} + +.has-text-link-80 { + color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-80-l)) !important; +} + +.has-background-link-80 { + background-color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-80-l)) !important; +} + +.has-text-link-80-invert { + color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-80-invert-l)) !important; +} + +.has-background-link-80-invert { + background-color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-80-invert-l)) !important; +} + +.has-text-link-85 { + color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-85-l)) !important; +} + +.has-background-link-85 { + background-color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-85-l)) !important; +} + +.has-text-link-85-invert { + color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-85-invert-l)) !important; +} + +.has-background-link-85-invert { + background-color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-85-invert-l)) !important; +} + +.has-text-link-90 { + color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-90-l)) !important; +} + +.has-background-link-90 { + background-color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-90-l)) !important; +} + +.has-text-link-90-invert { + color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-90-invert-l)) !important; +} + +.has-background-link-90-invert { + background-color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-90-invert-l)) !important; +} + +.has-text-link-95 { + color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-95-l)) !important; +} + +.has-background-link-95 { + background-color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-95-l)) !important; +} + +.has-text-link-95-invert { + color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-95-invert-l)) !important; +} + +.has-background-link-95-invert { + background-color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-95-invert-l)) !important; +} + +.has-text-link-100 { + color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-100-l)) !important; +} + +.has-background-link-100 { + background-color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-100-l)) !important; +} + +.has-text-link-100-invert { + color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-100-invert-l)) !important; +} + +.has-background-link-100-invert { + background-color: hsl(var(--bulma-link-h), var(--bulma-link-s), var(--bulma-link-100-invert-l)) !important; +} + +a.has-text-link:hover, a.has-text-link:focus-visible, +button.has-text-link:hover, +button.has-text-link:focus-visible, +has-text-link.is-hoverable:hover, +has-text-link.is-hoverable:focus-visible { + color: hsl(var(--bulma-link-h), var(--bulma-link-s), calc(var(--bulma-link-l) + var(--bulma-hover-color-l-delta))) !important; +} +a.has-text-link:active, +button.has-text-link:active, +has-text-link.is-hoverable:active { + color: hsl(var(--bulma-link-h), var(--bulma-link-s), calc(var(--bulma-link-l) + var(--bulma-active-color-l-delta))) !important; +} + +a.has-background-link:hover, a.has-background-link:focus-visible, +button.has-background-link:hover, +button.has-background-link:focus-visible, +has-background-link.is-hoverable:hover, +has-background-link.is-hoverable:focus-visible { + background-color: hsl(var(--bulma-link-h), var(--bulma-link-s), calc(var(--bulma-link-l) + var(--bulma-hover-background-l-delta))) !important; +} +a.has-background-link:active, +button.has-background-link:active, +has-background-link.is-hoverable:active { + background-color: hsl(var(--bulma-link-h), var(--bulma-link-s), calc(var(--bulma-link-l) + var(--bulma-active-background-l-delta))) !important; +} + +.is-palette-link { + --h: var(--bulma-link-h); + --s: var(--bulma-link-s); + --l: var(--bulma-link-l); + --color: hsl(var(--h), var(--s), var(--l)); + --00-l: var(--bulma-link-00-l); + --color-00: hsl(var(--h), var(--s), var(--00-l)); + --05-l: var(--bulma-link-05-l); + --color-05: hsl(var(--h), var(--s), var(--05-l)); + --10-l: var(--bulma-link-10-l); + --color-10: hsl(var(--h), var(--s), var(--10-l)); + --15-l: var(--bulma-link-15-l); + --color-15: hsl(var(--h), var(--s), var(--15-l)); + --20-l: var(--bulma-link-20-l); + --color-20: hsl(var(--h), var(--s), var(--20-l)); + --25-l: var(--bulma-link-25-l); + --color-25: hsl(var(--h), var(--s), var(--25-l)); + --30-l: var(--bulma-link-30-l); + --color-30: hsl(var(--h), var(--s), var(--30-l)); + --35-l: var(--bulma-link-35-l); + --color-35: hsl(var(--h), var(--s), var(--35-l)); + --40-l: var(--bulma-link-40-l); + --color-40: hsl(var(--h), var(--s), var(--40-l)); + --45-l: var(--bulma-link-45-l); + --color-45: hsl(var(--h), var(--s), var(--45-l)); + --50-l: var(--bulma-link-50-l); + --color-50: hsl(var(--h), var(--s), var(--50-l)); + --55-l: var(--bulma-link-55-l); + --color-55: hsl(var(--h), var(--s), var(--55-l)); + --60-l: var(--bulma-link-60-l); + --color-60: hsl(var(--h), var(--s), var(--60-l)); + --65-l: var(--bulma-link-65-l); + --color-65: hsl(var(--h), var(--s), var(--65-l)); + --70-l: var(--bulma-link-70-l); + --color-70: hsl(var(--h), var(--s), var(--70-l)); + --75-l: var(--bulma-link-75-l); + --color-75: hsl(var(--h), var(--s), var(--75-l)); + --80-l: var(--bulma-link-80-l); + --color-80: hsl(var(--h), var(--s), var(--80-l)); + --85-l: var(--bulma-link-85-l); + --color-85: hsl(var(--h), var(--s), var(--85-l)); + --90-l: var(--bulma-link-90-l); + --color-90: hsl(var(--h), var(--s), var(--90-l)); + --95-l: var(--bulma-link-95-l); + --color-95: hsl(var(--h), var(--s), var(--95-l)); + --100-l: var(--bulma-link-100-l); + --color-100: hsl(var(--h), var(--s), var(--100-l)); +} + +.has-text-info { + color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-l)) !important; +} + +.has-background-info { + background-color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-l)) !important; +} + +.has-text-info-invert { + color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-invert-l)) !important; +} + +.has-background-info-invert { + background-color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-invert-l)) !important; +} + +.has-text-info-on-scheme { + color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-on-scheme-l)) !important; +} + +.has-background-info-on-scheme { + background-color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-on-scheme-l)) !important; +} + +.has-text-info-light { + color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-light-l)) !important; +} + +.has-background-info-light { + background-color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-light-l)) !important; +} + +.has-text-info-light-invert { + color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-light-invert-l)) !important; +} + +.has-background-info-light-invert { + background-color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-light-invert-l)) !important; +} + +.has-text-info-dark { + color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-dark-l)) !important; +} + +.has-background-info-dark { + background-color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-dark-l)) !important; +} + +.has-text-info-dark-invert { + color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-dark-invert-l)) !important; +} + +.has-background-info-dark-invert { + background-color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-dark-invert-l)) !important; +} + +.has-text-info-soft { + color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-soft-l)) !important; +} + +.has-background-info-soft { + background-color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-soft-l)) !important; +} + +.has-text-info-bold { + color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-bold-l)) !important; +} + +.has-background-info-bold { + background-color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-bold-l)) !important; +} + +.has-text-info-soft-invert { + color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-soft-invert-l)) !important; +} + +.has-background-info-soft-invert { + background-color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-soft-invert-l)) !important; +} + +.has-text-info-bold-invert { + color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-bold-invert-l)) !important; +} + +.has-background-info-bold-invert { + background-color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-bold-invert-l)) !important; +} + +.has-text-info-00 { + color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-00-l)) !important; +} + +.has-background-info-00 { + background-color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-00-l)) !important; +} + +.has-text-info-00-invert { + color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-00-invert-l)) !important; +} + +.has-background-info-00-invert { + background-color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-00-invert-l)) !important; +} + +.has-text-info-05 { + color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-05-l)) !important; +} + +.has-background-info-05 { + background-color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-05-l)) !important; +} + +.has-text-info-05-invert { + color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-05-invert-l)) !important; +} + +.has-background-info-05-invert { + background-color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-05-invert-l)) !important; +} + +.has-text-info-10 { + color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-10-l)) !important; +} + +.has-background-info-10 { + background-color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-10-l)) !important; +} + +.has-text-info-10-invert { + color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-10-invert-l)) !important; +} + +.has-background-info-10-invert { + background-color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-10-invert-l)) !important; +} + +.has-text-info-15 { + color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-15-l)) !important; +} + +.has-background-info-15 { + background-color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-15-l)) !important; +} + +.has-text-info-15-invert { + color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-15-invert-l)) !important; +} + +.has-background-info-15-invert { + background-color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-15-invert-l)) !important; +} + +.has-text-info-20 { + color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-20-l)) !important; +} + +.has-background-info-20 { + background-color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-20-l)) !important; +} + +.has-text-info-20-invert { + color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-20-invert-l)) !important; +} + +.has-background-info-20-invert { + background-color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-20-invert-l)) !important; +} + +.has-text-info-25 { + color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-25-l)) !important; +} + +.has-background-info-25 { + background-color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-25-l)) !important; +} + +.has-text-info-25-invert { + color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-25-invert-l)) !important; +} + +.has-background-info-25-invert { + background-color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-25-invert-l)) !important; +} + +.has-text-info-30 { + color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-30-l)) !important; +} + +.has-background-info-30 { + background-color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-30-l)) !important; +} + +.has-text-info-30-invert { + color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-30-invert-l)) !important; +} + +.has-background-info-30-invert { + background-color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-30-invert-l)) !important; +} + +.has-text-info-35 { + color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-35-l)) !important; +} + +.has-background-info-35 { + background-color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-35-l)) !important; +} + +.has-text-info-35-invert { + color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-35-invert-l)) !important; +} + +.has-background-info-35-invert { + background-color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-35-invert-l)) !important; +} + +.has-text-info-40 { + color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-40-l)) !important; +} + +.has-background-info-40 { + background-color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-40-l)) !important; +} + +.has-text-info-40-invert { + color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-40-invert-l)) !important; +} + +.has-background-info-40-invert { + background-color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-40-invert-l)) !important; +} + +.has-text-info-45 { + color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-45-l)) !important; +} + +.has-background-info-45 { + background-color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-45-l)) !important; +} + +.has-text-info-45-invert { + color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-45-invert-l)) !important; +} + +.has-background-info-45-invert { + background-color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-45-invert-l)) !important; +} + +.has-text-info-50 { + color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-50-l)) !important; +} + +.has-background-info-50 { + background-color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-50-l)) !important; +} + +.has-text-info-50-invert { + color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-50-invert-l)) !important; +} + +.has-background-info-50-invert { + background-color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-50-invert-l)) !important; +} + +.has-text-info-55 { + color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-55-l)) !important; +} + +.has-background-info-55 { + background-color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-55-l)) !important; +} + +.has-text-info-55-invert { + color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-55-invert-l)) !important; +} + +.has-background-info-55-invert { + background-color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-55-invert-l)) !important; +} + +.has-text-info-60 { + color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-60-l)) !important; +} + +.has-background-info-60 { + background-color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-60-l)) !important; +} + +.has-text-info-60-invert { + color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-60-invert-l)) !important; +} + +.has-background-info-60-invert { + background-color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-60-invert-l)) !important; +} + +.has-text-info-65 { + color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-65-l)) !important; +} + +.has-background-info-65 { + background-color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-65-l)) !important; +} + +.has-text-info-65-invert { + color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-65-invert-l)) !important; +} + +.has-background-info-65-invert { + background-color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-65-invert-l)) !important; +} + +.has-text-info-70 { + color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-70-l)) !important; +} + +.has-background-info-70 { + background-color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-70-l)) !important; +} + +.has-text-info-70-invert { + color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-70-invert-l)) !important; +} + +.has-background-info-70-invert { + background-color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-70-invert-l)) !important; +} + +.has-text-info-75 { + color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-75-l)) !important; +} + +.has-background-info-75 { + background-color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-75-l)) !important; +} + +.has-text-info-75-invert { + color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-75-invert-l)) !important; +} + +.has-background-info-75-invert { + background-color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-75-invert-l)) !important; +} + +.has-text-info-80 { + color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-80-l)) !important; +} + +.has-background-info-80 { + background-color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-80-l)) !important; +} + +.has-text-info-80-invert { + color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-80-invert-l)) !important; +} + +.has-background-info-80-invert { + background-color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-80-invert-l)) !important; +} + +.has-text-info-85 { + color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-85-l)) !important; +} + +.has-background-info-85 { + background-color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-85-l)) !important; +} + +.has-text-info-85-invert { + color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-85-invert-l)) !important; +} + +.has-background-info-85-invert { + background-color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-85-invert-l)) !important; +} + +.has-text-info-90 { + color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-90-l)) !important; +} + +.has-background-info-90 { + background-color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-90-l)) !important; +} + +.has-text-info-90-invert { + color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-90-invert-l)) !important; +} + +.has-background-info-90-invert { + background-color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-90-invert-l)) !important; +} + +.has-text-info-95 { + color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-95-l)) !important; +} + +.has-background-info-95 { + background-color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-95-l)) !important; +} + +.has-text-info-95-invert { + color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-95-invert-l)) !important; +} + +.has-background-info-95-invert { + background-color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-95-invert-l)) !important; +} + +.has-text-info-100 { + color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-100-l)) !important; +} + +.has-background-info-100 { + background-color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-100-l)) !important; +} + +.has-text-info-100-invert { + color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-100-invert-l)) !important; +} + +.has-background-info-100-invert { + background-color: hsl(var(--bulma-info-h), var(--bulma-info-s), var(--bulma-info-100-invert-l)) !important; +} + +a.has-text-info:hover, a.has-text-info:focus-visible, +button.has-text-info:hover, +button.has-text-info:focus-visible, +has-text-info.is-hoverable:hover, +has-text-info.is-hoverable:focus-visible { + color: hsl(var(--bulma-info-h), var(--bulma-info-s), calc(var(--bulma-info-l) + var(--bulma-hover-color-l-delta))) !important; +} +a.has-text-info:active, +button.has-text-info:active, +has-text-info.is-hoverable:active { + color: hsl(var(--bulma-info-h), var(--bulma-info-s), calc(var(--bulma-info-l) + var(--bulma-active-color-l-delta))) !important; +} + +a.has-background-info:hover, a.has-background-info:focus-visible, +button.has-background-info:hover, +button.has-background-info:focus-visible, +has-background-info.is-hoverable:hover, +has-background-info.is-hoverable:focus-visible { + background-color: hsl(var(--bulma-info-h), var(--bulma-info-s), calc(var(--bulma-info-l) + var(--bulma-hover-background-l-delta))) !important; +} +a.has-background-info:active, +button.has-background-info:active, +has-background-info.is-hoverable:active { + background-color: hsl(var(--bulma-info-h), var(--bulma-info-s), calc(var(--bulma-info-l) + var(--bulma-active-background-l-delta))) !important; +} + +.is-palette-info { + --h: var(--bulma-info-h); + --s: var(--bulma-info-s); + --l: var(--bulma-info-l); + --color: hsl(var(--h), var(--s), var(--l)); + --00-l: var(--bulma-info-00-l); + --color-00: hsl(var(--h), var(--s), var(--00-l)); + --05-l: var(--bulma-info-05-l); + --color-05: hsl(var(--h), var(--s), var(--05-l)); + --10-l: var(--bulma-info-10-l); + --color-10: hsl(var(--h), var(--s), var(--10-l)); + --15-l: var(--bulma-info-15-l); + --color-15: hsl(var(--h), var(--s), var(--15-l)); + --20-l: var(--bulma-info-20-l); + --color-20: hsl(var(--h), var(--s), var(--20-l)); + --25-l: var(--bulma-info-25-l); + --color-25: hsl(var(--h), var(--s), var(--25-l)); + --30-l: var(--bulma-info-30-l); + --color-30: hsl(var(--h), var(--s), var(--30-l)); + --35-l: var(--bulma-info-35-l); + --color-35: hsl(var(--h), var(--s), var(--35-l)); + --40-l: var(--bulma-info-40-l); + --color-40: hsl(var(--h), var(--s), var(--40-l)); + --45-l: var(--bulma-info-45-l); + --color-45: hsl(var(--h), var(--s), var(--45-l)); + --50-l: var(--bulma-info-50-l); + --color-50: hsl(var(--h), var(--s), var(--50-l)); + --55-l: var(--bulma-info-55-l); + --color-55: hsl(var(--h), var(--s), var(--55-l)); + --60-l: var(--bulma-info-60-l); + --color-60: hsl(var(--h), var(--s), var(--60-l)); + --65-l: var(--bulma-info-65-l); + --color-65: hsl(var(--h), var(--s), var(--65-l)); + --70-l: var(--bulma-info-70-l); + --color-70: hsl(var(--h), var(--s), var(--70-l)); + --75-l: var(--bulma-info-75-l); + --color-75: hsl(var(--h), var(--s), var(--75-l)); + --80-l: var(--bulma-info-80-l); + --color-80: hsl(var(--h), var(--s), var(--80-l)); + --85-l: var(--bulma-info-85-l); + --color-85: hsl(var(--h), var(--s), var(--85-l)); + --90-l: var(--bulma-info-90-l); + --color-90: hsl(var(--h), var(--s), var(--90-l)); + --95-l: var(--bulma-info-95-l); + --color-95: hsl(var(--h), var(--s), var(--95-l)); + --100-l: var(--bulma-info-100-l); + --color-100: hsl(var(--h), var(--s), var(--100-l)); +} + +.has-text-success { + color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-l)) !important; +} + +.has-background-success { + background-color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-l)) !important; +} + +.has-text-success-invert { + color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-invert-l)) !important; +} + +.has-background-success-invert { + background-color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-invert-l)) !important; +} + +.has-text-success-on-scheme { + color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-on-scheme-l)) !important; +} + +.has-background-success-on-scheme { + background-color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-on-scheme-l)) !important; +} + +.has-text-success-light { + color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-light-l)) !important; +} + +.has-background-success-light { + background-color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-light-l)) !important; +} + +.has-text-success-light-invert { + color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-light-invert-l)) !important; +} + +.has-background-success-light-invert { + background-color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-light-invert-l)) !important; +} + +.has-text-success-dark { + color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-dark-l)) !important; +} + +.has-background-success-dark { + background-color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-dark-l)) !important; +} + +.has-text-success-dark-invert { + color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-dark-invert-l)) !important; +} + +.has-background-success-dark-invert { + background-color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-dark-invert-l)) !important; +} + +.has-text-success-soft { + color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-soft-l)) !important; +} + +.has-background-success-soft { + background-color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-soft-l)) !important; +} + +.has-text-success-bold { + color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-bold-l)) !important; +} + +.has-background-success-bold { + background-color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-bold-l)) !important; +} + +.has-text-success-soft-invert { + color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-soft-invert-l)) !important; +} + +.has-background-success-soft-invert { + background-color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-soft-invert-l)) !important; +} + +.has-text-success-bold-invert { + color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-bold-invert-l)) !important; +} + +.has-background-success-bold-invert { + background-color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-bold-invert-l)) !important; +} + +.has-text-success-00 { + color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-00-l)) !important; +} + +.has-background-success-00 { + background-color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-00-l)) !important; +} + +.has-text-success-00-invert { + color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-00-invert-l)) !important; +} + +.has-background-success-00-invert { + background-color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-00-invert-l)) !important; +} + +.has-text-success-05 { + color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-05-l)) !important; +} + +.has-background-success-05 { + background-color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-05-l)) !important; +} + +.has-text-success-05-invert { + color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-05-invert-l)) !important; +} + +.has-background-success-05-invert { + background-color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-05-invert-l)) !important; +} + +.has-text-success-10 { + color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-10-l)) !important; +} + +.has-background-success-10 { + background-color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-10-l)) !important; +} + +.has-text-success-10-invert { + color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-10-invert-l)) !important; +} + +.has-background-success-10-invert { + background-color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-10-invert-l)) !important; +} + +.has-text-success-15 { + color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-15-l)) !important; +} + +.has-background-success-15 { + background-color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-15-l)) !important; +} + +.has-text-success-15-invert { + color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-15-invert-l)) !important; +} + +.has-background-success-15-invert { + background-color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-15-invert-l)) !important; +} + +.has-text-success-20 { + color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-20-l)) !important; +} + +.has-background-success-20 { + background-color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-20-l)) !important; +} + +.has-text-success-20-invert { + color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-20-invert-l)) !important; +} + +.has-background-success-20-invert { + background-color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-20-invert-l)) !important; +} + +.has-text-success-25 { + color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-25-l)) !important; +} + +.has-background-success-25 { + background-color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-25-l)) !important; +} + +.has-text-success-25-invert { + color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-25-invert-l)) !important; +} + +.has-background-success-25-invert { + background-color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-25-invert-l)) !important; +} + +.has-text-success-30 { + color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-30-l)) !important; +} + +.has-background-success-30 { + background-color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-30-l)) !important; +} + +.has-text-success-30-invert { + color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-30-invert-l)) !important; +} + +.has-background-success-30-invert { + background-color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-30-invert-l)) !important; +} + +.has-text-success-35 { + color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-35-l)) !important; +} + +.has-background-success-35 { + background-color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-35-l)) !important; +} + +.has-text-success-35-invert { + color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-35-invert-l)) !important; +} + +.has-background-success-35-invert { + background-color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-35-invert-l)) !important; +} + +.has-text-success-40 { + color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-40-l)) !important; +} + +.has-background-success-40 { + background-color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-40-l)) !important; +} + +.has-text-success-40-invert { + color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-40-invert-l)) !important; +} + +.has-background-success-40-invert { + background-color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-40-invert-l)) !important; +} + +.has-text-success-45 { + color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-45-l)) !important; +} + +.has-background-success-45 { + background-color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-45-l)) !important; +} + +.has-text-success-45-invert { + color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-45-invert-l)) !important; +} + +.has-background-success-45-invert { + background-color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-45-invert-l)) !important; +} + +.has-text-success-50 { + color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-50-l)) !important; +} + +.has-background-success-50 { + background-color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-50-l)) !important; +} + +.has-text-success-50-invert { + color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-50-invert-l)) !important; +} + +.has-background-success-50-invert { + background-color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-50-invert-l)) !important; +} + +.has-text-success-55 { + color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-55-l)) !important; +} + +.has-background-success-55 { + background-color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-55-l)) !important; +} + +.has-text-success-55-invert { + color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-55-invert-l)) !important; +} + +.has-background-success-55-invert { + background-color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-55-invert-l)) !important; +} + +.has-text-success-60 { + color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-60-l)) !important; +} + +.has-background-success-60 { + background-color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-60-l)) !important; +} + +.has-text-success-60-invert { + color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-60-invert-l)) !important; +} + +.has-background-success-60-invert { + background-color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-60-invert-l)) !important; +} + +.has-text-success-65 { + color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-65-l)) !important; +} + +.has-background-success-65 { + background-color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-65-l)) !important; +} + +.has-text-success-65-invert { + color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-65-invert-l)) !important; +} + +.has-background-success-65-invert { + background-color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-65-invert-l)) !important; +} + +.has-text-success-70 { + color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-70-l)) !important; +} + +.has-background-success-70 { + background-color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-70-l)) !important; +} + +.has-text-success-70-invert { + color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-70-invert-l)) !important; +} + +.has-background-success-70-invert { + background-color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-70-invert-l)) !important; +} + +.has-text-success-75 { + color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-75-l)) !important; +} + +.has-background-success-75 { + background-color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-75-l)) !important; +} + +.has-text-success-75-invert { + color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-75-invert-l)) !important; +} + +.has-background-success-75-invert { + background-color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-75-invert-l)) !important; +} + +.has-text-success-80 { + color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-80-l)) !important; +} + +.has-background-success-80 { + background-color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-80-l)) !important; +} + +.has-text-success-80-invert { + color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-80-invert-l)) !important; +} + +.has-background-success-80-invert { + background-color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-80-invert-l)) !important; +} + +.has-text-success-85 { + color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-85-l)) !important; +} + +.has-background-success-85 { + background-color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-85-l)) !important; +} + +.has-text-success-85-invert { + color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-85-invert-l)) !important; +} + +.has-background-success-85-invert { + background-color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-85-invert-l)) !important; +} + +.has-text-success-90 { + color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-90-l)) !important; +} + +.has-background-success-90 { + background-color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-90-l)) !important; +} + +.has-text-success-90-invert { + color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-90-invert-l)) !important; +} + +.has-background-success-90-invert { + background-color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-90-invert-l)) !important; +} + +.has-text-success-95 { + color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-95-l)) !important; +} + +.has-background-success-95 { + background-color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-95-l)) !important; +} + +.has-text-success-95-invert { + color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-95-invert-l)) !important; +} + +.has-background-success-95-invert { + background-color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-95-invert-l)) !important; +} + +.has-text-success-100 { + color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-100-l)) !important; +} + +.has-background-success-100 { + background-color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-100-l)) !important; +} + +.has-text-success-100-invert { + color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-100-invert-l)) !important; +} + +.has-background-success-100-invert { + background-color: hsl(var(--bulma-success-h), var(--bulma-success-s), var(--bulma-success-100-invert-l)) !important; +} + +a.has-text-success:hover, a.has-text-success:focus-visible, +button.has-text-success:hover, +button.has-text-success:focus-visible, +has-text-success.is-hoverable:hover, +has-text-success.is-hoverable:focus-visible { + color: hsl(var(--bulma-success-h), var(--bulma-success-s), calc(var(--bulma-success-l) + var(--bulma-hover-color-l-delta))) !important; +} +a.has-text-success:active, +button.has-text-success:active, +has-text-success.is-hoverable:active { + color: hsl(var(--bulma-success-h), var(--bulma-success-s), calc(var(--bulma-success-l) + var(--bulma-active-color-l-delta))) !important; +} + +a.has-background-success:hover, a.has-background-success:focus-visible, +button.has-background-success:hover, +button.has-background-success:focus-visible, +has-background-success.is-hoverable:hover, +has-background-success.is-hoverable:focus-visible { + background-color: hsl(var(--bulma-success-h), var(--bulma-success-s), calc(var(--bulma-success-l) + var(--bulma-hover-background-l-delta))) !important; +} +a.has-background-success:active, +button.has-background-success:active, +has-background-success.is-hoverable:active { + background-color: hsl(var(--bulma-success-h), var(--bulma-success-s), calc(var(--bulma-success-l) + var(--bulma-active-background-l-delta))) !important; +} + +.is-palette-success { + --h: var(--bulma-success-h); + --s: var(--bulma-success-s); + --l: var(--bulma-success-l); + --color: hsl(var(--h), var(--s), var(--l)); + --00-l: var(--bulma-success-00-l); + --color-00: hsl(var(--h), var(--s), var(--00-l)); + --05-l: var(--bulma-success-05-l); + --color-05: hsl(var(--h), var(--s), var(--05-l)); + --10-l: var(--bulma-success-10-l); + --color-10: hsl(var(--h), var(--s), var(--10-l)); + --15-l: var(--bulma-success-15-l); + --color-15: hsl(var(--h), var(--s), var(--15-l)); + --20-l: var(--bulma-success-20-l); + --color-20: hsl(var(--h), var(--s), var(--20-l)); + --25-l: var(--bulma-success-25-l); + --color-25: hsl(var(--h), var(--s), var(--25-l)); + --30-l: var(--bulma-success-30-l); + --color-30: hsl(var(--h), var(--s), var(--30-l)); + --35-l: var(--bulma-success-35-l); + --color-35: hsl(var(--h), var(--s), var(--35-l)); + --40-l: var(--bulma-success-40-l); + --color-40: hsl(var(--h), var(--s), var(--40-l)); + --45-l: var(--bulma-success-45-l); + --color-45: hsl(var(--h), var(--s), var(--45-l)); + --50-l: var(--bulma-success-50-l); + --color-50: hsl(var(--h), var(--s), var(--50-l)); + --55-l: var(--bulma-success-55-l); + --color-55: hsl(var(--h), var(--s), var(--55-l)); + --60-l: var(--bulma-success-60-l); + --color-60: hsl(var(--h), var(--s), var(--60-l)); + --65-l: var(--bulma-success-65-l); + --color-65: hsl(var(--h), var(--s), var(--65-l)); + --70-l: var(--bulma-success-70-l); + --color-70: hsl(var(--h), var(--s), var(--70-l)); + --75-l: var(--bulma-success-75-l); + --color-75: hsl(var(--h), var(--s), var(--75-l)); + --80-l: var(--bulma-success-80-l); + --color-80: hsl(var(--h), var(--s), var(--80-l)); + --85-l: var(--bulma-success-85-l); + --color-85: hsl(var(--h), var(--s), var(--85-l)); + --90-l: var(--bulma-success-90-l); + --color-90: hsl(var(--h), var(--s), var(--90-l)); + --95-l: var(--bulma-success-95-l); + --color-95: hsl(var(--h), var(--s), var(--95-l)); + --100-l: var(--bulma-success-100-l); + --color-100: hsl(var(--h), var(--s), var(--100-l)); +} + +.has-text-warning { + color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-l)) !important; +} + +.has-background-warning { + background-color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-l)) !important; +} + +.has-text-warning-invert { + color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-invert-l)) !important; +} + +.has-background-warning-invert { + background-color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-invert-l)) !important; +} + +.has-text-warning-on-scheme { + color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-on-scheme-l)) !important; +} + +.has-background-warning-on-scheme { + background-color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-on-scheme-l)) !important; +} + +.has-text-warning-light { + color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-light-l)) !important; +} + +.has-background-warning-light { + background-color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-light-l)) !important; +} + +.has-text-warning-light-invert { + color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-light-invert-l)) !important; +} + +.has-background-warning-light-invert { + background-color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-light-invert-l)) !important; +} + +.has-text-warning-dark { + color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-dark-l)) !important; +} + +.has-background-warning-dark { + background-color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-dark-l)) !important; +} + +.has-text-warning-dark-invert { + color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-dark-invert-l)) !important; +} + +.has-background-warning-dark-invert { + background-color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-dark-invert-l)) !important; +} + +.has-text-warning-soft { + color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-soft-l)) !important; +} + +.has-background-warning-soft { + background-color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-soft-l)) !important; +} + +.has-text-warning-bold { + color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-bold-l)) !important; +} + +.has-background-warning-bold { + background-color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-bold-l)) !important; +} + +.has-text-warning-soft-invert { + color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-soft-invert-l)) !important; +} + +.has-background-warning-soft-invert { + background-color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-soft-invert-l)) !important; +} + +.has-text-warning-bold-invert { + color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-bold-invert-l)) !important; +} + +.has-background-warning-bold-invert { + background-color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-bold-invert-l)) !important; +} + +.has-text-warning-00 { + color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-00-l)) !important; +} + +.has-background-warning-00 { + background-color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-00-l)) !important; +} + +.has-text-warning-00-invert { + color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-00-invert-l)) !important; +} + +.has-background-warning-00-invert { + background-color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-00-invert-l)) !important; +} + +.has-text-warning-05 { + color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-05-l)) !important; +} + +.has-background-warning-05 { + background-color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-05-l)) !important; +} + +.has-text-warning-05-invert { + color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-05-invert-l)) !important; +} + +.has-background-warning-05-invert { + background-color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-05-invert-l)) !important; +} + +.has-text-warning-10 { + color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-10-l)) !important; +} + +.has-background-warning-10 { + background-color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-10-l)) !important; +} + +.has-text-warning-10-invert { + color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-10-invert-l)) !important; +} + +.has-background-warning-10-invert { + background-color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-10-invert-l)) !important; +} + +.has-text-warning-15 { + color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-15-l)) !important; +} + +.has-background-warning-15 { + background-color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-15-l)) !important; +} + +.has-text-warning-15-invert { + color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-15-invert-l)) !important; +} + +.has-background-warning-15-invert { + background-color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-15-invert-l)) !important; +} + +.has-text-warning-20 { + color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-20-l)) !important; +} + +.has-background-warning-20 { + background-color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-20-l)) !important; +} + +.has-text-warning-20-invert { + color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-20-invert-l)) !important; +} + +.has-background-warning-20-invert { + background-color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-20-invert-l)) !important; +} + +.has-text-warning-25 { + color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-25-l)) !important; +} + +.has-background-warning-25 { + background-color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-25-l)) !important; +} + +.has-text-warning-25-invert { + color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-25-invert-l)) !important; +} + +.has-background-warning-25-invert { + background-color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-25-invert-l)) !important; +} + +.has-text-warning-30 { + color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-30-l)) !important; +} + +.has-background-warning-30 { + background-color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-30-l)) !important; +} + +.has-text-warning-30-invert { + color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-30-invert-l)) !important; +} + +.has-background-warning-30-invert { + background-color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-30-invert-l)) !important; +} + +.has-text-warning-35 { + color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-35-l)) !important; +} + +.has-background-warning-35 { + background-color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-35-l)) !important; +} + +.has-text-warning-35-invert { + color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-35-invert-l)) !important; +} + +.has-background-warning-35-invert { + background-color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-35-invert-l)) !important; +} + +.has-text-warning-40 { + color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-40-l)) !important; +} + +.has-background-warning-40 { + background-color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-40-l)) !important; +} + +.has-text-warning-40-invert { + color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-40-invert-l)) !important; +} + +.has-background-warning-40-invert { + background-color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-40-invert-l)) !important; +} + +.has-text-warning-45 { + color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-45-l)) !important; +} + +.has-background-warning-45 { + background-color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-45-l)) !important; +} + +.has-text-warning-45-invert { + color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-45-invert-l)) !important; +} + +.has-background-warning-45-invert { + background-color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-45-invert-l)) !important; +} + +.has-text-warning-50 { + color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-50-l)) !important; +} + +.has-background-warning-50 { + background-color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-50-l)) !important; +} + +.has-text-warning-50-invert { + color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-50-invert-l)) !important; +} + +.has-background-warning-50-invert { + background-color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-50-invert-l)) !important; +} + +.has-text-warning-55 { + color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-55-l)) !important; +} + +.has-background-warning-55 { + background-color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-55-l)) !important; +} + +.has-text-warning-55-invert { + color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-55-invert-l)) !important; +} + +.has-background-warning-55-invert { + background-color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-55-invert-l)) !important; +} + +.has-text-warning-60 { + color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-60-l)) !important; +} + +.has-background-warning-60 { + background-color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-60-l)) !important; +} + +.has-text-warning-60-invert { + color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-60-invert-l)) !important; +} + +.has-background-warning-60-invert { + background-color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-60-invert-l)) !important; +} + +.has-text-warning-65 { + color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-65-l)) !important; +} + +.has-background-warning-65 { + background-color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-65-l)) !important; +} + +.has-text-warning-65-invert { + color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-65-invert-l)) !important; +} + +.has-background-warning-65-invert { + background-color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-65-invert-l)) !important; +} + +.has-text-warning-70 { + color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-70-l)) !important; +} + +.has-background-warning-70 { + background-color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-70-l)) !important; +} + +.has-text-warning-70-invert { + color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-70-invert-l)) !important; +} + +.has-background-warning-70-invert { + background-color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-70-invert-l)) !important; +} + +.has-text-warning-75 { + color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-75-l)) !important; +} + +.has-background-warning-75 { + background-color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-75-l)) !important; +} + +.has-text-warning-75-invert { + color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-75-invert-l)) !important; +} + +.has-background-warning-75-invert { + background-color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-75-invert-l)) !important; +} + +.has-text-warning-80 { + color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-80-l)) !important; +} + +.has-background-warning-80 { + background-color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-80-l)) !important; +} + +.has-text-warning-80-invert { + color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-80-invert-l)) !important; +} + +.has-background-warning-80-invert { + background-color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-80-invert-l)) !important; +} + +.has-text-warning-85 { + color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-85-l)) !important; +} + +.has-background-warning-85 { + background-color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-85-l)) !important; +} + +.has-text-warning-85-invert { + color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-85-invert-l)) !important; +} + +.has-background-warning-85-invert { + background-color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-85-invert-l)) !important; +} + +.has-text-warning-90 { + color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-90-l)) !important; +} + +.has-background-warning-90 { + background-color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-90-l)) !important; +} + +.has-text-warning-90-invert { + color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-90-invert-l)) !important; +} + +.has-background-warning-90-invert { + background-color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-90-invert-l)) !important; +} + +.has-text-warning-95 { + color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-95-l)) !important; +} + +.has-background-warning-95 { + background-color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-95-l)) !important; +} + +.has-text-warning-95-invert { + color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-95-invert-l)) !important; +} + +.has-background-warning-95-invert { + background-color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-95-invert-l)) !important; +} + +.has-text-warning-100 { + color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-100-l)) !important; +} + +.has-background-warning-100 { + background-color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-100-l)) !important; +} + +.has-text-warning-100-invert { + color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-100-invert-l)) !important; +} + +.has-background-warning-100-invert { + background-color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), var(--bulma-warning-100-invert-l)) !important; +} + +a.has-text-warning:hover, a.has-text-warning:focus-visible, +button.has-text-warning:hover, +button.has-text-warning:focus-visible, +has-text-warning.is-hoverable:hover, +has-text-warning.is-hoverable:focus-visible { + color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), calc(var(--bulma-warning-l) + var(--bulma-hover-color-l-delta))) !important; +} +a.has-text-warning:active, +button.has-text-warning:active, +has-text-warning.is-hoverable:active { + color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), calc(var(--bulma-warning-l) + var(--bulma-active-color-l-delta))) !important; +} + +a.has-background-warning:hover, a.has-background-warning:focus-visible, +button.has-background-warning:hover, +button.has-background-warning:focus-visible, +has-background-warning.is-hoverable:hover, +has-background-warning.is-hoverable:focus-visible { + background-color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), calc(var(--bulma-warning-l) + var(--bulma-hover-background-l-delta))) !important; +} +a.has-background-warning:active, +button.has-background-warning:active, +has-background-warning.is-hoverable:active { + background-color: hsl(var(--bulma-warning-h), var(--bulma-warning-s), calc(var(--bulma-warning-l) + var(--bulma-active-background-l-delta))) !important; +} + +.is-palette-warning { + --h: var(--bulma-warning-h); + --s: var(--bulma-warning-s); + --l: var(--bulma-warning-l); + --color: hsl(var(--h), var(--s), var(--l)); + --00-l: var(--bulma-warning-00-l); + --color-00: hsl(var(--h), var(--s), var(--00-l)); + --05-l: var(--bulma-warning-05-l); + --color-05: hsl(var(--h), var(--s), var(--05-l)); + --10-l: var(--bulma-warning-10-l); + --color-10: hsl(var(--h), var(--s), var(--10-l)); + --15-l: var(--bulma-warning-15-l); + --color-15: hsl(var(--h), var(--s), var(--15-l)); + --20-l: var(--bulma-warning-20-l); + --color-20: hsl(var(--h), var(--s), var(--20-l)); + --25-l: var(--bulma-warning-25-l); + --color-25: hsl(var(--h), var(--s), var(--25-l)); + --30-l: var(--bulma-warning-30-l); + --color-30: hsl(var(--h), var(--s), var(--30-l)); + --35-l: var(--bulma-warning-35-l); + --color-35: hsl(var(--h), var(--s), var(--35-l)); + --40-l: var(--bulma-warning-40-l); + --color-40: hsl(var(--h), var(--s), var(--40-l)); + --45-l: var(--bulma-warning-45-l); + --color-45: hsl(var(--h), var(--s), var(--45-l)); + --50-l: var(--bulma-warning-50-l); + --color-50: hsl(var(--h), var(--s), var(--50-l)); + --55-l: var(--bulma-warning-55-l); + --color-55: hsl(var(--h), var(--s), var(--55-l)); + --60-l: var(--bulma-warning-60-l); + --color-60: hsl(var(--h), var(--s), var(--60-l)); + --65-l: var(--bulma-warning-65-l); + --color-65: hsl(var(--h), var(--s), var(--65-l)); + --70-l: var(--bulma-warning-70-l); + --color-70: hsl(var(--h), var(--s), var(--70-l)); + --75-l: var(--bulma-warning-75-l); + --color-75: hsl(var(--h), var(--s), var(--75-l)); + --80-l: var(--bulma-warning-80-l); + --color-80: hsl(var(--h), var(--s), var(--80-l)); + --85-l: var(--bulma-warning-85-l); + --color-85: hsl(var(--h), var(--s), var(--85-l)); + --90-l: var(--bulma-warning-90-l); + --color-90: hsl(var(--h), var(--s), var(--90-l)); + --95-l: var(--bulma-warning-95-l); + --color-95: hsl(var(--h), var(--s), var(--95-l)); + --100-l: var(--bulma-warning-100-l); + --color-100: hsl(var(--h), var(--s), var(--100-l)); +} + +.has-text-danger { + color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-l)) !important; +} + +.has-background-danger { + background-color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-l)) !important; +} + +.has-text-danger-invert { + color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-invert-l)) !important; +} + +.has-background-danger-invert { + background-color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-invert-l)) !important; +} + +.has-text-danger-on-scheme { + color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-on-scheme-l)) !important; +} + +.has-background-danger-on-scheme { + background-color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-on-scheme-l)) !important; +} + +.has-text-danger-light { + color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-light-l)) !important; +} + +.has-background-danger-light { + background-color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-light-l)) !important; +} + +.has-text-danger-light-invert { + color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-light-invert-l)) !important; +} + +.has-background-danger-light-invert { + background-color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-light-invert-l)) !important; +} + +.has-text-danger-dark { + color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-dark-l)) !important; +} + +.has-background-danger-dark { + background-color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-dark-l)) !important; +} + +.has-text-danger-dark-invert { + color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-dark-invert-l)) !important; +} + +.has-background-danger-dark-invert { + background-color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-dark-invert-l)) !important; +} + +.has-text-danger-soft { + color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-soft-l)) !important; +} + +.has-background-danger-soft { + background-color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-soft-l)) !important; +} + +.has-text-danger-bold { + color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-bold-l)) !important; +} + +.has-background-danger-bold { + background-color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-bold-l)) !important; +} + +.has-text-danger-soft-invert { + color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-soft-invert-l)) !important; +} + +.has-background-danger-soft-invert { + background-color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-soft-invert-l)) !important; +} + +.has-text-danger-bold-invert { + color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-bold-invert-l)) !important; +} + +.has-background-danger-bold-invert { + background-color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-bold-invert-l)) !important; +} + +.has-text-danger-00 { + color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-00-l)) !important; +} + +.has-background-danger-00 { + background-color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-00-l)) !important; +} + +.has-text-danger-00-invert { + color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-00-invert-l)) !important; +} + +.has-background-danger-00-invert { + background-color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-00-invert-l)) !important; +} + +.has-text-danger-05 { + color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-05-l)) !important; +} + +.has-background-danger-05 { + background-color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-05-l)) !important; +} + +.has-text-danger-05-invert { + color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-05-invert-l)) !important; +} + +.has-background-danger-05-invert { + background-color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-05-invert-l)) !important; +} + +.has-text-danger-10 { + color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-10-l)) !important; +} + +.has-background-danger-10 { + background-color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-10-l)) !important; +} + +.has-text-danger-10-invert { + color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-10-invert-l)) !important; +} + +.has-background-danger-10-invert { + background-color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-10-invert-l)) !important; +} + +.has-text-danger-15 { + color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-15-l)) !important; +} + +.has-background-danger-15 { + background-color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-15-l)) !important; +} + +.has-text-danger-15-invert { + color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-15-invert-l)) !important; +} + +.has-background-danger-15-invert { + background-color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-15-invert-l)) !important; +} + +.has-text-danger-20 { + color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-20-l)) !important; +} + +.has-background-danger-20 { + background-color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-20-l)) !important; +} + +.has-text-danger-20-invert { + color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-20-invert-l)) !important; +} + +.has-background-danger-20-invert { + background-color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-20-invert-l)) !important; +} + +.has-text-danger-25 { + color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-25-l)) !important; +} + +.has-background-danger-25 { + background-color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-25-l)) !important; +} + +.has-text-danger-25-invert { + color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-25-invert-l)) !important; +} + +.has-background-danger-25-invert { + background-color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-25-invert-l)) !important; +} + +.has-text-danger-30 { + color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-30-l)) !important; +} + +.has-background-danger-30 { + background-color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-30-l)) !important; +} + +.has-text-danger-30-invert { + color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-30-invert-l)) !important; +} + +.has-background-danger-30-invert { + background-color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-30-invert-l)) !important; +} + +.has-text-danger-35 { + color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-35-l)) !important; +} + +.has-background-danger-35 { + background-color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-35-l)) !important; +} + +.has-text-danger-35-invert { + color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-35-invert-l)) !important; +} + +.has-background-danger-35-invert { + background-color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-35-invert-l)) !important; +} + +.has-text-danger-40 { + color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-40-l)) !important; +} + +.has-background-danger-40 { + background-color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-40-l)) !important; +} + +.has-text-danger-40-invert { + color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-40-invert-l)) !important; +} + +.has-background-danger-40-invert { + background-color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-40-invert-l)) !important; +} + +.has-text-danger-45 { + color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-45-l)) !important; +} + +.has-background-danger-45 { + background-color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-45-l)) !important; +} + +.has-text-danger-45-invert { + color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-45-invert-l)) !important; +} + +.has-background-danger-45-invert { + background-color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-45-invert-l)) !important; +} + +.has-text-danger-50 { + color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-50-l)) !important; +} + +.has-background-danger-50 { + background-color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-50-l)) !important; +} + +.has-text-danger-50-invert { + color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-50-invert-l)) !important; +} + +.has-background-danger-50-invert { + background-color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-50-invert-l)) !important; +} + +.has-text-danger-55 { + color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-55-l)) !important; +} + +.has-background-danger-55 { + background-color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-55-l)) !important; +} + +.has-text-danger-55-invert { + color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-55-invert-l)) !important; +} + +.has-background-danger-55-invert { + background-color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-55-invert-l)) !important; +} + +.has-text-danger-60 { + color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-60-l)) !important; +} + +.has-background-danger-60 { + background-color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-60-l)) !important; +} + +.has-text-danger-60-invert { + color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-60-invert-l)) !important; +} + +.has-background-danger-60-invert { + background-color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-60-invert-l)) !important; +} + +.has-text-danger-65 { + color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-65-l)) !important; +} + +.has-background-danger-65 { + background-color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-65-l)) !important; +} + +.has-text-danger-65-invert { + color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-65-invert-l)) !important; +} + +.has-background-danger-65-invert { + background-color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-65-invert-l)) !important; +} + +.has-text-danger-70 { + color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-70-l)) !important; +} + +.has-background-danger-70 { + background-color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-70-l)) !important; +} + +.has-text-danger-70-invert { + color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-70-invert-l)) !important; +} + +.has-background-danger-70-invert { + background-color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-70-invert-l)) !important; +} + +.has-text-danger-75 { + color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-75-l)) !important; +} + +.has-background-danger-75 { + background-color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-75-l)) !important; +} + +.has-text-danger-75-invert { + color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-75-invert-l)) !important; +} + +.has-background-danger-75-invert { + background-color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-75-invert-l)) !important; +} + +.has-text-danger-80 { + color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-80-l)) !important; +} + +.has-background-danger-80 { + background-color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-80-l)) !important; +} + +.has-text-danger-80-invert { + color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-80-invert-l)) !important; +} + +.has-background-danger-80-invert { + background-color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-80-invert-l)) !important; +} + +.has-text-danger-85 { + color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-85-l)) !important; +} + +.has-background-danger-85 { + background-color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-85-l)) !important; +} + +.has-text-danger-85-invert { + color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-85-invert-l)) !important; +} + +.has-background-danger-85-invert { + background-color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-85-invert-l)) !important; +} + +.has-text-danger-90 { + color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-90-l)) !important; +} + +.has-background-danger-90 { + background-color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-90-l)) !important; +} + +.has-text-danger-90-invert { + color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-90-invert-l)) !important; +} + +.has-background-danger-90-invert { + background-color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-90-invert-l)) !important; +} + +.has-text-danger-95 { + color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-95-l)) !important; +} + +.has-background-danger-95 { + background-color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-95-l)) !important; +} + +.has-text-danger-95-invert { + color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-95-invert-l)) !important; +} + +.has-background-danger-95-invert { + background-color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-95-invert-l)) !important; +} + +.has-text-danger-100 { + color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-100-l)) !important; +} + +.has-background-danger-100 { + background-color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-100-l)) !important; +} + +.has-text-danger-100-invert { + color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-100-invert-l)) !important; +} + +.has-background-danger-100-invert { + background-color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), var(--bulma-danger-100-invert-l)) !important; +} + +a.has-text-danger:hover, a.has-text-danger:focus-visible, +button.has-text-danger:hover, +button.has-text-danger:focus-visible, +has-text-danger.is-hoverable:hover, +has-text-danger.is-hoverable:focus-visible { + color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), calc(var(--bulma-danger-l) + var(--bulma-hover-color-l-delta))) !important; +} +a.has-text-danger:active, +button.has-text-danger:active, +has-text-danger.is-hoverable:active { + color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), calc(var(--bulma-danger-l) + var(--bulma-active-color-l-delta))) !important; +} + +a.has-background-danger:hover, a.has-background-danger:focus-visible, +button.has-background-danger:hover, +button.has-background-danger:focus-visible, +has-background-danger.is-hoverable:hover, +has-background-danger.is-hoverable:focus-visible { + background-color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), calc(var(--bulma-danger-l) + var(--bulma-hover-background-l-delta))) !important; +} +a.has-background-danger:active, +button.has-background-danger:active, +has-background-danger.is-hoverable:active { + background-color: hsl(var(--bulma-danger-h), var(--bulma-danger-s), calc(var(--bulma-danger-l) + var(--bulma-active-background-l-delta))) !important; +} + +.is-palette-danger { + --h: var(--bulma-danger-h); + --s: var(--bulma-danger-s); + --l: var(--bulma-danger-l); + --color: hsl(var(--h), var(--s), var(--l)); + --00-l: var(--bulma-danger-00-l); + --color-00: hsl(var(--h), var(--s), var(--00-l)); + --05-l: var(--bulma-danger-05-l); + --color-05: hsl(var(--h), var(--s), var(--05-l)); + --10-l: var(--bulma-danger-10-l); + --color-10: hsl(var(--h), var(--s), var(--10-l)); + --15-l: var(--bulma-danger-15-l); + --color-15: hsl(var(--h), var(--s), var(--15-l)); + --20-l: var(--bulma-danger-20-l); + --color-20: hsl(var(--h), var(--s), var(--20-l)); + --25-l: var(--bulma-danger-25-l); + --color-25: hsl(var(--h), var(--s), var(--25-l)); + --30-l: var(--bulma-danger-30-l); + --color-30: hsl(var(--h), var(--s), var(--30-l)); + --35-l: var(--bulma-danger-35-l); + --color-35: hsl(var(--h), var(--s), var(--35-l)); + --40-l: var(--bulma-danger-40-l); + --color-40: hsl(var(--h), var(--s), var(--40-l)); + --45-l: var(--bulma-danger-45-l); + --color-45: hsl(var(--h), var(--s), var(--45-l)); + --50-l: var(--bulma-danger-50-l); + --color-50: hsl(var(--h), var(--s), var(--50-l)); + --55-l: var(--bulma-danger-55-l); + --color-55: hsl(var(--h), var(--s), var(--55-l)); + --60-l: var(--bulma-danger-60-l); + --color-60: hsl(var(--h), var(--s), var(--60-l)); + --65-l: var(--bulma-danger-65-l); + --color-65: hsl(var(--h), var(--s), var(--65-l)); + --70-l: var(--bulma-danger-70-l); + --color-70: hsl(var(--h), var(--s), var(--70-l)); + --75-l: var(--bulma-danger-75-l); + --color-75: hsl(var(--h), var(--s), var(--75-l)); + --80-l: var(--bulma-danger-80-l); + --color-80: hsl(var(--h), var(--s), var(--80-l)); + --85-l: var(--bulma-danger-85-l); + --color-85: hsl(var(--h), var(--s), var(--85-l)); + --90-l: var(--bulma-danger-90-l); + --color-90: hsl(var(--h), var(--s), var(--90-l)); + --95-l: var(--bulma-danger-95-l); + --color-95: hsl(var(--h), var(--s), var(--95-l)); + --100-l: var(--bulma-danger-100-l); + --color-100: hsl(var(--h), var(--s), var(--100-l)); +} + +.has-text-black-bis { + color: hsl(221, 14%, 9%) !important; +} + +.has-background-black-bis { + background-color: hsl(221, 14%, 9%) !important; +} + +.has-text-black-ter { + color: hsl(221, 14%, 14%) !important; +} + +.has-background-black-ter { + background-color: hsl(221, 14%, 14%) !important; +} + +.has-text-grey-darker { + color: hsl(221, 14%, 21%) !important; +} + +.has-background-grey-darker { + background-color: hsl(221, 14%, 21%) !important; +} + +.has-text-grey-dark { + color: hsl(221, 14%, 29%) !important; +} + +.has-background-grey-dark { + background-color: hsl(221, 14%, 29%) !important; +} + +.has-text-grey { + color: hsl(221, 14%, 48%) !important; +} + +.has-background-grey { + background-color: hsl(221, 14%, 48%) !important; +} + +.has-text-grey-light { + color: hsl(221, 14%, 71%) !important; +} + +.has-background-grey-light { + background-color: hsl(221, 14%, 71%) !important; +} + +.has-text-grey-lighter { + color: hsl(221, 14%, 86%) !important; +} + +.has-background-grey-lighter { + background-color: hsl(221, 14%, 86%) !important; +} + +.has-text-white-ter { + color: hsl(221, 14%, 96%) !important; +} + +.has-background-white-ter { + background-color: hsl(221, 14%, 96%) !important; +} + +.has-text-white-bis { + color: hsl(221, 14%, 98%) !important; +} + +.has-background-white-bis { + background-color: hsl(221, 14%, 98%) !important; +} + +.has-text-current { + color: currentColor !important; +} + +.has-text-inherit { + color: inherit !important; +} + +.has-background-current { + background-color: currentColor !important; +} + +.has-background-inherit { + background-color: inherit !important; +} + +.is-flex-direction-row { + flex-direction: row !important; +} + +.is-flex-direction-row-reverse { + flex-direction: row-reverse !important; +} + +.is-flex-direction-column { + flex-direction: column !important; +} + +.is-flex-direction-column-reverse { + flex-direction: column-reverse !important; +} + +.is-flex-wrap-nowrap { + flex-wrap: nowrap !important; +} + +.is-flex-wrap-wrap { + flex-wrap: wrap !important; +} + +.is-flex-wrap-wrap-reverse { + flex-wrap: wrap-reverse !important; +} + +.is-justify-content-flex-start { + justify-content: flex-start !important; +} + +.is-justify-content-flex-end { + justify-content: flex-end !important; +} + +.is-justify-content-center { + justify-content: center !important; +} + +.is-justify-content-space-between { + justify-content: space-between !important; +} + +.is-justify-content-space-around { + justify-content: space-around !important; +} + +.is-justify-content-space-evenly { + justify-content: space-evenly !important; +} + +.is-justify-content-start { + justify-content: start !important; +} + +.is-justify-content-end { + justify-content: end !important; +} + +.is-justify-content-left { + justify-content: left !important; +} + +.is-justify-content-right { + justify-content: right !important; +} + +.is-align-content-flex-start { + align-content: flex-start !important; +} + +.is-align-content-flex-end { + align-content: flex-end !important; +} + +.is-align-content-center { + align-content: center !important; +} + +.is-align-content-space-between { + align-content: space-between !important; +} + +.is-align-content-space-around { + align-content: space-around !important; +} + +.is-align-content-space-evenly { + align-content: space-evenly !important; +} + +.is-align-content-stretch { + align-content: stretch !important; +} + +.is-align-content-start { + align-content: start !important; +} + +.is-align-content-end { + align-content: end !important; +} + +.is-align-content-baseline { + align-content: baseline !important; +} + +.is-align-items-stretch { + align-items: stretch !important; +} + +.is-align-items-flex-start { + align-items: flex-start !important; +} + +.is-align-items-flex-end { + align-items: flex-end !important; +} + +.is-align-items-center { + align-items: center !important; +} + +.is-align-items-baseline { + align-items: baseline !important; +} + +.is-align-items-start { + align-items: start !important; +} + +.is-align-items-end { + align-items: end !important; +} + +.is-align-items-self-start { + align-items: self-start !important; +} + +.is-align-items-self-end { + align-items: self-end !important; +} + +.is-align-self-auto { + align-self: auto !important; +} + +.is-align-self-flex-start { + align-self: flex-start !important; +} + +.is-align-self-flex-end { + align-self: flex-end !important; +} + +.is-align-self-center { + align-self: center !important; +} + +.is-align-self-baseline { + align-self: baseline !important; +} + +.is-align-self-stretch { + align-self: stretch !important; +} + +.is-flex-grow-0 { + flex-grow: 0 !important; +} + +.is-flex-grow-1 { + flex-grow: 1 !important; +} + +.is-flex-grow-2 { + flex-grow: 2 !important; +} + +.is-flex-grow-3 { + flex-grow: 3 !important; +} + +.is-flex-grow-4 { + flex-grow: 4 !important; +} + +.is-flex-grow-5 { + flex-grow: 5 !important; +} + +.is-flex-shrink-0 { + flex-shrink: 0 !important; +} + +.is-flex-shrink-1 { + flex-shrink: 1 !important; +} + +.is-flex-shrink-2 { + flex-shrink: 2 !important; +} + +.is-flex-shrink-3 { + flex-shrink: 3 !important; +} + +.is-flex-shrink-4 { + flex-shrink: 4 !important; +} + +.is-flex-shrink-5 { + flex-shrink: 5 !important; +} + +.is-clearfix::after { + clear: both; + content: " "; + display: table; +} + +.is-float-left, +.is-pulled-left { + float: left !important; +} + +.is-float-right, +.is-pulled-right { + float: right !important; +} + +.is-float-none { + float: none !important; +} + +.is-clear-both { + clear: both !important; +} + +.is-clear-left { + clear: left !important; +} + +.is-clear-none { + clear: none !important; +} + +.is-clear-right { + clear: right !important; +} + +.is-gapless { + gap: 0 !important; +} + +.is-gap-0 { + gap: 0rem !important; +} + +.is-gap-0\.5 { + gap: 0.25rem !important; +} + +.is-gap-1 { + gap: 0.5rem !important; +} + +.is-gap-1\.5 { + gap: 0.75rem !important; +} + +.is-gap-2 { + gap: 1rem !important; +} + +.is-gap-2\.5 { + gap: 1.25rem !important; +} + +.is-gap-3 { + gap: 1.5rem !important; +} + +.is-gap-3\.5 { + gap: 1.75rem !important; +} + +.is-gap-4 { + gap: 2rem !important; +} + +.is-gap-4\.5 { + gap: 2.25rem !important; +} + +.is-gap-5 { + gap: 2.5rem !important; +} + +.is-gap-5\.5 { + gap: 2.75rem !important; +} + +.is-gap-6 { + gap: 3rem !important; +} + +.is-gap-6\.5 { + gap: 3.25rem !important; +} + +.is-gap-7 { + gap: 3.5rem !important; +} + +.is-gap-7\.5 { + gap: 3.75rem !important; +} + +.is-gap-8 { + gap: 4rem !important; +} + +.is-column-gap-0 { + column-gap: 0rem !important; +} + +.is-column-gap-0\.5 { + column-gap: 0.25rem !important; +} + +.is-column-gap-1 { + column-gap: 0.5rem !important; +} + +.is-column-gap-1\.5 { + column-gap: 0.75rem !important; +} + +.is-column-gap-2 { + column-gap: 1rem !important; +} + +.is-column-gap-2\.5 { + column-gap: 1.25rem !important; +} + +.is-column-gap-3 { + column-gap: 1.5rem !important; +} + +.is-column-gap-3\.5 { + column-gap: 1.75rem !important; +} + +.is-column-gap-4 { + column-gap: 2rem !important; +} + +.is-column-gap-4\.5 { + column-gap: 2.25rem !important; +} + +.is-column-gap-5 { + column-gap: 2.5rem !important; +} + +.is-column-gap-5\.5 { + column-gap: 2.75rem !important; +} + +.is-column-gap-6 { + column-gap: 3rem !important; +} + +.is-column-gap-6\.5 { + column-gap: 3.25rem !important; +} + +.is-column-gap-7 { + column-gap: 3.5rem !important; +} + +.is-column-gap-7\.5 { + column-gap: 3.75rem !important; +} + +.is-column-gap-8 { + column-gap: 4rem !important; +} + +.is-row-gap-0 { + row-gap: 0rem !important; +} + +.is-row-gap-0\.5 { + row-gap: 0.25rem !important; +} + +.is-row-gap-1 { + row-gap: 0.5rem !important; +} + +.is-row-gap-1\.5 { + row-gap: 0.75rem !important; +} + +.is-row-gap-2 { + row-gap: 1rem !important; +} + +.is-row-gap-2\.5 { + row-gap: 1.25rem !important; +} + +.is-row-gap-3 { + row-gap: 1.5rem !important; +} + +.is-row-gap-3\.5 { + row-gap: 1.75rem !important; +} + +.is-row-gap-4 { + row-gap: 2rem !important; +} + +.is-row-gap-4\.5 { + row-gap: 2.25rem !important; +} + +.is-row-gap-5 { + row-gap: 2.5rem !important; +} + +.is-row-gap-5\.5 { + row-gap: 2.75rem !important; +} + +.is-row-gap-6 { + row-gap: 3rem !important; +} + +.is-row-gap-6\.5 { + row-gap: 3.25rem !important; +} + +.is-row-gap-7 { + row-gap: 3.5rem !important; +} + +.is-row-gap-7\.5 { + row-gap: 3.75rem !important; +} + +.is-row-gap-8 { + row-gap: 4rem !important; +} + +.is-clipped { + overflow: hidden !important; +} + +.is-overflow-auto { + overflow: auto !important; +} + +.is-overflow-x-auto { + overflow-x: auto !important; +} + +.is-overflow-y-auto { + overflow-y: auto !important; +} + +.is-overflow-clip { + overflow: clip !important; +} + +.is-overflow-x-clip { + overflow-x: clip !important; +} + +.is-overflow-y-clip { + overflow-y: clip !important; +} + +.is-overflow-hidden { + overflow: hidden !important; +} + +.is-overflow-x-hidden { + overflow-x: hidden !important; +} + +.is-overflow-y-hidden { + overflow-y: hidden !important; +} + +.is-overflow-scroll { + overflow: scroll !important; +} + +.is-overflow-x-scroll { + overflow-x: scroll !important; +} + +.is-overflow-y-scroll { + overflow-y: scroll !important; +} + +.is-overflow-visible { + overflow: visible !important; +} + +.is-overflow-x-visible { + overflow-x: visible !important; +} + +.is-overflow-y-visible { + overflow-y: visible !important; +} + +.is-relative { + position: relative !important; +} + +.is-position-absolute { + position: absolute !important; +} + +.is-position-fixed { + position: fixed !important; +} + +.is-position-relative { + position: relative !important; +} + +.is-position-static { + position: static !important; +} + +.is-position-sticky { + position: sticky !important; +} + +.marginless { + margin: 0 !important; +} + +.paddingless { + padding: 0 !important; +} + +.m-0 { + margin: 0 !important; +} + +.mt-0 { + margin-top: 0 !important; +} + +.mr-0 { + margin-right: 0 !important; +} + +.mb-0 { + margin-bottom: 0 !important; +} + +.ml-0 { + margin-left: 0 !important; +} + +.mx-0 { + margin-left: 0 !important; + margin-right: 0 !important; +} + +.my-0 { + margin-top: 0 !important; + margin-bottom: 0 !important; +} + +.m-1 { + margin: 0.25rem !important; +} + +.mt-1 { + margin-top: 0.25rem !important; +} + +.mr-1 { + margin-right: 0.25rem !important; +} + +.mb-1 { + margin-bottom: 0.25rem !important; +} + +.ml-1 { + margin-left: 0.25rem !important; +} + +.mx-1 { + margin-left: 0.25rem !important; + margin-right: 0.25rem !important; +} + +.my-1 { + margin-top: 0.25rem !important; + margin-bottom: 0.25rem !important; +} + +.m-2 { + margin: 0.5rem !important; +} + +.mt-2 { + margin-top: 0.5rem !important; +} + +.mr-2 { + margin-right: 0.5rem !important; +} + +.mb-2 { + margin-bottom: 0.5rem !important; +} + +.ml-2 { + margin-left: 0.5rem !important; +} + +.mx-2 { + margin-left: 0.5rem !important; + margin-right: 0.5rem !important; +} + +.my-2 { + margin-top: 0.5rem !important; + margin-bottom: 0.5rem !important; +} + +.m-3 { + margin: 0.75rem !important; +} + +.mt-3 { + margin-top: 0.75rem !important; +} + +.mr-3 { + margin-right: 0.75rem !important; +} + +.mb-3 { + margin-bottom: 0.75rem !important; +} + +.ml-3 { + margin-left: 0.75rem !important; +} + +.mx-3 { + margin-left: 0.75rem !important; + margin-right: 0.75rem !important; +} + +.my-3 { + margin-top: 0.75rem !important; + margin-bottom: 0.75rem !important; +} + +.m-4 { + margin: 1rem !important; +} + +.mt-4 { + margin-top: 1rem !important; +} + +.mr-4 { + margin-right: 1rem !important; +} + +.mb-4 { + margin-bottom: 1rem !important; +} + +.ml-4 { + margin-left: 1rem !important; +} + +.mx-4 { + margin-left: 1rem !important; + margin-right: 1rem !important; +} + +.my-4 { + margin-top: 1rem !important; + margin-bottom: 1rem !important; +} + +.m-5 { + margin: 1.5rem !important; +} + +.mt-5 { + margin-top: 1.5rem !important; +} + +.mr-5 { + margin-right: 1.5rem !important; +} + +.mb-5 { + margin-bottom: 1.5rem !important; +} + +.ml-5 { + margin-left: 1.5rem !important; +} + +.mx-5 { + margin-left: 1.5rem !important; + margin-right: 1.5rem !important; +} + +.my-5 { + margin-top: 1.5rem !important; + margin-bottom: 1.5rem !important; +} + +.m-6 { + margin: 3rem !important; +} + +.mt-6 { + margin-top: 3rem !important; +} + +.mr-6 { + margin-right: 3rem !important; +} + +.mb-6 { + margin-bottom: 3rem !important; +} + +.ml-6 { + margin-left: 3rem !important; +} + +.mx-6 { + margin-left: 3rem !important; + margin-right: 3rem !important; +} + +.my-6 { + margin-top: 3rem !important; + margin-bottom: 3rem !important; +} + +.m-auto { + margin: auto !important; +} + +.mt-auto { + margin-top: auto !important; +} + +.mr-auto { + margin-right: auto !important; +} + +.mb-auto { + margin-bottom: auto !important; +} + +.ml-auto { + margin-left: auto !important; +} + +.mx-auto { + margin-left: auto !important; + margin-right: auto !important; +} + +.my-auto { + margin-top: auto !important; + margin-bottom: auto !important; +} + +.p-0 { + padding: 0 !important; +} + +.pt-0 { + padding-top: 0 !important; +} + +.pr-0 { + padding-right: 0 !important; +} + +.pb-0 { + padding-bottom: 0 !important; +} + +.pl-0 { + padding-left: 0 !important; +} + +.px-0 { + padding-left: 0 !important; + padding-right: 0 !important; +} + +.py-0 { + padding-top: 0 !important; + padding-bottom: 0 !important; +} + +.p-1 { + padding: 0.25rem !important; +} + +.pt-1 { + padding-top: 0.25rem !important; +} + +.pr-1 { + padding-right: 0.25rem !important; +} + +.pb-1 { + padding-bottom: 0.25rem !important; +} + +.pl-1 { + padding-left: 0.25rem !important; +} + +.px-1 { + padding-left: 0.25rem !important; + padding-right: 0.25rem !important; +} + +.py-1 { + padding-top: 0.25rem !important; + padding-bottom: 0.25rem !important; +} + +.p-2 { + padding: 0.5rem !important; +} + +.pt-2 { + padding-top: 0.5rem !important; +} + +.pr-2 { + padding-right: 0.5rem !important; +} + +.pb-2 { + padding-bottom: 0.5rem !important; +} + +.pl-2 { + padding-left: 0.5rem !important; +} + +.px-2 { + padding-left: 0.5rem !important; + padding-right: 0.5rem !important; +} + +.py-2 { + padding-top: 0.5rem !important; + padding-bottom: 0.5rem !important; +} + +.p-3 { + padding: 0.75rem !important; +} + +.pt-3 { + padding-top: 0.75rem !important; +} + +.pr-3 { + padding-right: 0.75rem !important; +} + +.pb-3 { + padding-bottom: 0.75rem !important; +} + +.pl-3 { + padding-left: 0.75rem !important; +} + +.px-3 { + padding-left: 0.75rem !important; + padding-right: 0.75rem !important; +} + +.py-3 { + padding-top: 0.75rem !important; + padding-bottom: 0.75rem !important; +} + +.p-4 { + padding: 1rem !important; +} + +.pt-4 { + padding-top: 1rem !important; +} + +.pr-4 { + padding-right: 1rem !important; +} + +.pb-4 { + padding-bottom: 1rem !important; +} + +.pl-4 { + padding-left: 1rem !important; +} + +.px-4 { + padding-left: 1rem !important; + padding-right: 1rem !important; +} + +.py-4 { + padding-top: 1rem !important; + padding-bottom: 1rem !important; +} + +.p-5 { + padding: 1.5rem !important; +} + +.pt-5 { + padding-top: 1.5rem !important; +} + +.pr-5 { + padding-right: 1.5rem !important; +} + +.pb-5 { + padding-bottom: 1.5rem !important; +} + +.pl-5 { + padding-left: 1.5rem !important; +} + +.px-5 { + padding-left: 1.5rem !important; + padding-right: 1.5rem !important; +} + +.py-5 { + padding-top: 1.5rem !important; + padding-bottom: 1.5rem !important; +} + +.p-6 { + padding: 3rem !important; +} + +.pt-6 { + padding-top: 3rem !important; +} + +.pr-6 { + padding-right: 3rem !important; +} + +.pb-6 { + padding-bottom: 3rem !important; +} + +.pl-6 { + padding-left: 3rem !important; +} + +.px-6 { + padding-left: 3rem !important; + padding-right: 3rem !important; +} + +.py-6 { + padding-top: 3rem !important; + padding-bottom: 3rem !important; +} + +.p-auto { + padding: auto !important; +} + +.pt-auto { + padding-top: auto !important; +} + +.pr-auto { + padding-right: auto !important; +} + +.pb-auto { + padding-bottom: auto !important; +} + +.pl-auto { + padding-left: auto !important; +} + +.px-auto { + padding-left: auto !important; + padding-right: auto !important; +} + +.py-auto { + padding-top: auto !important; + padding-bottom: auto !important; +} + +.is-size-1 { + font-size: 3rem !important; +} + +.is-size-2 { + font-size: 2.5rem !important; +} + +.is-size-3 { + font-size: 2rem !important; +} + +.is-size-4 { + font-size: 1.5rem !important; +} + +.is-size-5 { + font-size: 1.25rem !important; +} + +.is-size-6 { + font-size: 1rem !important; +} + +.is-size-7 { + font-size: 0.75rem !important; +} + +@media screen and (max-width: 768px) { + .is-size-1-mobile { + font-size: 3rem !important; + } + .is-size-2-mobile { + font-size: 2.5rem !important; + } + .is-size-3-mobile { + font-size: 2rem !important; + } + .is-size-4-mobile { + font-size: 1.5rem !important; + } + .is-size-5-mobile { + font-size: 1.25rem !important; + } + .is-size-6-mobile { + font-size: 1rem !important; + } + .is-size-7-mobile { + font-size: 0.75rem !important; + } +} +@media screen and (min-width: 769px), print { + .is-size-1-tablet { + font-size: 3rem !important; + } + .is-size-2-tablet { + font-size: 2.5rem !important; + } + .is-size-3-tablet { + font-size: 2rem !important; + } + .is-size-4-tablet { + font-size: 1.5rem !important; + } + .is-size-5-tablet { + font-size: 1.25rem !important; + } + .is-size-6-tablet { + font-size: 1rem !important; + } + .is-size-7-tablet { + font-size: 0.75rem !important; + } +} +@media screen and (max-width: 1023px) { + .is-size-1-touch { + font-size: 3rem !important; + } + .is-size-2-touch { + font-size: 2.5rem !important; + } + .is-size-3-touch { + font-size: 2rem !important; + } + .is-size-4-touch { + font-size: 1.5rem !important; + } + .is-size-5-touch { + font-size: 1.25rem !important; + } + .is-size-6-touch { + font-size: 1rem !important; + } + .is-size-7-touch { + font-size: 0.75rem !important; + } +} +@media screen and (min-width: 1024px) { + .is-size-1-desktop { + font-size: 3rem !important; + } + .is-size-2-desktop { + font-size: 2.5rem !important; + } + .is-size-3-desktop { + font-size: 2rem !important; + } + .is-size-4-desktop { + font-size: 1.5rem !important; + } + .is-size-5-desktop { + font-size: 1.25rem !important; + } + .is-size-6-desktop { + font-size: 1rem !important; + } + .is-size-7-desktop { + font-size: 0.75rem !important; + } +} +@media screen and (min-width: 1216px) { + .is-size-1-widescreen { + font-size: 3rem !important; + } + .is-size-2-widescreen { + font-size: 2.5rem !important; + } + .is-size-3-widescreen { + font-size: 2rem !important; + } + .is-size-4-widescreen { + font-size: 1.5rem !important; + } + .is-size-5-widescreen { + font-size: 1.25rem !important; + } + .is-size-6-widescreen { + font-size: 1rem !important; + } + .is-size-7-widescreen { + font-size: 0.75rem !important; + } +} +@media screen and (min-width: 1408px) { + .is-size-1-fullhd { + font-size: 3rem !important; + } + .is-size-2-fullhd { + font-size: 2.5rem !important; + } + .is-size-3-fullhd { + font-size: 2rem !important; + } + .is-size-4-fullhd { + font-size: 1.5rem !important; + } + .is-size-5-fullhd { + font-size: 1.25rem !important; + } + .is-size-6-fullhd { + font-size: 1rem !important; + } + .is-size-7-fullhd { + font-size: 0.75rem !important; + } +} +.has-text-centered { + text-align: center !important; +} + +.has-text-justified { + text-align: justify !important; +} + +.has-text-left { + text-align: left !important; +} + +.has-text-right { + text-align: right !important; +} + +@media screen and (max-width: 768px) { + .has-text-centered-mobile { + text-align: center !important; + } +} +@media screen and (min-width: 769px), print { + .has-text-centered-tablet { + text-align: center !important; + } +} +@media screen and (min-width: 769px) and (max-width: 1023px) { + .has-text-centered-tablet-only { + text-align: center !important; + } +} +@media screen and (max-width: 1023px) { + .has-text-centered-touch { + text-align: center !important; + } +} +@media screen and (min-width: 1024px) { + .has-text-centered-desktop { + text-align: center !important; + } +} +@media screen and (min-width: 1024px) and (max-width: 1215px) { + .has-text-centered-desktop-only { + text-align: center !important; + } +} +@media screen and (min-width: 1216px) { + .has-text-centered-widescreen { + text-align: center !important; + } +} +@media screen and (min-width: 1216px) and (max-width: 1407px) { + .has-text-centered-widescreen-only { + text-align: center !important; + } +} +@media screen and (min-width: 1408px) { + .has-text-centered-fullhd { + text-align: center !important; + } +} +@media screen and (max-width: 768px) { + .has-text-justified-mobile { + text-align: justify !important; + } +} +@media screen and (min-width: 769px), print { + .has-text-justified-tablet { + text-align: justify !important; + } +} +@media screen and (min-width: 769px) and (max-width: 1023px) { + .has-text-justified-tablet-only { + text-align: justify !important; + } +} +@media screen and (max-width: 1023px) { + .has-text-justified-touch { + text-align: justify !important; + } +} +@media screen and (min-width: 1024px) { + .has-text-justified-desktop { + text-align: justify !important; + } +} +@media screen and (min-width: 1024px) and (max-width: 1215px) { + .has-text-justified-desktop-only { + text-align: justify !important; + } +} +@media screen and (min-width: 1216px) { + .has-text-justified-widescreen { + text-align: justify !important; + } +} +@media screen and (min-width: 1216px) and (max-width: 1407px) { + .has-text-justified-widescreen-only { + text-align: justify !important; + } +} +@media screen and (min-width: 1408px) { + .has-text-justified-fullhd { + text-align: justify !important; + } +} +@media screen and (max-width: 768px) { + .has-text-left-mobile { + text-align: left !important; + } +} +@media screen and (min-width: 769px), print { + .has-text-left-tablet { + text-align: left !important; + } +} +@media screen and (min-width: 769px) and (max-width: 1023px) { + .has-text-left-tablet-only { + text-align: left !important; + } +} +@media screen and (max-width: 1023px) { + .has-text-left-touch { + text-align: left !important; + } +} +@media screen and (min-width: 1024px) { + .has-text-left-desktop { + text-align: left !important; + } +} +@media screen and (min-width: 1024px) and (max-width: 1215px) { + .has-text-left-desktop-only { + text-align: left !important; + } +} +@media screen and (min-width: 1216px) { + .has-text-left-widescreen { + text-align: left !important; + } +} +@media screen and (min-width: 1216px) and (max-width: 1407px) { + .has-text-left-widescreen-only { + text-align: left !important; + } +} +@media screen and (min-width: 1408px) { + .has-text-left-fullhd { + text-align: left !important; + } +} +@media screen and (max-width: 768px) { + .has-text-right-mobile { + text-align: right !important; + } +} +@media screen and (min-width: 769px), print { + .has-text-right-tablet { + text-align: right !important; + } +} +@media screen and (min-width: 769px) and (max-width: 1023px) { + .has-text-right-tablet-only { + text-align: right !important; + } +} +@media screen and (max-width: 1023px) { + .has-text-right-touch { + text-align: right !important; + } +} +@media screen and (min-width: 1024px) { + .has-text-right-desktop { + text-align: right !important; + } +} +@media screen and (min-width: 1024px) and (max-width: 1215px) { + .has-text-right-desktop-only { + text-align: right !important; + } +} +@media screen and (min-width: 1216px) { + .has-text-right-widescreen { + text-align: right !important; + } +} +@media screen and (min-width: 1216px) and (max-width: 1407px) { + .has-text-right-widescreen-only { + text-align: right !important; + } +} +@media screen and (min-width: 1408px) { + .has-text-right-fullhd { + text-align: right !important; + } +} +.is-capitalized { + text-transform: capitalize !important; +} + +.is-lowercase { + text-transform: lowercase !important; +} + +.is-uppercase { + text-transform: uppercase !important; +} + +.is-italic { + font-style: italic !important; +} + +.is-underlined { + text-decoration: underline !important; +} + +.has-text-weight-light { + font-weight: 300 !important; +} + +.has-text-weight-normal { + font-weight: 400 !important; +} + +.has-text-weight-medium { + font-weight: 500 !important; +} + +.has-text-weight-semibold { + font-weight: 600 !important; +} + +.has-text-weight-bold { + font-weight: 700 !important; +} + +.is-family-primary { + font-family: "Inter", "SF Pro", "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Helvetica Neue", "Helvetica", "Arial", sans-serif !important; +} + +.is-family-secondary { + font-family: "Inter", "SF Pro", "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Helvetica Neue", "Helvetica", "Arial", sans-serif !important; +} + +.is-family-sans-serif { + font-family: "Inter", "SF Pro", "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Helvetica Neue", "Helvetica", "Arial", sans-serif !important; +} + +.is-family-monospace { + font-family: "Inconsolata", "Hack", "SF Mono", "Roboto Mono", "Source Code Pro", "Ubuntu Mono", monospace !important; +} + +.is-family-code { + font-family: "Inconsolata", "Hack", "SF Mono", "Roboto Mono", "Source Code Pro", "Ubuntu Mono", monospace !important; +} + +.is-display-none, +.is-hidden { + display: none !important; +} + +.is-display-block, +.is-block { + display: block !important; +} + +@media screen and (max-width: 768px) { + .is-display-block-mobile, + .is-block-mobile { + display: block !important; + } +} +@media screen and (min-width: 769px), print { + .is-display-block-tablet, + .is-block-tablet { + display: block !important; + } +} +@media screen and (min-width: 769px) and (max-width: 1023px) { + .is-display-block-tablet-only, + .is-block-tablet-only { + display: block !important; + } +} +@media screen and (max-width: 1023px) { + .is-display-block-touch, + .is-block-touch { + display: block !important; + } +} +@media screen and (min-width: 1024px) { + .is-display-block-desktop, + .is-block-desktop { + display: block !important; + } +} +@media screen and (min-width: 1024px) and (max-width: 1215px) { + .is-display-block-desktop-only, + .is-block-desktop-only { + display: block !important; + } +} +@media screen and (min-width: 1216px) { + .is-display-block-widescreen, + .is-block-widescreen { + display: block !important; + } +} +@media screen and (min-width: 1216px) and (max-width: 1407px) { + .is-display-block-widescreen-only, + .is-block-widescreen-only { + display: block !important; + } +} +@media screen and (min-width: 1408px) { + .is-display-block-fullhd, + .is-block-fullhd { + display: block !important; + } +} +.is-display-flex, +.is-flex { + display: flex !important; +} + +@media screen and (max-width: 768px) { + .is-display-flex-mobile, + .is-flex-mobile { + display: flex !important; + } +} +@media screen and (min-width: 769px), print { + .is-display-flex-tablet, + .is-flex-tablet { + display: flex !important; + } +} +@media screen and (min-width: 769px) and (max-width: 1023px) { + .is-display-flex-tablet-only, + .is-flex-tablet-only { + display: flex !important; + } +} +@media screen and (max-width: 1023px) { + .is-display-flex-touch, + .is-flex-touch { + display: flex !important; + } +} +@media screen and (min-width: 1024px) { + .is-display-flex-desktop, + .is-flex-desktop { + display: flex !important; + } +} +@media screen and (min-width: 1024px) and (max-width: 1215px) { + .is-display-flex-desktop-only, + .is-flex-desktop-only { + display: flex !important; + } +} +@media screen and (min-width: 1216px) { + .is-display-flex-widescreen, + .is-flex-widescreen { + display: flex !important; + } +} +@media screen and (min-width: 1216px) and (max-width: 1407px) { + .is-display-flex-widescreen-only, + .is-flex-widescreen-only { + display: flex !important; + } +} +@media screen and (min-width: 1408px) { + .is-display-flex-fullhd, + .is-flex-fullhd { + display: flex !important; + } +} +.is-display-inline, +.is-inline { + display: inline !important; +} + +@media screen and (max-width: 768px) { + .is-display-inline-mobile, + .is-inline-mobile { + display: inline !important; + } +} +@media screen and (min-width: 769px), print { + .is-display-inline-tablet, + .is-inline-tablet { + display: inline !important; + } +} +@media screen and (min-width: 769px) and (max-width: 1023px) { + .is-display-inline-tablet-only, + .is-inline-tablet-only { + display: inline !important; + } +} +@media screen and (max-width: 1023px) { + .is-display-inline-touch, + .is-inline-touch { + display: inline !important; + } +} +@media screen and (min-width: 1024px) { + .is-display-inline-desktop, + .is-inline-desktop { + display: inline !important; + } +} +@media screen and (min-width: 1024px) and (max-width: 1215px) { + .is-display-inline-desktop-only, + .is-inline-desktop-only { + display: inline !important; + } +} +@media screen and (min-width: 1216px) { + .is-display-inline-widescreen, + .is-inline-widescreen { + display: inline !important; + } +} +@media screen and (min-width: 1216px) and (max-width: 1407px) { + .is-display-inline-widescreen-only, + .is-inline-widescreen-only { + display: inline !important; + } +} +@media screen and (min-width: 1408px) { + .is-display-inline-fullhd, + .is-inline-fullhd { + display: inline !important; + } +} +.is-display-inline-block, +.is-inline-block { + display: inline-block !important; +} + +@media screen and (max-width: 768px) { + .is-display-inline-block-mobile, + .is-inline-block-mobile { + display: inline-block !important; + } +} +@media screen and (min-width: 769px), print { + .is-display-inline-block-tablet, + .is-inline-block-tablet { + display: inline-block !important; + } +} +@media screen and (min-width: 769px) and (max-width: 1023px) { + .is-display-inline-block-tablet-only, + .is-inline-block-tablet-only { + display: inline-block !important; + } +} +@media screen and (max-width: 1023px) { + .is-display-inline-block-touch, + .is-inline-block-touch { + display: inline-block !important; + } +} +@media screen and (min-width: 1024px) { + .is-display-inline-block-desktop, + .is-inline-block-desktop { + display: inline-block !important; + } +} +@media screen and (min-width: 1024px) and (max-width: 1215px) { + .is-display-inline-block-desktop-only, + .is-inline-block-desktop-only { + display: inline-block !important; + } +} +@media screen and (min-width: 1216px) { + .is-display-inline-block-widescreen, + .is-inline-block-widescreen { + display: inline-block !important; + } +} +@media screen and (min-width: 1216px) and (max-width: 1407px) { + .is-display-inline-block-widescreen-only, + .is-inline-block-widescreen-only { + display: inline-block !important; + } +} +@media screen and (min-width: 1408px) { + .is-display-inline-block-fullhd, + .is-inline-block-fullhd { + display: inline-block !important; + } +} +.is-display-inline-flex, +.is-inline-flex { + display: inline-flex !important; +} + +@media screen and (max-width: 768px) { + .is-display-inline-flex-mobile, + .is-inline-flex-mobile { + display: inline-flex !important; + } +} +@media screen and (min-width: 769px), print { + .is-display-inline-flex-tablet, + .is-inline-flex-tablet { + display: inline-flex !important; + } +} +@media screen and (min-width: 769px) and (max-width: 1023px) { + .is-display-inline-flex-tablet-only, + .is-inline-flex-tablet-only { + display: inline-flex !important; + } +} +@media screen and (max-width: 1023px) { + .is-display-inline-flex-touch, + .is-inline-flex-touch { + display: inline-flex !important; + } +} +@media screen and (min-width: 1024px) { + .is-display-inline-flex-desktop, + .is-inline-flex-desktop { + display: inline-flex !important; + } +} +@media screen and (min-width: 1024px) and (max-width: 1215px) { + .is-display-inline-flex-desktop-only, + .is-inline-flex-desktop-only { + display: inline-flex !important; + } +} +@media screen and (min-width: 1216px) { + .is-display-inline-flex-widescreen, + .is-inline-flex-widescreen { + display: inline-flex !important; + } +} +@media screen and (min-width: 1216px) and (max-width: 1407px) { + .is-display-inline-flex-widescreen-only, + .is-inline-flex-widescreen-only { + display: inline-flex !important; + } +} +@media screen and (min-width: 1408px) { + .is-display-inline-flex-fullhd, + .is-inline-flex-fullhd { + display: inline-flex !important; + } +} +.is-display-grid, +.is-grid { + display: grid !important; +} + +@media screen and (max-width: 768px) { + .is-display-grid-mobile, + .is-grid-mobile { + display: grid !important; + } +} +@media screen and (min-width: 769px), print { + .is-display-grid-tablet, + .is-grid-tablet { + display: grid !important; + } +} +@media screen and (min-width: 769px) and (max-width: 1023px) { + .is-display-grid-tablet-only, + .is-grid-tablet-only { + display: grid !important; + } +} +@media screen and (max-width: 1023px) { + .is-display-grid-touch, + .is-grid-touch { + display: grid !important; + } +} +@media screen and (min-width: 1024px) { + .is-display-grid-desktop, + .is-grid-desktop { + display: grid !important; + } +} +@media screen and (min-width: 1024px) and (max-width: 1215px) { + .is-display-grid-desktop-only, + .is-grid-desktop-only { + display: grid !important; + } +} +@media screen and (min-width: 1216px) { + .is-display-grid-widescreen, + .is-grid-widescreen { + display: grid !important; + } +} +@media screen and (min-width: 1216px) and (max-width: 1407px) { + .is-display-grid-widescreen-only, + .is-grid-widescreen-only { + display: grid !important; + } +} +@media screen and (min-width: 1408px) { + .is-display-grid-fullhd, + .is-grid-fullhd { + display: grid !important; + } +} +.is-sr-only { + border: none !important; + clip: rect(0, 0, 0, 0) !important; + height: 0.01em !important; + overflow: hidden !important; + padding: 0 !important; + position: absolute !important; + white-space: nowrap !important; + width: 0.01em !important; +} + +@media screen and (max-width: 768px) { + .is-display-none-mobile, + .is-hidden-mobile { + display: none !important; + } +} +@media screen and (min-width: 769px), print { + .is-display-none-tablet, + .is-hidden-tablet { + display: none !important; + } +} +@media screen and (min-width: 769px) and (max-width: 1023px) { + .is-display-none-tablet-only, + .is-hidden-tablet-only { + display: none !important; + } +} +@media screen and (max-width: 1023px) { + .is-display-none-touch, + .is-hidden-touch { + display: none !important; + } +} +@media screen and (min-width: 1024px) { + .is-display-none-desktop, + .is-hidden-desktop { + display: none !important; + } +} +@media screen and (min-width: 1024px) and (max-width: 1215px) { + .is-display-none-desktop-only, + .is-hidden-desktop-only { + display: none !important; + } +} +@media screen and (min-width: 1216px) { + .is-display-none-widescreen, + .is-hidden-widescreen { + display: none !important; + } +} +@media screen and (min-width: 1216px) and (max-width: 1407px) { + .is-display-none-widescreen-only, + .is-hidden-widescreen-only { + display: none !important; + } +} +@media screen and (min-width: 1408px) { + .is-display-none-fullhd, + .is-hidden-fullhd { + display: none !important; + } +} +.is-visibility-hidden, +.is-invisible { + visibility: hidden !important; +} + +@media screen and (max-width: 768px) { + .is-visibility-hidden-mobile, + .is-invisible-mobile { + visibility: hidden !important; + } +} +@media screen and (min-width: 769px), print { + .is-visibility-hidden-tablet, + .is-invisible-tablet { + visibility: hidden !important; + } +} +@media screen and (min-width: 769px) and (max-width: 1023px) { + .is-visibility-hidden-tablet-only, + .is-invisible-tablet-only { + visibility: hidden !important; + } +} +@media screen and (max-width: 1023px) { + .is-visibility-hidden-touch, + .is-invisible-touch { + visibility: hidden !important; + } +} +@media screen and (min-width: 1024px) { + .is-visibility-hidden-desktop, + .is-invisible-desktop { + visibility: hidden !important; + } +} +@media screen and (min-width: 1024px) and (max-width: 1215px) { + .is-visibility-hidden-desktop-only, + .is-invisible-desktop-only { + visibility: hidden !important; + } +} +@media screen and (min-width: 1216px) { + .is-visibility-hidden-widescreen, + .is-invisible-widescreen { + visibility: hidden !important; + } +} +@media screen and (min-width: 1216px) and (max-width: 1407px) { + .is-visibility-hidden-widescreen-only, + .is-invisible-widescreen-only { + visibility: hidden !important; + } +} +@media screen and (min-width: 1408px) { + .is-visibility-hidden-fullhd, + .is-invisible-fullhd { + visibility: hidden !important; + } +} +.is-radiusless { + border-radius: 0 !important; +} + +.is-shadowless { + box-shadow: none !important; +} + +.is-clickable { + cursor: pointer !important; + pointer-events: all !important; +} + +/*# sourceMappingURL=bulma.css.map */ From 5dd7c7f7eea56e27a41cbb06c3c812fe87047594 Mon Sep 17 00:00:00 2001 From: Jordan Wages Date: Thu, 26 Jun 2025 02:51:14 -0500 Subject: [PATCH 038/148] Set themeing colors --- options/options.html | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/options/options.html b/options/options.html index d53d70c..736954d 100644 --- a/options/options.html +++ b/options/options.html @@ -5,6 +5,33 @@ AI Filter Options +
From 6913859526618e4b7d839d0065ef52ce768449c5 Mon Sep 17 00:00:00 2001 From: Jordan Wages Date: Thu, 26 Jun 2025 02:56:22 -0500 Subject: [PATCH 039/148] Refactor rule UI to use Bulma message --- options/options.js | 81 ++++++++++++++++++++++++++++------------------ 1 file changed, 50 insertions(+), 31 deletions(-) diff --git a/options/options.js b/options/options.js index 3cea8ee..9bcf9dd 100644 --- a/options/options.js +++ b/options/options.js @@ -120,8 +120,9 @@ document.addEventListener('DOMContentLoaded', async () => { const row = document.createElement('div'); row.className = 'action-row field is-grouped mb-2'; + const typeWrapper = document.createElement('div'); + typeWrapper.className = 'select is-small mr-2'; const typeSelect = document.createElement('select'); - typeSelect.className = 'select is-small'; ['tag','move','junk'].forEach(t => { const opt = document.createElement('option'); opt.value = t; @@ -129,14 +130,17 @@ document.addEventListener('DOMContentLoaded', async () => { typeSelect.appendChild(opt); }); typeSelect.value = action.type; + typeWrapper.appendChild(typeSelect); const paramSpan = document.createElement('span'); function updateParams() { paramSpan.innerHTML = ''; if (typeSelect.value === 'tag') { + const wrap = document.createElement('div'); + wrap.className = 'select is-small'; const sel = document.createElement('select'); - sel.className = 'select is-small tag-select'; + sel.className = 'tag-select'; for (const t of tagList) { const opt = document.createElement('option'); opt.value = t.key; @@ -144,10 +148,13 @@ document.addEventListener('DOMContentLoaded', async () => { sel.appendChild(opt); } sel.value = action.tagKey || ''; - paramSpan.appendChild(sel); + wrap.appendChild(sel); + paramSpan.appendChild(wrap); } else if (typeSelect.value === 'move') { + const wrap = document.createElement('div'); + wrap.className = 'select is-small'; const sel = document.createElement('select'); - sel.className = 'select is-small folder-select'; + sel.className = 'folder-select'; for (const f of folderList) { const opt = document.createElement('option'); opt.value = f.id; @@ -155,14 +162,18 @@ document.addEventListener('DOMContentLoaded', async () => { sel.appendChild(opt); } sel.value = action.folder || ''; - paramSpan.appendChild(sel); + wrap.appendChild(sel); + paramSpan.appendChild(wrap); } else if (typeSelect.value === 'junk') { + const wrap = document.createElement('div'); + wrap.className = 'select is-small'; const sel = document.createElement('select'); - sel.className = 'select is-small junk-select'; + sel.className = 'junk-select'; sel.appendChild(new Option('mark junk','true')); sel.appendChild(new Option('mark not junk','false')); sel.value = String(action.junk ?? true); - paramSpan.appendChild(sel); + wrap.appendChild(sel); + paramSpan.appendChild(wrap); } } @@ -175,7 +186,7 @@ document.addEventListener('DOMContentLoaded', async () => { removeBtn.className = 'button is-small is-danger is-light'; removeBtn.addEventListener('click', () => row.remove()); - row.appendChild(typeSelect); + row.appendChild(typeWrapper); row.appendChild(paramSpan); row.appendChild(removeBtn); @@ -185,21 +196,21 @@ document.addEventListener('DOMContentLoaded', async () => { function renderRules(rules = []) { rulesContainer.innerHTML = ''; for (const rule of rules) { - const div = document.createElement('div'); - div.className = 'rule box mb-4'; - div.draggable = true; - div.addEventListener('dragstart', ev => { dragRule = div; ev.dataTransfer.setData('text/plain', ''); }); - div.addEventListener('dragover', ev => ev.preventDefault()); - div.addEventListener('drop', ev => { + const article = document.createElement('article'); + article.className = 'rule message mb-4'; + article.draggable = true; + article.addEventListener('dragstart', ev => { dragRule = article; ev.dataTransfer.setData('text/plain', ''); }); + article.addEventListener('dragover', ev => ev.preventDefault()); + article.addEventListener('drop', ev => { ev.preventDefault(); - if (dragRule && dragRule !== div) { + if (dragRule && dragRule !== article) { const children = Array.from(rulesContainer.children); const dragIndex = children.indexOf(dragRule); - const dropIndex = children.indexOf(div); + const dropIndex = children.indexOf(article); if (dragIndex < dropIndex) { - rulesContainer.insertBefore(dragRule, div.nextSibling); + rulesContainer.insertBefore(dragRule, article.nextSibling); } else { - rulesContainer.insertBefore(dragRule, div); + rulesContainer.insertBefore(dragRule, article); } markDirty(); } @@ -209,7 +220,18 @@ document.addEventListener('DOMContentLoaded', async () => { critInput.type = 'text'; critInput.placeholder = 'Criterion'; critInput.value = rule.criterion || ''; - critInput.className = 'input criterion mb-2'; + critInput.className = 'input criterion mr-2'; + critInput.style.flexGrow = '1'; + + const header = document.createElement('div'); + header.className = 'message-header'; + header.appendChild(critInput); + + const delBtn = document.createElement('button'); + delBtn.className = 'delete'; + delBtn.setAttribute('aria-label', 'delete'); + delBtn.addEventListener('click', () => article.remove()); + header.appendChild(delBtn); const actionsContainer = document.createElement('div'); actionsContainer.className = 'rule-actions mb-2'; @@ -225,7 +247,7 @@ document.addEventListener('DOMContentLoaded', async () => { addAction.addEventListener('click', () => actionsContainer.appendChild(createActionRow())); const stopLabel = document.createElement('label'); - stopLabel.className = 'checkbox ml-2 mb-2'; + stopLabel.className = 'checkbox mt-2'; const stopCheck = document.createElement('input'); stopCheck.type = 'checkbox'; stopCheck.className = 'stop-processing'; @@ -233,19 +255,16 @@ document.addEventListener('DOMContentLoaded', async () => { stopLabel.appendChild(stopCheck); stopLabel.append(' Stop after match'); - const delBtn = document.createElement('button'); - delBtn.textContent = 'Delete Rule'; - delBtn.type = 'button'; - delBtn.className = 'button is-small is-danger'; - delBtn.addEventListener('click', () => div.remove()); + const body = document.createElement('div'); + body.className = 'message-body'; + body.appendChild(actionsContainer); + body.appendChild(addAction); + body.appendChild(stopLabel); - div.appendChild(critInput); - div.appendChild(actionsContainer); - div.appendChild(addAction); - div.appendChild(stopLabel); - div.appendChild(delBtn); + article.appendChild(header); + article.appendChild(body); - rulesContainer.appendChild(div); + rulesContainer.appendChild(article); } } From 10706101749ff67491da08bc11a3bff92dfd8aee Mon Sep 17 00:00:00 2001 From: Jordan Wages Date: Thu, 26 Jun 2025 17:02:10 -0500 Subject: [PATCH 040/148] Parse full message for AI classification --- AGENTS.md | 15 +++++++++++++++ background.js | 46 ++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 57 insertions(+), 4 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 3683f2c..e4c3c8b 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -43,3 +43,18 @@ Additional documentation exists outside this repository. - [Bulma.css](https://github.com/jgthms/bulma) - Issue tracker: [Thunderbird tracker on Bugzilla](https://bugzilla.mozilla.org/describecomponents.cgi?product=Thunderbird) + +### Message Structure Notes + +Messages retrieved with `messenger.messages.getFull` are returned as +nested objects. The root contains `headers` and a `parts` array. Each part may +itself contain `parts` for multipart messages or a `body` string. Attachments are +indicated via the `content-disposition` header. + +When constructing the text sent to the AI service, parse the full message +recursively. Include key headers such as `from`, `to`, `subject`, and others, and +record attachment summaries rather than raw binary data. Inline or attached +base64 data should be replaced with placeholders showing the byte size. The +final string should have the headers, a brief attachment section, then the plain +text extracted from all text parts. + diff --git a/background.js b/background.js index 0df9f72..660dbfb 100644 --- a/background.js +++ b/background.js @@ -39,6 +39,45 @@ async function sha256Hex(str) { return Array.from(new Uint8Array(buf), b => b.toString(16).padStart(2, '0')).join(''); } +function byteSize(str) { + return new TextEncoder().encode(str || "").length; +} + +function replaceInlineBase64(text) { + return text.replace(/[A-Za-z0-9+/]{100,}={0,2}/g, + m => `[base64: ${byteSize(m)} bytes]`); +} + +function collectText(part, bodyParts, attachments) { + if (part.parts && part.parts.length) { + for (const p of part.parts) collectText(p, bodyParts, attachments); + return; + } + const ct = (part.contentType || "text/plain").toLowerCase(); + const cd = (part.headers?.["content-disposition"]?.[0] || "").toLowerCase(); + const body = String(part.body || ""); + if (cd.includes("attachment") || !ct.startsWith("text/")) { + const nameMatch = /filename\s*=\s*"?([^";]+)/i.exec(cd) || /name\s*=\s*"?([^";]+)/i.exec(part.headers?.["content-type"]?.[0] || ""); + const name = nameMatch ? nameMatch[1] : ""; + attachments.push(`${name} (${ct}, ${part.size || byteSize(body)} bytes)`); + } else if (ct.startsWith("text/html")) { + const doc = new DOMParser().parseFromString(body, 'text/html'); + bodyParts.push(replaceInlineBase64(doc.body.textContent || "")); + } else { + bodyParts.push(replaceInlineBase64(body)); + } +} + +function buildEmailText(full) { + const bodyParts = []; + const attachments = []; + collectText(full, bodyParts, attachments); + const headers = Object.entries(full.headers || {}) + .map(([k,v]) => `${k}: ${v.join(' ')}`) + .join('\n'); + const attachInfo = `Attachments: ${attachments.length}` + (attachments.length ? "\n" + attachments.map(a => ` - ${a}`).join('\n') : ""); + return `${headers}\n${attachInfo}\n\n${bodyParts.join('\n')}`.trim(); +} async function applyAiRules(idsInput) { const ids = Array.isArray(idsInput) ? idsInput : [idsInput]; if (!ids.length) return queue; @@ -66,10 +105,9 @@ async function applyAiRules(idsInput) { updateActionIcon(); try { const full = await messenger.messages.getFull(id); - const text = full?.parts?.[0]?.body || ""; - for (const rule of aiRules) { - const cacheKey = await sha256Hex(`${id}|${rule.criterion}`); - const matched = await AiClassifier.classifyText(text, rule.criterion, cacheKey); + const text = buildEmailText(full); + const cacheKey = await sha256Hex(`${id}|${rule.criterion}`); + const matched = await AiClassifier.classifyText(text, rule.criterion, cacheKey); if (matched) { for (const act of (rule.actions || [])) { if (act.type === 'tag' && act.tagKey) { From 36b167d335db97c0b8540bcacf9007e6349fb74b Mon Sep 17 00:00:00 2001 From: Jordan Wages Date: Thu, 26 Jun 2025 17:03:54 -0500 Subject: [PATCH 041/148] adjusting colors --- options/options.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/options/options.html b/options/options.html index 736954d..da9744d 100644 --- a/options/options.html +++ b/options/options.html @@ -24,8 +24,8 @@ --bulma-warning-l: 70%; --bulma-danger-h: 0deg; --bulma-danger-s: 49%; - --bulma-scheme-h: 326; - --bulma-scheme-s: 40%; + --bulma-scheme-h: 200; + --bulma-scheme-s: 25%; } .tag { From 492c2404cdf0c5b0104d5596af3a65b826894e18 Mon Sep 17 00:00:00 2001 From: Jordan Wages Date: Thu, 26 Jun 2025 17:18:40 -0500 Subject: [PATCH 042/148] Fix rule processing loop --- background.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/background.js b/background.js index 660dbfb..1463ee7 100644 --- a/background.js +++ b/background.js @@ -106,8 +106,10 @@ async function applyAiRules(idsInput) { try { const full = await messenger.messages.getFull(id); const text = buildEmailText(full); - const cacheKey = await sha256Hex(`${id}|${rule.criterion}`); - const matched = await AiClassifier.classifyText(text, rule.criterion, cacheKey); + + for (const rule of aiRules) { + const cacheKey = await sha256Hex(`${id}|${rule.criterion}`); + const matched = await AiClassifier.classifyText(text, rule.criterion, cacheKey); if (matched) { for (const act of (rule.actions || [])) { if (act.type === 'tag' && act.tagKey) { From 0f0584c4f5dcbfcef905772e94a575db226e737c Mon Sep 17 00:00:00 2001 From: Jordan Wages Date: Fri, 27 Jun 2025 00:06:34 -0500 Subject: [PATCH 043/148] adding additional icon colors --- resources/img/busy.png | Bin 0 -> 3603 bytes resources/img/done.png | Bin 0 -> 3543 bytes resources/img/error.png | Bin 0 -> 2921 bytes 3 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 resources/img/busy.png create mode 100644 resources/img/done.png create mode 100644 resources/img/error.png diff --git a/resources/img/busy.png b/resources/img/busy.png new file mode 100644 index 0000000000000000000000000000000000000000..ee7d5d6c3e23d877833d6ee0be3bf8c8cb23e51a GIT binary patch literal 3603 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 Z{{!~PeOa9a)Aj%W002ovPDHLkV1jZT)9nBN literal 0 HcmV?d00001 diff --git a/resources/img/done.png b/resources/img/done.png new file mode 100644 index 0000000000000000000000000000000000000000..b70d72805599e17c091d6b170b3dce3c55885407 GIT binary patch literal 3543 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 RKqUYG002ovPDHLkV1h&PnS1~M literal 0 HcmV?d00001 diff --git a/resources/img/error.png b/resources/img/error.png new file mode 100644 index 0000000000000000000000000000000000000000..07705d9211b034837eb3def0c4f29e22c5e3ecf0 GIT binary patch literal 2921 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 TIJ7S^00000NkvXXu0mjfV^C6t literal 0 HcmV?d00001 From e78478ab9a1460a7aa2a1920d3ead30a6ae15c66 Mon Sep 17 00:00:00 2001 From: Jordan Wages Date: Fri, 27 Jun 2025 00:32:19 -0500 Subject: [PATCH 044/148] Show classification progress and results via toolbar icons --- README.md | 2 +- background.js | 32 +++++++++++++++++++++----------- 2 files changed, 22 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 97fe5e8..e31a766 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ message meets a specified criterion. - **Automatic rules** – create rules that tag or move new messages based on AI classification. - **Rule ordering** – drag rules to prioritize them and optionally stop processing after a match. - **Context menu** – apply AI rules from the message list or the message display action button. -- **Status icons** – toolbar icons indicate when messages are queued or being classified. +- **Status icons** – toolbar icons show when classification is in progress and briefly display success or error states. - **Packaging script** – `build-xpi.ps1` builds an XPI ready for installation. ## Architecture Overview diff --git a/background.js b/background.js index 1463ee7..e47bf99 100644 --- a/background.js +++ b/background.js @@ -18,14 +18,9 @@ let aiRules = []; let queue = Promise.resolve(); let queuedCount = 0; let processing = false; +let iconTimer = null; -function updateActionIcon() { - let path = "resources/img/logo32.png"; - if (processing) { - path = "resources/img/status-classifying.png"; - } else if (queuedCount > 0) { - path = "resources/img/status-queued.png"; - } +function setIcon(path) { if (browser.browserAction) { browser.browserAction.setIcon({ path }); } @@ -34,6 +29,20 @@ function updateActionIcon() { } } +function updateActionIcon() { + let path = "resources/img/logo32.png"; + if (processing || queuedCount > 0) { + path = "resources/img/busy.png"; + } + setIcon(path); +} + +function showTransientIcon(path, delay = 1500) { + clearTimeout(iconTimer); + setIcon(path); + iconTimer = setTimeout(updateActionIcon, delay); +} + async function sha256Hex(str) { const buf = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(str)); return Array.from(new Uint8Array(buf), b => b.toString(16).padStart(2, '0')).join(''); @@ -125,11 +134,12 @@ async function applyAiRules(idsInput) { } } } - } catch (e) { - logger.aiLog("failed to apply AI rules", { level: 'error' }, e); - } finally { processing = false; - updateActionIcon(); + showTransientIcon("resources/img/done.png"); + } catch (e) { + processing = false; + logger.aiLog("failed to apply AI rules", { level: 'error' }, e); + showTransientIcon("resources/img/error.png"); } }); } From 1ad1b7004d6fd9771aa0ab405f7aa6e9e1a95a9d Mon Sep 17 00:00:00 2001 From: Jordan Wages Date: Fri, 27 Jun 2025 01:05:27 -0500 Subject: [PATCH 045/148] Add cache clearing feature and update UI --- background.js | 73 ++++++++++++++++++++++++++++++++++- manifest.json | 4 +- modules/AiClassifier.js | 21 +++++++++- resources/clearCacheButton.js | 22 +++++++++++ 4 files changed, 116 insertions(+), 4 deletions(-) create mode 100644 resources/clearCacheButton.js diff --git a/background.js b/background.js index e47bf99..de6b595 100644 --- a/background.js +++ b/background.js @@ -147,6 +147,37 @@ async function applyAiRules(idsInput) { return queue; } +async function clearCacheForMessages(idsInput) { + const ids = Array.isArray(idsInput) ? idsInput : [idsInput]; + if (!ids.length) return; + + if (!aiRules.length) { + const { aiRules: stored } = await storage.local.get("aiRules"); + aiRules = Array.isArray(stored) ? stored.map(r => { + if (r.actions) return r; + const actions = []; + if (r.tag) actions.push({ type: 'tag', tagKey: r.tag }); + if (r.moveTo) actions.push({ type: 'move', folder: r.moveTo }); + const rule = { criterion: r.criterion, actions }; + if (r.stopProcessing) rule.stopProcessing = true; + return rule; + }) : []; + } + + const keys = []; + for (const msg of ids) { + const id = msg?.id ?? msg; + for (const rule of aiRules) { + const key = await sha256Hex(`${id}|${rule.criterion}`); + keys.push(key); + } + } + if (keys.length) { + await AiClassifier.removeCacheEntries(keys); + showTransientIcon("resources/img/done.png"); + } +} + (async () => { logger = await import(browser.runtime.getURL("logger.js")); try { @@ -191,6 +222,21 @@ async function applyAiRules(idsInput) { } logger.aiLog("background.js loaded – ready to classify", {debug: true}); + if (browser.messageDisplayAction) { + browser.messageDisplayAction.setTitle({ title: "Classify" }); + if (browser.messageDisplayAction.setLabel) { + browser.messageDisplayAction.setLabel({ label: "Classify" }); + } + } + if (browser.messageDisplayScripts?.registerScripts) { + try { + await browser.messageDisplayScripts.registerScripts([ + { js: [browser.runtime.getURL("resources/clearCacheButton.js")] } + ]); + } catch (e) { + logger.aiLog("failed to register message display script", { level: 'warn' }, e); + } + } browser.menus.create({ id: "apply-ai-rules-list", @@ -202,6 +248,16 @@ async function applyAiRules(idsInput) { title: "Apply AI Rules", contexts: ["message_display_action"], }); + browser.menus.create({ + id: "clear-ai-cache-list", + title: "Clear AI Cache", + contexts: ["message_list"], + }); + browser.menus.create({ + id: "clear-ai-cache-display", + title: "Clear AI Cache", + contexts: ["message_display_action"], + }); if (browser.messageDisplayAction) { browser.messageDisplayAction.onClicked.addListener(async (tab) => { @@ -220,6 +276,10 @@ async function applyAiRules(idsInput) { const ids = info.selectedMessages?.messages?.map(m => m.id) || (info.messageId ? [info.messageId] : []); await applyAiRules(ids); + } else if (info.menuItemId === "clear-ai-cache-list" || info.menuItemId === "clear-ai-cache-display") { + const ids = info.selectedMessages?.messages?.map(m => m.id) || + (info.messageId ? [info.messageId] : []); + await clearCacheForMessages(ids); } }); @@ -243,8 +303,17 @@ async function applyAiRules(idsInput) { // rethrow so the caller sees the failure throw err; } - } - else { + } else if (msg?.type === "sortana:clearCacheForDisplayed") { + try { + const tabs = await browser.tabs.query({ active: true, currentWindow: true }); + const tabId = tabs[0]?.id; + const msgs = tabId ? await browser.messageDisplay.getDisplayedMessages(tabId) : []; + const ids = msgs.map(m => m.id); + await clearCacheForMessages(ids); + } catch (e) { + logger.aiLog("failed to clear cache from message script", { level: 'error' }, e); + } + } else { logger.aiLog("Unknown message type, ignoring", {level: 'warn'}, msg?.type); } }); diff --git a/manifest.json b/manifest.json index 1610453..0e9b20a 100644 --- a/manifest.json +++ b/manifest.json @@ -22,7 +22,9 @@ "default_icon": "resources/img/logo32.png" }, "message_display_action": { - "default_icon": "resources/img/logo32.png" + "default_icon": "resources/img/logo32.png", + "default_title": "Classify", + "default_label": "Classify" }, "background": { "scripts": [ "background.js" ] }, "options_ui": { diff --git a/modules/AiClassifier.js b/modules/AiClassifier.js index d2cae3a..cec4a31 100644 --- a/modules/AiClassifier.js +++ b/modules/AiClassifier.js @@ -210,6 +210,25 @@ function cacheResult(cacheKey, matched) { } } +async function removeCacheEntries(keys = []) { + if (!Array.isArray(keys)) { + keys = [keys]; + } + if (!gCacheLoaded) { + await loadCache(); + } + let removed = false; + for (let key of keys) { + if (gCache.delete(key)) { + removed = true; + aiLog(`[AiClassifier] Removed cache entry '${key}'`, {debug: true}); + } + } + if (removed) { + await saveCache(); + } +} + function classifyTextSync(text, criterion, cacheKey = null) { if (!Services?.tm?.spinEventLoopUntil) { throw new Error("classifyTextSync requires Services"); @@ -288,4 +307,4 @@ async function classifyText(text, criterion, cacheKey = null) { } } -export { classifyText, classifyTextSync, setConfig }; +export { classifyText, classifyTextSync, setConfig, removeCacheEntries }; diff --git a/resources/clearCacheButton.js b/resources/clearCacheButton.js new file mode 100644 index 0000000..a4d2adb --- /dev/null +++ b/resources/clearCacheButton.js @@ -0,0 +1,22 @@ +(function() { + function addButton() { + const toolbar = document.querySelector("#header-view-toolbar") || + document.querySelector("#mail-toolbox toolbar"); + if (!toolbar || document.getElementById('sortana-clear-cache-button')) return; + const button = document.createXULElement ? + document.createXULElement('toolbarbutton') : + document.createElement('button'); + button.id = 'sortana-clear-cache-button'; + button.setAttribute('label', 'Clear Cache'); + button.className = 'toolbarbutton-1'; + button.addEventListener('command', () => { + browser.runtime.sendMessage({ type: 'sortana:clearCacheForDisplayed' }); + }); + toolbar.appendChild(button); + } + if (document.readyState === 'complete' || document.readyState === 'interactive') { + addButton(); + } else { + document.addEventListener('DOMContentLoaded', addButton, { once: true }); + } +})(); From db7113b03d81faed2da12ddf3076cb0a6408f4f4 Mon Sep 17 00:00:00 2001 From: Jordan Wages Date: Fri, 27 Jun 2025 01:38:11 -0500 Subject: [PATCH 046/148] Create brain.png --- resources/img/brain.png | Bin 0 -> 13993 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 resources/img/brain.png diff --git a/resources/img/brain.png b/resources/img/brain.png new file mode 100644 index 0000000000000000000000000000000000000000..296bb646386cd6cbcbc028e261e84bc130a313a6 GIT binary patch literal 13993 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 tdr3enf1lt=s1iBLeWR-X{~ Date: Fri, 27 Jun 2025 01:39:02 -0500 Subject: [PATCH 047/148] Add reasoning cache and viewer --- background.js | 33 +++++++++++++- modules/AiClassifier.js | 92 ++++++++++++++++++++++++++++++++++++--- reasoning.html | 17 ++++++++ reasoning.js | 27 ++++++++++++ resources/img/brain.png | 44 +++++++++++++++++++ resources/reasonButton.js | 34 +++++++++++++++ 6 files changed, 240 insertions(+), 7 deletions(-) create mode 100644 reasoning.html create mode 100644 reasoning.js create mode 100644 resources/img/brain.png create mode 100644 resources/reasonButton.js diff --git a/background.js b/background.js index de6b595..17154b0 100644 --- a/background.js +++ b/background.js @@ -231,7 +231,8 @@ async function clearCacheForMessages(idsInput) { if (browser.messageDisplayScripts?.registerScripts) { try { await browser.messageDisplayScripts.registerScripts([ - { js: [browser.runtime.getURL("resources/clearCacheButton.js")] } + { js: [browser.runtime.getURL("resources/clearCacheButton.js")] }, + { js: [browser.runtime.getURL("resources/reasonButton.js")] } ]); } catch (e) { logger.aiLog("failed to register message display script", { level: 'warn' }, e); @@ -313,6 +314,36 @@ async function clearCacheForMessages(idsInput) { } catch (e) { logger.aiLog("failed to clear cache from message script", { level: 'error' }, e); } + } else if (msg?.type === "sortana:getReasons") { + try { + const id = msg.id; + const hdr = await messenger.messages.get(id); + const subject = hdr?.subject || ""; + if (!aiRules.length) { + const { aiRules: stored } = await storage.local.get("aiRules"); + aiRules = Array.isArray(stored) ? stored.map(r => { + if (r.actions) return r; + const actions = []; + if (r.tag) actions.push({ type: 'tag', tagKey: r.tag }); + if (r.moveTo) actions.push({ type: 'move', folder: r.moveTo }); + const rule = { criterion: r.criterion, actions }; + if (r.stopProcessing) rule.stopProcessing = true; + return rule; + }) : []; + } + const reasons = []; + for (const rule of aiRules) { + const key = await sha256Hex(`${id}|${rule.criterion}`); + const reason = AiClassifier.getReason(key); + if (reason) { + reasons.push({ criterion: rule.criterion, reason }); + } + } + return { subject, reasons }; + } catch (e) { + logger.aiLog("failed to collect reasons", { level: 'error' }, e); + return { subject: '', reasons: [] }; + } } else { logger.aiLog("Unknown message type, ignoring", {level: 'warn'}, msg?.type); } diff --git a/modules/AiClassifier.js b/modules/AiClassifier.js index cec4a31..4180973 100644 --- a/modules/AiClassifier.js +++ b/modules/AiClassifier.js @@ -49,6 +49,8 @@ let gAiParams = { let gCache = new Map(); let gCacheLoaded = false; +let gReasonCache = new Map(); +let gReasonCacheLoaded = false; async function loadCache() { if (gCacheLoaded) { @@ -94,6 +96,50 @@ async function saveCache(updatedKey, updatedValue) { } } +async function loadReasonCache() { + if (gReasonCacheLoaded) { + return; + } + aiLog(`[AiClassifier] Loading reason cache`, {debug: true}); + try { + const { aiReasonCache } = await storage.local.get("aiReasonCache"); + if (aiReasonCache) { + for (let [k, v] of Object.entries(aiReasonCache)) { + aiLog(`[AiClassifier] ⮡ Loaded reason '${k}'`, {debug: true}); + gReasonCache.set(k, v); + } + aiLog(`[AiClassifier] Loaded ${gReasonCache.size} reason entries`, {debug: true}); + } else { + aiLog(`[AiClassifier] Reason cache is empty`, {debug: true}); + } + } catch (e) { + aiLog(`Failed to load reason cache`, {level: 'error'}, e); + } + gReasonCacheLoaded = true; +} + +function loadReasonCacheSync() { + if (!gReasonCacheLoaded) { + if (!Services?.tm?.spinEventLoopUntil) { + throw new Error("loadReasonCacheSync requires Services"); + } + let done = false; + loadReasonCache().finally(() => { done = true; }); + Services.tm.spinEventLoopUntil(() => done); + } +} + +async function saveReasonCache(updatedKey, updatedValue) { + if (typeof updatedKey !== "undefined") { + aiLog(`[AiClassifier] ⮡ Persisting reason '${updatedKey}'`, {debug: true}); + } + try { + await storage.local.set({ aiReasonCache: Object.fromEntries(gReasonCache) }); + } catch (e) { + aiLog(`Failed to save reason cache`, {level: 'error'}, e); + } +} + async function loadTemplate(name) { try { const url = typeof browser !== "undefined" && browser.runtime?.getURL @@ -185,6 +231,17 @@ function getCachedResult(cacheKey) { return null; } +function getReason(cacheKey) { + if (!gReasonCacheLoaded) { + if (Services?.tm?.spinEventLoopUntil) { + loadReasonCacheSync(); + } else { + return null; + } + } + return cacheKey ? gReasonCache.get(cacheKey) || null : null; +} + function buildPayload(text, criterion) { let payloadObj = Object.assign({ prompt: buildPrompt(text, criterion) @@ -199,7 +256,8 @@ function parseMatch(result) { const cleanedText = rawText.replace(/[\s\S]*?<\/think>/gi, "").trim(); aiLog('[AiClassifier] ⮡ Cleaned Response Text:', {debug: true}, cleanedText); const obj = JSON.parse(cleanedText); - return obj.matched === true || obj.match === true; + const matched = obj.matched === true || obj.match === true; + return { matched, reason: thinkText }; } function cacheResult(cacheKey, matched) { @@ -210,6 +268,14 @@ function cacheResult(cacheKey, matched) { } } +function cacheReason(cacheKey, reason) { + if (cacheKey) { + aiLog(`[AiClassifier] Caching reason '${cacheKey}'`, {debug: true}); + gReasonCache.set(cacheKey, reason); + saveReasonCache(cacheKey, reason); + } +} + async function removeCacheEntries(keys = []) { if (!Array.isArray(keys)) { keys = [keys]; @@ -223,9 +289,14 @@ async function removeCacheEntries(keys = []) { removed = true; aiLog(`[AiClassifier] Removed cache entry '${key}'`, {debug: true}); } + if (gReasonCache.delete(key)) { + removed = true; + aiLog(`[AiClassifier] Removed reason entry '${key}'`, {debug: true}); + } } if (removed) { await saveCache(); + await saveReasonCache(); } } @@ -233,6 +304,9 @@ function classifyTextSync(text, criterion, cacheKey = null) { if (!Services?.tm?.spinEventLoopUntil) { throw new Error("classifyTextSync requires Services"); } + if (!gReasonCacheLoaded) { + loadReasonCacheSync(); + } const cached = getCachedResult(cacheKey); if (cached !== null) { return cached; @@ -255,7 +329,9 @@ function classifyTextSync(text, criterion, cacheKey = null) { const json = await response.json(); aiLog(`[AiClassifier] Received response:`, {debug: true}, json); result = parseMatch(json); - cacheResult(cacheKey, result); + cacheResult(cacheKey, result.matched); + cacheReason(cacheKey, result.reason); + result = result.matched; } else { aiLog(`HTTP status ${response.status}`, {level: 'warn'}); result = false; @@ -275,6 +351,9 @@ async function classifyText(text, criterion, cacheKey = null) { if (!gCacheLoaded) { await loadCache(); } + if (!gReasonCacheLoaded) { + await loadReasonCache(); + } const cached = getCachedResult(cacheKey); if (cached !== null) { return cached; @@ -298,13 +377,14 @@ async function classifyText(text, criterion, cacheKey = null) { const result = await response.json(); aiLog(`[AiClassifier] Received response:`, {debug: true}, result); - const matched = parseMatch(result); - cacheResult(cacheKey, matched); - return matched; + const parsed = parseMatch(result); + cacheResult(cacheKey, parsed.matched); + cacheReason(cacheKey, parsed.reason); + return parsed.matched; } catch (e) { aiLog(`HTTP request failed`, {level: 'error'}, e); return false; } } -export { classifyText, classifyTextSync, setConfig, removeCacheEntries }; +export { classifyText, classifyTextSync, setConfig, removeCacheEntries, getReason }; diff --git a/reasoning.html b/reasoning.html new file mode 100644 index 0000000..bb1577d --- /dev/null +++ b/reasoning.html @@ -0,0 +1,17 @@ + + + + + AI Reasoning + + + +
+
+

+
+
+
+ + + diff --git a/reasoning.js b/reasoning.js new file mode 100644 index 0000000..eb0b9da --- /dev/null +++ b/reasoning.js @@ -0,0 +1,27 @@ +document.addEventListener('DOMContentLoaded', async () => { + const params = new URLSearchParams(location.search); + const id = parseInt(params.get('mid'), 10); + if (!id) return; + try { + const { subject, reasons } = await browser.runtime.sendMessage({ type: 'sortana:getReasons', id }); + document.getElementById('subject').textContent = subject; + const container = document.getElementById('rules'); + for (const r of reasons) { + const article = document.createElement('article'); + article.className = 'message mb-4'; + const header = document.createElement('div'); + header.className = 'message-header'; + header.innerHTML = `

${r.criterion}

`; + const body = document.createElement('div'); + body.className = 'message-body'; + const pre = document.createElement('pre'); + pre.textContent = r.reason; + body.appendChild(pre); + article.appendChild(header); + article.appendChild(body); + container.appendChild(article); + } + } catch (e) { + console.error('failed to load reasons', e); + } +}); diff --git a/resources/img/brain.png b/resources/img/brain.png new file mode 100644 index 0000000..7d9e7d6 --- /dev/null +++ b/resources/img/brain.png @@ -0,0 +1,44 @@ + + + + +Object not found! + + + + + +

Object not found!

+

+ + + The requested URL was not found on this server. + + + + If you entered the URL manually please check your + spelling and try again. + + + +

+

+If you think this is a server error, please contact +the webmaster. + +

+ +

Error 404

+
+ openmoji.org
+ Apache +
+ + + diff --git a/resources/reasonButton.js b/resources/reasonButton.js new file mode 100644 index 0000000..0206ab9 --- /dev/null +++ b/resources/reasonButton.js @@ -0,0 +1,34 @@ +(function() { + function addButton() { + const toolbar = document.querySelector("#header-view-toolbar") || + document.querySelector("#mail-toolbox toolbar"); + if (!toolbar || document.getElementById('sortana-reason-button')) return; + const button = document.createXULElement ? + document.createXULElement('toolbarbutton') : + document.createElement('button'); + button.id = 'sortana-reason-button'; + button.setAttribute('label', 'Show Reasoning'); + button.className = 'toolbarbutton-1'; + const icon = browser.runtime.getURL('resources/img/brain.png'); + if (button.setAttribute) { + button.setAttribute('image', icon); + } else { + button.style.backgroundImage = `url(${icon})`; + button.style.backgroundSize = 'contain'; + } + button.addEventListener('command', async () => { + const tabs = await browser.tabs.query({ active: true, currentWindow: true }); + const tabId = tabs[0]?.id; + const msgs = tabId ? await browser.messageDisplay.getDisplayedMessages(tabId) : []; + if (!msgs.length) return; + const url = browser.runtime.getURL(`reasoning.html?mid=${msgs[0].id}`); + browser.tabs.create({ url }); + }); + toolbar.appendChild(button); + } + if (document.readyState === 'complete' || document.readyState === 'interactive') { + addButton(); + } else { + document.addEventListener('DOMContentLoaded', addButton, { once: true }); + } +})(); From 004815e39a06e8160388d88d8b0586b23d6a92cb Mon Sep 17 00:00:00 2001 From: Jordan Wages Date: Fri, 27 Jun 2025 01:39:36 -0500 Subject: [PATCH 048/148] Delete resources/img/brain.png --- resources/img/brain.png | 44 ----------------------------------------- 1 file changed, 44 deletions(-) delete mode 100644 resources/img/brain.png diff --git a/resources/img/brain.png b/resources/img/brain.png deleted file mode 100644 index 7d9e7d6..0000000 --- a/resources/img/brain.png +++ /dev/null @@ -1,44 +0,0 @@ - - - - -Object not found! - - - - - -

Object not found!

-

- - - The requested URL was not found on this server. - - - - If you entered the URL manually please check your - spelling and try again. - - - -

-

-If you think this is a server error, please contact -the webmaster. - -

- -

Error 404

-
- openmoji.org
- Apache -
- - - From 03844a5ab371feec4f74587b734ef12d55e7cfa4 Mon Sep 17 00:00:00 2001 From: Jordan Wages Date: Fri, 27 Jun 2025 02:02:55 -0500 Subject: [PATCH 049/148] Update ai-filter.sln --- ai-filter.sln | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/ai-filter.sln b/ai-filter.sln index 6aeca89..77a10cb 100644 --- a/ai-filter.sln +++ b/ai-filter.sln @@ -13,6 +13,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution logger.js = logger.js manifest.json = manifest.json README.md = README.md + reasoning.html = reasoning.html + reasoning.js = reasoning.js EndProjectSection ProjectSection(FolderGlobals) = preProject Q_5_4Users_4Jordan_4Documents_4Gitea_4thunderbird-ai-filter_4src_4manifest_1json__JsonSchema = @@ -51,9 +53,17 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "prompt_templates", "prompt_ EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "resources", "resources", "{68A87938-5C2B-49F5-8AAA-8A34FBBFD854}" + ProjectSection(SolutionItems) = preProject + resources\clearCacheButton.js = resources\clearCacheButton.js + resources\reasonButton.js = resources\reasonButton.js + EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "img", "img", "{F266602F-1755-4A95-A11B-6C90C701C5BF}" ProjectSection(SolutionItems) = preProject + resources\img\brain.png = resources\img\brain.png + resources\img\busy.png = resources\img\busy.png + resources\img\done.png = resources\img\done.png + resources\img\error.png = resources\img\error.png resources\img\full-logo.png = resources\img\full-logo.png resources\img\logo.png = resources\img\logo.png resources\img\logo128.png = resources\img\logo128.png From 22ab445dea92ca507956cfd62851474bb3a43b74 Mon Sep 17 00:00:00 2001 From: Jordan Wages Date: Fri, 27 Jun 2025 02:12:34 -0500 Subject: [PATCH 050/148] Add View Reasoning menu and fix button --- background.js | 29 ++++++++++++++++++++++++++--- resources/reasonButton.js | 2 +- 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/background.js b/background.js index 17154b0..5b536a5 100644 --- a/background.js +++ b/background.js @@ -228,12 +228,17 @@ async function clearCacheForMessages(idsInput) { browser.messageDisplayAction.setLabel({ label: "Classify" }); } } - if (browser.messageDisplayScripts?.registerScripts) { + if (browser.messageDisplayScripts) { try { - await browser.messageDisplayScripts.registerScripts([ + const scripts = [ { js: [browser.runtime.getURL("resources/clearCacheButton.js")] }, { js: [browser.runtime.getURL("resources/reasonButton.js")] } - ]); + ]; + if (browser.messageDisplayScripts.registerScripts) { + await browser.messageDisplayScripts.registerScripts(scripts); + } else if (browser.messageDisplayScripts.register) { + await browser.messageDisplayScripts.register(scripts); + } } catch (e) { logger.aiLog("failed to register message display script", { level: 'warn' }, e); } @@ -259,6 +264,18 @@ async function clearCacheForMessages(idsInput) { title: "Clear AI Cache", contexts: ["message_display_action"], }); + browser.menus.create({ + id: "view-ai-reason-list", + title: "View Reasoning", + contexts: ["message_list"], + icons: { "16": "resources/img/brain.png" } + }); + browser.menus.create({ + id: "view-ai-reason-display", + title: "View Reasoning", + contexts: ["message_display_action"], + icons: { "16": "resources/img/brain.png" } + }); if (browser.messageDisplayAction) { browser.messageDisplayAction.onClicked.addListener(async (tab) => { @@ -281,6 +298,12 @@ async function clearCacheForMessages(idsInput) { const ids = info.selectedMessages?.messages?.map(m => m.id) || (info.messageId ? [info.messageId] : []); await clearCacheForMessages(ids); + } else if (info.menuItemId === "view-ai-reason-list" || info.menuItemId === "view-ai-reason-display") { + const id = info.messageId || info.selectedMessages?.messages?.[0]?.id; + if (id) { + const url = browser.runtime.getURL(`reasoning.html?mid=${id}`); + browser.tabs.create({ url }); + } } }); diff --git a/resources/reasonButton.js b/resources/reasonButton.js index 0206ab9..d0b38e7 100644 --- a/resources/reasonButton.js +++ b/resources/reasonButton.js @@ -7,7 +7,7 @@ document.createXULElement('toolbarbutton') : document.createElement('button'); button.id = 'sortana-reason-button'; - button.setAttribute('label', 'Show Reasoning'); + button.setAttribute('label', 'View Reasoning'); button.className = 'toolbarbutton-1'; const icon = browser.runtime.getURL('resources/img/brain.png'); if (button.setAttribute) { From a29a6299efc03b0ea049a34f72dd1db16022bfef Mon Sep 17 00:00:00 2001 From: Jordan Wages Date: Fri, 27 Jun 2025 02:52:49 -0500 Subject: [PATCH 051/148] Use new scripting API for message display scripts --- background.js | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/background.js b/background.js index 5b536a5..ca235c8 100644 --- a/background.js +++ b/background.js @@ -228,11 +228,27 @@ async function clearCacheForMessages(idsInput) { browser.messageDisplayAction.setLabel({ label: "Classify" }); } } - if (browser.messageDisplayScripts) { + if (browser.scripting && browser.scripting.messageDisplay) { + try { + const scripts = [ + { + id: "clear-cache-button", + js: [browser.runtime.getURL("resources/clearCacheButton.js")], + }, + { + id: "reason-button", + js: [browser.runtime.getURL("resources/reasonButton.js")], + }, + ]; + await browser.scripting.messageDisplay.registerScripts(scripts); + } catch (e) { + logger.aiLog("failed to register message display script", { level: 'warn' }, e); + } + } else if (browser.messageDisplayScripts) { try { const scripts = [ { js: [browser.runtime.getURL("resources/clearCacheButton.js")] }, - { js: [browser.runtime.getURL("resources/reasonButton.js")] } + { js: [browser.runtime.getURL("resources/reasonButton.js")] }, ]; if (browser.messageDisplayScripts.registerScripts) { await browser.messageDisplayScripts.registerScripts(scripts); From 9ae22ad5ed209fc0ab1946e008dd78646e830895 Mon Sep 17 00:00:00 2001 From: Jordan Wages Date: Fri, 27 Jun 2025 02:52:49 -0500 Subject: [PATCH 052/148] Update README.md --- README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.md b/README.md index e31a766..299ecdc 100644 --- a/README.md +++ b/README.md @@ -106,6 +106,15 @@ Sortana requests the following Thunderbird permissions: - `accountsRead` – list accounts and folders for move actions. - `menus` – add context menu commands. +## Thunderbird Add-on Store Disclosures + +The [Third Party Library Usage](https://extensionworkshop.com/documentation/publish/third-party-library-usage/) policy +requires disclosure of third party libraries that are included in the add-on. Even though +the disclosure is only required for add-on review, they'll be listed here as well. Sortana +uses the following third party libraries: + +- [Bulma.css v1.0.4](https://github.com/jgthms/bulma/blob/1.0.4/css/bulma.css) + ## License This project is licensed under the terms of the GNU General Public License From a7009d644c8bd2502a400e6f0b01a95f592b6090 Mon Sep 17 00:00:00 2001 From: Jordan Wages Date: Fri, 27 Jun 2025 03:12:32 -0500 Subject: [PATCH 053/148] Fix script registration with relative URLs --- background.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/background.js b/background.js index ca235c8..1b25492 100644 --- a/background.js +++ b/background.js @@ -233,11 +233,11 @@ async function clearCacheForMessages(idsInput) { const scripts = [ { id: "clear-cache-button", - js: [browser.runtime.getURL("resources/clearCacheButton.js")], + js: ["resources/clearCacheButton.js"], }, { id: "reason-button", - js: [browser.runtime.getURL("resources/reasonButton.js")], + js: ["resources/reasonButton.js"], }, ]; await browser.scripting.messageDisplay.registerScripts(scripts); @@ -247,8 +247,8 @@ async function clearCacheForMessages(idsInput) { } else if (browser.messageDisplayScripts) { try { const scripts = [ - { js: [browser.runtime.getURL("resources/clearCacheButton.js")] }, - { js: [browser.runtime.getURL("resources/reasonButton.js")] }, + { js: ["resources/clearCacheButton.js"] }, + { js: ["resources/reasonButton.js"] }, ]; if (browser.messageDisplayScripts.registerScripts) { await browser.messageDisplayScripts.registerScripts(scripts); From 7be3c46e627ae0ebc680dd1d480a2742081743da Mon Sep 17 00:00:00 2001 From: Jordan Wages Date: Fri, 27 Jun 2025 03:14:57 -0500 Subject: [PATCH 054/148] Update manifest.json --- manifest.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/manifest.json b/manifest.json index 0e9b20a..3c0b02b 100644 --- a/manifest.json +++ b/manifest.json @@ -38,6 +38,7 @@ "messagesUpdate", "messagesTagsList", "accountsRead", - "menus" + "menus", + "scripting" ] } From 437616900192faed1c738bfb14980046de73c777 Mon Sep 17 00:00:00 2001 From: Jordan Wages Date: Fri, 27 Jun 2025 03:55:47 -0500 Subject: [PATCH 055/148] Update AGENTS.md --- AGENTS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/AGENTS.md b/AGENTS.md index e4c3c8b..87cfd6f 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -36,6 +36,7 @@ Additional documentation exists outside this repository. - Development guide: [Webextention-API for Thunderbird](https://webextension-api.thunderbird.net/en/stable/) - [Messages API](https://webextension-api.thunderbird.net/en/stable/messages.html) - [Message Tags API](https://webextension-api.thunderbird.net/en/stable/messages.tags.html) + - [messageDisplayAction API](https://webextension-api.thunderbird.net/en/stable/messageDisplayAction.html) - [Storage API](https://webextension-api.thunderbird.net/en/stable/storage.html) - Thunderbird Add-on Store Policies - [Third Party Library Usage](https://extensionworkshop.com/documentation/publish/third-party-library-usage/) From 1d7f0d534473c683b95151239be05827aec148df Mon Sep 17 00:00:00 2001 From: Jordan Wages Date: Fri, 27 Jun 2025 04:08:04 -0500 Subject: [PATCH 056/148] Add message details popup --- ai-filter.sln | 4 -- background.js | 90 +++++++++++++++++----------------- reasoning.html => details.html | 7 ++- reasoning.js => details.js | 18 +++++-- manifest.json | 7 +-- resources/clearCacheButton.js | 22 --------- resources/reasonButton.js | 34 ------------- 7 files changed, 66 insertions(+), 116 deletions(-) rename reasoning.html => details.html (61%) rename reasoning.js => details.js (54%) delete mode 100644 resources/clearCacheButton.js delete mode 100644 resources/reasonButton.js diff --git a/ai-filter.sln b/ai-filter.sln index 77a10cb..960bee0 100644 --- a/ai-filter.sln +++ b/ai-filter.sln @@ -13,8 +13,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution logger.js = logger.js manifest.json = manifest.json README.md = README.md - reasoning.html = reasoning.html - reasoning.js = reasoning.js EndProjectSection ProjectSection(FolderGlobals) = preProject Q_5_4Users_4Jordan_4Documents_4Gitea_4thunderbird-ai-filter_4src_4manifest_1json__JsonSchema = @@ -54,8 +52,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "prompt_templates", "prompt_ EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "resources", "resources", "{68A87938-5C2B-49F5-8AAA-8A34FBBFD854}" ProjectSection(SolutionItems) = preProject - resources\clearCacheButton.js = resources\clearCacheButton.js - resources\reasonButton.js = resources\reasonButton.js EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "img", "img", "{F266602F-1755-4A95-A11B-6C90C701C5BF}" diff --git a/background.js b/background.js index 1b25492..8e235d4 100644 --- a/background.js +++ b/background.js @@ -30,7 +30,7 @@ function setIcon(path) { } function updateActionIcon() { - let path = "resources/img/logo32.png"; + let path = "resources/img/brain.png"; if (processing || queuedCount > 0) { path = "resources/img/busy.png"; } @@ -223,40 +223,9 @@ async function clearCacheForMessages(idsInput) { logger.aiLog("background.js loaded – ready to classify", {debug: true}); if (browser.messageDisplayAction) { - browser.messageDisplayAction.setTitle({ title: "Classify" }); + browser.messageDisplayAction.setTitle({ title: "Details" }); if (browser.messageDisplayAction.setLabel) { - browser.messageDisplayAction.setLabel({ label: "Classify" }); - } - } - if (browser.scripting && browser.scripting.messageDisplay) { - try { - const scripts = [ - { - id: "clear-cache-button", - js: ["resources/clearCacheButton.js"], - }, - { - id: "reason-button", - js: ["resources/reasonButton.js"], - }, - ]; - await browser.scripting.messageDisplay.registerScripts(scripts); - } catch (e) { - logger.aiLog("failed to register message display script", { level: 'warn' }, e); - } - } else if (browser.messageDisplayScripts) { - try { - const scripts = [ - { js: ["resources/clearCacheButton.js"] }, - { js: ["resources/reasonButton.js"] }, - ]; - if (browser.messageDisplayScripts.registerScripts) { - await browser.messageDisplayScripts.registerScripts(scripts); - } else if (browser.messageDisplayScripts.register) { - await browser.messageDisplayScripts.register(scripts); - } - } catch (e) { - logger.aiLog("failed to register message display script", { level: 'warn' }, e); + browser.messageDisplayAction.setLabel({ label: "Details" }); } } @@ -293,17 +262,7 @@ async function clearCacheForMessages(idsInput) { icons: { "16": "resources/img/brain.png" } }); - if (browser.messageDisplayAction) { - browser.messageDisplayAction.onClicked.addListener(async (tab) => { - try { - const msgs = await browser.messageDisplay.getDisplayedMessages(tab.id); - const ids = msgs.map(m => m.id); - await applyAiRules(ids); - } catch (e) { - logger.aiLog("failed to apply AI rules from action", { level: 'error' }, e); - } - }); - } + browser.menus.onClicked.addListener(async info => { if (info.menuItemId === "apply-ai-rules-list" || info.menuItemId === "apply-ai-rules-display") { @@ -317,7 +276,7 @@ async function clearCacheForMessages(idsInput) { } else if (info.menuItemId === "view-ai-reason-list" || info.menuItemId === "view-ai-reason-display") { const id = info.messageId || info.selectedMessages?.messages?.[0]?.id; if (id) { - const url = browser.runtime.getURL(`reasoning.html?mid=${id}`); + const url = browser.runtime.getURL(`details.html?mid=${id}`); browser.tabs.create({ url }); } } @@ -383,6 +342,45 @@ async function clearCacheForMessages(idsInput) { logger.aiLog("failed to collect reasons", { level: 'error' }, e); return { subject: '', reasons: [] }; } + } else if (msg?.type === "sortana:getDetails") { + try { + const id = msg.id; + const hdr = await messenger.messages.get(id); + const subject = hdr?.subject || ""; + if (!aiRules.length) { + const { aiRules: stored } = await storage.local.get("aiRules"); + aiRules = Array.isArray(stored) ? stored.map(r => { + if (r.actions) return r; + const actions = []; + if (r.tag) actions.push({ type: 'tag', tagKey: r.tag }); + if (r.moveTo) actions.push({ type: 'move', folder: r.moveTo }); + const rule = { criterion: r.criterion, actions }; + if (r.stopProcessing) rule.stopProcessing = true; + return rule; + }) : []; + } + const results = []; + for (const rule of aiRules) { + const key = await sha256Hex(`${id}|${rule.criterion}`); + const matched = AiClassifier.getCachedResult(key); + const reason = AiClassifier.getReason(key); + if (matched !== null || reason) { + results.push({ criterion: rule.criterion, matched, reason }); + } + } + return { subject, results }; + } catch (e) { + logger.aiLog("failed to collect details", { level: 'error' }, e); + return { subject: '', results: [] }; + } + } else if (msg?.type === "sortana:clearCacheForMessage") { + try { + await clearCacheForMessages([msg.id]); + return { ok: true }; + } catch (e) { + logger.aiLog("failed to clear cache for message", { level: 'error' }, e); + return { ok: false }; + } } else { logger.aiLog("Unknown message type, ignoring", {level: 'warn'}, msg?.type); } diff --git a/reasoning.html b/details.html similarity index 61% rename from reasoning.html rename to details.html index bb1577d..1502471 100644 --- a/reasoning.html +++ b/details.html @@ -2,7 +2,7 @@ - AI Reasoning + AI Details @@ -10,8 +10,11 @@

+
+ +
- + diff --git a/reasoning.js b/details.js similarity index 54% rename from reasoning.js rename to details.js index eb0b9da..2b5b9e7 100644 --- a/reasoning.js +++ b/details.js @@ -3,25 +3,33 @@ document.addEventListener('DOMContentLoaded', async () => { const id = parseInt(params.get('mid'), 10); if (!id) return; try { - const { subject, reasons } = await browser.runtime.sendMessage({ type: 'sortana:getReasons', id }); + const { subject, results } = await browser.runtime.sendMessage({ type: 'sortana:getDetails', id }); document.getElementById('subject').textContent = subject; const container = document.getElementById('rules'); - for (const r of reasons) { + for (const r of results) { const article = document.createElement('article'); - article.className = 'message mb-4'; + const color = r.matched === true ? 'is-success' : 'is-danger'; + article.className = `message ${color} mb-4`; const header = document.createElement('div'); header.className = 'message-header'; header.innerHTML = `

${r.criterion}

`; const body = document.createElement('div'); body.className = 'message-body'; + const status = document.createElement('p'); + status.textContent = r.matched ? 'Matched' : 'Did not match'; const pre = document.createElement('pre'); - pre.textContent = r.reason; + pre.textContent = r.reason || ''; + body.appendChild(status); body.appendChild(pre); article.appendChild(header); article.appendChild(body); container.appendChild(article); } + document.getElementById('clear').addEventListener('click', async () => { + await browser.runtime.sendMessage({ type: 'sortana:clearCacheForMessage', id }); + window.close(); + }); } catch (e) { - console.error('failed to load reasons', e); + console.error('failed to load details', e); } }); diff --git a/manifest.json b/manifest.json index 3c0b02b..3f17845 100644 --- a/manifest.json +++ b/manifest.json @@ -22,9 +22,10 @@ "default_icon": "resources/img/logo32.png" }, "message_display_action": { - "default_icon": "resources/img/logo32.png", - "default_title": "Classify", - "default_label": "Classify" + "default_icon": "resources/img/brain.png", + "default_title": "Details", + "default_label": "Details", + "default_popup": "details.html" }, "background": { "scripts": [ "background.js" ] }, "options_ui": { diff --git a/resources/clearCacheButton.js b/resources/clearCacheButton.js deleted file mode 100644 index a4d2adb..0000000 --- a/resources/clearCacheButton.js +++ /dev/null @@ -1,22 +0,0 @@ -(function() { - function addButton() { - const toolbar = document.querySelector("#header-view-toolbar") || - document.querySelector("#mail-toolbox toolbar"); - if (!toolbar || document.getElementById('sortana-clear-cache-button')) return; - const button = document.createXULElement ? - document.createXULElement('toolbarbutton') : - document.createElement('button'); - button.id = 'sortana-clear-cache-button'; - button.setAttribute('label', 'Clear Cache'); - button.className = 'toolbarbutton-1'; - button.addEventListener('command', () => { - browser.runtime.sendMessage({ type: 'sortana:clearCacheForDisplayed' }); - }); - toolbar.appendChild(button); - } - if (document.readyState === 'complete' || document.readyState === 'interactive') { - addButton(); - } else { - document.addEventListener('DOMContentLoaded', addButton, { once: true }); - } -})(); diff --git a/resources/reasonButton.js b/resources/reasonButton.js deleted file mode 100644 index d0b38e7..0000000 --- a/resources/reasonButton.js +++ /dev/null @@ -1,34 +0,0 @@ -(function() { - function addButton() { - const toolbar = document.querySelector("#header-view-toolbar") || - document.querySelector("#mail-toolbox toolbar"); - if (!toolbar || document.getElementById('sortana-reason-button')) return; - const button = document.createXULElement ? - document.createXULElement('toolbarbutton') : - document.createElement('button'); - button.id = 'sortana-reason-button'; - button.setAttribute('label', 'View Reasoning'); - button.className = 'toolbarbutton-1'; - const icon = browser.runtime.getURL('resources/img/brain.png'); - if (button.setAttribute) { - button.setAttribute('image', icon); - } else { - button.style.backgroundImage = `url(${icon})`; - button.style.backgroundSize = 'contain'; - } - button.addEventListener('command', async () => { - const tabs = await browser.tabs.query({ active: true, currentWindow: true }); - const tabId = tabs[0]?.id; - const msgs = tabId ? await browser.messageDisplay.getDisplayedMessages(tabId) : []; - if (!msgs.length) return; - const url = browser.runtime.getURL(`reasoning.html?mid=${msgs[0].id}`); - browser.tabs.create({ url }); - }); - toolbar.appendChild(button); - } - if (document.readyState === 'complete' || document.readyState === 'interactive') { - addButton(); - } else { - document.addEventListener('DOMContentLoaded', addButton, { once: true }); - } -})(); From 9b91abb338d17147792c3ca89dc30102afaebccd Mon Sep 17 00:00:00 2001 From: Jordan Wages Date: Fri, 27 Jun 2025 21:59:11 -0500 Subject: [PATCH 057/148] Fix details popup when no mid parameter --- details.js | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/details.js b/details.js index 2b5b9e7..0d190d5 100644 --- a/details.js +++ b/details.js @@ -1,6 +1,17 @@ document.addEventListener('DOMContentLoaded', async () => { const params = new URLSearchParams(location.search); - const id = parseInt(params.get('mid'), 10); + let id = parseInt(params.get('mid'), 10); + + if (!id) { + try { + const tabs = await browser.tabs.query({ active: true, currentWindow: true }); + const tabId = tabs[0]?.id; + const msgs = tabId ? await browser.messageDisplay.getDisplayedMessages(tabId) : []; + id = msgs[0]?.id; + } catch (e) { + console.error('failed to determine message id', e); + } + } if (!id) return; try { const { subject, results } = await browser.runtime.sendMessage({ type: 'sortana:getDetails', id }); From ef864651d4073e8b7f1fee2c8e5da83c32d32858 Mon Sep 17 00:00:00 2001 From: Jordan Wages Date: Sat, 28 Jun 2025 02:56:29 -0500 Subject: [PATCH 058/148] Update ai-filter.sln --- ai-filter.sln | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ai-filter.sln b/ai-filter.sln index 960bee0..40cec4f 100644 --- a/ai-filter.sln +++ b/ai-filter.sln @@ -9,6 +9,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution AGENTS.md = AGENTS.md background.js = background.js build-xpi.ps1 = build-xpi.ps1 + details.html = details.html + details.js = details.js LICENSE = LICENSE logger.js = logger.js manifest.json = manifest.json @@ -51,8 +53,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "prompt_templates", "prompt_ EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "resources", "resources", "{68A87938-5C2B-49F5-8AAA-8A34FBBFD854}" - ProjectSection(SolutionItems) = preProject - EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "img", "img", "{F266602F-1755-4A95-A11B-6C90C701C5BF}" ProjectSection(SolutionItems) = preProject From bced7447b254327c18dfd3514cb898b4a80bf757 Mon Sep 17 00:00:00 2001 From: Jordan Wages Date: Fri, 27 Jun 2025 22:20:38 -0500 Subject: [PATCH 059/148] Export getCachedResult from classifier --- modules/AiClassifier.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/AiClassifier.js b/modules/AiClassifier.js index 4180973..cef1842 100644 --- a/modules/AiClassifier.js +++ b/modules/AiClassifier.js @@ -387,4 +387,4 @@ async function classifyText(text, criterion, cacheKey = null) { } } -export { classifyText, classifyTextSync, setConfig, removeCacheEntries, getReason }; +export { classifyText, classifyTextSync, setConfig, removeCacheEntries, getReason, getCachedResult }; From d69d0cae669ca96bcb4e1b584b1cc77c268f78a2 Mon Sep 17 00:00:00 2001 From: Jordan Wages Date: Sat, 28 Jun 2025 15:46:30 -0500 Subject: [PATCH 060/148] Merge AI caches and add cache key helper --- AGENTS.md | 7 ++ README.md | 9 +- background.js | 13 +-- modules/AiClassifier.js | 155 ++++++++++++++--------------- modules/ExpressionSearchFilter.jsm | 11 +- 5 files changed, 95 insertions(+), 100 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 87cfd6f..ad83d34 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -59,3 +59,10 @@ base64 data should be replaced with placeholders showing the byte size. The final string should have the headers, a brief attachment section, then the plain text extracted from all text parts. +### Cache Strategy + +`aiCache` persists classification results. Each key is the SHA‑256 hex of +`"|"` and maps to an object with `matched` and `reason` +properties. Any legacy `aiReasonCache` data is merged into `aiCache` the first +time the add-on loads after an update. + diff --git a/README.md b/README.md index 299ecdc..ed362eb 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ message meets a specified criterion. - **Custom system prompts** – tailor the instructions sent to the model for more precise results. - **Filter editor integration** – patches Thunderbird's filter editor to accept text criteria for AI classification. -- **Persistent result caching** – classification results are saved to disk so messages aren't re-evaluated across restarts. +- **Persistent result caching** – classification results and reasoning are saved to disk so messages aren't re-evaluated across restarts. - **Advanced parameters** – tune generation settings like temperature, top‑p and more from the options page. - **Debug logging** – optional colorized logs help troubleshoot interactions with the AI service. - **Automatic rules** – create rules that tag or move new messages based on AI classification. @@ -25,6 +25,13 @@ message meets a specified criterion. - **Status icons** – toolbar icons show when classification is in progress and briefly display success or error states. - **Packaging script** – `build-xpi.ps1` builds an XPI ready for installation. +### Cache Storage + +Classification results are stored under the `aiCache` key in extension storage. +Each entry maps a SHA‑256 hash of `"|"` to an object +containing `matched` and `reason` fields. Older installations with a separate +`aiReasonCache` will be migrated automatically on startup. + ## Architecture Overview Sortana is implemented entirely with standard WebExtension scripts—no custom experiment code is required: diff --git a/background.js b/background.js index 8e235d4..ab37701 100644 --- a/background.js +++ b/background.js @@ -43,10 +43,6 @@ function showTransientIcon(path, delay = 1500) { iconTimer = setTimeout(updateActionIcon, delay); } -async function sha256Hex(str) { - const buf = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(str)); - return Array.from(new Uint8Array(buf), b => b.toString(16).padStart(2, '0')).join(''); -} function byteSize(str) { return new TextEncoder().encode(str || "").length; @@ -117,7 +113,7 @@ async function applyAiRules(idsInput) { const text = buildEmailText(full); for (const rule of aiRules) { - const cacheKey = await sha256Hex(`${id}|${rule.criterion}`); + const cacheKey = await AiClassifier.buildCacheKey(id, rule.criterion); const matched = await AiClassifier.classifyText(text, rule.criterion, cacheKey); if (matched) { for (const act of (rule.actions || [])) { @@ -168,7 +164,7 @@ async function clearCacheForMessages(idsInput) { for (const msg of ids) { const id = msg?.id ?? msg; for (const rule of aiRules) { - const key = await sha256Hex(`${id}|${rule.criterion}`); + const key = await AiClassifier.buildCacheKey(id, rule.criterion); keys.push(key); } } @@ -192,6 +188,7 @@ async function clearCacheForMessages(idsInput) { const store = await storage.local.get(["endpoint", "templateName", "customTemplate", "customSystemPrompt", "aiParams", "debugLogging", "aiRules"]); logger.setDebug(store.debugLogging); await AiClassifier.setConfig(store); + await AiClassifier.init(); aiRules = Array.isArray(store.aiRules) ? store.aiRules.map(r => { if (r.actions) return r; const actions = []; @@ -331,7 +328,7 @@ async function clearCacheForMessages(idsInput) { } const reasons = []; for (const rule of aiRules) { - const key = await sha256Hex(`${id}|${rule.criterion}`); + const key = await AiClassifier.buildCacheKey(id, rule.criterion); const reason = AiClassifier.getReason(key); if (reason) { reasons.push({ criterion: rule.criterion, reason }); @@ -361,7 +358,7 @@ async function clearCacheForMessages(idsInput) { } const results = []; for (const rule of aiRules) { - const key = await sha256Hex(`${id}|${rule.criterion}`); + const key = await AiClassifier.buildCacheKey(id, rule.criterion); const matched = AiClassifier.getCachedResult(key); const reason = AiClassifier.getReason(key); if (matched !== null || reason) { diff --git a/modules/AiClassifier.js b/modules/AiClassifier.js index cef1842..e123288 100644 --- a/modules/AiClassifier.js +++ b/modules/AiClassifier.js @@ -49,8 +49,39 @@ let gAiParams = { let gCache = new Map(); let gCacheLoaded = false; -let gReasonCache = new Map(); -let gReasonCacheLoaded = false; + +function sha256HexSync(str) { + try { + const hasher = Cc["@mozilla.org/security/hash;1"].createInstance(Ci.nsICryptoHash); + hasher.init(Ci.nsICryptoHash.SHA256); + const data = new TextEncoder().encode(str); + hasher.update(data, data.length); + const binary = hasher.finish(false); + return Array.from(binary, c => ("0" + c.charCodeAt(0).toString(16)).slice(-2)).join(""); + } catch (e) { + aiLog(`sha256HexSync failed`, { level: 'error' }, e); + return ""; + } +} + +async function sha256Hex(str) { + if (typeof crypto?.subtle?.digest === "function") { + const buf = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(str)); + return Array.from(new Uint8Array(buf), b => b.toString(16).padStart(2, "0")).join(""); + } + return sha256HexSync(str); +} + +function buildCacheKeySync(id, criterion) { + return sha256HexSync(`${id}|${criterion}`); +} + +async function buildCacheKey(id, criterion) { + if (Services) { + return buildCacheKeySync(id, criterion); + } + return sha256Hex(`${id}|${criterion}`); +} async function loadCache() { if (gCacheLoaded) { @@ -58,16 +89,29 @@ async function loadCache() { } aiLog(`[AiClassifier] Loading cache`, {debug: true}); try { - const { aiCache } = await storage.local.get("aiCache"); + const { aiCache, aiReasonCache } = await storage.local.get(["aiCache", "aiReasonCache"]); if (aiCache) { for (let [k, v] of Object.entries(aiCache)) { - aiLog(`[AiClassifier] ⮡ Loaded entry '${k}' → ${v}`, {debug: true}); - gCache.set(k, v); + if (v && typeof v === "object") { + gCache.set(k, { matched: v.matched ?? null, reason: v.reason || "" }); + } else { + gCache.set(k, { matched: v, reason: "" }); + } } aiLog(`[AiClassifier] Loaded ${gCache.size} cache entries`, {debug: true}); } else { aiLog(`[AiClassifier] Cache is empty`, {debug: true}); } + if (aiReasonCache) { + aiLog(`[AiClassifier] Migrating ${Object.keys(aiReasonCache).length} reason entries`, {debug: true}); + for (let [k, reason] of Object.entries(aiReasonCache)) { + let entry = gCache.get(k) || { matched: null, reason: "" }; + entry.reason = reason; + gCache.set(k, entry); + } + await storage.local.remove("aiReasonCache"); + await storage.local.set({ aiCache: Object.fromEntries(gCache) }); + } } catch (e) { aiLog(`Failed to load cache`, {level: 'error'}, e); } @@ -96,49 +140,6 @@ async function saveCache(updatedKey, updatedValue) { } } -async function loadReasonCache() { - if (gReasonCacheLoaded) { - return; - } - aiLog(`[AiClassifier] Loading reason cache`, {debug: true}); - try { - const { aiReasonCache } = await storage.local.get("aiReasonCache"); - if (aiReasonCache) { - for (let [k, v] of Object.entries(aiReasonCache)) { - aiLog(`[AiClassifier] ⮡ Loaded reason '${k}'`, {debug: true}); - gReasonCache.set(k, v); - } - aiLog(`[AiClassifier] Loaded ${gReasonCache.size} reason entries`, {debug: true}); - } else { - aiLog(`[AiClassifier] Reason cache is empty`, {debug: true}); - } - } catch (e) { - aiLog(`Failed to load reason cache`, {level: 'error'}, e); - } - gReasonCacheLoaded = true; -} - -function loadReasonCacheSync() { - if (!gReasonCacheLoaded) { - if (!Services?.tm?.spinEventLoopUntil) { - throw new Error("loadReasonCacheSync requires Services"); - } - let done = false; - loadReasonCache().finally(() => { done = true; }); - Services.tm.spinEventLoopUntil(() => done); - } -} - -async function saveReasonCache(updatedKey, updatedValue) { - if (typeof updatedKey !== "undefined") { - aiLog(`[AiClassifier] ⮡ Persisting reason '${updatedKey}'`, {debug: true}); - } - try { - await storage.local.set({ aiReasonCache: Object.fromEntries(gReasonCache) }); - } catch (e) { - aiLog(`Failed to save reason cache`, {level: 'error'}, e); - } -} async function loadTemplate(name) { try { @@ -220,26 +221,27 @@ function getCachedResult(cacheKey) { if (Services?.tm?.spinEventLoopUntil) { loadCacheSync(); } else { - // In non-privileged contexts we can't block, so bail out early. return null; } } if (cacheKey && gCache.has(cacheKey)) { aiLog(`[AiClassifier] Cache hit for key: ${cacheKey}`, {debug: true}); - return gCache.get(cacheKey); + const entry = gCache.get(cacheKey); + return entry?.matched ?? null; } return null; } function getReason(cacheKey) { - if (!gReasonCacheLoaded) { + if (!gCacheLoaded) { if (Services?.tm?.spinEventLoopUntil) { - loadReasonCacheSync(); + loadCacheSync(); } else { return null; } } - return cacheKey ? gReasonCache.get(cacheKey) || null : null; + const entry = gCache.get(cacheKey); + return cacheKey && entry ? entry.reason || null : null; } function buildPayload(text, criterion) { @@ -260,20 +262,20 @@ function parseMatch(result) { return { matched, reason: thinkText }; } -function cacheResult(cacheKey, matched) { - if (cacheKey) { - aiLog(`[AiClassifier] Caching entry '${cacheKey}' → ${matched}`, {debug: true}); - gCache.set(cacheKey, matched); - saveCache(cacheKey, matched); +function cacheEntry(cacheKey, matched, reason) { + if (!cacheKey) { + return; } -} - -function cacheReason(cacheKey, reason) { - if (cacheKey) { - aiLog(`[AiClassifier] Caching reason '${cacheKey}'`, {debug: true}); - gReasonCache.set(cacheKey, reason); - saveReasonCache(cacheKey, reason); + aiLog(`[AiClassifier] Caching entry '${cacheKey}'`, {debug: true}); + const entry = gCache.get(cacheKey) || { matched: null, reason: "" }; + if (typeof matched === "boolean") { + entry.matched = matched; } + if (typeof reason === "string") { + entry.reason = reason; + } + gCache.set(cacheKey, entry); + saveCache(cacheKey, entry); } async function removeCacheEntries(keys = []) { @@ -289,14 +291,9 @@ async function removeCacheEntries(keys = []) { removed = true; aiLog(`[AiClassifier] Removed cache entry '${key}'`, {debug: true}); } - if (gReasonCache.delete(key)) { - removed = true; - aiLog(`[AiClassifier] Removed reason entry '${key}'`, {debug: true}); - } } if (removed) { await saveCache(); - await saveReasonCache(); } } @@ -304,9 +301,6 @@ function classifyTextSync(text, criterion, cacheKey = null) { if (!Services?.tm?.spinEventLoopUntil) { throw new Error("classifyTextSync requires Services"); } - if (!gReasonCacheLoaded) { - loadReasonCacheSync(); - } const cached = getCachedResult(cacheKey); if (cached !== null) { return cached; @@ -329,8 +323,7 @@ function classifyTextSync(text, criterion, cacheKey = null) { const json = await response.json(); aiLog(`[AiClassifier] Received response:`, {debug: true}, json); result = parseMatch(json); - cacheResult(cacheKey, result.matched); - cacheReason(cacheKey, result.reason); + cacheEntry(cacheKey, result.matched, result.reason); result = result.matched; } else { aiLog(`HTTP status ${response.status}`, {level: 'warn'}); @@ -351,9 +344,6 @@ async function classifyText(text, criterion, cacheKey = null) { if (!gCacheLoaded) { await loadCache(); } - if (!gReasonCacheLoaded) { - await loadReasonCache(); - } const cached = getCachedResult(cacheKey); if (cached !== null) { return cached; @@ -378,8 +368,7 @@ async function classifyText(text, criterion, cacheKey = null) { const result = await response.json(); aiLog(`[AiClassifier] Received response:`, {debug: true}, result); const parsed = parseMatch(result); - cacheResult(cacheKey, parsed.matched); - cacheReason(cacheKey, parsed.reason); + cacheEntry(cacheKey, parsed.matched, parsed.reason); return parsed.matched; } catch (e) { aiLog(`HTTP request failed`, {level: 'error'}, e); @@ -387,4 +376,8 @@ async function classifyText(text, criterion, cacheKey = null) { } } -export { classifyText, classifyTextSync, setConfig, removeCacheEntries, getReason, getCachedResult }; +async function init() { + await loadCache(); +} + +export { classifyText, classifyTextSync, setConfig, removeCacheEntries, getReason, getCachedResult, buildCacheKey, buildCacheKeySync, init }; diff --git a/modules/ExpressionSearchFilter.jsm b/modules/ExpressionSearchFilter.jsm index 791c181..b9998a9 100644 --- a/modules/ExpressionSearchFilter.jsm +++ b/modules/ExpressionSearchFilter.jsm @@ -5,15 +5,6 @@ var { aiLog } = ChromeUtils.import("resource://aifilter/modules/logger.jsm"); var AiClassifier = ChromeUtils.importESModule("resource://aifilter/modules/AiClassifier.js"); var { getPlainText } = ChromeUtils.import("resource://aifilter/modules/messageUtils.jsm"); -function sha256Hex(str) { - const hasher = Cc["@mozilla.org/security/hash;1"].createInstance(Ci.nsICryptoHash); - hasher.init(Ci.nsICryptoHash.SHA256); - const data = new TextEncoder().encode(str); - hasher.update(data, data.length); - const binary = hasher.finish(false); - return Array.from(binary, c => ("0" + c.charCodeAt(0).toString(16)).slice(-2)).join(""); -} - var EXPORTED_SYMBOLS = ["AIFilter", "ClassificationTerm"]; class CustomerTermBase { @@ -70,7 +61,7 @@ class ClassificationTerm extends CustomerTermBase { op === Ci.nsMsgSearchOp.DoesntMatch ? "doesn't match" : `unknown (${op})`; aiLog(`[ExpressionSearchFilter] Matching message ${msgHdr.messageId} using op "${opName}" and value "${value}"`, {debug: true}); - let key = [msgHdr.messageId, op, value].map(sha256Hex).join("|"); + let key = AiClassifier.buildCacheKeySync(msgHdr.messageId, value); let body = getPlainText(msgHdr); let matched = AiClassifier.classifyTextSync(body, value, key); From 3e1df7be3f4abd5f0cf4deb77115b4d305070831 Mon Sep 17 00:00:00 2001 From: Jordan Wages Date: Sun, 29 Jun 2025 00:07:37 -0500 Subject: [PATCH 061/148] Preserve existing tags when applying multiple rules --- background.js | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/background.js b/background.js index ab37701..b49e691 100644 --- a/background.js +++ b/background.js @@ -111,6 +111,13 @@ async function applyAiRules(idsInput) { try { const full = await messenger.messages.getFull(id); const text = buildEmailText(full); + let currentTags = []; + try { + const hdr = await messenger.messages.get(id); + currentTags = Array.isArray(hdr.tags) ? [...hdr.tags] : []; + } catch (e) { + currentTags = []; + } for (const rule of aiRules) { const cacheKey = await AiClassifier.buildCacheKey(id, rule.criterion); @@ -118,7 +125,10 @@ async function applyAiRules(idsInput) { if (matched) { for (const act of (rule.actions || [])) { if (act.type === 'tag' && act.tagKey) { - await messenger.messages.update(id, { tags: [act.tagKey] }); + if (!currentTags.includes(act.tagKey)) { + currentTags.push(act.tagKey); + await messenger.messages.update(id, { tags: currentTags }); + } } else if (act.type === 'move' && act.folder) { await messenger.messages.move([id], act.folder); } else if (act.type === 'junk') { From 41a0f4f8f252e98c959aabefad7e738dc37a0ee1 Mon Sep 17 00:00:00 2001 From: Jordan Wages Date: Sun, 29 Jun 2025 00:26:26 -0500 Subject: [PATCH 062/148] Added additional logging --- modules/AiClassifier.js | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/AiClassifier.js b/modules/AiClassifier.js index e123288..ff80aac 100644 --- a/modules/AiClassifier.js +++ b/modules/AiClassifier.js @@ -352,6 +352,7 @@ async function classifyText(text, criterion, cacheKey = null) { const payload = buildPayload(text, criterion); aiLog(`[AiClassifier] Sending classification request to ${gEndpoint}`, {debug: true}); + aiLog(`[AiClassifier] Classification request payload:`, { debug: true }, payload); try { const response = await fetch(gEndpoint, { From 8ba2a931b9d72b66b0dd483332fccf21f28a7982 Mon Sep 17 00:00:00 2001 From: Jordan Wages Date: Sun, 29 Jun 2025 02:37:05 -0500 Subject: [PATCH 063/148] Use Message-ID for cache keys --- AGENTS.md | 2 +- README.md | 2 +- modules/AiClassifier.js | 23 +++++++++++++++++++---- 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index ad83d34..9ae810b 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -62,7 +62,7 @@ text extracted from all text parts. ### Cache Strategy `aiCache` persists classification results. Each key is the SHA‑256 hex of -`"|"` and maps to an object with `matched` and `reason` +`"|"` and maps to an object with `matched` and `reason` properties. Any legacy `aiReasonCache` data is merged into `aiCache` the first time the add-on loads after an update. diff --git a/README.md b/README.md index ed362eb..e6aecbe 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ message meets a specified criterion. ### Cache Storage Classification results are stored under the `aiCache` key in extension storage. -Each entry maps a SHA‑256 hash of `"|"` to an object +Each entry maps a SHA‑256 hash of `"|"` to an object containing `matched` and `reason` fields. Older installations with a separate `aiReasonCache` will be migrated automatically on startup. diff --git a/modules/AiClassifier.js b/modules/AiClassifier.js index ff80aac..a546fcd 100644 --- a/modules/AiClassifier.js +++ b/modules/AiClassifier.js @@ -76,11 +76,26 @@ function buildCacheKeySync(id, criterion) { return sha256HexSync(`${id}|${criterion}`); } -async function buildCacheKey(id, criterion) { - if (Services) { - return buildCacheKeySync(id, criterion); +async function resolveHeaderId(id) { + if (typeof id === "number" && typeof messenger?.messages?.get === "function") { + try { + const hdr = await messenger.messages.get(id); + if (hdr?.headerMessageId) { + return hdr.headerMessageId; + } + } catch (e) { + aiLog(`Failed to resolve headerMessageId for ${id}`, { level: 'warn' }, e); + } } - return sha256Hex(`${id}|${criterion}`); + return String(id); +} + +async function buildCacheKey(id, criterion) { + const resolvedId = await resolveHeaderId(id); + if (Services) { + return buildCacheKeySync(resolvedId, criterion); + } + return sha256Hex(`${resolvedId}|${criterion}`); } async function loadCache() { From a77e5e68fbf128312dbca2dde80c9af55757440c Mon Sep 17 00:00:00 2001 From: Jordan Wages Date: Sun, 29 Jun 2025 02:42:58 -0500 Subject: [PATCH 064/148] clean up --- ai-filter.sln | 8 +-- modules/ExpressionSearchFilter.jsm | 90 ------------------------------ modules/messageUtils.jsm | 89 ----------------------------- 3 files changed, 2 insertions(+), 185 deletions(-) delete mode 100644 modules/ExpressionSearchFilter.jsm delete mode 100644 modules/messageUtils.jsm diff --git a/ai-filter.sln b/ai-filter.sln index 40cec4f..2d171dd 100644 --- a/ai-filter.sln +++ b/ai-filter.sln @@ -29,8 +29,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "options", "options", "{7372 EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "modules", "modules", "{75ED3C1E-D3C7-4546-9F2E-AC85859DDF4B}" ProjectSection(SolutionItems) = preProject + modules\AiClassifier.js = modules\AiClassifier.js modules\ExpressionSearchFilter.jsm = modules\ExpressionSearchFilter.jsm modules\logger.jsm = modules\logger.jsm + modules\messageUtils.jsm = modules\messageUtils.jsm EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "_locales", "_locales", "{D446E5C6-BDDE-4091-BD1A-EC57170003CF}" @@ -40,11 +42,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "en-US", "en-US", "{8BEA7793 _locales\en-US\messages.json = _locales\en-US\messages.json EndProjectSection EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "content", "content", "{028FDA4B-AC3E-4A0E-9291-978E213F9B78}" - ProjectSection(SolutionItems) = preProject - content\filterEditor.js = content\filterEditor.js - EndProjectSection -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "prompt_templates", "prompt_templates", "{86516D53-50D4-4FE2-9D8A-977A8F5EBDBD}" ProjectSection(SolutionItems) = preProject prompt_templates\mistral.txt = prompt_templates\mistral.txt @@ -79,7 +76,6 @@ Global {75ED3C1E-D3C7-4546-9F2E-AC85859DDF4B} = {BCC6E6D2-343B-4C48-854D-5FE3BBC3CB70} {D446E5C6-BDDE-4091-BD1A-EC57170003CF} = {BCC6E6D2-343B-4C48-854D-5FE3BBC3CB70} {8BEA7793-3336-40ED-AB96-7FFB09FEB0F6} = {D446E5C6-BDDE-4091-BD1A-EC57170003CF} - {028FDA4B-AC3E-4A0E-9291-978E213F9B78} = {BCC6E6D2-343B-4C48-854D-5FE3BBC3CB70} {86516D53-50D4-4FE2-9D8A-977A8F5EBDBD} = {BCC6E6D2-343B-4C48-854D-5FE3BBC3CB70} {68A87938-5C2B-49F5-8AAA-8A34FBBFD854} = {BCC6E6D2-343B-4C48-854D-5FE3BBC3CB70} {F266602F-1755-4A95-A11B-6C90C701C5BF} = {68A87938-5C2B-49F5-8AAA-8A34FBBFD854} diff --git a/modules/ExpressionSearchFilter.jsm b/modules/ExpressionSearchFilter.jsm deleted file mode 100644 index b9998a9..0000000 --- a/modules/ExpressionSearchFilter.jsm +++ /dev/null @@ -1,90 +0,0 @@ -"use strict"; -var { ExtensionParent } = ChromeUtils.importESModule("resource://gre/modules/ExtensionParent.sys.mjs"); -var { MailServices } = ChromeUtils.importESModule("resource:///modules/MailServices.sys.mjs"); -var { aiLog } = ChromeUtils.import("resource://aifilter/modules/logger.jsm"); -var AiClassifier = ChromeUtils.importESModule("resource://aifilter/modules/AiClassifier.js"); -var { getPlainText } = ChromeUtils.import("resource://aifilter/modules/messageUtils.jsm"); - -var EXPORTED_SYMBOLS = ["AIFilter", "ClassificationTerm"]; - -class CustomerTermBase { - constructor(nameId, operators) { - // Lookup our extension instance using the ID from manifest.json - // so locale strings are resolved correctly. - this.extension = ExtensionParent.GlobalManager.getExtension("ai-filter@jordanwages"); - this.id = "aifilter#" + nameId; - this.name = this.extension.localeData.localizeMessage(nameId); - this.operators = operators; - - aiLog(`[ExpressionSearchFilter] Initialized term base "${this.id}"`, {debug: true}); - } - - - getEnabled() { - aiLog(`[ExpressionSearchFilter] getEnabled() called on "${this.id}"`, {debug: true}); - return true; - } - - getAvailable() { - aiLog(`[ExpressionSearchFilter] getAvailable() called on "${this.id}"`, {debug: true}); - return true; - } - - getAvailableOperators() { - aiLog(`[ExpressionSearchFilter] getAvailableOperators() called on "${this.id}"`, {debug: true}); - return this.operators; - } - - getAvailableValues() { - aiLog(`[ExpressionSearchFilter] getAvailableValues() called on "${this.id}"`, {debug: true}); - return null; - } - - get attrib() { - aiLog(`[ExpressionSearchFilter] attrib getter called for "${this.id}"`, {debug: true}); - - //return Ci.nsMsgSearchAttrib.Custom; - } -} - - -class ClassificationTerm extends CustomerTermBase { - constructor() { - super("classification", [Ci.nsMsgSearchOp.Matches, Ci.nsMsgSearchOp.DoesntMatch]); - aiLog(`[ExpressionSearchFilter] ClassificationTerm constructed`, {debug: true}); - } - - needsBody() { return true; } - - match(msgHdr, value, op) { - const opName = op === Ci.nsMsgSearchOp.Matches ? "matches" : - op === Ci.nsMsgSearchOp.DoesntMatch ? "doesn't match" : `unknown (${op})`; - aiLog(`[ExpressionSearchFilter] Matching message ${msgHdr.messageId} using op "${opName}" and value "${value}"`, {debug: true}); - - let key = AiClassifier.buildCacheKeySync(msgHdr.messageId, value); - let body = getPlainText(msgHdr); - - let matched = AiClassifier.classifyTextSync(body, value, key); - - if (op === Ci.nsMsgSearchOp.DoesntMatch) { - matched = !matched; - aiLog(`[ExpressionSearchFilter] Operator is "doesn't match" → inverting to ${matched}`, {debug: true}); - } - - aiLog(`[ExpressionSearchFilter] Final match result: ${matched}`, {debug: true}); - return matched; - } -} - -(function register() { - aiLog(`[ExpressionSearchFilter] Registering custom filter term...`, {debug: true}); - let term = new ClassificationTerm(); - if (!MailServices.filters.getCustomTerm(term.id)) { - MailServices.filters.addCustomTerm(term); - aiLog(`[ExpressionSearchFilter] Registered term: ${term.id}`, {debug: true}); - } else { - aiLog(`[ExpressionSearchFilter] Term already registered: ${term.id}`, {debug: true}); - } -})(); - -var AIFilter = { setConfig: AiClassifier.setConfig }; diff --git a/modules/messageUtils.jsm b/modules/messageUtils.jsm deleted file mode 100644 index a4978a7..0000000 --- a/modules/messageUtils.jsm +++ /dev/null @@ -1,89 +0,0 @@ -"use strict"; -var { NetUtil } = ChromeUtils.importESModule("resource://gre/modules/NetUtil.sys.mjs"); -var { MimeParser } = ChromeUtils.importESModule("resource:///modules/mimeParser.sys.mjs"); -var { aiLog } = ChromeUtils.import("resource://aifilter/modules/logger.jsm"); - -var EXPORTED_SYMBOLS = ["getPlainText"]; - -function getPlainText(msgHdr) { - aiLog(`[ExpressionSearchFilter] Extracting plain text for message ID ${msgHdr.messageId}`, {debug: true}); - let folder = msgHdr.folder; - if (!folder.getMsgInputStream) return ""; - let reusable = {}; - let stream = folder.getMsgInputStream(msgHdr, reusable); - let data = NetUtil.readInputStreamToString(stream, msgHdr.messageSize); - if (!reusable.value) stream.close(); - - let parser = Cc["@mozilla.org/parserutils;1"].getService(Ci.nsIParserUtils); - - try { - let root = MimeParser.parseSync(data, {strformat: "unicode"}); - let parts = []; - - function pushPlaceholder(type, info, bytes) { - bytes = bytes || 0; - let prettyType = type.split("/")[1] || type; - parts.push(`[${info}: ${prettyType}, ${bytes} bytes]`); - } - - function byteSizeFromBase64(str) { - let clean = str.replace(/[^A-Za-z0-9+/=]/g, ""); - return Math.floor(clean.length * 3 / 4); - } - - function replaceInlineBase64(text) { - return text.replace(/[A-Za-z0-9+/]{100,}={0,2}/g, - m => `[base64: ${byteSizeFromBase64(m)} bytes]`); - } - - function walk(node) { - if (node.parts && node.parts.length) { - for (let child of node.parts) { - walk(child); - } - return; - } - - let ct = (node.contentType || "text/plain").toLowerCase(); - let cd = (node.headers?.["content-disposition"]?.[0] || "").toLowerCase(); - let enc = (node.headers?.["content-transfer-encoding"]?.[0] || "").toLowerCase(); - let bodyText = String(node.body || ""); - - if (cd.includes("attachment")) { - pushPlaceholder(ct, "binary attachment", byteSizeFromBase64(bodyText)); - } else if (ct.startsWith("text/plain")) { - if (enc === "base64") { - parts.push(`[base64: ${byteSizeFromBase64(bodyText)} bytes]`); - } else { - parts.push(replaceInlineBase64(bodyText)); - } - } else if (ct.startsWith("text/html")) { - if (enc === "base64") { - parts.push(`[base64: ${byteSizeFromBase64(bodyText)} bytes]`); - } else { - let txt = parser.convertToPlainText(bodyText, - Ci.nsIDocumentEncoder.OutputLFLineBreak | - Ci.nsIDocumentEncoder.OutputNoScriptContent | - Ci.nsIDocumentEncoder.OutputNoFramesContent | - Ci.nsIDocumentEncoder.OutputBodyOnly, 0); - parts.push(replaceInlineBase64(txt)); - } - } else { - // Other single part types treated as attachments - pushPlaceholder(ct, "binary attachment", byteSizeFromBase64(bodyText)); - } - } - - walk(root); - return parts.join("\n"); - } catch (e) { - // Fallback: convert entire raw message to text - aiLog(`Failed to parse MIME, falling back to raw conversion`, {level: 'warn'}, e); - return parser.convertToPlainText(data, - Ci.nsIDocumentEncoder.OutputLFLineBreak | - Ci.nsIDocumentEncoder.OutputNoScriptContent | - Ci.nsIDocumentEncoder.OutputNoFramesContent | - Ci.nsIDocumentEncoder.OutputBodyOnly, 0); - } -} - From db767fae48de6cff2f4ba6b5d06de7f43f511787 Mon Sep 17 00:00:00 2001 From: Jordan Wages Date: Sun, 29 Jun 2025 02:46:49 -0500 Subject: [PATCH 065/148] Add maintenance tab and cache clearing --- README.md | 1 + modules/AiClassifier.js | 13 ++++++++++++- options/options.html | 12 ++++++++++++ options/options.js | 12 +++++++++++- 4 files changed, 36 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index e6aecbe..3e60766 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,7 @@ message meets a specified criterion. - **Context menu** – apply AI rules from the message list or the message display action button. - **Status icons** – toolbar icons show when classification is in progress and briefly display success or error states. - **Packaging script** – `build-xpi.ps1` builds an XPI ready for installation. +- **Maintenance tab** – view rule counts, cache entries and clear cached results from the options page. ### Cache Storage diff --git a/modules/AiClassifier.js b/modules/AiClassifier.js index a546fcd..de267b6 100644 --- a/modules/AiClassifier.js +++ b/modules/AiClassifier.js @@ -312,6 +312,17 @@ async function removeCacheEntries(keys = []) { } } +async function clearCache() { + if (!gCacheLoaded) { + await loadCache(); + } + if (gCache.size > 0) { + gCache.clear(); + await saveCache(); + aiLog(`[AiClassifier] Cleared cache`, {debug: true}); + } +} + function classifyTextSync(text, criterion, cacheKey = null) { if (!Services?.tm?.spinEventLoopUntil) { throw new Error("classifyTextSync requires Services"); @@ -396,4 +407,4 @@ async function init() { await loadCache(); } -export { classifyText, classifyTextSync, setConfig, removeCacheEntries, getReason, getCachedResult, buildCacheKey, buildCacheKeySync, init }; +export { classifyText, classifyTextSync, setConfig, removeCacheEntries, clearCache, getReason, getCachedResult, buildCacheKey, buildCacheKeySync, init }; diff --git a/options/options.html b/options/options.html index da9744d..f776fa2 100644 --- a/options/options.html +++ b/options/options.html @@ -46,6 +46,7 @@ @@ -171,6 +172,17 @@
+ + diff --git a/options/options.js b/options/options.js index 9bcf9dd..5536ad5 100644 --- a/options/options.js +++ b/options/options.js @@ -9,7 +9,8 @@ document.addEventListener('DOMContentLoaded', async () => { 'customSystemPrompt', 'aiParams', 'debugLogging', - 'aiRules' + 'aiRules', + 'aiCache' ]); const tabButtons = document.querySelectorAll('#main-tabs li'); const tabs = document.querySelectorAll('.tab-content'); @@ -300,6 +301,15 @@ document.addEventListener('DOMContentLoaded', async () => { if (r.stopProcessing) rule.stopProcessing = true; return rule; })); + + const ruleCountEl = document.getElementById('rule-count'); + const cacheCountEl = document.getElementById('cache-count'); + ruleCountEl.textContent = (defaults.aiRules || []).length; + cacheCountEl.textContent = defaults.aiCache ? Object.keys(defaults.aiCache).length : 0; + document.getElementById('clear-cache').addEventListener('click', async () => { + await AiClassifier.clearCache(); + cacheCountEl.textContent = '0'; + }); initialized = true; document.getElementById('save').addEventListener('click', async () => { From 8c03ad008e67833c7a2c954deaa2fce440541162 Mon Sep 17 00:00:00 2001 From: Jordan Wages Date: Sun, 29 Jun 2025 03:16:12 -0500 Subject: [PATCH 066/148] Add queue count stat to maintenance page --- background.js | 2 ++ options/options.html | 1 + options/options.js | 14 ++++++++++++++ 3 files changed, 17 insertions(+) diff --git a/background.js b/background.js index b49e691..781b9df 100644 --- a/background.js +++ b/background.js @@ -388,6 +388,8 @@ async function clearCacheForMessages(idsInput) { logger.aiLog("failed to clear cache for message", { level: 'error' }, e); return { ok: false }; } + } else if (msg?.type === "sortana:getQueueCount") { + return { count: queuedCount + (processing ? 1 : 0) }; } else { logger.aiLog("Unknown message type, ignoring", {level: 'warn'}, msg?.type); } diff --git a/options/options.html b/options/options.html index f776fa2..6ddefa7 100644 --- a/options/options.html +++ b/options/options.html @@ -179,6 +179,7 @@ Rule count Cache entries + Queue items diff --git a/options/options.js b/options/options.js index 5536ad5..7c1e595 100644 --- a/options/options.js +++ b/options/options.js @@ -304,8 +304,22 @@ document.addEventListener('DOMContentLoaded', async () => { const ruleCountEl = document.getElementById('rule-count'); const cacheCountEl = document.getElementById('cache-count'); + const queueCountEl = document.getElementById('queue-count'); ruleCountEl.textContent = (defaults.aiRules || []).length; cacheCountEl.textContent = defaults.aiCache ? Object.keys(defaults.aiCache).length : 0; + + async function refreshQueueCount() { + try { + const { count } = await browser.runtime.sendMessage({ type: 'sortana:getQueueCount' }); + queueCountEl.textContent = count; + } catch (e) { + queueCountEl.textContent = '?'; + } + } + + refreshQueueCount(); + setInterval(refreshQueueCount, 2000); + document.getElementById('clear-cache').addEventListener('click', async () => { await AiClassifier.clearCache(); cacheCountEl.textContent = '0'; From d5aecc6e8a8ede144c20269f64d3b81806eb6ea7 Mon Sep 17 00:00:00 2001 From: Jordan Wages Date: Sun, 29 Jun 2025 20:10:06 -0500 Subject: [PATCH 067/148] Add timing stats to Maintenance tab --- background.js | 35 +++++++++++++++++++++++++++++ modules/AiClassifier.js | 9 +++++++- options/options.html | 3 +++ options/options.js | 49 ++++++++++++++++++++++++++++++++++++----- 4 files changed, 90 insertions(+), 6 deletions(-) diff --git a/background.js b/background.js index 781b9df..6ef7eb5 100644 --- a/background.js +++ b/background.js @@ -19,6 +19,8 @@ let queue = Promise.resolve(); let queuedCount = 0; let processing = false; let iconTimer = null; +let timingStats = { count: 0, mean: 0, m2: 0, total: 0 }; +let currentStart = 0; function setIcon(path) { if (browser.browserAction) { @@ -106,6 +108,7 @@ async function applyAiRules(idsInput) { updateActionIcon(); queue = queue.then(async () => { processing = true; + currentStart = Date.now(); queuedCount--; updateActionIcon(); try { @@ -141,9 +144,27 @@ async function applyAiRules(idsInput) { } } processing = false; + const elapsed = Date.now() - currentStart; + currentStart = 0; + const t = timingStats; + t.count += 1; + t.total += elapsed; + const delta = elapsed - t.mean; + t.mean += delta / t.count; + t.m2 += delta * (elapsed - t.mean); + await storage.local.set({ classifyStats: t }); showTransientIcon("resources/img/done.png"); } catch (e) { processing = false; + const elapsed = Date.now() - currentStart; + currentStart = 0; + const t = timingStats; + t.count += 1; + t.total += elapsed; + const delta = elapsed - t.mean; + t.mean += delta / t.count; + t.m2 += delta * (elapsed - t.mean); + await storage.local.set({ classifyStats: t }); logger.aiLog("failed to apply AI rules", { level: 'error' }, e); showTransientIcon("resources/img/error.png"); } @@ -199,6 +220,10 @@ async function clearCacheForMessages(idsInput) { logger.setDebug(store.debugLogging); await AiClassifier.setConfig(store); await AiClassifier.init(); + const savedStats = await storage.local.get('classifyStats'); + if (savedStats.classifyStats && typeof savedStats.classifyStats === 'object') { + Object.assign(timingStats, savedStats.classifyStats); + } aiRules = Array.isArray(store.aiRules) ? store.aiRules.map(r => { if (r.actions) return r; const actions = []; @@ -390,6 +415,16 @@ async function clearCacheForMessages(idsInput) { } } else if (msg?.type === "sortana:getQueueCount") { return { count: queuedCount + (processing ? 1 : 0) }; + } else if (msg?.type === "sortana:getTiming") { + const t = timingStats; + const std = t.count > 1 ? Math.sqrt(t.m2 / (t.count - 1)) : 0; + return { + count: queuedCount + (processing ? 1 : 0), + current: currentStart ? Date.now() - currentStart : -1, + average: t.mean, + total: t.total, + stddev: std + }; } else { logger.aiLog("Unknown message type, ignoring", {level: 'warn'}, msg?.type); } diff --git a/modules/AiClassifier.js b/modules/AiClassifier.js index de267b6..3c526f8 100644 --- a/modules/AiClassifier.js +++ b/modules/AiClassifier.js @@ -323,6 +323,13 @@ async function clearCache() { } } +async function getCacheSize() { + if (!gCacheLoaded) { + await loadCache(); + } + return gCache.size; +} + function classifyTextSync(text, criterion, cacheKey = null) { if (!Services?.tm?.spinEventLoopUntil) { throw new Error("classifyTextSync requires Services"); @@ -407,4 +414,4 @@ async function init() { await loadCache(); } -export { classifyText, classifyTextSync, setConfig, removeCacheEntries, clearCache, getReason, getCachedResult, buildCacheKey, buildCacheKeySync, init }; +export { classifyText, classifyTextSync, setConfig, removeCacheEntries, clearCache, getReason, getCachedResult, buildCacheKey, buildCacheKeySync, getCacheSize, init }; diff --git a/options/options.html b/options/options.html index 6ddefa7..ed1ef41 100644 --- a/options/options.html +++ b/options/options.html @@ -180,6 +180,9 @@ Rule count Cache entries Queue items + Current run time--:-- + Average run time--:-- + Total run time--:-- diff --git a/options/options.js b/options/options.js index 7c1e595..997d7f7 100644 --- a/options/options.js +++ b/options/options.js @@ -305,20 +305,59 @@ document.addEventListener('DOMContentLoaded', async () => { const ruleCountEl = document.getElementById('rule-count'); const cacheCountEl = document.getElementById('cache-count'); const queueCountEl = document.getElementById('queue-count'); + const currentTimeEl = document.getElementById('current-time'); + const averageTimeEl = document.getElementById('average-time'); + const totalTimeEl = document.getElementById('total-time'); + let timingLogged = false; ruleCountEl.textContent = (defaults.aiRules || []).length; cacheCountEl.textContent = defaults.aiCache ? Object.keys(defaults.aiCache).length : 0; - async function refreshQueueCount() { + function format(ms) { + if (ms < 0) return '--:--'; + return (ms / 1000).toFixed(1) + 's'; + } + + async function refreshMaintenance() { try { - const { count } = await browser.runtime.sendMessage({ type: 'sortana:getQueueCount' }); - queueCountEl.textContent = count; + const stats = await browser.runtime.sendMessage({ type: 'sortana:getTiming' }); + queueCountEl.textContent = stats.count; + currentTimeEl.classList.remove('has-text-success','has-text-danger'); + let arrow = ''; + if (stats.current >= 0) { + if (stats.stddev > 0 && stats.current - stats.average > stats.stddev) { + currentTimeEl.classList.add('has-text-danger'); + arrow = ' ▲'; + } else if (stats.stddev > 0 && stats.average - stats.current > stats.stddev) { + currentTimeEl.classList.add('has-text-success'); + arrow = ' ▼'; + } + currentTimeEl.textContent = format(stats.current) + arrow; + } else { + currentTimeEl.textContent = '--:--'; + } + averageTimeEl.textContent = stats.count ? format(stats.average) : '--:--'; + totalTimeEl.textContent = format(stats.total); + if (!timingLogged) { + logger.aiLog('retrieved timing stats', {debug: true}); + timingLogged = true; + } } catch (e) { queueCountEl.textContent = '?'; + currentTimeEl.textContent = '--:--'; + averageTimeEl.textContent = '--:--'; + totalTimeEl.textContent = '--:--'; + } + + ruleCountEl.textContent = document.querySelectorAll('#rules-container .rule').length; + try { + cacheCountEl.textContent = await AiClassifier.getCacheSize(); + } catch { + cacheCountEl.textContent = '?'; } } - refreshQueueCount(); - setInterval(refreshQueueCount, 2000); + refreshMaintenance(); + setInterval(refreshMaintenance, 2000); document.getElementById('clear-cache').addEventListener('click', async () => { await AiClassifier.clearCache(); From 15de566068f62603bc367dede0750ca78a0ce7b3 Mon Sep 17 00:00:00 2001 From: Jordan Wages Date: Sun, 29 Jun 2025 20:10:38 -0500 Subject: [PATCH 068/148] Delete logger.jsm --- modules/logger.jsm | 26 -------------------------- 1 file changed, 26 deletions(-) delete mode 100644 modules/logger.jsm diff --git a/modules/logger.jsm b/modules/logger.jsm deleted file mode 100644 index 7c64176..0000000 --- a/modules/logger.jsm +++ /dev/null @@ -1,26 +0,0 @@ -var EXPORTED_SYMBOLS = ['aiLog', 'setDebug']; -let debugEnabled = false; - -function setDebug(value) { - debugEnabled = !!value; -} - -function getCaller() { - try { - let stack = new Error().stack.split('\n'); - if (stack.length >= 3) { - return stack[2].trim().replace(/^@?\s*\(?/,'').replace(/^at\s+/, ''); - } - } catch (e) {} - return ''; -} - -function aiLog(message, opts = {}, ...args) { - const { level = 'log', debug = false } = opts; - if (debug && !debugEnabled) { - return; - } - const caller = getCaller(); - const prefix = caller ? `[ai-filter][${caller}]` : '[ai-filter]'; - console[level](`%c${prefix}`, 'color:#1c92d2;font-weight:bold', message, ...args); -} From c2e114266ebd929c4a4970fd3771b77f939e17fd Mon Sep 17 00:00:00 2001 From: Jordan Wages Date: Sun, 29 Jun 2025 21:22:31 -0500 Subject: [PATCH 069/148] Update maintenance stats display --- background.js | 9 ++++++++- options/options.html | 7 ++++--- options/options.js | 44 ++++++++++++++++++++++++++++++-------------- 3 files changed, 42 insertions(+), 18 deletions(-) diff --git a/background.js b/background.js index 6ef7eb5..3960e27 100644 --- a/background.js +++ b/background.js @@ -19,7 +19,7 @@ let queue = Promise.resolve(); let queuedCount = 0; let processing = false; let iconTimer = null; -let timingStats = { count: 0, mean: 0, m2: 0, total: 0 }; +let timingStats = { count: 0, mean: 0, m2: 0, total: 0, last: -1 }; let currentStart = 0; function setIcon(path) { @@ -149,6 +149,7 @@ async function applyAiRules(idsInput) { const t = timingStats; t.count += 1; t.total += elapsed; + t.last = elapsed; const delta = elapsed - t.mean; t.mean += delta / t.count; t.m2 += delta * (elapsed - t.mean); @@ -161,6 +162,7 @@ async function applyAiRules(idsInput) { const t = timingStats; t.count += 1; t.total += elapsed; + t.last = elapsed; const delta = elapsed - t.mean; t.mean += delta / t.count; t.m2 += delta * (elapsed - t.mean); @@ -224,6 +226,9 @@ async function clearCacheForMessages(idsInput) { if (savedStats.classifyStats && typeof savedStats.classifyStats === 'object') { Object.assign(timingStats, savedStats.classifyStats); } + if (typeof timingStats.last !== 'number') { + timingStats.last = -1; + } aiRules = Array.isArray(store.aiRules) ? store.aiRules.map(r => { if (r.actions) return r; const actions = []; @@ -421,6 +426,8 @@ async function clearCacheForMessages(idsInput) { return { count: queuedCount + (processing ? 1 : 0), current: currentStart ? Date.now() - currentStart : -1, + last: t.last, + runs: t.count, average: t.mean, total: t.total, stddev: std diff --git a/options/options.html b/options/options.html index ed1ef41..cb9668a 100644 --- a/options/options.html +++ b/options/options.html @@ -180,9 +180,10 @@ Rule count Cache entries Queue items - Current run time--:-- - Average run time--:-- - Total run time--:-- + Current run time--:--:-- + Last run time--:--:-- + Average run time--:--:-- + Total run time--:--:-- diff --git a/options/options.js b/options/options.js index 997d7f7..58dcd4f 100644 --- a/options/options.js +++ b/options/options.js @@ -306,6 +306,7 @@ document.addEventListener('DOMContentLoaded', async () => { const cacheCountEl = document.getElementById('cache-count'); const queueCountEl = document.getElementById('queue-count'); const currentTimeEl = document.getElementById('current-time'); + const lastTimeEl = document.getElementById('last-time'); const averageTimeEl = document.getElementById('average-time'); const totalTimeEl = document.getElementById('total-time'); let timingLogged = false; @@ -313,29 +314,43 @@ document.addEventListener('DOMContentLoaded', async () => { cacheCountEl.textContent = defaults.aiCache ? Object.keys(defaults.aiCache).length : 0; function format(ms) { - if (ms < 0) return '--:--'; - return (ms / 1000).toFixed(1) + 's'; + if (ms < 0) return '--:--:--'; + let totalSec = Math.floor(ms / 1000); + const sec = totalSec % 60; + totalSec = (totalSec - sec) / 60; + const min = totalSec % 60; + const hr = (totalSec - min) / 60; + return `${String(hr).padStart(2, '0')}:${String(min).padStart(2, '0')}:${String(sec).padStart(2, '0')}`; } async function refreshMaintenance() { try { const stats = await browser.runtime.sendMessage({ type: 'sortana:getTiming' }); queueCountEl.textContent = stats.count; - currentTimeEl.classList.remove('has-text-success','has-text-danger'); + currentTimeEl.classList.remove('has-text-danger'); + lastTimeEl.classList.remove('has-text-success','has-text-danger'); let arrow = ''; + if (stats.last >= 0) { + if (stats.stddev > 0 && stats.last - stats.average > stats.stddev) { + lastTimeEl.classList.add('has-text-danger'); + arrow = ' ▲'; + } else if (stats.stddev > 0 && stats.average - stats.last > stats.stddev) { + lastTimeEl.classList.add('has-text-success'); + arrow = ' ▼'; + } + lastTimeEl.textContent = format(stats.last) + arrow; + } else { + lastTimeEl.textContent = '--:--:--'; + } if (stats.current >= 0) { if (stats.stddev > 0 && stats.current - stats.average > stats.stddev) { currentTimeEl.classList.add('has-text-danger'); - arrow = ' ▲'; - } else if (stats.stddev > 0 && stats.average - stats.current > stats.stddev) { - currentTimeEl.classList.add('has-text-success'); - arrow = ' ▼'; } - currentTimeEl.textContent = format(stats.current) + arrow; + currentTimeEl.textContent = format(stats.current); } else { - currentTimeEl.textContent = '--:--'; + currentTimeEl.textContent = '--:--:--'; } - averageTimeEl.textContent = stats.count ? format(stats.average) : '--:--'; + averageTimeEl.textContent = stats.runs > 0 ? format(stats.average) : '--:--:--'; totalTimeEl.textContent = format(stats.total); if (!timingLogged) { logger.aiLog('retrieved timing stats', {debug: true}); @@ -343,9 +358,10 @@ document.addEventListener('DOMContentLoaded', async () => { } } catch (e) { queueCountEl.textContent = '?'; - currentTimeEl.textContent = '--:--'; - averageTimeEl.textContent = '--:--'; - totalTimeEl.textContent = '--:--'; + currentTimeEl.textContent = '--:--:--'; + lastTimeEl.textContent = '--:--:--'; + averageTimeEl.textContent = '--:--:--'; + totalTimeEl.textContent = '--:--:--'; } ruleCountEl.textContent = document.querySelectorAll('#rules-container .rule').length; @@ -357,7 +373,7 @@ document.addEventListener('DOMContentLoaded', async () => { } refreshMaintenance(); - setInterval(refreshMaintenance, 2000); + setInterval(refreshMaintenance, 1000); document.getElementById('clear-cache').addEventListener('click', async () => { await AiClassifier.clearCache(); From f9c1f0f048a063fe0537b541027041e73061ca2c Mon Sep 17 00:00:00 2001 From: Jordan Wages Date: Sun, 29 Jun 2025 23:34:51 -0500 Subject: [PATCH 070/148] Update documentation for current code --- AGENTS.md | 6 +++--- README.md | 26 +++++++++++++------------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 9ae810b..ab79c66 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -5,9 +5,9 @@ This file provides guidelines for codex agents contributing to the Sortana proje ## Repository Overview - `background.js`: Handles startup tasks and coordinates message passing within the extension. -- `modules/`: Holds reusable JavaScript modules for the extension. -- `content/`: Scripts for modifying Thunderbird windows (e.g., the filter editor). -- `options/`: The options page HTML and JavaScript. +- `modules/`: Contains reusable JavaScript modules such as `AiClassifier.js`. +- `options/`: The options page HTML, JavaScript and Bulma CSS. +- `details.html` and `details.js`: View AI reasoning and clear cache for a message. - `resources/`: Images and other static files. - `prompt_templates/`: Prompt template files for the AI service. - `build-xpi.ps1`: PowerShell script to package the extension. diff --git a/README.md b/README.md index 3e60766..ef4c429 100644 --- a/README.md +++ b/README.md @@ -9,13 +9,10 @@ message meets a specified criterion. ## Features -- **AI classification rule** – adds the "AI classification" term with - `matches` and `doesn't match` operators. +- **AI classification rule** – adds the "AI classification" term with `matches` and `doesn't match` operators. - **Configurable endpoint** – set the classification service URL on the options page. - **Prompt templates** – choose between several model formats or provide your own custom template. - **Custom system prompts** – tailor the instructions sent to the model for more precise results. -- **Filter editor integration** – patches Thunderbird's filter editor to accept - text criteria for AI classification. - **Persistent result caching** – classification results and reasoning are saved to disk so messages aren't re-evaluated across restarts. - **Advanced parameters** – tune generation settings like temperature, top‑p and more from the options page. - **Debug logging** – optional colorized logs help troubleshoot interactions with the AI service. @@ -23,6 +20,9 @@ message meets a specified criterion. - **Rule ordering** – drag rules to prioritize them and optionally stop processing after a match. - **Context menu** – apply AI rules from the message list or the message display action button. - **Status icons** – toolbar icons show when classification is in progress and briefly display success or error states. +- **View reasoning** – inspect why rules matched via the Details popup. +- **Cache management** – clear cached results from the context menu or options page. +- **Queue & timing stats** – monitor processing time on the Maintenance tab. - **Packaging script** – `build-xpi.ps1` builds an XPI ready for installation. - **Maintenance tab** – view rule counts, cache entries and clear cached results from the options page. @@ -37,22 +37,22 @@ containing `matched` and `reason` fields. Older installations with a separate Sortana is implemented entirely with standard WebExtension scripts—no custom experiment code is required: -- `background.js` loads saved settings and listens for new messages. -- `modules/ExpressionSearchFilter.jsm` implements the AI filter and performs the - HTTP request. -- `options/` contains the HTML and JavaScript for configuring the endpoint and - rules. +- `background.js` loads saved settings, manages the classification queue and listens for new messages. +- `modules/AiClassifier.js` implements the classification logic and cache handling. +- `options/` contains the HTML and JavaScript for configuring the endpoint and rules. +- `details.html` / `details.js` present cached reasoning for a message. - `_locales/` holds localized strings used throughout the UI. ### Key Files | Path | Purpose | | --------------------------------------- | ---------------------------------------------- | -| `manifest.json` | Extension manifest and entry points. | -| `background.js` | Startup tasks and message handling. | -| `modules/ExpressionSearchFilter.jsm` | Custom filter term and AI request logic. | +| `manifest.json` | Extension manifest and entry points. | +| `background.js` | Startup tasks and classification queue management. | +| `modules/AiClassifier.js` | Core classification logic and cache handling. | | `options/options.html` and `options.js` | Endpoint and rule configuration UI. | -| `logger.js` and `modules/logger.jsm` | Colorized logging with optional debug mode. | +| `details.html` and `details.js` | View stored reasoning for a message. | +| `logger.js` | Colorized logging with optional debug mode. | ## Building From d7416c16ceb02f853d64fe44d5253acde525a3fe Mon Sep 17 00:00:00 2001 From: Jordan Wages Date: Sun, 29 Jun 2025 23:37:34 -0500 Subject: [PATCH 071/148] Update README.md --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index ef4c429..2baa5e8 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,6 @@ message meets a specified criterion. ## Features -- **AI classification rule** – adds the "AI classification" term with `matches` and `doesn't match` operators. - **Configurable endpoint** – set the classification service URL on the options page. - **Prompt templates** – choose between several model formats or provide your own custom template. - **Custom system prompts** – tailor the instructions sent to the model for more precise results. From 86db83bb66103b2eb48363652cb17c1238ad5704 Mon Sep 17 00:00:00 2001 From: Jordan Wages Date: Mon, 30 Jun 2025 01:56:22 -0500 Subject: [PATCH 072/148] Cleanup --- ai-filter.sln | 3 --- background.js | 12 ++++++++---- build-xpi.ps1 | 2 +- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/ai-filter.sln b/ai-filter.sln index 2d171dd..86ceaed 100644 --- a/ai-filter.sln +++ b/ai-filter.sln @@ -30,9 +30,6 @@ EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "modules", "modules", "{75ED3C1E-D3C7-4546-9F2E-AC85859DDF4B}" ProjectSection(SolutionItems) = preProject modules\AiClassifier.js = modules\AiClassifier.js - modules\ExpressionSearchFilter.jsm = modules\ExpressionSearchFilter.jsm - modules\logger.jsm = modules\logger.jsm - modules\messageUtils.jsm = modules\messageUtils.jsm EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "_locales", "_locales", "{D446E5C6-BDDE-4091-BD1A-EC57170003CF}" diff --git a/background.js b/background.js index 3960e27..d0425c2 100644 --- a/background.js +++ b/background.js @@ -21,6 +21,7 @@ let processing = false; let iconTimer = null; let timingStats = { count: 0, mean: 0, m2: 0, total: 0, last: -1 }; let currentStart = 0; +let logGetTiming = true; function setIcon(path) { if (browser.browserAction) { @@ -321,12 +322,15 @@ async function clearCacheForMessages(idsInput) { // Listen for messages from UI/devtools browser.runtime.onMessage.addListener(async (msg) => { - logger.aiLog("onMessage received", {debug: true}, msg); + if ((msg?.type === "sortana:getTiming" && logGetTiming) || (msg?.type !== "sortana:getTiming")) { + logGetTiming = false; + logger.aiLog("onMessage received", { debug: true }, msg); + } - if (msg?.type === "aiFilter:test") { + if (msg?.type === "sortana:test") { const { text = "", criterion = "" } = msg; - logger.aiLog("aiFilter:test – text", {debug: true}, text); - logger.aiLog("aiFilter:test – criterion", {debug: true}, criterion); + logger.aiLog("sortana:test – text", {debug: true}, text); + logger.aiLog("sortana:test – criterion", {debug: true}, criterion); try { logger.aiLog("Calling AiClassifier.classifyText()", {debug: true}); diff --git a/build-xpi.ps1 b/build-xpi.ps1 index 92a9474..708fe72 100644 --- a/build-xpi.ps1 +++ b/build-xpi.ps1 @@ -26,7 +26,7 @@ if (-not $version) { } # 4) Define output names & clean up -$xpiName = "ai-filter-$version.xpi" +$xpiName = "sortana-$version.xpi" $zipPath = Join-Path $ReleaseDir "ai-filter-$version.zip" $xpiPath = Join-Path $ReleaseDir $xpiName From 8ae32fe752d679e403e48d1cce0972e28cd712df Mon Sep 17 00:00:00 2001 From: Jordan Wages Date: Thu, 3 Jul 2025 03:07:59 -0500 Subject: [PATCH 073/148] Housekeeping for add-on store --- manifest.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/manifest.json b/manifest.json index 3f17845..506e392 100644 --- a/manifest.json +++ b/manifest.json @@ -7,7 +7,7 @@ "gecko": { "id": "ai-filter@jordanwages", "strict_min_version": "128.0", - "strict_max_version": "*" + "strict_max_version": "140.*" } }, "icons": { From 1057d8c7fd77154d9e33a873bab5e6053998bbe7 Mon Sep 17 00:00:00 2001 From: Jordan Wages Date: Sat, 5 Jul 2025 01:51:32 -0500 Subject: [PATCH 074/148] Adding turndown for possible use Looking at adding html to markdown conversion for html email bodies. --- resources/js/turndown.js | 974 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 974 insertions(+) create mode 100644 resources/js/turndown.js diff --git a/resources/js/turndown.js b/resources/js/turndown.js new file mode 100644 index 0000000..e86fb18 --- /dev/null +++ b/resources/js/turndown.js @@ -0,0 +1,974 @@ +var TurndownService = (function () { + 'use strict'; + + function extend (destination) { + for (var i = 1; i < arguments.length; i++) { + var source = arguments[i]; + for (var key in source) { + if (source.hasOwnProperty(key)) destination[key] = source[key]; + } + } + return destination + } + + function repeat (character, count) { + return Array(count + 1).join(character) + } + + function trimLeadingNewlines (string) { + return string.replace(/^\n*/, '') + } + + function trimTrailingNewlines (string) { + // avoid match-at-end regexp bottleneck, see #370 + var indexEnd = string.length; + while (indexEnd > 0 && string[indexEnd - 1] === '\n') indexEnd--; + return string.substring(0, indexEnd) + } + + var blockElements = [ + 'ADDRESS', 'ARTICLE', 'ASIDE', 'AUDIO', 'BLOCKQUOTE', 'BODY', 'CANVAS', + 'CENTER', 'DD', 'DIR', 'DIV', 'DL', 'DT', 'FIELDSET', 'FIGCAPTION', 'FIGURE', + 'FOOTER', 'FORM', 'FRAMESET', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'HEADER', + 'HGROUP', 'HR', 'HTML', 'ISINDEX', 'LI', 'MAIN', 'MENU', 'NAV', 'NOFRAMES', + 'NOSCRIPT', 'OL', 'OUTPUT', 'P', 'PRE', 'SECTION', 'TABLE', 'TBODY', 'TD', + 'TFOOT', 'TH', 'THEAD', 'TR', 'UL' + ]; + + function isBlock (node) { + return is(node, blockElements) + } + + var voidElements = [ + 'AREA', 'BASE', 'BR', 'COL', 'COMMAND', 'EMBED', 'HR', 'IMG', 'INPUT', + 'KEYGEN', 'LINK', 'META', 'PARAM', 'SOURCE', 'TRACK', 'WBR' + ]; + + function isVoid (node) { + return is(node, voidElements) + } + + function hasVoid (node) { + return has(node, voidElements) + } + + var meaningfulWhenBlankElements = [ + 'A', 'TABLE', 'THEAD', 'TBODY', 'TFOOT', 'TH', 'TD', 'IFRAME', 'SCRIPT', + 'AUDIO', 'VIDEO' + ]; + + function isMeaningfulWhenBlank (node) { + return is(node, meaningfulWhenBlankElements) + } + + function hasMeaningfulWhenBlank (node) { + return has(node, meaningfulWhenBlankElements) + } + + function is (node, tagNames) { + return tagNames.indexOf(node.nodeName) >= 0 + } + + function has (node, tagNames) { + return ( + node.getElementsByTagName && + tagNames.some(function (tagName) { + return node.getElementsByTagName(tagName).length + }) + ) + } + + var rules = {}; + + rules.paragraph = { + filter: 'p', + + replacement: function (content) { + return '\n\n' + content + '\n\n' + } + }; + + rules.lineBreak = { + filter: 'br', + + replacement: function (content, node, options) { + return options.br + '\n' + } + }; + + rules.heading = { + filter: ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'], + + replacement: function (content, node, options) { + var hLevel = Number(node.nodeName.charAt(1)); + + if (options.headingStyle === 'setext' && hLevel < 3) { + var underline = repeat((hLevel === 1 ? '=' : '-'), content.length); + return ( + '\n\n' + content + '\n' + underline + '\n\n' + ) + } else { + return '\n\n' + repeat('#', hLevel) + ' ' + content + '\n\n' + } + } + }; + + rules.blockquote = { + filter: 'blockquote', + + replacement: function (content) { + content = content.replace(/^\n+|\n+$/g, ''); + content = content.replace(/^/gm, '> '); + return '\n\n' + content + '\n\n' + } + }; + + rules.list = { + filter: ['ul', 'ol'], + + replacement: function (content, node) { + var parent = node.parentNode; + if (parent.nodeName === 'LI' && parent.lastElementChild === node) { + return '\n' + content + } else { + return '\n\n' + content + '\n\n' + } + } + }; + + rules.listItem = { + filter: 'li', + + replacement: function (content, node, options) { + content = content + .replace(/^\n+/, '') // remove leading newlines + .replace(/\n+$/, '\n') // replace trailing newlines with just a single one + .replace(/\n/gm, '\n '); // indent + var prefix = options.bulletListMarker + ' '; + var parent = node.parentNode; + if (parent.nodeName === 'OL') { + var start = parent.getAttribute('start'); + var index = Array.prototype.indexOf.call(parent.children, node); + prefix = (start ? Number(start) + index : index + 1) + '. '; + } + return ( + prefix + content + (node.nextSibling && !/\n$/.test(content) ? '\n' : '') + ) + } + }; + + rules.indentedCodeBlock = { + filter: function (node, options) { + return ( + options.codeBlockStyle === 'indented' && + node.nodeName === 'PRE' && + node.firstChild && + node.firstChild.nodeName === 'CODE' + ) + }, + + replacement: function (content, node, options) { + return ( + '\n\n ' + + node.firstChild.textContent.replace(/\n/g, '\n ') + + '\n\n' + ) + } + }; + + rules.fencedCodeBlock = { + filter: function (node, options) { + return ( + options.codeBlockStyle === 'fenced' && + node.nodeName === 'PRE' && + node.firstChild && + node.firstChild.nodeName === 'CODE' + ) + }, + + replacement: function (content, node, options) { + var className = node.firstChild.getAttribute('class') || ''; + var language = (className.match(/language-(\S+)/) || [null, ''])[1]; + var code = node.firstChild.textContent; + + var fenceChar = options.fence.charAt(0); + var fenceSize = 3; + var fenceInCodeRegex = new RegExp('^' + fenceChar + '{3,}', 'gm'); + + var match; + while ((match = fenceInCodeRegex.exec(code))) { + if (match[0].length >= fenceSize) { + fenceSize = match[0].length + 1; + } + } + + var fence = repeat(fenceChar, fenceSize); + + return ( + '\n\n' + fence + language + '\n' + + code.replace(/\n$/, '') + + '\n' + fence + '\n\n' + ) + } + }; + + rules.horizontalRule = { + filter: 'hr', + + replacement: function (content, node, options) { + return '\n\n' + options.hr + '\n\n' + } + }; + + rules.inlineLink = { + filter: function (node, options) { + return ( + options.linkStyle === 'inlined' && + node.nodeName === 'A' && + node.getAttribute('href') + ) + }, + + replacement: function (content, node) { + var href = node.getAttribute('href'); + if (href) href = href.replace(/([()])/g, '\\$1'); + var title = cleanAttribute(node.getAttribute('title')); + if (title) title = ' "' + title.replace(/"/g, '\\"') + '"'; + return '[' + content + '](' + href + title + ')' + } + }; + + rules.referenceLink = { + filter: function (node, options) { + return ( + options.linkStyle === 'referenced' && + node.nodeName === 'A' && + node.getAttribute('href') + ) + }, + + replacement: function (content, node, options) { + var href = node.getAttribute('href'); + var title = cleanAttribute(node.getAttribute('title')); + if (title) title = ' "' + title + '"'; + var replacement; + var reference; + + switch (options.linkReferenceStyle) { + case 'collapsed': + replacement = '[' + content + '][]'; + reference = '[' + content + ']: ' + href + title; + break + case 'shortcut': + replacement = '[' + content + ']'; + reference = '[' + content + ']: ' + href + title; + break + default: + var id = this.references.length + 1; + replacement = '[' + content + '][' + id + ']'; + reference = '[' + id + ']: ' + href + title; + } + + this.references.push(reference); + return replacement + }, + + references: [], + + append: function (options) { + var references = ''; + if (this.references.length) { + references = '\n\n' + this.references.join('\n') + '\n\n'; + this.references = []; // Reset references + } + return references + } + }; + + rules.emphasis = { + filter: ['em', 'i'], + + replacement: function (content, node, options) { + if (!content.trim()) return '' + return options.emDelimiter + content + options.emDelimiter + } + }; + + rules.strong = { + filter: ['strong', 'b'], + + replacement: function (content, node, options) { + if (!content.trim()) return '' + return options.strongDelimiter + content + options.strongDelimiter + } + }; + + rules.code = { + filter: function (node) { + var hasSiblings = node.previousSibling || node.nextSibling; + var isCodeBlock = node.parentNode.nodeName === 'PRE' && !hasSiblings; + + return node.nodeName === 'CODE' && !isCodeBlock + }, + + replacement: function (content) { + if (!content) return '' + content = content.replace(/\r?\n|\r/g, ' '); + + var extraSpace = /^`|^ .*?[^ ].* $|`$/.test(content) ? ' ' : ''; + var delimiter = '`'; + var matches = content.match(/`+/gm) || []; + while (matches.indexOf(delimiter) !== -1) delimiter = delimiter + '`'; + + return delimiter + extraSpace + content + extraSpace + delimiter + } + }; + + rules.image = { + filter: 'img', + + replacement: function (content, node) { + var alt = cleanAttribute(node.getAttribute('alt')); + var src = node.getAttribute('src') || ''; + var title = cleanAttribute(node.getAttribute('title')); + var titlePart = title ? ' "' + title + '"' : ''; + return src ? '![' + alt + ']' + '(' + src + titlePart + ')' : '' + } + }; + + function cleanAttribute (attribute) { + return attribute ? attribute.replace(/(\n+\s*)+/g, '\n') : '' + } + + /** + * Manages a collection of rules used to convert HTML to Markdown + */ + + function Rules (options) { + this.options = options; + this._keep = []; + this._remove = []; + + this.blankRule = { + replacement: options.blankReplacement + }; + + this.keepReplacement = options.keepReplacement; + + this.defaultRule = { + replacement: options.defaultReplacement + }; + + this.array = []; + for (var key in options.rules) this.array.push(options.rules[key]); + } + + Rules.prototype = { + add: function (key, rule) { + this.array.unshift(rule); + }, + + keep: function (filter) { + this._keep.unshift({ + filter: filter, + replacement: this.keepReplacement + }); + }, + + remove: function (filter) { + this._remove.unshift({ + filter: filter, + replacement: function () { + return '' + } + }); + }, + + forNode: function (node) { + if (node.isBlank) return this.blankRule + var rule; + + if ((rule = findRule(this.array, node, this.options))) return rule + if ((rule = findRule(this._keep, node, this.options))) return rule + if ((rule = findRule(this._remove, node, this.options))) return rule + + return this.defaultRule + }, + + forEach: function (fn) { + for (var i = 0; i < this.array.length; i++) fn(this.array[i], i); + } + }; + + function findRule (rules, node, options) { + for (var i = 0; i < rules.length; i++) { + var rule = rules[i]; + if (filterValue(rule, node, options)) return rule + } + return void 0 + } + + function filterValue (rule, node, options) { + var filter = rule.filter; + if (typeof filter === 'string') { + if (filter === node.nodeName.toLowerCase()) return true + } else if (Array.isArray(filter)) { + if (filter.indexOf(node.nodeName.toLowerCase()) > -1) return true + } else if (typeof filter === 'function') { + if (filter.call(rule, node, options)) return true + } else { + throw new TypeError('`filter` needs to be a string, array, or function') + } + } + + /** + * The collapseWhitespace function is adapted from collapse-whitespace + * by Luc Thevenard. + * + * The MIT License (MIT) + * + * Copyright (c) 2014 Luc Thevenard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + + /** + * collapseWhitespace(options) removes extraneous whitespace from an the given element. + * + * @param {Object} options + */ + function collapseWhitespace (options) { + var element = options.element; + var isBlock = options.isBlock; + var isVoid = options.isVoid; + var isPre = options.isPre || function (node) { + return node.nodeName === 'PRE' + }; + + if (!element.firstChild || isPre(element)) return + + var prevText = null; + var keepLeadingWs = false; + + var prev = null; + var node = next(prev, element, isPre); + + while (node !== element) { + if (node.nodeType === 3 || node.nodeType === 4) { // Node.TEXT_NODE or Node.CDATA_SECTION_NODE + var text = node.data.replace(/[ \r\n\t]+/g, ' '); + + if ((!prevText || / $/.test(prevText.data)) && + !keepLeadingWs && text[0] === ' ') { + text = text.substr(1); + } + + // `text` might be empty at this point. + if (!text) { + node = remove(node); + continue + } + + node.data = text; + + prevText = node; + } else if (node.nodeType === 1) { // Node.ELEMENT_NODE + if (isBlock(node) || node.nodeName === 'BR') { + if (prevText) { + prevText.data = prevText.data.replace(/ $/, ''); + } + + prevText = null; + keepLeadingWs = false; + } else if (isVoid(node) || isPre(node)) { + // Avoid trimming space around non-block, non-BR void elements and inline PRE. + prevText = null; + keepLeadingWs = true; + } else if (prevText) { + // Drop protection if set previously. + keepLeadingWs = false; + } + } else { + node = remove(node); + continue + } + + var nextNode = next(prev, node, isPre); + prev = node; + node = nextNode; + } + + if (prevText) { + prevText.data = prevText.data.replace(/ $/, ''); + if (!prevText.data) { + remove(prevText); + } + } + } + + /** + * remove(node) removes the given node from the DOM and returns the + * next node in the sequence. + * + * @param {Node} node + * @return {Node} node + */ + function remove (node) { + var next = node.nextSibling || node.parentNode; + + node.parentNode.removeChild(node); + + return next + } + + /** + * next(prev, current, isPre) returns the next node in the sequence, given the + * current and previous nodes. + * + * @param {Node} prev + * @param {Node} current + * @param {Function} isPre + * @return {Node} + */ + function next (prev, current, isPre) { + if ((prev && prev.parentNode === current) || isPre(current)) { + return current.nextSibling || current.parentNode + } + + return current.firstChild || current.nextSibling || current.parentNode + } + + /* + * Set up window for Node.js + */ + + var root = (typeof window !== 'undefined' ? window : {}); + + /* + * Parsing HTML strings + */ + + function canParseHTMLNatively () { + var Parser = root.DOMParser; + var canParse = false; + + // Adapted from https://gist.github.com/1129031 + // Firefox/Opera/IE throw errors on unsupported types + try { + // WebKit returns null on unsupported types + if (new Parser().parseFromString('', 'text/html')) { + canParse = true; + } + } catch (e) {} + + return canParse + } + + function createHTMLParser () { + var Parser = function () {}; + + { + if (shouldUseActiveX()) { + Parser.prototype.parseFromString = function (string) { + var doc = new window.ActiveXObject('htmlfile'); + doc.designMode = 'on'; // disable on-page scripts + doc.open(); + doc.write(string); + doc.close(); + return doc + }; + } else { + Parser.prototype.parseFromString = function (string) { + var doc = document.implementation.createHTMLDocument(''); + doc.open(); + doc.write(string); + doc.close(); + return doc + }; + } + } + return Parser + } + + function shouldUseActiveX () { + var useActiveX = false; + try { + document.implementation.createHTMLDocument('').open(); + } catch (e) { + if (root.ActiveXObject) useActiveX = true; + } + return useActiveX + } + + var HTMLParser = canParseHTMLNatively() ? root.DOMParser : createHTMLParser(); + + function RootNode (input, options) { + var root; + if (typeof input === 'string') { + var doc = htmlParser().parseFromString( + // DOM parsers arrange elements in the and . + // Wrapping in a custom element ensures elements are reliably arranged in + // a single element. + '' + input + '', + 'text/html' + ); + root = doc.getElementById('turndown-root'); + } else { + root = input.cloneNode(true); + } + collapseWhitespace({ + element: root, + isBlock: isBlock, + isVoid: isVoid, + isPre: options.preformattedCode ? isPreOrCode : null + }); + + return root + } + + var _htmlParser; + function htmlParser () { + _htmlParser = _htmlParser || new HTMLParser(); + return _htmlParser + } + + function isPreOrCode (node) { + return node.nodeName === 'PRE' || node.nodeName === 'CODE' + } + + function Node (node, options) { + node.isBlock = isBlock(node); + node.isCode = node.nodeName === 'CODE' || node.parentNode.isCode; + node.isBlank = isBlank(node); + node.flankingWhitespace = flankingWhitespace(node, options); + return node + } + + function isBlank (node) { + return ( + !isVoid(node) && + !isMeaningfulWhenBlank(node) && + /^\s*$/i.test(node.textContent) && + !hasVoid(node) && + !hasMeaningfulWhenBlank(node) + ) + } + + function flankingWhitespace (node, options) { + if (node.isBlock || (options.preformattedCode && node.isCode)) { + return { leading: '', trailing: '' } + } + + var edges = edgeWhitespace(node.textContent); + + // abandon leading ASCII WS if left-flanked by ASCII WS + if (edges.leadingAscii && isFlankedByWhitespace('left', node, options)) { + edges.leading = edges.leadingNonAscii; + } + + // abandon trailing ASCII WS if right-flanked by ASCII WS + if (edges.trailingAscii && isFlankedByWhitespace('right', node, options)) { + edges.trailing = edges.trailingNonAscii; + } + + return { leading: edges.leading, trailing: edges.trailing } + } + + function edgeWhitespace (string) { + var m = string.match(/^(([ \t\r\n]*)(\s*))(?:(?=\S)[\s\S]*\S)?((\s*?)([ \t\r\n]*))$/); + return { + leading: m[1], // whole string for whitespace-only strings + leadingAscii: m[2], + leadingNonAscii: m[3], + trailing: m[4], // empty for whitespace-only strings + trailingNonAscii: m[5], + trailingAscii: m[6] + } + } + + function isFlankedByWhitespace (side, node, options) { + var sibling; + var regExp; + var isFlanked; + + if (side === 'left') { + sibling = node.previousSibling; + regExp = / $/; + } else { + sibling = node.nextSibling; + regExp = /^ /; + } + + if (sibling) { + if (sibling.nodeType === 3) { + isFlanked = regExp.test(sibling.nodeValue); + } else if (options.preformattedCode && sibling.nodeName === 'CODE') { + isFlanked = false; + } else if (sibling.nodeType === 1 && !isBlock(sibling)) { + isFlanked = regExp.test(sibling.textContent); + } + } + return isFlanked + } + + var reduce = Array.prototype.reduce; + var escapes = [ + [/\\/g, '\\\\'], + [/\*/g, '\\*'], + [/^-/g, '\\-'], + [/^\+ /g, '\\+ '], + [/^(=+)/g, '\\$1'], + [/^(#{1,6}) /g, '\\$1 '], + [/`/g, '\\`'], + [/^~~~/g, '\\~~~'], + [/\[/g, '\\['], + [/\]/g, '\\]'], + [/^>/g, '\\>'], + [/_/g, '\\_'], + [/^(\d+)\. /g, '$1\\. '] + ]; + + function TurndownService (options) { + if (!(this instanceof TurndownService)) return new TurndownService(options) + + var defaults = { + rules: rules, + headingStyle: 'setext', + hr: '* * *', + bulletListMarker: '*', + codeBlockStyle: 'indented', + fence: '```', + emDelimiter: '_', + strongDelimiter: '**', + linkStyle: 'inlined', + linkReferenceStyle: 'full', + br: ' ', + preformattedCode: false, + blankReplacement: function (content, node) { + return node.isBlock ? '\n\n' : '' + }, + keepReplacement: function (content, node) { + return node.isBlock ? '\n\n' + node.outerHTML + '\n\n' : node.outerHTML + }, + defaultReplacement: function (content, node) { + return node.isBlock ? '\n\n' + content + '\n\n' : content + } + }; + this.options = extend({}, defaults, options); + this.rules = new Rules(this.options); + } + + TurndownService.prototype = { + /** + * The entry point for converting a string or DOM node to Markdown + * @public + * @param {String|HTMLElement} input The string or DOM node to convert + * @returns A Markdown representation of the input + * @type String + */ + + turndown: function (input) { + if (!canConvert(input)) { + throw new TypeError( + input + ' is not a string, or an element/document/fragment node.' + ) + } + + if (input === '') return '' + + var output = process.call(this, new RootNode(input, this.options)); + return postProcess.call(this, output) + }, + + /** + * Add one or more plugins + * @public + * @param {Function|Array} plugin The plugin or array of plugins to add + * @returns The Turndown instance for chaining + * @type Object + */ + + use: function (plugin) { + if (Array.isArray(plugin)) { + for (var i = 0; i < plugin.length; i++) this.use(plugin[i]); + } else if (typeof plugin === 'function') { + plugin(this); + } else { + throw new TypeError('plugin must be a Function or an Array of Functions') + } + return this + }, + + /** + * Adds a rule + * @public + * @param {String} key The unique key of the rule + * @param {Object} rule The rule + * @returns The Turndown instance for chaining + * @type Object + */ + + addRule: function (key, rule) { + this.rules.add(key, rule); + return this + }, + + /** + * Keep a node (as HTML) that matches the filter + * @public + * @param {String|Array|Function} filter The unique key of the rule + * @returns The Turndown instance for chaining + * @type Object + */ + + keep: function (filter) { + this.rules.keep(filter); + return this + }, + + /** + * Remove a node that matches the filter + * @public + * @param {String|Array|Function} filter The unique key of the rule + * @returns The Turndown instance for chaining + * @type Object + */ + + remove: function (filter) { + this.rules.remove(filter); + return this + }, + + /** + * Escapes Markdown syntax + * @public + * @param {String} string The string to escape + * @returns A string with Markdown syntax escaped + * @type String + */ + + escape: function (string) { + return escapes.reduce(function (accumulator, escape) { + return accumulator.replace(escape[0], escape[1]) + }, string) + } + }; + + /** + * Reduces a DOM node down to its Markdown string equivalent + * @private + * @param {HTMLElement} parentNode The node to convert + * @returns A Markdown representation of the node + * @type String + */ + + function process (parentNode) { + var self = this; + return reduce.call(parentNode.childNodes, function (output, node) { + node = new Node(node, self.options); + + var replacement = ''; + if (node.nodeType === 3) { + replacement = node.isCode ? node.nodeValue : self.escape(node.nodeValue); + } else if (node.nodeType === 1) { + replacement = replacementForNode.call(self, node); + } + + return join(output, replacement) + }, '') + } + + /** + * Appends strings as each rule requires and trims the output + * @private + * @param {String} output The conversion output + * @returns A trimmed version of the ouput + * @type String + */ + + function postProcess (output) { + var self = this; + this.rules.forEach(function (rule) { + if (typeof rule.append === 'function') { + output = join(output, rule.append(self.options)); + } + }); + + return output.replace(/^[\t\r\n]+/, '').replace(/[\t\r\n\s]+$/, '') + } + + /** + * Converts an element node to its Markdown equivalent + * @private + * @param {HTMLElement} node The node to convert + * @returns A Markdown representation of the node + * @type String + */ + + function replacementForNode (node) { + var rule = this.rules.forNode(node); + var content = process.call(this, node); + var whitespace = node.flankingWhitespace; + if (whitespace.leading || whitespace.trailing) content = content.trim(); + return ( + whitespace.leading + + rule.replacement(content, node, this.options) + + whitespace.trailing + ) + } + + /** + * Joins replacement to the current output with appropriate number of new lines + * @private + * @param {String} output The current conversion output + * @param {String} replacement The string to append to the output + * @returns Joined output + * @type String + */ + + function join (output, replacement) { + var s1 = trimTrailingNewlines(output); + var s2 = trimLeadingNewlines(replacement); + var nls = Math.max(output.length - s1.length, replacement.length - s2.length); + var separator = '\n\n'.substring(0, nls); + + return s1 + separator + s2 + } + + /** + * Determines whether an input can be converted + * @private + * @param {String|HTMLElement} input Describe this parameter + * @returns Describe what it returns + * @type String|Object|Array|Boolean|Number + */ + + function canConvert (input) { + return ( + input != null && ( + typeof input === 'string' || + (input.nodeType && ( + input.nodeType === 1 || input.nodeType === 9 || input.nodeType === 11 + )) + ) + ) + } + + return TurndownService; + +}()); From 5e0356086a0c4b527f461393ce4dea6cdb9a1e85 Mon Sep 17 00:00:00 2001 From: Jordan Wages Date: Sat, 5 Jul 2025 01:54:38 -0500 Subject: [PATCH 075/148] Update README.md --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 2baa5e8..effdd3f 100644 --- a/README.md +++ b/README.md @@ -121,11 +121,14 @@ the disclosure is only required for add-on review, they'll be listed here as wel uses the following third party libraries: - [Bulma.css v1.0.4](https://github.com/jgthms/bulma/blob/1.0.4/css/bulma.css) + - MIT License +- [turndown v7.2.0](https://github.com/mixmark-io/turndown/tree/v7.2.0) + - MIT License ## License This project is licensed under the terms of the GNU General Public License -version 3. See `LICENSE` for the full text. +version 3. See `LICENSE` for the full text. Third party libraries are licensed seperately. ## Acknowledgments From 200c03c875fbcbe478730a4a492aa782def5fd95 Mon Sep 17 00:00:00 2001 From: Jordan Wages Date: Sat, 5 Jul 2025 02:26:58 -0500 Subject: [PATCH 076/148] Add Markdown conversion option --- README.md | 1 + _locales/en-US/messages.json | 1 + background.js | 23 +++++++++++++++++++++-- options/options.html | 5 +++++ options/options.js | 7 ++++++- resources/js/turndown.js | 3 +++ 6 files changed, 37 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index effdd3f..a5fbce1 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,7 @@ message meets a specified criterion. - **Custom system prompts** – tailor the instructions sent to the model for more precise results. - **Persistent result caching** – classification results and reasoning are saved to disk so messages aren't re-evaluated across restarts. - **Advanced parameters** – tune generation settings like temperature, top‑p and more from the options page. +- **Markdown conversion** – optionally convert HTML bodies to Markdown before sending them to the AI service. - **Debug logging** – optional colorized logs help troubleshoot interactions with the AI service. - **Automatic rules** – create rules that tag or move new messages based on AI classification. - **Rule ordering** – drag rules to prioritize them and optionally stop processing after a match. diff --git a/_locales/en-US/messages.json b/_locales/en-US/messages.json index 591373d..172a152 100644 --- a/_locales/en-US/messages.json +++ b/_locales/en-US/messages.json @@ -15,4 +15,5 @@ "template.custom": { "message": "Custom" }, "options.save": { "message": "Save" }, "options.debugLogging": { "message": "Enable debug logging" } + ,"options.htmlToMarkdown": { "message": "Convert HTML body to Markdown" } } diff --git a/background.js b/background.js index d0425c2..2021990 100644 --- a/background.js +++ b/background.js @@ -22,6 +22,8 @@ let iconTimer = null; let timingStats = { count: 0, mean: 0, m2: 0, total: 0, last: -1 }; let currentStart = 0; let logGetTiming = true; +let htmlToMarkdown = false; +let TurndownService = null; function setIcon(path) { if (browser.browserAction) { @@ -70,7 +72,17 @@ function collectText(part, bodyParts, attachments) { attachments.push(`${name} (${ct}, ${part.size || byteSize(body)} bytes)`); } else if (ct.startsWith("text/html")) { const doc = new DOMParser().parseFromString(body, 'text/html'); - bodyParts.push(replaceInlineBase64(doc.body.textContent || "")); + if (htmlToMarkdown && TurndownService) { + try { + const td = new TurndownService(); + const md = td.turndown(doc.body.innerHTML || body); + bodyParts.push(replaceInlineBase64(`[HTML Body converted to Markdown]\n${md}`)); + } catch (e) { + bodyParts.push(replaceInlineBase64(doc.body.textContent || "")); + } + } else { + bodyParts.push(replaceInlineBase64(doc.body.textContent || "")); + } } else { bodyParts.push(replaceInlineBase64(body)); } @@ -213,16 +225,19 @@ async function clearCacheForMessages(idsInput) { try { AiClassifier = await import(browser.runtime.getURL("modules/AiClassifier.js")); logger.aiLog("AiClassifier imported", {debug: true}); + const td = await import(browser.runtime.getURL("resources/js/turndown.js")); + TurndownService = td.default || td.TurndownService; } catch (e) { console.error("failed to import AiClassifier", e); return; } try { - const store = await storage.local.get(["endpoint", "templateName", "customTemplate", "customSystemPrompt", "aiParams", "debugLogging", "aiRules"]); + const store = await storage.local.get(["endpoint", "templateName", "customTemplate", "customSystemPrompt", "aiParams", "debugLogging", "htmlToMarkdown", "aiRules"]); logger.setDebug(store.debugLogging); await AiClassifier.setConfig(store); await AiClassifier.init(); + htmlToMarkdown = store.htmlToMarkdown === true; const savedStats = await storage.local.get('classifyStats'); if (savedStats.classifyStats && typeof savedStats.classifyStats === 'object') { Object.assign(timingStats, savedStats.classifyStats); @@ -254,6 +269,10 @@ async function clearCacheForMessages(idsInput) { }); logger.aiLog("aiRules updated from storage change", {debug: true}, aiRules); } + if (changes.htmlToMarkdown) { + htmlToMarkdown = changes.htmlToMarkdown.newValue === true; + logger.aiLog("htmlToMarkdown updated from storage change", {debug: true}, htmlToMarkdown); + } }); } catch (err) { logger.aiLog("failed to load config", {level: 'error'}, err); diff --git a/options/options.html b/options/options.html index cb9668a..e285a22 100644 --- a/options/options.html +++ b/options/options.html @@ -98,6 +98,11 @@ Enable debug logging +
+ +
diff --git a/options/options.js b/options/options.js index 58dcd4f..1b8537a 100644 --- a/options/options.js +++ b/options/options.js @@ -9,6 +9,7 @@ document.addEventListener('DOMContentLoaded', async () => { 'customSystemPrompt', 'aiParams', 'debugLogging', + 'htmlToMarkdown', 'aiRules', 'aiCache' ]); @@ -81,6 +82,9 @@ document.addEventListener('DOMContentLoaded', async () => { const debugToggle = document.getElementById('debug-logging'); debugToggle.checked = defaults.debugLogging === true; + const htmlToggle = document.getElementById('html-to-markdown'); + htmlToggle.checked = defaults.htmlToMarkdown === true; + const aiParams = Object.assign({}, DEFAULT_AI_PARAMS, defaults.aiParams || {}); for (const [key, val] of Object.entries(aiParams)) { const el = document.getElementById(key); @@ -395,6 +399,7 @@ document.addEventListener('DOMContentLoaded', async () => { } } const debugLogging = debugToggle.checked; + const htmlToMarkdown = htmlToggle.checked; const rules = [...rulesContainer.querySelectorAll('.rule')].map(ruleEl => { const criterion = ruleEl.querySelector('.criterion').value; const actions = [...ruleEl.querySelectorAll('.action-row')].map(row => { @@ -413,7 +418,7 @@ document.addEventListener('DOMContentLoaded', async () => { const stopProcessing = ruleEl.querySelector('.stop-processing')?.checked; return { criterion, actions, stopProcessing }; }).filter(r => r.criterion); - await storage.local.set({ endpoint, templateName, customTemplate: customTemplateText, customSystemPrompt, aiParams: aiParamsSave, debugLogging, aiRules: rules }); + await storage.local.set({ endpoint, templateName, customTemplate: customTemplateText, customSystemPrompt, aiParams: aiParamsSave, debugLogging, htmlToMarkdown, aiRules: rules }); try { await AiClassifier.setConfig({ endpoint, templateName, customTemplate: customTemplateText, customSystemPrompt, aiParams: aiParamsSave, debugLogging }); logger.setDebug(debugLogging); diff --git a/resources/js/turndown.js b/resources/js/turndown.js index e86fb18..cb9d04d 100644 --- a/resources/js/turndown.js +++ b/resources/js/turndown.js @@ -972,3 +972,6 @@ var TurndownService = (function () { return TurndownService; }()); + +export { TurndownService }; +export default TurndownService; From 149ff03cf902128281917712837344eed353501d Mon Sep 17 00:00:00 2001 From: Jordan Wages Date: Sat, 5 Jul 2025 03:45:49 -0500 Subject: [PATCH 077/148] Add HTML sanitization options --- _locales/en-US/messages.json | 7 +++-- background.js | 61 ++++++++++++++++++++++++++++++++---- options/options.html | 15 +++++++++ options/options.js | 17 +++++++++- 4 files changed, 91 insertions(+), 9 deletions(-) diff --git a/_locales/en-US/messages.json b/_locales/en-US/messages.json index 172a152..97a356b 100644 --- a/_locales/en-US/messages.json +++ b/_locales/en-US/messages.json @@ -14,6 +14,9 @@ "template.mistral": { "message": "Mistral" }, "template.custom": { "message": "Custom" }, "options.save": { "message": "Save" }, - "options.debugLogging": { "message": "Enable debug logging" } - ,"options.htmlToMarkdown": { "message": "Convert HTML body to Markdown" } + "options.debugLogging": { "message": "Enable debug logging" }, + "options.htmlToMarkdown": { "message": "Convert HTML body to Markdown" }, + "options.stripUrlParams": { "message": "Remove URL tracking parameters" }, + "options.altTextImages": { "message": "Replace images with alt text" }, + "options.collapseWhitespace": { "message": "Collapse long whitespace" } } diff --git a/background.js b/background.js index 2021990..0613788 100644 --- a/background.js +++ b/background.js @@ -23,6 +23,9 @@ let timingStats = { count: 0, mean: 0, m2: 0, total: 0, last: -1 }; let currentStart = 0; let logGetTiming = true; let htmlToMarkdown = false; +let stripUrlParams = false; +let altTextImages = false; +let collapseWhitespace = false; let TurndownService = null; function setIcon(path) { @@ -58,6 +61,20 @@ function replaceInlineBase64(text) { m => `[base64: ${byteSize(m)} bytes]`); } +function sanitizeString(text) { + let t = String(text); + if (stripUrlParams) { + t = t.replace(/https?:\/\/[^\s)]+/g, m => { + const idx = m.indexOf('?'); + return idx >= 0 ? m.slice(0, idx) : m; + }); + } + if (collapseWhitespace) { + t = t.replace(/[ \t\u00A0]{2,}/g, ' ').replace(/\n{3,}/g, '\n\n'); + } + return t; +} + function collectText(part, bodyParts, attachments) { if (part.parts && part.parts.length) { for (const p of part.parts) collectText(p, bodyParts, attachments); @@ -72,19 +89,35 @@ function collectText(part, bodyParts, attachments) { attachments.push(`${name} (${ct}, ${part.size || byteSize(body)} bytes)`); } else if (ct.startsWith("text/html")) { const doc = new DOMParser().parseFromString(body, 'text/html'); + if (altTextImages) { + doc.querySelectorAll('img').forEach(img => { + const alt = img.getAttribute('alt') || ''; + img.replaceWith(doc.createTextNode(alt)); + }); + } + if (stripUrlParams) { + doc.querySelectorAll('[href]').forEach(a => { + const href = a.getAttribute('href'); + if (href) a.setAttribute('href', href.split('?')[0]); + }); + doc.querySelectorAll('[src]').forEach(e => { + const src = e.getAttribute('src'); + if (src) e.setAttribute('src', src.split('?')[0]); + }); + } if (htmlToMarkdown && TurndownService) { try { const td = new TurndownService(); - const md = td.turndown(doc.body.innerHTML || body); + const md = sanitizeString(td.turndown(doc.body.innerHTML || body)); bodyParts.push(replaceInlineBase64(`[HTML Body converted to Markdown]\n${md}`)); } catch (e) { - bodyParts.push(replaceInlineBase64(doc.body.textContent || "")); + bodyParts.push(replaceInlineBase64(sanitizeString(doc.body.textContent || ""))); } } else { - bodyParts.push(replaceInlineBase64(doc.body.textContent || "")); + bodyParts.push(replaceInlineBase64(sanitizeString(doc.body.textContent || ""))); } } else { - bodyParts.push(replaceInlineBase64(body)); + bodyParts.push(replaceInlineBase64(sanitizeString(body))); } } @@ -96,7 +129,8 @@ function buildEmailText(full) { .map(([k,v]) => `${k}: ${v.join(' ')}`) .join('\n'); const attachInfo = `Attachments: ${attachments.length}` + (attachments.length ? "\n" + attachments.map(a => ` - ${a}`).join('\n') : ""); - return `${headers}\n${attachInfo}\n\n${bodyParts.join('\n')}`.trim(); + const combined = `${headers}\n${attachInfo}\n\n${bodyParts.join('\n')}`.trim(); + return sanitizeString(combined); } async function applyAiRules(idsInput) { const ids = Array.isArray(idsInput) ? idsInput : [idsInput]; @@ -233,11 +267,14 @@ async function clearCacheForMessages(idsInput) { } try { - const store = await storage.local.get(["endpoint", "templateName", "customTemplate", "customSystemPrompt", "aiParams", "debugLogging", "htmlToMarkdown", "aiRules"]); + const store = await storage.local.get(["endpoint", "templateName", "customTemplate", "customSystemPrompt", "aiParams", "debugLogging", "htmlToMarkdown", "stripUrlParams", "altTextImages", "collapseWhitespace", "aiRules"]); logger.setDebug(store.debugLogging); await AiClassifier.setConfig(store); await AiClassifier.init(); htmlToMarkdown = store.htmlToMarkdown === true; + stripUrlParams = store.stripUrlParams === true; + altTextImages = store.altTextImages === true; + collapseWhitespace = store.collapseWhitespace === true; const savedStats = await storage.local.get('classifyStats'); if (savedStats.classifyStats && typeof savedStats.classifyStats === 'object') { Object.assign(timingStats, savedStats.classifyStats); @@ -273,6 +310,18 @@ async function clearCacheForMessages(idsInput) { htmlToMarkdown = changes.htmlToMarkdown.newValue === true; logger.aiLog("htmlToMarkdown updated from storage change", {debug: true}, htmlToMarkdown); } + if (changes.stripUrlParams) { + stripUrlParams = changes.stripUrlParams.newValue === true; + logger.aiLog("stripUrlParams updated from storage change", {debug: true}, stripUrlParams); + } + if (changes.altTextImages) { + altTextImages = changes.altTextImages.newValue === true; + logger.aiLog("altTextImages updated from storage change", {debug: true}, altTextImages); + } + if (changes.collapseWhitespace) { + collapseWhitespace = changes.collapseWhitespace.newValue === true; + logger.aiLog("collapseWhitespace updated from storage change", {debug: true}, collapseWhitespace); + } }); } catch (err) { logger.aiLog("failed to load config", {level: 'error'}, err); diff --git a/options/options.html b/options/options.html index e285a22..f40cda2 100644 --- a/options/options.html +++ b/options/options.html @@ -103,6 +103,21 @@ Convert HTML body to Markdown
+
+ +
+
+ +
+
+ +
diff --git a/options/options.js b/options/options.js index 1b8537a..2350efb 100644 --- a/options/options.js +++ b/options/options.js @@ -10,6 +10,9 @@ document.addEventListener('DOMContentLoaded', async () => { 'aiParams', 'debugLogging', 'htmlToMarkdown', + 'stripUrlParams', + 'altTextImages', + 'collapseWhitespace', 'aiRules', 'aiCache' ]); @@ -85,6 +88,15 @@ document.addEventListener('DOMContentLoaded', async () => { const htmlToggle = document.getElementById('html-to-markdown'); htmlToggle.checked = defaults.htmlToMarkdown === true; + const stripUrlToggle = document.getElementById('strip-url-params'); + stripUrlToggle.checked = defaults.stripUrlParams === true; + + const altTextToggle = document.getElementById('alt-text-images'); + altTextToggle.checked = defaults.altTextImages === true; + + const collapseWhitespaceToggle = document.getElementById('collapse-whitespace'); + collapseWhitespaceToggle.checked = defaults.collapseWhitespace === true; + const aiParams = Object.assign({}, DEFAULT_AI_PARAMS, defaults.aiParams || {}); for (const [key, val] of Object.entries(aiParams)) { const el = document.getElementById(key); @@ -418,7 +430,10 @@ document.addEventListener('DOMContentLoaded', async () => { const stopProcessing = ruleEl.querySelector('.stop-processing')?.checked; return { criterion, actions, stopProcessing }; }).filter(r => r.criterion); - await storage.local.set({ endpoint, templateName, customTemplate: customTemplateText, customSystemPrompt, aiParams: aiParamsSave, debugLogging, htmlToMarkdown, aiRules: rules }); + const stripUrlParams = stripUrlToggle.checked; + const altTextImages = altTextToggle.checked; + const collapseWhitespace = collapseWhitespaceToggle.checked; + await storage.local.set({ endpoint, templateName, customTemplate: customTemplateText, customSystemPrompt, aiParams: aiParamsSave, debugLogging, htmlToMarkdown, stripUrlParams, altTextImages, collapseWhitespace, aiRules: rules }); try { await AiClassifier.setConfig({ endpoint, templateName, customTemplate: customTemplateText, customSystemPrompt, aiParams: aiParamsSave, debugLogging }); logger.setDebug(debugLogging); From 41769c0e96384f9cbf6896923e2dc249e5759ca3 Mon Sep 17 00:00:00 2001 From: Jordan Wages Date: Sat, 5 Jul 2025 04:33:01 -0500 Subject: [PATCH 078/148] Handle preview pane when loading details --- README.md | 1 + details.js | 6 ++++++ manifest.json | 3 ++- 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index a5fbce1..b9ee4be 100644 --- a/README.md +++ b/README.md @@ -113,6 +113,7 @@ Sortana requests the following Thunderbird permissions: - `messagesTagsList` – retrieve existing message tags for rule actions. - `accountsRead` – list accounts and folders for move actions. - `menus` – add context menu commands. +- `tabs` – open new tabs and query the active tab. ## Thunderbird Add-on Store Disclosures diff --git a/details.js b/details.js index 0d190d5..4442ab1 100644 --- a/details.js +++ b/details.js @@ -8,6 +8,12 @@ document.addEventListener('DOMContentLoaded', async () => { const tabId = tabs[0]?.id; const msgs = tabId ? await browser.messageDisplay.getDisplayedMessages(tabId) : []; id = msgs[0]?.id; + if (!id) { + const mailTabs = await browser.mailTabs.query({ active: true, currentWindow: true }); + const mailTabId = mailTabs[0]?.id; + const selected = mailTabId !== undefined ? await browser.mailTabs.getSelectedMessages(mailTabId) : null; + id = selected?.messages?.[0]?.id; + } } catch (e) { console.error('failed to determine message id', e); } diff --git a/manifest.json b/manifest.json index 506e392..879d1f3 100644 --- a/manifest.json +++ b/manifest.json @@ -40,6 +40,7 @@ "messagesTagsList", "accountsRead", "menus", - "scripting" + "scripting", + "tabs" ] } From c0ba2d1fdd707423eb68df99e1f032c376dfb221 Mon Sep 17 00:00:00 2001 From: Jordan Wages Date: Sat, 5 Jul 2025 04:50:18 -0500 Subject: [PATCH 079/148] Add logging to details page --- details.js | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/details.js b/details.js index 4442ab1..1985aa9 100644 --- a/details.js +++ b/details.js @@ -1,6 +1,13 @@ document.addEventListener('DOMContentLoaded', async () => { + const storage = (globalThis.messenger ?? browser).storage; + const logger = await import(browser.runtime.getURL('logger.js')); + const { debugLogging } = await storage.local.get('debugLogging'); + logger.setDebug(debugLogging === true); + logger.aiLog('details page loaded', { debug: true }); + const params = new URLSearchParams(location.search); let id = parseInt(params.get('mid'), 10); + logger.aiLog('initial message id', { debug: true }, id); if (!id) { try { @@ -8,22 +15,27 @@ document.addEventListener('DOMContentLoaded', async () => { const tabId = tabs[0]?.id; const msgs = tabId ? await browser.messageDisplay.getDisplayedMessages(tabId) : []; id = msgs[0]?.id; + logger.aiLog('message id from displayed messages', { debug: true }, id); if (!id) { const mailTabs = await browser.mailTabs.query({ active: true, currentWindow: true }); const mailTabId = mailTabs[0]?.id; const selected = mailTabId !== undefined ? await browser.mailTabs.getSelectedMessages(mailTabId) : null; id = selected?.messages?.[0]?.id; + logger.aiLog('message id from selected messages', { debug: true }, id); } } catch (e) { - console.error('failed to determine message id', e); + logger.aiLog('failed to determine message id', { level: 'error' }, e); } } if (!id) return; try { + logger.aiLog('requesting message details', {}, id); const { subject, results } = await browser.runtime.sendMessage({ type: 'sortana:getDetails', id }); + logger.aiLog('received details', { debug: true }, { subject, results }); document.getElementById('subject').textContent = subject; const container = document.getElementById('rules'); for (const r of results) { + logger.aiLog('rendering rule result', { debug: true }, r); const article = document.createElement('article'); const color = r.matched === true ? 'is-success' : 'is-danger'; article.className = `message ${color} mb-4`; @@ -43,10 +55,11 @@ document.addEventListener('DOMContentLoaded', async () => { container.appendChild(article); } document.getElementById('clear').addEventListener('click', async () => { + logger.aiLog('clearing cache for message', {}, id); await browser.runtime.sendMessage({ type: 'sortana:clearCacheForMessage', id }); window.close(); }); } catch (e) { - console.error('failed to load details', e); + logger.aiLog('failed to load details', { level: 'error' }, e); } }); From 6b741595cced2d29f24d04418cdaf7b45b61eb1f Mon Sep 17 00:00:00 2001 From: Jordan Wages Date: Sat, 5 Jul 2025 05:07:48 -0500 Subject: [PATCH 080/148] Fix message lookup in details popup --- background.js | 2 +- details.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/background.js b/background.js index 0613788..bc3c5dd 100644 --- a/background.js +++ b/background.js @@ -413,7 +413,7 @@ async function clearCacheForMessages(idsInput) { } } else if (msg?.type === "sortana:clearCacheForDisplayed") { try { - const tabs = await browser.tabs.query({ active: true, currentWindow: true }); + const tabs = await browser.tabs.query({ active: true, lastFocusedWindow: true }); const tabId = tabs[0]?.id; const msgs = tabId ? await browser.messageDisplay.getDisplayedMessages(tabId) : []; const ids = msgs.map(m => m.id); diff --git a/details.js b/details.js index 1985aa9..c586cc2 100644 --- a/details.js +++ b/details.js @@ -11,13 +11,13 @@ document.addEventListener('DOMContentLoaded', async () => { if (!id) { try { - const tabs = await browser.tabs.query({ active: true, currentWindow: true }); + const tabs = await browser.tabs.query({ active: true, lastFocusedWindow: true }); const tabId = tabs[0]?.id; const msgs = tabId ? await browser.messageDisplay.getDisplayedMessages(tabId) : []; id = msgs[0]?.id; logger.aiLog('message id from displayed messages', { debug: true }, id); if (!id) { - const mailTabs = await browser.mailTabs.query({ active: true, currentWindow: true }); + const mailTabs = await browser.mailTabs.query({ active: true, lastFocusedWindow: true }); const mailTabId = mailTabs[0]?.id; const selected = mailTabId !== undefined ? await browser.mailTabs.getSelectedMessages(mailTabId) : null; id = selected?.messages?.[0]?.id; From 9724c19b7d1a7518f46c8b08bcda9595c33d1118 Mon Sep 17 00:00:00 2001 From: Jordan Wages Date: Sat, 5 Jul 2025 19:33:05 -0500 Subject: [PATCH 081/148] Debug attempt --- ai-filter.sln | 6 ++++++ details.js | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/ai-filter.sln b/ai-filter.sln index 86ceaed..7922392 100644 --- a/ai-filter.sln +++ b/ai-filter.sln @@ -64,6 +64,11 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "img", "img", "{F266602F-175 resources\img\logo96.png = resources\img\logo96.png EndProjectSection EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "js", "js", "{21D2A42C-3F85-465C-9141-C106AFD92B68}" + ProjectSection(SolutionItems) = preProject + resources\js\turndown.js = resources\js\turndown.js + EndProjectSection +EndProject Global GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -76,5 +81,6 @@ Global {86516D53-50D4-4FE2-9D8A-977A8F5EBDBD} = {BCC6E6D2-343B-4C48-854D-5FE3BBC3CB70} {68A87938-5C2B-49F5-8AAA-8A34FBBFD854} = {BCC6E6D2-343B-4C48-854D-5FE3BBC3CB70} {F266602F-1755-4A95-A11B-6C90C701C5BF} = {68A87938-5C2B-49F5-8AAA-8A34FBBFD854} + {21D2A42C-3F85-465C-9141-C106AFD92B68} = {68A87938-5C2B-49F5-8AAA-8A34FBBFD854} EndGlobalSection EndGlobal diff --git a/details.js b/details.js index c586cc2..28c7504 100644 --- a/details.js +++ b/details.js @@ -11,7 +11,7 @@ document.addEventListener('DOMContentLoaded', async () => { if (!id) { try { - const tabs = await browser.tabs.query({ active: true, lastFocusedWindow: true }); + const tabs = await messenger.tabs.query({ active: true, currentWindow: true }); const tabId = tabs[0]?.id; const msgs = tabId ? await browser.messageDisplay.getDisplayedMessages(tabId) : []; id = msgs[0]?.id; From 79f49fd5028314b7740d7eac6feb609b88e0fbe5 Mon Sep 17 00:00:00 2001 From: Jordan Wages Date: Sat, 5 Jul 2025 19:58:11 -0500 Subject: [PATCH 082/148] Simplify message lookup --- background.js | 4 +--- details.js | 8 ++------ 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/background.js b/background.js index bc3c5dd..7198e23 100644 --- a/background.js +++ b/background.js @@ -413,9 +413,7 @@ async function clearCacheForMessages(idsInput) { } } else if (msg?.type === "sortana:clearCacheForDisplayed") { try { - const tabs = await browser.tabs.query({ active: true, lastFocusedWindow: true }); - const tabId = tabs[0]?.id; - const msgs = tabId ? await browser.messageDisplay.getDisplayedMessages(tabId) : []; + const msgs = await browser.messageDisplay.getDisplayedMessages(); const ids = msgs.map(m => m.id); await clearCacheForMessages(ids); } catch (e) { diff --git a/details.js b/details.js index c586cc2..6ea15fe 100644 --- a/details.js +++ b/details.js @@ -11,15 +11,11 @@ document.addEventListener('DOMContentLoaded', async () => { if (!id) { try { - const tabs = await browser.tabs.query({ active: true, lastFocusedWindow: true }); - const tabId = tabs[0]?.id; - const msgs = tabId ? await browser.messageDisplay.getDisplayedMessages(tabId) : []; + const msgs = await browser.messageDisplay.getDisplayedMessages(); id = msgs[0]?.id; logger.aiLog('message id from displayed messages', { debug: true }, id); if (!id) { - const mailTabs = await browser.mailTabs.query({ active: true, lastFocusedWindow: true }); - const mailTabId = mailTabs[0]?.id; - const selected = mailTabId !== undefined ? await browser.mailTabs.getSelectedMessages(mailTabId) : null; + const selected = await browser.mailTabs.getSelectedMessages(); id = selected?.messages?.[0]?.id; logger.aiLog('message id from selected messages', { debug: true }, id); } From 846d1270c55bf511132c9504b7013531545dc181 Mon Sep 17 00:00:00 2001 From: Jordan Wages Date: Sat, 5 Jul 2025 20:02:51 -0500 Subject: [PATCH 083/148] Updating version number since we're making significant changes --- manifest.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/manifest.json b/manifest.json index 879d1f3..36b94b0 100644 --- a/manifest.json +++ b/manifest.json @@ -1,7 +1,7 @@ { "manifest_version": 2, "name": "Sortana", - "version": "2.0.0", + "version": "2.1.0", "default_locale": "en-US", "applications": { "gecko": { From 97bfabfbea8aafa17db6f573954c6901df3b1469 Mon Sep 17 00:00:00 2001 From: Jordan Wages Date: Sat, 5 Jul 2025 22:53:40 -0500 Subject: [PATCH 084/148] Add fallback message to fetch active message id --- background.js | 13 +++++++++++++ details.js | 13 ++++++++++++- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/background.js b/background.js index 7198e23..58852c2 100644 --- a/background.js +++ b/background.js @@ -411,6 +411,19 @@ async function clearCacheForMessages(idsInput) { // rethrow so the caller sees the failure throw err; } + } else if (msg?.type === "sortana:getActiveMessage") { + try { + const displayed = await browser.messageDisplay.getDisplayedMessages(); + let id = displayed[0]?.id; + if (!id) { + const selected = await browser.mailTabs.getSelectedMessages(); + id = selected?.messages?.[0]?.id; + } + return { id: id ?? null }; + } catch (e) { + logger.aiLog("failed to get active message", { level: 'error' }, e); + return { id: null }; + } } else if (msg?.type === "sortana:clearCacheForDisplayed") { try { const msgs = await browser.messageDisplay.getDisplayedMessages(); diff --git a/details.js b/details.js index 6ea15fe..3b78e8a 100644 --- a/details.js +++ b/details.js @@ -20,9 +20,20 @@ document.addEventListener('DOMContentLoaded', async () => { logger.aiLog('message id from selected messages', { debug: true }, id); } } catch (e) { - logger.aiLog('failed to determine message id', { level: 'error' }, e); + logger.aiLog('failed to determine message id locally', { level: 'error' }, e); } } + + if (!id) { + try { + const resp = await browser.runtime.sendMessage({ type: 'sortana:getActiveMessage' }); + id = resp?.id; + logger.aiLog('message id from background', { debug: true }, id); + } catch (e) { + logger.aiLog('failed to get message id from background', { level: 'error' }, e); + } + } + if (!id) return; try { logger.aiLog('requesting message details', {}, id); From eb91474f5a0e6b44f8ee803a7ade66b53a0ee8be Mon Sep 17 00:00:00 2001 From: Jordan Wages Date: Sun, 6 Jul 2025 00:05:31 -0500 Subject: [PATCH 085/148] Migrate manifest to version 3 --- manifest.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/manifest.json b/manifest.json index 36b94b0..8d1ab76 100644 --- a/manifest.json +++ b/manifest.json @@ -1,9 +1,9 @@ { - "manifest_version": 2, + "manifest_version": 3, "name": "Sortana", "version": "2.1.0", "default_locale": "en-US", - "applications": { + "browser_specific_settings": { "gecko": { "id": "ai-filter@jordanwages", "strict_min_version": "128.0", @@ -18,7 +18,7 @@ "96": "resources/img/logo96.png", "128": "resources/img/logo128.png" }, - "browser_action": { + "action": { "default_icon": "resources/img/logo32.png" }, "message_display_action": { From 8f5165dcec4a12b50a9f33fe61f89cd53605b620 Mon Sep 17 00:00:00 2001 From: Jordan Wages Date: Sun, 6 Jul 2025 00:29:46 -0500 Subject: [PATCH 086/148] Add host permissions for endpoint access --- README.md | 1 + manifest.json | 3 +++ 2 files changed, 4 insertions(+) diff --git a/README.md b/README.md index b9ee4be..eff53b1 100644 --- a/README.md +++ b/README.md @@ -114,6 +114,7 @@ Sortana requests the following Thunderbird permissions: - `accountsRead` – list accounts and folders for move actions. - `menus` – add context menu commands. - `tabs` – open new tabs and query the active tab. +- Host permissions (`*://*/*`) – allow network requests to your configured classification service. ## Thunderbird Add-on Store Disclosures diff --git a/manifest.json b/manifest.json index 8d1ab76..d43df2c 100644 --- a/manifest.json +++ b/manifest.json @@ -42,5 +42,8 @@ "menus", "scripting", "tabs" + ], + "host_permissions": [ + "*://*/*" ] } From 0c07479fa987cfa96ed1a1ddcbd05492841e26ec Mon Sep 17 00:00:00 2001 From: Jordan Wages Date: Sun, 6 Jul 2025 01:22:44 -0500 Subject: [PATCH 087/148] Added CSP --- manifest.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/manifest.json b/manifest.json index d43df2c..2ff6b74 100644 --- a/manifest.json +++ b/manifest.json @@ -45,5 +45,8 @@ ], "host_permissions": [ "*://*/*" - ] + ], + "content_security_policy": { + "extension_pages": "script-src 'self'; object-src 'none'; connect-src 'self' http: https:" + } } From d60725eb4b3fb20755a555f0edad927f91eb9b67 Mon Sep 17 00:00:00 2001 From: Jordan Wages Date: Sun, 6 Jul 2025 02:10:46 -0500 Subject: [PATCH 088/148] Handle message display in TB 128 --- background.js | 39 ++++++++++++++-------------- details.js | 70 +++++++++++++++++++++++---------------------------- manifest.json | 3 +-- 3 files changed, 52 insertions(+), 60 deletions(-) diff --git a/background.js b/background.js index 58852c2..82c1fd0 100644 --- a/background.js +++ b/background.js @@ -333,6 +333,19 @@ async function clearCacheForMessages(idsInput) { if (browser.messageDisplayAction.setLabel) { browser.messageDisplayAction.setLabel({ label: "Details" }); } + + browser.messageDisplayAction.onClicked.addListener(async (tab) => { + const header = await browser.messageDisplay.getDisplayedMessage(tab.id); + if (!header) { + console.warn("[Sortana] no displayed message in tab", tab.id); + return; + } + + const popupUrl = `${browser.runtime.getURL("details.html")}?mid=${header.id}`; + + await browser.messageDisplayAction.setPopup({ tabId: tab.id, popup: popupUrl }); + await browser.messageDisplayAction.openPopup({ tabId: tab.id }); + }); } browser.menus.create({ @@ -370,7 +383,7 @@ async function clearCacheForMessages(idsInput) { - browser.menus.onClicked.addListener(async info => { + browser.menus.onClicked.addListener(async (info, tab) => { if (info.menuItemId === "apply-ai-rules-list" || info.menuItemId === "apply-ai-rules-display") { const ids = info.selectedMessages?.messages?.map(m => m.id) || (info.messageId ? [info.messageId] : []); @@ -380,11 +393,12 @@ async function clearCacheForMessages(idsInput) { (info.messageId ? [info.messageId] : []); await clearCacheForMessages(ids); } else if (info.menuItemId === "view-ai-reason-list" || info.menuItemId === "view-ai-reason-display") { - const id = info.messageId || info.selectedMessages?.messages?.[0]?.id; - if (id) { - const url = browser.runtime.getURL(`details.html?mid=${id}`); - browser.tabs.create({ url }); - } + const header = await browser.messageDisplay.getDisplayedMessage(tab.id); + if (!header) { return; } + + const url = `${browser.runtime.getURL("details.html")}?mid=${header.id}`; + + await browser.tabs.create({ url }); } }); @@ -411,19 +425,6 @@ async function clearCacheForMessages(idsInput) { // rethrow so the caller sees the failure throw err; } - } else if (msg?.type === "sortana:getActiveMessage") { - try { - const displayed = await browser.messageDisplay.getDisplayedMessages(); - let id = displayed[0]?.id; - if (!id) { - const selected = await browser.mailTabs.getSelectedMessages(); - id = selected?.messages?.[0]?.id; - } - return { id: id ?? null }; - } catch (e) { - logger.aiLog("failed to get active message", { level: 'error' }, e); - return { id: null }; - } } else if (msg?.type === "sortana:clearCacheForDisplayed") { try { const msgs = await browser.messageDisplay.getDisplayedMessages(); diff --git a/details.js b/details.js index 3b78e8a..c5488f6 100644 --- a/details.js +++ b/details.js @@ -1,48 +1,40 @@ document.addEventListener('DOMContentLoaded', async () => { + const logger = (await import(browser.runtime.getURL('logger.js'))).aiLog; + + const midParam = new URLSearchParams(location.search).get('mid'); + const messageId = parseInt(midParam, 10); + + if (!messageId) { + logger('no ?mid → trying displayedMessage fallback'); + const openerTabId = (await browser.tabs.getCurrent()).openerTabId; + const header = await browser.messageDisplay.getDisplayedMessage(openerTabId); + if (!header) { + logger('still no message – aborting'); + return; + } + loadMessage(header.id); + return; + } + + loadMessage(messageId); +}); + +async function loadMessage(id) { const storage = (globalThis.messenger ?? browser).storage; - const logger = await import(browser.runtime.getURL('logger.js')); + const logMod = await import(browser.runtime.getURL('logger.js')); const { debugLogging } = await storage.local.get('debugLogging'); - logger.setDebug(debugLogging === true); - logger.aiLog('details page loaded', { debug: true }); + logMod.setDebug(debugLogging === true); + const log = logMod.aiLog; - const params = new URLSearchParams(location.search); - let id = parseInt(params.get('mid'), 10); - logger.aiLog('initial message id', { debug: true }, id); - - if (!id) { - try { - const msgs = await browser.messageDisplay.getDisplayedMessages(); - id = msgs[0]?.id; - logger.aiLog('message id from displayed messages', { debug: true }, id); - if (!id) { - const selected = await browser.mailTabs.getSelectedMessages(); - id = selected?.messages?.[0]?.id; - logger.aiLog('message id from selected messages', { debug: true }, id); - } - } catch (e) { - logger.aiLog('failed to determine message id locally', { level: 'error' }, e); - } - } - - if (!id) { - try { - const resp = await browser.runtime.sendMessage({ type: 'sortana:getActiveMessage' }); - id = resp?.id; - logger.aiLog('message id from background', { debug: true }, id); - } catch (e) { - logger.aiLog('failed to get message id from background', { level: 'error' }, e); - } - } - - if (!id) return; + log('details page loaded', { debug: true }); try { - logger.aiLog('requesting message details', {}, id); + log('requesting message details', {}, id); const { subject, results } = await browser.runtime.sendMessage({ type: 'sortana:getDetails', id }); - logger.aiLog('received details', { debug: true }, { subject, results }); + log('received details', { debug: true }, { subject, results }); document.getElementById('subject').textContent = subject; const container = document.getElementById('rules'); for (const r of results) { - logger.aiLog('rendering rule result', { debug: true }, r); + log('rendering rule result', { debug: true }, r); const article = document.createElement('article'); const color = r.matched === true ? 'is-success' : 'is-danger'; article.className = `message ${color} mb-4`; @@ -62,11 +54,11 @@ document.addEventListener('DOMContentLoaded', async () => { container.appendChild(article); } document.getElementById('clear').addEventListener('click', async () => { - logger.aiLog('clearing cache for message', {}, id); + log('clearing cache for message', {}, id); await browser.runtime.sendMessage({ type: 'sortana:clearCacheForMessage', id }); window.close(); }); } catch (e) { - logger.aiLog('failed to load details', { level: 'error' }, e); + log('failed to load details', { level: 'error' }, e); } -}); +} diff --git a/manifest.json b/manifest.json index 2ff6b74..77506b2 100644 --- a/manifest.json +++ b/manifest.json @@ -24,8 +24,7 @@ "message_display_action": { "default_icon": "resources/img/brain.png", "default_title": "Details", - "default_label": "Details", - "default_popup": "details.html" + "default_label": "Details" }, "background": { "scripts": [ "background.js" ] }, "options_ui": { From 34cf8e234e87ce6750a774be7acc5c9f558da21a Mon Sep 17 00:00:00 2001 From: Jordan Wages Date: Sun, 6 Jul 2025 02:36:42 -0500 Subject: [PATCH 089/148] Restore popup defaults and update message lookups --- background.js | 14 +------------- details.js | 29 ++++++++++++++--------------- manifest.json | 3 ++- 3 files changed, 17 insertions(+), 29 deletions(-) diff --git a/background.js b/background.js index 82c1fd0..6d0b4e8 100644 --- a/background.js +++ b/background.js @@ -334,18 +334,6 @@ async function clearCacheForMessages(idsInput) { browser.messageDisplayAction.setLabel({ label: "Details" }); } - browser.messageDisplayAction.onClicked.addListener(async (tab) => { - const header = await browser.messageDisplay.getDisplayedMessage(tab.id); - if (!header) { - console.warn("[Sortana] no displayed message in tab", tab.id); - return; - } - - const popupUrl = `${browser.runtime.getURL("details.html")}?mid=${header.id}`; - - await browser.messageDisplayAction.setPopup({ tabId: tab.id, popup: popupUrl }); - await browser.messageDisplayAction.openPopup({ tabId: tab.id }); - }); } browser.menus.create({ @@ -393,7 +381,7 @@ async function clearCacheForMessages(idsInput) { (info.messageId ? [info.messageId] : []); await clearCacheForMessages(ids); } else if (info.menuItemId === "view-ai-reason-list" || info.menuItemId === "view-ai-reason-display") { - const header = await browser.messageDisplay.getDisplayedMessage(tab.id); + const [header] = await browser.messageDisplay.getDisplayedMessages(tab.id); if (!header) { return; } const url = `${browser.runtime.getURL("details.html")}?mid=${header.id}`; diff --git a/details.js b/details.js index c5488f6..016783a 100644 --- a/details.js +++ b/details.js @@ -1,22 +1,21 @@ -document.addEventListener('DOMContentLoaded', async () => { - const logger = (await import(browser.runtime.getURL('logger.js'))).aiLog; +document.addEventListener("DOMContentLoaded", async () => { + const aiLog = (await import(browser.runtime.getURL("logger.js"))).aiLog; - const midParam = new URLSearchParams(location.search).get('mid'); - const messageId = parseInt(midParam, 10); - - if (!messageId) { - logger('no ?mid → trying displayedMessage fallback'); - const openerTabId = (await browser.tabs.getCurrent()).openerTabId; - const header = await browser.messageDisplay.getDisplayedMessage(openerTabId); - if (!header) { - logger('still no message – aborting'); - return; - } - loadMessage(header.id); + const qMid = parseInt(new URLSearchParams(location.search).get("mid"), 10); + if (!isNaN(qMid)) { + loadMessage(qMid); return; } - loadMessage(messageId); + const thisTab = await browser.tabs.getCurrent(); + const baseTabId = thisTab.openerTabId ?? thisTab.id; + const [header] = await browser.messageDisplay.getDisplayedMessages(baseTabId); + + if (header) { + loadMessage(header.id); + } else { + aiLog("Details popup: no displayed message found"); + } }); async function loadMessage(id) { diff --git a/manifest.json b/manifest.json index 77506b2..2ff6b74 100644 --- a/manifest.json +++ b/manifest.json @@ -24,7 +24,8 @@ "message_display_action": { "default_icon": "resources/img/brain.png", "default_title": "Details", - "default_label": "Details" + "default_label": "Details", + "default_popup": "details.html" }, "background": { "scripts": [ "background.js" ] }, "options_ui": { From 254f0c5ffc1672e071cb38f82c9b8a235416ab70 Mon Sep 17 00:00:00 2001 From: Jordan Wages Date: Sun, 6 Jul 2025 04:31:51 -0500 Subject: [PATCH 090/148] just catching up --- background.js | 15 +++++++++++++++ manifest.json | 3 +-- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/background.js b/background.js index 6d0b4e8..d5a5e3a 100644 --- a/background.js +++ b/background.js @@ -369,7 +369,22 @@ async function clearCacheForMessages(idsInput) { icons: { "16": "resources/img/brain.png" } }); + //for the love of god work please + browser.messageDisplayAction.onClicked.addListener(async (tab, info) => { + try { + let header = await browser.messageDisplay.getDisplayedMessages(); + if (!header) { + logger.aiLog("No header, no message loaded?", { debug: true }); + return; + } + const url = browser.runtime.getURL(`details.html?mid=${header.id}`); + await browser.messageDisplayAction.setPopup({ tabId: tab.id, popup: url }); + await browser.messageDisplayAction.openPopup({ tabId: tab.id }); + } catch (err) { + logger.aiLog("Failed to open details popup", { debug: true }); + } + }); browser.menus.onClicked.addListener(async (info, tab) => { if (info.menuItemId === "apply-ai-rules-list" || info.menuItemId === "apply-ai-rules-display") { diff --git a/manifest.json b/manifest.json index 2ff6b74..77506b2 100644 --- a/manifest.json +++ b/manifest.json @@ -24,8 +24,7 @@ "message_display_action": { "default_icon": "resources/img/brain.png", "default_title": "Details", - "default_label": "Details", - "default_popup": "details.html" + "default_label": "Details" }, "background": { "scripts": [ "background.js" ] }, "options_ui": { From aec56aac33a6003348f04ded1cf1b85772dc0d52 Mon Sep 17 00:00:00 2001 From: Jordan Wages Date: Sun, 6 Jul 2025 04:35:46 -0500 Subject: [PATCH 091/148] Revert manifest to version 2 --- manifest.json | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/manifest.json b/manifest.json index 77506b2..0d6db48 100644 --- a/manifest.json +++ b/manifest.json @@ -1,9 +1,9 @@ { - "manifest_version": 3, + "manifest_version": 2, "name": "Sortana", "version": "2.1.0", "default_locale": "en-US", - "browser_specific_settings": { + "applications": { "gecko": { "id": "ai-filter@jordanwages", "strict_min_version": "128.0", @@ -18,7 +18,7 @@ "96": "resources/img/logo96.png", "128": "resources/img/logo128.png" }, - "action": { + "browser_action": { "default_icon": "resources/img/logo32.png" }, "message_display_action": { @@ -40,12 +40,8 @@ "accountsRead", "menus", "scripting", - "tabs" - ], - "host_permissions": [ + "tabs", "*://*/*" ], - "content_security_policy": { - "extension_pages": "script-src 'self'; object-src 'none'; connect-src 'self' http: https:" - } + "content_security_policy": "script-src 'self'; object-src 'none'; connect-src 'self' http: https:" } From 13751b3ab2741b23cbbf5fc0e8e497ed7dea203c Mon Sep 17 00:00:00 2001 From: Jordan Wages Date: Sun, 6 Jul 2025 18:05:19 -0500 Subject: [PATCH 092/148] Trying new things --- background.js | 24 ++++++++++++++---------- details.js | 14 +++++++------- manifest.json | 6 ++---- 3 files changed, 23 insertions(+), 21 deletions(-) diff --git a/background.js b/background.js index d5a5e3a..b600169 100644 --- a/background.js +++ b/background.js @@ -258,7 +258,7 @@ async function clearCacheForMessages(idsInput) { logger = await import(browser.runtime.getURL("logger.js")); try { AiClassifier = await import(browser.runtime.getURL("modules/AiClassifier.js")); - logger.aiLog("AiClassifier imported", {debug: true}); + logger.aiLog("AiClassifier imported", { debug: true }); const td = await import(browser.runtime.getURL("resources/js/turndown.js")); TurndownService = td.default || td.TurndownService; } catch (e) { @@ -291,7 +291,7 @@ async function clearCacheForMessages(idsInput) { if (r.stopProcessing) rule.stopProcessing = true; return rule; }) : []; - logger.aiLog("configuration loaded", {debug: true}, store); + logger.aiLog("configuration loaded", { debug: true }, store); storage.onChanged.addListener(async changes => { if (changes.aiRules) { const newRules = changes.aiRules.newValue || []; @@ -304,30 +304,30 @@ async function clearCacheForMessages(idsInput) { if (r.stopProcessing) rule.stopProcessing = true; return rule; }); - logger.aiLog("aiRules updated from storage change", {debug: true}, aiRules); + logger.aiLog("aiRules updated from storage change", { debug: true }, aiRules); } if (changes.htmlToMarkdown) { htmlToMarkdown = changes.htmlToMarkdown.newValue === true; - logger.aiLog("htmlToMarkdown updated from storage change", {debug: true}, htmlToMarkdown); + logger.aiLog("htmlToMarkdown updated from storage change", { debug: true }, htmlToMarkdown); } if (changes.stripUrlParams) { stripUrlParams = changes.stripUrlParams.newValue === true; - logger.aiLog("stripUrlParams updated from storage change", {debug: true}, stripUrlParams); + logger.aiLog("stripUrlParams updated from storage change", { debug: true }, stripUrlParams); } if (changes.altTextImages) { altTextImages = changes.altTextImages.newValue === true; - logger.aiLog("altTextImages updated from storage change", {debug: true}, altTextImages); + logger.aiLog("altTextImages updated from storage change", { debug: true }, altTextImages); } if (changes.collapseWhitespace) { collapseWhitespace = changes.collapseWhitespace.newValue === true; - logger.aiLog("collapseWhitespace updated from storage change", {debug: true}, collapseWhitespace); + logger.aiLog("collapseWhitespace updated from storage change", { debug: true }, collapseWhitespace); } }); } catch (err) { - logger.aiLog("failed to load config", {level: 'error'}, err); + logger.aiLog("failed to load config", { level: 'error' }, err); } - logger.aiLog("background.js loaded – ready to classify", {debug: true}); + logger.aiLog("background.js loaded – ready to classify", { debug: true }); if (browser.messageDisplayAction) { browser.messageDisplayAction.setTitle({ title: "Details" }); if (browser.messageDisplayAction.setLabel) { @@ -372,7 +372,7 @@ async function clearCacheForMessages(idsInput) { //for the love of god work please browser.messageDisplayAction.onClicked.addListener(async (tab, info) => { try { - let header = await browser.messageDisplay.getDisplayedMessages(); + let header = await browser.messageDisplay.getDisplayedMessages(tab.id); if (!header) { logger.aiLog("No header, no message loaded?", { debug: true }); return; @@ -386,6 +386,10 @@ async function clearCacheForMessages(idsInput) { } }); + browser.messageDisplay.onMessagesDisplayed.addListener(async (tab, displayedMessages) => { + logger.aiLog("Messages displayed!", { debug: true }, displayedMessages); + }); + browser.menus.onClicked.addListener(async (info, tab) => { if (info.menuItemId === "apply-ai-rules-list" || info.menuItemId === "apply-ai-rules-display") { const ids = info.selectedMessages?.messages?.map(m => m.id) || diff --git a/details.js b/details.js index 016783a..6269dae 100644 --- a/details.js +++ b/details.js @@ -8,14 +8,14 @@ document.addEventListener("DOMContentLoaded", async () => { } const thisTab = await browser.tabs.getCurrent(); - const baseTabId = thisTab.openerTabId ?? thisTab.id; - const [header] = await browser.messageDisplay.getDisplayedMessages(baseTabId); + //const baseTabId = thisTab.openerTabId ?? thisTab.id; + //const [header] = await browser.messageDisplay.getDisplayedMessages(baseTabId); - if (header) { - loadMessage(header.id); - } else { - aiLog("Details popup: no displayed message found"); - } + //if (header) { + // loadMessage(header.id); + //} else { + // aiLog("Details popup: no displayed message found"); + //} }); async function loadMessage(id) { diff --git a/manifest.json b/manifest.json index 0d6db48..fbd37ae 100644 --- a/manifest.json +++ b/manifest.json @@ -40,8 +40,6 @@ "accountsRead", "menus", "scripting", - "tabs", - "*://*/*" - ], - "content_security_policy": "script-src 'self'; object-src 'none'; connect-src 'self' http: https:" + "tabs" + ] } From caf18ed5ab1c5db206303b2a79f0578538c998ce Mon Sep 17 00:00:00 2001 From: Jordan Wages Date: Mon, 7 Jul 2025 00:14:47 -0500 Subject: [PATCH 093/148] Add message for displayed messages and convert details to module --- background.js | 9 +++++++++ details.html | 2 +- details.js | 15 ++++++--------- 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/background.js b/background.js index b600169..d58adf7 100644 --- a/background.js +++ b/background.js @@ -501,6 +501,15 @@ async function clearCacheForMessages(idsInput) { logger.aiLog("failed to collect details", { level: 'error' }, e); return { subject: '', results: [] }; } + } else if (msg?.type === "sortana:getDisplayedMessages") { + try { + const [tab] = await browser.tabs.query({ active: true, currentWindow: true }); + const messages = await browser.messageDisplay.getDisplayedMessages(tab?.id); + return { messages }; + } catch (e) { + logger.aiLog("failed to get displayed messages", { level: 'error' }, e); + return { messages: [] }; + } } else if (msg?.type === "sortana:clearCacheForMessage") { try { await clearCacheForMessages([msg.id]); diff --git a/details.html b/details.html index 1502471..d15a3c9 100644 --- a/details.html +++ b/details.html @@ -15,6 +15,6 @@
- + diff --git a/details.js b/details.js index 6269dae..ca53cbe 100644 --- a/details.js +++ b/details.js @@ -1,12 +1,9 @@ -document.addEventListener("DOMContentLoaded", async () => { - const aiLog = (await import(browser.runtime.getURL("logger.js"))).aiLog; - - const qMid = parseInt(new URLSearchParams(location.search).get("mid"), 10); - if (!isNaN(qMid)) { - loadMessage(qMid); - return; - } +const aiLog = (await import(browser.runtime.getURL("logger.js"))).aiLog; +const qMid = parseInt(new URLSearchParams(location.search).get("mid"), 10); +if (!isNaN(qMid)) { + loadMessage(qMid); +} else { const thisTab = await browser.tabs.getCurrent(); //const baseTabId = thisTab.openerTabId ?? thisTab.id; //const [header] = await browser.messageDisplay.getDisplayedMessages(baseTabId); @@ -16,7 +13,7 @@ document.addEventListener("DOMContentLoaded", async () => { //} else { // aiLog("Details popup: no displayed message found"); //} -}); +} async function loadMessage(id) { const storage = (globalThis.messenger ?? browser).storage; From 51816d8a19d7c8976ada797b5116c711700b97b2 Mon Sep 17 00:00:00 2001 From: Jordan Wages Date: Mon, 7 Jul 2025 00:23:54 -0500 Subject: [PATCH 094/148] Use getDisplayedMessages to load message --- details.js | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/details.js b/details.js index ca53cbe..1e9023f 100644 --- a/details.js +++ b/details.js @@ -4,15 +4,14 @@ const qMid = parseInt(new URLSearchParams(location.search).get("mid"), 10); if (!isNaN(qMid)) { loadMessage(qMid); } else { - const thisTab = await browser.tabs.getCurrent(); - //const baseTabId = thisTab.openerTabId ?? thisTab.id; - //const [header] = await browser.messageDisplay.getDisplayedMessages(baseTabId); - - //if (header) { - // loadMessage(header.id); - //} else { - // aiLog("Details popup: no displayed message found"); - //} + const { messages } = await browser.runtime.sendMessage({ + type: "sortana:getDisplayedMessages", + }); + if (messages && messages[0]) { + loadMessage(messages[0].id); + } else { + aiLog("Details popup: no displayed message found"); + } } async function loadMessage(id) { From 6a85dbb2eb12ff072871c4aa429e0bdf89b1f310 Mon Sep 17 00:00:00 2001 From: Jordan Wages Date: Mon, 7 Jul 2025 21:46:21 -0500 Subject: [PATCH 095/148] Going back to what works. Manifest v3 and its consequences have been a disaster for the human race. --- background.js | 283 +++++++++++++++++++++++--------------------------- details.js | 11 +- manifest.json | 3 +- 3 files changed, 144 insertions(+), 153 deletions(-) diff --git a/background.js b/background.js index d58adf7..59bac43 100644 --- a/background.js +++ b/background.js @@ -126,7 +126,7 @@ function buildEmailText(full) { const attachments = []; collectText(full, bodyParts, attachments); const headers = Object.entries(full.headers || {}) - .map(([k,v]) => `${k}: ${v.join(' ')}`) + .map(([k, v]) => `${k}: ${v.join(' ')}`) .join('\n'); const attachInfo = `Attachments: ${attachments.length}` + (attachments.length ? "\n" + attachments.map(a => ` - ${a}`).join('\n') : ""); const combined = `${headers}\n${attachInfo}\n\n${bodyParts.join('\n')}`.trim(); @@ -369,35 +369,14 @@ async function clearCacheForMessages(idsInput) { icons: { "16": "resources/img/brain.png" } }); - //for the love of god work please - browser.messageDisplayAction.onClicked.addListener(async (tab, info) => { - try { - let header = await browser.messageDisplay.getDisplayedMessages(tab.id); - if (!header) { - logger.aiLog("No header, no message loaded?", { debug: true }); - return; - } - - const url = browser.runtime.getURL(`details.html?mid=${header.id}`); - await browser.messageDisplayAction.setPopup({ tabId: tab.id, popup: url }); - await browser.messageDisplayAction.openPopup({ tabId: tab.id }); - } catch (err) { - logger.aiLog("Failed to open details popup", { debug: true }); - } - }); - - browser.messageDisplay.onMessagesDisplayed.addListener(async (tab, displayedMessages) => { - logger.aiLog("Messages displayed!", { debug: true }, displayedMessages); - }); - browser.menus.onClicked.addListener(async (info, tab) => { if (info.menuItemId === "apply-ai-rules-list" || info.menuItemId === "apply-ai-rules-display") { const ids = info.selectedMessages?.messages?.map(m => m.id) || - (info.messageId ? [info.messageId] : []); + (info.messageId ? [info.messageId] : []); await applyAiRules(ids); } else if (info.menuItemId === "clear-ai-cache-list" || info.menuItemId === "clear-ai-cache-display") { const ids = info.selectedMessages?.messages?.map(m => m.id) || - (info.messageId ? [info.messageId] : []); + (info.messageId ? [info.messageId] : []); await clearCacheForMessages(ids); } else if (info.menuItemId === "view-ai-reason-list" || info.menuItemId === "view-ai-reason-display") { const [header] = await browser.messageDisplay.getDisplayedMessages(tab.id); @@ -417,141 +396,143 @@ async function clearCacheForMessages(idsInput) { } if (msg?.type === "sortana:test") { - const { text = "", criterion = "" } = msg; - logger.aiLog("sortana:test – text", {debug: true}, text); - logger.aiLog("sortana:test – criterion", {debug: true}, criterion); + const { text = "", criterion = "" } = msg; + logger.aiLog("sortana:test – text", { debug: true }, text); + logger.aiLog("sortana:test – criterion", { debug: true }, criterion); - try { - logger.aiLog("Calling AiClassifier.classifyText()", {debug: true}); - const result = await AiClassifier.classifyText(text, criterion); - logger.aiLog("classify() returned", {debug: true}, result); - return { match: result }; - } - catch (err) { - logger.aiLog("Error in classify()", {level: 'error'}, err); - // rethrow so the caller sees the failure - throw err; - } - } else if (msg?.type === "sortana:clearCacheForDisplayed") { - try { - const msgs = await browser.messageDisplay.getDisplayedMessages(); - const ids = msgs.map(m => m.id); - await clearCacheForMessages(ids); - } catch (e) { - logger.aiLog("failed to clear cache from message script", { level: 'error' }, e); - } - } else if (msg?.type === "sortana:getReasons") { - try { - const id = msg.id; - const hdr = await messenger.messages.get(id); - const subject = hdr?.subject || ""; - if (!aiRules.length) { - const { aiRules: stored } = await storage.local.get("aiRules"); - aiRules = Array.isArray(stored) ? stored.map(r => { - if (r.actions) return r; - const actions = []; - if (r.tag) actions.push({ type: 'tag', tagKey: r.tag }); - if (r.moveTo) actions.push({ type: 'move', folder: r.moveTo }); - const rule = { criterion: r.criterion, actions }; - if (r.stopProcessing) rule.stopProcessing = true; - return rule; - }) : []; + try { + logger.aiLog("Calling AiClassifier.classifyText()", { debug: true }); + const result = await AiClassifier.classifyText(text, criterion); + logger.aiLog("classify() returned", { debug: true }, result); + return { match: result }; } - const reasons = []; - for (const rule of aiRules) { - const key = await AiClassifier.buildCacheKey(id, rule.criterion); - const reason = AiClassifier.getReason(key); - if (reason) { - reasons.push({ criterion: rule.criterion, reason }); + catch (err) { + logger.aiLog("Error in classify()", { level: 'error' }, err); + // rethrow so the caller sees the failure + throw err; + } + } else if (msg?.type === "sortana:clearCacheForDisplayed") { + try { + const msgs = await browser.messageDisplay.getDisplayedMessages(); + const ids = msgs.map(m => m.id); + await clearCacheForMessages(ids); + } catch (e) { + logger.aiLog("failed to clear cache from message script", { level: 'error' }, e); + } + } else if (msg?.type === "sortana:getReasons") { + try { + const id = msg.id; + const hdr = await messenger.messages.get(id); + const subject = hdr?.subject || ""; + if (!aiRules.length) { + const { aiRules: stored } = await storage.local.get("aiRules"); + aiRules = Array.isArray(stored) ? stored.map(r => { + if (r.actions) return r; + const actions = []; + if (r.tag) actions.push({ type: 'tag', tagKey: r.tag }); + if (r.moveTo) actions.push({ type: 'move', folder: r.moveTo }); + const rule = { criterion: r.criterion, actions }; + if (r.stopProcessing) rule.stopProcessing = true; + return rule; + }) : []; } - } - return { subject, reasons }; - } catch (e) { - logger.aiLog("failed to collect reasons", { level: 'error' }, e); - return { subject: '', reasons: [] }; - } - } else if (msg?.type === "sortana:getDetails") { - try { - const id = msg.id; - const hdr = await messenger.messages.get(id); - const subject = hdr?.subject || ""; - if (!aiRules.length) { - const { aiRules: stored } = await storage.local.get("aiRules"); - aiRules = Array.isArray(stored) ? stored.map(r => { - if (r.actions) return r; - const actions = []; - if (r.tag) actions.push({ type: 'tag', tagKey: r.tag }); - if (r.moveTo) actions.push({ type: 'move', folder: r.moveTo }); - const rule = { criterion: r.criterion, actions }; - if (r.stopProcessing) rule.stopProcessing = true; - return rule; - }) : []; - } - const results = []; - for (const rule of aiRules) { - const key = await AiClassifier.buildCacheKey(id, rule.criterion); - const matched = AiClassifier.getCachedResult(key); - const reason = AiClassifier.getReason(key); - if (matched !== null || reason) { - results.push({ criterion: rule.criterion, matched, reason }); + const reasons = []; + for (const rule of aiRules) { + const key = await AiClassifier.buildCacheKey(id, rule.criterion); + const reason = AiClassifier.getReason(key); + if (reason) { + reasons.push({ criterion: rule.criterion, reason }); + } } + return { subject, reasons }; + } catch (e) { + logger.aiLog("failed to collect reasons", { level: 'error' }, e); + return { subject: '', reasons: [] }; } - return { subject, results }; - } catch (e) { - logger.aiLog("failed to collect details", { level: 'error' }, e); - return { subject: '', results: [] }; - } - } else if (msg?.type === "sortana:getDisplayedMessages") { - try { - const [tab] = await browser.tabs.query({ active: true, currentWindow: true }); - const messages = await browser.messageDisplay.getDisplayedMessages(tab?.id); - return { messages }; - } catch (e) { - logger.aiLog("failed to get displayed messages", { level: 'error' }, e); - return { messages: [] }; - } - } else if (msg?.type === "sortana:clearCacheForMessage") { - try { - await clearCacheForMessages([msg.id]); - return { ok: true }; - } catch (e) { - logger.aiLog("failed to clear cache for message", { level: 'error' }, e); - return { ok: false }; - } - } else if (msg?.type === "sortana:getQueueCount") { - return { count: queuedCount + (processing ? 1 : 0) }; - } else if (msg?.type === "sortana:getTiming") { - const t = timingStats; - const std = t.count > 1 ? Math.sqrt(t.m2 / (t.count - 1)) : 0; - return { - count: queuedCount + (processing ? 1 : 0), - current: currentStart ? Date.now() - currentStart : -1, - last: t.last, - runs: t.count, - average: t.mean, - total: t.total, - stddev: std - }; - } else { - logger.aiLog("Unknown message type, ignoring", {level: 'warn'}, msg?.type); - } -}); + } else if (msg?.type === "sortana:getDetails") { + try { + const id = msg.id; + const hdr = await messenger.messages.get(id); + const subject = hdr?.subject || ""; + if (!aiRules.length) { + const { aiRules: stored } = await storage.local.get("aiRules"); + aiRules = Array.isArray(stored) ? stored.map(r => { + if (r.actions) return r; + const actions = []; + if (r.tag) actions.push({ type: 'tag', tagKey: r.tag }); + if (r.moveTo) actions.push({ type: 'move', folder: r.moveTo }); + const rule = { criterion: r.criterion, actions }; + if (r.stopProcessing) rule.stopProcessing = true; + return rule; + }) : []; + } + const results = []; + for (const rule of aiRules) { + const key = await AiClassifier.buildCacheKey(id, rule.criterion); + const matched = AiClassifier.getCachedResult(key); + const reason = AiClassifier.getReason(key); + if (matched !== null || reason) { + results.push({ criterion: rule.criterion, matched, reason }); + } + } + return { subject, results }; + } catch (e) { + logger.aiLog("failed to collect details", { level: 'error' }, e); + return { subject: '', results: [] }; + } + } else if (msg?.type === "sortana:getDisplayedMessages") { + try { + const [tab] = await browser.tabs.query({ active: true, currentWindow: true }); + const messages = await browser.messageDisplay.getDisplayedMessages(tab?.id); + const ids = messages.map(hdr => hdr.id); -// Automatically classify new messages -if (typeof messenger !== "undefined" && messenger.messages?.onNewMailReceived) { - messenger.messages.onNewMailReceived.addListener(async (folder, messages) => { - logger.aiLog("onNewMailReceived", {debug: true}, messages); - const ids = (messages?.messages || messages || []).map(m => m.id ?? m); - await applyAiRules(ids); + return { ids }; + } catch (e) { + logger.aiLog("failed to get displayed messages", { level: 'error' }, e); + return { messages: [] }; + } + } else if (msg?.type === "sortana:clearCacheForMessage") { + try { + await clearCacheForMessages([msg.id]); + return { ok: true }; + } catch (e) { + logger.aiLog("failed to clear cache for message", { level: 'error' }, e); + return { ok: false }; + } + } else if (msg?.type === "sortana:getQueueCount") { + return { count: queuedCount + (processing ? 1 : 0) }; + } else if (msg?.type === "sortana:getTiming") { + const t = timingStats; + const std = t.count > 1 ? Math.sqrt(t.m2 / (t.count - 1)) : 0; + return { + count: queuedCount + (processing ? 1 : 0), + current: currentStart ? Date.now() - currentStart : -1, + last: t.last, + runs: t.count, + average: t.mean, + total: t.total, + stddev: std + }; + } else { + logger.aiLog("Unknown message type, ignoring", { level: 'warn' }, msg?.type); + } }); -} else { - logger.aiLog("messenger.messages API unavailable, skipping new mail listener", { level: 'warn' }); -} -// Catch any unhandled rejections -window.addEventListener("unhandledrejection", ev => { - logger.aiLog("Unhandled promise rejection", {level: 'error'}, ev.reason); -}); + // Automatically classify new messages + if (typeof messenger !== "undefined" && messenger.messages?.onNewMailReceived) { + messenger.messages.onNewMailReceived.addListener(async (folder, messages) => { + logger.aiLog("onNewMailReceived", { debug: true }, messages); + const ids = (messages?.messages || messages || []).map(m => m.id ?? m); + await applyAiRules(ids); + }); + } else { + logger.aiLog("messenger.messages API unavailable, skipping new mail listener", { level: 'warn' }); + } + + // Catch any unhandled rejections + window.addEventListener("unhandledrejection", ev => { + logger.aiLog("Unhandled promise rejection", { level: 'error' }, ev.reason); + }); browser.runtime.onInstalled.addListener(async ({ reason }) => { if (reason === "install") { diff --git a/details.js b/details.js index 1e9023f..f84ebf4 100644 --- a/details.js +++ b/details.js @@ -10,7 +10,16 @@ if (!isNaN(qMid)) { if (messages && messages[0]) { loadMessage(messages[0].id); } else { - aiLog("Details popup: no displayed message found"); + const tabs = await browser.tabs.query({ active: true, currentWindow: true }); + const tabId = tabs[0]?.id; + const msgs = tabId ? await browser.messageDisplay.getDisplayedMessages(tabId) : []; + let id = msgs[0]?.id; + if (id) { + loadMessage(id); + } + else { + aiLog("Details popup: no displayed message found"); + } } } diff --git a/manifest.json b/manifest.json index fbd37ae..36b94b0 100644 --- a/manifest.json +++ b/manifest.json @@ -24,7 +24,8 @@ "message_display_action": { "default_icon": "resources/img/brain.png", "default_title": "Details", - "default_label": "Details" + "default_label": "Details", + "default_popup": "details.html" }, "background": { "scripts": [ "background.js" ] }, "options_ui": { From c7333482ce0fe646e7eb601fa0f9700f648ac8ee Mon Sep 17 00:00:00 2001 From: Jordan Wages Date: Mon, 7 Jul 2025 22:07:00 -0500 Subject: [PATCH 096/148] Allow selective data export and import --- options/dataTransfer.js | 45 +++++++++++++++++++++++++++++++++++++++++ options/options.html | 17 ++++++++++++++++ options/options.js | 19 +++++++++++++++++ 3 files changed, 81 insertions(+) create mode 100644 options/dataTransfer.js diff --git a/options/dataTransfer.js b/options/dataTransfer.js new file mode 100644 index 0000000..b289c02 --- /dev/null +++ b/options/dataTransfer.js @@ -0,0 +1,45 @@ +"use strict"; +const storage = (globalThis.messenger ?? browser).storage; +const KEY_GROUPS = { + settings: [ + 'endpoint', + 'templateName', + 'customTemplate', + 'customSystemPrompt', + 'aiParams', + 'debugLogging', + 'htmlToMarkdown', + 'stripUrlParams', + 'altTextImages', + 'collapseWhitespace' + ], + rules: ['aiRules'], + cache: ['aiCache'] +}; + +function collectKeys(categories = Object.keys(KEY_GROUPS)) { + return categories.flatMap(cat => KEY_GROUPS[cat] || []); +} + +export async function exportData(categories) { + const data = await storage.local.get(collectKeys(categories)); + const blob = new Blob([JSON.stringify(data, null, 2)], { type: 'application/json' }); + const url = URL.createObjectURL(blob); + const a = document.createElement('a'); + a.href = url; + a.download = 'sortana-export.json'; + document.body.appendChild(a); + a.click(); + a.remove(); + URL.revokeObjectURL(url); +} + +export async function importData(file, categories) { + const text = await file.text(); + const parsed = JSON.parse(text); + const data = {}; + for (const key of collectKeys(categories)) { + if (key in parsed) data[key] = parsed[key]; + } + await storage.local.set(data); +} diff --git a/options/options.html b/options/options.html index f40cda2..186e2b6 100644 --- a/options/options.html +++ b/options/options.html @@ -207,6 +207,23 @@ +
+ +
+ + + +
+
+
+

+ +

+

+ + +

+
diff --git a/options/options.js b/options/options.js index 2350efb..ca25eb4 100644 --- a/options/options.js +++ b/options/options.js @@ -2,6 +2,7 @@ document.addEventListener('DOMContentLoaded', async () => { const storage = (globalThis.messenger ?? browser).storage; const logger = await import(browser.runtime.getURL('logger.js')); const AiClassifier = await import(browser.runtime.getURL('modules/AiClassifier.js')); + const dataTransfer = await import(browser.runtime.getURL('options/dataTransfer.js')); const defaults = await storage.local.get([ 'endpoint', 'templateName', @@ -395,6 +396,24 @@ document.addEventListener('DOMContentLoaded', async () => { await AiClassifier.clearCache(); cacheCountEl.textContent = '0'; }); + + function selectedCategories() { + return [...document.querySelectorAll('.transfer-category:checked')].map(el => el.value); + } + + document.getElementById('export-data').addEventListener('click', () => { + dataTransfer.exportData(selectedCategories()); + }); + + const importInput = document.getElementById('import-file'); + document.getElementById('import-data').addEventListener('click', () => importInput.click()); + importInput.addEventListener('change', async () => { + if (importInput.files.length) { + await dataTransfer.importData(importInput.files[0], selectedCategories()); + location.reload(); + } + }); + initialized = true; document.getElementById('save').addEventListener('click', async () => { From 97628c693ba80c96d855cf2d79ce222b7e8d5448 Mon Sep 17 00:00:00 2001 From: Jordan Wages Date: Mon, 7 Jul 2025 23:54:52 -0500 Subject: [PATCH 097/148] Changing up imagery --- ai-filter.sln | 7 +++---- resources/img/average-16.png | Bin 0 -> 416 bytes resources/img/average-32.png | Bin 0 -> 794 bytes resources/img/average-64.png | Bin 0 -> 1506 bytes resources/img/brain.png | Bin 13993 -> 0 bytes resources/img/busy.png | Bin 3603 -> 0 bytes resources/img/circle-16.png | Bin 0 -> 389 bytes resources/img/circle-32.png | Bin 0 -> 724 bytes resources/img/circle-64.png | Bin 0 -> 1566 bytes resources/img/clipboarddata-16.png | Bin 0 -> 314 bytes resources/img/clipboarddata-32.png | Bin 0 -> 543 bytes resources/img/clipboarddata-64.png | Bin 0 -> 989 bytes resources/img/done.png | Bin 3543 -> 0 bytes resources/img/download-16.png | Bin 0 -> 345 bytes resources/img/download-32.png | Bin 0 -> 571 bytes resources/img/download-64.png | Bin 0 -> 1006 bytes resources/img/error.png | Bin 2921 -> 0 bytes resources/img/eye-16.png | Bin 0 -> 371 bytes resources/img/eye-32.png | Bin 0 -> 733 bytes resources/img/eye-64.png | Bin 0 -> 1394 bytes resources/img/flag-16.png | Bin 0 -> 300 bytes resources/img/flag-32.png | Bin 0 -> 475 bytes resources/img/flag-64.png | Bin 0 -> 800 bytes resources/img/gear-16.png | Bin 0 -> 462 bytes resources/img/gear-32.png | Bin 0 -> 993 bytes resources/img/gear-64.png | Bin 0 -> 2169 bytes resources/img/reply-16.png | Bin 0 -> 289 bytes resources/img/reply-32.png | Bin 0 -> 432 bytes resources/img/reply-64.png | Bin 0 -> 750 bytes resources/img/settings-16.png | Bin 0 -> 421 bytes resources/img/settings-32.png | Bin 0 -> 787 bytes resources/img/settings-64.png | Bin 0 -> 1489 bytes resources/img/trash-16.png | Bin 0 -> 390 bytes resources/img/trash-32.png | Bin 0 -> 631 bytes resources/img/trash-64.png | Bin 0 -> 1126 bytes resources/img/upload-16.png | Bin 0 -> 352 bytes resources/img/upload-32.png | Bin 0 -> 565 bytes resources/img/upload-64.png | Bin 0 -> 1006 bytes resources/svg/average.svg | 3 +++ resources/svg/circle.svg | 3 +++ resources/svg/clipboarddata.svg | 3 +++ resources/svg/download.svg | 4 ++++ resources/svg/eye.svg | 4 ++++ resources/svg/flag.svg | 3 +++ resources/svg/gear.svg | 11 +++++++++++ resources/svg/reply.svg | 4 ++++ resources/svg/settings.svg | 3 +++ resources/svg/trash.svg | 3 +++ resources/svg/upload.svg | 4 ++++ resources/svg2img.ps1 | 28 ++++++++++++++++++++++++++++ 50 files changed, 76 insertions(+), 4 deletions(-) create mode 100644 resources/img/average-16.png create mode 100644 resources/img/average-32.png create mode 100644 resources/img/average-64.png delete mode 100644 resources/img/brain.png delete mode 100644 resources/img/busy.png create mode 100644 resources/img/circle-16.png create mode 100644 resources/img/circle-32.png create mode 100644 resources/img/circle-64.png create mode 100644 resources/img/clipboarddata-16.png create mode 100644 resources/img/clipboarddata-32.png create mode 100644 resources/img/clipboarddata-64.png delete mode 100644 resources/img/done.png create mode 100644 resources/img/download-16.png create mode 100644 resources/img/download-32.png create mode 100644 resources/img/download-64.png delete mode 100644 resources/img/error.png create mode 100644 resources/img/eye-16.png create mode 100644 resources/img/eye-32.png create mode 100644 resources/img/eye-64.png create mode 100644 resources/img/flag-16.png create mode 100644 resources/img/flag-32.png create mode 100644 resources/img/flag-64.png create mode 100644 resources/img/gear-16.png create mode 100644 resources/img/gear-32.png create mode 100644 resources/img/gear-64.png create mode 100644 resources/img/reply-16.png create mode 100644 resources/img/reply-32.png create mode 100644 resources/img/reply-64.png create mode 100644 resources/img/settings-16.png create mode 100644 resources/img/settings-32.png create mode 100644 resources/img/settings-64.png create mode 100644 resources/img/trash-16.png create mode 100644 resources/img/trash-32.png create mode 100644 resources/img/trash-64.png create mode 100644 resources/img/upload-16.png create mode 100644 resources/img/upload-32.png create mode 100644 resources/img/upload-64.png create mode 100644 resources/svg/average.svg create mode 100644 resources/svg/circle.svg create mode 100644 resources/svg/clipboarddata.svg create mode 100644 resources/svg/download.svg create mode 100644 resources/svg/eye.svg create mode 100644 resources/svg/flag.svg create mode 100644 resources/svg/gear.svg create mode 100644 resources/svg/reply.svg create mode 100644 resources/svg/settings.svg create mode 100644 resources/svg/trash.svg create mode 100644 resources/svg/upload.svg create mode 100644 resources/svg2img.ps1 diff --git a/ai-filter.sln b/ai-filter.sln index 7922392..7818aed 100644 --- a/ai-filter.sln +++ b/ai-filter.sln @@ -47,13 +47,12 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "prompt_templates", "prompt_ EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "resources", "resources", "{68A87938-5C2B-49F5-8AAA-8A34FBBFD854}" + ProjectSection(SolutionItems) = preProject + resources\svg2img.ps1 = resources\svg2img.ps1 + EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "img", "img", "{F266602F-1755-4A95-A11B-6C90C701C5BF}" ProjectSection(SolutionItems) = preProject - resources\img\brain.png = resources\img\brain.png - resources\img\busy.png = resources\img\busy.png - resources\img\done.png = resources\img\done.png - resources\img\error.png = resources\img\error.png resources\img\full-logo.png = resources\img\full-logo.png resources\img\logo.png = resources\img\logo.png resources\img\logo128.png = resources\img\logo128.png diff --git a/resources/img/average-16.png b/resources/img/average-16.png new file mode 100644 index 0000000000000000000000000000000000000000..ff202ff88b987856d28c37c894f1a362af2b0b00 GIT binary patch literal 416 zcmV;R0bl-!P)H zK~y-6ozuH6MPU#H;BOjr z&X4U9JDKFqT3Pe2HM9RJBK+s8s%i>%1K*G>tY9*s8=OYOL-K7LU{*xbg+c7&1y?xA z>L#|2PM+Hlp%f3{9JiP+8z;YjdjvW?yo|7eQOrfeQ$wNjzLb+H){`qIb*E*iG6n$up7h@*nKOikV3^&9aaHX`D%VJ1<|V5^MK zWcyRBZZ`fh#DzbImvV?>pZ|kB?|c49Jd8W+)>uJyGS@v88^nt#KEvRL28HcTI(fl0 zj&YLbXY7{Zh)`iVSGd+&RX(O=?~kd<2B#76*su-#m~P7amwE%VNkkY)Rgm5Q0000< KMNUMnLSTY>O0#DG literal 0 HcmV?d00001 diff --git a/resources/img/average-32.png b/resources/img/average-32.png new file mode 100644 index 0000000000000000000000000000000000000000..e0fe4b46d0d2d0de6ca4ff004a33dd5acb80462d GIT binary patch literal 794 zcmV+#1LgdQP)7;9myn zimd}B5g`w87jOYs4v=Pz??46EqcKK-pZe?%@EBMEsyf#X z><3N(2MqQ-a2vR*+ui_~r4E!g;4^{@81g^BrM$Uf zVoZAi#)7zjW4CTyN`9;ja+`4JSOB{62)JgP+F7}u?RQMP%TWO&rS?_9FFQb9*7;XD z_XV#+{Qy%&?WPHrhg_eHn79)$0S^`QVTp_4!Opz?yy|4o8H`#TV+>hDh zvI6X?`^d01$^Dp3uBHGHsgoSD0D~FiW#E~TH-Mu#$!*M4vAu(rD6=Hnv$&mv%Sgf{ z^}QD>!%141I=t0Vi;y2SamQlBA1St55Q9IoM^623fa_9!; zjnj6>Pmmnx0=y&7ajcGGo`C5#$gdjm8qgoa1sp@ogpeGmBRLc9jq$4ihqCbNno_TC zZvf|k>p+Q?eIjX8{ibvfI8D-=rZx|p5s@lcW|Rl(oK{<23+zhP_=aiAqdTS~B{s=+ zk`kQ&W`NZI=?ZWk7{@EMJOU~)@{D)g1MJh$v(+SBmjn8vcoBFmA`6-C>mOM3&uAy? YFQTTm<6Y?dp#T5?07*qoM6N<$f-$sWFaQ7m literal 0 HcmV?d00001 diff --git a/resources/img/average-64.png b/resources/img/average-64.png new file mode 100644 index 0000000000000000000000000000000000000000..bec89df178cb32f906ae102e43d4ff8284711374 GIT binary patch literal 1506 zcmV<81s(c{P)d2v}$TK3Ik$)eORZ2I4U|Y@fQOcb7!y=VZ7c=t_^^B1y?f8h?(ELpyD2A`hdcM|Ip_O5Gqdw+ zmDZXESsrS10F9Ohh5)5hn^H=}>(@O2N~sQ|)DOS{Fr$=uvFiWzJO(JGI)HItccgkw zYu&l3QzQXOsU~1M&%o@<9zX+|wAOb4n({hI2%-fz2aLgcN)3K~O369&j9Z zG==&sa0R#u+#(qK0NQ}3fStf|1cPLfEC2&q>#q~~{AJ)Zt@WRxl^j{$7y`FtY6Un4 z9058VYUI&BqBGn|gg?TR?r#CMF7F7E^c%g4-*_8nUCrBB2SjAtH`7v zh6RH|Wy*Z)xl@Av$xH+Qo2VW6SL&U8*USs8Aij2(2U@Za@U{@Zxw3+f*q9WaJ!I0i z?F#P`>P}nqb4jixZM8@-?l)>%n7m9alU-%ae8g6_VB?Zg7a-UyjgP1^Wd|Rzc_U_L z8Q9>`1-hx-z5T`5j53N+s-0l@Y-;ugQa1azT#5bONU+ILBPIg23w75s1Y(r1&rbj^ z2!B`l{2v+3Ulr;kOhy8v{k>ZmgQ<}^X1*d4apIn(iGWt2Zc(UnmJs|H=FA_+k@<@J zEz~_CDHeJ-S`c_AF%ckTyDg8Sg27AKUXT<`XM>XRlUbwjILS#XQmj(9Ft&hMp>9`} zND3J6BRSx8;J6`D0`Ss?$Zeq6nSjvXkN{-Z zpqptM%QFF|1m7pD&mG@0g8voZrQ8IB4!#l`EMY#SEfW0m$VX$RQ$3&3$rjRIc`Fip7x0@9!#uFr z8v&uS!zBcN-4Mq+sqHvAwOxvuF1XoCnb*KECtD6qlg{UtfTIO~|H#niHSitKS;BRI6U2K-L-RoSNrc5^D(n;C!Rn7ogy^Jjxn!W9O{$*gaj=)DrF}=-9KpyZh zJ9~hW1T(U{pl^q^tgAX-1emVDW<8~C2Hpfd0WMLy(JGZ?;3Duba0tt0hL5s32r8wT z3GV*IzpeAOho_XbMPR1HyD0i+N!noavEHAS=V2Vrjd33?QoL(53T<1VIFT)r~m)}07*qo IM6N<$g6_7zO#lD@ literal 0 HcmV?d00001 diff --git a/resources/img/brain.png b/resources/img/brain.png deleted file mode 100644 index 296bb646386cd6cbcbc028e261e84bc130a313a6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13993 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 Z{{!~PeOa9a)Aj%W002ovPDHLkV1jZT)9nBN diff --git a/resources/img/circle-16.png b/resources/img/circle-16.png new file mode 100644 index 0000000000000000000000000000000000000000..9984541714ea2e78e5bcd3c480ee3aa3f5be7ca1 GIT binary patch literal 389 zcmV;00eb$4P) zK~y-6ozuZCLs1Y0;P2kBs0Yy4X(jbN+v_h|m;SmbKAM*N2FBYAlS1uY(M`xI*APoxmk_kWFDK;3b^l6$7kSay=Yi zj3HW61gY~mZqTWAs7=^SHN$d}GO?FB&ji;<-q5cSTw(AVxI%J>Q7OO*Ce=63LC{N> zc8*ni;J#6&=D16kPM#$CPh^?i?Su zrjT)~ZlqI%NoJBH@GXv2jg*qDL^4+Byiv(*;wW`KQMYn!nfe$hbS{@^f(vY`EmQWx jIxqWH<}M;$n(96QSQkD23raJV00000NkvXXu0mjf2D772 literal 0 HcmV?d00001 diff --git a/resources/img/circle-32.png b/resources/img/circle-32.png new file mode 100644 index 0000000000000000000000000000000000000000..6023c0e97862d2eacd2b0fa78dad9ad5653301eb GIT binary patch literal 724 zcmV;_0xSKAP)%_D0Ty}iH~|ZU5IZgcI|x=F zfhZ3G7k~{&F?mRV0}#u_VruM4XFQn+)1swTX}Y`W|E8xOHBLnMpJgDggL7^O7zNG% z=e4;7>;fAi@+((B5jnB~RbUSI0JH(=Q`^8IFbh;O#XdrK0JsbM>?63NHL0%!OabL% z0RX3g1uy6la38n~oG@c6+V((a$@;tnYPkS_OTaf1WEHrPWlGh*4y+mfufRwq0HEfH zzW_>E#Z4RsJO(-j;?PVaee-zQJ3u3^a01AbfoS?`!XJFky!n%V6*qC8nYfKa0NrZw zYF|0dw5I@+fOWGws!0HIhBEVl%K#o+MzD;1#|K_;>3`iB20p64T zYqk%(1E%d(ORG)=G8fIBMuD>&{5jnr`Z@ibD_&lJqRU@oF-b>-c!^&C00002ElnGxQj3v*5<-m8t+phMQIZ;6xOam<)VMGb zKuz2jU!*S3s)<3xM|2}dqCzxjt8PTz1}a6M+}?gJ=3F>;?wq-&_s%(|H~3E`xidNU zoB#Kp$2s%Oj1m#9Wz5Q&K-S1q0HsuuQtF0GIV3#SHKMgyt z0h>kSTwKm2sG`+Z0)J4xwT=UC1CIgAf!Pk5vw?Qtao`>Fq*%`W@4#KD4gugPV8THv z59|RR1nQ~~xjwM5C$Je+-zDJ5#03Bp@PdQLRM6VXe2h<{?pEO4ppK~ew#}k_#BV+Nb!uyzuBrq8=3;-jsiD_iu1rtA~IGeFnhp#ma;Eu&3OP3$)Q7MVblR@!v&_Z zJr-Nvc;uBfzP6OD3TI3KS}lM0!5f|QallemUctq2CwKtEe!{AyJE%Yvl7Ha-op9B7o>mLbJ=yPmowzFt_2y!x?i395eE_Dy3$7 zr<4+uQjNe;qxfhzV+t^A(-6Y`cWGr-PY$FhW1&E90D4%cGAK5 zI^Y)z@4b=#aTx0aE?bQ4$l6f{XWJ2;9F8-Eu2p9vxa&Y!pNyNKglKx_emN(Lgj*95RJ zL+AS=T3&!nv20AEvTYF+3Hn&;^(i{ui2e9ZAw3t{)-)^L<*4*9usQ|j*F?PP3TfxG z>{UQutE2KM;60!%0ms|X7bjdtWn;H|#R3Fm1|lZLLdpXl01pB6RXE)MJPdq@`>^!I zxMSXn00Fr!^f|mJQiXIX=oOoQ4jf;S!PxEyp4}b%x19YEV$AkYsoDz@&A=Am8RB1b z$fE-lr@0!1ZbGl!7Zd;DMGn{rY!Q*lH*h?S&raYo%D0xUv=`{`!rh0FkPzMI@oGC@ zS#8Rp=arQ{IVW{(t_6J{sTX~@_Gt4QPGe3Bdr2sPl*ZlVQe^mr{58M2! Qvj6}907*qoM6N<$f_{k1&;S4c literal 0 HcmV?d00001 diff --git a/resources/img/clipboarddata-16.png b/resources/img/clipboarddata-16.png new file mode 100644 index 0000000000000000000000000000000000000000..6d615ef77b2fba225855802cb3e4f5d4e1b1ab23 GIT binary patch literal 314 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`oCO|{#X#yh2s3WX6WN&PEET=(wkgV~9oX+sTGpOojrk_gnTh zh;3?(a}?0k&3&`Cze3(SwO_G(>{F*T`lWsWGT58Z!e{`8q-zi8DBfr)$< z%)f+%e(y~Rtz{@UAo1bA!2|7cs$UwO&3?c$r=jzp=993M9$E%WSqr#BW^!sR5YKAc zxZWf0GSi+_?;0{6uRH(!ql5LlySoqhKhADEB=nH`x#D)7FFZRKy65|U5LbA8#OUj; zn^T1zAGxD<#UxiIFuBa}QmL3AJI{{WR^sjni&tIuxWgbjr+2U2RXanVml!-<{an^L HB{Ts5PGNe5 literal 0 HcmV?d00001 diff --git a/resources/img/clipboarddata-32.png b/resources/img/clipboarddata-32.png new file mode 100644 index 0000000000000000000000000000000000000000..a4268788d8922fd9d58f18a10f42b526d3681169 GIT binary patch literal 543 zcmV+)0^t3LP)h)4k#HJ?|ZI*!-!DiJG)!Jswy9p1J4Z-bJuF==JokhU=iFtG|O@{>zfH1KFY h4Q)vLIXc~*e*t55xZec^9X$X5002ovPDHLkV1mug>2&}A literal 0 HcmV?d00001 diff --git a/resources/img/clipboarddata-64.png b/resources/img/clipboarddata-64.png new file mode 100644 index 0000000000000000000000000000000000000000..9d945d01d1ba90f1d95bdec111e91d4d91aec7e8 GIT binary patch literal 989 zcmV<310wv1P)$Z zybZ`3?O6&JkqXe2Qp~)n{`O%{EL7Ed0S1AWz#^b2%Odas=+DH~44l8^!Rbcj=DH@p zJo&7g|5pZl+U#u-6cGU~`jXcK7mO}1kTlDnh*W{|z-eFy^^@vP;B{gJ0eY#QNLPSQ zz!Tt(s(wr?Jz=OJ~X?pgsbF-LhxFluxi1HMMuItXmEhhqeMpq}-jje-SWXGq`im_AcZJ~=qw zMt%5C#`HT$5EZ_ip8-z9=$nf4s{w6UtO8xshyP5pld3)wk%Pcl;4rYwK}Q^Bfj7Wi zRs9ju{u$^A{q8Wf&e;feAs{aMip`=_^*eCeL3SF%*1J> z9QFgcX|d}|upejhZvP7C42|nFbv9#%EOw2%v)B-6N&rDLEm=CDgud_q0}kVsfOcO5 z6n+lyMu4iW0K=BuCs@6KI%eu@Fl=;rf!9e;Rfk37IgXQ{s{Rs@qvS9NdS3;MfzC!6 zLLU0Irxgl62b6h0nFo}4K(SHg0lox5nFj!69Vfzg<{`+1OHoWB>-^wdd?NhWNSR)KfaADD#T#O4)T_#aT0 z3lz2)Qz-MghJDty)@8)mp9BO{fXC~=*=Tu0f?Ffb1cXSqO6w~#Yf(~NnMp)Ih=?k1 zgWwqbT9UC0yf?b{r12rut+6o7Rkkf>f+;dNSM_0UH&Ce;xh{xftxFvSZp(00000 LNkvXXu0mjfL+`Wz literal 0 HcmV?d00001 diff --git a/resources/img/done.png b/resources/img/done.png deleted file mode 100644 index b70d72805599e17c091d6b170b3dce3c55885407..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3543 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 RKqUYG002ovPDHLkV1h&PnS1~M diff --git a/resources/img/download-16.png b/resources/img/download-16.png new file mode 100644 index 0000000000000000000000000000000000000000..620f8687f8c8303c97a8af259cc528a254da2195 GIT binary patch literal 345 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`oCO|{#X#yh2s3WX6WN&PEET=$WUBV~9oX-OGl0M-l~CKiqdV zadDjDurxh@Ea`AHAO%wUI`zFWk8|S>2{d`uN zpB9%E6v}omV13G@w<^_pEtG4y&Ln<1FZ+k(f1tw2nn|}+xMTA-d#;Q&4MeC&2 zy@F=%Gs$e?I}Qg=+NyF{wl!^{*vB66H%Su5SE!vc=$hO1xohdFR~&C1?^(5Fv7qG< zPB;6feuV*{b6uqlCx6cgy?W@H`90f&KibP0l+XkKMly-e literal 0 HcmV?d00001 diff --git a/resources/img/download-32.png b/resources/img/download-32.png new file mode 100644 index 0000000000000000000000000000000000000000..840c82bc7d42bb4a1a21d5d9c971a6efebc4af80 GIT binary patch literal 571 zcmV-B0>u4^P)ruf3NrTnac=wmEFhr68~fmJlit{Lrra3?v;gaYh)!QXK)wq+&yri=gG5pe7zW+~ z5wK@wbCM$9J22p&i@=DBSAmZ%{z-g0{*p8X^Z@6;4`9X2E)%x^cm}L_D=GPFHy;Im zBJ^G0g~PT3*TMWI(3ZFbz`O@O2KIqvpxMJjz{cOm9WD?MV8qa&>;J<3FNHH@z14h$u z2|538J&aEHXapP*7YM+sf56r4#RsLJtP@JwChlCP#697pM&vEPC!iJBH?!LX21n%` za7J>ctJW`op|rc83z!0WiO+g1>>StzzL?ow8DA*ie_P#8!42$Q6^|nLNJIbt002ov JPDHLkV1j-8_PPK7 literal 0 HcmV?d00001 diff --git a/resources/img/download-64.png b/resources/img/download-64.png new file mode 100644 index 0000000000000000000000000000000000000000..67aa68df0ef30c4a0232edecfec0c03cb7d48807 GIT binary patch literal 1006 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 TIJ7S^00000NkvXXu0mjfV^C6t diff --git a/resources/img/eye-16.png b/resources/img/eye-16.png new file mode 100644 index 0000000000000000000000000000000000000000..392340e68ffc711ea339434e4587a3cd6441a659 GIT binary patch literal 371 zcmV-(0gV2MP)`@!!F*@$~oT;7+^aR$C!;+2OsF+GS;o29krXq@McgvEUmH_ z)R(Y;SFD!uM|eVWs*qwx(0;_`kZ-+! R5e@(V002ovPDHLkV1nL7os|Fp literal 0 HcmV?d00001 diff --git a/resources/img/eye-32.png b/resources/img/eye-32.png new file mode 100644 index 0000000000000000000000000000000000000000..5531c1a5252f0b50190e6493752d731548c55b43 GIT binary patch literal 733 zcmV<30wVp1P)tiUv|}w+qZfEDP9!ER*jKk=NFwNMI+7Dn8TB7x(ID&yF&OgGodQO% zF^9Y>B0Hp1McX3#<{aO37)~*F(G&~V5(U^@r7HR&+_cQvgVcVqivOO-e@h6VVkfND z9fzamNyUdGNs{Qj{HB*iQf7&c;Fi)6^yTbeo>CewV`@r#FxuJr9N+bk?;Y_Gq<{qq z7o>Ozx90>p8j<~uf(C^ikyP;6fuR)h3iI>Iut%X(iUBWTP6pG8V<~xDhF8#@!Oq2{ z2=gAxbNfKlL>@#=11Vu=g^JjrP-5MgwQd|&=#+7v=*aTrwc^Rxk6mbqmYx{hiU(4A zn^G%Yg(Z>CFiv1!2;plPSzgIRyF7z$nRM4Ozv48ORpY4jb37eu(%Fl}%Ks%s@J!)z zd=1w^2%pA`U5kJUf+k|7Lh6h6i$pI5YP}%cL9F@n@x_{OJ%mX P00000NkvXXu0mjfBB52F literal 0 HcmV?d00001 diff --git a/resources/img/eye-64.png b/resources/img/eye-64.png new file mode 100644 index 0000000000000000000000000000000000000000..7d7fbd2011d74575fe311d18ae099c025e684e35 GIT binary patch literal 1394 zcmV-&1&#WNP)W)xBMP=c00K@UYQl_02L(FLO- zQ_=@}iO7iPrbWGUqav_Oi=Z^kQbN--PlT7%!>og{U6(!kTvp)zV4n7T|L;HlHS^8P zH#;RkHS zw|GBI)6IRtv$q6Dl4Jm8<3?PE@x20k%(i14-p2YgO^@^nYMQ1!Y8ZhBuoY=PwcoH9 zr}dbB4+cIKFXEqm9C%~v!t$O75xoSGBpHbNvM(?)!gU9}#}@o0B)tRKZ^JUIkvI<* zVq66FUM#|jG))gj_{GftTq-1{sxNaC8}K-$V?+xxY$Rsl34GH;%oN|@l0I1in6G-e zZ^c76vkAPx!p<-iooyz3RYGG{Tw%AKm}GO?#9R2ENM(^D{+1W z#sJ)cFDf`K$DkewkPZHWk{~-UN4A|-U`@fsCZ_QrENMc_1at9w3D){55vsn{8ztb+ zVQ7=f=L#X|#bo%`t3=4Khv9`1oV8^*W$Lc(l{FR)M1MpMzPmjg5$AT{NS%lCGCE=e zSXuzI4U?NCm0_(dz}kaX@si^8d>B(AVoeoJjCoj#n-T!m;7AU@PFxT<_=yErt8r>W z-|5(u)AyCgm=g+cj$l@)0NHx_HOF}$ro|A+@E*>=dQU;p#AP{x?Z@EAxRbLP));%c zhP>72_)Lz|AzT?d_zdsO9K6dbeAeaoG`$Rt!A_xdI4TzbnUKVJm~rFh9w` zE8muQG{@(L7UM6@!RkV1cb{e|LOrP(<(kA?=SPqlh>uDJS=5eTc0`;xI9PzSM$y@$ z1aN?GAt@rb9K)L=HyWQt4E|r-8L`aDuIsOfy$l@(K1jGy7J=`?ydrgTupTSi z6^Eq^uLF0=T}S zCBO-Rk|e>|LhcwPl;4JDKkpX?y%)RFG~L!Or1YZz|5rQd|0C2Epl$+nTU&s-3Dj+E z0qQ1Dx3vYRn?T*x7NBkdbz572x(U>6C%pjw0TyUl8PSTrR{#J207*qoM6N<$f}z=i ALjV8( literal 0 HcmV?d00001 diff --git a/resources/img/flag-16.png b/resources/img/flag-16.png new file mode 100644 index 0000000000000000000000000000000000000000..3c2b58c46f67f386e6d384a0849d0e9ad531eed7 GIT binary patch literal 300 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`oCO|{#X#yh2s3WX6WN&PEETXs4%(V~9oX-HV2POo<{a58ks& zYrWagB*G@u=kSp6&6*w4F5Rx+)!!g0D#|KyTaep#9_yR5*odDSOD0`E^ThYwY)`?3 zPF^qNl=mk~3%c&TY;+^B;e6lIXc0lfl`}h5u&X}vUANHoA@gSWnm)#5Heev3N3eZzTh`PJ^aO*atDnm{r-UW|K{#>J literal 0 HcmV?d00001 diff --git a/resources/img/flag-32.png b/resources/img/flag-32.png new file mode 100644 index 0000000000000000000000000000000000000000..531dee24dbddcc7213738008845885a005265531 GIT binary patch literal 475 zcmV<10VMv3P) z5=>$cku?}}J%%@n<<0nZclL?!4h%Ez%{|OFcbE%flK4yY`6kS499RU(U9Qmt&Lq`S zXCu}NmA1n9~HpNhJbTm0C)!$Bt3^b(E!Y>1e^e)B&lDKbn}}pW(GEaSvTI5 zRLx?F2{7mS4`4s5DJH-=NzthQRWs|)6+qGzu;D(ZfWuq?oOXcL*)N;fTCM;}s?aKM z>wfK-*>uPgD#a}go7qI0EL$X3vI3l%*`%b$)W{5_I7Yk3trUCo>6^%M1V^-SuT#_n z?z#bZl2q#gAgH{Kpa3WU3V;IOe*!dI|JF+Y^SzGU<8%f%kkm*G>Loy4`UdU)3)QWZ Rx&;6L002ovPDHLkV1k1O$kYG; literal 0 HcmV?d00001 diff --git a/resources/img/flag-64.png b/resources/img/flag-64.png new file mode 100644 index 0000000000000000000000000000000000000000..64464154e79aa1bbc80c3cfde1b41a0b032b5c7c GIT binary patch literal 800 zcmV+*1K<3KP)Smrg}2EF`RgjcqzbD-l#8f>t6}q!QGq zD5#{fvR4p6C1_zIB>0G+kv$f>h)(XB%-q>MC!6_Uik-uG+>hOV_s(8XRhF|>SPx*W zRjG+0vIZE)I7=PPsp_|+OjV6qz!2~RXaeeFHQO@{MPE+>fH4Ob+-Z%)UQdb#>`ch% zmA1zwqyX@2oDX6Xl1(tsGhi-Lt%bB3SXZ%s7Z{JOmf!)C%>V4IkFArkfMMWQMgLd8 z+LW4}-_HL?M79C9fR#aL1~{myUsCEW2>|Wi91nqwL8u9gsOsC)+U@~}hyXW%9Tnj- zs`|K2efI!>)4-96{rkYBy2V`s5RqZvTt(|6O9B9N&lGc=3Lg`Z@0n`-PgB4&up!uQh{$tQy&hdL)2XnB^#j<|x2M93 z&>%1xo77JL03YA{TQ2=3&6Ol&Sa|9Q}xqFAV~#) z^#Il?0IUbFRsmo=fVBz$>jA7)09X%TtpdP$0BaQh)&p3p0I(jwS_Odh0M;r1tOu}G z0g#Z>T;$%8Pzr#T!RrsI`Z>oi7D@qd9(YRYAKCZ7(X12oSd#kmY5R%p*={_(+Djz^ e=oc;fZ-L*$`ho>)%P__O0000 zq2ZN#by_%Y9bPYXU|`P7oSEl5&p9GO+wd53)&2pNQEt?ZIs6VI46%B8(<#07+^AE9ZaNO@H-LRug)nr%I>FlK8}|x-m9*2&@@=a{9aEUY94tC*^adib2S(IR*SS6FBQ z2MPZId$-8=BGCliqtwaiB=bzZdDjoA@uzaYw)&s6CM;(6B|LTgjDIF4Yni+Ezt8mH zuf{yX%Ov>{Z`<_^ynh;%Qc{^gMEuCuL)?jouWfz*06^nayWlO6ZvX%Q07*qoM6N<$ Eg7A#aUjP6A literal 0 HcmV?d00001 diff --git a/resources/img/gear-32.png b/resources/img/gear-32.png new file mode 100644 index 0000000000000000000000000000000000000000..67300de32f7e208241ca8f76c9d526056736ad3f GIT binary patch literal 993 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 literal 0 HcmV?d00001 diff --git a/resources/img/reply-32.png b/resources/img/reply-32.png new file mode 100644 index 0000000000000000000000000000000000000000..193deacfb988ca7da2d88811ee8fd6616922c4d1 GIT binary patch literal 432 zcmV;h0Z;ykP)LBxownu3nX=b;}DH5un+Vi#OxKgxBZ?QLZFqp z@~6}|R=oiiz}ny)sHzXl15Mys(q8&R(IYqjo+Fqq09(Kzun2qtJGL)@KSQ`2E$z?% z9>U&TV0zfsFeXGZwfANwKv-BxBLZgWzZC|Kazkjl4V;GQ2CzC}4w8L8fX6Uh0hlRR z+?I6PANno^K+sn>st_PRoJTay)MWn;l%%A+zd))HRV7L5z&3DZyH`2Dp#EhBYJeKx ahrR(F>X`>a$?AFl0000^6 zZ_$_&m7#35GKa-mRA+IRSyJX(aSt64?%XK}!rEIme2VU9O~_m;@X_Ca^W~EsL%~H) z(hI8<-<-`W`*yDS`=-waM64%E*S+6ty?b)(WS7}9Kk+^A6?!0hV7AHu>jrbrhH{4d zNeu59?x`@|W8CA(w1>IEcnX8@Y{Shn16w~X*v4SIo4urQ-ORhPu}chM8mVgW&a#0q>b-8vD}JGm>nZsI{x z{RH71Pxkh;XRg(&i)Uot`y+@kS7Tp*Lv+{lmQ>dFNom~&<{tQ4BwfK&v!Z^EoW>!x^4e~;s+_wtY25X^pH~OVAPS#FVdQ&MBb@07w`^00000 literal 0 HcmV?d00001 diff --git a/resources/img/settings-16.png b/resources/img/settings-16.png new file mode 100644 index 0000000000000000000000000000000000000000..bb7581d506458a18599594975402ef774d06ca03 GIT binary patch literal 421 zcmV;W0b2fvP)~3* zK|~DW5I@ku9BP?))>i;CI4WIX48L)TA^druwuRS~%={J+bxdLxYq&ra?{VHopdmB= z5sTQz0hYURukf-nmYH-1dJ$X5!cU#KN<=)zI>s^5W7H~^Fk3unM8p-E_*g-^>~m4r zjfv9vya;45ehSt9UEvEZ3qRlU03UFI?|9ooAW$!i&Rn2|uXu;2*uWb%x6lul*o*RY zJ9t)%Y~mNL2MDw=AEl^)pBOF53z_-Q1>Qkqrihrv3a+p{=>G2sJO+OOP)yR=mcdHVa5gi?GU>cEq7RS+3w{In07yO-4;KlxN zR{`Kr%;aES;~DJ1r+Mujo^1j^iU=vCL41X66)Fux#I;gBOyXhO!0)S6{x;r@h;P~_ zex(D|^LStpJ6CF?S&4s8W+34J9?1wF$B8_CEh5fj2A>T=6EWs)Od{zp2N71_5^YJAmNGUyyhid8SY)|0BJRZd{B)p4}y#4|% z=ke``m|c(nuUAmF8lP6WC(w((E54h<{)kw(j{j1$*R@(p(Y)GrH~V7i#SZdy91&wF zrN{8#DgzJUtRfNL#Ob^~f-QM`0zc&OG(MMuH<5q|-};y0pYU^Oevu;Ix>*G~@SXqb zJ%R1ZDnq=K(N5zJ#r3;$1t5Actf+)h971pHp3>$cibPy|f*HKn6jPM|@TB5~3jBzp zIEg>=+I94G13>#x`Z6}<(>@ou*Qb;&;7e@Bdnu*K<&?xSYzm)5M61ofNBN|eD>SW= zr3oJ{GjJpS4y2U&BVsDgcPmN^ZuxJMS&RLqsE&mk7*uquP?XZEIIMVhMBcEuYe|?v zoa#VT3kSPe1tk!}iY^uk?I$$!{O;tHFQWYXo{xyRhBWVJwNJA9Ve9_y_#YNnS=U7p R4GjPQ002ovPDHLkV1lC5YoGuC literal 0 HcmV?d00001 diff --git a/resources/img/settings-64.png b/resources/img/settings-64.png new file mode 100644 index 0000000000000000000000000000000000000000..347d454ca9f7c20728838a6404877bf507b3d2e1 GIT binary patch literal 1489 zcmV;?1upuDP)`A~XgeL@}<6@gqi~)QwSeff_$H zMi%PE7=xlFd;~xE(kL5r!{=1>b=LzCX~yjR^JBwrEAaGs%FG&Vz;(qRwgbNM6jm=H z7gykE@syc06c`PfT?#*sNoosm=YVFQ$r^hAc*CVB$|)UbXPN;Dz>BK7uQ=fQ8C(Wz zw1$rX3srTO#XAMqgh{Az>;gJHCS6M$RMo!tfUg540zE*h^=Jrq4^syWV9p3DfXf|X zma6J!$>*FgQdEM=NuPmtg#PZ^~!mfB-L({7lddw1kef z)0V1UhFdU6t(4)1foFjF(1w;GuOwIsB60<=0Q1eCf+;z713Oi9xJudcfqOB|o*4}v z#GEtMscLsM@`Fd9%<5_ZKBe;Z+62rBvIR0Uz8&aGV0@7d0qw!IKrJC6t(b;tqvxxC z1J`S;%1eSgw#C;_+W5l}xiAfQ*IQfY5(lKcK2ZV@9k9yhZqiMVy9!rZOw0 z85s7E_ZQX*i3>X~QW)CkIPFfbZMr>W{y}sIR2_R37{+vT^Mn%#c#e6>oPi0pf#uBy zf&T~}`63MflgdPY5^&U0=EkyhfQZZlW_xll{)z@6iBJu*}P!`92Od0ON z9^g$?J-KQ^fBLM5K8iaLt^n#{e07+vk}Cl|?4vVRm7s`B!gQQ2b3E?FoIC|{Fmmzi z2WG44U}B}AqwZJ*9r%6PiZl!?^3|8SQdm{DVU~Bn>w<|@3L_eX&D zfvKlqMN9?eL{u|D(v}WyuEXY*|bpT(G{Cd2Iy}*sCI^g+UP>lHsh)4tQ zA#US`F?aoaj%Q%1N4qM^Kdhzy67GHeD$o$)n-6^F;2k8V{r^Nc0QkjW)Kew$L_O}K z=+mK%O636HQim};z_^kxo4bHop8m3=0ZePHv6KVa9WT98)_dmv1$k?tRHC(U8{$cD z0;gigF&4*2L}wDNj{k@|;E;p)h6=*w0TZj8(P_pv@gJjgK-3XFh-n$cu|!orx1~h< zTQIHcIC?Rc6nR4d*a56k)sw9@Yfrnn!bdUp`V!;22w3ajEdXtyGrJGjf0S$ie#Z3L zZ0y4vN+x3(5|bS~>s57m+7JbSBeQpsF1z+q#Vu{{I>2(mYER>j05^p;re+R^obVW? zc&KE27jRW*L()>&rl^QC0#9P@-{!_1odCYZ{IPn2mJ^b5B<>1F9otJV2cG^j+2}ZO r)fNwd+;xRdH_kaA^aMiVtarfwH_=Tv5PQ|!00000NkvXXu0mjfGS|6a literal 0 HcmV?d00001 diff --git a/resources/img/trash-16.png b/resources/img/trash-16.png new file mode 100644 index 0000000000000000000000000000000000000000..43e1f7fee82f83c47d98c64decbdd3c8063a9868 GIT binary patch literal 390 zcmV;10eSw3P)@wb`yx|FqUDvm1Ao99aG$MpCu86R7}a_J-1se)OVt^3<~sRKLgZfu z+WrcKnO(RR&a|Cb9J~V10|cD9T>^KmrTfmD={98m&^c0n+Dq&|2+#_fOR5eh=o6TQ zHB?R9P)%k%fFzmO(jg?>hTv)40Tv1$D3$>54O|^5q3_I2_6Fq{SW_R_sB7RUp0WM! kY-T;+vLS;4ManZK@rxo4-h1hn{Qx1a!yX-CF+9+K7e>he1lvf=3p*K z4qjCPLM}q02BJpX@-Q{hHr+eZGb0j6K~rqkzi+C(-fmGbPjnSKMG zRCPNkp{kZzKnvIav|z0RtCdWq85reXV8`<<6ve$XEoRBO(J;D_d;44gi2*FX^C&Oa_WgipZe1?Z%!r0swdi?1{*{Q+yuS zGg}NmQU_eLJ`bim9owq~pkD`4Vh&U=8>RY&v_JwzuZ_=CK!+GgvHkjUJO-qsuj};uXvBtIC@&A43xy z2+kkk8~`{mJz4|6i0RWR0KS=?6Opmh$|5ojytJQRqJH_SIFMkP>>bx4WAKke3{S~U z!4>daRd<431tfZ7#jC!4&wvTNyz+R7IS9qdHm}t}Oi0lI-=QdT<Dxr8kKnJ=7d*gG;ChYvHc@*9h{!bX#JIEs zJSIx(OclT^u+NbzFs-V8R(3Lh5PyMFhU^dEgsT2kM1hDL0PX;DNpY;ZRsur20!Iwl z#iGFjsOo#*qH*bHX|GZcf`HEr+3ON|UKz44O6bW%R|%$F5Rn<+3h>7_$(oM1B@ol7l31_3Yx)h^w$R;fXT%9s;YiW zYn)jL#tk`;z|&yY7bxgNQ)oN`J^&j9oJhib zA{y(lbh{Ikc~8@=12#xZd;7kHk^@fNDa1wY5{E~6|k3{2w-vGB%^+t{_m1c#Y#6n3CSp*IyL~m7f+}Cg& z5Rtd^uVGqL)k8iy%1mpyEN`X0fOiJeLBLk}3$#MOurN&PEET=&h%VV~9oX-OKB}S^`B_KHM+d zzgCR({{qM64uz(>54eA@ud&ii>+UflPDYerC>??JJC&ZvbPjQnAql| zrP(iN@kx~aeDqI~^_>ShTh54{{c<2Yejm%)M}ns<4r@;1+J5cI^=JtNWP@y|RWA%5)A_)!U!=6OWa3ba%Tg}*|9=twC22}CI&L4ryr#PcK~ zB7W4Okq|`Wy`$K3-=4j@>+Q;A6+6i!v**m6`R?2~b9N)8WRfy7(d<}VUxmaYNZDwq7@Ohv$jXb zRmSY*D!OzHe&}@R6*@BPc@`II zucI|m>=6M@m&uEZYZ)M~l@Mo|1endGJzu*ydjRtK+3Y*l7{CyyfdJ#`e>DlG08@Y| zz!YFySsY@IC4GO*#*i1dgP(Z)r$PFD5BzJHcn|yn?X6@UmO5cF00000NkvXXu0mjf Dma6|+ literal 0 HcmV?d00001 diff --git a/resources/img/upload-64.png b/resources/img/upload-64.png new file mode 100644 index 0000000000000000000000000000000000000000..65629dfb4ae1193db0e6150f47a5887cc9c27d32 GIT binary patch literal 1006 zcmVXdZ>uB0FMYdPJn|V(xIw-89ic&!{^E=v;w|3 ze7jTA$%7+#fMr0hh_q+%44}o~`|P|jq@kz*#wczm&H`0sG%CA*QAgYvn*jEg*$f>6 z{uIQW2I^hcJKJFZ5xE0&I);XTcg(iK!@xCFeeMi28?P03$p16%!UPbx97JRra1L0P z=iW@v5*MOhRok3_B96m;67SUI7qF#_nNL&+KrQe+W~?coIW$&8IUT0BoWksQNQ_q8 z%PGpnfjuEH4>na^+b# zQu1k}aKE#*$TnqVE)0!tIl{7sKOtN3QTTe5 z)^Wj~2zdd#0M-Po;RUcJU=1&TH34gQ0jvpF!wX + + diff --git a/resources/svg/circle.svg b/resources/svg/circle.svg new file mode 100644 index 0000000..84f078d --- /dev/null +++ b/resources/svg/circle.svg @@ -0,0 +1,3 @@ + + + diff --git a/resources/svg/clipboarddata.svg b/resources/svg/clipboarddata.svg new file mode 100644 index 0000000..aebd8f5 --- /dev/null +++ b/resources/svg/clipboarddata.svg @@ -0,0 +1,3 @@ + + + diff --git a/resources/svg/download.svg b/resources/svg/download.svg new file mode 100644 index 0000000..595f3a5 --- /dev/null +++ b/resources/svg/download.svg @@ -0,0 +1,4 @@ + + + + diff --git a/resources/svg/eye.svg b/resources/svg/eye.svg new file mode 100644 index 0000000..2f1f62f --- /dev/null +++ b/resources/svg/eye.svg @@ -0,0 +1,4 @@ + + + + diff --git a/resources/svg/flag.svg b/resources/svg/flag.svg new file mode 100644 index 0000000..ef18dc3 --- /dev/null +++ b/resources/svg/flag.svg @@ -0,0 +1,3 @@ + + + diff --git a/resources/svg/gear.svg b/resources/svg/gear.svg new file mode 100644 index 0000000..3827d6a --- /dev/null +++ b/resources/svg/gear.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/resources/svg/reply.svg b/resources/svg/reply.svg new file mode 100644 index 0000000..fdf9414 --- /dev/null +++ b/resources/svg/reply.svg @@ -0,0 +1,4 @@ + + + + diff --git a/resources/svg/settings.svg b/resources/svg/settings.svg new file mode 100644 index 0000000..ce5be79 --- /dev/null +++ b/resources/svg/settings.svg @@ -0,0 +1,3 @@ + + + diff --git a/resources/svg/trash.svg b/resources/svg/trash.svg new file mode 100644 index 0000000..c236be7 --- /dev/null +++ b/resources/svg/trash.svg @@ -0,0 +1,3 @@ + + + diff --git a/resources/svg/upload.svg b/resources/svg/upload.svg new file mode 100644 index 0000000..09e7ce4 --- /dev/null +++ b/resources/svg/upload.svg @@ -0,0 +1,4 @@ + + + + diff --git a/resources/svg2img.ps1 b/resources/svg2img.ps1 new file mode 100644 index 0000000..c71f0ff --- /dev/null +++ b/resources/svg2img.ps1 @@ -0,0 +1,28 @@ +$svgDir = "./svg" +$outDir = "./img" +$sizes = @(16, 32, 64) + +# Ensure output directory exists +if (!(Test-Path -Path $outDir)) { + New-Item -ItemType Directory -Path $outDir | Out-Null +} + +# Check for Inkscape +if (-not (Get-Command "inkscape" -ErrorAction SilentlyContinue)) { + Write-Error "Inkscape CLI is not installed or not in PATH. Please install it from https://inkscape.org/" + exit 1 +} + +# Process SVGs +Get-ChildItem -Path $svgDir -Filter *.svg | ForEach-Object { + $svgPath = $_.FullName + $baseName = $_.BaseName + + foreach ($size in $sizes) { + $outFile = Join-Path $outDir "$baseName-$size.png" + Write-Host "Converting $($_.Name) to $outFile ($size x $size)..." + & inkscape "$svgPath" --export-type=png --export-filename="$outFile" --export-width=$size --export-height=$size + } +} + +Write-Host "Conversion complete." From 58a2891847eaaf7991ba72ef8cdd3aa3e2895a30 Mon Sep 17 00:00:00 2001 From: Jordan Wages Date: Mon, 7 Jul 2025 23:55:38 -0500 Subject: [PATCH 098/148] Update ai-filter.sln --- ai-filter.sln | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/ai-filter.sln b/ai-filter.sln index 7818aed..f41f23f 100644 --- a/ai-filter.sln +++ b/ai-filter.sln @@ -53,7 +53,29 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "resources", "resources", "{ EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "img", "img", "{F266602F-1755-4A95-A11B-6C90C701C5BF}" ProjectSection(SolutionItems) = preProject + resources\img\average-16.png = resources\img\average-16.png + resources\img\average-32.png = resources\img\average-32.png + resources\img\average-64.png = resources\img\average-64.png + resources\img\circle-16.png = resources\img\circle-16.png + resources\img\circle-32.png = resources\img\circle-32.png + resources\img\circle-64.png = resources\img\circle-64.png + resources\img\clipboarddata-16.png = resources\img\clipboarddata-16.png + resources\img\clipboarddata-32.png = resources\img\clipboarddata-32.png + resources\img\clipboarddata-64.png = resources\img\clipboarddata-64.png + resources\img\download-16.png = resources\img\download-16.png + resources\img\download-32.png = resources\img\download-32.png + resources\img\download-64.png = resources\img\download-64.png + resources\img\eye-16.png = resources\img\eye-16.png + resources\img\eye-32.png = resources\img\eye-32.png + resources\img\eye-64.png = resources\img\eye-64.png + resources\img\flag-16.png = resources\img\flag-16.png + resources\img\flag-32.png = resources\img\flag-32.png + resources\img\flag-64.png = resources\img\flag-64.png + resources\img\full-logo-white.png = resources\img\full-logo-white.png resources\img\full-logo.png = resources\img\full-logo.png + resources\img\gear-16.png = resources\img\gear-16.png + resources\img\gear-32.png = resources\img\gear-32.png + resources\img\gear-64.png = resources\img\gear-64.png resources\img\logo.png = resources\img\logo.png resources\img\logo128.png = resources\img\logo128.png resources\img\logo16.png = resources\img\logo16.png @@ -61,6 +83,18 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "img", "img", "{F266602F-175 resources\img\logo48.png = resources\img\logo48.png resources\img\logo64.png = resources\img\logo64.png resources\img\logo96.png = resources\img\logo96.png + resources\img\reply-16.png = resources\img\reply-16.png + resources\img\reply-32.png = resources\img\reply-32.png + resources\img\reply-64.png = resources\img\reply-64.png + resources\img\settings-16.png = resources\img\settings-16.png + resources\img\settings-32.png = resources\img\settings-32.png + resources\img\settings-64.png = resources\img\settings-64.png + resources\img\trash-16.png = resources\img\trash-16.png + resources\img\trash-32.png = resources\img\trash-32.png + resources\img\trash-64.png = resources\img\trash-64.png + resources\img\upload-16.png = resources\img\upload-16.png + resources\img\upload-32.png = resources\img\upload-32.png + resources\img\upload-64.png = resources\img\upload-64.png EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "js", "js", "{21D2A42C-3F85-465C-9141-C106AFD92B68}" From 6c352e904e146fcf3f619d093f6905ac041aaf0e Mon Sep 17 00:00:00 2001 From: Jordan Wages Date: Tue, 8 Jul 2025 00:24:43 -0500 Subject: [PATCH 099/148] more images --- resources/img/check-16.png | Bin 0 -> 300 bytes resources/img/check-32.png | Bin 0 -> 450 bytes resources/img/check-64.png | Bin 0 -> 927 bytes resources/img/circledots-16.png | Bin 0 -> 394 bytes resources/img/circledots-32.png | Bin 0 -> 773 bytes resources/img/circledots-64.png | Bin 0 -> 1656 bytes resources/img/x-16.png | Bin 0 -> 227 bytes resources/img/x-32.png | Bin 0 -> 331 bytes resources/img/x-64.png | Bin 0 -> 655 bytes resources/svg/check.svg | 3 +++ resources/svg/circledots.svg | 4 ++++ resources/svg/x.svg | 3 +++ 12 files changed, 10 insertions(+) create mode 100644 resources/img/check-16.png create mode 100644 resources/img/check-32.png create mode 100644 resources/img/check-64.png create mode 100644 resources/img/circledots-16.png create mode 100644 resources/img/circledots-32.png create mode 100644 resources/img/circledots-64.png create mode 100644 resources/img/x-16.png create mode 100644 resources/img/x-32.png create mode 100644 resources/img/x-64.png create mode 100644 resources/svg/check.svg create mode 100644 resources/svg/circledots.svg create mode 100644 resources/svg/x.svg diff --git a/resources/img/check-16.png b/resources/img/check-16.png new file mode 100644 index 0000000000000000000000000000000000000000..2a829805b3a1cd134853c1ad26ec809c1048a6c7 GIT binary patch literal 300 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`oCO|{#X#yh2s3WX6WN&PEETXs4%(V~9oX)yuY7PJsff5At0u zbxbhPpS!G3_}zh9u1mz;Y-+f2v#B*Zfa6BDZxB~xW2!=e;`L{m&t86J=l*y|(nd_4)D+W|Fx{` zSH?7sJ;{yN;_}loIxIIa{S>XwkQdRfka^7AZ+Y#Y(A}Ww*4)xF29DDEU&x+)-f&-M s`=&$3Pd0cvRUeerTF&z5UwaF1JXNji0(O88K!ICe<=0Gw@DA{7@F!q1b*>`#DsX4;cVIhnwgUJPaBc7} zV1Md-$?z6%VQ>WwbN8f#w1K3cz*zu4joOnEa&7?wC;T{okAPNDf$$afBjG(eZw0P^ z#c1)Auw`Hzd_)I1@Z7GuKSE$FsL=%2&6tbox?8})H-JYAfBo5IPuB|x7-S2037)WH z_g!5tEMTy1aK;b7y0_~y37Etl@M*v|Z`WrQFo}Kuc6GfJ0h1UQ{L<6)X_r`V^b(N- sxL4JQYhzZPSD@_mfBuRafj=wo4O$HW=K^IzoB#j-07*qoM6N<$g5e&#HUIzs literal 0 HcmV?d00001 diff --git a/resources/img/check-64.png b/resources/img/check-64.png new file mode 100644 index 0000000000000000000000000000000000000000..175c4a276691fe7854413dbf6b0ec13e843c6a3d GIT binary patch literal 927 zcmV;Q17Q4#P)7@5gh`@7;4nRoTpH zvNm9?9Dua}Yvll}4OlA&U~Rx!IRI+|*2)1`8?aUmz}i645|M(442Vd3RUK5dVJ_f0 zpzitsbXMxqFe^YrhJdSU{01%Nr;8v`@Sw9dFkpl1%*jCc?3plK*)8+bS zdIg9`2Qbe1@Csb06dp1RKt$SrXTa`=<`GpLt7;(Yojc}kzXh0Nb;na~?3W&%cFdES`3v{dMmzu}S3IGx50UiM@B~1$y%iT^n9G2c9}F9`4|OmzZF5vKkCCld@`02U+WSptp*TX9vI>ve%k%`F4R z6A0e{eDr6MngBSn!ycnw<2<9JRO=H1 z;7t2U)JI@X4dW#GUY{la0q%N?zXNvG2{P7ueQE%l`DWmuC%{yt0KlN9Z;)D_H~<%7 zEAYw_;;2<0XzIpz`A3WjjScX?k_*7U#x`7w0|5O#Fr@$#y zT}jM93?+Ibrm9oGS&DCT<@5$PV;vp>oC&JxW8fmiB_5?&pjTBFlb$<{f*gvf>OJ5} zMAHIrLSuZu2&SMrEL>yt4RQfEV!i1F-2|f~B8Pwjz;jid3p!a0W#-dZC~fEuBWWlH zU~Rx!IRI+|*2)1`8?aUmz}kSdasbu_thMO@`~w5OS?n{{`V0U7002ovPDHLkV1mW! Bk2wGU literal 0 HcmV?d00001 diff --git a/resources/img/circledots-16.png b/resources/img/circledots-16.png new file mode 100644 index 0000000000000000000000000000000000000000..1443d226c15d61a0f9fa7c9a5e055a1d468258b0 GIT binary patch literal 394 zcmV;50d@X~P);L)DsdN}nXE&|t}_FxN( zl3MDS>i?^{|F04e#ziS*0iFDOj)<4B2P5KVpnU=$~Snxa$TX-VJFXYn@*a9Bhonm!KEi-^~TanH~s zohhoX7|OWaHqw=$NhXpc_z@RsBV}?nNj?m9UaxW+IL*qJ+E#82(=P7vk(yx|;1)Yt o!_;X1D@rNz*)lvu#M`)Y-~5wsLN!KCO#lD@07*qoM6N<$f}a1N?*IS* literal 0 HcmV?d00001 diff --git a/resources/img/circledots-32.png b/resources/img/circledots-32.png new file mode 100644 index 0000000000000000000000000000000000000000..e8dfa44211444bbbf9660f7e39b74fc6ac5ce183 GIT binary patch literal 773 zcmV+g1N!`lP)@(^qejM*MXzJF15ELx*HNDZSw-Cq#^(u0lp|F?|@TDLMrw(;Jvc{3=AhC z08~8iM?fJdxbkCwyFgo!*b<4*nMYx71NF4P0V0!%M8nSsfAcl<<@f#$9oTw%NwjKxS-05Hbv15V;( zj={+jnQL;TI|9H7;&YPf@`1hYRPn8*uN!H#={7!;*4BXu|IAYnP(;eWH1L}Kzh-}d zSHP4mwSL10Kw^>ZX$&|>_s{7j?&tJRDt~DS@?3cCbFv#5B5g)C845R3$b5Hv=w%93n+kgU;zcP|J;jRzwE z)WnMsh2Q~MB^m@oq8Cw&2$2XV@!*4(;r*VO{XA3;+f!X#(=$`uy%WBqveUIyU;V#- zRekkVBEroqEqMdTTXH2pDb=Br8k;MIw7Y;(>ULlrFb9|dbORHC@kY|Kz;WOZa2VJF zd?zBOQ^l7C0ZOU6fu+C_Uk+eYz7_& zS{op_Ezq$!&>2_WRp5ox2>=xEx&z2iP}`Gz^iQMgDZs};8FA&WN{xWP`1c%z{{lSZ z+i(kxhk^YL9P82|;0;Hi@4NbT3M7mI-gLBvm0k%zd-=G&_f%GfTX6L`e9?dx0)SaD zg`5W#=4E^c-y-yIYO9>yh6n)0VIS(Qjs)Wk5^R<9JJ8t(0c&DBeQwR(fweEDE4*D7 z0l;*iU{Sa_Z(|*p-?88=0Qc8Jz}FUK`?B=*br8@F9I)WtUK0VpY>Sc-8I1EDNSGTl zJX*2GDf!Hz;KRI)tAT`#7W{*@w2{@IQmPC1o61#L3794#M`!|3N_7JVsoaPu0{4o@ z@o-w(PE9}2CFx+Z7!M#KhtL}{VQE8;6cu74V2LH}0}r^e78~ZL&4`LF5Nu$cqLP^7 z=%!QjjWA77N{s^k0qzV%mw-D&Zwy*qM9Z^}61yCfo)Z+v-jf?JJzf?iR^IknW% z*Xjh#sqk;;^ZT+Cfw3ZT-9>RQO!Wf`gQ#7=hAP8aYUxAy+JQ?{4uc0pr02$$!PX#A zrl(e8d87uQ$70WxxKRM~%?wj))8l3l8}>ut50e1f)Nz3&u32QEC2mjn!}I~S0sm1+ z%n4wUG}(&Ku^gTtBIn8x6)iwS&Ym4@AnFqPctagx-HD(RED$m}sVrv;Yw~0eophw*aryRS)^da-yw!s~9`N zKNI z+fWB)+ZCPyjyr|b6t1=?6re9}V=Y+wW3ayE%vVKeCwfoNRC*0ql(*3#oQttvkT?u< z)J;I3ycc~V#8iG^B#;mof6;>P3XXdLi3tb_8Hj0K*MOxt8s8sN^8zeOq@#wyR>c$~ z=xeRFW@vaj_Uk+4@M>aRH5RHx6PQTPzB0q9P_@M-9W z6RxYWiEF-Y0s=4tF^;huO2DVU6F^%7MvnrX1h(M5EPW+upZ7vQ0InB(4=)Z>Ih+hy z#WM63RqRYM=-WL(+KoZpYWfe8z}v@#MjuRc0xN)*N&e8Ggx;t)#qhyP2YT&(56K^1 z6o9qB3K2BTEVA*IWp#92BpP18nHrIu| zkhBE-v?gh@Hl+mYMepQn5|NXB5DrTg4=2Z?ucgdEpUrmzccC9nsvw!5A5Q*@c4|j} z?}2Z{*u(RVFKq&xg$K`OMdVU$81f`wB*;zwdi;NiiK$R6J&G>?0000N&PEETsKC?3F~p+x>SS-e1_d6M`xTzT z268>KUoFeKz`$shs_bdLey*pzV_MtuT)nSF%$}Y>GNRsGlY&^!zTsA2GB227^So~k zx9EG3cL!MK7@L`7uo{27upo1%^(Es S(sBuCH-o3EpUXO@geCxx1x&*L literal 0 HcmV?d00001 diff --git a/resources/img/x-32.png b/resources/img/x-32.png new file mode 100644 index 0000000000000000000000000000000000000000..785d7befb5343bc41d835d7516845ad133dbdd3b GIT binary patch literal 331 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?4`^&rfc{H*UVP*AeO zHKHUqKdq!Zu_%?Hyu4g5GcUV1Ik6yBFTW^#_B$IXprRX|E{-7)t#79}ay1(WxZd}8 zKRI{7ju)Y}NlS10nFnheJ(8kyNKyg zV3`*}dV7}cJ}6hQ@qpX`?)5?*jZqJ-GIh$ns|vouBrTM;W7RJEqyEhMvzhePEty}% z^5ss8Wk9!!@t)8}0u|jy5)0n@=&gAFeul7&N0X<@TW*y_sVyP>5y{)F-mk3S_|toU Zn}NyWzp!@RC!il0JYD@<);T3K0RZc!e%}B9 literal 0 HcmV?d00001 diff --git a/resources/img/x-64.png b/resources/img/x-64.png new file mode 100644 index 0000000000000000000000000000000000000000..37dce1ab667d77e328cbca34ef17ff6b429a6c16 GIT binary patch literal 655 zcmV;A0&x9_P)W z^#LFA(79r+0f&~&6j(av#u4)c$=6u=n!gpkq$B7LfhYdbPkttF{K$* + + diff --git a/resources/svg/circledots.svg b/resources/svg/circledots.svg new file mode 100644 index 0000000..6275a98 --- /dev/null +++ b/resources/svg/circledots.svg @@ -0,0 +1,4 @@ + + + + diff --git a/resources/svg/x.svg b/resources/svg/x.svg new file mode 100644 index 0000000..b209221 --- /dev/null +++ b/resources/svg/x.svg @@ -0,0 +1,3 @@ + + + From 9a4b1ce2390974bcebd891131b048a795ed5efb8 Mon Sep 17 00:00:00 2001 From: Jordan Wages Date: Tue, 8 Jul 2025 00:40:40 -0500 Subject: [PATCH 100/148] Update icons and options UI --- AGENTS.md | 7 +++++ README.md | 2 ++ background.js | 61 +++++++++++++++++++++++++++++++++++++++----- manifest.json | 2 +- options/options.html | 50 ++++++++++++++++++++++++++++-------- 5 files changed, 103 insertions(+), 19 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index ab79c66..c51f40c 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -66,3 +66,10 @@ text extracted from all text parts. properties. Any legacy `aiReasonCache` data is merged into `aiCache` the first time the add-on loads after an update. +### Icon Set Usage + +Toolbar and menu icons reside under `resources/img` and are provided in 16, 32 +and 64 pixel variants. When changing these icons, pass a dictionary mapping the +sizes to the paths in `browserAction.setIcon` or `messageDisplayAction.setIcon`. +Use `resources/svg/svg2img.ps1` to regenerate PNGs from the SVG sources. + diff --git a/README.md b/README.md index eff53b1..bdff14a 100644 --- a/README.md +++ b/README.md @@ -141,3 +141,5 @@ Sortana builds upon knowledge gained from open-source projects. In particular, how Thunderbird's WebExtension and experiment APIs can be extended. Their code provided invaluable guidance during development. +- Icons from [cc0-icons.jonh.eu](https://cc0-icons.jonh.eu/) are used under the CC0 license. + diff --git a/background.js b/background.js index 59bac43..2916c06 100644 --- a/background.js +++ b/background.js @@ -28,6 +28,25 @@ let altTextImages = false; let collapseWhitespace = false; let TurndownService = null; +const ICONS = { + logo: "resources/img/logo.png", + circledots: { + 16: "resources/img/circledots-16.png", + 32: "resources/img/circledots-32.png", + 64: "resources/img/circledots-64.png" + }, + circle: { + 16: "resources/img/circle-16.png", + 32: "resources/img/circle-32.png", + 64: "resources/img/circle-64.png" + }, + average: { + 16: "resources/img/average-16.png", + 32: "resources/img/average-32.png", + 64: "resources/img/average-64.png" + } +}; + function setIcon(path) { if (browser.browserAction) { browser.browserAction.setIcon({ path }); @@ -38,9 +57,9 @@ function setIcon(path) { } function updateActionIcon() { - let path = "resources/img/brain.png"; + let path = ICONS.logo; if (processing || queuedCount > 0) { - path = "resources/img/busy.png"; + path = ICONS.circledots; } setIcon(path); } @@ -201,7 +220,7 @@ async function applyAiRules(idsInput) { t.mean += delta / t.count; t.m2 += delta * (elapsed - t.mean); await storage.local.set({ classifyStats: t }); - showTransientIcon("resources/img/done.png"); + showTransientIcon(ICONS.circle); } catch (e) { processing = false; const elapsed = Date.now() - currentStart; @@ -215,7 +234,7 @@ async function applyAiRules(idsInput) { t.m2 += delta * (elapsed - t.mean); await storage.local.set({ classifyStats: t }); logger.aiLog("failed to apply AI rules", { level: 'error' }, e); - showTransientIcon("resources/img/error.png"); + showTransientIcon(ICONS.average); } }); } @@ -250,7 +269,7 @@ async function clearCacheForMessages(idsInput) { } if (keys.length) { await AiClassifier.removeCacheEntries(keys); - showTransientIcon("resources/img/done.png"); + showTransientIcon(ICONS.circle); } } @@ -340,33 +359,61 @@ async function clearCacheForMessages(idsInput) { id: "apply-ai-rules-list", title: "Apply AI Rules", contexts: ["message_list"], + icons: { + 16: "resources/img/eye-16.png", + 32: "resources/img/eye-32.png", + 64: "resources/img/eye-64.png" + } }); browser.menus.create({ id: "apply-ai-rules-display", title: "Apply AI Rules", contexts: ["message_display_action"], + icons: { + 16: "resources/img/eye-16.png", + 32: "resources/img/eye-32.png", + 64: "resources/img/eye-64.png" + } }); browser.menus.create({ id: "clear-ai-cache-list", title: "Clear AI Cache", contexts: ["message_list"], + icons: { + 16: "resources/img/trash-16.png", + 32: "resources/img/trash-32.png", + 64: "resources/img/trash-64.png" + } }); browser.menus.create({ id: "clear-ai-cache-display", title: "Clear AI Cache", contexts: ["message_display_action"], + icons: { + 16: "resources/img/trash-16.png", + 32: "resources/img/trash-32.png", + 64: "resources/img/trash-64.png" + } }); browser.menus.create({ id: "view-ai-reason-list", title: "View Reasoning", contexts: ["message_list"], - icons: { "16": "resources/img/brain.png" } + icons: { + 16: "resources/img/clipboarddata-16.png", + 32: "resources/img/clipboarddata-32.png", + 64: "resources/img/clipboarddata-64.png" + } }); browser.menus.create({ id: "view-ai-reason-display", title: "View Reasoning", contexts: ["message_display_action"], - icons: { "16": "resources/img/brain.png" } + icons: { + 16: "resources/img/clipboarddata-16.png", + 32: "resources/img/clipboarddata-32.png", + 64: "resources/img/clipboarddata-64.png" + } }); browser.menus.onClicked.addListener(async (info, tab) => { diff --git a/manifest.json b/manifest.json index 36b94b0..d44fd1d 100644 --- a/manifest.json +++ b/manifest.json @@ -22,7 +22,7 @@ "default_icon": "resources/img/logo32.png" }, "message_display_action": { - "default_icon": "resources/img/brain.png", + "default_icon": "resources/img/logo.png", "default_title": "Details", "default_label": "Details", "default_popup": "details.html" diff --git a/options/options.html b/options/options.html index 186e2b6..0fc5cae 100644 --- a/options/options.html +++ b/options/options.html @@ -44,18 +44,25 @@
- +
+

+ + Settings +

@@ -88,8 +95,14 @@
- - + +
+ diff --git a/options/options.js b/options/options.js index ebd7497..3a09d37 100644 --- a/options/options.js +++ b/options/options.js @@ -21,7 +21,9 @@ document.addEventListener('DOMContentLoaded', async () => { 'aiCache', 'theme', 'showDebugTab', - 'lastPayload' + 'lastPayload', + 'lastFullText', + 'lastPromptText' ]); const tabButtons = document.querySelectorAll('#main-tabs li'); const tabs = document.querySelectorAll('.tab-content'); @@ -67,9 +69,17 @@ document.addEventListener('DOMContentLoaded', async () => { await applyTheme(themeSelect.value); const payloadDisplay = document.getElementById('payload-display'); + const diffDisplay = document.getElementById('diff-display'); if (defaults.lastPayload) { payloadDisplay.textContent = JSON.stringify(defaults.lastPayload, null, 2); } + if (defaults.lastFullText && defaults.lastPromptText && diff_match_patch) { + const dmp = new diff_match_patch(); + dmp.Diff_EditCost = 4; + const diffs = dmp.diff_main(defaults.lastFullText, defaults.lastPromptText); + dmp.diff_cleanupEfficiency(diffs); + diffDisplay.innerHTML = dmp.diff_prettyHtml(diffs); + } themeSelect.addEventListener('change', async () => { markDirty(); await applyTheme(themeSelect.value); From 841a697c69a9204bcaf7c22c30be8fd5259837f5 Mon Sep 17 00:00:00 2001 From: Jordan Wages Date: Sat, 19 Jul 2025 19:46:44 -0500 Subject: [PATCH 145/148] Update debug tab with live refresh --- README.md | 2 +- options/options.js | 37 +++++++++++++++++++++++++++++++++---- 2 files changed, 34 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 64fbf26..82649d0 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ message meets a specified criterion. - **Advanced parameters** – tune generation settings like temperature, top‑p and more from the options page. - **Markdown conversion** – optionally convert HTML bodies to Markdown before sending them to the AI service. - **Debug logging** – optional colorized logs help troubleshoot interactions with the AI service. -- **Debug tab** – view the last request payload sent to the AI service. +- **Debug tab** – view the last request payload and message diff with live updates. - **Light/Dark themes** – automatically match Thunderbird's appearance with optional manual override. - **Automatic rules** – create rules that tag, move, copy, forward, reply, delete, archive, mark read/unread or flag/unflag messages based on AI classification. Rules can optionally apply only to unread messages and can ignore messages outside a chosen age range. - **Rule ordering** – drag rules to prioritize them and optionally stop processing after a match. diff --git a/options/options.js b/options/options.js index 3a09d37..3402dcf 100644 --- a/options/options.js +++ b/options/options.js @@ -70,13 +70,18 @@ document.addEventListener('DOMContentLoaded', async () => { await applyTheme(themeSelect.value); const payloadDisplay = document.getElementById('payload-display'); const diffDisplay = document.getElementById('diff-display'); - if (defaults.lastPayload) { - payloadDisplay.textContent = JSON.stringify(defaults.lastPayload, null, 2); + + let lastFullText = defaults.lastFullText || ''; + let lastPromptText = defaults.lastPromptText || ''; + let lastPayload = defaults.lastPayload ? JSON.stringify(defaults.lastPayload, null, 2) : ''; + + if (lastPayload) { + payloadDisplay.textContent = lastPayload; } - if (defaults.lastFullText && defaults.lastPromptText && diff_match_patch) { + if (lastFullText && lastPromptText && diff_match_patch) { const dmp = new diff_match_patch(); dmp.Diff_EditCost = 4; - const diffs = dmp.diff_main(defaults.lastFullText, defaults.lastPromptText); + const diffs = dmp.diff_main(lastFullText, lastPromptText); dmp.diff_cleanupEfficiency(diffs); diffDisplay.innerHTML = dmp.diff_prettyHtml(diffs); } @@ -729,6 +734,30 @@ document.addEventListener('DOMContentLoaded', async () => { } catch { cacheCountEl.textContent = '?'; } + + try { + if (debugTabToggle.checked) { + const latest = await storage.local.get(['lastPayload', 'lastFullText', 'lastPromptText']); + const payloadStr = latest.lastPayload ? JSON.stringify(latest.lastPayload, null, 2) : ''; + if (payloadStr !== lastPayload) { + lastPayload = payloadStr; + payloadDisplay.textContent = payloadStr; + } + if (latest.lastFullText !== lastFullText || latest.lastPromptText !== lastPromptText) { + lastFullText = latest.lastFullText || ''; + lastPromptText = latest.lastPromptText || ''; + if (lastFullText && lastPromptText && diff_match_patch) { + const dmp = new diff_match_patch(); + dmp.Diff_EditCost = 4; + const diffs = dmp.diff_main(lastFullText, lastPromptText); + dmp.diff_cleanupEfficiency(diffs); + diffDisplay.innerHTML = dmp.diff_prettyHtml(diffs); + } else { + diffDisplay.innerHTML = ''; + } + } + } + } catch {} } refreshMaintenance(); From bcac4ad01709c85002e2f8123406bacffcf1d4cd Mon Sep 17 00:00:00 2001 From: Jordan Wages Date: Sat, 19 Jul 2025 21:58:37 -0500 Subject: [PATCH 146/148] Improve debug tab layout --- options/options.html | 15 +++++++++------ options/options.js | 22 ++++++++++++++++++++-- 2 files changed, 29 insertions(+), 8 deletions(-) diff --git a/options/options.html b/options/options.html index 3618a20..ddc5ee0 100644 --- a/options/options.html +++ b/options/options.html @@ -154,6 +154,11 @@ Aggressive token reduction
+
+ +
@@ -220,11 +225,6 @@
-
- -
@@ -290,7 +290,10 @@ Debug

-                
+ diff --git a/options/options.js b/options/options.js index 3402dcf..d881d6a 100644 --- a/options/options.js +++ b/options/options.js @@ -70,6 +70,7 @@ document.addEventListener('DOMContentLoaded', async () => { await applyTheme(themeSelect.value); const payloadDisplay = document.getElementById('payload-display'); const diffDisplay = document.getElementById('diff-display'); + const diffContainer = document.getElementById('diff-container'); let lastFullText = defaults.lastFullText || ''; let lastPromptText = defaults.lastPromptText || ''; @@ -83,7 +84,16 @@ document.addEventListener('DOMContentLoaded', async () => { dmp.Diff_EditCost = 4; const diffs = dmp.diff_main(lastFullText, lastPromptText); dmp.diff_cleanupEfficiency(diffs); - diffDisplay.innerHTML = dmp.diff_prettyHtml(diffs); + const hasDiff = diffs.some(d => d[0] !== 0); + if (hasDiff) { + diffDisplay.innerHTML = dmp.diff_prettyHtml(diffs); + diffContainer.classList.remove('is-hidden'); + } else { + diffDisplay.innerHTML = ''; + diffContainer.classList.add('is-hidden'); + } + } else { + diffContainer.classList.add('is-hidden'); } themeSelect.addEventListener('change', async () => { markDirty(); @@ -751,9 +761,17 @@ document.addEventListener('DOMContentLoaded', async () => { dmp.Diff_EditCost = 4; const diffs = dmp.diff_main(lastFullText, lastPromptText); dmp.diff_cleanupEfficiency(diffs); - diffDisplay.innerHTML = dmp.diff_prettyHtml(diffs); + const hasDiff = diffs.some(d => d[0] !== 0); + if (hasDiff) { + diffDisplay.innerHTML = dmp.diff_prettyHtml(diffs); + diffContainer.classList.remove('is-hidden'); + } else { + diffDisplay.innerHTML = ''; + diffContainer.classList.add('is-hidden'); + } } else { diffDisplay.innerHTML = ''; + diffContainer.classList.add('is-hidden'); } } } From 9cad2674e3841fbc40d237f7233fbd6784f61760 Mon Sep 17 00:00:00 2001 From: Jordan Wages Date: Sat, 19 Jul 2025 22:44:04 -0500 Subject: [PATCH 147/148] Capture raw message text for debug --- README.md | 2 +- background.js | 31 ++++++++++++++++++++++++++----- 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 82649d0..57a0285 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ message meets a specified criterion. - **Advanced parameters** – tune generation settings like temperature, top‑p and more from the options page. - **Markdown conversion** – optionally convert HTML bodies to Markdown before sending them to the AI service. - **Debug logging** – optional colorized logs help troubleshoot interactions with the AI service. -- **Debug tab** – view the last request payload and message diff with live updates. +- **Debug tab** – view the last request payload and a diff between the unaltered message text and the final prompt. - **Light/Dark themes** – automatically match Thunderbird's appearance with optional manual override. - **Automatic rules** – create rules that tag, move, copy, forward, reply, delete, archive, mark read/unread or flag/unflag messages based on AI classification. Rules can optionally apply only to unread messages and can ignore messages outside a chosen age range. - **Rule ordering** – drag rules to prioritize them and optionally stop processing after a match. diff --git a/background.js b/background.js index 58a5de5..fc585ff 100644 --- a/background.js +++ b/background.js @@ -210,17 +210,38 @@ function collectText(part, bodyParts, attachments) { } } -function buildEmailText(full) { +function collectRawText(part, bodyParts, attachments) { + if (part.parts && part.parts.length) { + for (const p of part.parts) collectRawText(p, bodyParts, attachments); + return; + } + const ct = (part.contentType || "text/plain").toLowerCase(); + const cd = (part.headers?.["content-disposition"]?.[0] || "").toLowerCase(); + const body = String(part.body || ""); + if (cd.includes("attachment") || !ct.startsWith("text/")) { + const nameMatch = /filename\s*=\s*"?([^";]+)/i.exec(cd) || /name\s*=\s*"?([^";]+)/i.exec(part.headers?.["content-type"]?.[0] || ""); + const name = nameMatch ? nameMatch[1] : ""; + attachments.push(`${name} (${ct}, ${part.size || byteSize(body)} bytes)`); + } else if (ct.startsWith("text/html")) { + const doc = new DOMParser().parseFromString(body, 'text/html'); + bodyParts.push(doc.body.textContent || ""); + } else { + bodyParts.push(body); + } +} + +function buildEmailText(full, applyTransforms = true) { const bodyParts = []; const attachments = []; - collectText(full, bodyParts, attachments); + const collect = applyTransforms ? collectText : collectRawText; + collect(full, bodyParts, attachments); const headers = Object.entries(full.headers || {}) .map(([k, v]) => `${k}: ${v.join(' ')}`) .join('\n'); const attachInfo = `Attachments: ${attachments.length}` + (attachments.length ? "\n" + attachments.map(a => ` - ${a}`).join('\n') : ""); let combined = `${headers}\n${attachInfo}\n\n${bodyParts.join('\n')}`.trim(); - if (tokenReduction) { + if (applyTransforms && tokenReduction) { const seen = new Set(); combined = combined.split('\n').filter(l => { if (seen.has(l)) return false; @@ -228,7 +249,7 @@ function buildEmailText(full) { return true; }).join('\n'); } - return sanitizeString(combined); + return applyTransforms ? sanitizeString(combined) : combined; } function updateTimingStats(elapsed) { @@ -262,8 +283,8 @@ async function processMessage(id) { updateActionIcon(); try { const full = await messenger.messages.getFull(id); + const originalText = buildEmailText(full, false); let text = buildEmailText(full); - const originalText = text; if (tokenReduction && maxTokens > 0) { const limit = Math.floor(maxTokens * 0.9); if (text.length > limit) { From c622c07c66a6936c4c8d3bb039b1f0bba4692384 Mon Sep 17 00:00:00 2001 From: Jordan Wages Date: Mon, 18 Aug 2025 19:39:35 -0500 Subject: [PATCH 148/148] Supporting v140+ After testing in Betterbird v140, updating manifest. --- manifest.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/manifest.json b/manifest.json index a3c9f7c..e7cb9d8 100644 --- a/manifest.json +++ b/manifest.json @@ -1,13 +1,13 @@ { "manifest_version": 2, "name": "Sortana", - "version": "2.1.2", + "version": "2.2.0", "default_locale": "en-US", "applications": { "gecko": { "id": "ai-filter@jordanwages", "strict_min_version": "128.0", - "strict_max_version": "139.*" + "strict_max_version": "140.*" } }, "icons": {