From 97317398ac30d500b624ca262afe5df4fe44cbea Mon Sep 17 00:00:00 2001 From: dgtlmoon Date: Wed, 2 Sep 2026 10:07:34 +0200 Subject: [PATCH] LLM - Per watch/group settings and UI tidyup (#4354) * UI - LLM section tidyup * Rebuild translatiosn * UI - Fixing language for prompt adjustement to be more clear * UI - clarify field action * UI - clarify layout for sections * WIP * test tweaks --- changedetectionio/blueprint/tags/__init__.py | 3 + changedetectionio/blueprint/tags/form.py | 20 +- .../blueprint/tags/templates/edit-tag.html | 6 +- changedetectionio/blueprint/ui/edit.py | 51 +- changedetectionio/forms.py | 7 +- changedetectionio/llm/evaluator.py | 102 ++- changedetectionio/model/Tag.py | 4 + changedetectionio/model/__init__.py | 17 +- .../processors/restock_diff/processor.py | 7 +- changedetectionio/static/js/plugins.js | 19 + .../static/styles/scss/styles.scss | 4 + changedetectionio/static/styles/styles.css | 2 +- .../templates/edit/include_llm_intent.html | 164 ++-- changedetectionio/tests/llm/test_evaluator.py | 145 +++- .../tests/test_llm_change_summary.py | 5 +- .../tests/test_llm_group_overrides.py | 727 ++++++++++++++++-- .../translations/cs/LC_MESSAGES/messages.mo | Bin 55429 -> 55378 bytes .../translations/cs/LC_MESSAGES/messages.po | 47 +- .../translations/de/LC_MESSAGES/messages.po | 43 +- .../en_GB/LC_MESSAGES/messages.po | 43 +- .../en_US/LC_MESSAGES/messages.po | 43 +- .../translations/es/LC_MESSAGES/messages.po | 43 +- .../translations/fr/LC_MESSAGES/messages.po | 43 +- .../translations/it/LC_MESSAGES/messages.po | 43 +- .../translations/ja/LC_MESSAGES/messages.po | 43 +- .../translations/ko/LC_MESSAGES/messages.mo | Bin 102720 -> 102606 bytes .../translations/ko/LC_MESSAGES/messages.po | 49 +- changedetectionio/translations/messages.pot | 45 +- .../translations/pl/LC_MESSAGES/messages.mo | Bin 124360 -> 124235 bytes .../translations/pl/LC_MESSAGES/messages.po | 49 +- .../pt_BR/LC_MESSAGES/messages.po | 43 +- .../translations/ru/LC_MESSAGES/messages.mo | Bin 139687 -> 139534 bytes .../translations/ru/LC_MESSAGES/messages.po | 49 +- .../translations/tr/LC_MESSAGES/messages.po | 43 +- .../translations/uk/LC_MESSAGES/messages.po | 43 +- .../translations/zh/LC_MESSAGES/messages.po | 43 +- .../zh_Hant_TW/LC_MESSAGES/messages.po | 43 +- changedetectionio/worker.py | 11 +- docs/api-spec.yaml | 11 + 39 files changed, 1782 insertions(+), 278 deletions(-) diff --git a/changedetectionio/blueprint/tags/__init__.py b/changedetectionio/blueprint/tags/__init__.py index 8cc689b2a..2fa5bdb0d 100644 --- a/changedetectionio/blueprint/tags/__init__.py +++ b/changedetectionio/blueprint/tags/__init__.py @@ -189,6 +189,9 @@ def construct_blueprint(datastore: ChangeDetectionStore): 'watch': default, 'extra_notification_token_placeholder_info': datastore.get_unique_notification_token_placeholders_available(), 'llm_configured': bool(_get_llm_config(datastore)), + # Tells the shared AI include it is rendering a group, not a watch — `watch` above + # is this tag, so it cannot be used to tell the two apart. + 'llm_group_edit': True, } included_content = {} diff --git a/changedetectionio/blueprint/tags/form.py b/changedetectionio/blueprint/tags/form.py index ecfcbc8ea..483146fb6 100644 --- a/changedetectionio/blueprint/tags/form.py +++ b/changedetectionio/blueprint/tags/form.py @@ -10,6 +10,7 @@ from wtforms.fields.simple import BooleanField from flask_babel import lazy_gettext as _l from changedetectionio.blueprint.tags.colour import CSS_HEX_COLOUR_REGEX +from changedetectionio.widgets.ternary_boolean import TernaryNoneBooleanField from changedetectionio.processors.restock_diff.forms import processor_settings_form as restock_settings_form from changedetectionio.llm.ui_strings import LLM_INTENT_TAG_PLACEHOLDER from changedetectionio.llm.evaluator import ( @@ -28,7 +29,22 @@ class group_restock_settings_form(restock_settings_form): validators=[validators.Optional(), validators.Regexp(CSS_HEX_COLOUR_REGEX, message=_l('Must be a hex colour, for example #4f8ef7'))]) - llm_intent = TextAreaField('AI Change Intent', + # The group's one and only AI control. Same key as the per-watch switch (see forms.py) but + # ternary, because a group has a third useful answer: "no opinion, leave it to each watch" + # (the default). See tag_llm_decision() for the semantics of each state — #4204. + # @NOTE! In the near future this stops being a ternary bool and becomes a *profile* + # selector — pick one of the configured LLM profiles, or 'off', or inherit. The + # field name is already the future one; only the widget and the True/False/None + # value space need to change, so keep reads going through tag_llm_decision(). + llm_backend_profile = TernaryNoneBooleanField( + _l('AI for watches in this group'), + default=None, + yes_text=_l('On, use the settings below'), + no_text=_l('Off for every watch'), + none_text=_l('Leave it to each watch'), + ) + + llm_intent = TextAreaField('AI Change Intent - Notify me when..', validators=[validators.Optional(), validators.Length(max=2000)], render_kw={"rows": "5", "placeholder": LLM_INTENT_TAG_PLACEHOLDER}) @@ -38,7 +54,7 @@ class group_restock_settings_form(restock_settings_form): default='') llm_change_summary_mode = RadioField( - _l('How this prompt combines with the inherited one'), + _l('Change Summary prompt - Append or Replace the default?'), choices=[ (LLM_PROMPT_MODE_REPLACE, _l('Replace the inherited prompt')), (LLM_PROMPT_MODE_APPEND, _l('Append to the inherited prompt')), diff --git a/changedetectionio/blueprint/tags/templates/edit-tag.html b/changedetectionio/blueprint/tags/templates/edit-tag.html index 64d4e569e..82e8aca8d 100644 --- a/changedetectionio/blueprint/tags/templates/edit-tag.html +++ b/changedetectionio/blueprint/tags/templates/edit-tag.html @@ -27,9 +27,9 @@
- {% if llm_configured %}
{% include "edit/include_llm_intent.html" %}
- {% endif %}
{# TRANSLATORS: CJK fonts lack native italics; allow substitution with conventional local styling. dennis-ignore: W303 #} diff --git a/changedetectionio/blueprint/ui/edit.py b/changedetectionio/blueprint/ui/edit.py index 9ba78ed87..27f4ec71c 100644 --- a/changedetectionio/blueprint/ui/edit.py +++ b/changedetectionio/blueprint/ui/edit.py @@ -15,23 +15,50 @@ from changedetectionio.llm.evaluator import get_llm_config as _get_llm_config def construct_blueprint(datastore: ChangeDetectionStore, update_q, queuedWatchMetaData): edit_blueprint = Blueprint('ui_edit', __name__, template_folder="../ui/templates") + def _watch_tags(watch): + """(uuid, tag) for this watch's tags, in its own tag order, skipping UUIDs we don't know.""" + tags = datastore.data['settings']['application'].get('tags', {}) + return [(tag_uuid, tags[tag_uuid]) for tag_uuid in watch.get('tags', []) if tag_uuid in tags] + def _resolve_llm_group_overrides(watch, datastore) -> dict: """ For each LLM field (llm_intent, llm_change_summary): if the watch has no own - value but a linked tag does, return {'value': ..., 'group_name': ...} so the - edit template can render the textarea as readonly with a group-sourced placeholder. - Returns None for each field when the watch has its own value (editable). + value but a linked group does, return {'value': ..., 'group_name': ..., 'group_uuid': ...} + so the edit template can show the inherited value as the textarea placeholder and link + back to the group that supplied it. + Returns None for each field when the watch has its own value (nothing inherited). + + Only groups whose AI setting is "On" lend their prompts — the same gate the evaluator + applies via resolve_llm_field(), so the placeholder always reflects what will actually + run. See llm/evaluator.py:tag_llm_decision(). """ - result = {'llm_intent': None, 'llm_change_summary': None} + from changedetectionio.llm.evaluator import tag_llm_applies_to_watches, tag_llm_decision + + result = {'llm_intent': None, 'llm_change_summary': None, 'llm_backend_profile': None} + + # AI on/off is not a "fill in the blank" field: a group that has taken the decision + # (On or Off, i.e. not "leave it to each watch") decides for every watch in it (#4204), + # so report it and let the template show the watch's own checkbox as overridden. + for tag_uuid, tag in _watch_tags(watch): + if tag_llm_decision(tag) is not None: + result['llm_backend_profile'] = { + 'value': tag_llm_decision(tag), + 'group_name': tag.get('title', 'tag'), + 'group_uuid': tag_uuid, + } + break + for field in ('llm_intent', 'llm_change_summary'): if (watch.get(field) or '').strip(): continue # watch has its own value — editable, no group override - for tag_uuid in watch.get('tags', []): - tag = datastore.data['settings']['application'].get('tags', {}).get(tag_uuid) - if tag and (tag.get(field) or '').strip(): + for tag_uuid, tag in _watch_tags(watch): + if not tag_llm_applies_to_watches(tag): + continue + if (tag.get(field) or '').strip(): result[field] = { 'value': tag.get(field).strip(), 'group_name': tag.get('title', 'tag'), + 'group_uuid': tag_uuid, } break return result @@ -211,6 +238,16 @@ def construct_blueprint(datastore: ChangeDetectionStore, update_q, queuedWatchMe extra_update_obj['filter_text_replaced'] = True extra_update_obj['filter_text_removed'] = True + # A group that has taken the AI on/off decision owns that control, so the edit page + # renders it disabled (see include_llm_intent.html). A disabled checkbox isn't + # submitted at all, and for a checkbox "not submitted" is indistinguishable from + # "unticked" — so don't take this field from the form while a group decides. The + # watch keeps its own preference untouched, ready for when the group stops deciding. + # Resolved against the watch's *stored* tags — i.e. what the page was rendered from, + # so attaching or detaching a group in this same save is still honoured correctly. + if _resolve_llm_group_overrides(datastore.data['watching'][uuid], datastore).get('llm_backend_profile'): + extra_update_obj['llm_backend_profile'] = datastore.data['watching'][uuid].get('llm_backend_profile', True) + # Because wtforms doesn't support accessing other data in process_ , but we convert the CSV list of tags back to a list of UUIDs tag_uuids = [] if form.data.get('tags'): diff --git a/changedetectionio/forms.py b/changedetectionio/forms.py index facb8de4b..6a7364da9 100644 --- a/changedetectionio/forms.py +++ b/changedetectionio/forms.py @@ -953,7 +953,7 @@ class processor_text_json_diff_form(commonSettingsForm): time_between_check_use_default = BooleanField(_l('Use global settings for time between check and scheduler.'), default=False) - llm_intent = TextAreaField(_l('AI Change Intent'), validators=[validators.Optional(), validators.Length(max=2000)], + llm_intent = TextAreaField(_l('AI Change Intent - Notify me when..'), validators=[validators.Optional(), validators.Length(max=2000)], render_kw={"rows": "5", "placeholder": LLM_INTENT_WATCH_PLACEHOLDER}) llm_change_summary = TextAreaField(_l('AI Change Summary'), validators=[validators.Optional(), validators.Length(max=2000)], @@ -961,13 +961,16 @@ class processor_text_json_diff_form(commonSettingsForm): default='') llm_change_summary_mode = RadioField( - _l('How this prompt combines with the inherited one'), + _l('Change Summary prompt - Append or Replace the default?'), choices=[ (LLM_PROMPT_MODE_REPLACE, _l('Replace the inherited prompt')), (LLM_PROMPT_MODE_APPEND, _l('Append to the inherited prompt')), ], default=LLM_PROMPT_MODE_REPLACE, ) + # @NOTE! In the near future you should be able to select which LLM profile *OR* "off"/None for this watch/group + # For now we use the 'future' field naming but keep the functionality simple. + llm_backend_profile = BooleanField(_l('AI enabled for this watch?'), default=True) include_filters = StringListField(_l('CSS/JSONPath/JQ/XPath Filters'), [ValidateCSSJSONXPATHInput()], default='') diff --git a/changedetectionio/llm/evaluator.py b/changedetectionio/llm/evaluator.py index 210db66ea..fefb5c2a4 100644 --- a/changedetectionio/llm/evaluator.py +++ b/changedetectionio/llm/evaluator.py @@ -5,7 +5,8 @@ Two public entry points: - run_setup(watch, datastore) — one-time: decide if pre-filter needed - evaluate_change(watch, datastore, diff, current_snapshot) — per-change evaluation -Intent resolution: watch.llm_intent → first tag with llm_intent → None (no evaluation) +Intent resolution: watch.llm_intent → first tag with llm_intent whose AI switch is "on" + (see tag_llm_applies_to_watches) → None (no evaluation) Cache: each (intent, diff) pair is evaluated exactly once, result stored in watch. Environment variable overrides (take priority over datastore settings): @@ -244,6 +245,70 @@ def resolve_llm_timeout(llm_cfg: dict) -> int: # Intent resolution # --------------------------------------------------------------------------- +# A group/tag has exactly one AI control (`llm_backend_profile`), and it is ternary: +# +# True — AI on for every watch in the group, using the group's AI settings +# (llm_intent / llm_change_summary cascade down to the watches) +# False — AI off for every watch in the group; its prompts are stored but never used +# None — the group has no opinion: each watch's own AI switch and prompts apply +# +# On a *watch* the same key is a plain bool (on/off, default on). One control per level, so +# there is nothing to reconcile between an "override?" flag and an "enabled?" flag. +def tag_llm_decision(tag): + """This group's AI decision: True (on, use its settings), False (off), or None (no opinion).""" + if not tag: + return None + value = tag.get('llm_backend_profile') + return None if value is None else bool(value) + + +def tag_llm_applies_to_watches(tag) -> bool: + """True when this group hands its AI settings down to its watches. + + Only the "on" state does that: a group set to "off" suppresses AI for its watches rather + than lending them prompts, and a group with no opinion leaves them alone entirely. This is + the single gate behind both the evaluator cascade and the watch edit page's + "From group ..." placeholder. + """ + return tag_llm_decision(tag) is True + + +def _watch_tags(watch, datastore): + """Yield this watch's tag dicts, in the watch's own tag order, skipping unknown UUIDs.""" + for tag_uuid in watch.get('tags', []): + tag = datastore.data['settings']['application'].get('tags', {}).get(tag_uuid) + if tag: + yield tag + + +def _tags_applying_llm(watch, datastore): + """Yield this watch's groups, in order, that hand their AI settings to their watches.""" + for tag in _watch_tags(watch, datastore): + if tag_llm_applies_to_watches(tag): + yield tag + + +def llm_enabled_for_watch(watch, datastore) -> tuple[bool, str]: + """Is automatic AI evaluation switched on for this watch? Returns (enabled, source). + + See #4204 — users with hundreds of watches want AI on only a select few. + + A group with an opinion decides for all of its watches ("the group setting overrides any + watch on/off"), so the first such group wins over the watch's own switch; groups set to + "leave it to each watch" are skipped. With no group deciding, the watch decides — and a + missing key means on, so watches predating this switch keep working. + + Only gates *automatic* spend (the worker's intent/summary passes and the restock AI + plugin). Explicit user actions — the diff page "Summary" button, the intent preview — + stay available, since those cost tokens only when someone deliberately clicks. + """ + for tag in _watch_tags(watch, datastore): + decision = tag_llm_decision(tag) + if decision is not None: + return decision, tag.get('title', 'tag') + return bool(watch.get('llm_backend_profile', True)), 'watch' + + def resolve_llm_field(watch, datastore, field: str) -> tuple[str, str]: """ Generic cascade resolver for any LLM per-watch field. @@ -254,12 +319,10 @@ def resolve_llm_field(watch, datastore, field: str) -> tuple[str, str]: if value: return value, 'watch' - for tag_uuid in watch.get('tags', []): - tag = datastore.data['settings']['application'].get('tags', {}).get(tag_uuid) - if tag: - tag_value = (tag.get(field) or '').strip() - if tag_value: - return tag_value, tag.get('title', 'tag') + for tag in _tags_applying_llm(watch, datastore): + tag_value = (tag.get(field) or '').strip() + if tag_value: + return tag_value, tag.get('title', 'tag') return '', '' @@ -273,12 +336,10 @@ def resolve_intent(watch, datastore) -> tuple[str, str]: if intent: return intent, 'watch' - for tag_uuid in watch.get('tags', []): - tag = datastore.data['settings']['application'].get('tags', {}).get(tag_uuid) - if tag: - tag_intent = (tag.get('llm_intent') or '').strip() - if tag_intent: - return tag_intent, tag.get('title', 'tag') + for tag in _tags_applying_llm(watch, datastore): + tag_intent = (tag.get('llm_intent') or '').strip() + if tag_intent: + return tag_intent, tag.get('title', 'tag') return '', '' @@ -549,15 +610,14 @@ def run_setup(watch, datastore, snapshot_text: str) -> None: def _first_tag_with_field(watch, datastore, field: str): """Return (value, tag) for the first linked tag with a non-empty `field`, else ('', None). - Same first-match-wins order as resolve_llm_field(); this variant also hands back the - tag itself so the caller can read sibling keys such as the prompt mode. + Same first-match-wins order as resolve_llm_field() (so only groups opted in via + tag_llm_applies_to_watches() count); this variant also hands back the tag itself so + the caller can read sibling keys such as the prompt mode. """ - for tag_uuid in watch.get('tags', []): - tag = datastore.data['settings']['application'].get('tags', {}).get(tag_uuid) - if tag: - value = (tag.get(field) or '').strip() - if value: - return value, tag + for tag in _tags_applying_llm(watch, datastore): + value = (tag.get(field) or '').strip() + if value: + return value, tag return '', None diff --git a/changedetectionio/model/Tag.py b/changedetectionio/model/Tag.py index 58154425d..81208c25b 100644 --- a/changedetectionio/model/Tag.py +++ b/changedetectionio/model/Tag.py @@ -46,6 +46,10 @@ class model(EntityPersistenceMixin, watch_base): super(model, self).__init__(*arg, **kw) self['overrides_watch'] = kw.get('default', {}).get('overrides_watch') + # Ternary on a tag, unlike the plain bool on a watch: None ("leave it to each watch") + # is the default, so a group never touches its watches' AI until explicitly set. + # See llm/evaluator.py:tag_llm_decision(). + self['llm_backend_profile'] = kw.get('default', {}).get('llm_backend_profile', None) self['url_match_pattern'] = kw.get('default', {}).get('url_match_pattern', '') if kw.get('default'): diff --git a/changedetectionio/model/__init__.py b/changedetectionio/model/__init__.py index 0fde60429..2d6684656 100644 --- a/changedetectionio/model/__init__.py +++ b/changedetectionio/model/__init__.py @@ -184,16 +184,11 @@ class watch_base(dict): 'check_count': 0, 'check_unique_lines': False, # On change-detected, compare against all history if its something new 'consecutive_filter_failures': 0, # Every time the CSS/xPath filter cannot be located, reset when all is fine. + # LLM intent-based evaluation 'content-type': None, 'date_created': None, 'extract_lines_containing': [], # Keep only lines containing these substrings (plain text, case-insensitive) 'extract_text': [], # Extract text by regex after filters - # LLM intent-based evaluation - 'llm_intent': '', # Plain-English description of what the user cares about (change filter) - 'llm_change_summary': '', # Prompt for AI Change Summary — replaces {{ diff }} in notifications - 'llm_change_summary_mode': 'replace', # 'replace' the inherited prompt, or 'append' to it - 'llm_prefilter': None, # CSS selector derived at setup time (semantic only, e.g. "footer") - 'llm_evaluation_cache': {}, # {sha256(intent+diff): {important, summary}} - evaluated once, cached 'fetch_backend': 'system', # plaintext, playwright etc 'fetch_time': 0.0, 'filter_failure_notification_send': strtobool(os.getenv('FILTER_FAILURE_NOTIFICATION_SEND_DEFAULT', 'True')), @@ -202,16 +197,22 @@ class watch_base(dict): 'filter_text_replaced': True, 'follow_price_changes': True, 'has_ldjson_price_data': None, - 'history_snapshot_max_length': None, 'headers': {}, # Extra headers to send - 'ignore_text': [], # List of text to ignore when calculating the comparison checksum + 'history_snapshot_max_length': None, 'ignore_status_codes': None, + 'ignore_text': [], # List of text to ignore when calculating the comparison checksum 'in_stock_only': True, # Only trigger change on going to instock from out-of-stock 'include_filters': [], 'last_checked': 0, 'last_error': False, 'last_notification_error': None, 'last_viewed': 0, # history key value of the last viewed via the [diff] link + 'llm_backend_profile': True, # @note - now its just a bool but in the near future we can select a LLM profile or 'off'/false + 'llm_change_summary': '', # Prompt for AI Change Summary — replaces {{ diff }} in notifications + 'llm_change_summary_mode': 'replace', # 'replace' the inherited prompt, or 'append' to it + 'llm_evaluation_cache': {}, # {sha256(intent+diff): {important, summary}} - evaluated once, cached + 'llm_intent': '', # Plain-English description of what the user cares about (change filter) + 'llm_prefilter': None, # CSS selector derived at setup time (semantic only, e.g. "footer") 'method': 'GET', 'notification_alert_count': 0, 'notification_body': None, diff --git a/changedetectionio/processors/restock_diff/processor.py b/changedetectionio/processors/restock_diff/processor.py index e428e336b..5299511fe 100644 --- a/changedetectionio/processors/restock_diff/processor.py +++ b/changedetectionio/processors/restock_diff/processor.py @@ -506,8 +506,11 @@ class perform_site_check(difference_detection_processor): # Try plugin override - plugins can decide if they support this fetcher if fetcher_name: logger.debug(f"Calling extra plugins for getting item price/availability (fetcher: {fetcher_name})") - from changedetectionio.llm.evaluator import resolve_intent - _llm_intent, _ = resolve_intent(watch, self.datastore) + from changedetectionio.llm.evaluator import llm_enabled_for_watch, resolve_intent + # AI off for this watch (or for its group) means no intent is handed to the + # LLM restock plugin, so it doesn't spend tokens here either — #4204. + _llm_on, _ = llm_enabled_for_watch(watch, self.datastore) + _llm_intent, _ = resolve_intent(watch, self.datastore) if _llm_on else ('', '') plugin_availability = get_itemprop_availability_from_plugin(self.fetcher.content, fetcher_name, self.fetcher, watch.link, llm_intent=_llm_intent or None) if plugin_availability: diff --git a/changedetectionio/static/js/plugins.js b/changedetectionio/static/js/plugins.js index 5191c1189..d0d99a284 100644 --- a/changedetectionio/static/js/plugins.js +++ b/changedetectionio/static/js/plugins.js @@ -179,6 +179,25 @@ function toggleOpacity(checkboxSelector, fieldSelector, inverted) { checkbox.addEventListener('change', updateOpacity); } +// Radio-group counterpart of toggleOpacity: fields are full opacity only while the named +// radio group sits on activeValue, otherwise greyed out. Used by the tag AI/LLM tab, where a +// ternary (On / Off / Leave it to each watch) decides whether the prompts below apply. +function toggleOpacityByRadioValue(radioName, activeValue, fieldSelector) { + const radios = document.querySelectorAll(`input[type="radio"][name="${radioName}"]`); + const fields = document.querySelectorAll(fieldSelector); + + function updateOpacity() { + const active = Array.from(radios).some(radio => radio.checked && radio.value === activeValue); + fields.forEach(field => { + field.style.opacity = active ? 1 : 0.6; + }); + } + + // Initial setup + updateOpacity(); + radios.forEach(radio => radio.addEventListener('change', updateOpacity)); +} + function toggleVisibility(checkboxSelector, fieldSelector, inverted) { const checkbox = document.querySelector(checkboxSelector); const fields = document.querySelectorAll(fieldSelector); diff --git a/changedetectionio/static/styles/scss/styles.scss b/changedetectionio/static/styles/scss/styles.scss index b1d1d1b55..f0e3baff1 100644 --- a/changedetectionio/static/styles/scss/styles.scss +++ b/changedetectionio/static/styles/scss/styles.scss @@ -1152,4 +1152,8 @@ header { cursor: pointer; width: 1.4rem; /*it's slightly more wider than square so default auto will trim it slightly */ } +} + +textarea::placeholder { + white-space: pre-wrap; } \ No newline at end of file diff --git a/changedetectionio/static/styles/styles.css b/changedetectionio/static/styles/styles.css index 92ab9546b..7dec70064 100644 --- a/changedetectionio/static/styles/styles.css +++ b/changedetectionio/static/styles/styles.css @@ -1 +1 @@ -.header{color:var(--color-text-menu-heading)}.header a{color:var(--color-text-menu-heading)}.header::after{content:"";position:absolute;left:0;right:0;bottom:0;height:1px;pointer-events:none;background:linear-gradient(to right, rgba(200, 200, 200, 0.02), rgba(200, 200, 200, 0.6))}ul#top-right-menu{list-style:none;margin-left:auto;padding:0;margin-top:0;margin-right:0;margin-bottom:0;display:grid;gap:1.1rem;grid-auto-flow:column;grid-auto-columns:max-content;align-items:center}ul#top-right-menu .toggle-button{padding:0}.current-diff-url{flex:1 1 auto;min-width:0;overflow:hidden;white-space:nowrap;text-align:left;margin:0 .55rem;-webkit-mask-image:linear-gradient(to right, #000 calc(100% - 2.5em), transparent);mask-image:linear-gradient(to right, #000 calc(100% - 2.5em), transparent)}.current-diff-url span{overflow:visible;white-space:nowrap}.pure-menu-horizontal{padding:.55rem;display:flex;justify-content:space-between;align-items:center}.pure-menu-horizontal svg{height:1.3rem}.fi{height:1.3rem;cursor:pointer}#pure-menu-horizontal-spinner{height:2px;background:linear-gradient(-75deg, #ff6000, #ff8f00, #ffdd00, #ed0000);background-size:400% 400%;animation:gradient 200s ease infinite;opacity:.8;position:fixed;bottom:0;left:0;width:100%;z-index:100;pointer-events:none}.status-pill{display:inline-flex;align-items:center;gap:8px;height:30px;padding:0 12px;border-radius:var(--common-round-border);border:1px solid hsla(0,0%,100%,.25);background:hsla(0,0%,100%,.1);color:var(--color-text-menu-heading);font-size:.78rem;font-weight:600;white-space:nowrap;text-decoration:none}.status-pill:hover{background:hsla(0,0%,100%,.18)}.status-pill .live-dot{width:8px;height:8px;border-radius:50%;background:#42dd53;box-shadow:0 0 0 3px rgba(66,221,83,.3);animation:status-pill-pulse 2s infinite}.status-pill.paused .live-dot{background:#e8a33d;box-shadow:0 0 0 3px rgba(232,163,61,.3);animation:none}.status-pill .action-icon{width:16px;height:16px}.status-pill.muted{opacity:.8}.status-pill.muted .action-icon{color:#e8a33d}@keyframes status-pill-pulse{0%,100%{opacity:1}50%{opacity:.4}}.menu-pop-wrap{position:relative}.icon-btn{display:inline-flex;align-items:center;justify-content:center;width:36px;height:36px;border:0;border-radius:var(--common-round-border);background:rgba(0,0,0,0);color:var(--color-text-menu-heading);cursor:pointer}.icon-btn svg{width:18px;height:18px;fill:none;stroke:currentColor}.icon-btn:hover{background:hsla(0,0%,100%,.14)}.menu-pop{display:none;position:absolute;top:calc(100% + 8px);right:0;min-width:220px;padding:6px;border:1px solid var(--color-border-table-cell);border-radius:12px;background:var(--color-background);box-shadow:0 18px 50px rgba(0,0,0,.18);z-index:80}.menu-pop.open{display:block}.menu-pop .mi{display:flex;align-items:center;gap:10px;width:100%;padding:9px 10px;border:0;border-radius:8px;background:rgba(0,0,0,0);color:var(--color-text);font-size:.85rem;text-align:left;text-decoration:none;white-space:nowrap;cursor:pointer}.menu-pop .mi:hover{background:var(--color-background-menu-link-hover)}.menu-pop .mi .ico{display:inline-flex;color:var(--color-text-input-description)}.menu-pop .mi .ico svg{width:16px;height:16px;fill:none;stroke:currentColor}.menu-pop .mi .right{margin-left:auto;font-size:.75rem;color:var(--color-text-input-description)}.top-menu-list .action-label{color:var(--color-text-menu-heading)}@media only screen and (max-width: 768px){.top-menu-list .action-label{display:none}}#inline-menu-extras-group{list-style:none;margin:0;padding:0;display:grid;gap:.55rem;grid-auto-flow:column;grid-auto-columns:max-content;align-items:center}@media only screen and (max-width: 980px){#nav-menu #menu-settings span{display:none}}:root{--body-main-text-size: 0.9rem;--color-white: #fff;--color-grey-50: #111;--color-grey-100: #262626;--color-grey-200: #333;--color-grey-300: #444;--color-grey-325: #555;--color-grey-350: #565d64;--color-grey-400: #666;--color-grey-500: #777;--color-grey-600: #999;--color-grey-700: #cbcbcb;--color-grey-750: #ddd;--color-grey-800: #e0e0e0;--color-grey-850: #eee;--color-grey-900: #f2f2f2;--color-black: #000;--color-dark-red: #a00;--color-light-red: #dd0000;--color-background-page: var(--color-grey-100);--color-background-gradient-first: #5ad8f7;--color-background-gradient-second: #2f50af;--color-background-gradient-third: #9150bf;--color-background: var(--color-white);--color-text: var(--color-grey-200);--color-link: #1b98f8;--color-menu-accent: #ed5900;--color-background-code: var(--color-grey-850);--color-error: var(--color-dark-red);--color-error-input: #ffebeb;--color-error-list: var(--color-light-red);--color-table-background: var(--color-background);--color-table-stripe: var(--color-grey-900);--watchlist-row-selected: #e3f0ff;--watchlist-row-hover: #f2f2f2;--color-text-tab: var(--color-white);--color-background-tab: rgba(255, 255, 255, 0.2);--color-background-tab-hover: rgba(255, 255, 255, 0.5);--color-text-tab-active: #222;--color-api-key: #0078e7;--color-background-button-primary: #0078e7;--color-background-button-green: #42dd53;--color-background-button-red: #dd4242;--color-background-button-success: rgb(28, 184, 65);--color-background-button-error: rgb(202, 60, 60);--color-text-button-error: var(--color-white);--color-background-button-warning: rgb(202, 60, 60);--color-text-button-warning: var(--color-white);--color-background-button-secondary: rgb(66, 184, 221);--color-background-button-cancel: rgb(200, 200, 200);--color-text-button: var(--color-white);--color-background-button-tag: rgb(99, 99, 99);--color-background-snapshot-age: #dfdfdf;--color-error-text-snapshot-age: var(--color-white);--color-error-background-snapshot-age: #ff0000;--color-background-button-tag-active: #9c9c9c;--color-text-messages: var(--color-white);--color-background-messages-message: rgba(255, 255, 255, .2);--color-background-messages-error: rgba(255, 1, 1, .5);--color-background-messages-notice: rgba(255, 255, 255, .5);--color-border-notification: #ccc;--color-background-checkbox-operations: rgba(0, 0, 0, 0.05);--color-warning: #ff3300;--color-border-warning: var(--color-warning);--color-text-legend: var(--color-white);--color-link-new-version: #e07171;--color-last-checked: #bbb;--color-text-footer: #444;--color-border-watch-table-cell: #eee;--color-text-watch-tag-list: rgba(231, 0, 105, 0.4);--color-background-new-watch-form: rgba(0, 0, 0, 0.05);--color-background-new-watch-input: var(--color-white);--color-background-new-watch-input-transparent: rgba(255, 255, 255, 0.1);--color-text-new-watch-input: var(--color-text);--color-border-input: var(--color-grey-500);--color-shadow-input: var(--color-grey-400);--color-background-input: var(--color-white);--color-text-input: var(--color-text);--color-text-input-description: var(--color-grey-500);--color-text-input-placeholder: var(--color-grey-600);--color-background-table-thead: var(--color-grey-800);--color-border-table-cell: var(--color-grey-700);--color-text-menu-heading: var(--color-white);--color-text-menu-link: var(--color-grey-500);--color-background-menu-link-hover: var(--color-grey-850);--color-text-menu-link-hover: var(--color-grey-300);--color-shadow-jump: var(--color-grey-500);--color-icon-github: var(--color-black);--color-watch-table-error: var(--color-dark-red);--color-watch-table-row-text: var(--color-grey-100);--color-table-line: #e7e9ee;--highlight-trigger-text-bg-color: #1b98f8;--highlight-ignored-text-bg-color: var(--color-grey-700);--highlight-blocked-text-bg-color: rgb(202, 60, 60);--color-sidebar-bg: rgba(255, 255, 255, 0.97);--color-sidebar-text: var(--color-text);--color-sidebar-shadow: 6px 0 28px rgba(0, 0, 0, 0.18);--color-sidebar-item-hover-bg: rgba(0, 0, 0, 0.06);--color-sidebar-item-active-bg: rgba(0, 0, 0, 0.10);--common-round-border: 8px}html[data-darkmode=true]{--color-link: #59bdfb;--color-text: var(--color-white);--color-table-line: #262c37;--color-background-gradient-first: #3f90a5;--color-background-gradient-second: #1e316c;--color-background-gradient-third: #4d2c64;--color-background-new-watch-input: var(--color-grey-100);--color-background-new-watch-input-transparent: var(--color-grey-100);--color-text-new-watch-input: var(--color-text);--color-background-table-thead: var(--color-grey-200);--color-table-background: var(--color-grey-300);--color-table-stripe: var(--color-grey-325);--watchlist-row-selected: #1e3a5f;--watchlist-row-hover: #2a2a2a;--color-background: var(--color-grey-300);--color-text-menu-heading: var(--color-grey-850);--color-text-menu-link: var(--color-grey-800);--color-border-table-cell: var(--color-grey-400);--color-text-tab-active: var(--color-text);--color-border-input: var(--color-grey-400);--color-shadow-input: var(--color-grey-50);--color-background-input: var(--color-grey-350);--color-text-input-description: var(--color-grey-600);--color-text-input-placeholder: var(--color-grey-600);--color-text-watch-tag-list: rgba(250, 62, 146, 0.4);--color-background-code: var(--color-grey-200);--color-background-tab: rgba(0, 0, 0, 0.2);--color-background-tab-hover: rgba(0, 0, 0, 0.5);--color-background-snapshot-age: var(--color-grey-200);--color-shadow-jump: var(--color-grey-200);--color-icon-github: var(--color-white);--color-watch-table-error: var(--color-light-red);--color-watch-table-row-text: var(--color-grey-800);--color-sidebar-bg: rgba(8, 10, 14, 0.97);--color-sidebar-text: var(--color-white);--color-sidebar-shadow: 6px 0 28px rgba(0, 0, 0, 0.45);--color-sidebar-item-hover-bg: rgba(255, 255, 255, 0.06);--color-sidebar-item-active-bg: rgba(255, 255, 255, 0.10)}html[data-darkmode=true] .icon-spread{filter:hue-rotate(-10deg) brightness(1.5)}html[data-darkmode=true] .watch-table .title-col a[target=_blank]::after,html[data-darkmode=true] .watch-table .current-diff-url::after{filter:invert(0.5) hue-rotate(10deg) brightness(2)}html[data-darkmode=true] .watch-table .status-browsersteps{filter:invert(0.5) hue-rotate(10deg) brightness(1.5)}html[data-darkmode=true] .watch-table .watch-controls .state-off svg{opacity:.3}html[data-darkmode=true] .watch-table .watch-controls .state-on svg{opacity:1}html[data-darkmode=true] .watch-table .unviewed{color:#fff}html[data-darkmode=true] .watch-table .unviewed.error{color:var(--color-watch-table-error)}.arrow{border:solid var(--color-border-input);border-width:0 2px 2px 0;display:inline-block;padding:3px}.arrow.right{transform:rotate(-45deg);-webkit-transform:rotate(-45deg)}.arrow.left{transform:rotate(135deg);-webkit-transform:rotate(135deg)}.arrow.up,.arrow.asc{transform:rotate(-135deg);-webkit-transform:rotate(-135deg)}.arrow.down,.arrow.desc{transform:rotate(45deg);-webkit-transform:rotate(45deg)}#browser_steps th{display:none}#browser_steps li{list-style:decimal;padding:5px}#browser_steps li.browser-step-with-error{background-color:#ffd6d6;border-radius:4px}#browser_steps li:not(:first-child):hover{opacity:1}#browser_steps li .control{padding-left:5px;padding-right:5px}#browser_steps li .control a{font-size:70%}#browser_steps li.empty{padding:0px;opacity:.35}#browser_steps li.empty .control{display:none}#browser_steps li:hover{background:#eee}#browser_steps li>label{display:none}@media only screen and (min-width: 760px){#browser-steps .flex-wrapper{display:flex;flex-flow:row;height:70vh;font-size:80%}#browser-steps .flex-wrapper #browser-steps-ui{flex-grow:1;flex-shrink:1;flex-basis:0;background-color:#eee;border-radius:5px}#browser-steps-fieldlist{flex-grow:0;flex-shrink:0;flex-basis:auto;max-width:400px;padding-left:1rem;overflow-y:scroll}#browsersteps-selector-wrapper{height:100% !important}}#browsersteps-selector-wrapper{width:100%;overflow-y:scroll;position:relative;height:80vh}#browsersteps-selector-wrapper>img{position:absolute;max-width:100%}#browsersteps-selector-wrapper>canvas{position:relative;max-width:100%}#browsersteps-selector-wrapper>canvas:hover{cursor:pointer}#browsersteps-selector-wrapper .loader{position:absolute;left:50%;top:50%;transform:translate(-50%, -50%);z-index:100;max-width:350px;text-align:center}#browsersteps-selector-wrapper .spinner,#browsersteps-selector-wrapper .spinner:after{width:80px;height:80px;font-size:3px}#browsersteps-selector-wrapper #browsersteps-click-start{color:var(--color-grey-400)}#browsersteps-selector-wrapper #browsersteps-click-start:hover{cursor:pointer}ul#requests-extra_proxies{list-style:none}ul#requests-extra_proxies li>label{display:none}ul#requests-extra_proxies table tr{display:table-row}ul#requests-extra_proxies table tr input[type=text]{width:100%}@media only screen and (min-width: 1024px){ul#requests-extra_proxies table tr{display:inline}}#request label[for=proxy]{display:inline-block}body.proxy-check-active #request .proxy-check-details{font-size:80%;color:#555;display:block;padding-left:2em;max-width:500px}body.proxy-check-active #request .proxy-timing{font-size:80%;padding-left:1rem;color:var(--color-link)}#recommended-proxy{display:grid;gap:2rem;padding-bottom:1em}@media(min-width: 991px){#recommended-proxy{grid-template-columns:repeat(2, 1fr)}}#recommended-proxy>div{border:1px #aaa solid;border-radius:4px;padding:1em}#extra-proxies-setting{border:1px solid var(--color-grey-800);border-radius:4px;margin:1em;padding:1em}ul#requests-extra_browsers{list-style:none}ul#requests-extra_browsers li>label{display:none}ul#requests-extra_browsers table tr{display:table-row}ul#requests-extra_browsers table tr input[type=text]{width:100%}@media only screen and (min-width: 1280px){ul#requests-extra_browsers table tr{display:inline}ul#requests-extra_browsers table tr input[type=text]{width:100%}}#extra-browsers-setting{border:1px solid var(--color-grey-800);border-radius:4px;margin:1em;padding:1em}.pagination-page-info{text-transform:capitalize}.pagination.menu>*{display:inline-block}.pagination.menu li{display:inline-block}.pagination.menu a{padding:.65rem;margin:3px;border:none;background:#444;border-radius:2px;color:var(--color-text-button)}.pagination.menu a.disabled{display:none}.pagination.menu a.active{font-weight:bold;background:#888}.pagination.menu a:hover{background:#999}.spinner,.spinner:after{border-radius:50%;width:10px;height:10px}.spinner{margin:0px auto;font-size:3px;vertical-align:middle;display:inline-block;text-indent:-9999em;border-top:1.1em solid rgba(38,104,237,.2);border-right:1.1em solid rgba(38,104,237,.2);border-bottom:1.1em solid rgba(38,104,237,.2);border-left:1.1em solid #2668ed;-webkit-transform:translateZ(0);-ms-transform:translateZ(0);transform:translateZ(0);-webkit-animation:load8 1.1s infinite linear;animation:load8 1.1s infinite linear}@-webkit-keyframes load8{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@keyframes load8{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}.toggle-light-mode .icon-dark{display:none}html[data-darkmode=true] .toggle-light-mode .icon-light{display:none}html[data-darkmode=true] .toggle-light-mode .icon-dark{display:block}.pure-menu-link{padding:.5rem 1em;line-height:1.2rem}#menu-mute img,#menu-pause img{height:1.2rem}.pure-menu-item{height:initial}.pure-menu-item svg{height:1.2rem}.pure-menu-item *{vertical-align:middle}.pure-menu-item .bi-heart:hover{cursor:pointer}.pure-menu-item.active .pure-menu-link{background-color:var(--color-background-menu-link-hover);color:var(--color-text-menu-heading)}.pure-menu-item .action-icon{stroke:var(--color-text-menu-heading)}#overlay{opacity:.95;position:fixed;width:350px;max-width:100%;height:100%;top:50px;right:-350px;background-color:var(--color-table-stripe);border:1px solid #aaa;z-index:2;transform:translateX(0);transition:transform .5s ease}#overlay.visible{transform:translateX(-100%)}#overlay .content{font-size:.875rem;padding:1.1rem;max-width:400px;color:var(--color-watch-table-row-text)}#heartpath{height:1.6rem;width:1.6rem;z-index:100;transition:all ease .3s !important}#heartpath:hover{fill:red !important;transition:all ease .3s !important}.minitabs-wrapper{width:100%}.minitabs-wrapper>div[id]{padding:20px;border:1px solid #ccc;border-top:none}.minitabs-wrapper .minitabs-content{width:100%;display:flex}.minitabs-wrapper .minitabs-content>div{flex:1 1 auto;min-width:0;overflow:scroll}.minitabs-wrapper .minitabs{display:flex;border-bottom:1px solid #ccc}.minitabs-wrapper .minitab{flex:1;text-align:center;padding:12px 0;text-decoration:none;color:#333;background-color:#f1f1f1;border:1px solid #ccc;border-bottom:none;cursor:pointer;transition:background-color .3s}.minitabs-wrapper .minitab:hover{background-color:#ddd}.minitabs-wrapper .minitab.active{background-color:#fff;font-weight:bold}@media(min-width: 800px){body.preview-text-enabled #filters-and-triggers>div{display:flex;gap:20px;position:relative}}body.preview-text-enabled #edit-text-filter,body.preview-text-enabled #text-preview{flex:1;align-self:flex-start}body.preview-text-enabled #edit-text-filter #pro-tips{display:none}body.preview-text-enabled #text-preview{position:sticky;top:20px;padding-top:1rem;padding-bottom:1rem;display:block !important}body.preview-text-enabled #activate-text-preview{background-color:var(--color-grey-500)}body.preview-text-enabled .monospace-preview{background:var(--color-background-input);border:1px solid var(--color-grey-600);padding:1rem;color:var(--color-text-input);font-family:"Courier New",Courier,monospace;font-size:70%;word-break:break-word;white-space:pre-wrap}#activate-text-preview{right:0;position:absolute;z-index:3;box-shadow:1px 1px 4px var(--color-shadow-jump)}.cdio-table{width:100%;font-size:var(--body-main-text-size)}.cdio-table thead{text-transform:uppercase}.cdio-table thead a{color:var(--color-text)}.cdio-table td,.cdio-table th{vertical-align:middle;border:none}.cdio-table tbody tr{color:var(--color-watch-table-row-text);border-bottom:1px solid var(--color-table-line);background-color:var(--color-table-background)}.cdio-table tbody tr td{background-color:var(--color-table-background)}.cdio-table tbody tr:hover>td{background-color:var(--watchlist-row-hover)}.cdio-table-clip{border-radius:var(--common-round-border);overflow:hidden;margin-bottom:1.1rem}.seg{display:inline-flex;align-items:center;gap:2px;padding:2px;border:1px solid var(--color-border-table-cell);border-radius:var(--common-round-border);background:var(--color-background-table-thead)}.seg a,.seg button{display:inline-flex;align-items:center;gap:6px;border:0;background:rgba(0,0,0,0);color:var(--color-text-input-description);font-size:.8rem;font-weight:600;line-height:1.4;padding:5px 11px;border-radius:calc(var(--common-round-border) - 1px);text-decoration:none;cursor:pointer;white-space:nowrap}.seg a:hover,.seg button:hover{color:var(--color-text)}.seg a.active,.seg a:hover,.seg button.active,.seg button:hover{background:var(--color-background);color:var(--color-text);box-shadow:0 1px 2px rgba(0,0,0,.15)}html[data-darkmode=true] .seg a.active,html[data-darkmode=true] .seg button.active{background:var(--color-grey-400);box-shadow:0 1px 2px rgba(0,0,0,.5)}.seg-count{font-size:.62rem;line-height:1;font-weight:700;padding:2px 6px;border-radius:999px;background:var(--color-background-button-tag);color:var(--color-white)}.seg-count--unread{background:#3e95bb}.seg-count--error{background:var(--color-background-button-error)}.seg-count--deal{background:var(--color-background-button-success)}.cdio-btn{display:inline-flex;align-items:center;gap:6px;height:32px;padding:0 12px;border-radius:var(--common-round-border);border:1px solid var(--color-border-table-cell);background:var(--color-background);color:var(--color-text-input-description);font-family:inherit;font-size:.8rem;font-weight:600;line-height:1;white-space:nowrap;text-decoration:none;cursor:pointer;transition:border-color .12s ease,color .12s ease,background-color .12s ease}.cdio-btn:hover{border-color:var(--color-border-input);color:var(--color-text)}.cdio-btn:focus-visible{outline:2px solid var(--color-link);outline-offset:2px}.cdio-btn svg{width:15px;height:15px;stroke:currentColor}.cdio-btn img{height:15px;display:block}.cdio-btn--icon{width:32px;padding:0;justify-content:center}.cdio-btn--sm{height:26px;padding:0 9px;font-size:.72rem;gap:5px}.cdio-btn--sm svg{width:13px;height:13px}.cdio-btn--primary{background:var(--color-background-button-primary);border-color:var(--color-background-button-primary);color:var(--color-text-button)}.cdio-btn--primary:hover{background:var(--color-link);border-color:var(--color-link);color:var(--color-text-button)}.cdio-btn--danger{color:var(--color-background-button-error)}.cdio-btn--danger:hover{color:var(--color-background-button-error);border-color:var(--color-background-button-error)}.cdio-btn--warning{color:#d68a00}.cdio-btn--warning:hover{color:#d68a00;border-color:#d68a00}.watch-table tr:has(input[name=uuids]:checked)>td{background-color:var(--watchlist-row-selected)}.watch-table tbody tr:hover td.buttons *,.watch-table tbody tr:focus-within td.buttons *,.watch-table tbody tr:has(input[name=uuids]:checked) td.buttons *{opacity:1}.select-all-banner{margin:.4rem 0;padding:.5rem .75rem;border-radius:var(--common-round-border);background:var(--watchlist-row-selected);color:var(--color-watch-table-row-text);font-size:var(--body-main-text-size)}.select-all-banner button{margin-left:.5rem;vertical-align:baseline}.watch-controls svg{width:18px;height:18px;stroke:currentColor;fill:none;vertical-align:middle}#stats_row{display:flex;align-items:center;width:100%;color:#fff;font-size:.85rem}#stats_row>*{padding-bottom:.5rem}#stats_row .left{text-align:left}#stats_row .left .records-selected{margin-top:.25rem;opacity:.9}#stats_row .right{opacity:.5;transition:opacity .6s ease;margin-left:auto;text-align:right}body.has-queue #stats_row .right{opacity:1}#checkbox-operations{margin-bottom:.55rem;background:var(--color-background-new-watch-form);padding:1em;border-radius:10px;max-width:100%;position:sticky;top:20px;display:none}#checkbox-operations button{margin-bottom:3px;margin-top:3px;display:inline-flex;align-items:center}#checkbox-operations i,#checkbox-operations svg{width:14px;height:14px;stroke:#fff}body.watch-selection-active #checkbox-operations{display:block}.watch-table .checkbox-uuid{text-align:center}.watch-table .checkbox-uuid>*{vertical-align:middle}@media only screen and (max-width: 1200px){.watch-table .last-checked,.watch-table .last-changed{text-align:center}}.watch-table #th-webpage{text-align:center}.watch-table tbody tr.unviewed{font-weight:bold}.watch-table tbody tr td.inline.title-col{width:100%}.watch-table tbody tr td.inline.title-col .grid-wrapper{display:grid;grid-template-columns:auto minmax(0, 1fr) auto;grid-auto-columns:auto;align-items:center;gap:.55rem}.watch-table tbody tr td.inline.title-col .grid-wrapper>.favicon{grid-column:1}.watch-table tbody tr td.inline.title-col .grid-wrapper>.watch-text-info{grid-column:2}.watch-table tbody tr td.inline.title-col .grid-wrapper>.status-icons{grid-column:3}.watch-table tbody tr td.inline.title-col .grid-wrapper>.restock-info-wrap{grid-column:4}@media only screen and (max-width: 1200px){.watch-table tbody tr td.inline.title-col .grid-wrapper>.restock-info-wrap{grid-column:1/-1;justify-self:center}}.watch-table tbody tr .watch-text-info{line-height:1.5}.watch-table tbody tr.checking-now td:first-child{position:relative}.watch-table tbody tr.checking-now td:first-child::before{content:"";position:absolute;top:0;bottom:0;left:0;width:3px;background-color:#293eff}.watch-table tbody tr.checking-now td.last-checked .spinner-wrapper{display:inline-block !important;white-space:nowrap !important}.watch-table tbody tr.checking-now td.last-checked .spinner{margin-right:.275rem}.watch-table tbody tr.checking-now td.last-checked .innertext{display:none !important}.watch-table tbody tr.queued a.recheck{display:none !important}.watch-table tbody tr.queued a.already-in-queue-button{display:inline-flex !important;opacity:.8}.watch-table tbody tr.paused a.pause-toggle.state-on{display:inline !important}.watch-table tbody tr.paused a.pause-toggle.state-off{display:none !important}.watch-table tbody tr.notification_muted a.mute-toggle.state-on{display:inline !important}.watch-table tbody tr.notification_muted a.mute-toggle.state-off{display:none !important}.watch-table tbody tr.has-error .error-text{display:block !important;color:var(--color-watch-table-error)}.watch-table tbody tr.single-history a.preview-link{display:inherit !important}.watch-table tbody tr.multiple-history a.history-link{display:inherit !important}.watch-table tbody tr.has-favicon.unviewed img.favicon{opacity:1 !important;border-radius:4px}.watch-table td.buttons{font-size:12px;white-space:nowrap}.watch-table td.buttons>div{display:inline-flex;align-items:center;gap:6px}.watch-table td.buttons>div>*{opacity:0;transition:opacity .12s ease}.watch-table td.title-col{word-break:break-all;white-space:normal}.watch-table td a.external::after{content:"";display:inline-block;width:var(--body-main-text-size);height:var(--body-main-text-size);vertical-align:-0.1em;background:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23777' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6'/%3E%3Cpolyline points='15 3 21 3 21 9'/%3E%3Cline x1='10' y1='14' x2='21' y2='3'/%3E%3C/svg%3E") no-repeat center/contain;margin:0 3px 0 5px}.watch-table td.watch-controls>div{display:flex;justify-content:space-between;align-items:center}@media(min-width: 1020px){.watch-table th{white-space:nowrap}}.watch-table th#h-lastchanged,.watch-table th#h-lastchecked{text-align:center}.watch-table th a{font-weight:normal}.watch-table th a.active{font-weight:bolder}.watch-table th a.inactive .arrow{display:none}.watch-table th#mute-pause{white-space:nowrap}.watch-table th#mute-pause>div{display:flex;justify-content:space-between;align-items:center}.watch-table.favicon-not-enabled tr .favicon{display:none}.watch-table .status-icons{white-space:nowrap;display:flex;align-items:center;gap:4px}.watch-table .status-icons>*{vertical-align:middle}.watch-table .title-wrapper{display:flex;align-items:center;gap:10px}.watch-table .title-col-inner{display:inline-block;vertical-align:middle}.watch-table img.favicon{vertical-align:middle;max-width:36px;max-height:36px;height:36px;border-radius:var(--common-round-border)}.watch-table img.favicon:hover{outline:2px solid color-mix(in srgb, var(--color-watch-table-row-text) 50%, transparent);outline-offset:1px}body.watch-selection-active #buttons-for-all-watches{display:none !important}#buttons-for-all-watches{display:flex;align-items:center;justify-content:flex-start;flex-wrap:wrap;gap:.55rem;margin:0}#buttons-for-all-watches #post-list-mark-views{display:none}body.has-any-unviewed #post-list-mark-views{display:inline-flex !important}#watch-table-wrapper{display:inline-block;width:100%}#watch-table-wrapper #list-related-buttons{display:flex;align-items:center;justify-content:flex-start;flex-wrap:wrap;gap:.55rem;margin:0;padding:1.1rem 0 .55rem 0}#watch-table-wrapper.has-error #list-related-buttons #post-list-with-errors{display:inline-flex !important}#watch-table-wrapper.has-unread-changes #list-related-buttons #post-list-unread{display:inline-flex !important}#watch-table-wrapper #tag-lister #tag-all{opacity:1}#watch-table-wrapper #tag-lister.active-tag .button-tag{opacity:.35}#watch-table-wrapper #tag-lister.active-tag .button-tag.active,#watch-table-wrapper #tag-lister.active-tag .button-tag:hover{opacity:1}.content .group-overview-table{width:100%}.content .group-overview-table .pure-button{margin-top:.3rem;margin-bottom:.3rem}.content .group-overview-table .watch-controls,.content .group-overview-table .watch-count{text-align:center}.content .group-overview-table td{padding:5px !important;color:var(--color-watch-table-row-text)}.pure-button{border-radius:var(--common-round-border)}body.blueprint-watchlist #add-watch-ui{margin-bottom:1.1rem;padding:0}body.blueprint-watchlist #add-watch-url-row{margin-bottom:0 !important}body.blueprint-watchlist #quick-watch-llm-intent{margin-top:.55rem}body.blueprint-watchlist #url{width:auto}@media only screen and (min-width: 980px){body.blueprint-watchlist #url{min-width:32rem;max-width:min(80%,80vw);box-sizing:border-box}}body.blueprint-watchlist #quick-watch-llm-intent,body.blueprint-watchlist #quick-watch-processor-type{display:none}body.blueprint-watchlist #new-watch-form:has(#url:not(:placeholder-shown)) #quick-watch-llm-intent,body.blueprint-watchlist #new-watch-form:has(#url:not(:placeholder-shown)) #quick-watch-processor-type{display:block}@media(max-width: 767px){.watch-table thead{display:block}.watch-table thead tr th{display:inline-block}.watch-table thead tr th .hide-on-mobile{display:none}.watch-table thead .empty-cell{display:none}.watch-table .last-checked::before{color:var(--color-text);content:attr(data-label) " "}.watch-table .last-changed::before{color:var(--color-text);content:attr(data-label) " "}.watch-table td.inline{display:inline-block}.watch-table .pure-table td,.watch-table .pure-table th{border:none}.watch-table td{border:none;border-bottom:1px solid var(--color-border-watch-table-cell);vertical-align:middle}.watch-table td:before{top:6px;left:6px;width:45%;padding-right:10px;white-space:nowrap}.watch-table.pure-table-striped tr{background-color:var(--color-table-background)}.watch-table.pure-table-striped tr:nth-child(2n-1){background-color:var(--color-table-stripe)}.watch-table.pure-table-striped tr:nth-child(2n-1) td{background-color:inherit}}@media(max-width: 767px){.watch-table tbody tr{padding-bottom:10px;padding-top:10px;display:grid;grid-template-columns:40px 1fr 100px;grid-template-rows:auto auto auto auto;gap:.5rem}.watch-table tbody tr .counter-i{display:none}.watch-table tbody tr>td{border-bottom:none}.watch-table tbody tr>td[colspan]{grid-column:1/-1}.watch-table tbody tr>td.title-col{grid-column:1/-1;grid-row:1}.watch-table tbody tr>td.title-col .watch-title{font-size:.92rem}.watch-table tbody tr>td.title-col .link-spread{display:none}.watch-table tbody tr>td.last-checked{grid-column:1/-1;grid-row:2}.watch-table tbody tr>td.last-changed{grid-column:1/-1;grid-row:3}.watch-table tbody tr>td.checkbox-uuid{grid-column:1;grid-row:4}.watch-table tbody tr>td.buttons{grid-column:2;grid-row:4;display:flex;align-items:center;justify-content:flex-start}.watch-table tbody tr>td.watch-controls{grid-column:3;grid-row:4;display:grid;place-items:center}.watch-table tbody tr>td.watch-controls a img{padding:10px}.pure-table td{padding:0 !important}}@media(min-width: 768px){.watch-table thead tr th .hide-on-desktop{display:none}.watch-table td.last-checked .innertext,.watch-table td.last-changed .innertext{white-space:nowrap}}#llm-intent-section textarea{white-space:normal;overflow-wrap:break-word;overflow-x:hidden;overflow-y:auto;resize:vertical;font-family:inherit}ul#conditions_match_logic{list-style:none}ul#conditions_match_logic input,ul#conditions_match_logic label,ul#conditions_match_logic li{display:inline-block}ul#conditions_match_logic li{padding-right:1em}.fieldlist_formfields{width:100%;background-color:var(--color-background, #fff);border-radius:4px;border:1px solid var(--color-border-table-cell, #cbcbcb)}.fieldlist_formfields .fieldlist-header{display:flex;background-color:var(--color-background-table-thead, #e0e0e0);font-weight:bold;border-bottom:1px solid var(--color-border-table-cell, #cbcbcb)}.fieldlist_formfields .fieldlist-header-cell{flex:1;padding:.5em 1em;text-align:left}.fieldlist_formfields .fieldlist-header-cell:last-child{flex:0 0 120px}.fieldlist_formfields .fieldlist-body{display:flex;flex-direction:column}.fieldlist_formfields .fieldlist-row{display:flex;border-bottom:1px solid var(--color-border-table-cell, #cbcbcb)}.fieldlist_formfields .fieldlist-row:last-child{border-bottom:none}.fieldlist_formfields .fieldlist-row:nth-child(2n-1){background-color:var(--color-table-stripe, #f2f2f2)}.fieldlist_formfields .fieldlist-row.error-row{background-color:var(--color-error-input, #ffdddd)}.fieldlist_formfields .fieldlist-cell{flex:1;padding:.5em 1em;display:flex;flex-direction:column;justify-content:center}.fieldlist_formfields .fieldlist-cell input,.fieldlist_formfields .fieldlist-cell select{width:100%}.fieldlist_formfields .fieldlist-cell.fieldlist-actions{flex:0 0 120px;display:flex;flex-direction:row;align-items:center;gap:4px}.fieldlist_formfields ul.errors{margin-top:.5em;margin-bottom:0;padding:.5em;background-color:var(--color-error-background-snapshot-age, #ffdddd);border-radius:4px;list-style-position:inside}@media only screen and (max-width: 760px){.fieldlist_formfields .fieldlist-header,.fieldlist_formfields .fieldlist-row{flex-direction:column}.fieldlist_formfields .fieldlist-header-cell{display:none}.fieldlist_formfields .fieldlist-row{padding:.5em 0;border-bottom:2px solid var(--color-border-table-cell, #cbcbcb)}.fieldlist_formfields .fieldlist-cell{padding:.25em .5em}.fieldlist_formfields .fieldlist-cell.fieldlist-actions{flex:1;justify-content:flex-start;padding-top:.5em}.fieldlist_formfields .fieldlist-cell:not(:last-child){margin-bottom:.5em}.fieldlist_formfields .fieldlist-cell::before{content:attr(data-label);font-weight:bold;margin-bottom:.25em}}.fieldlist_formfields .addRuleRow,.fieldlist_formfields .removeRuleRow,.fieldlist_formfields .verifyRuleRow{cursor:pointer;border:none;padding:4px 8px;border-radius:3px;font-weight:bold;background-color:#aaa;color:var(--color-foreground-text, #fff)}.fieldlist_formfields .addRuleRow:hover,.fieldlist_formfields .removeRuleRow:hover,.fieldlist_formfields .verifyRuleRow:hover{background-color:#999}body.checking-now #checking-now-fixed-tab{display:block !important}#checking-now-fixed-tab{background:#ccc;border-radius:5px;bottom:0;color:var(--color-text);display:none;font-size:.8rem;left:0;padding:5px;position:fixed}#selector-wrapper{height:100%;text-align:center;max-height:70vh;overflow-y:scroll;position:relative}#selector-wrapper>img{position:absolute;z-index:4;max-width:100%}#selector-wrapper>canvas{position:relative;z-index:5;max-width:100%}#selector-wrapper>canvas:hover{cursor:pointer}#selector-current-xpath{font-size:80%}@media(min-width: 901px){body.blueprint-add_watch_ui #add-watch-ui{width:80%}}#add-watch-ui{padding:0}#add-watch-ui #add-watch-url-row{display:flex;gap:.5rem;align-items:stretch;margin-bottom:1rem}#add-watch-ui #add-watch-url-row>span{flex:1 1 auto;min-width:0}#add-watch-ui #add-watch-url-row>span input{width:100%}#add-watch-ui #add-watch-url-row #add-watch-go{flex:0 0 auto;white-space:nowrap}#add-watch-ui #add-watch-panes{display:flex;gap:.55rem;align-items:stretch}@media(max-width: 900px){#add-watch-ui #add-watch-panes{flex-direction:column}}#add-watch-ui #add-watch-selector-pane{flex:1 1 62%;min-width:0;min-height:380px;position:relative;display:flex;flex-direction:column;overflow:hidden;border:1px solid var(--color-background-tab);border-radius:6px;background:rgba(0,0,0,.15);padding:.75rem}#add-watch-ui #add-watch-selector-pane #add-watch-empty-state,#add-watch-ui #add-watch-selector-pane #add-watch-spinner,#add-watch-ui #add-watch-selector-pane #add-watch-error{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:.6rem;text-align:center;padding:2rem 1rem}#add-watch-ui #add-watch-selector-pane #add-watch-empty-state{opacity:.8}#add-watch-ui #add-watch-selector-pane #add-watch-empty-state svg{opacity:.55}#add-watch-ui #add-watch-selector-pane #add-watch-empty-state strong{font-size:1.05rem}#add-watch-ui #add-watch-selector-pane #add-watch-empty-state span{font-size:.85rem;opacity:.8;max-width:32ch}#add-watch-ui #add-watch-selector-pane #add-watch-spinner{gap:1.2rem}#add-watch-ui #add-watch-selector-pane #add-watch-spinner .spinner{font-size:5px}#add-watch-ui #add-watch-selector-pane #add-watch-spinner .fetching-update-notice{font-size:.85rem;opacity:.85}#add-watch-ui #add-watch-selector-pane #add-watch-error{color:#ffb4b4;font-size:.9rem;word-break:break-word}#add-watch-ui #add-watch-selector-pane #selector-wrapper{position:relative;display:block;width:100%;flex:1 1 auto;min-height:0;max-height:none;overflow-y:auto;overflow-x:hidden;text-align:left}#add-watch-ui #add-watch-selector-pane #selector-wrapper>img{position:relative;display:block;max-width:100%;height:auto;z-index:4}#add-watch-ui #add-watch-selector-pane #selector-wrapper>canvas{position:absolute;top:0;left:0;max-width:none;z-index:5}#add-watch-ui #add-watch-options-pane{flex:0 0 34%;min-width:0;display:flex;flex-direction:column;gap:1.1rem}@media(max-width: 900px){#add-watch-ui #add-watch-options-pane{flex:1 1 auto}}#add-watch-ui #add-watch-options-pane .add-watch-option-group label{display:inline-block}#add-watch-ui #add-watch-options-pane #quick-watch-fetch-backend ul{margin:.35rem 0 0 0;padding:0;list-style:none}#add-watch-ui #add-watch-options-pane #quick-watch-fetch-backend li{display:flex;align-items:flex-start;gap:.5em;padding:.15rem 0}#add-watch-ui #add-watch-options-pane #quick-watch-fetch-backend li input[type=radio]{flex:0 0 auto;margin-top:.2em}#add-watch-ui #add-watch-options-pane #quick-watch-fetch-backend li label{display:block;min-width:0;overflow-wrap:anywhere;font-size:.85rem;line-height:1.35}#add-watch-ui #add-watch-options-pane #quick-watch-fetch-backend li.unusable{opacity:.55;cursor:not-allowed}#add-watch-ui #add-watch-options-pane #quick-watch-fetch-backend li.unusable label{cursor:not-allowed}#add-watch-ui #add-watch-options-pane #quick-watch-fetch-backend .pure-form-message-inline{display:block;margin-top:.35rem;font-size:.8rem;opacity:.8}#add-watch-ui #add-watch-options-pane #by-element-toggle-group .pure-form-message-inline{display:block;margin-top:.25rem;font-size:.8rem;opacity:.8}#add-watch-ui #add-watch-options-pane #by-element-toggle-group #clear-selector{margin-top:.5rem}#add-watch-ui #add-watch-options-pane #quick-watch-llm-intent label{display:block;margin-bottom:.35rem}#add-watch-ui #add-watch-options-pane #add-watch-submit-row{display:flex;flex-wrap:wrap;gap:.5rem}body.blueprint-add_watch_ui #add-watch-ui{height:90vh;display:flex;flex-direction:column}body.blueprint-add_watch_ui #add-watch-fieldset{flex:1 1 auto;min-height:0;min-width:0;display:flex;flex-direction:column;border:0;margin:0;padding:0}body.blueprint-add_watch_ui #add-watch-legend{margin:0 0 .75rem;font-size:1.1rem;font-weight:600}body.blueprint-add_watch_ui #new-watch-form{flex:1 1 auto;min-height:0;display:flex;flex-direction:column}@media(min-width: 901px){body.blueprint-add_watch_ui #add-watch-panes{flex:1 1 auto;min-height:0}body.blueprint-add_watch_ui #add-watch-selector-pane{min-height:0}}@media(max-width: 900px){body.blueprint-add_watch_ui #add-watch-ui{height:auto}body.blueprint-add_watch_ui #add-watch-panes{flex:0 0 auto}}.ternary-radio-group{display:flex;gap:0;border:1px solid var(--color-grey-750);border-radius:4px;overflow:hidden;width:fit-content;background:var(--color-background)}.ternary-radio-group .ternary-radio-option{position:relative;cursor:pointer;margin:0;display:flex;align-items:center}.ternary-radio-group .ternary-radio-option input[type=radio]{position:absolute;opacity:0;width:0;height:0}.ternary-radio-group .ternary-radio-option .ternary-radio-label{padding:8px 16px;background:var(--color-grey-900);border:none;border-right:1px solid var(--color-grey-750);font-size:13px;font-weight:500;color:var(--color-text);transition:all .2s ease;cursor:pointer;display:block;text-align:center}.ternary-radio-group .ternary-radio-option:last-child .ternary-radio-label{border-right:none}.ternary-radio-group .ternary-radio-option input:checked+.ternary-radio-label{background:var(--color-link);color:var(--color-text-button);font-weight:600}.ternary-radio-group .ternary-radio-option input:checked+.ternary-radio-label.ternary-default{background:var(--color-grey-600);color:var(--color-text-button)}.ternary-radio-group .ternary-radio-option input:checked+.ternary-radio-label:hover{background:#1a7bc4}.ternary-radio-group .ternary-radio-option input:checked+.ternary-radio-label:hover.ternary-default{background:var(--color-grey-500)}.ternary-radio-group .ternary-radio-option:hover .ternary-radio-label{background:var(--color-grey-800)}@media(max-width: 480px){.ternary-radio-group{width:100%}.ternary-radio-group .ternary-radio-label{flex:1;min-width:auto}}input[type=radio].pure-radio:checked+label,input[type=radio].pure-radio:checked{background:var(--color-link);color:var(--color-text-button)}html[data-darkmode=true] .ternary-radio-group .ternary-radio-option .ternary-radio-label{background:var(--color-grey-350)}html[data-darkmode=true] .ternary-radio-group .ternary-radio-option:hover .ternary-radio-label{background:var(--color-grey-400)}html[data-darkmode=true] .ternary-radio-group .ternary-radio-option input:checked+.ternary-radio-label{background:var(--color-link);color:var(--color-text-button)}html[data-darkmode=true] .ternary-radio-group .ternary-radio-option input:checked+.ternary-radio-label.ternary-default{background:var(--color-grey-600)}html[data-darkmode=true] .ternary-radio-group .ternary-radio-option input:checked+.ternary-radio-label:hover{background:#1a7bc4}html[data-darkmode=true] .ternary-radio-group .ternary-radio-option input:checked+.ternary-radio-label:hover.ternary-default{background:var(--color-grey-500)}body.processor-image_ssim_diff #edit-text-filter .text-filtering{display:none}body.processor-image_ssim_diff #conditions-tab{display:none}.modal-dialog{border:none;border-radius:10px;padding:0;background:var(--color-background);color:var(--color-text);box-shadow:0 5px 20px rgba(0,0,0,.3);max-width:500px;width:90%}.modal-dialog::backdrop{background:rgba(0,0,0,.6);backdrop-filter:blur(3px);animation:fadeIn .2s ease-out}.modal-dialog[open]{animation:slideIn .25s ease-out}.modal-dialog .modal-header{padding:1.5rem;border-bottom:1px solid var(--color-border-table-cell);display:flex;align-items:center;gap:1rem}.modal-dialog .modal-header .modal-icon{font-size:2rem;line-height:1;flex-shrink:0}.modal-dialog .modal-header .modal-icon.warning{color:var(--color-warning)}.modal-dialog .modal-header .modal-icon.danger{color:var(--color-background-button-error)}.modal-dialog .modal-header .modal-icon.info{color:var(--color-background-button-primary)}.modal-dialog .modal-header .modal-title{font-size:1.3rem;font-weight:bold;margin:0;color:var(--color-text)}.modal-dialog .modal-body{padding:1.5rem;line-height:1.6}.modal-dialog .modal-body p{margin:0 0 1rem 0}.modal-dialog .modal-body p:last-child{margin-bottom:0}.modal-dialog .modal-body strong{color:var(--color-text);font-weight:600}.modal-dialog .modal-footer{padding:1rem 1.5rem;border-top:1px solid var(--color-border-table-cell);display:flex;gap:.75rem;justify-content:flex-end;background:var(--color-grey-900)}.modal-dialog .modal-footer button{padding:.6rem 1.5rem;border:none;border-radius:4px;cursor:pointer;font-weight:500;transition:all .2s ease;font-size:.95rem}.modal-dialog .modal-footer button:hover{transform:translateY(-1px);box-shadow:0 2px 8px rgba(0,0,0,.15)}.modal-dialog .modal-footer button:active{transform:translateY(0)}.modal-dialog .modal-footer button.modal-btn-cancel{background:var(--color-background-button-cancel);color:var(--color-grey-200)}.modal-dialog .modal-footer button.modal-btn-cancel:hover{background:var(--color-grey-700)}.modal-dialog .modal-footer button.modal-btn-confirm{background:var(--color-background-button-primary);color:var(--color-white)}.modal-dialog .modal-footer button.modal-btn-confirm:hover{opacity:.9}.modal-dialog .modal-footer button.modal-btn-danger{background:var(--color-background-button-error);color:var(--color-white)}.modal-dialog .modal-footer button.modal-btn-danger:hover{background:var(--color-dark-red)}.modal-dialog .modal-footer button.modal-btn-warning{background:var(--color-background-button-warning);color:var(--color-white)}.modal-dialog .modal-footer button.modal-btn-warning:hover{opacity:.9}html[data-darkmode=true] .modal-dialog{box-shadow:0 5px 30px rgba(0,0,0,.7)}html[data-darkmode=true] .modal-dialog .modal-footer{background:var(--color-grey-200)}@keyframes fadeIn{from{opacity:0}to{opacity:1}}@keyframes slideIn{from{opacity:0;transform:translateY(-20px) scale(0.95)}to{opacity:1;transform:translateY(0) scale(1)}}@media only screen and (max-width: 760px){.modal-dialog{width:95%;max-width:none}.modal-dialog .modal-header{padding:1rem}.modal-dialog .modal-header .modal-title{font-size:1.1rem}.modal-dialog .modal-body{padding:1rem;font-size:.95rem}.modal-dialog .modal-footer{padding:.75rem 1rem;flex-wrap:wrap}.modal-dialog .modal-footer button{flex:1;min-width:120px}}.bulk-choice-list{display:flex;flex-direction:column;gap:2px;max-height:50vh;overflow-y:auto;text-align:left}.bulk-choice-list .bulk-choice-row{display:block;padding:6px 8px;cursor:pointer;border-radius:4px}.bulk-choice-list .bulk-choice-row input[type=radio]{margin-right:8px}.bulk-choice-list .bulk-choice-row:hover{background:rgba(127,127,127,.15)}.bulk-choice-list .bulk-choice-row em{opacity:.7;font-size:.9em}#language-selector-flag{display:inline-block;width:1.2em;height:1.2em;vertical-align:middle;border-radius:50%;overflow:hidden;opacity:.6}#language-selector-flag:hover{opacity:1}.language-list{display:flex;flex-direction:column;gap:.5rem;padding:.5rem 0}.language-option{display:flex;align-items:center;gap:1rem;padding:.25rem;border-radius:4px;transition:background-color .2s ease;text-decoration:none;color:var(--color-text);border:1px solid rgba(0,0,0,0)}.language-option:hover{background-color:var(--color-background-menu-link-hover);border-color:var(--color-border-table-cell)}.language-option.active{background-color:var(--color-link);color:var(--color-text-button);font-weight:600}.language-option .flag{font-size:1.5rem;flex-shrink:0}.language-option .language-name{flex-grow:1;font-size:1rem}#language-modal .language-list .lang-option{display:inline-block;width:1.5em;height:1.5em;vertical-align:middle;margin-right:.5em;border-radius:50%;overflow:hidden}.action-sidebar{display:flex;flex-direction:column;align-items:center;align-self:flex-start;position:sticky;top:0;height:100vh;background:hsla(0,0%,100%,.05);z-index:60;pointer-events:none}@media only screen and (max-width: 980px){.action-sidebar{display:none}}.action-sidebar-inner{pointer-events:auto;width:64px;overflow:hidden;flex:1 1 auto;display:flex;flex-direction:column;transition:width .08s ease-out;padding-left:.55rem;padding-right:.55rem}body.actionsidebar-minimal .action-sidebar-inner:hover,body.actionsidebar-minimal .action-sidebar-inner:focus-within{width:200px;transition:width .22s cubic-bezier(0.2, 0.7, 0.2, 1)}body.actionside-bar-on .action-sidebar-inner{width:200px;transition:none}ul.action-sidebar-list{list-style:none;padding:0;margin:0;display:flex;flex-direction:column;gap:0}.action-sidebar-list.action-sidebar-list--bottom{margin-top:auto}.action-sidebar-li{list-style:none;margin:0;position:relative;color:var(--color-white)}.action-sidebar-li:nth-child(2){padding-top:2rem}.action-sidebar-li button{padding:0;margin:0}.action-sidebar-li a{color:var(--color-white)}.action-sidebar-li--spark .queue-spark{display:block;width:100%;height:15px;box-sizing:border-box;padding:0;margin:0;border-radius:3px;background:hsla(0,0%,100%,.05);box-shadow:inset 0 0 0 1px hsla(0,0%,100%,.06)}.action-sidebar-divider{height:1px;background:hsla(0,0%,100%,.18);margin:6px 16px;list-style:none}.action-sidebar .action-sidebar-item{position:relative;display:flex;align-items:center;padding:.55rem;font-size:var(--body-main-text-size);border-radius:var(--common-round-border);color:var(--color-white);text-decoration:none;white-space:nowrap;background:rgba(0,0,0,0);border:0;text-align:left;cursor:pointer;transition:background-color .12s ease,color .12s ease}.action-sidebar .action-sidebar-item:hover{background-color:var(--color-sidebar-item-hover-bg)}.action-sidebar .action-sidebar-item:hover .action-icon{stroke-width:2.3}.action-sidebar .action-sidebar-item:focus-visible{outline:2px solid var(--color-link);outline-offset:2px}.action-sidebar .action-sidebar-item.active .action-icon{stroke-width:2.4;filter:drop-shadow(0 0 0.4px currentColor)}.action-sidebar .action-sidebar-item.active .action-label{font-weight:700}.action-sidebar .action-sidebar-item.is-disabled{opacity:.45;cursor:not-allowed;pointer-events:none}.action-sidebar .action-sidebar-item.action-sidebar-item--accent .action-icon{stroke:#fff;stroke-width:2.6}.action-sidebar .action-sidebar-item .action-label{flex:0 0 auto;margin-left:14px;font-family:inherit;font-weight:400;letter-spacing:0;text-transform:none;color:inherit;opacity:0;transform:translateX(-4px);transition:opacity .05s ease-out,transform .05s ease-out}.action-sidebar .action-sidebar-item .action-badge{margin-left:10px;font-size:.7rem;line-height:1;padding:3px 7px;border-radius:999px;background:hsla(0,0%,100%,.14);color:hsla(0,0%,100%,.85);text-transform:uppercase;letter-spacing:.06em;font-weight:700;pointer-events:none;opacity:0;transition:opacity .05s ease-out}.action-sidebar .action-sidebar-item .action-badge.action-badge--count{margin-left:auto;text-transform:none;letter-spacing:0;background:#3e95bb;color:var(--color-white);font-variant-numeric:tabular-nums}body.actionsidebar-minimal .action-sidebar-inner:hover .action-sidebar-item .action-label,body.actionsidebar-minimal .action-sidebar-inner:focus-within .action-sidebar-item .action-label{opacity:1;transform:translateX(0);transition:opacity .18s ease .05s,transform .18s cubic-bezier(0.2, 0.7, 0.2, 1) .05s}body.actionsidebar-minimal .action-sidebar-inner:hover .action-sidebar-item .action-badge,body.actionsidebar-minimal .action-sidebar-inner:focus-within .action-sidebar-item .action-badge{opacity:1;transition:opacity .18s ease .05s}body.actionside-bar-on .action-sidebar .action-sidebar-item .action-label{opacity:1;transform:translateX(0);transition:none}body.actionside-bar-on .action-sidebar .action-sidebar-item .action-badge{opacity:1;transition:none}.action-icon{flex:0 0 auto;width:24px;height:24px;stroke:currentColor;stroke-width:1.9;fill:none;stroke-linecap:round;stroke-linejoin:round}.action-badge{flex:0 0 auto;font-size:.62rem;text-transform:uppercase;letter-spacing:.08em;padding:2px 6px;border-radius:999px;background:hsla(0,0%,100%,.15);color:hsla(0,0%,100%,.85);font-weight:700}.mobile-menu-section{padding:.5rem .75rem;border-bottom:1px solid var(--color-border-table-cell)}.mobile-menu-section ul.action-sidebar-list{gap:1px}.mobile-menu-section ul.action-sidebar-list .action-sidebar-li a,.mobile-menu-section ul.action-sidebar-list .action-sidebar-li button{padding:.55rem}.mobile-menu-section .action-sidebar-item{position:relative;display:flex;align-items:center;justify-content:flex-start;gap:.55rem;padding:.55rem .55rem;border-radius:var(--common-round-border);color:var(--color-text)}.mobile-menu-section .action-sidebar-item:hover{background-color:var(--color-background-menu-link-hover);color:var(--color-text)}.mobile-menu-section .action-sidebar-item.active{background-color:var(--color-background-menu-link-hover);color:var(--color-text)}.mobile-menu-section .action-sidebar-item .action-label{position:static;transform:none;background:rgba(0,0,0,0);box-shadow:none;color:inherit;opacity:1;pointer-events:auto;padding:0;font-weight:500}.mobile-menu-section .action-sidebar-item .action-label::before{display:none}.mobile-menu-section .action-sidebar-item .action-badge{position:static;margin-left:auto;font-size:.62rem;background:rgba(0,0,0,.08);color:var(--color-text)}.mobile-menu-section .action-sidebar-item.action-sidebar-item--accent{background:var(--color-background-menu-link-hover);box-shadow:inset 0 0 0 1px var(--color-border-table-cell);color:var(--color-text)}.mobile-menu-section .action-sidebar-item.action-sidebar-item--accent .action-label{color:inherit}.mobile-menu-section .action-sidebar-item--button{background:rgba(0,0,0,0);border:none;cursor:pointer;text-align:left;font:inherit}#add-watch-live-info{width:100%;margin-top:1rem}#add-watch-live-info .add-watch-live-placeholder{border:1px dashed hsla(0,0%,100%,.25);background:hsla(0,0%,100%,.04);border-radius:10px;padding:1.25rem;color:var(--color-white)}#add-watch-live-info .add-watch-live-placeholder h3{margin:0 0 .4rem 0;font-size:1rem;letter-spacing:.02em}#add-watch-live-info .add-watch-live-placeholder .muted{opacity:.7;margin:0 0 .75rem 0;font-size:.85rem}#add-watch-live-info .add-watch-live-placeholder .add-watch-live-stream{font-size:.85rem;opacity:.6;padding:.6rem 0}.mobile-menu-drawer .action-sidebar-list{padding:0}.mobile-menu-drawer .mobile-menu-section .action-sidebar-item{padding-left:0}#action-sidebar-logo{padding-top:1.1rem;padding-left:.55rem}.actionsidebar-minimal #checking-now-stats-sidebar{display:none}.actionsidebar-minimal #cdio-logo #logo-expanded{display:none}.actionsidebar-minimal.action-side-bar-expanded #checking-now-stats-sidebar{display:block}.actionsidebar-minimal.action-side-bar-expanded #cdio-logo #logo-expanded{display:inline-block}.action-side-bar-expanded #cdio-logo #logo-short{display:none}#queue-page{width:100%;color:var(--color-white)}#queue-page h2,#queue-page h3{color:var(--color-white)}#queue-page .queue-panel{background:var(--color-background-new-watch-form);padding:1em;border-radius:10px;margin-bottom:1em;width:100%;box-sizing:border-box;color:var(--color-white)}#queue-page .queue-stats{display:grid;grid-template-columns:repeat(auto-fit, minmax(160px, 1fr));gap:.75rem}#queue-page .queue-stat .label{font-size:.7rem;text-transform:uppercase;letter-spacing:.06em;opacity:.7}#queue-page .queue-stat .value{font-size:1.6rem;font-weight:700;color:var(--color-white)}#queue-page .queue-stat.queue-stat--action{display:flex;align-items:center;justify-content:flex-start}#queue-page .queue-stat.queue-stat--action .pure-button{white-space:nowrap}#queue-page table.pure-table{width:100%;background:rgba(0,0,0,0);color:var(--color-white);font-size:80%}#queue-page table.pure-table thead th{background:rgba(0,0,0,0);color:var(--color-white);border-bottom:1px solid hsla(0,0%,100%,.18);font-weight:700;white-space:nowrap}#queue-page table.pure-table td{color:var(--color-white);border-color:hsla(0,0%,100%,.08);white-space:nowrap}#queue-page table.pure-table td.title-col,#queue-page table.pure-table td.watch-cell{white-space:normal;word-break:break-all}#queue-page table.pure-table td.time-cell{font-variant-numeric:tabular-nums;color:hsla(0,0%,100%,.75);font-size:.95em}#queue-page table.pure-table code,#queue-page table.pure-table small,#queue-page table.pure-table em,#queue-page table.pure-table strong{color:var(--color-white)}#queue-page table.pure-table code{background:rgba(0,0,0,.18)}#queue-page table.pure-table small{opacity:.7}#queue-page table.pure-table-striped tr:nth-child(2n-1) td{background:hsla(0,0%,100%,.04)}#queue-page tr.is-completed td{opacity:.45;transition:opacity .4s ease}#queue-page tbody[data-section=workers]{border-bottom:1px solid hsla(0,0%,100%,.18)}#queue-page tr.worker-slot td{border-color:hsla(0,0%,100%,.05)}#queue-page tr.worker-idle td{background:hsla(0,0%,100%,.02)}#queue-page .inline-tag,#queue-page .processor-badge,#queue-page .watch-tag-list,#queue-page .tracking-ldjson-price-data,#queue-page .restock-label{background:hsla(0,0%,100%,.14);color:var(--color-white)}#queue-page .inline-tag--running{background:rgba(28,184,65,.45)}#queue-page .inline-tag--idle{background:hsla(0,0%,100%,.08);color:hsla(0,0%,100%,.6)}#queue-page .inline-tag--done{background:hsla(0,0%,100%,.1);color:hsla(0,0%,100%,.7)}#queue-page a.queue-cancel{display:inline-block;margin-left:8px;font-size:.75rem;color:hsla(0,0%,100%,.65);text-decoration:underline;text-decoration-style:dotted;text-underline-offset:2px}#queue-page a.queue-cancel:hover{color:var(--color-white);text-decoration-style:solid}#queue-page a.queue-cancel.is-busy{pointer-events:none;opacity:.5}#queue-page tr.is-new td{animation:queue-row-in .45s ease}@keyframes queue-row-in{from{background-color:rgba(28,184,65,.18)}to{background-color:rgba(0,0,0,0)}}#queue-page .queue-waiting{display:none;align-items:center;gap:.5rem;margin-top:1rem;padding:.5rem 0;color:hsla(0,0%,100%,.7);font-size:.85rem}#queue-page .queue-waiting[data-show=true]{display:flex}#queue-page .queue-waiting .spinner{margin:0;flex:0 0 auto;border-top-color:hsla(0,0%,100%,.18);border-right-color:hsla(0,0%,100%,.18);border-bottom-color:hsla(0,0%,100%,.18);border-left-color:var(--color-white)}.hamburger-menu{display:none;background:rgba(0,0,0,0);border:none;cursor:pointer;padding:.55rem;z-index:10001;position:relative}@media only screen and (max-width: 980px){.hamburger-menu{display:flex;flex-direction:column;justify-content:center;align-items:center}}.hamburger-icon{width:24px;height:20px;position:relative;display:flex;flex-direction:column;justify-content:space-between}.hamburger-icon span{display:block;height:3px;width:100%;background:var(--color-white);border-radius:2px;transition:all .3s cubic-bezier(0.68, -0.55, 0.265, 1.55);transform-origin:center}.hamburger-menu.active .hamburger-icon span{background-color:var(--color-text)}.hamburger-menu.active .hamburger-icon span:nth-child(1){transform:translateY(8.5px) rotate(45deg)}.hamburger-menu.active .hamburger-icon span:nth-child(2){opacity:0;transform:translateX(-10px)}.hamburger-menu.active .hamburger-icon span:nth-child(3){transform:translateY(-8.5px) rotate(-45deg)}.mobile-menu-overlay{display:none;position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(0,0,0,.5);z-index:9999;opacity:0;transition:opacity .3s ease}.mobile-menu-overlay.active{display:block;opacity:1}.mobile-menu-drawer{position:fixed;top:0;right:-280px;width:280px;height:100%;background:var(--color-background);opacity:1;box-shadow:-2px 0 8px rgba(0,0,0,.15);z-index:10000;transition:right .3s cubic-bezier(0.68, -0.55, 0.265, 1.55);overflow-y:auto;padding-top:60px}.mobile-menu-drawer #cdio-logo{color:var(--color-text)}.mobile-menu-drawer #cdio-logo #logo-short{display:none}.mobile-menu-drawer #cdio-logo #logo-expanded{display:inline-block}.mobile-menu-drawer .action-icon{stroke:var(--color-text)}.mobile-menu-drawer.active{right:0}.mobile-menu-drawer .mobile-menu-items{list-style:none;padding:1rem 0;margin:0}.mobile-menu-drawer .mobile-menu-items li{border-bottom:1px solid var(--color-border-table-cell)}.mobile-menu-drawer .mobile-menu-items li>*{display:block;padding:1rem 1.5rem;color:var(--color-text);text-decoration:none;font-weight:500;transition:background .2s ease}.mobile-menu-drawer .mobile-menu-items li>*:hover{background:var(--color-background-menu-link-hover)}.mobile-menu-drawer .mobile-menu-items li#menu-pause,.mobile-menu-drawer .mobile-menu-items li#menu-mute{display:none}.logo-cdio{font-weight:bold;font-size:1.1rem}.logo-cdio .logo-cd{color:var(--color-grey-500)}.logo-cdio .logo-io{color:var(--color-text)}.menu-always-visible{display:flex;align-items:center;gap:.5rem;margin-left:auto}@media only screen and (max-width: 980px){#top-right-menu .menu-collapsible{display:none !important}.pure-menu-horizontal{overflow-x:visible !important}#nav-menu{overflow-x:visible !important}}@media only screen and (min-width: 1025px){.hamburger-menu,.mobile-menu-drawer,.mobile-menu-overlay{display:none !important}}html[data-darkmode=true] .mobile-menu-drawer{box-shadow:-2px 0 8px rgba(0,0,0,.4)}#search-modal .modal-body{padding:2rem 1.5rem}#search-modal .modal-body .pure-control-group{padding-bottom:0}#search-modal .modal-body .pure-control-group label{display:block;margin-bottom:.5rem;font-size:.9rem;font-weight:600;color:var(--color-text)}#search-modal .modal-body .pure-control-group #search-modal-input{width:100%;max-width:100%;box-sizing:border-box;padding:.6rem .8rem;font-size:1rem;border:1px solid var(--color-border-input);border-radius:4px;background-color:var(--color-background-input);color:var(--color-text-input);box-shadow:inset 0 1px 3px var(--color-shadow-input);transition:border-color .2s ease,box-shadow .2s ease}#search-modal .modal-body .pure-control-group #search-modal-input:focus{outline:none;border-color:var(--color-link);box-shadow:0 0 0 3px rgba(27,152,248,.1)}#search-modal .modal-body .pure-control-group #search-modal-input::placeholder{color:var(--color-text-input-placeholder);opacity:.7}html[data-darkmode=true] #search-modal #search-modal-input:focus{box-shadow:0 0 0 3px rgba(89,189,251,.15)}#llm-diff-summary-area{margin:.6rem 0 .4rem;padding:.65rem .9rem;background:linear-gradient(135deg, rgba(120, 80, 200, 0.18), rgba(80, 160, 220, 0.14));border-left:3px solid rgba(140,90,220,.8);border-radius:0 4px 4px 0;min-width:0;max-width:100%;box-sizing:border-box;overflow:hidden}#llm-diff-summary-area .llm-diff-summary-label{display:block;font-size:.7rem;font-weight:700;letter-spacing:.06em;text-transform:uppercase;opacity:.55;margin-bottom:.25rem}#llm-diff-summary-area .llm-diff-summary-text{margin:0;font-size:.9rem;line-height:1.5;white-space:pre-wrap;overflow-wrap:break-word;word-break:break-word}.llm-diff-summary-prompt{margin:.4em 0 0;font-size:.78rem;font-style:italic;overflow:hidden;max-height:3.8em;animation:llm-prompt-reveal .7s ease-out both}.llm-diff-summary-prompt .llm-diff-summary-prompt-text{display:block;opacity:.55;mask-image:linear-gradient(to bottom, rgba(0, 0, 0, 0.85) 30%, rgba(0, 0, 0, 0) 100%);-webkit-mask-image:linear-gradient(to bottom, rgba(0, 0, 0, 0.85) 30%, rgba(0, 0, 0, 0) 100%);white-space:pre-wrap;overflow-wrap:break-word;line-height:1.45}@keyframes llm-prompt-reveal{from{opacity:0;transform:translateY(-3px)}to{opacity:1;transform:translateY(0)}}.llm-diff-summary-loading{opacity:.5;font-style:italic;animation:llm-pulse 1.4s ease-in-out infinite;font-weight:bold}@keyframes llm-pulse{0%,100%{opacity:.5}50%{opacity:.2}}.llm-budget-exceeded,.llm-error{color:#c0392b;font-weight:600;font-style:normal;opacity:1}.toggle-ai-mode{opacity:.4;transition:opacity .2s ease,filter .2s ease;display:inline-flex;align-items:center;color:var(--color-text-menu-link)}.toggle-ai-mode svg{height:1.2rem;width:1.2rem}.toggle-ai-mode .ai-mode-label{font-size:.75rem;font-weight:600;letter-spacing:.04em;line-height:1}html[data-ai-mode=true] .toggle-ai-mode{opacity:1;filter:drop-shadow(0 0 4px rgba(160, 100, 255, 0.7))}.btn-label-summary{display:none}html[data-ai-mode=true] body.llm-configured .btn-label-history{display:none}html[data-ai-mode=true] body.llm-configured .btn-label-summary{display:inline}.ai-inline-summary-row td{white-space:normal !important;word-break:break-word;padding:.5rem 1rem .6rem 1.4rem !important;background:linear-gradient(135deg, #f0ebff, #eaf0ff) !important;border-top:1px solid #c4b5fd !important;border-left:3px solid #8b5cf6 !important;color:#1a0640 !important;line-height:1.5}html[data-darkmode=true] .ai-inline-summary-row td{background:linear-gradient(135deg, #1c0d35, #0d1535) !important;border-top:1px solid #3b1f6e !important;border-left-color:#8b5cf6 !important;color:#e9d5ff !important}.ai-inline-summary-row .ai-inline-summary-content{display:flex;gap:.5rem;align-items:flex-start}.ai-inline-summary-row .ai-inline-summary-content .ai-inline-spinner{flex-shrink:0;animation:llm-pulse 1.4s ease-in-out infinite}.ai-inline-summary-row .ai-inline-summary-content .ai-inline-body{display:flex;flex-direction:column;min-width:0}.ai-inline-summary-row .ai-inline-summary-content .ai-inline-text{font-style:italic;opacity:.75;white-space:pre-wrap}.ai-inline-summary-row .ai-inline-summary-content.loaded .ai-inline-spinner{animation:none}.ai-inline-summary-row .ai-inline-summary-content.loaded .ai-inline-text{font-style:normal;opacity:1}.ai-inline-summary-row .ai-inline-history-link{display:inline-block;margin-top:.4rem;font-size:.78rem;font-weight:700;opacity:.7;white-space:nowrap}.ai-inline-summary-row .ai-inline-history-link:hover{opacity:1}.ai-inline-summary-row .ai-inline-error{color:#c0392b}.ai-inline-summary-row .ai-inline-prompt{display:block;margin-top:.3em;font-size:.75rem;font-style:italic;overflow:hidden;max-height:3.6em;animation:llm-prompt-reveal .6s ease-out both;mask-image:linear-gradient(to bottom, rgba(0, 0, 0, 0.7) 30%, rgba(0, 0, 0, 0) 100%);-webkit-mask-image:linear-gradient(to bottom, rgba(0, 0, 0, 0.7) 30%, rgba(0, 0, 0, 0) 100%);opacity:.55;line-height:1.4;white-space:pre-wrap;overflow-wrap:break-word}.action-sidebar-item{position:relative}.action-sidebar-item .notification-bubble{position:absolute;top:8px;left:8px;min-width:18px;height:18px;background:#f44;color:#fff;font-size:10px;font-weight:700;line-height:18px;text-align:center;border-radius:9px;padding:0 2px;box-shadow:0 2px 4px rgba(0,0,0,.3);pointer-events:none;transition:all .2s ease;display:none}.action-sidebar-item .notification-bubble.red-bubble{background:#f44}.action-sidebar-item .notification-bubble.blue-bubble{background:#4a9eff;color:#fff}.action-sidebar-item .notification-bubble.visible{display:block}.action-sidebar-item .notification-bubble.pulse{animation:bubblePulse .4s ease-out}.action-sidebar-item .notification-bubble.large-number{font-size:8px;min-width:20px;height:20px;line-height:20px;border-radius:10px}@keyframes bubblePulse{0%{transform:scale(1)}50%{transform:scale(1.3)}100%{transform:scale(1)}}html[data-darkmode=true] .notification-bubble{box-shadow:0 2px 6px rgba(0,0,0,.6)}.notification-add-buttons{margin-bottom:.5rem;display:flex;align-items:center;flex-wrap:wrap;gap:.4rem}.notification-add-buttons .add-destination-inline{display:inline-flex;align-items:center;gap:.3rem}.notification-add-buttons .add-destination-inline input[type=email]{margin:0;min-width:16rem}#notification-add-email-preset{padding-top:.55rem;padding-bottom:.55rem}#notification-recipients{padding-bottom:.55rem}.notification-recipients{display:flex;flex-wrap:wrap;gap:.4rem;margin-bottom:.5rem}.notification-recipients .notification-chip{display:inline-flex;align-items:center;gap:.35rem;padding:.2rem .5rem;line-height:1.4;border:1px solid var(--color-border-notification);border-radius:var(--common-round-border);max-width:100%}.notification-recipients .notification-chip .notification-chip-label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:22rem}.notification-recipients .notification-chip .notification-chip-remove{cursor:pointer;font-weight:bold;opacity:.55;text-decoration:none}.notification-recipients .notification-chip .notification-chip-remove:hover{opacity:1}.notifications-wrapper{padding-top:.5rem}.notifications-wrapper #notification-test-log{margin-top:1rem;padding:1rem;white-space:pre-wrap;word-break:break-word;overflow-wrap:break-word;max-width:100%;box-sizing:border-box;max-height:12rem;overflow-y:scroll;border:1px solid var(--color-border-notification);border-radius:5px}#notification-error-log{border:1px solid var(--color-border-notification);padding:1rem;border-radius:5px;overflow-wrap:break-word}#restock-diff{width:100%;box-sizing:border-box}#restock-diff-summary{margin-top:.6rem;display:flex;align-items:center;gap:.6rem;flex-wrap:wrap}.restock-latest-price{font-size:1.4rem;font-weight:700}.restock-badge{display:inline-block;padding:.15rem .55rem;border-radius:1rem;font-size:.8rem;font-weight:600;white-space:nowrap}.restock-badge.in-stock{background:rgba(31,164,99,.15);color:#1fa463}.restock-badge.out-of-stock{background:rgba(231,76,60,.15);color:#e74c3c}#restock-tabs{background:var(--color-background);color:var(--color-text);padding:1rem;border-radius:5px}#restock-tabs .tab-pane-inner#screenshot{text-align:center}#restock-tabs .tab-pane-inner#screenshot img{max-width:99%}#restock-graph{margin-top:1rem;box-sizing:border-box}@media(min-width: 1200px){#restock-graph{max-width:80%;margin-left:auto;margin-right:auto}}.js-restock-graph{position:relative;width:100%}.js-restock-graph svg{display:block;max-width:100%}.js-restock-graph .rg-axis{stroke:var(--color-border-notification, rgba(127, 127, 127, 0.4));stroke-width:1}.js-restock-graph .rg-label{fill:currentColor;opacity:.7;font-size:12px}.js-restock-graph .rg-line{stroke:currentColor;opacity:.55}.js-restock-graph .rg-dot{stroke:var(--color-background, #fff);stroke-width:1.5}.js-restock-graph .rg-legend{display:flex;justify-content:center;gap:1.1rem;margin-top:.4rem;font-size:.78rem;opacity:.85}.js-restock-graph .rg-legend .rg-legend-item{display:inline-flex;align-items:center;gap:.35rem}.js-restock-graph .rg-legend .rg-legend-dot{width:9px;height:9px;border-radius:50%;display:inline-block}.js-restock-graph .rg-legend .rg-legend-dot.in{background:#1fa463}.js-restock-graph .rg-legend .rg-legend-dot.out{background:#e74c3c}.js-restock-graph .rg-header{display:flex;align-items:center;justify-content:space-between;gap:.5rem;flex-wrap:wrap;margin-bottom:.5rem}.js-restock-graph .rg-stats{font-size:.8rem;opacity:.7;text-align:right;margin-left:auto}.js-restock-graph .rg-band{fill:rgba(120,130,150,.14)}.js-restock-graph .rg-avg-line{stroke:var(--color-text, #555);opacity:.45;stroke-width:1}.js-restock-graph .rg-avg-text{opacity:.5}.rg-status{display:inline-flex;align-items:baseline;gap:.4rem;padding:.2rem .6rem;border-radius:1rem;font-size:.85rem}.rg-status .rg-status-label{font-weight:700}.rg-status .rg-status-sub{font-size:.78rem;opacity:.8}.rg-status.rg-status-low{background:rgba(31,164,99,.16);color:#1fa463}.rg-status.rg-status-typical{background:rgba(120,130,150,.16);color:var(--color-text, #555)}.rg-status.rg-status-high{background:rgba(231,76,60,.16);color:#e74c3c}.rg-tooltip{position:absolute;display:none;pointer-events:none;z-index:5;transform:translateY(-50%);white-space:nowrap;background:var(--color-background, #fff);color:var(--color-text, #222);border:1px solid var(--color-border-notification, rgba(127, 127, 127, 0.4));border-radius:5px;padding:4px 8px;font-size:12px;line-height:1.4;box-shadow:0 2px 6px rgba(0,0,0,.15)}#restock-history-table{margin-left:auto;margin-right:auto}#restock-history-table td,#restock-history-table th{text-align:left}.restock-table-toolbar{display:flex;align-items:center;justify-content:center;gap:.75rem;margin-bottom:.5rem}html[data-ai-mode=true] body.llm-configured tr.processor-restock_diff .btn-label-history{display:inline}html[data-ai-mode=true] body.llm-configured tr.processor-restock_diff .btn-label-summary{display:none}.restock-inline-row td{white-space:normal !important;word-break:break-word;padding:.6rem 1rem .8rem 1.4rem !important;background:linear-gradient(135deg, #e6fbf0, #e8f6ff) !important;border-top:1px solid #9fe3c2 !important;border-left:3px solid #1fa463 !important;color:#06281a !important;line-height:1.5}html[data-darkmode=true] .restock-inline-row td{background:linear-gradient(135deg, #0c2a1c, #0d2230) !important;border-top:1px solid #1f5e40 !important;border-left-color:#1fa463 !important;color:#d6ffe9 !important}.restock-inline-row .restock-inline-graph{width:100%;min-height:40px}.restock-inline-row .restock-inline-history-link{display:inline-block;margin-top:.5rem;font-size:.78rem;font-weight:700;opacity:.75;white-space:nowrap}.restock-inline-row .restock-inline-history-link:hover{opacity:1}.restock-inline-row .restock-inline-error{color:#c0392b}.toast-container{position:fixed;display:flex;flex-direction:column;gap:.75rem;pointer-events:none;z-index:10000}.toast-container.toast-top-right{top:20px;right:20px}.toast-container.toast-top-center{top:100px;left:50%;transform:translateX(-50%)}.toast-container.toast-top-left{top:20px;left:20px}.toast-container.toast-bottom-right{bottom:20px;right:20px}.toast-container.toast-bottom-center{bottom:20px;left:50%;transform:translateX(-50%)}.toast-container.toast-bottom-left{bottom:20px;left:20px}.toast{position:relative;display:flex;align-items:center;gap:.75rem;min-width:300px;max-width:500px;padding:1rem 1.25rem;background:var(--color-background);border-radius:8px;box-shadow:0 4px 12px rgba(0,0,0,.15),0 0 0 1px rgba(0,0,0,.05);pointer-events:auto;overflow:hidden;opacity:0;transform:translateY(-50px);transition:all .3s cubic-bezier(0.68, -0.55, 0.265, 1.55);font-family:inherit}.toast.toast-show{opacity:1;transform:translateY(0)}.toast.toast-hide{opacity:0;transform:translateY(-50px) scale(0.95)}.toast.toast-success{border-left:4px solid #10b981}.toast.toast-success .toast-icon{color:#10b981}.toast.toast-error{border-left:4px solid #ef4444}.toast.toast-error .toast-icon{color:#ef4444}.toast.toast-warning{border-left:4px solid #f59e0b}.toast.toast-warning .toast-icon{color:#f59e0b}.toast.toast-info{border-left:4px solid #3b82f6}.toast.toast-info .toast-icon{color:#3b82f6}.toast.toast-default{border-left:4px solid var(--color-grey-500)}.toast-icon{flex-shrink:0;width:24px;height:24px}.toast-icon svg{width:100%;height:100%}.toast-message{flex:1;font-size:.875rem;line-height:1.5;color:var(--color-text);word-break:break-word;font-family:inherit}.toast-close{flex-shrink:0;width:24px;height:24px;display:flex;align-items:center;justify-content:center;background:rgba(0,0,0,0);border:none;border-radius:4px;color:var(--color-grey-500);font-size:1.5rem;line-height:1;cursor:pointer;transition:all .2s ease;padding:0;margin-left:.25rem}.toast-close:hover{background:var(--color-grey-800);color:var(--color-text)}.toast-close:active{transform:scale(0.95)}.toast-progress{position:absolute;bottom:0;left:0;right:0;height:3px;background:currentColor;opacity:.3;transform-origin:left;transition:transform linear}html[data-darkmode=true] .toast{background:var(--color-grey-300);box-shadow:0 4px 12px rgba(0,0,0,.4),0 0 0 1px hsla(0,0%,100%,.05)}html[data-darkmode=true] .toast-close:hover{background:var(--color-grey-400)}@media only screen and (max-width: 768px){.toast-container{left:50% !important;right:auto !important;top:80px !important;transform:translateX(-50%) !important;align-items:center}.toast-container.toast-bottom-right,.toast-container.toast-bottom-center,.toast-container.toast-bottom-left{top:auto !important;bottom:80px !important}.toast{min-width:auto;max-width:none;width:80vw;transform:translateY(-100px)}.toast.toast-show{transform:translateY(0)}.toast.toast-hide{transform:translateY(-100px) scale(0.95)}}@media(prefers-reduced-motion: reduce){.toast{transition:opacity .2s ease;transform:none !important}.toast.toast-show{opacity:1}.toast.toast-hide{opacity:0}}.login-form{min-height:52vh;display:flex;align-items:center;justify-content:center;padding:2rem 1rem}.login-form .inner{background:var(--color-background);border-radius:16px;box-shadow:0 10px 40px rgba(0,0,0,.08),0 2px 8px rgba(0,0,0,.04);padding:3rem 2.5rem;width:100%;max-width:420px;position:relative;overflow:hidden;transition:transform .3s ease,box-shadow .3s ease}.login-form .inner:hover{box-shadow:0 15px 50px rgba(0,0,0,.12),0 5px 15px rgba(0,0,0,.06)}.login-form form{margin:0}.login-form fieldset{border:none;padding:0;margin:0}.login-form .pure-control-group{margin-bottom:1.75rem}.login-form .pure-control-group:last-of-type{margin-bottom:0;margin-top:2rem}.login-form label{display:block;margin-bottom:.5rem;font-weight:600;font-size:.9rem;color:var(--color-text);letter-spacing:.01em}.login-form input[type=password]{width:100%;padding:.875rem 1rem;border:2px solid var(--color-grey-800);border-radius:8px;font-size:1rem;background:var(--color-background-input);color:var(--color-text-input);transition:all .2s ease;box-sizing:border-box}.login-form input[type=password]:focus{outline:none;border-color:var(--color-link);box-shadow:0 0 0 3px rgba(27,152,248,.1);transform:translateY(-1px)}.login-form input[type=password]::placeholder{color:var(--color-text-input-placeholder)}.login-form button[type=submit]{width:100%;padding:.875rem 1.5rem;font-size:1rem;font-weight:600;border-radius:8px;border:none;background:var(--color-background-button-primary);color:var(--color-text-button);cursor:pointer;transition:all .2s ease;box-shadow:0 2px 8px rgba(27,152,248,.2)}.login-form button[type=submit]:hover{box-shadow:0 4px 12px rgba(27,152,248,.3);background:#06c}.login-form button[type=submit]:active{transform:translateY(0);box-shadow:0 2px 4px rgba(27,152,248,.2)}.content-main>ul.messages{position:fixed;top:120px;left:50%;transform:translateX(-50%);list-style:none;padding:0;margin:0;z-index:1000;min-width:300px;max-width:500px}.content-main>ul.messages li{padding:1rem 1.25rem;border-radius:8px;font-size:.95rem;line-height:1.5;font-weight:500;box-shadow:0 4px 12px rgba(0,0,0,.15);animation:slideDown .3s ease-out;border:2px solid rgba(0,0,0,0)}.content-main>ul.messages li.error{background:#fee;border:2px solid #ef4444;color:#991b1b;font-weight:600}.content-main>ul.messages li.success{background:#f0fdf4;border:2px solid #10b981;color:#166534}.content-main>ul.messages li.info,.content-main>ul.messages li.message{background:#eff6ff;border:2px solid #3b82f6;color:#1e40af}@keyframes slideDown{from{opacity:0;transform:translateY(-20px)}to{opacity:1;transform:translateY(0)}}html[data-darkmode=true] .login-form .inner{box-shadow:0 10px 40px rgba(0,0,0,.4),0 2px 8px rgba(0,0,0,.2)}html[data-darkmode=true] .login-form .inner:hover{box-shadow:0 15px 50px rgba(0,0,0,.5),0 5px 15px rgba(0,0,0,.3)}html[data-darkmode=true] .login-form input[type=password]{border-color:var(--color-grey-400)}html[data-darkmode=true] .login-form input[type=password]:focus{border-color:var(--color-link)}html[data-darkmode=true] .content-main>ul.messages li{box-shadow:0 4px 12px rgba(0,0,0,.4)}html[data-darkmode=true] .content-main>ul.messages li.error{background:#4a1d1d;border-color:#ef4444;color:#fca5a5}html[data-darkmode=true] .content-main>ul.messages li.success{background:#1a3a2a;border-color:#10b981;color:#86efac}html[data-darkmode=true] .content-main>ul.messages li.info,html[data-darkmode=true] .content-main>ul.messages li.message{background:#1e3a5f;border-color:#3b82f6;color:#93c5fd}@media only screen and (max-width: 768px){.login-form{min-height:auto;padding:1rem .5rem;padding-top:5rem}.login-form .inner{padding:2rem 1.5rem;border-radius:12px}.content-main>ul.messages{top:70px;left:10px;right:10px;transform:none;min-width:auto}}body.wrapped-tabs .tabs ul{grid-template-columns:repeat(auto-fill, minmax(var(--tab-width, 180px), 1fr));grid-auto-flow:row;grid-auto-columns:unset;gap:0;column-gap:5px}body.wrapped-tabs .tabs ul li{border-radius:0}.tabs ul{margin:0px;padding:0px;display:grid;grid-auto-flow:column;grid-auto-columns:max-content;gap:5px;list-style:none}.tabs ul li{white-space:nowrap;color:var(--color-text-tab);border-top-left-radius:5px;border-top-right-radius:5px;background-color:var(--color-background-tab)}.tabs ul li:not(.active):hover{background-color:var(--color-background-tab-hover)}.tabs ul li.active,.tabs ul li :target{background-color:var(--color-background)}.tabs ul li.active a,.tabs ul li :target a{color:var(--color-text-tab-active);font-weight:bold}.tabs ul li a{display:block;padding:.7em;color:var(--color-text-tab)}.stab-shell{display:flex;align-items:stretch;background:var(--color-background);border:1px solid rgba(0,0,0,.08);border-radius:8px;overflow:hidden;box-shadow:0 2px 8px rgba(0,0,0,.05);margin-bottom:1.5rem}.stab-nav{display:flex;flex-direction:column;width:11rem;flex-shrink:0;padding:.75rem 0;gap:1px;background:linear-gradient(180deg, rgba(0, 0, 0, 0.03) 0%, rgba(0, 0, 0, 0.05) 100%);border-right:1px solid rgba(0,0,0,.07)}.stab-btn{position:relative;display:flex;align-items:center;gap:.5rem;padding:.65rem .9rem .65rem 1rem;width:100%;background:none;border:none;border-left:3px solid rgba(0,0,0,0);border-radius:0;cursor:pointer;font:inherit;color:var(--color-text);text-align:left;opacity:.65;transition:background .12s ease,opacity .12s ease,border-color .12s ease,color .12s ease}.stab-btn:hover{background:rgba(0,0,0,.04);opacity:.85}.stab-btn.active{border-left-color:var(--color-menu-accent);background:rgba(237,89,0,.07);color:var(--color-menu-accent);font-weight:700;opacity:1}.stab-btn .stab-icon{display:inline-flex;align-items:center;justify-content:center;width:1.1rem;flex-shrink:0;opacity:.8}.stab-btn .stab-icon svg{width:.95rem;height:.95rem;stroke:currentColor;fill:none}.stab-body{flex:1;min-width:0;padding:1.4rem 1.6rem;overflow-x:hidden}.stab-pane{visibility:hidden;height:0;overflow:hidden}.stab-pane.active{visibility:visible;height:auto;overflow:visible;animation:stab-enter .16s ease both}@keyframes stab-enter{from{opacity:0;transform:translateY(5px)}to{opacity:1;transform:translateY(0)}}.stab-overview-hero{margin-bottom:1.5rem}.stab-overview-hero h3{margin:0 0 .3rem;font-size:1.05rem}.stab-overview-hero .stab-overview-glyph{color:var(--color-menu-accent);margin-right:.2rem}.stab-overview-hero .stab-overview-glyph svg{width:1.1rem;height:1.1rem;stroke:currentColor;fill:none;vertical-align:-0.15em}.stab-overview-hero p{margin:0;font-size:.88rem;color:var(--color-text-input-description);max-width:44rem;line-height:1.55}.stab-overview-features{display:flex;flex-direction:column;gap:.7rem;margin-bottom:1.6rem}.stab-overview-feature{display:flex;gap:.85rem;align-items:flex-start;padding:.75rem 1rem;border-radius:6px;background:rgba(0,0,0,.022);border:1px solid rgba(0,0,0,.05);transition:background .12s ease}.stab-overview-feature:hover{background:rgba(0,0,0,.035)}.stab-overview-feature .stab-overview-icon{width:1.6rem;flex-shrink:0;padding-top:.05rem;opacity:.7;display:flex;justify-content:center}.stab-overview-feature .stab-overview-icon svg{width:1.3rem;height:1.3rem;stroke:currentColor;fill:none}.stab-overview-feature .stab-overview-text>strong{display:block;margin-bottom:.2rem}.stab-overview-feature .stab-overview-text p{color:var(--color-text-input-description)}.stab-overview-disclaimer{display:flex;gap:.75rem;align-items:flex-start;margin:0 0 1.1rem;padding:.85rem 1rem;border-radius:6px;border:1px solid rgba(211,136,0,.35);background:rgba(255,180,0,.07)}.stab-overview-disclaimer .stab-disclaimer-icon{flex-shrink:0;padding-top:.05rem;color:#c07800}.stab-overview-disclaimer .stab-disclaimer-icon svg{width:1.2rem;height:1.2rem;stroke:currentColor;fill:none}.stab-overview-disclaimer .stab-disclaimer-body{font-size:.85rem;line-height:1.55}.stab-overview-disclaimer .stab-disclaimer-body>strong{display:block;margin-bottom:.35rem;color:#8a5500;font-size:.87rem}.stab-overview-disclaimer .stab-disclaimer-body p{margin:0 0 .45rem;color:var(--color-text-input-description)}.stab-overview-disclaimer .stab-disclaimer-body ul{margin:0 0 .6rem;padding-left:1.25rem;color:var(--color-text-input-description)}.stab-overview-disclaimer .stab-disclaimer-body ul li{margin-bottom:.2rem}.stab-overview-disclaimer .stab-disclaimer-check{display:flex;gap:.5rem;align-items:flex-start;cursor:pointer;font-size:.82rem;color:var(--color-text-input-description);font-weight:600}.stab-overview-disclaimer .stab-disclaimer-check input[type=checkbox]{flex-shrink:0;margin-top:.18rem;cursor:pointer}.stab-overview-cta{margin-top:.4rem;display:flex;align-items:center;gap:.8rem;flex-wrap:wrap}.stab-configured-badge{display:inline-flex;align-items:center;gap:.4rem;padding:.35rem .75rem;background:rgba(39,174,96,.09);border:1px solid rgba(39,174,96,.28);border-radius:4px;color:#2a7a4e;font-size:.82rem;font-weight:600}.stab-section-title{font-size:.72rem;font-weight:700;letter-spacing:.07em;text-transform:uppercase;opacity:.45;margin:1.4rem 0 .6rem}.stab-section-title:first-child{margin-top:0}@media(max-width: 600px){.stab-shell{flex-direction:column;min-height:unset}.stab-nav{width:100%;border-right:none;border-bottom:1px solid rgba(0,0,0,.07);padding:.4rem 0}.stab-body{padding-left:1rem}}.llm-usage-grid{display:grid;grid-template-columns:repeat(auto-fit, minmax(12rem, 1fr));gap:.9rem;margin-bottom:1.4rem}.llm-stat-card{padding:1rem 1.1rem .85rem;border-radius:7px;background:rgba(0,0,0,.025);border:1px solid rgba(0,0,0,.07)}.llm-stat-card .llm-stat-label{font-size:.7rem;font-weight:700;letter-spacing:.07em;text-transform:uppercase;opacity:.4;margin-bottom:.4rem}.llm-stat-card .llm-stat-value{font-size:1.65rem;font-weight:700;letter-spacing:-0.02em;line-height:1;margin-bottom:.25rem}.llm-stat-card .llm-stat-sub{font-size:.79rem;opacity:.5}.llm-stat-card .llm-stat-budget-text{font-size:.77rem;opacity:.55;margin-top:.3rem}.llm-stat-bar-wrap{height:4px;border-radius:2px;background:rgba(0,0,0,.1);overflow:hidden;margin-top:.65rem}.llm-stat-bar-fill{height:100%;border-radius:2px;transition:width .5s ease}.llm-stat-bar-fill.bar-ok{background:#27ae60}.llm-stat-bar-fill.bar-warn{background:#e67e22}.llm-stat-bar-fill.bar-over{background:#c0392b}.llm-usage-settings{border-top:1px solid rgba(0,0,0,.07);padding-top:.9rem;display:flex;flex-direction:column;gap:.65rem}.llm-usage-row{display:flex;align-items:baseline;gap:.9rem;flex-wrap:wrap}.llm-usage-row .llm-usage-row-label{font-size:.82rem;font-weight:600;opacity:.6;min-width:12rem;flex-shrink:0}.llm-usage-row .llm-usage-row-value{display:flex;align-items:baseline;gap:.5rem;flex-wrap:wrap;font-size:.88rem}.llm-field-hint{font-size:.8rem;opacity:.55}.llm-env-badge{font-size:.79rem;opacity:.6}.llm-budget-alert{color:#c0392b;font-weight:600;font-size:.88rem;margin:0 0 1rem}.llm-no-usage{opacity:.5;font-style:italic;font-size:.88rem;margin-bottom:1rem}html[data-darkmode=true] .stab-shell{border-color:hsla(0,0%,100%,.07);box-shadow:0 2px 8px rgba(0,0,0,.25)}html[data-darkmode=true] .stab-nav{background:linear-gradient(180deg, rgba(255, 255, 255, 0.025) 0%, rgba(255, 255, 255, 0.04) 100%);border-right-color:hsla(0,0%,100%,.07)}html[data-darkmode=true] .stab-btn:hover{background:hsla(0,0%,100%,.05)}html[data-darkmode=true] .stab-btn.active{background:rgba(237,89,0,.12)}html[data-darkmode=true] .stab-overview-feature{background:hsla(0,0%,100%,.025);border-color:hsla(0,0%,100%,.05)}html[data-darkmode=true] .stab-overview-feature:hover{background:hsla(0,0%,100%,.04)}html[data-darkmode=true] .stab-configured-badge{background:rgba(39,174,96,.1);border-color:rgba(39,174,96,.22);color:#5db880}html[data-darkmode=true] .stab-overview-disclaimer{border-color:rgba(255,190,50,.22);background:rgba(255,180,0,.05)}html[data-darkmode=true] .stab-overview-disclaimer .stab-disclaimer-icon{color:#c9963a}html[data-darkmode=true] .stab-overview-disclaimer .stab-disclaimer-body>strong{color:#c9a050}html[data-darkmode=true] .llm-stat-card{background:hsla(0,0%,100%,.03);border-color:hsla(0,0%,100%,.07)}html[data-darkmode=true] .llm-stat-bar-wrap{background:hsla(0,0%,100%,.1)}html[data-darkmode=true] .llm-usage-settings{border-top-color:hsla(0,0%,100%,.07)}body,.pure-table,.pure-table thead,.pure-table td,.pure-table th,.pure-form input,.pure-form textarea,.pure-form select,.edit-form .inner,.pure-menu-horizontal,footer,.sticky-tab,#diff-jump,.button-tag,#new-watch-form,#new-watch-form input:not(.pure-button),code,.messages li,#checkbox-operations,.inline-warning,a,.watch-controls img{transition:color .4s ease,background-color .4s ease,background .4s ease,border-color .4s ease,box-shadow .4s ease}body{color:var(--color-text);background:var(--color-background-page);font-family:Helvetica Neue,Helvetica,Lucida Grande,Arial,Ubuntu,Cantarell,Fira Sans,sans-serif}.app{display:flex;align-items:stretch;min-height:100vh}.app-main{flex:1 1 auto;min-width:0;display:flex;flex-direction:column;gap:.55rem}.content-wrapper{display:flex;width:100%;max-width:100%;position:relative;align-items:flex-start}@media only screen and (max-width: 980px){.content-wrapper{flex-direction:column}}.content-main{flex:1 1 auto;width:100%;min-width:0;display:flex;flex-direction:column;align-items:center}@media only screen and (min-width: 980px){.content-main{flex-direction:column}}.visually-hidden{clip:rect(0 0 0 0);clip-path:inset(50%);height:1px;overflow:hidden;position:absolute;white-space:nowrap;width:1px}.status-icon{display:inline-block;height:1rem;vertical-align:middle}a{text-decoration:none;color:var(--color-link)}#search-result-info{color:#fff}button.toggle-button{vertical-align:middle;background:rgba(0,0,0,0);border:none;cursor:pointer;color:var(--color-text-menu-heading)}button.toggle-button svg{fill:currentColor}button.toggle-button svg.feather{fill:none;stroke:currentColor}button.toggle-button .icon-light{display:block}body.spinner-active #pure-menu-horizontal-spinner{animation:gradient 1s ease infinite}@keyframes gradient{0%{background-position:0% 50%}50%{background-position:100% 50%}100%{background-position:0% 50%}}#cdio-logo{color:var(--color-white);text-transform:uppercase}.pure-menu-link{color:var(--color-text-menu-link)}.pure-menu-link:hover{background-color:var(--color-background-menu-link-hover);color:var(--color-text-menu-link-hover)}.tab-pane-inner{scroll-margin-top:200px}section.content{padding-bottom:1em;padding-left:.55rem;padding-right:.55rem;flex-direction:column;display:flex;align-items:center;justify-content:flex-start}details summary{cursor:pointer;font-weight:600;color:var(--color-link);width:fit-content}details summary:hover{text-decoration:underline}code{background:var(--color-background-code);color:var(--color-text)}.inline-tag,.restock-label,.tracking-ldjson-price-data,.watch-tag-list,.processor-badge{white-space:nowrap;border-radius:5px;padding:2px 5px;margin-right:4px}.processor-badge{font-weight:900;text-decoration:none}.processor-badge:hover{text-decoration:none;opacity:.8;cursor:pointer}.processor-badge.active{outline:2px solid var(--color-link);outline-offset:1px}.watch-tag-list{color:var(--color-white);background:var(--color-text-watch-tag-list);text-decoration:none}.watch-tag-list:hover{text-decoration:none;opacity:.8;cursor:pointer}.watch-tag-list:visited{color:var(--color-white)}body:after{content:"";background:linear-gradient(130deg, var(--color-background-gradient-first), var(--color-background-gradient-second) 41.07%, var(--color-background-gradient-third) 84.05%)}body:after,body:before{display:block;position:fixed;top:0;left:0;width:100%;height:100vh;z-index:-1}body::after{opacity:.91}body::before{content:""}.button-small{font-size:85%}.button-xsmall{font-size:70%}.fetch-error{padding-top:1em;font-size:80%;max-width:400px;display:block}.pure-button-primary,a.pure-button-primary,.pure-button-selected,a.pure-button-selected{background-color:var(--color-background-button-primary)}.button-secondary{color:var(--color-text-button);border-radius:4px;text-shadow:0 1px 1px rgba(0,0,0,.2)}.button-success{background:var(--color-background-button-success)}.button-tag{background:var(--color-background-button-tag);color:var(--color-text-button);font-size:75%;border-radius:6px;margin-right:4px;margin-bottom:1px}.button-tag.active{background:var(--color-background-button-tag-active);font-weight:bold}.button-error{background:var(--color-background-button-error);color:var(--color-text-button-error)}.button-warning{background:var(--color-background-button-warning);color:var(--color-text-button-warning)}.button-secondary{background:var(--color-background-button-secondary)}.button-cancel{background:var(--color-background-button-cancel)}.messages li{list-style:none;padding:1em;border-radius:10px;color:var(--color-text-messages);font-weight:bold}.messages li.message{background:var(--color-background-messages-message)}.messages li.error{background:var(--color-background-messages-error)}.messages li.notice{background:var(--color-background-messages-notice)}.messages.with-share-link>*:hover{cursor:pointer}label:hover{cursor:pointer}.grey-form-border{border:1px solid var(--color-border-notification);padding:.5rem;border-radius:5px}#token-table.pure-table td,#token-table.pure-table th{font-size:80%}.pure-form input[type=text].transparent-field{background-color:var(--color-background-new-watch-input-transparent) !important;color:var(--color-white) !important;border:1px solid hsla(0,0%,100%,.2) !important;box-shadow:none !important;-webkit-box-shadow:none !important}.pure-form input[type=text].transparent-field::placeholder{opacity:.5;color:hsla(0,0%,100%,.7);font-weight:lighter}#new-watch-form{background:var(--color-background-new-watch-form);padding:1em;border-radius:10px;max-width:100%}#new-watch-form #url::placeholder{font-weight:bold}#new-watch-form input{display:inline-block}#new-watch-form input:not(.pure-button){background-color:var(--color-background-new-watch-input);color:var(--color-text-new-watch-input)}#new-watch-form .label{display:none}#new-watch-form legend{color:var(--color-text-legend);font-weight:bold}@media only screen and (min-width: 760px){#new-watch-form #watch-add-wrapper-zone{display:flex;gap:.3rem;flex-direction:row;min-width:70vw}}#new-watch-form #watch-add-wrapper-zone>span{flex-grow:0}#new-watch-form #watch-add-wrapper-zone>span input{width:100%;padding-right:1em}#new-watch-form #watch-add-wrapper-zone>span:first-child{flex-grow:1}@media only screen and (max-width: 760px){#new-watch-form #watch-add-wrapper-zone #url{width:100%}}#new-watch-form #watch-group-tag{font-size:.9rem;padding:.3rem;display:flex;align-items:center;gap:.5rem;color:var(--color-white)}#new-watch-form #watch-group-tag label,#new-watch-form #watch-group-tag input{margin:0}#new-watch-form #watch-group-tag input{flex:1}#diff-col{padding-left:40px}#diff-jump{position:fixed;left:0px;top:120px;background:var(--color-background);padding:10px;border-top-right-radius:5px;border-bottom-right-radius:5px;box-shadow:1px 1px 4px var(--color-shadow-jump)}#diff-jump a{color:var(--color-link);cursor:pointer;-moz-user-select:none;-webkit-user-select:none;-ms-user-select:none;user-select:none;-o-user-select:none}footer{padding:10px;background:var(--color-background);color:var(--color-text-footer);text-align:center}#feed-icon{vertical-align:middle}#new-version-text a{color:var(--color-link-new-version)}.watch-controls{color:#f8321b}.watch-controls .state-on img{opacity:.8}.watch-controls img{opacity:.2}.watch-controls img:hover{transition:opacity .3s;opacity:.8}.monospaced-textarea textarea{width:100%;font-family:monospace;white-space:pre;overflow-wrap:normal;overflow-x:auto}.pure-form fieldset{padding-top:0px}.pure-form fieldset ul{padding-bottom:0px;margin-bottom:0px}.pure-form .pure-control-group,.pure-form .pure-group,.pure-form .pure-controls{padding-bottom:1em}.pure-form .pure-control-group div,.pure-form .pure-group div,.pure-form .pure-controls div{margin:0px}.pure-form .pure-control-group .checkbox>*,.pure-form .pure-group .checkbox>*,.pure-form .pure-controls .checkbox>*{display:inline;vertical-align:middle}.pure-form .pure-control-group .checkbox>label,.pure-form .pure-group .checkbox>label,.pure-form .pure-controls .checkbox>label{padding-left:5px}.pure-form .pure-control-group legend,.pure-form .pure-group legend,.pure-form .pure-controls legend{color:var(--color-text-legend)}.pure-form .error input{background-color:var(--color-error-input)}.pure-form ul.errors{padding:.5em .6em;border:1px solid var(--color-error-list);border-radius:4px;vertical-align:middle;-webkit-box-sizing:border-box;box-sizing:border-box}.pure-form ul.errors li{margin-left:1em;color:var(--color-error-list)}.pure-form label{font-weight:bold}.pure-form textarea{width:100%}.pure-form .inline-radio ul{margin:0px;list-style:none}.pure-form .inline-radio ul li{display:flex;align-items:center;gap:1em}@media only screen and (max-width: 760px),(min-device-width: 768px)and (max-device-width: 980px){.edit-form{padding:.5em;margin:0}#nav-menu{overflow-x:scroll}}@media only screen and (max-width: 760px),(min-device-width: 768px)and (max-device-width: 980px){input[type=text]{width:100%}}.pure-table{border-color:var(--color-border-table-cell)}.pure-table thead{background-color:var(--color-background-table-thead);color:var(--color-text);border-bottom:1px solid var(--color-background-table-thead)}.pure-table td,.pure-table th{border-left-color:var(--color-border-table-cell)}.pure-form input[type=color],.pure-form input[type=date],.pure-form input[type=datetime-local],.pure-form input[type=datetime],.pure-form input[type=email],.pure-form input[type=month],.pure-form input[type=number],.pure-form input[type=password],.pure-form input[type=search],.pure-form input[type=tel],.pure-form input[type=text],.pure-form input[type=time],.pure-form input[type=url],.pure-form input[type=week],.pure-form select,.pure-form textarea{border:var(--color-border-input);box-shadow:inset 0 1px 3px var(--color-shadow-input);background-color:var(--color-background-input);color:var(--color-text-input)}.pure-form input[type=color]:active,.pure-form input[type=date]:active,.pure-form input[type=datetime-local]:active,.pure-form input[type=datetime]:active,.pure-form input[type=email]:active,.pure-form input[type=month]:active,.pure-form input[type=number]:active,.pure-form input[type=password]:active,.pure-form input[type=search]:active,.pure-form input[type=tel]:active,.pure-form input[type=text]:active,.pure-form input[type=time]:active,.pure-form input[type=url]:active,.pure-form input[type=week]:active,.pure-form select:active,.pure-form textarea:active{background-color:var(--color-background-input)}input::placeholder,textarea::placeholder{color:var(--color-text-input-placeholder)}.m-d{min-width:100%}@media only screen and (min-width: 761px){.m-d{min-width:80%}}.pure-form-stacked>div:first-child{display:block}.tab-pane-inner{padding:0px}.tab-pane-inner:not(:target){display:none}.tab-pane-inner:target{display:block}.beta-logo{height:50px;right:-3px;top:-3px;position:absolute}#selector-header{padding-bottom:1em}.edit-form{max-width:95%}.edit-form .box-wrap{position:relative}.edit-form .inner{background:var(--color-background);padding:1.1rem}.edit-form #actions{display:block;background:var(--color-background)}.edit-form #actions .pure-control-group{display:flex;gap:.625em;flex-wrap:wrap}.edit-form .pure-form-message-inline{padding-left:0;color:var(--color-text-input-description)}.edit-form .pure-form-message-inline code{font-size:.875em}.border-fieldset{border:1px solid #ccc;padding:1rem;border-radius:5px;margin-bottom:1rem}.border-fieldset h3{margin-top:0}.border-fieldset fieldset:last-of-type{padding-bottom:0}.border-fieldset fieldset:last-of-type .pure-control-group{padding-bottom:0}ul{padding-left:1em;padding-top:0px;margin-top:4px}.time-check-widget tr{display:inline}.time-check-widget tr input[type=number]{width:5em}@media only screen and (max-width: 760px){.time-check-widget tbody{display:grid;grid-template-columns:auto 1fr auto 1fr;gap:.625em .3125em;align-items:center}.time-check-widget tr{display:contents}.time-check-widget tr th{text-align:right;padding-right:5px}.time-check-widget tr input[type=number]{width:100%;max-width:5em}}#webdriver_delay{width:5em}#api-key:hover{cursor:pointer}#api-key-copy{color:var(--color-api-key)}.button-green{background-color:var(--color-background-button-green)}.button-red{background-color:var(--color-background-button-red)}.noselect{-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}[type=checkbox],[type=radio]{width:17px;height:17px;border-radius:5px;cursor:pointer}.inline-warning{border:1px solid var(--color-border-warning);padding:.5rem;border-radius:5px;color:var(--color-warning)}.inline-warning>span{display:inline-block;vertical-align:middle}.inline-warning img.inline-warning-icon{display:inline;height:26px;vertical-align:middle}.tracking-ldjson-price-data{background-color:var(--color-background-button-green);color:#000;opacity:.6}.ldjson-price-track-offer{font-weight:bold;font-style:italic}.ldjson-price-track-offer a.pure-button{border-radius:3px;padding:3px;background-color:var(--color-background-button-green)}.price-follow-tag-icon{display:inline-block;height:.8rem;vertical-align:middle}#quick-watch-processor-type ul#processor{color:#fff;padding-left:0px}#quick-watch-processor-type ul#processor li{list-style:none;font-size:.9rem;display:grid;grid-template-columns:auto 1fr;align-items:center;gap:.5rem;margin-bottom:.5rem}#quick-watch-processor-type label,#quick-watch-processor-type input{padding:0;margin:0}.restock-label.in-stock{background-color:#7a0cc5;color:#fff}.restock-label.not-in-stock{background-color:var(--color-background-button-cancel);color:#777}.restock-label.error{background-color:var(--color-background-button-error);color:#fff;opacity:.7}.restock-label.price{border:1px solid var(--color-background-button-cancel)}.restock-label svg{vertical-align:middle}.price-change{white-space:nowrap;font-weight:700;font-size:90%;margin-left:4px;vertical-align:middle}.price-change.down{color:var(--color-background-button-green)}.price-change.up{color:var(--color-background-button-error)}#chrome-extension-link{padding:9px;border:1px solid var(--color-grey-800);border-radius:10px;vertical-align:middle}#chrome-extension-link img{height:21px;padding:2px;vertical-align:middle}#realtime-conn-error{position:fixed;bottom:0;left:0;background:var(--color-warning);padding:10px;font-size:.8rem;color:#fff;opacity:.8;z-index:100}#bottom-horizontal-offscreen{position:fixed;bottom:0;left:0;right:0;width:100%;min-height:50px;max-height:50vh;background:hsla(0,0%,100%,.7215686275);border-top:1px solid var(--color-border-table-cell);padding:10px;box-shadow:0 -2px 10px rgba(0,0,0,.2);z-index:100;overflow-y:auto;transition:opacity .3s ease-in-out;scroll-margin-bottom:10px;display:flex;justify-content:center;align-items:center}ul#highlightSnippetActions{list-style:none}ul#highlightSnippetActions li{display:inline-block}@media only screen and (max-width: 768px){.box{padding:.25rem !important}}.box{color:var(--color-white);border-width:1px;border-style:dashed;border-color:hsla(0,0%,100%,.25);border-image:initial;background:hsla(0,0%,100%,.04);border-radius:var(--common-round-border);padding:1.1rem}header{color:var(--color-white)}#heart-us svg{display:inline-block;vertical-align:middle;cursor:pointer;width:1.4rem} +.header{color:var(--color-text-menu-heading)}.header a{color:var(--color-text-menu-heading)}.header::after{content:"";position:absolute;left:0;right:0;bottom:0;height:1px;pointer-events:none;background:linear-gradient(to right, rgba(200, 200, 200, 0.02), rgba(200, 200, 200, 0.6))}ul#top-right-menu{list-style:none;margin-left:auto;padding:0;margin-top:0;margin-right:0;margin-bottom:0;display:grid;gap:1.1rem;grid-auto-flow:column;grid-auto-columns:max-content;align-items:center}ul#top-right-menu .toggle-button{padding:0}.current-diff-url{flex:1 1 auto;min-width:0;overflow:hidden;white-space:nowrap;text-align:left;margin:0 .55rem;-webkit-mask-image:linear-gradient(to right, #000 calc(100% - 2.5em), transparent);mask-image:linear-gradient(to right, #000 calc(100% - 2.5em), transparent)}.current-diff-url span{overflow:visible;white-space:nowrap}.pure-menu-horizontal{padding:.55rem;display:flex;justify-content:space-between;align-items:center}.pure-menu-horizontal svg{height:1.3rem}.fi{height:1.3rem;cursor:pointer}#pure-menu-horizontal-spinner{height:2px;background:linear-gradient(-75deg, #ff6000, #ff8f00, #ffdd00, #ed0000);background-size:400% 400%;animation:gradient 200s ease infinite;opacity:.8;position:fixed;bottom:0;left:0;width:100%;z-index:100;pointer-events:none}.status-pill{display:inline-flex;align-items:center;gap:8px;height:30px;padding:0 12px;border-radius:var(--common-round-border);border:1px solid hsla(0,0%,100%,.25);background:hsla(0,0%,100%,.1);color:var(--color-text-menu-heading);font-size:.78rem;font-weight:600;white-space:nowrap;text-decoration:none}.status-pill:hover{background:hsla(0,0%,100%,.18)}.status-pill .live-dot{width:8px;height:8px;border-radius:50%;background:#42dd53;box-shadow:0 0 0 3px rgba(66,221,83,.3);animation:status-pill-pulse 2s infinite}.status-pill.paused .live-dot{background:#e8a33d;box-shadow:0 0 0 3px rgba(232,163,61,.3);animation:none}.status-pill .action-icon{width:16px;height:16px}.status-pill.muted{opacity:.8}.status-pill.muted .action-icon{color:#e8a33d}@keyframes status-pill-pulse{0%,100%{opacity:1}50%{opacity:.4}}.menu-pop-wrap{position:relative}.icon-btn{display:inline-flex;align-items:center;justify-content:center;width:36px;height:36px;border:0;border-radius:var(--common-round-border);background:rgba(0,0,0,0);color:var(--color-text-menu-heading);cursor:pointer}.icon-btn svg{width:18px;height:18px;fill:none;stroke:currentColor}.icon-btn:hover{background:hsla(0,0%,100%,.14)}.menu-pop{display:none;position:absolute;top:calc(100% + 8px);right:0;min-width:220px;padding:6px;border:1px solid var(--color-border-table-cell);border-radius:12px;background:var(--color-background);box-shadow:0 18px 50px rgba(0,0,0,.18);z-index:80}.menu-pop.open{display:block}.menu-pop .mi{display:flex;align-items:center;gap:10px;width:100%;padding:9px 10px;border:0;border-radius:8px;background:rgba(0,0,0,0);color:var(--color-text);font-size:.85rem;text-align:left;text-decoration:none;white-space:nowrap;cursor:pointer}.menu-pop .mi:hover{background:var(--color-background-menu-link-hover)}.menu-pop .mi .ico{display:inline-flex;color:var(--color-text-input-description)}.menu-pop .mi .ico svg{width:16px;height:16px;fill:none;stroke:currentColor}.menu-pop .mi .right{margin-left:auto;font-size:.75rem;color:var(--color-text-input-description)}.top-menu-list .action-label{color:var(--color-text-menu-heading)}@media only screen and (max-width: 768px){.top-menu-list .action-label{display:none}}#inline-menu-extras-group{list-style:none;margin:0;padding:0;display:grid;gap:.55rem;grid-auto-flow:column;grid-auto-columns:max-content;align-items:center}@media only screen and (max-width: 980px){#nav-menu #menu-settings span{display:none}}:root{--body-main-text-size: 0.9rem;--color-white: #fff;--color-grey-50: #111;--color-grey-100: #262626;--color-grey-200: #333;--color-grey-300: #444;--color-grey-325: #555;--color-grey-350: #565d64;--color-grey-400: #666;--color-grey-500: #777;--color-grey-600: #999;--color-grey-700: #cbcbcb;--color-grey-750: #ddd;--color-grey-800: #e0e0e0;--color-grey-850: #eee;--color-grey-900: #f2f2f2;--color-black: #000;--color-dark-red: #a00;--color-light-red: #dd0000;--color-background-page: var(--color-grey-100);--color-background-gradient-first: #5ad8f7;--color-background-gradient-second: #2f50af;--color-background-gradient-third: #9150bf;--color-background: var(--color-white);--color-text: var(--color-grey-200);--color-link: #1b98f8;--color-menu-accent: #ed5900;--color-background-code: var(--color-grey-850);--color-error: var(--color-dark-red);--color-error-input: #ffebeb;--color-error-list: var(--color-light-red);--color-table-background: var(--color-background);--color-table-stripe: var(--color-grey-900);--watchlist-row-selected: #e3f0ff;--watchlist-row-hover: #f2f2f2;--color-text-tab: var(--color-white);--color-background-tab: rgba(255, 255, 255, 0.2);--color-background-tab-hover: rgba(255, 255, 255, 0.5);--color-text-tab-active: #222;--color-api-key: #0078e7;--color-background-button-primary: #0078e7;--color-background-button-green: #42dd53;--color-background-button-red: #dd4242;--color-background-button-success: rgb(28, 184, 65);--color-background-button-error: rgb(202, 60, 60);--color-text-button-error: var(--color-white);--color-background-button-warning: rgb(202, 60, 60);--color-text-button-warning: var(--color-white);--color-background-button-secondary: rgb(66, 184, 221);--color-background-button-cancel: rgb(200, 200, 200);--color-text-button: var(--color-white);--color-background-button-tag: rgb(99, 99, 99);--color-background-snapshot-age: #dfdfdf;--color-error-text-snapshot-age: var(--color-white);--color-error-background-snapshot-age: #ff0000;--color-background-button-tag-active: #9c9c9c;--color-text-messages: var(--color-white);--color-background-messages-message: rgba(255, 255, 255, .2);--color-background-messages-error: rgba(255, 1, 1, .5);--color-background-messages-notice: rgba(255, 255, 255, .5);--color-border-notification: #ccc;--color-background-checkbox-operations: rgba(0, 0, 0, 0.05);--color-warning: #ff3300;--color-border-warning: var(--color-warning);--color-text-legend: var(--color-white);--color-link-new-version: #e07171;--color-last-checked: #bbb;--color-text-footer: #444;--color-border-watch-table-cell: #eee;--color-text-watch-tag-list: rgba(231, 0, 105, 0.4);--color-background-new-watch-form: rgba(0, 0, 0, 0.05);--color-background-new-watch-input: var(--color-white);--color-background-new-watch-input-transparent: rgba(255, 255, 255, 0.1);--color-text-new-watch-input: var(--color-text);--color-border-input: var(--color-grey-500);--color-shadow-input: var(--color-grey-400);--color-background-input: var(--color-white);--color-text-input: var(--color-text);--color-text-input-description: var(--color-grey-500);--color-text-input-placeholder: var(--color-grey-600);--color-background-table-thead: var(--color-grey-800);--color-border-table-cell: var(--color-grey-700);--color-text-menu-heading: var(--color-white);--color-text-menu-link: var(--color-grey-500);--color-background-menu-link-hover: var(--color-grey-850);--color-text-menu-link-hover: var(--color-grey-300);--color-shadow-jump: var(--color-grey-500);--color-icon-github: var(--color-black);--color-watch-table-error: var(--color-dark-red);--color-watch-table-row-text: var(--color-grey-100);--color-table-line: #e7e9ee;--highlight-trigger-text-bg-color: #1b98f8;--highlight-ignored-text-bg-color: var(--color-grey-700);--highlight-blocked-text-bg-color: rgb(202, 60, 60);--color-sidebar-bg: rgba(255, 255, 255, 0.97);--color-sidebar-text: var(--color-text);--color-sidebar-shadow: 6px 0 28px rgba(0, 0, 0, 0.18);--color-sidebar-item-hover-bg: rgba(0, 0, 0, 0.06);--color-sidebar-item-active-bg: rgba(0, 0, 0, 0.10);--common-round-border: 8px}html[data-darkmode=true]{--color-link: #59bdfb;--color-text: var(--color-white);--color-table-line: #262c37;--color-background-gradient-first: #3f90a5;--color-background-gradient-second: #1e316c;--color-background-gradient-third: #4d2c64;--color-background-new-watch-input: var(--color-grey-100);--color-background-new-watch-input-transparent: var(--color-grey-100);--color-text-new-watch-input: var(--color-text);--color-background-table-thead: var(--color-grey-200);--color-table-background: var(--color-grey-300);--color-table-stripe: var(--color-grey-325);--watchlist-row-selected: #1e3a5f;--watchlist-row-hover: #2a2a2a;--color-background: var(--color-grey-300);--color-text-menu-heading: var(--color-grey-850);--color-text-menu-link: var(--color-grey-800);--color-border-table-cell: var(--color-grey-400);--color-text-tab-active: var(--color-text);--color-border-input: var(--color-grey-400);--color-shadow-input: var(--color-grey-50);--color-background-input: var(--color-grey-350);--color-text-input-description: var(--color-grey-600);--color-text-input-placeholder: var(--color-grey-600);--color-text-watch-tag-list: rgba(250, 62, 146, 0.4);--color-background-code: var(--color-grey-200);--color-background-tab: rgba(0, 0, 0, 0.2);--color-background-tab-hover: rgba(0, 0, 0, 0.5);--color-background-snapshot-age: var(--color-grey-200);--color-shadow-jump: var(--color-grey-200);--color-icon-github: var(--color-white);--color-watch-table-error: var(--color-light-red);--color-watch-table-row-text: var(--color-grey-800);--color-sidebar-bg: rgba(8, 10, 14, 0.97);--color-sidebar-text: var(--color-white);--color-sidebar-shadow: 6px 0 28px rgba(0, 0, 0, 0.45);--color-sidebar-item-hover-bg: rgba(255, 255, 255, 0.06);--color-sidebar-item-active-bg: rgba(255, 255, 255, 0.10)}html[data-darkmode=true] .icon-spread{filter:hue-rotate(-10deg) brightness(1.5)}html[data-darkmode=true] .watch-table .title-col a[target=_blank]::after,html[data-darkmode=true] .watch-table .current-diff-url::after{filter:invert(0.5) hue-rotate(10deg) brightness(2)}html[data-darkmode=true] .watch-table .status-browsersteps{filter:invert(0.5) hue-rotate(10deg) brightness(1.5)}html[data-darkmode=true] .watch-table .watch-controls .state-off svg{opacity:.3}html[data-darkmode=true] .watch-table .watch-controls .state-on svg{opacity:1}html[data-darkmode=true] .watch-table .unviewed{color:#fff}html[data-darkmode=true] .watch-table .unviewed.error{color:var(--color-watch-table-error)}.arrow{border:solid var(--color-border-input);border-width:0 2px 2px 0;display:inline-block;padding:3px}.arrow.right{transform:rotate(-45deg);-webkit-transform:rotate(-45deg)}.arrow.left{transform:rotate(135deg);-webkit-transform:rotate(135deg)}.arrow.up,.arrow.asc{transform:rotate(-135deg);-webkit-transform:rotate(-135deg)}.arrow.down,.arrow.desc{transform:rotate(45deg);-webkit-transform:rotate(45deg)}#browser_steps th{display:none}#browser_steps li{list-style:decimal;padding:5px}#browser_steps li.browser-step-with-error{background-color:#ffd6d6;border-radius:4px}#browser_steps li:not(:first-child):hover{opacity:1}#browser_steps li .control{padding-left:5px;padding-right:5px}#browser_steps li .control a{font-size:70%}#browser_steps li.empty{padding:0px;opacity:.35}#browser_steps li.empty .control{display:none}#browser_steps li:hover{background:#eee}#browser_steps li>label{display:none}@media only screen and (min-width: 760px){#browser-steps .flex-wrapper{display:flex;flex-flow:row;height:70vh;font-size:80%}#browser-steps .flex-wrapper #browser-steps-ui{flex-grow:1;flex-shrink:1;flex-basis:0;background-color:#eee;border-radius:5px}#browser-steps-fieldlist{flex-grow:0;flex-shrink:0;flex-basis:auto;max-width:400px;padding-left:1rem;overflow-y:scroll}#browsersteps-selector-wrapper{height:100% !important}}#browsersteps-selector-wrapper{width:100%;overflow-y:scroll;position:relative;height:80vh}#browsersteps-selector-wrapper>img{position:absolute;max-width:100%}#browsersteps-selector-wrapper>canvas{position:relative;max-width:100%}#browsersteps-selector-wrapper>canvas:hover{cursor:pointer}#browsersteps-selector-wrapper .loader{position:absolute;left:50%;top:50%;transform:translate(-50%, -50%);z-index:100;max-width:350px;text-align:center}#browsersteps-selector-wrapper .spinner,#browsersteps-selector-wrapper .spinner:after{width:80px;height:80px;font-size:3px}#browsersteps-selector-wrapper #browsersteps-click-start{color:var(--color-grey-400)}#browsersteps-selector-wrapper #browsersteps-click-start:hover{cursor:pointer}ul#requests-extra_proxies{list-style:none}ul#requests-extra_proxies li>label{display:none}ul#requests-extra_proxies table tr{display:table-row}ul#requests-extra_proxies table tr input[type=text]{width:100%}@media only screen and (min-width: 1024px){ul#requests-extra_proxies table tr{display:inline}}#request label[for=proxy]{display:inline-block}body.proxy-check-active #request .proxy-check-details{font-size:80%;color:#555;display:block;padding-left:2em;max-width:500px}body.proxy-check-active #request .proxy-timing{font-size:80%;padding-left:1rem;color:var(--color-link)}#recommended-proxy{display:grid;gap:2rem;padding-bottom:1em}@media(min-width: 991px){#recommended-proxy{grid-template-columns:repeat(2, 1fr)}}#recommended-proxy>div{border:1px #aaa solid;border-radius:4px;padding:1em}#extra-proxies-setting{border:1px solid var(--color-grey-800);border-radius:4px;margin:1em;padding:1em}ul#requests-extra_browsers{list-style:none}ul#requests-extra_browsers li>label{display:none}ul#requests-extra_browsers table tr{display:table-row}ul#requests-extra_browsers table tr input[type=text]{width:100%}@media only screen and (min-width: 1280px){ul#requests-extra_browsers table tr{display:inline}ul#requests-extra_browsers table tr input[type=text]{width:100%}}#extra-browsers-setting{border:1px solid var(--color-grey-800);border-radius:4px;margin:1em;padding:1em}.pagination-page-info{text-transform:capitalize}.pagination.menu>*{display:inline-block}.pagination.menu li{display:inline-block}.pagination.menu a{padding:.65rem;margin:3px;border:none;background:#444;border-radius:2px;color:var(--color-text-button)}.pagination.menu a.disabled{display:none}.pagination.menu a.active{font-weight:bold;background:#888}.pagination.menu a:hover{background:#999}.spinner,.spinner:after{border-radius:50%;width:10px;height:10px}.spinner{margin:0px auto;font-size:3px;vertical-align:middle;display:inline-block;text-indent:-9999em;border-top:1.1em solid rgba(38,104,237,.2);border-right:1.1em solid rgba(38,104,237,.2);border-bottom:1.1em solid rgba(38,104,237,.2);border-left:1.1em solid #2668ed;-webkit-transform:translateZ(0);-ms-transform:translateZ(0);transform:translateZ(0);-webkit-animation:load8 1.1s infinite linear;animation:load8 1.1s infinite linear}@-webkit-keyframes load8{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@keyframes load8{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}.toggle-light-mode .icon-dark{display:none}html[data-darkmode=true] .toggle-light-mode .icon-light{display:none}html[data-darkmode=true] .toggle-light-mode .icon-dark{display:block}.pure-menu-link{padding:.5rem 1em;line-height:1.2rem}#menu-mute img,#menu-pause img{height:1.2rem}.pure-menu-item{height:initial}.pure-menu-item svg{height:1.2rem}.pure-menu-item *{vertical-align:middle}.pure-menu-item .bi-heart:hover{cursor:pointer}.pure-menu-item.active .pure-menu-link{background-color:var(--color-background-menu-link-hover);color:var(--color-text-menu-heading)}.pure-menu-item .action-icon{stroke:var(--color-text-menu-heading)}#overlay{opacity:.95;position:fixed;width:350px;max-width:100%;height:100%;top:50px;right:-350px;background-color:var(--color-table-stripe);border:1px solid #aaa;z-index:2;transform:translateX(0);transition:transform .5s ease}#overlay.visible{transform:translateX(-100%)}#overlay .content{font-size:.875rem;padding:1.1rem;max-width:400px;color:var(--color-watch-table-row-text)}#heartpath{height:1.6rem;width:1.6rem;z-index:100;transition:all ease .3s !important}#heartpath:hover{fill:red !important;transition:all ease .3s !important}.minitabs-wrapper{width:100%}.minitabs-wrapper>div[id]{padding:20px;border:1px solid #ccc;border-top:none}.minitabs-wrapper .minitabs-content{width:100%;display:flex}.minitabs-wrapper .minitabs-content>div{flex:1 1 auto;min-width:0;overflow:scroll}.minitabs-wrapper .minitabs{display:flex;border-bottom:1px solid #ccc}.minitabs-wrapper .minitab{flex:1;text-align:center;padding:12px 0;text-decoration:none;color:#333;background-color:#f1f1f1;border:1px solid #ccc;border-bottom:none;cursor:pointer;transition:background-color .3s}.minitabs-wrapper .minitab:hover{background-color:#ddd}.minitabs-wrapper .minitab.active{background-color:#fff;font-weight:bold}@media(min-width: 800px){body.preview-text-enabled #filters-and-triggers>div{display:flex;gap:20px;position:relative}}body.preview-text-enabled #edit-text-filter,body.preview-text-enabled #text-preview{flex:1;align-self:flex-start}body.preview-text-enabled #edit-text-filter #pro-tips{display:none}body.preview-text-enabled #text-preview{position:sticky;top:20px;padding-top:1rem;padding-bottom:1rem;display:block !important}body.preview-text-enabled #activate-text-preview{background-color:var(--color-grey-500)}body.preview-text-enabled .monospace-preview{background:var(--color-background-input);border:1px solid var(--color-grey-600);padding:1rem;color:var(--color-text-input);font-family:"Courier New",Courier,monospace;font-size:70%;word-break:break-word;white-space:pre-wrap}#activate-text-preview{right:0;position:absolute;z-index:3;box-shadow:1px 1px 4px var(--color-shadow-jump)}.cdio-table{width:100%;font-size:var(--body-main-text-size)}.cdio-table thead{text-transform:uppercase}.cdio-table thead a{color:var(--color-text)}.cdio-table td,.cdio-table th{vertical-align:middle;border:none}.cdio-table tbody tr{color:var(--color-watch-table-row-text);border-bottom:1px solid var(--color-table-line);background-color:var(--color-table-background)}.cdio-table tbody tr td{background-color:var(--color-table-background)}.cdio-table tbody tr:hover>td{background-color:var(--watchlist-row-hover)}.cdio-table-clip{border-radius:var(--common-round-border);overflow:hidden;margin-bottom:1.1rem}.seg{display:inline-flex;align-items:center;gap:2px;padding:2px;border:1px solid var(--color-border-table-cell);border-radius:var(--common-round-border);background:var(--color-background-table-thead)}.seg a,.seg button{display:inline-flex;align-items:center;gap:6px;border:0;background:rgba(0,0,0,0);color:var(--color-text-input-description);font-size:.8rem;font-weight:600;line-height:1.4;padding:5px 11px;border-radius:calc(var(--common-round-border) - 1px);text-decoration:none;cursor:pointer;white-space:nowrap}.seg a:hover,.seg button:hover{color:var(--color-text)}.seg a.active,.seg a:hover,.seg button.active,.seg button:hover{background:var(--color-background);color:var(--color-text);box-shadow:0 1px 2px rgba(0,0,0,.15)}html[data-darkmode=true] .seg a.active,html[data-darkmode=true] .seg button.active{background:var(--color-grey-400);box-shadow:0 1px 2px rgba(0,0,0,.5)}.seg-count{font-size:.62rem;line-height:1;font-weight:700;padding:2px 6px;border-radius:999px;background:var(--color-background-button-tag);color:var(--color-white)}.seg-count--unread{background:#3e95bb}.seg-count--error{background:var(--color-background-button-error)}.seg-count--deal{background:var(--color-background-button-success)}.cdio-btn{display:inline-flex;align-items:center;gap:6px;height:32px;padding:0 12px;border-radius:var(--common-round-border);border:1px solid var(--color-border-table-cell);background:var(--color-background);color:var(--color-text-input-description);font-family:inherit;font-size:.8rem;font-weight:600;line-height:1;white-space:nowrap;text-decoration:none;cursor:pointer;transition:border-color .12s ease,color .12s ease,background-color .12s ease}.cdio-btn:hover{border-color:var(--color-border-input);color:var(--color-text)}.cdio-btn:focus-visible{outline:2px solid var(--color-link);outline-offset:2px}.cdio-btn svg{width:15px;height:15px;stroke:currentColor}.cdio-btn img{height:15px;display:block}.cdio-btn--icon{width:32px;padding:0;justify-content:center}.cdio-btn--sm{height:26px;padding:0 9px;font-size:.72rem;gap:5px}.cdio-btn--sm svg{width:13px;height:13px}.cdio-btn--primary{background:var(--color-background-button-primary);border-color:var(--color-background-button-primary);color:var(--color-text-button)}.cdio-btn--primary:hover{background:var(--color-link);border-color:var(--color-link);color:var(--color-text-button)}.cdio-btn--danger{color:var(--color-background-button-error)}.cdio-btn--danger:hover{color:var(--color-background-button-error);border-color:var(--color-background-button-error)}.cdio-btn--warning{color:#d68a00}.cdio-btn--warning:hover{color:#d68a00;border-color:#d68a00}.watch-table tr:has(input[name=uuids]:checked)>td{background-color:var(--watchlist-row-selected)}.watch-table tbody tr:hover td.buttons *,.watch-table tbody tr:focus-within td.buttons *,.watch-table tbody tr:has(input[name=uuids]:checked) td.buttons *{opacity:1}.select-all-banner{margin:.4rem 0;padding:.5rem .75rem;border-radius:var(--common-round-border);background:var(--watchlist-row-selected);color:var(--color-watch-table-row-text);font-size:var(--body-main-text-size)}.select-all-banner button{margin-left:.5rem;vertical-align:baseline}.watch-controls svg{width:18px;height:18px;stroke:currentColor;fill:none;vertical-align:middle}#stats_row{display:flex;align-items:center;width:100%;color:#fff;font-size:.85rem}#stats_row>*{padding-bottom:.5rem}#stats_row .left{text-align:left}#stats_row .left .records-selected{margin-top:.25rem;opacity:.9}#stats_row .right{opacity:.5;transition:opacity .6s ease;margin-left:auto;text-align:right}body.has-queue #stats_row .right{opacity:1}#checkbox-operations{margin-bottom:.55rem;background:var(--color-background-new-watch-form);padding:1em;border-radius:10px;max-width:100%;position:sticky;top:20px;display:none}#checkbox-operations button{margin-bottom:3px;margin-top:3px;display:inline-flex;align-items:center}#checkbox-operations i,#checkbox-operations svg{width:14px;height:14px;stroke:#fff}body.watch-selection-active #checkbox-operations{display:block}.watch-table .checkbox-uuid{text-align:center}.watch-table .checkbox-uuid>*{vertical-align:middle}@media only screen and (max-width: 1200px){.watch-table .last-checked,.watch-table .last-changed{text-align:center}}.watch-table #th-webpage{text-align:center}.watch-table tbody tr.unviewed{font-weight:bold}.watch-table tbody tr td.inline.title-col{width:100%}.watch-table tbody tr td.inline.title-col .grid-wrapper{display:grid;grid-template-columns:auto minmax(0, 1fr) auto;grid-auto-columns:auto;align-items:center;gap:.55rem}.watch-table tbody tr td.inline.title-col .grid-wrapper>.favicon{grid-column:1}.watch-table tbody tr td.inline.title-col .grid-wrapper>.watch-text-info{grid-column:2}.watch-table tbody tr td.inline.title-col .grid-wrapper>.status-icons{grid-column:3}.watch-table tbody tr td.inline.title-col .grid-wrapper>.restock-info-wrap{grid-column:4}@media only screen and (max-width: 1200px){.watch-table tbody tr td.inline.title-col .grid-wrapper>.restock-info-wrap{grid-column:1/-1;justify-self:center}}.watch-table tbody tr .watch-text-info{line-height:1.5}.watch-table tbody tr.checking-now td:first-child{position:relative}.watch-table tbody tr.checking-now td:first-child::before{content:"";position:absolute;top:0;bottom:0;left:0;width:3px;background-color:#293eff}.watch-table tbody tr.checking-now td.last-checked .spinner-wrapper{display:inline-block !important;white-space:nowrap !important}.watch-table tbody tr.checking-now td.last-checked .spinner{margin-right:.275rem}.watch-table tbody tr.checking-now td.last-checked .innertext{display:none !important}.watch-table tbody tr.queued a.recheck{display:none !important}.watch-table tbody tr.queued a.already-in-queue-button{display:inline-flex !important;opacity:.8}.watch-table tbody tr.paused a.pause-toggle.state-on{display:inline !important}.watch-table tbody tr.paused a.pause-toggle.state-off{display:none !important}.watch-table tbody tr.notification_muted a.mute-toggle.state-on{display:inline !important}.watch-table tbody tr.notification_muted a.mute-toggle.state-off{display:none !important}.watch-table tbody tr.has-error .error-text{display:block !important;color:var(--color-watch-table-error)}.watch-table tbody tr.single-history a.preview-link{display:inherit !important}.watch-table tbody tr.multiple-history a.history-link{display:inherit !important}.watch-table tbody tr.has-favicon.unviewed img.favicon{opacity:1 !important;border-radius:4px}.watch-table td.buttons{font-size:12px;white-space:nowrap}.watch-table td.buttons>div{display:inline-flex;align-items:center;gap:6px}.watch-table td.buttons>div>*{opacity:0;transition:opacity .12s ease}.watch-table td.title-col{word-break:break-all;white-space:normal}.watch-table td a.external::after{content:"";display:inline-block;width:var(--body-main-text-size);height:var(--body-main-text-size);vertical-align:-0.1em;background:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23777' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6'/%3E%3Cpolyline points='15 3 21 3 21 9'/%3E%3Cline x1='10' y1='14' x2='21' y2='3'/%3E%3C/svg%3E") no-repeat center/contain;margin:0 3px 0 5px}.watch-table td.watch-controls>div{display:flex;justify-content:space-between;align-items:center}@media(min-width: 1020px){.watch-table th{white-space:nowrap}}.watch-table th#h-lastchanged,.watch-table th#h-lastchecked{text-align:center}.watch-table th a{font-weight:normal}.watch-table th a.active{font-weight:bolder}.watch-table th a.inactive .arrow{display:none}.watch-table th#mute-pause{white-space:nowrap}.watch-table th#mute-pause>div{display:flex;justify-content:space-between;align-items:center}.watch-table.favicon-not-enabled tr .favicon{display:none}.watch-table .status-icons{white-space:nowrap;display:flex;align-items:center;gap:4px}.watch-table .status-icons>*{vertical-align:middle}.watch-table .title-wrapper{display:flex;align-items:center;gap:10px}.watch-table .title-col-inner{display:inline-block;vertical-align:middle}.watch-table img.favicon{vertical-align:middle;max-width:36px;max-height:36px;height:36px;border-radius:var(--common-round-border)}.watch-table img.favicon:hover{outline:2px solid color-mix(in srgb, var(--color-watch-table-row-text) 50%, transparent);outline-offset:1px}body.watch-selection-active #buttons-for-all-watches{display:none !important}#buttons-for-all-watches{display:flex;align-items:center;justify-content:flex-start;flex-wrap:wrap;gap:.55rem;margin:0}#buttons-for-all-watches #post-list-mark-views{display:none}body.has-any-unviewed #post-list-mark-views{display:inline-flex !important}#watch-table-wrapper{display:inline-block;width:100%}#watch-table-wrapper #list-related-buttons{display:flex;align-items:center;justify-content:flex-start;flex-wrap:wrap;gap:.55rem;margin:0;padding:1.1rem 0 .55rem 0}#watch-table-wrapper.has-error #list-related-buttons #post-list-with-errors{display:inline-flex !important}#watch-table-wrapper.has-unread-changes #list-related-buttons #post-list-unread{display:inline-flex !important}#watch-table-wrapper #tag-lister #tag-all{opacity:1}#watch-table-wrapper #tag-lister.active-tag .button-tag{opacity:.35}#watch-table-wrapper #tag-lister.active-tag .button-tag.active,#watch-table-wrapper #tag-lister.active-tag .button-tag:hover{opacity:1}.content .group-overview-table{width:100%}.content .group-overview-table .pure-button{margin-top:.3rem;margin-bottom:.3rem}.content .group-overview-table .watch-controls,.content .group-overview-table .watch-count{text-align:center}.content .group-overview-table td{padding:5px !important;color:var(--color-watch-table-row-text)}.pure-button{border-radius:var(--common-round-border)}body.blueprint-watchlist #add-watch-ui{margin-bottom:1.1rem;padding:0}body.blueprint-watchlist #add-watch-url-row{margin-bottom:0 !important}body.blueprint-watchlist #quick-watch-llm-intent{margin-top:.55rem}body.blueprint-watchlist #url{width:auto}@media only screen and (min-width: 980px){body.blueprint-watchlist #url{min-width:32rem;max-width:min(80%,80vw);box-sizing:border-box}}body.blueprint-watchlist #quick-watch-llm-intent,body.blueprint-watchlist #quick-watch-processor-type{display:none}body.blueprint-watchlist #new-watch-form:has(#url:not(:placeholder-shown)) #quick-watch-llm-intent,body.blueprint-watchlist #new-watch-form:has(#url:not(:placeholder-shown)) #quick-watch-processor-type{display:block}@media(max-width: 767px){.watch-table thead{display:block}.watch-table thead tr th{display:inline-block}.watch-table thead tr th .hide-on-mobile{display:none}.watch-table thead .empty-cell{display:none}.watch-table .last-checked::before{color:var(--color-text);content:attr(data-label) " "}.watch-table .last-changed::before{color:var(--color-text);content:attr(data-label) " "}.watch-table td.inline{display:inline-block}.watch-table .pure-table td,.watch-table .pure-table th{border:none}.watch-table td{border:none;border-bottom:1px solid var(--color-border-watch-table-cell);vertical-align:middle}.watch-table td:before{top:6px;left:6px;width:45%;padding-right:10px;white-space:nowrap}.watch-table.pure-table-striped tr{background-color:var(--color-table-background)}.watch-table.pure-table-striped tr:nth-child(2n-1){background-color:var(--color-table-stripe)}.watch-table.pure-table-striped tr:nth-child(2n-1) td{background-color:inherit}}@media(max-width: 767px){.watch-table tbody tr{padding-bottom:10px;padding-top:10px;display:grid;grid-template-columns:40px 1fr 100px;grid-template-rows:auto auto auto auto;gap:.5rem}.watch-table tbody tr .counter-i{display:none}.watch-table tbody tr>td{border-bottom:none}.watch-table tbody tr>td[colspan]{grid-column:1/-1}.watch-table tbody tr>td.title-col{grid-column:1/-1;grid-row:1}.watch-table tbody tr>td.title-col .watch-title{font-size:.92rem}.watch-table tbody tr>td.title-col .link-spread{display:none}.watch-table tbody tr>td.last-checked{grid-column:1/-1;grid-row:2}.watch-table tbody tr>td.last-changed{grid-column:1/-1;grid-row:3}.watch-table tbody tr>td.checkbox-uuid{grid-column:1;grid-row:4}.watch-table tbody tr>td.buttons{grid-column:2;grid-row:4;display:flex;align-items:center;justify-content:flex-start}.watch-table tbody tr>td.watch-controls{grid-column:3;grid-row:4;display:grid;place-items:center}.watch-table tbody tr>td.watch-controls a img{padding:10px}.pure-table td{padding:0 !important}}@media(min-width: 768px){.watch-table thead tr th .hide-on-desktop{display:none}.watch-table td.last-checked .innertext,.watch-table td.last-changed .innertext{white-space:nowrap}}#llm-intent-section textarea{white-space:normal;overflow-wrap:break-word;overflow-x:hidden;overflow-y:auto;resize:vertical;font-family:inherit}ul#conditions_match_logic{list-style:none}ul#conditions_match_logic input,ul#conditions_match_logic label,ul#conditions_match_logic li{display:inline-block}ul#conditions_match_logic li{padding-right:1em}.fieldlist_formfields{width:100%;background-color:var(--color-background, #fff);border-radius:4px;border:1px solid var(--color-border-table-cell, #cbcbcb)}.fieldlist_formfields .fieldlist-header{display:flex;background-color:var(--color-background-table-thead, #e0e0e0);font-weight:bold;border-bottom:1px solid var(--color-border-table-cell, #cbcbcb)}.fieldlist_formfields .fieldlist-header-cell{flex:1;padding:.5em 1em;text-align:left}.fieldlist_formfields .fieldlist-header-cell:last-child{flex:0 0 120px}.fieldlist_formfields .fieldlist-body{display:flex;flex-direction:column}.fieldlist_formfields .fieldlist-row{display:flex;border-bottom:1px solid var(--color-border-table-cell, #cbcbcb)}.fieldlist_formfields .fieldlist-row:last-child{border-bottom:none}.fieldlist_formfields .fieldlist-row:nth-child(2n-1){background-color:var(--color-table-stripe, #f2f2f2)}.fieldlist_formfields .fieldlist-row.error-row{background-color:var(--color-error-input, #ffdddd)}.fieldlist_formfields .fieldlist-cell{flex:1;padding:.5em 1em;display:flex;flex-direction:column;justify-content:center}.fieldlist_formfields .fieldlist-cell input,.fieldlist_formfields .fieldlist-cell select{width:100%}.fieldlist_formfields .fieldlist-cell.fieldlist-actions{flex:0 0 120px;display:flex;flex-direction:row;align-items:center;gap:4px}.fieldlist_formfields ul.errors{margin-top:.5em;margin-bottom:0;padding:.5em;background-color:var(--color-error-background-snapshot-age, #ffdddd);border-radius:4px;list-style-position:inside}@media only screen and (max-width: 760px){.fieldlist_formfields .fieldlist-header,.fieldlist_formfields .fieldlist-row{flex-direction:column}.fieldlist_formfields .fieldlist-header-cell{display:none}.fieldlist_formfields .fieldlist-row{padding:.5em 0;border-bottom:2px solid var(--color-border-table-cell, #cbcbcb)}.fieldlist_formfields .fieldlist-cell{padding:.25em .5em}.fieldlist_formfields .fieldlist-cell.fieldlist-actions{flex:1;justify-content:flex-start;padding-top:.5em}.fieldlist_formfields .fieldlist-cell:not(:last-child){margin-bottom:.5em}.fieldlist_formfields .fieldlist-cell::before{content:attr(data-label);font-weight:bold;margin-bottom:.25em}}.fieldlist_formfields .addRuleRow,.fieldlist_formfields .removeRuleRow,.fieldlist_formfields .verifyRuleRow{cursor:pointer;border:none;padding:4px 8px;border-radius:3px;font-weight:bold;background-color:#aaa;color:var(--color-foreground-text, #fff)}.fieldlist_formfields .addRuleRow:hover,.fieldlist_formfields .removeRuleRow:hover,.fieldlist_formfields .verifyRuleRow:hover{background-color:#999}body.checking-now #checking-now-fixed-tab{display:block !important}#checking-now-fixed-tab{background:#ccc;border-radius:5px;bottom:0;color:var(--color-text);display:none;font-size:.8rem;left:0;padding:5px;position:fixed}#selector-wrapper{height:100%;text-align:center;max-height:70vh;overflow-y:scroll;position:relative}#selector-wrapper>img{position:absolute;z-index:4;max-width:100%}#selector-wrapper>canvas{position:relative;z-index:5;max-width:100%}#selector-wrapper>canvas:hover{cursor:pointer}#selector-current-xpath{font-size:80%}@media(min-width: 901px){body.blueprint-add_watch_ui #add-watch-ui{width:80%}}#add-watch-ui{padding:0}#add-watch-ui #add-watch-url-row{display:flex;gap:.5rem;align-items:stretch;margin-bottom:1rem}#add-watch-ui #add-watch-url-row>span{flex:1 1 auto;min-width:0}#add-watch-ui #add-watch-url-row>span input{width:100%}#add-watch-ui #add-watch-url-row #add-watch-go{flex:0 0 auto;white-space:nowrap}#add-watch-ui #add-watch-panes{display:flex;gap:.55rem;align-items:stretch}@media(max-width: 900px){#add-watch-ui #add-watch-panes{flex-direction:column}}#add-watch-ui #add-watch-selector-pane{flex:1 1 62%;min-width:0;min-height:380px;position:relative;display:flex;flex-direction:column;overflow:hidden;border:1px solid var(--color-background-tab);border-radius:6px;background:rgba(0,0,0,.15);padding:.75rem}#add-watch-ui #add-watch-selector-pane #add-watch-empty-state,#add-watch-ui #add-watch-selector-pane #add-watch-spinner,#add-watch-ui #add-watch-selector-pane #add-watch-error{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:.6rem;text-align:center;padding:2rem 1rem}#add-watch-ui #add-watch-selector-pane #add-watch-empty-state{opacity:.8}#add-watch-ui #add-watch-selector-pane #add-watch-empty-state svg{opacity:.55}#add-watch-ui #add-watch-selector-pane #add-watch-empty-state strong{font-size:1.05rem}#add-watch-ui #add-watch-selector-pane #add-watch-empty-state span{font-size:.85rem;opacity:.8;max-width:32ch}#add-watch-ui #add-watch-selector-pane #add-watch-spinner{gap:1.2rem}#add-watch-ui #add-watch-selector-pane #add-watch-spinner .spinner{font-size:5px}#add-watch-ui #add-watch-selector-pane #add-watch-spinner .fetching-update-notice{font-size:.85rem;opacity:.85}#add-watch-ui #add-watch-selector-pane #add-watch-error{color:#ffb4b4;font-size:.9rem;word-break:break-word}#add-watch-ui #add-watch-selector-pane #selector-wrapper{position:relative;display:block;width:100%;flex:1 1 auto;min-height:0;max-height:none;overflow-y:auto;overflow-x:hidden;text-align:left}#add-watch-ui #add-watch-selector-pane #selector-wrapper>img{position:relative;display:block;max-width:100%;height:auto;z-index:4}#add-watch-ui #add-watch-selector-pane #selector-wrapper>canvas{position:absolute;top:0;left:0;max-width:none;z-index:5}#add-watch-ui #add-watch-options-pane{flex:0 0 34%;min-width:0;display:flex;flex-direction:column;gap:1.1rem}@media(max-width: 900px){#add-watch-ui #add-watch-options-pane{flex:1 1 auto}}#add-watch-ui #add-watch-options-pane .add-watch-option-group label{display:inline-block}#add-watch-ui #add-watch-options-pane #quick-watch-fetch-backend ul{margin:.35rem 0 0 0;padding:0;list-style:none}#add-watch-ui #add-watch-options-pane #quick-watch-fetch-backend li{display:flex;align-items:flex-start;gap:.5em;padding:.15rem 0}#add-watch-ui #add-watch-options-pane #quick-watch-fetch-backend li input[type=radio]{flex:0 0 auto;margin-top:.2em}#add-watch-ui #add-watch-options-pane #quick-watch-fetch-backend li label{display:block;min-width:0;overflow-wrap:anywhere;font-size:.85rem;line-height:1.35}#add-watch-ui #add-watch-options-pane #quick-watch-fetch-backend li.unusable{opacity:.55;cursor:not-allowed}#add-watch-ui #add-watch-options-pane #quick-watch-fetch-backend li.unusable label{cursor:not-allowed}#add-watch-ui #add-watch-options-pane #quick-watch-fetch-backend .pure-form-message-inline{display:block;margin-top:.35rem;font-size:.8rem;opacity:.8}#add-watch-ui #add-watch-options-pane #by-element-toggle-group .pure-form-message-inline{display:block;margin-top:.25rem;font-size:.8rem;opacity:.8}#add-watch-ui #add-watch-options-pane #by-element-toggle-group #clear-selector{margin-top:.5rem}#add-watch-ui #add-watch-options-pane #quick-watch-llm-intent label{display:block;margin-bottom:.35rem}#add-watch-ui #add-watch-options-pane #add-watch-submit-row{display:flex;flex-wrap:wrap;gap:.5rem}body.blueprint-add_watch_ui #add-watch-ui{height:90vh;display:flex;flex-direction:column}body.blueprint-add_watch_ui #add-watch-fieldset{flex:1 1 auto;min-height:0;min-width:0;display:flex;flex-direction:column;border:0;margin:0;padding:0}body.blueprint-add_watch_ui #add-watch-legend{margin:0 0 .75rem;font-size:1.1rem;font-weight:600}body.blueprint-add_watch_ui #new-watch-form{flex:1 1 auto;min-height:0;display:flex;flex-direction:column}@media(min-width: 901px){body.blueprint-add_watch_ui #add-watch-panes{flex:1 1 auto;min-height:0}body.blueprint-add_watch_ui #add-watch-selector-pane{min-height:0}}@media(max-width: 900px){body.blueprint-add_watch_ui #add-watch-ui{height:auto}body.blueprint-add_watch_ui #add-watch-panes{flex:0 0 auto}}.ternary-radio-group{display:flex;gap:0;border:1px solid var(--color-grey-750);border-radius:4px;overflow:hidden;width:fit-content;background:var(--color-background)}.ternary-radio-group .ternary-radio-option{position:relative;cursor:pointer;margin:0;display:flex;align-items:center}.ternary-radio-group .ternary-radio-option input[type=radio]{position:absolute;opacity:0;width:0;height:0}.ternary-radio-group .ternary-radio-option .ternary-radio-label{padding:8px 16px;background:var(--color-grey-900);border:none;border-right:1px solid var(--color-grey-750);font-size:13px;font-weight:500;color:var(--color-text);transition:all .2s ease;cursor:pointer;display:block;text-align:center}.ternary-radio-group .ternary-radio-option:last-child .ternary-radio-label{border-right:none}.ternary-radio-group .ternary-radio-option input:checked+.ternary-radio-label{background:var(--color-link);color:var(--color-text-button);font-weight:600}.ternary-radio-group .ternary-radio-option input:checked+.ternary-radio-label.ternary-default{background:var(--color-grey-600);color:var(--color-text-button)}.ternary-radio-group .ternary-radio-option input:checked+.ternary-radio-label:hover{background:#1a7bc4}.ternary-radio-group .ternary-radio-option input:checked+.ternary-radio-label:hover.ternary-default{background:var(--color-grey-500)}.ternary-radio-group .ternary-radio-option:hover .ternary-radio-label{background:var(--color-grey-800)}@media(max-width: 480px){.ternary-radio-group{width:100%}.ternary-radio-group .ternary-radio-label{flex:1;min-width:auto}}input[type=radio].pure-radio:checked+label,input[type=radio].pure-radio:checked{background:var(--color-link);color:var(--color-text-button)}html[data-darkmode=true] .ternary-radio-group .ternary-radio-option .ternary-radio-label{background:var(--color-grey-350)}html[data-darkmode=true] .ternary-radio-group .ternary-radio-option:hover .ternary-radio-label{background:var(--color-grey-400)}html[data-darkmode=true] .ternary-radio-group .ternary-radio-option input:checked+.ternary-radio-label{background:var(--color-link);color:var(--color-text-button)}html[data-darkmode=true] .ternary-radio-group .ternary-radio-option input:checked+.ternary-radio-label.ternary-default{background:var(--color-grey-600)}html[data-darkmode=true] .ternary-radio-group .ternary-radio-option input:checked+.ternary-radio-label:hover{background:#1a7bc4}html[data-darkmode=true] .ternary-radio-group .ternary-radio-option input:checked+.ternary-radio-label:hover.ternary-default{background:var(--color-grey-500)}body.processor-image_ssim_diff #edit-text-filter .text-filtering{display:none}body.processor-image_ssim_diff #conditions-tab{display:none}.modal-dialog{border:none;border-radius:10px;padding:0;background:var(--color-background);color:var(--color-text);box-shadow:0 5px 20px rgba(0,0,0,.3);max-width:500px;width:90%}.modal-dialog::backdrop{background:rgba(0,0,0,.6);backdrop-filter:blur(3px);animation:fadeIn .2s ease-out}.modal-dialog[open]{animation:slideIn .25s ease-out}.modal-dialog .modal-header{padding:1.5rem;border-bottom:1px solid var(--color-border-table-cell);display:flex;align-items:center;gap:1rem}.modal-dialog .modal-header .modal-icon{font-size:2rem;line-height:1;flex-shrink:0}.modal-dialog .modal-header .modal-icon.warning{color:var(--color-warning)}.modal-dialog .modal-header .modal-icon.danger{color:var(--color-background-button-error)}.modal-dialog .modal-header .modal-icon.info{color:var(--color-background-button-primary)}.modal-dialog .modal-header .modal-title{font-size:1.3rem;font-weight:bold;margin:0;color:var(--color-text)}.modal-dialog .modal-body{padding:1.5rem;line-height:1.6}.modal-dialog .modal-body p{margin:0 0 1rem 0}.modal-dialog .modal-body p:last-child{margin-bottom:0}.modal-dialog .modal-body strong{color:var(--color-text);font-weight:600}.modal-dialog .modal-footer{padding:1rem 1.5rem;border-top:1px solid var(--color-border-table-cell);display:flex;gap:.75rem;justify-content:flex-end;background:var(--color-grey-900)}.modal-dialog .modal-footer button{padding:.6rem 1.5rem;border:none;border-radius:4px;cursor:pointer;font-weight:500;transition:all .2s ease;font-size:.95rem}.modal-dialog .modal-footer button:hover{transform:translateY(-1px);box-shadow:0 2px 8px rgba(0,0,0,.15)}.modal-dialog .modal-footer button:active{transform:translateY(0)}.modal-dialog .modal-footer button.modal-btn-cancel{background:var(--color-background-button-cancel);color:var(--color-grey-200)}.modal-dialog .modal-footer button.modal-btn-cancel:hover{background:var(--color-grey-700)}.modal-dialog .modal-footer button.modal-btn-confirm{background:var(--color-background-button-primary);color:var(--color-white)}.modal-dialog .modal-footer button.modal-btn-confirm:hover{opacity:.9}.modal-dialog .modal-footer button.modal-btn-danger{background:var(--color-background-button-error);color:var(--color-white)}.modal-dialog .modal-footer button.modal-btn-danger:hover{background:var(--color-dark-red)}.modal-dialog .modal-footer button.modal-btn-warning{background:var(--color-background-button-warning);color:var(--color-white)}.modal-dialog .modal-footer button.modal-btn-warning:hover{opacity:.9}html[data-darkmode=true] .modal-dialog{box-shadow:0 5px 30px rgba(0,0,0,.7)}html[data-darkmode=true] .modal-dialog .modal-footer{background:var(--color-grey-200)}@keyframes fadeIn{from{opacity:0}to{opacity:1}}@keyframes slideIn{from{opacity:0;transform:translateY(-20px) scale(0.95)}to{opacity:1;transform:translateY(0) scale(1)}}@media only screen and (max-width: 760px){.modal-dialog{width:95%;max-width:none}.modal-dialog .modal-header{padding:1rem}.modal-dialog .modal-header .modal-title{font-size:1.1rem}.modal-dialog .modal-body{padding:1rem;font-size:.95rem}.modal-dialog .modal-footer{padding:.75rem 1rem;flex-wrap:wrap}.modal-dialog .modal-footer button{flex:1;min-width:120px}}.bulk-choice-list{display:flex;flex-direction:column;gap:2px;max-height:50vh;overflow-y:auto;text-align:left}.bulk-choice-list .bulk-choice-row{display:block;padding:6px 8px;cursor:pointer;border-radius:4px}.bulk-choice-list .bulk-choice-row input[type=radio]{margin-right:8px}.bulk-choice-list .bulk-choice-row:hover{background:rgba(127,127,127,.15)}.bulk-choice-list .bulk-choice-row em{opacity:.7;font-size:.9em}#language-selector-flag{display:inline-block;width:1.2em;height:1.2em;vertical-align:middle;border-radius:50%;overflow:hidden;opacity:.6}#language-selector-flag:hover{opacity:1}.language-list{display:flex;flex-direction:column;gap:.5rem;padding:.5rem 0}.language-option{display:flex;align-items:center;gap:1rem;padding:.25rem;border-radius:4px;transition:background-color .2s ease;text-decoration:none;color:var(--color-text);border:1px solid rgba(0,0,0,0)}.language-option:hover{background-color:var(--color-background-menu-link-hover);border-color:var(--color-border-table-cell)}.language-option.active{background-color:var(--color-link);color:var(--color-text-button);font-weight:600}.language-option .flag{font-size:1.5rem;flex-shrink:0}.language-option .language-name{flex-grow:1;font-size:1rem}#language-modal .language-list .lang-option{display:inline-block;width:1.5em;height:1.5em;vertical-align:middle;margin-right:.5em;border-radius:50%;overflow:hidden}.action-sidebar{display:flex;flex-direction:column;align-items:center;align-self:flex-start;position:sticky;top:0;height:100vh;background:hsla(0,0%,100%,.05);z-index:60;pointer-events:none}@media only screen and (max-width: 980px){.action-sidebar{display:none}}.action-sidebar-inner{pointer-events:auto;width:64px;overflow:hidden;flex:1 1 auto;display:flex;flex-direction:column;transition:width .08s ease-out;padding-left:.55rem;padding-right:.55rem}body.actionsidebar-minimal .action-sidebar-inner:hover,body.actionsidebar-minimal .action-sidebar-inner:focus-within{width:200px;transition:width .22s cubic-bezier(0.2, 0.7, 0.2, 1)}body.actionside-bar-on .action-sidebar-inner{width:200px;transition:none}ul.action-sidebar-list{list-style:none;padding:0;margin:0;display:flex;flex-direction:column;gap:0}.action-sidebar-list.action-sidebar-list--bottom{margin-top:auto}.action-sidebar-li{list-style:none;margin:0;position:relative;color:var(--color-white)}.action-sidebar-li:nth-child(2){padding-top:2rem}.action-sidebar-li button{padding:0;margin:0}.action-sidebar-li a{color:var(--color-white)}.action-sidebar-li--spark .queue-spark{display:block;width:100%;height:15px;box-sizing:border-box;padding:0;margin:0;border-radius:3px;background:hsla(0,0%,100%,.05);box-shadow:inset 0 0 0 1px hsla(0,0%,100%,.06)}.action-sidebar-divider{height:1px;background:hsla(0,0%,100%,.18);margin:6px 16px;list-style:none}.action-sidebar .action-sidebar-item{position:relative;display:flex;align-items:center;padding:.55rem;font-size:var(--body-main-text-size);border-radius:var(--common-round-border);color:var(--color-white);text-decoration:none;white-space:nowrap;background:rgba(0,0,0,0);border:0;text-align:left;cursor:pointer;transition:background-color .12s ease,color .12s ease}.action-sidebar .action-sidebar-item:hover{background-color:var(--color-sidebar-item-hover-bg)}.action-sidebar .action-sidebar-item:hover .action-icon{stroke-width:2.3}.action-sidebar .action-sidebar-item:focus-visible{outline:2px solid var(--color-link);outline-offset:2px}.action-sidebar .action-sidebar-item.active .action-icon{stroke-width:2.4;filter:drop-shadow(0 0 0.4px currentColor)}.action-sidebar .action-sidebar-item.active .action-label{font-weight:700}.action-sidebar .action-sidebar-item.is-disabled{opacity:.45;cursor:not-allowed;pointer-events:none}.action-sidebar .action-sidebar-item.action-sidebar-item--accent .action-icon{stroke:#fff;stroke-width:2.6}.action-sidebar .action-sidebar-item .action-label{flex:0 0 auto;margin-left:14px;font-family:inherit;font-weight:400;letter-spacing:0;text-transform:none;color:inherit;opacity:0;transform:translateX(-4px);transition:opacity .05s ease-out,transform .05s ease-out}.action-sidebar .action-sidebar-item .action-badge{margin-left:10px;font-size:.7rem;line-height:1;padding:3px 7px;border-radius:999px;background:hsla(0,0%,100%,.14);color:hsla(0,0%,100%,.85);text-transform:uppercase;letter-spacing:.06em;font-weight:700;pointer-events:none;opacity:0;transition:opacity .05s ease-out}.action-sidebar .action-sidebar-item .action-badge.action-badge--count{margin-left:auto;text-transform:none;letter-spacing:0;background:#3e95bb;color:var(--color-white);font-variant-numeric:tabular-nums}body.actionsidebar-minimal .action-sidebar-inner:hover .action-sidebar-item .action-label,body.actionsidebar-minimal .action-sidebar-inner:focus-within .action-sidebar-item .action-label{opacity:1;transform:translateX(0);transition:opacity .18s ease .05s,transform .18s cubic-bezier(0.2, 0.7, 0.2, 1) .05s}body.actionsidebar-minimal .action-sidebar-inner:hover .action-sidebar-item .action-badge,body.actionsidebar-minimal .action-sidebar-inner:focus-within .action-sidebar-item .action-badge{opacity:1;transition:opacity .18s ease .05s}body.actionside-bar-on .action-sidebar .action-sidebar-item .action-label{opacity:1;transform:translateX(0);transition:none}body.actionside-bar-on .action-sidebar .action-sidebar-item .action-badge{opacity:1;transition:none}.action-icon{flex:0 0 auto;width:24px;height:24px;stroke:currentColor;stroke-width:1.9;fill:none;stroke-linecap:round;stroke-linejoin:round}.action-badge{flex:0 0 auto;font-size:.62rem;text-transform:uppercase;letter-spacing:.08em;padding:2px 6px;border-radius:999px;background:hsla(0,0%,100%,.15);color:hsla(0,0%,100%,.85);font-weight:700}.mobile-menu-section{padding:.5rem .75rem;border-bottom:1px solid var(--color-border-table-cell)}.mobile-menu-section ul.action-sidebar-list{gap:1px}.mobile-menu-section ul.action-sidebar-list .action-sidebar-li a,.mobile-menu-section ul.action-sidebar-list .action-sidebar-li button{padding:.55rem}.mobile-menu-section .action-sidebar-item{position:relative;display:flex;align-items:center;justify-content:flex-start;gap:.55rem;padding:.55rem .55rem;border-radius:var(--common-round-border);color:var(--color-text)}.mobile-menu-section .action-sidebar-item:hover{background-color:var(--color-background-menu-link-hover);color:var(--color-text)}.mobile-menu-section .action-sidebar-item.active{background-color:var(--color-background-menu-link-hover);color:var(--color-text)}.mobile-menu-section .action-sidebar-item .action-label{position:static;transform:none;background:rgba(0,0,0,0);box-shadow:none;color:inherit;opacity:1;pointer-events:auto;padding:0;font-weight:500}.mobile-menu-section .action-sidebar-item .action-label::before{display:none}.mobile-menu-section .action-sidebar-item .action-badge{position:static;margin-left:auto;font-size:.62rem;background:rgba(0,0,0,.08);color:var(--color-text)}.mobile-menu-section .action-sidebar-item.action-sidebar-item--accent{background:var(--color-background-menu-link-hover);box-shadow:inset 0 0 0 1px var(--color-border-table-cell);color:var(--color-text)}.mobile-menu-section .action-sidebar-item.action-sidebar-item--accent .action-label{color:inherit}.mobile-menu-section .action-sidebar-item--button{background:rgba(0,0,0,0);border:none;cursor:pointer;text-align:left;font:inherit}#add-watch-live-info{width:100%;margin-top:1rem}#add-watch-live-info .add-watch-live-placeholder{border:1px dashed hsla(0,0%,100%,.25);background:hsla(0,0%,100%,.04);border-radius:10px;padding:1.25rem;color:var(--color-white)}#add-watch-live-info .add-watch-live-placeholder h3{margin:0 0 .4rem 0;font-size:1rem;letter-spacing:.02em}#add-watch-live-info .add-watch-live-placeholder .muted{opacity:.7;margin:0 0 .75rem 0;font-size:.85rem}#add-watch-live-info .add-watch-live-placeholder .add-watch-live-stream{font-size:.85rem;opacity:.6;padding:.6rem 0}.mobile-menu-drawer .action-sidebar-list{padding:0}.mobile-menu-drawer .mobile-menu-section .action-sidebar-item{padding-left:0}#action-sidebar-logo{padding-top:1.1rem;padding-left:.55rem}.actionsidebar-minimal #checking-now-stats-sidebar{display:none}.actionsidebar-minimal #cdio-logo #logo-expanded{display:none}.actionsidebar-minimal.action-side-bar-expanded #checking-now-stats-sidebar{display:block}.actionsidebar-minimal.action-side-bar-expanded #cdio-logo #logo-expanded{display:inline-block}.action-side-bar-expanded #cdio-logo #logo-short{display:none}#queue-page{width:100%;color:var(--color-white)}#queue-page h2,#queue-page h3{color:var(--color-white)}#queue-page .queue-panel{background:var(--color-background-new-watch-form);padding:1em;border-radius:10px;margin-bottom:1em;width:100%;box-sizing:border-box;color:var(--color-white)}#queue-page .queue-stats{display:grid;grid-template-columns:repeat(auto-fit, minmax(160px, 1fr));gap:.75rem}#queue-page .queue-stat .label{font-size:.7rem;text-transform:uppercase;letter-spacing:.06em;opacity:.7}#queue-page .queue-stat .value{font-size:1.6rem;font-weight:700;color:var(--color-white)}#queue-page .queue-stat.queue-stat--action{display:flex;align-items:center;justify-content:flex-start}#queue-page .queue-stat.queue-stat--action .pure-button{white-space:nowrap}#queue-page table.pure-table{width:100%;background:rgba(0,0,0,0);color:var(--color-white);font-size:80%}#queue-page table.pure-table thead th{background:rgba(0,0,0,0);color:var(--color-white);border-bottom:1px solid hsla(0,0%,100%,.18);font-weight:700;white-space:nowrap}#queue-page table.pure-table td{color:var(--color-white);border-color:hsla(0,0%,100%,.08);white-space:nowrap}#queue-page table.pure-table td.title-col,#queue-page table.pure-table td.watch-cell{white-space:normal;word-break:break-all}#queue-page table.pure-table td.time-cell{font-variant-numeric:tabular-nums;color:hsla(0,0%,100%,.75);font-size:.95em}#queue-page table.pure-table code,#queue-page table.pure-table small,#queue-page table.pure-table em,#queue-page table.pure-table strong{color:var(--color-white)}#queue-page table.pure-table code{background:rgba(0,0,0,.18)}#queue-page table.pure-table small{opacity:.7}#queue-page table.pure-table-striped tr:nth-child(2n-1) td{background:hsla(0,0%,100%,.04)}#queue-page tr.is-completed td{opacity:.45;transition:opacity .4s ease}#queue-page tbody[data-section=workers]{border-bottom:1px solid hsla(0,0%,100%,.18)}#queue-page tr.worker-slot td{border-color:hsla(0,0%,100%,.05)}#queue-page tr.worker-idle td{background:hsla(0,0%,100%,.02)}#queue-page .inline-tag,#queue-page .processor-badge,#queue-page .watch-tag-list,#queue-page .tracking-ldjson-price-data,#queue-page .restock-label{background:hsla(0,0%,100%,.14);color:var(--color-white)}#queue-page .inline-tag--running{background:rgba(28,184,65,.45)}#queue-page .inline-tag--idle{background:hsla(0,0%,100%,.08);color:hsla(0,0%,100%,.6)}#queue-page .inline-tag--done{background:hsla(0,0%,100%,.1);color:hsla(0,0%,100%,.7)}#queue-page a.queue-cancel{display:inline-block;margin-left:8px;font-size:.75rem;color:hsla(0,0%,100%,.65);text-decoration:underline;text-decoration-style:dotted;text-underline-offset:2px}#queue-page a.queue-cancel:hover{color:var(--color-white);text-decoration-style:solid}#queue-page a.queue-cancel.is-busy{pointer-events:none;opacity:.5}#queue-page tr.is-new td{animation:queue-row-in .45s ease}@keyframes queue-row-in{from{background-color:rgba(28,184,65,.18)}to{background-color:rgba(0,0,0,0)}}#queue-page .queue-waiting{display:none;align-items:center;gap:.5rem;margin-top:1rem;padding:.5rem 0;color:hsla(0,0%,100%,.7);font-size:.85rem}#queue-page .queue-waiting[data-show=true]{display:flex}#queue-page .queue-waiting .spinner{margin:0;flex:0 0 auto;border-top-color:hsla(0,0%,100%,.18);border-right-color:hsla(0,0%,100%,.18);border-bottom-color:hsla(0,0%,100%,.18);border-left-color:var(--color-white)}.hamburger-menu{display:none;background:rgba(0,0,0,0);border:none;cursor:pointer;padding:.55rem;z-index:10001;position:relative}@media only screen and (max-width: 980px){.hamburger-menu{display:flex;flex-direction:column;justify-content:center;align-items:center}}.hamburger-icon{width:24px;height:20px;position:relative;display:flex;flex-direction:column;justify-content:space-between}.hamburger-icon span{display:block;height:3px;width:100%;background:var(--color-white);border-radius:2px;transition:all .3s cubic-bezier(0.68, -0.55, 0.265, 1.55);transform-origin:center}.hamburger-menu.active .hamburger-icon span{background-color:var(--color-text)}.hamburger-menu.active .hamburger-icon span:nth-child(1){transform:translateY(8.5px) rotate(45deg)}.hamburger-menu.active .hamburger-icon span:nth-child(2){opacity:0;transform:translateX(-10px)}.hamburger-menu.active .hamburger-icon span:nth-child(3){transform:translateY(-8.5px) rotate(-45deg)}.mobile-menu-overlay{display:none;position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(0,0,0,.5);z-index:9999;opacity:0;transition:opacity .3s ease}.mobile-menu-overlay.active{display:block;opacity:1}.mobile-menu-drawer{position:fixed;top:0;right:-280px;width:280px;height:100%;background:var(--color-background);opacity:1;box-shadow:-2px 0 8px rgba(0,0,0,.15);z-index:10000;transition:right .3s cubic-bezier(0.68, -0.55, 0.265, 1.55);overflow-y:auto;padding-top:60px}.mobile-menu-drawer #cdio-logo{color:var(--color-text)}.mobile-menu-drawer #cdio-logo #logo-short{display:none}.mobile-menu-drawer #cdio-logo #logo-expanded{display:inline-block}.mobile-menu-drawer .action-icon{stroke:var(--color-text)}.mobile-menu-drawer.active{right:0}.mobile-menu-drawer .mobile-menu-items{list-style:none;padding:1rem 0;margin:0}.mobile-menu-drawer .mobile-menu-items li{border-bottom:1px solid var(--color-border-table-cell)}.mobile-menu-drawer .mobile-menu-items li>*{display:block;padding:1rem 1.5rem;color:var(--color-text);text-decoration:none;font-weight:500;transition:background .2s ease}.mobile-menu-drawer .mobile-menu-items li>*:hover{background:var(--color-background-menu-link-hover)}.mobile-menu-drawer .mobile-menu-items li#menu-pause,.mobile-menu-drawer .mobile-menu-items li#menu-mute{display:none}.logo-cdio{font-weight:bold;font-size:1.1rem}.logo-cdio .logo-cd{color:var(--color-grey-500)}.logo-cdio .logo-io{color:var(--color-text)}.menu-always-visible{display:flex;align-items:center;gap:.5rem;margin-left:auto}@media only screen and (max-width: 980px){#top-right-menu .menu-collapsible{display:none !important}.pure-menu-horizontal{overflow-x:visible !important}#nav-menu{overflow-x:visible !important}}@media only screen and (min-width: 1025px){.hamburger-menu,.mobile-menu-drawer,.mobile-menu-overlay{display:none !important}}html[data-darkmode=true] .mobile-menu-drawer{box-shadow:-2px 0 8px rgba(0,0,0,.4)}#search-modal .modal-body{padding:2rem 1.5rem}#search-modal .modal-body .pure-control-group{padding-bottom:0}#search-modal .modal-body .pure-control-group label{display:block;margin-bottom:.5rem;font-size:.9rem;font-weight:600;color:var(--color-text)}#search-modal .modal-body .pure-control-group #search-modal-input{width:100%;max-width:100%;box-sizing:border-box;padding:.6rem .8rem;font-size:1rem;border:1px solid var(--color-border-input);border-radius:4px;background-color:var(--color-background-input);color:var(--color-text-input);box-shadow:inset 0 1px 3px var(--color-shadow-input);transition:border-color .2s ease,box-shadow .2s ease}#search-modal .modal-body .pure-control-group #search-modal-input:focus{outline:none;border-color:var(--color-link);box-shadow:0 0 0 3px rgba(27,152,248,.1)}#search-modal .modal-body .pure-control-group #search-modal-input::placeholder{color:var(--color-text-input-placeholder);opacity:.7}html[data-darkmode=true] #search-modal #search-modal-input:focus{box-shadow:0 0 0 3px rgba(89,189,251,.15)}#llm-diff-summary-area{margin:.6rem 0 .4rem;padding:.65rem .9rem;background:linear-gradient(135deg, rgba(120, 80, 200, 0.18), rgba(80, 160, 220, 0.14));border-left:3px solid rgba(140,90,220,.8);border-radius:0 4px 4px 0;min-width:0;max-width:100%;box-sizing:border-box;overflow:hidden}#llm-diff-summary-area .llm-diff-summary-label{display:block;font-size:.7rem;font-weight:700;letter-spacing:.06em;text-transform:uppercase;opacity:.55;margin-bottom:.25rem}#llm-diff-summary-area .llm-diff-summary-text{margin:0;font-size:.9rem;line-height:1.5;white-space:pre-wrap;overflow-wrap:break-word;word-break:break-word}.llm-diff-summary-prompt{margin:.4em 0 0;font-size:.78rem;font-style:italic;overflow:hidden;max-height:3.8em;animation:llm-prompt-reveal .7s ease-out both}.llm-diff-summary-prompt .llm-diff-summary-prompt-text{display:block;opacity:.55;mask-image:linear-gradient(to bottom, rgba(0, 0, 0, 0.85) 30%, rgba(0, 0, 0, 0) 100%);-webkit-mask-image:linear-gradient(to bottom, rgba(0, 0, 0, 0.85) 30%, rgba(0, 0, 0, 0) 100%);white-space:pre-wrap;overflow-wrap:break-word;line-height:1.45}@keyframes llm-prompt-reveal{from{opacity:0;transform:translateY(-3px)}to{opacity:1;transform:translateY(0)}}.llm-diff-summary-loading{opacity:.5;font-style:italic;animation:llm-pulse 1.4s ease-in-out infinite;font-weight:bold}@keyframes llm-pulse{0%,100%{opacity:.5}50%{opacity:.2}}.llm-budget-exceeded,.llm-error{color:#c0392b;font-weight:600;font-style:normal;opacity:1}.toggle-ai-mode{opacity:.4;transition:opacity .2s ease,filter .2s ease;display:inline-flex;align-items:center;color:var(--color-text-menu-link)}.toggle-ai-mode svg{height:1.2rem;width:1.2rem}.toggle-ai-mode .ai-mode-label{font-size:.75rem;font-weight:600;letter-spacing:.04em;line-height:1}html[data-ai-mode=true] .toggle-ai-mode{opacity:1;filter:drop-shadow(0 0 4px rgba(160, 100, 255, 0.7))}.btn-label-summary{display:none}html[data-ai-mode=true] body.llm-configured .btn-label-history{display:none}html[data-ai-mode=true] body.llm-configured .btn-label-summary{display:inline}.ai-inline-summary-row td{white-space:normal !important;word-break:break-word;padding:.5rem 1rem .6rem 1.4rem !important;background:linear-gradient(135deg, #f0ebff, #eaf0ff) !important;border-top:1px solid #c4b5fd !important;border-left:3px solid #8b5cf6 !important;color:#1a0640 !important;line-height:1.5}html[data-darkmode=true] .ai-inline-summary-row td{background:linear-gradient(135deg, #1c0d35, #0d1535) !important;border-top:1px solid #3b1f6e !important;border-left-color:#8b5cf6 !important;color:#e9d5ff !important}.ai-inline-summary-row .ai-inline-summary-content{display:flex;gap:.5rem;align-items:flex-start}.ai-inline-summary-row .ai-inline-summary-content .ai-inline-spinner{flex-shrink:0;animation:llm-pulse 1.4s ease-in-out infinite}.ai-inline-summary-row .ai-inline-summary-content .ai-inline-body{display:flex;flex-direction:column;min-width:0}.ai-inline-summary-row .ai-inline-summary-content .ai-inline-text{font-style:italic;opacity:.75;white-space:pre-wrap}.ai-inline-summary-row .ai-inline-summary-content.loaded .ai-inline-spinner{animation:none}.ai-inline-summary-row .ai-inline-summary-content.loaded .ai-inline-text{font-style:normal;opacity:1}.ai-inline-summary-row .ai-inline-history-link{display:inline-block;margin-top:.4rem;font-size:.78rem;font-weight:700;opacity:.7;white-space:nowrap}.ai-inline-summary-row .ai-inline-history-link:hover{opacity:1}.ai-inline-summary-row .ai-inline-error{color:#c0392b}.ai-inline-summary-row .ai-inline-prompt{display:block;margin-top:.3em;font-size:.75rem;font-style:italic;overflow:hidden;max-height:3.6em;animation:llm-prompt-reveal .6s ease-out both;mask-image:linear-gradient(to bottom, rgba(0, 0, 0, 0.7) 30%, rgba(0, 0, 0, 0) 100%);-webkit-mask-image:linear-gradient(to bottom, rgba(0, 0, 0, 0.7) 30%, rgba(0, 0, 0, 0) 100%);opacity:.55;line-height:1.4;white-space:pre-wrap;overflow-wrap:break-word}.action-sidebar-item{position:relative}.action-sidebar-item .notification-bubble{position:absolute;top:8px;left:8px;min-width:18px;height:18px;background:#f44;color:#fff;font-size:10px;font-weight:700;line-height:18px;text-align:center;border-radius:9px;padding:0 2px;box-shadow:0 2px 4px rgba(0,0,0,.3);pointer-events:none;transition:all .2s ease;display:none}.action-sidebar-item .notification-bubble.red-bubble{background:#f44}.action-sidebar-item .notification-bubble.blue-bubble{background:#4a9eff;color:#fff}.action-sidebar-item .notification-bubble.visible{display:block}.action-sidebar-item .notification-bubble.pulse{animation:bubblePulse .4s ease-out}.action-sidebar-item .notification-bubble.large-number{font-size:8px;min-width:20px;height:20px;line-height:20px;border-radius:10px}@keyframes bubblePulse{0%{transform:scale(1)}50%{transform:scale(1.3)}100%{transform:scale(1)}}html[data-darkmode=true] .notification-bubble{box-shadow:0 2px 6px rgba(0,0,0,.6)}.notification-add-buttons{margin-bottom:.5rem;display:flex;align-items:center;flex-wrap:wrap;gap:.4rem}.notification-add-buttons .add-destination-inline{display:inline-flex;align-items:center;gap:.3rem}.notification-add-buttons .add-destination-inline input[type=email]{margin:0;min-width:16rem}#notification-add-email-preset{padding-top:.55rem;padding-bottom:.55rem}#notification-recipients{padding-bottom:.55rem}.notification-recipients{display:flex;flex-wrap:wrap;gap:.4rem;margin-bottom:.5rem}.notification-recipients .notification-chip{display:inline-flex;align-items:center;gap:.35rem;padding:.2rem .5rem;line-height:1.4;border:1px solid var(--color-border-notification);border-radius:var(--common-round-border);max-width:100%}.notification-recipients .notification-chip .notification-chip-label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:22rem}.notification-recipients .notification-chip .notification-chip-remove{cursor:pointer;font-weight:bold;opacity:.55;text-decoration:none}.notification-recipients .notification-chip .notification-chip-remove:hover{opacity:1}.notifications-wrapper{padding-top:.5rem}.notifications-wrapper #notification-test-log{margin-top:1rem;padding:1rem;white-space:pre-wrap;word-break:break-word;overflow-wrap:break-word;max-width:100%;box-sizing:border-box;max-height:12rem;overflow-y:scroll;border:1px solid var(--color-border-notification);border-radius:5px}#notification-error-log{border:1px solid var(--color-border-notification);padding:1rem;border-radius:5px;overflow-wrap:break-word}#restock-diff{width:100%;box-sizing:border-box}#restock-diff-summary{margin-top:.6rem;display:flex;align-items:center;gap:.6rem;flex-wrap:wrap}.restock-latest-price{font-size:1.4rem;font-weight:700}.restock-badge{display:inline-block;padding:.15rem .55rem;border-radius:1rem;font-size:.8rem;font-weight:600;white-space:nowrap}.restock-badge.in-stock{background:rgba(31,164,99,.15);color:#1fa463}.restock-badge.out-of-stock{background:rgba(231,76,60,.15);color:#e74c3c}#restock-tabs{background:var(--color-background);color:var(--color-text);padding:1rem;border-radius:5px}#restock-tabs .tab-pane-inner#screenshot{text-align:center}#restock-tabs .tab-pane-inner#screenshot img{max-width:99%}#restock-graph{margin-top:1rem;box-sizing:border-box}@media(min-width: 1200px){#restock-graph{max-width:80%;margin-left:auto;margin-right:auto}}.js-restock-graph{position:relative;width:100%}.js-restock-graph svg{display:block;max-width:100%}.js-restock-graph .rg-axis{stroke:var(--color-border-notification, rgba(127, 127, 127, 0.4));stroke-width:1}.js-restock-graph .rg-label{fill:currentColor;opacity:.7;font-size:12px}.js-restock-graph .rg-line{stroke:currentColor;opacity:.55}.js-restock-graph .rg-dot{stroke:var(--color-background, #fff);stroke-width:1.5}.js-restock-graph .rg-legend{display:flex;justify-content:center;gap:1.1rem;margin-top:.4rem;font-size:.78rem;opacity:.85}.js-restock-graph .rg-legend .rg-legend-item{display:inline-flex;align-items:center;gap:.35rem}.js-restock-graph .rg-legend .rg-legend-dot{width:9px;height:9px;border-radius:50%;display:inline-block}.js-restock-graph .rg-legend .rg-legend-dot.in{background:#1fa463}.js-restock-graph .rg-legend .rg-legend-dot.out{background:#e74c3c}.js-restock-graph .rg-header{display:flex;align-items:center;justify-content:space-between;gap:.5rem;flex-wrap:wrap;margin-bottom:.5rem}.js-restock-graph .rg-stats{font-size:.8rem;opacity:.7;text-align:right;margin-left:auto}.js-restock-graph .rg-band{fill:rgba(120,130,150,.14)}.js-restock-graph .rg-avg-line{stroke:var(--color-text, #555);opacity:.45;stroke-width:1}.js-restock-graph .rg-avg-text{opacity:.5}.rg-status{display:inline-flex;align-items:baseline;gap:.4rem;padding:.2rem .6rem;border-radius:1rem;font-size:.85rem}.rg-status .rg-status-label{font-weight:700}.rg-status .rg-status-sub{font-size:.78rem;opacity:.8}.rg-status.rg-status-low{background:rgba(31,164,99,.16);color:#1fa463}.rg-status.rg-status-typical{background:rgba(120,130,150,.16);color:var(--color-text, #555)}.rg-status.rg-status-high{background:rgba(231,76,60,.16);color:#e74c3c}.rg-tooltip{position:absolute;display:none;pointer-events:none;z-index:5;transform:translateY(-50%);white-space:nowrap;background:var(--color-background, #fff);color:var(--color-text, #222);border:1px solid var(--color-border-notification, rgba(127, 127, 127, 0.4));border-radius:5px;padding:4px 8px;font-size:12px;line-height:1.4;box-shadow:0 2px 6px rgba(0,0,0,.15)}#restock-history-table{margin-left:auto;margin-right:auto}#restock-history-table td,#restock-history-table th{text-align:left}.restock-table-toolbar{display:flex;align-items:center;justify-content:center;gap:.75rem;margin-bottom:.5rem}html[data-ai-mode=true] body.llm-configured tr.processor-restock_diff .btn-label-history{display:inline}html[data-ai-mode=true] body.llm-configured tr.processor-restock_diff .btn-label-summary{display:none}.restock-inline-row td{white-space:normal !important;word-break:break-word;padding:.6rem 1rem .8rem 1.4rem !important;background:linear-gradient(135deg, #e6fbf0, #e8f6ff) !important;border-top:1px solid #9fe3c2 !important;border-left:3px solid #1fa463 !important;color:#06281a !important;line-height:1.5}html[data-darkmode=true] .restock-inline-row td{background:linear-gradient(135deg, #0c2a1c, #0d2230) !important;border-top:1px solid #1f5e40 !important;border-left-color:#1fa463 !important;color:#d6ffe9 !important}.restock-inline-row .restock-inline-graph{width:100%;min-height:40px}.restock-inline-row .restock-inline-history-link{display:inline-block;margin-top:.5rem;font-size:.78rem;font-weight:700;opacity:.75;white-space:nowrap}.restock-inline-row .restock-inline-history-link:hover{opacity:1}.restock-inline-row .restock-inline-error{color:#c0392b}.toast-container{position:fixed;display:flex;flex-direction:column;gap:.75rem;pointer-events:none;z-index:10000}.toast-container.toast-top-right{top:20px;right:20px}.toast-container.toast-top-center{top:100px;left:50%;transform:translateX(-50%)}.toast-container.toast-top-left{top:20px;left:20px}.toast-container.toast-bottom-right{bottom:20px;right:20px}.toast-container.toast-bottom-center{bottom:20px;left:50%;transform:translateX(-50%)}.toast-container.toast-bottom-left{bottom:20px;left:20px}.toast{position:relative;display:flex;align-items:center;gap:.75rem;min-width:300px;max-width:500px;padding:1rem 1.25rem;background:var(--color-background);border-radius:8px;box-shadow:0 4px 12px rgba(0,0,0,.15),0 0 0 1px rgba(0,0,0,.05);pointer-events:auto;overflow:hidden;opacity:0;transform:translateY(-50px);transition:all .3s cubic-bezier(0.68, -0.55, 0.265, 1.55);font-family:inherit}.toast.toast-show{opacity:1;transform:translateY(0)}.toast.toast-hide{opacity:0;transform:translateY(-50px) scale(0.95)}.toast.toast-success{border-left:4px solid #10b981}.toast.toast-success .toast-icon{color:#10b981}.toast.toast-error{border-left:4px solid #ef4444}.toast.toast-error .toast-icon{color:#ef4444}.toast.toast-warning{border-left:4px solid #f59e0b}.toast.toast-warning .toast-icon{color:#f59e0b}.toast.toast-info{border-left:4px solid #3b82f6}.toast.toast-info .toast-icon{color:#3b82f6}.toast.toast-default{border-left:4px solid var(--color-grey-500)}.toast-icon{flex-shrink:0;width:24px;height:24px}.toast-icon svg{width:100%;height:100%}.toast-message{flex:1;font-size:.875rem;line-height:1.5;color:var(--color-text);word-break:break-word;font-family:inherit}.toast-close{flex-shrink:0;width:24px;height:24px;display:flex;align-items:center;justify-content:center;background:rgba(0,0,0,0);border:none;border-radius:4px;color:var(--color-grey-500);font-size:1.5rem;line-height:1;cursor:pointer;transition:all .2s ease;padding:0;margin-left:.25rem}.toast-close:hover{background:var(--color-grey-800);color:var(--color-text)}.toast-close:active{transform:scale(0.95)}.toast-progress{position:absolute;bottom:0;left:0;right:0;height:3px;background:currentColor;opacity:.3;transform-origin:left;transition:transform linear}html[data-darkmode=true] .toast{background:var(--color-grey-300);box-shadow:0 4px 12px rgba(0,0,0,.4),0 0 0 1px hsla(0,0%,100%,.05)}html[data-darkmode=true] .toast-close:hover{background:var(--color-grey-400)}@media only screen and (max-width: 768px){.toast-container{left:50% !important;right:auto !important;top:80px !important;transform:translateX(-50%) !important;align-items:center}.toast-container.toast-bottom-right,.toast-container.toast-bottom-center,.toast-container.toast-bottom-left{top:auto !important;bottom:80px !important}.toast{min-width:auto;max-width:none;width:80vw;transform:translateY(-100px)}.toast.toast-show{transform:translateY(0)}.toast.toast-hide{transform:translateY(-100px) scale(0.95)}}@media(prefers-reduced-motion: reduce){.toast{transition:opacity .2s ease;transform:none !important}.toast.toast-show{opacity:1}.toast.toast-hide{opacity:0}}.login-form{min-height:52vh;display:flex;align-items:center;justify-content:center;padding:2rem 1rem}.login-form .inner{background:var(--color-background);border-radius:16px;box-shadow:0 10px 40px rgba(0,0,0,.08),0 2px 8px rgba(0,0,0,.04);padding:3rem 2.5rem;width:100%;max-width:420px;position:relative;overflow:hidden;transition:transform .3s ease,box-shadow .3s ease}.login-form .inner:hover{box-shadow:0 15px 50px rgba(0,0,0,.12),0 5px 15px rgba(0,0,0,.06)}.login-form form{margin:0}.login-form fieldset{border:none;padding:0;margin:0}.login-form .pure-control-group{margin-bottom:1.75rem}.login-form .pure-control-group:last-of-type{margin-bottom:0;margin-top:2rem}.login-form label{display:block;margin-bottom:.5rem;font-weight:600;font-size:.9rem;color:var(--color-text);letter-spacing:.01em}.login-form input[type=password]{width:100%;padding:.875rem 1rem;border:2px solid var(--color-grey-800);border-radius:8px;font-size:1rem;background:var(--color-background-input);color:var(--color-text-input);transition:all .2s ease;box-sizing:border-box}.login-form input[type=password]:focus{outline:none;border-color:var(--color-link);box-shadow:0 0 0 3px rgba(27,152,248,.1);transform:translateY(-1px)}.login-form input[type=password]::placeholder{color:var(--color-text-input-placeholder)}.login-form button[type=submit]{width:100%;padding:.875rem 1.5rem;font-size:1rem;font-weight:600;border-radius:8px;border:none;background:var(--color-background-button-primary);color:var(--color-text-button);cursor:pointer;transition:all .2s ease;box-shadow:0 2px 8px rgba(27,152,248,.2)}.login-form button[type=submit]:hover{box-shadow:0 4px 12px rgba(27,152,248,.3);background:#06c}.login-form button[type=submit]:active{transform:translateY(0);box-shadow:0 2px 4px rgba(27,152,248,.2)}.content-main>ul.messages{position:fixed;top:120px;left:50%;transform:translateX(-50%);list-style:none;padding:0;margin:0;z-index:1000;min-width:300px;max-width:500px}.content-main>ul.messages li{padding:1rem 1.25rem;border-radius:8px;font-size:.95rem;line-height:1.5;font-weight:500;box-shadow:0 4px 12px rgba(0,0,0,.15);animation:slideDown .3s ease-out;border:2px solid rgba(0,0,0,0)}.content-main>ul.messages li.error{background:#fee;border:2px solid #ef4444;color:#991b1b;font-weight:600}.content-main>ul.messages li.success{background:#f0fdf4;border:2px solid #10b981;color:#166534}.content-main>ul.messages li.info,.content-main>ul.messages li.message{background:#eff6ff;border:2px solid #3b82f6;color:#1e40af}@keyframes slideDown{from{opacity:0;transform:translateY(-20px)}to{opacity:1;transform:translateY(0)}}html[data-darkmode=true] .login-form .inner{box-shadow:0 10px 40px rgba(0,0,0,.4),0 2px 8px rgba(0,0,0,.2)}html[data-darkmode=true] .login-form .inner:hover{box-shadow:0 15px 50px rgba(0,0,0,.5),0 5px 15px rgba(0,0,0,.3)}html[data-darkmode=true] .login-form input[type=password]{border-color:var(--color-grey-400)}html[data-darkmode=true] .login-form input[type=password]:focus{border-color:var(--color-link)}html[data-darkmode=true] .content-main>ul.messages li{box-shadow:0 4px 12px rgba(0,0,0,.4)}html[data-darkmode=true] .content-main>ul.messages li.error{background:#4a1d1d;border-color:#ef4444;color:#fca5a5}html[data-darkmode=true] .content-main>ul.messages li.success{background:#1a3a2a;border-color:#10b981;color:#86efac}html[data-darkmode=true] .content-main>ul.messages li.info,html[data-darkmode=true] .content-main>ul.messages li.message{background:#1e3a5f;border-color:#3b82f6;color:#93c5fd}@media only screen and (max-width: 768px){.login-form{min-height:auto;padding:1rem .5rem;padding-top:5rem}.login-form .inner{padding:2rem 1.5rem;border-radius:12px}.content-main>ul.messages{top:70px;left:10px;right:10px;transform:none;min-width:auto}}body.wrapped-tabs .tabs ul{grid-template-columns:repeat(auto-fill, minmax(var(--tab-width, 180px), 1fr));grid-auto-flow:row;grid-auto-columns:unset;gap:0;column-gap:5px}body.wrapped-tabs .tabs ul li{border-radius:0}.tabs ul{margin:0px;padding:0px;display:grid;grid-auto-flow:column;grid-auto-columns:max-content;gap:5px;list-style:none}.tabs ul li{white-space:nowrap;color:var(--color-text-tab);border-top-left-radius:5px;border-top-right-radius:5px;background-color:var(--color-background-tab)}.tabs ul li:not(.active):hover{background-color:var(--color-background-tab-hover)}.tabs ul li.active,.tabs ul li :target{background-color:var(--color-background)}.tabs ul li.active a,.tabs ul li :target a{color:var(--color-text-tab-active);font-weight:bold}.tabs ul li a{display:block;padding:.7em;color:var(--color-text-tab)}.stab-shell{display:flex;align-items:stretch;background:var(--color-background);border:1px solid rgba(0,0,0,.08);border-radius:8px;overflow:hidden;box-shadow:0 2px 8px rgba(0,0,0,.05);margin-bottom:1.5rem}.stab-nav{display:flex;flex-direction:column;width:11rem;flex-shrink:0;padding:.75rem 0;gap:1px;background:linear-gradient(180deg, rgba(0, 0, 0, 0.03) 0%, rgba(0, 0, 0, 0.05) 100%);border-right:1px solid rgba(0,0,0,.07)}.stab-btn{position:relative;display:flex;align-items:center;gap:.5rem;padding:.65rem .9rem .65rem 1rem;width:100%;background:none;border:none;border-left:3px solid rgba(0,0,0,0);border-radius:0;cursor:pointer;font:inherit;color:var(--color-text);text-align:left;opacity:.65;transition:background .12s ease,opacity .12s ease,border-color .12s ease,color .12s ease}.stab-btn:hover{background:rgba(0,0,0,.04);opacity:.85}.stab-btn.active{border-left-color:var(--color-menu-accent);background:rgba(237,89,0,.07);color:var(--color-menu-accent);font-weight:700;opacity:1}.stab-btn .stab-icon{display:inline-flex;align-items:center;justify-content:center;width:1.1rem;flex-shrink:0;opacity:.8}.stab-btn .stab-icon svg{width:.95rem;height:.95rem;stroke:currentColor;fill:none}.stab-body{flex:1;min-width:0;padding:1.4rem 1.6rem;overflow-x:hidden}.stab-pane{visibility:hidden;height:0;overflow:hidden}.stab-pane.active{visibility:visible;height:auto;overflow:visible;animation:stab-enter .16s ease both}@keyframes stab-enter{from{opacity:0;transform:translateY(5px)}to{opacity:1;transform:translateY(0)}}.stab-overview-hero{margin-bottom:1.5rem}.stab-overview-hero h3{margin:0 0 .3rem;font-size:1.05rem}.stab-overview-hero .stab-overview-glyph{color:var(--color-menu-accent);margin-right:.2rem}.stab-overview-hero .stab-overview-glyph svg{width:1.1rem;height:1.1rem;stroke:currentColor;fill:none;vertical-align:-0.15em}.stab-overview-hero p{margin:0;font-size:.88rem;color:var(--color-text-input-description);max-width:44rem;line-height:1.55}.stab-overview-features{display:flex;flex-direction:column;gap:.7rem;margin-bottom:1.6rem}.stab-overview-feature{display:flex;gap:.85rem;align-items:flex-start;padding:.75rem 1rem;border-radius:6px;background:rgba(0,0,0,.022);border:1px solid rgba(0,0,0,.05);transition:background .12s ease}.stab-overview-feature:hover{background:rgba(0,0,0,.035)}.stab-overview-feature .stab-overview-icon{width:1.6rem;flex-shrink:0;padding-top:.05rem;opacity:.7;display:flex;justify-content:center}.stab-overview-feature .stab-overview-icon svg{width:1.3rem;height:1.3rem;stroke:currentColor;fill:none}.stab-overview-feature .stab-overview-text>strong{display:block;margin-bottom:.2rem}.stab-overview-feature .stab-overview-text p{color:var(--color-text-input-description)}.stab-overview-disclaimer{display:flex;gap:.75rem;align-items:flex-start;margin:0 0 1.1rem;padding:.85rem 1rem;border-radius:6px;border:1px solid rgba(211,136,0,.35);background:rgba(255,180,0,.07)}.stab-overview-disclaimer .stab-disclaimer-icon{flex-shrink:0;padding-top:.05rem;color:#c07800}.stab-overview-disclaimer .stab-disclaimer-icon svg{width:1.2rem;height:1.2rem;stroke:currentColor;fill:none}.stab-overview-disclaimer .stab-disclaimer-body{font-size:.85rem;line-height:1.55}.stab-overview-disclaimer .stab-disclaimer-body>strong{display:block;margin-bottom:.35rem;color:#8a5500;font-size:.87rem}.stab-overview-disclaimer .stab-disclaimer-body p{margin:0 0 .45rem;color:var(--color-text-input-description)}.stab-overview-disclaimer .stab-disclaimer-body ul{margin:0 0 .6rem;padding-left:1.25rem;color:var(--color-text-input-description)}.stab-overview-disclaimer .stab-disclaimer-body ul li{margin-bottom:.2rem}.stab-overview-disclaimer .stab-disclaimer-check{display:flex;gap:.5rem;align-items:flex-start;cursor:pointer;font-size:.82rem;color:var(--color-text-input-description);font-weight:600}.stab-overview-disclaimer .stab-disclaimer-check input[type=checkbox]{flex-shrink:0;margin-top:.18rem;cursor:pointer}.stab-overview-cta{margin-top:.4rem;display:flex;align-items:center;gap:.8rem;flex-wrap:wrap}.stab-configured-badge{display:inline-flex;align-items:center;gap:.4rem;padding:.35rem .75rem;background:rgba(39,174,96,.09);border:1px solid rgba(39,174,96,.28);border-radius:4px;color:#2a7a4e;font-size:.82rem;font-weight:600}.stab-section-title{font-size:.72rem;font-weight:700;letter-spacing:.07em;text-transform:uppercase;opacity:.45;margin:1.4rem 0 .6rem}.stab-section-title:first-child{margin-top:0}@media(max-width: 600px){.stab-shell{flex-direction:column;min-height:unset}.stab-nav{width:100%;border-right:none;border-bottom:1px solid rgba(0,0,0,.07);padding:.4rem 0}.stab-body{padding-left:1rem}}.llm-usage-grid{display:grid;grid-template-columns:repeat(auto-fit, minmax(12rem, 1fr));gap:.9rem;margin-bottom:1.4rem}.llm-stat-card{padding:1rem 1.1rem .85rem;border-radius:7px;background:rgba(0,0,0,.025);border:1px solid rgba(0,0,0,.07)}.llm-stat-card .llm-stat-label{font-size:.7rem;font-weight:700;letter-spacing:.07em;text-transform:uppercase;opacity:.4;margin-bottom:.4rem}.llm-stat-card .llm-stat-value{font-size:1.65rem;font-weight:700;letter-spacing:-0.02em;line-height:1;margin-bottom:.25rem}.llm-stat-card .llm-stat-sub{font-size:.79rem;opacity:.5}.llm-stat-card .llm-stat-budget-text{font-size:.77rem;opacity:.55;margin-top:.3rem}.llm-stat-bar-wrap{height:4px;border-radius:2px;background:rgba(0,0,0,.1);overflow:hidden;margin-top:.65rem}.llm-stat-bar-fill{height:100%;border-radius:2px;transition:width .5s ease}.llm-stat-bar-fill.bar-ok{background:#27ae60}.llm-stat-bar-fill.bar-warn{background:#e67e22}.llm-stat-bar-fill.bar-over{background:#c0392b}.llm-usage-settings{border-top:1px solid rgba(0,0,0,.07);padding-top:.9rem;display:flex;flex-direction:column;gap:.65rem}.llm-usage-row{display:flex;align-items:baseline;gap:.9rem;flex-wrap:wrap}.llm-usage-row .llm-usage-row-label{font-size:.82rem;font-weight:600;opacity:.6;min-width:12rem;flex-shrink:0}.llm-usage-row .llm-usage-row-value{display:flex;align-items:baseline;gap:.5rem;flex-wrap:wrap;font-size:.88rem}.llm-field-hint{font-size:.8rem;opacity:.55}.llm-env-badge{font-size:.79rem;opacity:.6}.llm-budget-alert{color:#c0392b;font-weight:600;font-size:.88rem;margin:0 0 1rem}.llm-no-usage{opacity:.5;font-style:italic;font-size:.88rem;margin-bottom:1rem}html[data-darkmode=true] .stab-shell{border-color:hsla(0,0%,100%,.07);box-shadow:0 2px 8px rgba(0,0,0,.25)}html[data-darkmode=true] .stab-nav{background:linear-gradient(180deg, rgba(255, 255, 255, 0.025) 0%, rgba(255, 255, 255, 0.04) 100%);border-right-color:hsla(0,0%,100%,.07)}html[data-darkmode=true] .stab-btn:hover{background:hsla(0,0%,100%,.05)}html[data-darkmode=true] .stab-btn.active{background:rgba(237,89,0,.12)}html[data-darkmode=true] .stab-overview-feature{background:hsla(0,0%,100%,.025);border-color:hsla(0,0%,100%,.05)}html[data-darkmode=true] .stab-overview-feature:hover{background:hsla(0,0%,100%,.04)}html[data-darkmode=true] .stab-configured-badge{background:rgba(39,174,96,.1);border-color:rgba(39,174,96,.22);color:#5db880}html[data-darkmode=true] .stab-overview-disclaimer{border-color:rgba(255,190,50,.22);background:rgba(255,180,0,.05)}html[data-darkmode=true] .stab-overview-disclaimer .stab-disclaimer-icon{color:#c9963a}html[data-darkmode=true] .stab-overview-disclaimer .stab-disclaimer-body>strong{color:#c9a050}html[data-darkmode=true] .llm-stat-card{background:hsla(0,0%,100%,.03);border-color:hsla(0,0%,100%,.07)}html[data-darkmode=true] .llm-stat-bar-wrap{background:hsla(0,0%,100%,.1)}html[data-darkmode=true] .llm-usage-settings{border-top-color:hsla(0,0%,100%,.07)}body,.pure-table,.pure-table thead,.pure-table td,.pure-table th,.pure-form input,.pure-form textarea,.pure-form select,.edit-form .inner,.pure-menu-horizontal,footer,.sticky-tab,#diff-jump,.button-tag,#new-watch-form,#new-watch-form input:not(.pure-button),code,.messages li,#checkbox-operations,.inline-warning,a,.watch-controls img{transition:color .4s ease,background-color .4s ease,background .4s ease,border-color .4s ease,box-shadow .4s ease}body{color:var(--color-text);background:var(--color-background-page);font-family:Helvetica Neue,Helvetica,Lucida Grande,Arial,Ubuntu,Cantarell,Fira Sans,sans-serif}.app{display:flex;align-items:stretch;min-height:100vh}.app-main{flex:1 1 auto;min-width:0;display:flex;flex-direction:column;gap:.55rem}.content-wrapper{display:flex;width:100%;max-width:100%;position:relative;align-items:flex-start}@media only screen and (max-width: 980px){.content-wrapper{flex-direction:column}}.content-main{flex:1 1 auto;width:100%;min-width:0;display:flex;flex-direction:column;align-items:center}@media only screen and (min-width: 980px){.content-main{flex-direction:column}}.visually-hidden{clip:rect(0 0 0 0);clip-path:inset(50%);height:1px;overflow:hidden;position:absolute;white-space:nowrap;width:1px}.status-icon{display:inline-block;height:1rem;vertical-align:middle}a{text-decoration:none;color:var(--color-link)}#search-result-info{color:#fff}button.toggle-button{vertical-align:middle;background:rgba(0,0,0,0);border:none;cursor:pointer;color:var(--color-text-menu-heading)}button.toggle-button svg{fill:currentColor}button.toggle-button svg.feather{fill:none;stroke:currentColor}button.toggle-button .icon-light{display:block}body.spinner-active #pure-menu-horizontal-spinner{animation:gradient 1s ease infinite}@keyframes gradient{0%{background-position:0% 50%}50%{background-position:100% 50%}100%{background-position:0% 50%}}#cdio-logo{color:var(--color-white);text-transform:uppercase}.pure-menu-link{color:var(--color-text-menu-link)}.pure-menu-link:hover{background-color:var(--color-background-menu-link-hover);color:var(--color-text-menu-link-hover)}.tab-pane-inner{scroll-margin-top:200px}section.content{padding-bottom:1em;padding-left:.55rem;padding-right:.55rem;flex-direction:column;display:flex;align-items:center;justify-content:flex-start}details summary{cursor:pointer;font-weight:600;color:var(--color-link);width:fit-content}details summary:hover{text-decoration:underline}code{background:var(--color-background-code);color:var(--color-text)}.inline-tag,.restock-label,.tracking-ldjson-price-data,.watch-tag-list,.processor-badge{white-space:nowrap;border-radius:5px;padding:2px 5px;margin-right:4px}.processor-badge{font-weight:900;text-decoration:none}.processor-badge:hover{text-decoration:none;opacity:.8;cursor:pointer}.processor-badge.active{outline:2px solid var(--color-link);outline-offset:1px}.watch-tag-list{color:var(--color-white);background:var(--color-text-watch-tag-list);text-decoration:none}.watch-tag-list:hover{text-decoration:none;opacity:.8;cursor:pointer}.watch-tag-list:visited{color:var(--color-white)}body:after{content:"";background:linear-gradient(130deg, var(--color-background-gradient-first), var(--color-background-gradient-second) 41.07%, var(--color-background-gradient-third) 84.05%)}body:after,body:before{display:block;position:fixed;top:0;left:0;width:100%;height:100vh;z-index:-1}body::after{opacity:.91}body::before{content:""}.button-small{font-size:85%}.button-xsmall{font-size:70%}.fetch-error{padding-top:1em;font-size:80%;max-width:400px;display:block}.pure-button-primary,a.pure-button-primary,.pure-button-selected,a.pure-button-selected{background-color:var(--color-background-button-primary)}.button-secondary{color:var(--color-text-button);border-radius:4px;text-shadow:0 1px 1px rgba(0,0,0,.2)}.button-success{background:var(--color-background-button-success)}.button-tag{background:var(--color-background-button-tag);color:var(--color-text-button);font-size:75%;border-radius:6px;margin-right:4px;margin-bottom:1px}.button-tag.active{background:var(--color-background-button-tag-active);font-weight:bold}.button-error{background:var(--color-background-button-error);color:var(--color-text-button-error)}.button-warning{background:var(--color-background-button-warning);color:var(--color-text-button-warning)}.button-secondary{background:var(--color-background-button-secondary)}.button-cancel{background:var(--color-background-button-cancel)}.messages li{list-style:none;padding:1em;border-radius:10px;color:var(--color-text-messages);font-weight:bold}.messages li.message{background:var(--color-background-messages-message)}.messages li.error{background:var(--color-background-messages-error)}.messages li.notice{background:var(--color-background-messages-notice)}.messages.with-share-link>*:hover{cursor:pointer}label:hover{cursor:pointer}.grey-form-border{border:1px solid var(--color-border-notification);padding:.5rem;border-radius:5px}#token-table.pure-table td,#token-table.pure-table th{font-size:80%}.pure-form input[type=text].transparent-field{background-color:var(--color-background-new-watch-input-transparent) !important;color:var(--color-white) !important;border:1px solid hsla(0,0%,100%,.2) !important;box-shadow:none !important;-webkit-box-shadow:none !important}.pure-form input[type=text].transparent-field::placeholder{opacity:.5;color:hsla(0,0%,100%,.7);font-weight:lighter}#new-watch-form{background:var(--color-background-new-watch-form);padding:1em;border-radius:10px;max-width:100%}#new-watch-form #url::placeholder{font-weight:bold}#new-watch-form input{display:inline-block}#new-watch-form input:not(.pure-button){background-color:var(--color-background-new-watch-input);color:var(--color-text-new-watch-input)}#new-watch-form .label{display:none}#new-watch-form legend{color:var(--color-text-legend);font-weight:bold}@media only screen and (min-width: 760px){#new-watch-form #watch-add-wrapper-zone{display:flex;gap:.3rem;flex-direction:row;min-width:70vw}}#new-watch-form #watch-add-wrapper-zone>span{flex-grow:0}#new-watch-form #watch-add-wrapper-zone>span input{width:100%;padding-right:1em}#new-watch-form #watch-add-wrapper-zone>span:first-child{flex-grow:1}@media only screen and (max-width: 760px){#new-watch-form #watch-add-wrapper-zone #url{width:100%}}#new-watch-form #watch-group-tag{font-size:.9rem;padding:.3rem;display:flex;align-items:center;gap:.5rem;color:var(--color-white)}#new-watch-form #watch-group-tag label,#new-watch-form #watch-group-tag input{margin:0}#new-watch-form #watch-group-tag input{flex:1}#diff-col{padding-left:40px}#diff-jump{position:fixed;left:0px;top:120px;background:var(--color-background);padding:10px;border-top-right-radius:5px;border-bottom-right-radius:5px;box-shadow:1px 1px 4px var(--color-shadow-jump)}#diff-jump a{color:var(--color-link);cursor:pointer;-moz-user-select:none;-webkit-user-select:none;-ms-user-select:none;user-select:none;-o-user-select:none}footer{padding:10px;background:var(--color-background);color:var(--color-text-footer);text-align:center}#feed-icon{vertical-align:middle}#new-version-text a{color:var(--color-link-new-version)}.watch-controls{color:#f8321b}.watch-controls .state-on img{opacity:.8}.watch-controls img{opacity:.2}.watch-controls img:hover{transition:opacity .3s;opacity:.8}.monospaced-textarea textarea{width:100%;font-family:monospace;white-space:pre;overflow-wrap:normal;overflow-x:auto}.pure-form fieldset{padding-top:0px}.pure-form fieldset ul{padding-bottom:0px;margin-bottom:0px}.pure-form .pure-control-group,.pure-form .pure-group,.pure-form .pure-controls{padding-bottom:1em}.pure-form .pure-control-group div,.pure-form .pure-group div,.pure-form .pure-controls div{margin:0px}.pure-form .pure-control-group .checkbox>*,.pure-form .pure-group .checkbox>*,.pure-form .pure-controls .checkbox>*{display:inline;vertical-align:middle}.pure-form .pure-control-group .checkbox>label,.pure-form .pure-group .checkbox>label,.pure-form .pure-controls .checkbox>label{padding-left:5px}.pure-form .pure-control-group legend,.pure-form .pure-group legend,.pure-form .pure-controls legend{color:var(--color-text-legend)}.pure-form .error input{background-color:var(--color-error-input)}.pure-form ul.errors{padding:.5em .6em;border:1px solid var(--color-error-list);border-radius:4px;vertical-align:middle;-webkit-box-sizing:border-box;box-sizing:border-box}.pure-form ul.errors li{margin-left:1em;color:var(--color-error-list)}.pure-form label{font-weight:bold}.pure-form textarea{width:100%}.pure-form .inline-radio ul{margin:0px;list-style:none}.pure-form .inline-radio ul li{display:flex;align-items:center;gap:1em}@media only screen and (max-width: 760px),(min-device-width: 768px)and (max-device-width: 980px){.edit-form{padding:.5em;margin:0}#nav-menu{overflow-x:scroll}}@media only screen and (max-width: 760px),(min-device-width: 768px)and (max-device-width: 980px){input[type=text]{width:100%}}.pure-table{border-color:var(--color-border-table-cell)}.pure-table thead{background-color:var(--color-background-table-thead);color:var(--color-text);border-bottom:1px solid var(--color-background-table-thead)}.pure-table td,.pure-table th{border-left-color:var(--color-border-table-cell)}.pure-form input[type=color],.pure-form input[type=date],.pure-form input[type=datetime-local],.pure-form input[type=datetime],.pure-form input[type=email],.pure-form input[type=month],.pure-form input[type=number],.pure-form input[type=password],.pure-form input[type=search],.pure-form input[type=tel],.pure-form input[type=text],.pure-form input[type=time],.pure-form input[type=url],.pure-form input[type=week],.pure-form select,.pure-form textarea{border:var(--color-border-input);box-shadow:inset 0 1px 3px var(--color-shadow-input);background-color:var(--color-background-input);color:var(--color-text-input)}.pure-form input[type=color]:active,.pure-form input[type=date]:active,.pure-form input[type=datetime-local]:active,.pure-form input[type=datetime]:active,.pure-form input[type=email]:active,.pure-form input[type=month]:active,.pure-form input[type=number]:active,.pure-form input[type=password]:active,.pure-form input[type=search]:active,.pure-form input[type=tel]:active,.pure-form input[type=text]:active,.pure-form input[type=time]:active,.pure-form input[type=url]:active,.pure-form input[type=week]:active,.pure-form select:active,.pure-form textarea:active{background-color:var(--color-background-input)}input::placeholder,textarea::placeholder{color:var(--color-text-input-placeholder)}.m-d{min-width:100%}@media only screen and (min-width: 761px){.m-d{min-width:80%}}.pure-form-stacked>div:first-child{display:block}.tab-pane-inner{padding:0px}.tab-pane-inner:not(:target){display:none}.tab-pane-inner:target{display:block}.beta-logo{height:50px;right:-3px;top:-3px;position:absolute}#selector-header{padding-bottom:1em}.edit-form{max-width:95%}.edit-form .box-wrap{position:relative}.edit-form .inner{background:var(--color-background);padding:1.1rem}.edit-form #actions{display:block;background:var(--color-background)}.edit-form #actions .pure-control-group{display:flex;gap:.625em;flex-wrap:wrap}.edit-form .pure-form-message-inline{padding-left:0;color:var(--color-text-input-description)}.edit-form .pure-form-message-inline code{font-size:.875em}.border-fieldset{border:1px solid #ccc;padding:1rem;border-radius:5px;margin-bottom:1rem}.border-fieldset h3{margin-top:0}.border-fieldset fieldset:last-of-type{padding-bottom:0}.border-fieldset fieldset:last-of-type .pure-control-group{padding-bottom:0}ul{padding-left:1em;padding-top:0px;margin-top:4px}.time-check-widget tr{display:inline}.time-check-widget tr input[type=number]{width:5em}@media only screen and (max-width: 760px){.time-check-widget tbody{display:grid;grid-template-columns:auto 1fr auto 1fr;gap:.625em .3125em;align-items:center}.time-check-widget tr{display:contents}.time-check-widget tr th{text-align:right;padding-right:5px}.time-check-widget tr input[type=number]{width:100%;max-width:5em}}#webdriver_delay{width:5em}#api-key:hover{cursor:pointer}#api-key-copy{color:var(--color-api-key)}.button-green{background-color:var(--color-background-button-green)}.button-red{background-color:var(--color-background-button-red)}.noselect{-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}[type=checkbox],[type=radio]{width:17px;height:17px;border-radius:5px;cursor:pointer}.inline-warning{border:1px solid var(--color-border-warning);padding:.5rem;border-radius:5px;color:var(--color-warning)}.inline-warning>span{display:inline-block;vertical-align:middle}.inline-warning img.inline-warning-icon{display:inline;height:26px;vertical-align:middle}.tracking-ldjson-price-data{background-color:var(--color-background-button-green);color:#000;opacity:.6}.ldjson-price-track-offer{font-weight:bold;font-style:italic}.ldjson-price-track-offer a.pure-button{border-radius:3px;padding:3px;background-color:var(--color-background-button-green)}.price-follow-tag-icon{display:inline-block;height:.8rem;vertical-align:middle}#quick-watch-processor-type ul#processor{color:#fff;padding-left:0px}#quick-watch-processor-type ul#processor li{list-style:none;font-size:.9rem;display:grid;grid-template-columns:auto 1fr;align-items:center;gap:.5rem;margin-bottom:.5rem}#quick-watch-processor-type label,#quick-watch-processor-type input{padding:0;margin:0}.restock-label.in-stock{background-color:#7a0cc5;color:#fff}.restock-label.not-in-stock{background-color:var(--color-background-button-cancel);color:#777}.restock-label.error{background-color:var(--color-background-button-error);color:#fff;opacity:.7}.restock-label.price{border:1px solid var(--color-background-button-cancel)}.restock-label svg{vertical-align:middle}.price-change{white-space:nowrap;font-weight:700;font-size:90%;margin-left:4px;vertical-align:middle}.price-change.down{color:var(--color-background-button-green)}.price-change.up{color:var(--color-background-button-error)}#chrome-extension-link{padding:9px;border:1px solid var(--color-grey-800);border-radius:10px;vertical-align:middle}#chrome-extension-link img{height:21px;padding:2px;vertical-align:middle}#realtime-conn-error{position:fixed;bottom:0;left:0;background:var(--color-warning);padding:10px;font-size:.8rem;color:#fff;opacity:.8;z-index:100}#bottom-horizontal-offscreen{position:fixed;bottom:0;left:0;right:0;width:100%;min-height:50px;max-height:50vh;background:hsla(0,0%,100%,.7215686275);border-top:1px solid var(--color-border-table-cell);padding:10px;box-shadow:0 -2px 10px rgba(0,0,0,.2);z-index:100;overflow-y:auto;transition:opacity .3s ease-in-out;scroll-margin-bottom:10px;display:flex;justify-content:center;align-items:center}ul#highlightSnippetActions{list-style:none}ul#highlightSnippetActions li{display:inline-block}@media only screen and (max-width: 768px){.box{padding:.25rem !important}}.box{color:var(--color-white);border-width:1px;border-style:dashed;border-color:hsla(0,0%,100%,.25);border-image:initial;background:hsla(0,0%,100%,.04);border-radius:var(--common-round-border);padding:1.1rem}header{color:var(--color-white)}#heart-us svg{display:inline-block;vertical-align:middle;cursor:pointer;width:1.4rem}textarea::placeholder{white-space:pre-wrap} diff --git a/changedetectionio/templates/edit/include_llm_intent.html b/changedetectionio/templates/edit/include_llm_intent.html index 0641d24bb..9c9535bdd 100644 --- a/changedetectionio/templates/edit/include_llm_intent.html +++ b/changedetectionio/templates/edit/include_llm_intent.html @@ -5,59 +5,130 @@ llm_configured — bool: LLM provider is configured in settings form — the WTForms form (must have .llm_intent and .llm_change_summary fields) - Optional (watch edit only): + Group/tag edit only: + llm_group_edit — bool: True when rendering the tag/group edit page. This is the ONLY + way to tell the two contexts apart — the tags blueprint also passes + the tag dict as `watch`, so `watch` is truthy in both. + form.llm_backend_profile is ternary here (On / Off / Leave it to each + watch) and is the group's only AI control; on a watch it is a checkbox. + + Watch edit only: watch — the Watch object (for processor check and prefilter display) llm_group_overrides — dict returned by _resolve_llm_group_overrides(): {'llm_intent': {'value': str, 'group_name': str} | None, - 'llm_change_summary': {'value': str, 'group_name': str} | None} - Present only in watch edit context; absent in tag edit context. + 'llm_change_summary': {'value': str, 'group_name': str} | None, + 'llm_backend_profile': {'value': bool, 'group_name': str} | None} + The two prompt entries are non-None only when the watch has no own + value AND a linked group set to "On" has one — that is what puts + "From group '': " in the placeholder. + llm_backend_profile is non-None when a linked group has taken the + on/off decision (On or Off, not "leave it to each watch") — #4204. - Usage in watch edit (edit.html): - {% include "edit/include_llm_intent.html" %} - - Usage in tag edit (edit-tag.html): - {% include "edit/include_llm_intent.html" %} - (watch is not set → tag mode: no processor check, no examples, different description) + Usage (both): {% include "edit/include_llm_intent.html" %} #} -{% from '_helpers.html' import render_field %} +{% from '_helpers.html' import render_field, render_checkbox_field, render_ternary_field %} -{# Processor check only applies in watch-edit context (llm_group_overrides present). #} -{# In tag/group edit context the AI section is always visible. #} +{% set llm_group_mode = llm_group_edit|default(false) %} + +{# Processor check only applies in watch-edit context. #} +{# In tag/group edit context the AI section is always visible. #} {# Processors whose edit form carries the AI Intent / Change Summary fields (i.e. those whose form inherits processor_text_json_diff_form). text_json_diff + restock_diff today. #} -{% if llm_group_overrides is defined %} - {% set show_ai_section = not watch.get('processor') or watch.get('processor') in ['text_json_diff', 'restock_diff'] %} -{% else %} +{% if llm_group_mode %} {% set show_ai_section = true %} +{% else %} + {% set show_ai_section = not watch.get('processor') or watch.get('processor') in ['text_json_diff', 'restock_diff'] %} +{% endif %} + +{# An unrendered switch is absent from the POST, and WTForms reads that as off. So whenever we + do NOT render the AI switch (no LLM provider configured, or a processor whose form has no AI + fields) we carry its saved state through in a hidden input — otherwise merely saving the page + would silently switch AI off. #} +{% if not (show_ai_section and llm_configured) %} + {% if llm_group_mode %} + {# Group: ternary, so preserve whichever of the three states it is in #} + {% if form.llm_backend_profile.data is not none %}{% endif %} + {% elif form.llm_backend_profile.data %} + + {% endif %} {% endif %} {% if show_ai_section %} {# ── Configured: show the intent + summary fields ────────────────── #} {% if llm_configured %} -
-

✨ {{ _('AI') }}

+
- {# — AI Change Intent — #} -

{{ _('AI — Notify when…') }}

+{% if llm_group_mode %} +{# The group's single AI control. "On" is also what makes the prompts below cascade to the + watches (tag_llm_applies_to_watches), so there is no second "does this override?" flag. #} +
+ {{ render_ternary_field(form.llm_backend_profile) }} + + {{ _('On – every watch in this group uses the AI settings below, unless it fills in its own. Off – no AI for any watch in this group. Leave it to each watch – this group has no say; each watch uses its own AI settings.')|safe }} + +
+{# The prompts below only mean something in the "On" state, so grey them out otherwise — the + radio counterpart of the toggleOpacity cue used by #overrides_watch on the restock tab. #} + +{% else %} +{# Per-watch AI on/off (#4204). Resolution is global settings → group → watch, so a group that + has taken the decision (its AI setting is On or Off rather than "leave it to each watch") + owns this control: we disable it, show the state the group decided, and name the group. + The watch's own preference is not lost — because the field isn't user-writable in this + state, edit.py ignores whatever the POST says for it and keeps the stored value. #} +{% set profile_group = llm_group_overrides.llm_backend_profile if llm_group_overrides is defined else none %} +
+ {# Only the checkbox is dimmed — the explanation of *why* has to stay readable. #} + + {% if profile_group %} + {# Show what the group decided, not this watch's now-inert own value. #} + {% set dummy = form.llm_backend_profile.__setattr__('checked', profile_group.value) %} + {{ render_checkbox_field(form.llm_backend_profile, disabled=True) }} + {% else %} + {{ render_checkbox_field(form.llm_backend_profile) }} + {% endif %} +
+ {% if profile_group %} + {# The group name links to its edit page so the decision can be changed where it lives. + Built as escaped markup and passed into the sentence, so translators keep one string. #} + {%- set group_link -%} + {{ profile_group.group_name }} + {%- endset -%} + + {% if profile_group.value %} + {{ _("Group %(name)s decides this: AI is ON for every watch in that group.", name=group_link) | safe }} + {% else %} + {{ _("Group %(name)s decides this: AI is OFF for every watch in that group.", name=group_link) | safe }} + {% endif %} + + {% endif %} +
+{% endif %} + +

- {% if watch is defined and watch %} + {% if not llm_group_mode %} {{ _('Describe what you care about. The AI evaluates every detected change against this and only notifies you when it matches.') }} {% else %} {{ _('Set a change intent for all watches in this tag/group. Each watch can override with its own.') }} {% endif %}

- {% if watch is defined and watch and llm_group_overrides is defined and llm_group_overrides.llm_intent %} + {% if not llm_group_mode and llm_group_overrides is defined and llm_group_overrides.llm_intent %} {% set intent_placeholder = _("From group '%(name)s': %(value)s", name=llm_group_overrides.llm_intent.group_name, value=llm_group_overrides.llm_intent.value) %} - {% elif watch is defined and watch %} + {% elif not llm_group_mode %} {% set intent_placeholder = _('e.g. Alert me when the price drops below $300, or a new product is launched. Ignore footer and navigation changes.') %} {% else %} {% set intent_placeholder = _('e.g. Flag price changes or new product launches across all watches in this group') %} {% endif %} {{ render_field(form.llm_intent, placeholder=intent_placeholder, rows=5, class="pure-input-1") }}
- {% if watch is defined and watch %} + {% if not llm_group_mode %}
{{ _('Examples:') }}
    @@ -67,19 +138,19 @@
  • {{ _('Only important if package versions change or a CVE is mentioned') }}
- {% if watch.get('llm_prefilter') %} + {% if watch is defined and watch.get('llm_prefilter') %}
{{ _('AI pre-filter active: %(filter)s — narrows content scope before evaluation', filter=watch.get('llm_prefilter')|e) | safe }}
{% endif %} {% endif %} -
+
+
{# — AI Change Summary — #} -

{{ _('AI Change Summary') }}

- {% if watch is defined and watch %} + {% if not llm_group_mode %} {{ _('When a change is detected, the AI describes it according to your instructions and replaces %(diff)s in your notification. Use %(raw_diff)s if you still want the original diff.', diff='{{diff}}', raw_diff='{{raw_diff}}') | safe }} {% else %} @@ -87,34 +158,30 @@ {% endif %}

- {% if watch is defined and watch and llm_group_overrides is defined and llm_group_overrides.llm_change_summary %} + {% if not llm_group_mode and llm_group_overrides is defined and llm_group_overrides.llm_change_summary %} {% set summary_placeholder = _("From group '%(name)s': %(value)s", name=llm_group_overrides.llm_change_summary.group_name, value=llm_group_overrides.llm_change_summary.value) %} {% else %} {% set summary_placeholder = form.llm_change_summary.render_kw['placeholder'] %} {% endif %} {{ render_field(form.llm_change_summary, placeholder=summary_placeholder, rows=5, class="pure-input-1") }} -
- -
- -
- {% for subfield in form.llm_change_summary_mode %} - - {% endfor %} +
+
+ {{ render_field(form.llm_change_summary_mode) }} + + {% if not llm_group_mode %} + {{ _('Appending keeps the prompt inherited from the group or from global settings and adds your text after it, so later edits to that prompt still reach this watch.') }} + {% else %} + {{ _('Appending keeps the prompt inherited from global settings and adds your text after it, so later edits to that prompt still reach this group.') }} + {% endif %} +
- - {% if watch is defined and watch %} - {{ _('Appending keeps the prompt inherited from the group or from global settings and adds your text after it, so later edits to that prompt still reach this watch.') }} - {% else %} - {{ _('Appending keeps the prompt inherited from global settings and adds your text after it, so later edits to that prompt still reach this group.') }} - {% endif %} -
- {% if watch is defined and watch %} + + + + {% if not llm_group_mode %}
{{ _('Examples:') }}
    @@ -125,13 +192,14 @@
{% endif %}
+
{# ── Not configured: greyed-out prompt to configure ──────────────── #} {% else %}

✨ {{ _('AI') }}

- {% if watch is defined and watch %} + {% if not llm_group_mode %} {{ _('Configure an AI / LLM provider in Settings → AI / LLM to enable AI Change Intent and AI Change Summary.', url=url_for('settings.settings_page') + '#ai') | safe }} {% else %} diff --git a/changedetectionio/tests/llm/test_evaluator.py b/changedetectionio/tests/llm/test_evaluator.py index 398797494..6b55ffac6 100644 --- a/changedetectionio/tests/llm/test_evaluator.py +++ b/changedetectionio/tests/llm/test_evaluator.py @@ -22,6 +22,19 @@ def _make_datastore(llm_cfg=None, tags=None): return ds +def _make_tag(ai=True, **fields): + """Build a tag dict. + + `ai` is the group's single AI control (llm_backend_profile): True = on, and its AI + settings apply to its watches; False = off for every watch in the group; None = the + group has no say. Defaults to True because most cases here are about what a group set + to "On" does. + """ + tag = {'title': 'grp', 'llm_backend_profile': ai} + tag.update(fields) + return tag + + def _make_watch(llm_intent='', llm_change_summary='', tags=None, uuid='test-uuid-1234'): w = {} w['llm_intent'] = llm_intent @@ -43,7 +56,7 @@ class TestResolveIntent: def test_watch_intent_takes_priority(self): from changedetectionio.llm.evaluator import resolve_intent - tag = {'title': 'mygroup', 'llm_intent': 'group intent'} + tag = _make_tag(title='mygroup', llm_intent='group intent') ds = _make_datastore(tags={'tag-1': tag}) watch = _make_watch(llm_intent='watch intent', tags=['tag-1']) @@ -54,7 +67,7 @@ class TestResolveIntent: def test_tag_intent_used_when_watch_has_none(self): from changedetectionio.llm.evaluator import resolve_intent - tag = {'title': 'pricing-group', 'llm_intent': 'flag price drops'} + tag = _make_tag(title='pricing-group', llm_intent='flag price drops') ds = _make_datastore(tags={'tag-1': tag}) watch = _make_watch(llm_intent='', tags=['tag-1']) @@ -73,10 +86,10 @@ class TestResolveIntent: assert source == '' def test_tag_applied_to_all_watches_in_group(self): - """Tag intent propagates to every watch in the tag (no opt-in needed).""" + """An opted-in tag's intent propagates to every watch in the tag.""" from changedetectionio.llm.evaluator import resolve_intent - tag = {'title': 'job-board', 'llm_intent': 'new engineering jobs'} + tag = _make_tag(title='job-board', llm_intent='new engineering jobs') ds = _make_datastore(tags={'tag-1': tag}) # Three different watches, all in the tag, none have their own intent @@ -103,6 +116,114 @@ class TestResolveIntent: assert intent == '' +# --------------------------------------------------------------------------- +# The group's AI setting gates the whole cascade +# --------------------------------------------------------------------------- + +class TestGroupAiSettingGatesTheCascade: + def test_only_the_on_state_hands_settings_down(self): + from changedetectionio.llm.evaluator import tag_llm_applies_to_watches + assert tag_llm_applies_to_watches(_make_tag(ai=True)) is True + # "Off" suppresses AI rather than lending prompts; "leave it to each watch" and tags + # predating the setting (and missing tags) hand nothing down either + assert tag_llm_applies_to_watches(_make_tag(ai=False)) is False + assert tag_llm_applies_to_watches(_make_tag(ai=None)) is False + assert tag_llm_applies_to_watches({'title': 'legacy'}) is False + assert tag_llm_applies_to_watches(None) is False + + def test_intent_not_inherited_when_group_is_off(self): + from changedetectionio.llm.evaluator import resolve_intent + tag = _make_tag(ai=False, title='pricing-group', llm_intent='flag price drops') + ds = _make_datastore(tags={'tag-1': tag}) + watch = _make_watch(llm_intent='', tags=['tag-1']) + assert resolve_intent(watch, ds) == ('', '') + + def test_field_not_inherited_when_group_is_off(self): + from changedetectionio.llm.evaluator import resolve_llm_field + tag = _make_tag(ai=False, llm_change_summary='list new events') + ds = _make_datastore(tags={'t1': tag}) + watch = _make_watch(llm_change_summary='', tags=['t1']) + assert resolve_llm_field(watch, ds, 'llm_change_summary') == ('', '') + + def test_summary_prompt_not_inherited_when_group_is_off(self): + from changedetectionio.llm.evaluator import get_effective_summary_prompt + tag = _make_tag(ai=False, llm_change_summary='TAG') + ds = _make_datastore(llm_cfg={'change_summary_default': 'GLOBAL'}, tags={'t1': tag}) + watch = _make_watch(llm_change_summary='', tags=['t1']) + assert get_effective_summary_prompt(watch, ds) == 'GLOBAL' + + def test_first_group_set_to_on_wins_over_an_earlier_one_that_is_off(self): + """A group that isn't "On" is skipped entirely, not treated as "found, but empty".""" + from changedetectionio.llm.evaluator import resolve_intent + ds = _make_datastore(tags={ + 'ignored': _make_tag(ai=False, title='ignored-group', llm_intent='IGNORED'), + 'used': _make_tag(ai=True, title='used-group', llm_intent='USED'), + }) + watch = _make_watch(llm_intent='', tags=['ignored', 'used']) + assert resolve_intent(watch, ds) == ('USED', 'used-group') + + +# --------------------------------------------------------------------------- +# llm_enabled_for_watch — per-watch / per-group AI on-off switch (#4204) +# --------------------------------------------------------------------------- + +class TestLlmEnabledForWatch: + def test_enabled_by_default(self): + """Watches predating the switch (no key at all) keep AI on.""" + from changedetectionio.llm.evaluator import llm_enabled_for_watch + ds = _make_datastore() + assert llm_enabled_for_watch(_make_watch(), ds) == (True, 'watch') + + def test_watch_switch_off(self): + from changedetectionio.llm.evaluator import llm_enabled_for_watch + ds = _make_datastore() + watch = _make_watch() + watch['llm_backend_profile'] = False + assert llm_enabled_for_watch(watch, ds) == (False, 'watch') + + def test_group_switch_overrides_watch_off(self): + """"The group setting overrides any watch on/off" — group ON beats watch OFF.""" + from changedetectionio.llm.evaluator import llm_enabled_for_watch + tag = _make_tag(ai=True, title='ai-group') + ds = _make_datastore(tags={'t1': tag}) + watch = _make_watch(tags=['t1']) + watch['llm_backend_profile'] = False + assert llm_enabled_for_watch(watch, ds) == (True, 'ai-group') + + def test_group_switch_overrides_watch_on(self): + from changedetectionio.llm.evaluator import llm_enabled_for_watch + tag = _make_tag(ai=False, title='no-ai-group') + ds = _make_datastore(tags={'t1': tag}) + watch = _make_watch(tags=['t1']) + watch['llm_backend_profile'] = True + assert llm_enabled_for_watch(watch, ds) == (False, 'no-ai-group') + + def test_group_leaving_it_to_each_watch_does_not_decide(self): + from changedetectionio.llm.evaluator import llm_enabled_for_watch + ds = _make_datastore(tags={'t1': _make_tag(ai=None, title='undecided-group')}) + watch = _make_watch(tags=['t1']) + watch['llm_backend_profile'] = False + assert llm_enabled_for_watch(watch, ds) == (False, 'watch') + + def test_group_without_the_key_leaves_it_to_the_watch(self): + """Tags predating the setting behave like "leave it to each watch".""" + from changedetectionio.llm.evaluator import llm_enabled_for_watch + ds = _make_datastore(tags={'t1': {'title': 'legacy'}}) + watch = _make_watch(tags=['t1']) + watch['llm_backend_profile'] = False + assert llm_enabled_for_watch(watch, ds) == (False, 'watch') + + def test_first_deciding_group_wins(self): + """An undecided group is skipped; the next group with an opinion decides.""" + from changedetectionio.llm.evaluator import llm_enabled_for_watch + ds = _make_datastore(tags={ + 'a': _make_tag(ai=None, title='undecided-group'), + 'b': _make_tag(ai=False, title='no-ai-group'), + }) + watch = _make_watch(tags=['a', 'b']) + assert llm_enabled_for_watch(watch, ds) == (False, 'no-ai-group') + + # --------------------------------------------------------------------------- # get_llm_config # --------------------------------------------------------------------------- @@ -386,7 +507,7 @@ class TestTokenBudget: class TestResolveLlmField: def test_watch_value_takes_priority(self): from changedetectionio.llm.evaluator import resolve_llm_field - tag = {'title': 'mygroup', 'llm_change_summary': 'tag summary prompt'} + tag = _make_tag(title='mygroup', llm_change_summary='tag summary prompt') ds = _make_datastore(tags={'tag-1': tag}) watch = _make_watch(llm_change_summary='watch summary prompt', tags=['tag-1']) value, source = resolve_llm_field(watch, ds, 'llm_change_summary') @@ -395,7 +516,7 @@ class TestResolveLlmField: def test_tag_value_used_when_watch_empty(self): from changedetectionio.llm.evaluator import resolve_llm_field - tag = {'title': 'events-group', 'llm_change_summary': 'list new events'} + tag = _make_tag(title='events-group', llm_change_summary='list new events') ds = _make_datastore(tags={'tag-1': tag}) watch = _make_watch(llm_change_summary='', tags=['tag-1']) value, source = resolve_llm_field(watch, ds, 'llm_change_summary') @@ -413,7 +534,7 @@ class TestResolveLlmField: def test_works_for_llm_intent_field_too(self): """resolve_llm_field is generic — works for llm_intent same as llm_change_summary.""" from changedetectionio.llm.evaluator import resolve_llm_field - tag = {'title': 'grp', 'llm_intent': 'flag price drops'} + tag = _make_tag(llm_intent='flag price drops') ds = _make_datastore(tags={'t1': tag}) watch = _make_watch(llm_intent='', tags=['t1']) value, source = resolve_llm_field(watch, ds, 'llm_intent') @@ -469,7 +590,7 @@ class TestSummariseChange: def test_cascades_from_tag(self): """llm_change_summary on a tag propagates to watches in that tag.""" from changedetectionio.llm.evaluator import summarise_change - tag = {'title': 'events', 'llm_change_summary': 'Translate events to English'} + tag = _make_tag(title='events', llm_change_summary='Translate events to English') ds = _make_datastore(llm_cfg={'model': 'gpt-4o-mini'}, tags={'tag-1': tag}) watch = _make_watch(llm_change_summary='', tags=['tag-1']) with patch('changedetectionio.llm.client.completion', @@ -552,7 +673,7 @@ class TestSummaryCacheKey: def test_get_effective_prompt_cascades_from_tag(self): from changedetectionio.llm.evaluator import get_effective_summary_prompt - tag = {'title': 'grp', 'llm_change_summary': 'tag-level prompt'} + tag = _make_tag(llm_change_summary='tag-level prompt') ds = _make_datastore(tags={'t1': tag}) watch = _make_watch(llm_change_summary='', tags=['t1']) assert get_effective_summary_prompt(watch, ds) == 'tag-level prompt' @@ -592,7 +713,7 @@ class TestSummaryPromptAppendMode: def test_watch_append_targets_the_tag_prompt_when_a_tag_supplies_one(self): """The watch appends to what it would otherwise have inherited — here the tag.""" from changedetectionio.llm.evaluator import get_effective_summary_prompt - tag = {'title': 'grp', 'llm_change_summary': 'TAG'} + tag = _make_tag(llm_change_summary='TAG') ds = _make_datastore(llm_cfg={'change_summary_default': 'GLOBAL'}, tags={'t1': tag}) watch = _make_watch(llm_change_summary='WATCH', tags=['t1']) watch['llm_change_summary_mode'] = 'append' @@ -600,7 +721,7 @@ class TestSummaryPromptAppendMode: def test_tag_and_watch_can_both_append_forming_a_chain(self): from changedetectionio.llm.evaluator import get_effective_summary_prompt - tag = {'title': 'grp', 'llm_change_summary': 'TAG', 'llm_change_summary_mode': 'append'} + tag = _make_tag(llm_change_summary='TAG', llm_change_summary_mode='append') ds = _make_datastore(llm_cfg={'change_summary_default': 'GLOBAL'}, tags={'t1': tag}) watch = _make_watch(llm_change_summary='WATCH', tags=['t1']) watch['llm_change_summary_mode'] = 'append' @@ -608,7 +729,7 @@ class TestSummaryPromptAppendMode: def test_tag_appends_while_watch_replaces(self): from changedetectionio.llm.evaluator import get_effective_summary_prompt - tag = {'title': 'grp', 'llm_change_summary': 'TAG', 'llm_change_summary_mode': 'append'} + tag = _make_tag(llm_change_summary='TAG', llm_change_summary_mode='append') ds = _make_datastore(llm_cfg={'change_summary_default': 'GLOBAL'}, tags={'t1': tag}) watch = _make_watch(llm_change_summary='WATCH', tags=['t1']) assert get_effective_summary_prompt(watch, ds) == 'WATCH' diff --git a/changedetectionio/tests/test_llm_change_summary.py b/changedetectionio/tests/test_llm_change_summary.py index f094d6291..01162612d 100644 --- a/changedetectionio/tests/test_llm_change_summary.py +++ b/changedetectionio/tests/test_llm_change_summary.py @@ -75,9 +75,10 @@ def test_llm_change_summary_cascades_from_tag( _set_response(datastore_path, HTML_V1) test_url = url_for('test_endpoint', _external=True) - # Create a tag with llm_change_summary + # Create a tag with llm_change_summary, AI set to On so its watches inherit it tag_uuid = ds.add_tag('events-group') ds.data['settings']['application']['tags'][tag_uuid]['llm_change_summary'] = 'Summarise new events' + ds.data['settings']['application']['tags'][tag_uuid]['llm_backend_profile'] = True # Watch in that tag, no own summary prompt uuid = ds.add_watch(url=test_url) @@ -281,6 +282,7 @@ def test_tag_prompt_overrides_global_default( tag_uuid = ds.add_tag('my-group') ds.data['settings']['application']['tags'][tag_uuid]['llm_change_summary'] = 'Tag: bullet points.' + ds.data['settings']['application']['tags'][tag_uuid]['llm_backend_profile'] = True uuid = ds.add_watch(url='https://example.com') watch = ds.data['watching'][uuid] @@ -306,6 +308,7 @@ def test_watch_prompt_overrides_tag_and_global( tag_uuid = ds.add_tag('my-group') ds.data['settings']['application']['tags'][tag_uuid]['llm_change_summary'] = 'Tag prompt.' + ds.data['settings']['application']['tags'][tag_uuid]['llm_backend_profile'] = True uuid = ds.add_watch(url='https://example.com') watch = ds.data['watching'][uuid] diff --git a/changedetectionio/tests/test_llm_group_overrides.py b/changedetectionio/tests/test_llm_group_overrides.py index a32c95df2..6680a02ca 100644 --- a/changedetectionio/tests/test_llm_group_overrides.py +++ b/changedetectionio/tests/test_llm_group_overrides.py @@ -1,18 +1,27 @@ #!/usr/bin/env python3 """ -Tests for group/tag LLM field overrides on the watch edit page. +Tests for the AI/LLM settings a group hands to its watches. -When a watch's first linked tag has llm_intent or llm_change_summary set -and the watch itself has no own value, the watch edit form should render -the relevant textarea as readonly with a "From group '': " -placeholder. +A group has exactly ONE AI control on its edit page — the ternary llm_backend_profile +("AI for watches in this group"): -When the watch has its own value, the textarea is editable as normal. + On the group's llm_intent / llm_change_summary apply to every watch in + it (unless the watch fills in its own), and AI is on for all of them + Off AI off for every watch in the group; its prompts are never used + Leave it to each the group has no say; each watch's own AI settings apply -The evaluator cascade (resolve_llm_field) is already tested in the -evaluator unit tests; these tests focus on the UI and form behaviour. +Only "On" makes anything cascade, so it decides both: + + * whether the evaluator inherits the group's prompts (resolve_llm_field / + get_effective_summary_prompt), and + * whether the watch edit page shows the inherited value as a + "From group '': " placeholder. + +So every UI assertion here is paired: group On → "From group ..." visible, group Off or +undecided → not a trace of it. On a watch the same field is a plain on/off checkbox (#4204). """ +import html import json from flask import url_for @@ -20,6 +29,42 @@ from flask import url_for from changedetectionio.tests.util import live_server_setup, delete_all_watches +# The exact rendered string under test, from templates/edit/include_llm_intent.html: +# {% set intent_placeholder = _("From group '%(name)s': %(value)s", ...) %} +def _from_group_text(name, value): + return f"From group '{name}': {value}" + + +def _page_text(res): + """Response body with HTML entities resolved, so we can match the placeholder as written.""" + return html.unescape(res.data.decode('utf-8', errors='replace')) + + +def _input_tags(body, name): + """Every whole tag carrying name="", in document order.""" + tags = [] + pos = body.find(f'name="{name}"') + while pos != -1: + start = body.rfind('', pos) + tags.append(body[start:end + 1]) + pos = body.find(f'name="{name}"', end) + return tags + + +def _input_tag(body, name): + """Return the first tag carrying name="", or '' if there isn't one.""" + tags = _input_tags(body, name) + return tags[0] if tags else '' + + +def _checkbox_is_checked(body, name): + """True when that checkbox renders as checked (attribute order is not guaranteed).""" + tag = _input_tag(body, name) + assert tag, f'no in the page' + return 'checked' in tag + + # --------------------------------------------------------------------------- # Helpers # --------------------------------------------------------------------------- @@ -51,14 +96,20 @@ def _api_token(client): # Tag setup # --------------------------------------------------------------------------- -def _add_tag_with_llm(datastore, title, llm_intent='', llm_change_summary=''): - """Create a tag with LLM fields set directly in the datastore.""" +def _add_tag_with_llm(datastore, title, llm_intent='', llm_change_summary='', ai=True): + """Create a tag with LLM fields set directly in the datastore. + + `ai` is the group's single AI control (llm_backend_profile): True = On, False = Off, + None = leave it to each watch. Defaults to True because most cases here are about what + a group set to "On" hands down. + """ tag_uuid = datastore.add_tag(title) tag = datastore.data['settings']['application']['tags'][tag_uuid] if llm_intent: tag['llm_intent'] = llm_intent if llm_change_summary: tag['llm_change_summary'] = llm_change_summary + tag['llm_backend_profile'] = ai return tag_uuid @@ -72,16 +123,123 @@ def _link_watch_to_tag(datastore, watch_uuid, tag_uuid): # --------------------------------------------------------------------------- -# Watch edit page — llm_intent group override +# The group's one AI control — ternary on a group, checkbox on a watch # --------------------------------------------------------------------------- -def test_watch_edit_shows_llm_intent_placeholder_from_group( +def test_group_edit_page_has_the_ternary_ai_control( client, live_server, measure_memory_usage, datastore_path): """ - When a watch has no own llm_intent but its first tag does, - the edit page must show "From group" + group name + group value in the - placeholder so the user sees the inherited value but can still type to override. - The field must NOT be readonly. + The group edit page must offer all three states — without them there is no way to turn + group-wide AI settings on, or to switch AI off for a whole group (#4204). + """ + ds = client.application.config.get('DATASTORE') + _configure_llm(ds) + + tag_uuid = ds.add_tag('Ternary Group') + + res = client.get(url_for('tags.form_tag_edit', uuid=tag_uuid)) + assert res.status_code == 200 + body = res.data.decode('utf-8', errors='replace') + text = _page_text(res) + + assert 'name="llm_backend_profile"' in body, \ + "group edit page is missing the 'AI for watches in this group' control" + for value in ('true', 'false', 'none'): + assert f'name="llm_backend_profile" value="{value}"' in body, \ + f"group AI control is missing its '{value}' option" + assert 'AI for watches in this group' in text + assert 'Leave it to each watch' in text + # New groups start undecided, so they never touch their watches + assert 'id="llm_backend_profile_none" checked' in body, \ + "a new group must default to 'Leave it to each watch'" + + delete_all_watches(client) + + +def test_watch_edit_page_has_a_plain_ai_checkbox( + client, live_server, measure_memory_usage, datastore_path): + """A watch gets a simple on/off, not the group's three-way choice.""" + ds = client.application.config.get('DATASTORE') + _configure_llm(ds) + api_token = _api_token(client) + watch_uuid = _create_watch(client, url_for('test_endpoint', _external=True), api_token) + + res = client.get(url_for('ui.ui_edit.edit_page', uuid=watch_uuid)) + assert res.status_code == 200 + body = res.data.decode('utf-8', errors='replace') + + assert 'name="llm_intent"' in body # AI section is rendered... + assert 'type="checkbox"' in _input_tag(body, 'llm_backend_profile') + assert 'Leave it to each watch' not in _page_text(res), \ + "the group's three-way AI choice must not appear on a watch" + + delete_all_watches(client) + + +def test_group_edit_page_never_shows_the_from_group_placeholder( + client, live_server, measure_memory_usage, datastore_path): + """ + "From group ..." describes something inherited by a watch; the group edit page is + where the value is authored, so it must show group-flavoured copy instead. + """ + ds = client.application.config.get('DATASTORE') + _configure_llm(ds) + + tag_uuid = _add_tag_with_llm(ds, 'Authoring Group', llm_intent='Group intent value') + + res = client.get(url_for('tags.form_tag_edit', uuid=tag_uuid)) + assert res.status_code == 200 + text = _page_text(res) + + assert 'From group' not in text + # Group copy, not the per-watch copy (both live in the same shared include) + assert 'Set a change intent for all watches in this tag/group' in text + assert 'Describe what you care about' not in text + + delete_all_watches(client) + + +def test_group_edit_form_saves_and_reloads_each_ai_state( + client, live_server, measure_memory_usage, datastore_path): + """All three states round-trip through the real form, and the prompt is kept regardless.""" + res = client.post(url_for('tags.form_tag_add'), data={'name': 'Saved Group'}, follow_redirects=True) + assert b'Tag added' in res.data + + ds = client.application.config.get('DATASTORE') + _configure_llm(ds) + tag_uuid = list(ds.data['settings']['application']['tags'].keys())[0] + + for posted, expected in (('true', True), ('false', False), ('none', None)): + res = client.post( + url_for('tags.form_tag_edit_submit', uuid=tag_uuid), + data={'title': 'Saved Group', + 'llm_intent': 'Only notify me about price drops', + 'llm_backend_profile': posted}, + follow_redirects=True, + ) + assert b'Updated' in res.data + tag = ds.data['settings']['application']['tags'][tag_uuid] + assert tag.get('llm_backend_profile') is expected, f"posting {posted!r} should store {expected!r}" + # The prompt is always kept — the AI state only decides whether it is used + assert tag.get('llm_intent') == 'Only notify me about price drops' + + # ..and the reloaded page comes back on the same option + body = client.get(url_for('tags.form_tag_edit', uuid=tag_uuid)).data.decode('utf-8', errors='replace') + assert f'id="llm_backend_profile_{posted}" checked' in body, \ + f"saved state {posted!r} must render as the selected option" + + delete_all_watches(client) + + +# --------------------------------------------------------------------------- +# Watch edit page — llm_intent group override, gated on the checkbox +# --------------------------------------------------------------------------- + +def test_watch_edit_shows_llm_intent_placeholder_when_group_overrides_enabled( + client, live_server, measure_memory_usage, datastore_path): + """ + Group override ON + watch has no own llm_intent → the edit page shows + "From group '': " as the placeholder, and the field stays editable. """ ds = client.application.config.get('DATASTORE') _configure_llm(ds) @@ -89,34 +247,64 @@ def test_watch_edit_shows_llm_intent_placeholder_from_group( test_url = url_for('test_endpoint', _external=True) watch_uuid = _create_watch(client, test_url, api_token) - tag_uuid = _add_tag_with_llm(ds, 'Price Watchers', llm_intent='Notify only when price drops') + tag_uuid = _add_tag_with_llm(ds, 'Price Watchers', + llm_intent='Notify only when price drops', + ai=True) _link_watch_to_tag(ds, watch_uuid, tag_uuid) res = client.get(url_for('ui.ui_edit.edit_page', uuid=watch_uuid)) assert res.status_code == 200 - body = res.data.decode('utf-8', errors='replace') + text = _page_text(res) - assert 'name="llm_intent"' in body - - # Placeholder must contain "From group", the tag name, and the value - assert 'From group' in body - assert 'Price Watchers' in body - assert 'Notify only when price drops' in body + assert 'name="llm_intent"' in text + assert _from_group_text('Price Watchers', 'Notify only when price drops') in text, \ + "watch edit must show the inherited group intent as a 'From group ...' placeholder" # Field must be editable — no readonly attribute - intent_pos = body.find('name="llm_intent"') - snippet = body[max(0, intent_pos - 50): intent_pos + 300] + intent_pos = text.find('name="llm_intent"') + snippet = text[max(0, intent_pos - 50): intent_pos + 300] assert 'readonly' not in snippet, \ f"llm_intent must be editable when group sets it; snippet: {snippet!r}" delete_all_watches(client) +def test_watch_edit_hides_llm_intent_placeholder_when_group_overrides_disabled( + client, live_server, measure_memory_usage, datastore_path): + """ + Same group, same intent, checkbox OFF → no "From group ..." anywhere, and the + generic example placeholder is used instead. This is the pairing that makes the + checkbox meaningful. + """ + ds = client.application.config.get('DATASTORE') + _configure_llm(ds) + api_token = _api_token(client) + test_url = url_for('test_endpoint', _external=True) + + watch_uuid = _create_watch(client, test_url, api_token) + tag_uuid = _add_tag_with_llm(ds, 'Price Watchers', + llm_intent='Notify only when price drops', + ai=False) + _link_watch_to_tag(ds, watch_uuid, tag_uuid) + + res = client.get(url_for('ui.ui_edit.edit_page', uuid=watch_uuid)) + assert res.status_code == 200 + text = _page_text(res) + + assert 'From group' not in text, \ + "group AI settings must not leak into the watch unless the group is set to On" + assert 'Notify only when price drops' not in text + # Falls back to the normal per-watch example placeholder + assert 'e.g. Alert me when the price drops below $300' in text + + delete_all_watches(client) + + def test_watch_edit_llm_intent_shows_own_value_not_group_placeholder( client, live_server, measure_memory_usage, datastore_path): """ - When a watch has its own llm_intent, the textarea body shows the watch's value - and the placeholder does NOT say "From group" (the group value is irrelevant). + When the watch has its own llm_intent, the textarea body shows the watch's value + and the placeholder does NOT say "From group" — even with the group opted in. """ ds = client.application.config.get('DATASTORE') _configure_llm(ds) @@ -124,33 +312,32 @@ def test_watch_edit_llm_intent_shows_own_value_not_group_placeholder( test_url = url_for('test_endpoint', _external=True) watch_uuid = _create_watch(client, test_url, api_token) - tag_uuid = _add_tag_with_llm(ds, 'Deals Group', llm_intent='Tag intent: notify on any deal') + tag_uuid = _add_tag_with_llm(ds, 'Deals Group', + llm_intent='Tag intent: notify on any deal', + ai=True) _link_watch_to_tag(ds, watch_uuid, tag_uuid) ds.data['watching'][watch_uuid]['llm_intent'] = 'My own watch intent' res = client.get(url_for('ui.ui_edit.edit_page', uuid=watch_uuid)) assert res.status_code == 200 - body = res.data.decode('utf-8', errors='replace') + text = _page_text(res) # Watch's own value in the textarea body - assert 'My own watch intent' in body + assert 'My own watch intent' in text # No group placeholder — the watch has its own value - assert 'From group' not in body + assert 'From group' not in text delete_all_watches(client) # --------------------------------------------------------------------------- -# Watch edit page — llm_change_summary group override +# Watch edit page — llm_change_summary group override, gated on the checkbox # --------------------------------------------------------------------------- -def test_watch_edit_shows_llm_change_summary_placeholder_from_group( +def test_watch_edit_shows_llm_change_summary_placeholder_when_group_overrides_enabled( client, live_server, measure_memory_usage, datastore_path): - """ - When a watch has no own llm_change_summary but its first tag does, - the edit page shows the group value as placeholder (editable, not readonly). - """ + """Group override ON → the group summary prompt shows as placeholder (editable).""" ds = client.application.config.get('DATASTORE') _configure_llm(ds) api_token = _api_token(client) @@ -159,31 +346,58 @@ def test_watch_edit_shows_llm_change_summary_placeholder_from_group( watch_uuid = _create_watch(client, test_url, api_token) tag_uuid = _add_tag_with_llm( ds, 'Summary Group', - llm_change_summary='List new items as bullet points. Translate to English.' + llm_change_summary='List new items as bullet points. Translate to English.', + ai=True, ) _link_watch_to_tag(ds, watch_uuid, tag_uuid) res = client.get(url_for('ui.ui_edit.edit_page', uuid=watch_uuid)) assert res.status_code == 200 - body = res.data.decode('utf-8', errors='replace') + text = _page_text(res) - assert 'Summary Group' in body - assert 'List new items as bullet points' in body + assert _from_group_text('Summary Group', + 'List new items as bullet points. Translate to English.') in text # Field must be editable - summary_pos = body.find('name="llm_change_summary"') + summary_pos = text.find('name="llm_change_summary"') assert summary_pos != -1 - snippet = body[max(0, summary_pos - 50): summary_pos + 300] + snippet = text[max(0, summary_pos - 50): summary_pos + 300] assert 'readonly' not in snippet, \ f"llm_change_summary must be editable; snippet: {snippet!r}" delete_all_watches(client) +def test_watch_edit_hides_llm_change_summary_placeholder_when_group_overrides_disabled( + client, live_server, measure_memory_usage, datastore_path): + """Group override OFF → no "From group ..." for the summary prompt either.""" + ds = client.application.config.get('DATASTORE') + _configure_llm(ds) + api_token = _api_token(client) + test_url = url_for('test_endpoint', _external=True) + + watch_uuid = _create_watch(client, test_url, api_token) + tag_uuid = _add_tag_with_llm( + ds, 'Summary Group', + llm_change_summary='List new items as bullet points. Translate to English.', + ai=False, + ) + _link_watch_to_tag(ds, watch_uuid, tag_uuid) + + res = client.get(url_for('ui.ui_edit.edit_page', uuid=watch_uuid)) + assert res.status_code == 200 + text = _page_text(res) + + assert 'From group' not in text + assert 'List new items as bullet points' not in text + + delete_all_watches(client) + + def test_watch_edit_llm_change_summary_shows_own_value_not_group_placeholder( client, live_server, measure_memory_usage, datastore_path): """ - When a watch has its own llm_change_summary, the textarea body shows the watch's + When the watch has its own llm_change_summary, the textarea body shows the watch's value and no group placeholder appears. """ ds = client.application.config.get('DATASTORE') @@ -192,17 +406,18 @@ def test_watch_edit_llm_change_summary_shows_own_value_not_group_placeholder( test_url = url_for('test_endpoint', _external=True) watch_uuid = _create_watch(client, test_url, api_token) - tag_uuid = _add_tag_with_llm(ds, 'Summary Group', llm_change_summary='Tag summary prompt') + tag_uuid = _add_tag_with_llm(ds, 'Summary Group', llm_change_summary='Tag summary prompt', + ai=True) _link_watch_to_tag(ds, watch_uuid, tag_uuid) ds.data['watching'][watch_uuid]['llm_change_summary'] = 'My own summary prompt' res = client.get(url_for('ui.ui_edit.edit_page', uuid=watch_uuid)) assert res.status_code == 200 - body = res.data.decode('utf-8', errors='replace') + text = _page_text(res) - assert 'My own summary prompt' in body - assert 'From group' not in body + assert 'My own summary prompt' in text + assert 'From group' not in text delete_all_watches(client) @@ -230,8 +445,7 @@ def test_watch_edit_no_tag_fields_are_editable( # Neither textarea should be readonly for field in ('llm_intent', 'llm_change_summary'): pos = body.find(f'name="{field}"') - if pos == -1: - continue # field might not render if LLM section hidden for some reason + assert pos != -1, f"{field} textarea missing from watch edit page" snippet = body[max(0, pos - 50): pos + 300] assert 'readonly' not in snippet, \ f"{field} textarea must not be readonly with no tags; snippet: {snippet!r}" @@ -242,14 +456,14 @@ def test_watch_edit_no_tag_fields_are_editable( # --------------------------------------------------------------------------- -# Evaluator cascade — group value used when watch has none +# Evaluator cascade — gated on the same checkbox as the UI # --------------------------------------------------------------------------- -def test_resolve_llm_field_uses_tag_value_when_watch_has_none( +def test_resolve_llm_field_uses_tag_value_when_group_overrides_enabled( client, live_server, measure_memory_usage, datastore_path): """ - resolve_llm_field returns the tag's value (and tag name as source) when - the watch has no own value. + resolve_llm_field returns the tag's value (and tag name as source) when the watch + has no own value and the group is opted in. """ from changedetectionio.llm.evaluator import resolve_llm_field @@ -258,7 +472,8 @@ def test_resolve_llm_field_uses_tag_value_when_watch_has_none( test_url = url_for('test_endpoint', _external=True) watch_uuid = _create_watch(client, test_url, api_token) - tag_uuid = _add_tag_with_llm(ds, 'Cascade Group', llm_intent='Group-level intent') + tag_uuid = _add_tag_with_llm(ds, 'Cascade Group', llm_intent='Group-level intent', + ai=True) _link_watch_to_tag(ds, watch_uuid, tag_uuid) watch = ds.data['watching'][watch_uuid] @@ -270,10 +485,33 @@ def test_resolve_llm_field_uses_tag_value_when_watch_has_none( delete_all_watches(client) +def test_resolve_llm_field_ignores_tag_value_when_group_overrides_disabled( + client, live_server, measure_memory_usage, datastore_path): + """The UI hint and the evaluator agree: no opt-in, no inheritance.""" + from changedetectionio.llm.evaluator import resolve_llm_field + + ds = client.application.config.get('DATASTORE') + api_token = _api_token(client) + test_url = url_for('test_endpoint', _external=True) + + watch_uuid = _create_watch(client, test_url, api_token) + tag_uuid = _add_tag_with_llm(ds, 'Cascade Group', llm_intent='Group-level intent', + ai=False) + _link_watch_to_tag(ds, watch_uuid, tag_uuid) + + watch = ds.data['watching'][watch_uuid] + value, source = resolve_llm_field(watch, ds, 'llm_intent') + + assert value == '' + assert source == '' + + delete_all_watches(client) + + def test_resolve_llm_field_uses_watch_value_over_tag( client, live_server, measure_memory_usage, datastore_path): """ - resolve_llm_field prefers the watch's own value over the tag's. + resolve_llm_field prefers the watch's own value over the tag's, opted in or not. """ from changedetectionio.llm.evaluator import resolve_llm_field @@ -282,7 +520,8 @@ def test_resolve_llm_field_uses_watch_value_over_tag( test_url = url_for('test_endpoint', _external=True) watch_uuid = _create_watch(client, test_url, api_token) - tag_uuid = _add_tag_with_llm(ds, 'Override Group', llm_intent='Tag intent') + tag_uuid = _add_tag_with_llm(ds, 'Override Group', llm_intent='Tag intent', + ai=True) _link_watch_to_tag(ds, watch_uuid, tag_uuid) ds.data['watching'][watch_uuid]['llm_intent'] = 'Watch-level intent' @@ -303,8 +542,8 @@ def test_resolve_llm_field_uses_watch_value_over_tag( def test_watch_edit_independent_field_overrides( client, live_server, measure_memory_usage, datastore_path): """ - llm_intent can come from a group (readonly) while llm_change_summary - is editable (watch has its own), and vice versa. + llm_intent can be inherited from an opted-in group while llm_change_summary + is the watch's own value. """ ds = client.application.config.get('DATASTORE') _configure_llm(ds) @@ -316,6 +555,7 @@ def test_watch_edit_independent_field_overrides( ds, 'Mixed Group', llm_intent='Group intent here', llm_change_summary='Group summary here', + ai=True, ) _link_watch_to_tag(ds, watch_uuid, tag_uuid) @@ -324,21 +564,22 @@ def test_watch_edit_independent_field_overrides( res = client.get(url_for('ui.ui_edit.edit_page', uuid=watch_uuid)) assert res.status_code == 200 - body = res.data.decode('utf-8', errors='replace') + text = _page_text(res) # llm_intent: group placeholder visible (watch has no own value) - assert 'Group intent here' in body - intent_pos = body.find('name="llm_intent"') + assert _from_group_text('Mixed Group', 'Group intent here') in text + intent_pos = text.find('name="llm_intent"') assert intent_pos != -1 - intent_snippet = body[max(0, intent_pos - 50): intent_pos + 300] + intent_snippet = text[max(0, intent_pos - 50): intent_pos + 300] assert 'readonly' not in intent_snippet, \ f"llm_intent must be editable even when group sets it; snippet: {intent_snippet!r}" - # llm_change_summary: watch own value shown in body, no group placeholder - assert 'My own summary' in body - summary_pos = body.find('name="llm_change_summary"') + # llm_change_summary: watch own value shown in body, no group placeholder for it + assert 'My own summary' in text + assert _from_group_text('Mixed Group', 'Group summary here') not in text + summary_pos = text.find('name="llm_change_summary"') assert summary_pos != -1 - summary_snippet = body[max(0, summary_pos - 50): summary_pos + 300] + summary_snippet = text[max(0, summary_pos - 50): summary_pos + 300] assert 'readonly' not in summary_snippet, \ f"llm_change_summary should be editable; snippet: {summary_snippet!r}" @@ -409,7 +650,7 @@ def test_tag_edit_page_shows_prompt_mode_radio( def test_tag_append_mode_persists_and_applies( client, live_server, measure_memory_usage, datastore_path): - """A group set to append adds its text to the global prompt for its watches.""" + """An opted-in group set to append adds its text to the global prompt for its watches.""" from changedetectionio.llm.evaluator import get_effective_summary_prompt ds = client.application.config.get('DATASTORE') @@ -420,7 +661,8 @@ def test_tag_append_mode_persists_and_applies( test_url = url_for('test_endpoint', _external=True) watch_uuid = _create_watch(client, test_url, api_token) - tag_uuid = _add_tag_with_llm(ds, 'Append Group', llm_change_summary='Group extra line.') + tag_uuid = _add_tag_with_llm(ds, 'Append Group', llm_change_summary='Group extra line.', + ai=True) ds.data['settings']['application']['tags'][tag_uuid]['llm_change_summary_mode'] = 'append' _link_watch_to_tag(ds, watch_uuid, tag_uuid) @@ -428,3 +670,348 @@ def test_tag_append_mode_persists_and_applies( assert get_effective_summary_prompt(watch, ds) == 'GLOBAL RULES\n\nGroup extra line.' delete_all_watches(client) + + +def test_tag_append_mode_ignored_when_group_overrides_disabled( + client, live_server, measure_memory_usage, datastore_path): + """Without the opt-in the group's appended text never reaches the effective prompt.""" + from changedetectionio.llm.evaluator import get_effective_summary_prompt + + ds = client.application.config.get('DATASTORE') + _configure_llm(ds) + ds.data['settings']['application']['llm']['change_summary_default'] = 'GLOBAL RULES' + + api_token = _api_token(client) + test_url = url_for('test_endpoint', _external=True) + watch_uuid = _create_watch(client, test_url, api_token) + + tag_uuid = _add_tag_with_llm(ds, 'Append Group', llm_change_summary='Group extra line.', + ai=False) + ds.data['settings']['application']['tags'][tag_uuid]['llm_change_summary_mode'] = 'append' + _link_watch_to_tag(ds, watch_uuid, tag_uuid) + + watch = ds.data['watching'][watch_uuid] + assert get_effective_summary_prompt(watch, ds) == 'GLOBAL RULES' + + delete_all_watches(client) + + +# --------------------------------------------------------------------------- +# AI on/off per watch, and per group when the group overrides — #4204 +# --------------------------------------------------------------------------- + +def test_watch_edit_has_ai_enabled_checkbox( + client, live_server, measure_memory_usage, datastore_path): + """Every watch gets its own AI on/off switch, on by default.""" + ds = client.application.config.get('DATASTORE') + _configure_llm(ds) + api_token = _api_token(client) + watch_uuid = _create_watch(client, url_for('test_endpoint', _external=True), api_token) + + res = client.get(url_for('ui.ui_edit.edit_page', uuid=watch_uuid)) + body = res.data.decode('utf-8', errors='replace') + + assert 'name="llm_backend_profile"' in body, \ + "watch edit page is missing the AI on/off checkbox (#4204)" + assert _checkbox_is_checked(body, 'llm_backend_profile'), \ + "AI should default to on for a new watch" + # No group involved, so no override note + assert 'overrides this' not in _page_text(res) + + delete_all_watches(client) + + +def test_group_edit_can_switch_ai_off_for_the_whole_group( + client, live_server, measure_memory_usage, datastore_path): + """The group's control has an explicit "Off for every watch" state — the #4204 ask.""" + ds = client.application.config.get('DATASTORE') + _configure_llm(ds) + tag_uuid = ds.add_tag('AI Toggle Group') + + res = client.get(url_for('tags.form_tag_edit', uuid=tag_uuid)) + assert 'Off for every watch' in _page_text(res), \ + "group edit page cannot switch AI off for all of its watches (#4204)" + + delete_all_watches(client) + + +def test_group_edit_greys_out_the_prompts_unless_ai_is_on( + client, live_server, measure_memory_usage, datastore_path): + """ + Same cue as the restock group override (#overrides_watch + toggleOpacity): the prompts + only mean something in the "On" state, so they are greyed out otherwise. The state + changes without a reload, so this pins the JS wiring rather than the opacity value. + """ + ds = client.application.config.get('DATASTORE') + _configure_llm(ds) + tag_uuid = ds.add_tag('Dimmed Group') + + res = client.get(url_for('tags.form_tag_edit', uuid=tag_uuid)) + body = res.data.decode('utf-8', errors='replace') + + assert "toggleOpacityByRadioValue('llm_backend_profile', 'true'" in body, \ + "group edit page lost the wiring that greys out the AI prompts" + # ..and the elements it drives are all present + for element_id in ('llm_backend_profile_true', 'change-intent-notify-me-when', 'change-summary'): + assert f'id="{element_id}"' in body, f"#{element_id} missing — opacity toggle would be a no-op" + + delete_all_watches(client) + + +def test_watch_edit_shows_which_group_decided_the_ai_switch( + client, live_server, measure_memory_usage, datastore_path): + """ + A group that has taken the decision decides for its watches, so the watch edit page says + which group is in charge and what it decided — and that explanation must stay readable + (only the checkbox it describes is dimmed). + """ + ds = client.application.config.get('DATASTORE') + _configure_llm(ds) + api_token = _api_token(client) + watch_uuid = _create_watch(client, url_for('test_endpoint', _external=True), api_token) + + tag_uuid = _add_tag_with_llm(ds, 'Tech news', ai=False) + _link_watch_to_tag(ds, watch_uuid, tag_uuid) + + res = client.get(url_for('ui.ui_edit.edit_page', uuid=watch_uuid)) + text = _page_text(res) + assert 'decides this: AI is OFF for every watch in that group.' in text + + # The group name links to that group's edit page, straight to its AI tab + tag_edit_url = url_for('tags.form_tag_edit', uuid=tag_uuid) + assert f'Tech news' in text, \ + "the group name in the note must link to the group's edit page" + + # The note itself is not inside the dimmed wrapper + note_pos = text.find('decides this: AI is OFF') + dimmed_pos = text.find('style="opacity: 0.6;"', text.find('id="llm-ai-enabled-row"')) + assert dimmed_pos != -1, "the overridden checkbox should be dimmed" + assert text.find('

', dimmed_pos) < note_pos, \ + "the 'Group X decides this' note must not be greyed out with the checkbox" + + # Group switched to On → the note reflects that, still linked + ds.data['settings']['application']['tags'][tag_uuid]['llm_backend_profile'] = True + text = _page_text(client.get(url_for('ui.ui_edit.edit_page', uuid=watch_uuid))) + assert 'decides this: AI is ON for every watch in that group.' in text + assert f'Tech news' in text + + # ..and the watch's own checkbox is disabled, showing what the group decided + body = client.get(url_for('ui.ui_edit.edit_page', uuid=watch_uuid)).data.decode('utf-8', errors='replace') + checkbox = _input_tags(body, 'llm_backend_profile')[0] + assert 'disabled' in checkbox, "the group decides, so the watch's own checkbox must be disabled" + assert 'checked' in checkbox, "disabled checkbox must show the state the group decided (ON)" + + ds.data['settings']['application']['tags'][tag_uuid]['llm_backend_profile'] = False + body = client.get(url_for('ui.ui_edit.edit_page', uuid=watch_uuid)).data.decode('utf-8', errors='replace') + checkbox = _input_tags(body, 'llm_backend_profile')[0] + assert 'disabled' in checkbox and 'checked' not in checkbox, \ + "disabled checkbox must show the state the group decided (OFF)" + + # ..and with the group leaving it to each watch, the watch is on its own again + ds.data['settings']['application']['tags'][tag_uuid]['llm_backend_profile'] = None + res = client.get(url_for('ui.ui_edit.edit_page', uuid=watch_uuid)) + assert 'decides this' not in _page_text(res) + + delete_all_watches(client) + + +def test_watch_own_ai_switch_survives_being_overridden_by_a_group( + client, live_server, measure_memory_usage, datastore_path): + """ + While a group decides, the watch's checkbox is disabled — and a disabled checkbox is not + POSTed, which for a checkbox reads as "off". Saving the watch must therefore NOT quietly + rewrite its own preference: it has to come back unchanged once the group stops deciding. + """ + from changedetectionio.llm.evaluator import llm_enabled_for_watch + + ds = client.application.config.get('DATASTORE') + _configure_llm(ds) + api_token = _api_token(client) + test_url = url_for('test_endpoint', _external=True) + watch_uuid = _create_watch(client, test_url, api_token) + + # Watch says AI on (the default); the group overrules it with "off" + tag_uuid = _add_tag_with_llm(ds, 'Deciding Group', ai=False) + _link_watch_to_tag(ds, watch_uuid, tag_uuid) + assert ds.data['watching'][watch_uuid].get('llm_backend_profile') is True + assert llm_enabled_for_watch(ds.data['watching'][watch_uuid], ds) == (False, 'Deciding Group') + + # Save the page exactly as the browser would: the disabled checkbox sends nothing at all + res = client.post( + url_for('ui.ui_edit.edit_page', uuid=watch_uuid), + data={'url': test_url, 'fetch_backend': 'html_requests', + 'time_between_check_use_default': 'y'}, + follow_redirects=True, + ) + assert b'Updated watch' in res.data + + watch = ds.data['watching'][watch_uuid] + assert watch.get('llm_backend_profile') is True, \ + "saving while a group decides must not overwrite the watch's own AI preference" + # Not even a hand-crafted POST can write it while it isn't user-editable + res = client.post( + url_for('ui.ui_edit.edit_page', uuid=watch_uuid), + data={'url': test_url, 'fetch_backend': 'html_requests', + 'time_between_check_use_default': 'y', 'llm_backend_profile': ''}, + follow_redirects=True, + ) + assert b'Updated watch' in res.data + watch = ds.data['watching'][watch_uuid] + assert watch.get('llm_backend_profile') is True + # The group still wins for now... + assert llm_enabled_for_watch(watch, ds) == (False, 'Deciding Group') + # ..and when the group stops deciding, the watch's untouched preference applies again + ds.data['settings']['application']['tags'][tag_uuid]['llm_backend_profile'] = None + assert llm_enabled_for_watch(watch, ds) == (True, 'watch') + + delete_all_watches(client) + + +def test_watch_ai_switch_saves_via_edit_form( + client, live_server, measure_memory_usage, datastore_path): + """Turning AI off on a watch persists, and turning it back on works.""" + ds = client.application.config.get('DATASTORE') + _configure_llm(ds) + api_token = _api_token(client) + test_url = url_for('test_endpoint', _external=True) + watch_uuid = _create_watch(client, test_url, api_token) + + from changedetectionio.llm.evaluator import llm_enabled_for_watch + + # Unchecked checkbox is simply absent from the POST + res = client.post( + url_for('ui.ui_edit.edit_page', uuid=watch_uuid), + data={'url': test_url, 'fetch_backend': 'html_requests', + 'time_between_check_use_default': 'y'}, + follow_redirects=True, + ) + assert b'Updated watch' in res.data + watch = ds.data['watching'][watch_uuid] + assert watch.get('llm_backend_profile') is False + assert llm_enabled_for_watch(watch, ds) == (False, 'watch') + + res = client.post( + url_for('ui.ui_edit.edit_page', uuid=watch_uuid), + data={'url': test_url, 'fetch_backend': 'html_requests', + 'time_between_check_use_default': 'y', 'llm_backend_profile': 'y'}, + follow_redirects=True, + ) + assert b'Updated watch' in res.data + watch = ds.data['watching'][watch_uuid] + assert watch.get('llm_backend_profile') is True + assert llm_enabled_for_watch(watch, ds) == (True, 'watch') + + delete_all_watches(client) + + +def test_group_ai_switch_saves_and_decides_for_its_watches( + client, live_server, measure_memory_usage, datastore_path): + """ + Group form set to "Off for every watch" → every watch in the group is off, whatever the + watch itself says. This is the #4204 "turn AI off for a whole group" flow. + """ + from changedetectionio.llm.evaluator import llm_enabled_for_watch + + ds = client.application.config.get('DATASTORE') + _configure_llm(ds) + api_token = _api_token(client) + watch_uuid = _create_watch(client, url_for('test_endpoint', _external=True), api_token) + + res = client.post(url_for('tags.form_tag_add'), data={'name': 'Budget Group'}, follow_redirects=True) + assert b'Tag added' in res.data + tag_uuid = [u for u, t in ds.data['settings']['application']['tags'].items() + if t.get('title') == 'Budget Group'][0] + + res = client.post( + url_for('tags.form_tag_edit_submit', uuid=tag_uuid), + data={'title': 'Budget Group', 'llm_backend_profile': 'false'}, + follow_redirects=True, + ) + assert b'Updated' in res.data + tag = ds.data['settings']['application']['tags'][tag_uuid] + assert tag.get('llm_backend_profile') is False + + _link_watch_to_tag(ds, watch_uuid, tag_uuid) + watch = ds.data['watching'][watch_uuid] + assert watch.get('llm_backend_profile') is True # the watch itself still says "on" + assert llm_enabled_for_watch(watch, ds) == (False, 'Budget Group'), \ + "a group set to Off must win over the watch's own AI switch" + + delete_all_watches(client) + + +def test_group_ai_state_survives_a_save_with_no_llm_configured( + client, live_server, measure_memory_usage, datastore_path): + """ + With no provider configured the AI control isn't rendered, and an unrendered control is + indistinguishable from "off" in a POST — so the page must carry the saved state in a + hidden input, otherwise merely saving the group would switch AI off. + """ + ds = client.application.config.get('DATASTORE') + # deliberately NOT calling _configure_llm + + res = client.post(url_for('tags.form_tag_add'), data={'name': 'Unconfigured Group'}, follow_redirects=True) + assert b'Tag added' in res.data + tag_uuid = [u for u, t in ds.data['settings']['application']['tags'].items() + if t.get('title') == 'Unconfigured Group'][0] + ds.data['settings']['application']['tags'][tag_uuid]['llm_backend_profile'] = True + + res = client.get(url_for('tags.form_tag_edit', uuid=tag_uuid)) + body = res.data.decode('utf-8', errors='replace') + assert 'name="llm_intent"' not in body, "AI fields should not render without a provider" + hidden = _input_tag(body, 'llm_backend_profile') + assert 'type="hidden"' in hidden and 'value="true"' in hidden, \ + "the group AI state must be preserved in a hidden input when the AI section is not rendered" + + # Submit exactly what that page would send + res = client.post( + url_for('tags.form_tag_edit_submit', uuid=tag_uuid), + data={'title': 'Unconfigured Group', 'llm_backend_profile': 'true'}, + follow_redirects=True, + ) + assert b'Updated' in res.data + + tag = ds.data['settings']['application']['tags'][tag_uuid] + assert tag.get('llm_backend_profile') is True, \ + "saving with the AI section hidden must not switch AI off" + + delete_all_watches(client) + + +# --------------------------------------------------------------------------- +# End-to-end through the real forms — the path the user actually clicks +# --------------------------------------------------------------------------- + +def test_group_override_round_trip_through_both_forms( + client, live_server, measure_memory_usage, datastore_path): + """ + Set the group to On with an intent via the group form, tag a watch with it, and the watch + edit page shows the inherited value as its placeholder. This is the flow that was broken: + the group had no way to switch group-wide AI settings on at all. + """ + ds = client.application.config.get('DATASTORE') + _configure_llm(ds) + api_token = _api_token(client) + test_url = url_for('test_endpoint', _external=True) + watch_uuid = _create_watch(client, test_url, api_token) + + res = client.post(url_for('tags.form_tag_add'), data={'name': 'E2E Group'}, follow_redirects=True) + assert b'Tag added' in res.data + tag_uuid = [u for u, t in ds.data['settings']['application']['tags'].items() + if t.get('title') == 'E2E Group'][0] + + res = client.post( + url_for('tags.form_tag_edit_submit', uuid=tag_uuid), + data={'title': 'E2E Group', + 'llm_intent': 'Only tell me about stock changes', + 'llm_backend_profile': 'true'}, + follow_redirects=True, + ) + assert b'Updated' in res.data + + _link_watch_to_tag(ds, watch_uuid, tag_uuid) + + res = client.get(url_for('ui.ui_edit.edit_page', uuid=watch_uuid)) + assert _from_group_text('E2E Group', 'Only tell me about stock changes') in _page_text(res) + + delete_all_watches(client) diff --git a/changedetectionio/translations/cs/LC_MESSAGES/messages.mo b/changedetectionio/translations/cs/LC_MESSAGES/messages.mo index 0371ed5eed19cd703b89f02face928cf1a804ea8..792bac3ea2839a9243ca1986629630bffef71e4a 100644 GIT binary patch delta 10916 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 – every watch in this group uses the AI settings below, unless it fills in its own. " +"Off – no AI for any watch in this group. Leave it to each watch – this " +"group has no say; each watch uses its own AI settings." +msgstr "" #: changedetectionio/templates/edit/include_llm_intent.html -msgid "AI — Notify when…" +#, python-format +msgid "Group %(name)s decides this: AI is ON for every watch in that group." +msgstr "" + +#: changedetectionio/templates/edit/include_llm_intent.html +#, python-format +msgid "Group %(name)s decides this: AI is OFF for every watch in that group." msgstr "" #: changedetectionio/templates/edit/include_llm_intent.html @@ -4618,6 +4647,10 @@ msgstr "" msgid "Describe the price change: old price, new price, percentage difference." msgstr "" +#: changedetectionio/templates/edit/include_llm_intent.html +msgid "AI" +msgstr "AI" + #: changedetectionio/templates/edit/include_llm_intent.html #, python-format msgid "" diff --git a/changedetectionio/translations/de/LC_MESSAGES/messages.po b/changedetectionio/translations/de/LC_MESSAGES/messages.po index db1286c5c..f5fdd3c6e 100644 --- a/changedetectionio/translations/de/LC_MESSAGES/messages.po +++ b/changedetectionio/translations/de/LC_MESSAGES/messages.po @@ -1348,6 +1348,22 @@ msgstr "" msgid "Must be a hex colour, for example #4f8ef7" msgstr "Muss eine Hex-Farbe sein, zum Beispiel #4f8ef7" +#: changedetectionio/blueprint/tags/form.py +msgid "AI for watches in this group" +msgstr "" + +#: changedetectionio/blueprint/tags/form.py +msgid "On, use the settings below" +msgstr "" + +#: changedetectionio/blueprint/tags/form.py +msgid "Off for every watch" +msgstr "" + +#: changedetectionio/blueprint/tags/form.py +msgid "Leave it to each watch" +msgstr "" + #: changedetectionio/blueprint/tags/form.py msgid "Tag name" msgstr "" @@ -3230,16 +3246,16 @@ msgid "Use global settings for time between check and scheduler." msgstr "Verwenden Sie globale Einstellungen für die Zeit zwischen Prüfung und Planer." #: changedetectionio/forms.py -msgid "AI Change Intent" +msgid "AI Change Intent - Notify me when.." msgstr "" #: changedetectionio/blueprint/settings/templates/settings_llm_tab.html changedetectionio/blueprint/ui/templates/diff.html -#: changedetectionio/forms.py changedetectionio/templates/edit/include_llm_intent.html +#: changedetectionio/forms.py msgid "AI Change Summary" msgstr "" #: changedetectionio/blueprint/tags/form.py changedetectionio/forms.py -msgid "How this prompt combines with the inherited one" +msgid "Change Summary prompt - Append or Replace the default?" msgstr "" #: changedetectionio/blueprint/tags/form.py changedetectionio/forms.py @@ -3250,6 +3266,10 @@ msgstr "" msgid "Append to the inherited prompt" msgstr "" +#: changedetectionio/forms.py +msgid "AI enabled for this watch?" +msgstr "" + #: changedetectionio/forms.py msgid "CSS/JSONPath/JQ/XPath Filters" msgstr "CSS/xPath-Filter" @@ -4582,11 +4602,20 @@ msgid "Enter search term..." msgstr "Suchbegriff eingeben..." #: changedetectionio/templates/edit/include_llm_intent.html -msgid "AI" +msgid "" +"On – every watch in this group uses the AI settings below, unless it fills in its own. " +"Off – no AI for any watch in this group. Leave it to each watch – this " +"group has no say; each watch uses its own AI settings." msgstr "" #: changedetectionio/templates/edit/include_llm_intent.html -msgid "AI — Notify when…" +#, python-format +msgid "Group %(name)s decides this: AI is ON for every watch in that group." +msgstr "" + +#: changedetectionio/templates/edit/include_llm_intent.html +#, python-format +msgid "Group %(name)s decides this: AI is OFF for every watch in that group." msgstr "" #: changedetectionio/templates/edit/include_llm_intent.html @@ -4672,6 +4701,10 @@ msgstr "" msgid "Describe the price change: old price, new price, percentage difference." msgstr "" +#: changedetectionio/templates/edit/include_llm_intent.html +msgid "AI" +msgstr "" + #: changedetectionio/templates/edit/include_llm_intent.html #, python-format msgid "" diff --git a/changedetectionio/translations/en_GB/LC_MESSAGES/messages.po b/changedetectionio/translations/en_GB/LC_MESSAGES/messages.po index b6c73fe81..dda350109 100644 --- a/changedetectionio/translations/en_GB/LC_MESSAGES/messages.po +++ b/changedetectionio/translations/en_GB/LC_MESSAGES/messages.po @@ -1330,6 +1330,22 @@ msgstr "" msgid "Must be a hex colour, for example #4f8ef7" msgstr "" +#: changedetectionio/blueprint/tags/form.py +msgid "AI for watches in this group" +msgstr "" + +#: changedetectionio/blueprint/tags/form.py +msgid "On, use the settings below" +msgstr "" + +#: changedetectionio/blueprint/tags/form.py +msgid "Off for every watch" +msgstr "" + +#: changedetectionio/blueprint/tags/form.py +msgid "Leave it to each watch" +msgstr "" + #: changedetectionio/blueprint/tags/form.py msgid "Tag name" msgstr "" @@ -3173,16 +3189,16 @@ msgid "Use global settings for time between check and scheduler." msgstr "" #: changedetectionio/forms.py -msgid "AI Change Intent" +msgid "AI Change Intent - Notify me when.." msgstr "" #: changedetectionio/blueprint/settings/templates/settings_llm_tab.html changedetectionio/blueprint/ui/templates/diff.html -#: changedetectionio/forms.py changedetectionio/templates/edit/include_llm_intent.html +#: changedetectionio/forms.py msgid "AI Change Summary" msgstr "" #: changedetectionio/blueprint/tags/form.py changedetectionio/forms.py -msgid "How this prompt combines with the inherited one" +msgid "Change Summary prompt - Append or Replace the default?" msgstr "" #: changedetectionio/blueprint/tags/form.py changedetectionio/forms.py @@ -3193,6 +3209,10 @@ msgstr "" msgid "Append to the inherited prompt" msgstr "" +#: changedetectionio/forms.py +msgid "AI enabled for this watch?" +msgstr "" + #: changedetectionio/forms.py msgid "CSS/JSONPath/JQ/XPath Filters" msgstr "" @@ -4520,11 +4540,20 @@ msgid "Enter search term..." msgstr "" #: changedetectionio/templates/edit/include_llm_intent.html -msgid "AI" +msgid "" +"On – every watch in this group uses the AI settings below, unless it fills in its own. " +"Off – no AI for any watch in this group. Leave it to each watch – this " +"group has no say; each watch uses its own AI settings." msgstr "" #: changedetectionio/templates/edit/include_llm_intent.html -msgid "AI — Notify when…" +#, python-format +msgid "Group %(name)s decides this: AI is ON for every watch in that group." +msgstr "" + +#: changedetectionio/templates/edit/include_llm_intent.html +#, python-format +msgid "Group %(name)s decides this: AI is OFF for every watch in that group." msgstr "" #: changedetectionio/templates/edit/include_llm_intent.html @@ -4610,6 +4639,10 @@ msgstr "" msgid "Describe the price change: old price, new price, percentage difference." msgstr "" +#: changedetectionio/templates/edit/include_llm_intent.html +msgid "AI" +msgstr "" + #: changedetectionio/templates/edit/include_llm_intent.html #, python-format msgid "" diff --git a/changedetectionio/translations/en_US/LC_MESSAGES/messages.po b/changedetectionio/translations/en_US/LC_MESSAGES/messages.po index 0a674a6fa..1c0ca7f50 100644 --- a/changedetectionio/translations/en_US/LC_MESSAGES/messages.po +++ b/changedetectionio/translations/en_US/LC_MESSAGES/messages.po @@ -1330,6 +1330,22 @@ msgstr "" msgid "Must be a hex colour, for example #4f8ef7" msgstr "" +#: changedetectionio/blueprint/tags/form.py +msgid "AI for watches in this group" +msgstr "" + +#: changedetectionio/blueprint/tags/form.py +msgid "On, use the settings below" +msgstr "" + +#: changedetectionio/blueprint/tags/form.py +msgid "Off for every watch" +msgstr "" + +#: changedetectionio/blueprint/tags/form.py +msgid "Leave it to each watch" +msgstr "" + #: changedetectionio/blueprint/tags/form.py msgid "Tag name" msgstr "" @@ -3173,16 +3189,16 @@ msgid "Use global settings for time between check and scheduler." msgstr "" #: changedetectionio/forms.py -msgid "AI Change Intent" +msgid "AI Change Intent - Notify me when.." msgstr "" #: changedetectionio/blueprint/settings/templates/settings_llm_tab.html changedetectionio/blueprint/ui/templates/diff.html -#: changedetectionio/forms.py changedetectionio/templates/edit/include_llm_intent.html +#: changedetectionio/forms.py msgid "AI Change Summary" msgstr "" #: changedetectionio/blueprint/tags/form.py changedetectionio/forms.py -msgid "How this prompt combines with the inherited one" +msgid "Change Summary prompt - Append or Replace the default?" msgstr "" #: changedetectionio/blueprint/tags/form.py changedetectionio/forms.py @@ -3193,6 +3209,10 @@ msgstr "" msgid "Append to the inherited prompt" msgstr "" +#: changedetectionio/forms.py +msgid "AI enabled for this watch?" +msgstr "" + #: changedetectionio/forms.py msgid "CSS/JSONPath/JQ/XPath Filters" msgstr "" @@ -4520,11 +4540,20 @@ msgid "Enter search term..." msgstr "" #: changedetectionio/templates/edit/include_llm_intent.html -msgid "AI" +msgid "" +"On – every watch in this group uses the AI settings below, unless it fills in its own. " +"Off – no AI for any watch in this group. Leave it to each watch – this " +"group has no say; each watch uses its own AI settings." msgstr "" #: changedetectionio/templates/edit/include_llm_intent.html -msgid "AI — Notify when…" +#, python-format +msgid "Group %(name)s decides this: AI is ON for every watch in that group." +msgstr "" + +#: changedetectionio/templates/edit/include_llm_intent.html +#, python-format +msgid "Group %(name)s decides this: AI is OFF for every watch in that group." msgstr "" #: changedetectionio/templates/edit/include_llm_intent.html @@ -4610,6 +4639,10 @@ msgstr "" msgid "Describe the price change: old price, new price, percentage difference." msgstr "" +#: changedetectionio/templates/edit/include_llm_intent.html +msgid "AI" +msgstr "" + #: changedetectionio/templates/edit/include_llm_intent.html #, python-format msgid "" diff --git a/changedetectionio/translations/es/LC_MESSAGES/messages.po b/changedetectionio/translations/es/LC_MESSAGES/messages.po index c6b0db8ad..7e13c25b6 100644 --- a/changedetectionio/translations/es/LC_MESSAGES/messages.po +++ b/changedetectionio/translations/es/LC_MESSAGES/messages.po @@ -1368,6 +1368,22 @@ msgstr "" msgid "Must be a hex colour, for example #4f8ef7" msgstr "Debe ser un color hexadecimal, por ejemplo #4f8ef7" +#: changedetectionio/blueprint/tags/form.py +msgid "AI for watches in this group" +msgstr "" + +#: changedetectionio/blueprint/tags/form.py +msgid "On, use the settings below" +msgstr "" + +#: changedetectionio/blueprint/tags/form.py +msgid "Off for every watch" +msgstr "" + +#: changedetectionio/blueprint/tags/form.py +msgid "Leave it to each watch" +msgstr "" + #: changedetectionio/blueprint/tags/form.py msgid "Tag name" msgstr "" @@ -3246,16 +3262,16 @@ msgid "Use global settings for time between check and scheduler." msgstr "Utilice la configuración global para el tiempo entre la verificación y el programador." #: changedetectionio/forms.py -msgid "AI Change Intent" +msgid "AI Change Intent - Notify me when.." msgstr "" #: changedetectionio/blueprint/settings/templates/settings_llm_tab.html changedetectionio/blueprint/ui/templates/diff.html -#: changedetectionio/forms.py changedetectionio/templates/edit/include_llm_intent.html +#: changedetectionio/forms.py msgid "AI Change Summary" msgstr "" #: changedetectionio/blueprint/tags/form.py changedetectionio/forms.py -msgid "How this prompt combines with the inherited one" +msgid "Change Summary prompt - Append or Replace the default?" msgstr "" #: changedetectionio/blueprint/tags/form.py changedetectionio/forms.py @@ -3266,6 +3282,10 @@ msgstr "" msgid "Append to the inherited prompt" msgstr "" +#: changedetectionio/forms.py +msgid "AI enabled for this watch?" +msgstr "" + #: changedetectionio/forms.py msgid "CSS/JSONPath/JQ/XPath Filters" msgstr "Filtros CSS/JSONPath/JQ/XPath" @@ -4597,11 +4617,20 @@ msgid "Enter search term..." msgstr "Introduzca el término de búsqueda..." #: changedetectionio/templates/edit/include_llm_intent.html -msgid "AI" +msgid "" +"On – every watch in this group uses the AI settings below, unless it fills in its own. " +"Off – no AI for any watch in this group. Leave it to each watch – this " +"group has no say; each watch uses its own AI settings." msgstr "" #: changedetectionio/templates/edit/include_llm_intent.html -msgid "AI — Notify when…" +#, python-format +msgid "Group %(name)s decides this: AI is ON for every watch in that group." +msgstr "" + +#: changedetectionio/templates/edit/include_llm_intent.html +#, python-format +msgid "Group %(name)s decides this: AI is OFF for every watch in that group." msgstr "" #: changedetectionio/templates/edit/include_llm_intent.html @@ -4687,6 +4716,10 @@ msgstr "" msgid "Describe the price change: old price, new price, percentage difference." msgstr "" +#: changedetectionio/templates/edit/include_llm_intent.html +msgid "AI" +msgstr "" + #: changedetectionio/templates/edit/include_llm_intent.html #, python-format msgid "" diff --git a/changedetectionio/translations/fr/LC_MESSAGES/messages.po b/changedetectionio/translations/fr/LC_MESSAGES/messages.po index 5923fc495..1dfb0cda4 100644 --- a/changedetectionio/translations/fr/LC_MESSAGES/messages.po +++ b/changedetectionio/translations/fr/LC_MESSAGES/messages.po @@ -1336,6 +1336,22 @@ msgstr "" msgid "Must be a hex colour, for example #4f8ef7" msgstr "Doit être une couleur hexadécimale, par exemple #4f8ef7" +#: changedetectionio/blueprint/tags/form.py +msgid "AI for watches in this group" +msgstr "" + +#: changedetectionio/blueprint/tags/form.py +msgid "On, use the settings below" +msgstr "" + +#: changedetectionio/blueprint/tags/form.py +msgid "Off for every watch" +msgstr "" + +#: changedetectionio/blueprint/tags/form.py +msgid "Leave it to each watch" +msgstr "" + #: changedetectionio/blueprint/tags/form.py msgid "Tag name" msgstr "" @@ -3186,16 +3202,16 @@ msgid "Use global settings for time between check and scheduler." msgstr "Utilisez les paramètres globaux pour le temps entre la vérification et le programmateur." #: changedetectionio/forms.py -msgid "AI Change Intent" +msgid "AI Change Intent - Notify me when.." msgstr "" #: changedetectionio/blueprint/settings/templates/settings_llm_tab.html changedetectionio/blueprint/ui/templates/diff.html -#: changedetectionio/forms.py changedetectionio/templates/edit/include_llm_intent.html +#: changedetectionio/forms.py msgid "AI Change Summary" msgstr "" #: changedetectionio/blueprint/tags/form.py changedetectionio/forms.py -msgid "How this prompt combines with the inherited one" +msgid "Change Summary prompt - Append or Replace the default?" msgstr "" #: changedetectionio/blueprint/tags/form.py changedetectionio/forms.py @@ -3206,6 +3222,10 @@ msgstr "" msgid "Append to the inherited prompt" msgstr "" +#: changedetectionio/forms.py +msgid "AI enabled for this watch?" +msgstr "" + #: changedetectionio/forms.py msgid "CSS/JSONPath/JQ/XPath Filters" msgstr "Filtre CSS/JSONPath/JQ/XPath" @@ -4535,11 +4555,20 @@ msgid "Enter search term..." msgstr "" #: changedetectionio/templates/edit/include_llm_intent.html -msgid "AI" +msgid "" +"On – every watch in this group uses the AI settings below, unless it fills in its own. " +"Off – no AI for any watch in this group. Leave it to each watch – this " +"group has no say; each watch uses its own AI settings." msgstr "" #: changedetectionio/templates/edit/include_llm_intent.html -msgid "AI — Notify when…" +#, python-format +msgid "Group %(name)s decides this: AI is ON for every watch in that group." +msgstr "" + +#: changedetectionio/templates/edit/include_llm_intent.html +#, python-format +msgid "Group %(name)s decides this: AI is OFF for every watch in that group." msgstr "" #: changedetectionio/templates/edit/include_llm_intent.html @@ -4625,6 +4654,10 @@ msgstr "" msgid "Describe the price change: old price, new price, percentage difference." msgstr "" +#: changedetectionio/templates/edit/include_llm_intent.html +msgid "AI" +msgstr "" + #: changedetectionio/templates/edit/include_llm_intent.html #, python-format msgid "" diff --git a/changedetectionio/translations/it/LC_MESSAGES/messages.po b/changedetectionio/translations/it/LC_MESSAGES/messages.po index ae18711ea..640d7c0d1 100644 --- a/changedetectionio/translations/it/LC_MESSAGES/messages.po +++ b/changedetectionio/translations/it/LC_MESSAGES/messages.po @@ -1332,6 +1332,22 @@ msgstr "" msgid "Must be a hex colour, for example #4f8ef7" msgstr "Deve essere un colore esadecimale, ad esempio #4f8ef7" +#: changedetectionio/blueprint/tags/form.py +msgid "AI for watches in this group" +msgstr "" + +#: changedetectionio/blueprint/tags/form.py +msgid "On, use the settings below" +msgstr "" + +#: changedetectionio/blueprint/tags/form.py +msgid "Off for every watch" +msgstr "" + +#: changedetectionio/blueprint/tags/form.py +msgid "Leave it to each watch" +msgstr "" + #: changedetectionio/blueprint/tags/form.py msgid "Tag name" msgstr "" @@ -3175,16 +3191,16 @@ msgid "Use global settings for time between check and scheduler." msgstr "Usa impostazioni globali per intervallo controlli e pianificazione." #: changedetectionio/forms.py -msgid "AI Change Intent" +msgid "AI Change Intent - Notify me when.." msgstr "" #: changedetectionio/blueprint/settings/templates/settings_llm_tab.html changedetectionio/blueprint/ui/templates/diff.html -#: changedetectionio/forms.py changedetectionio/templates/edit/include_llm_intent.html +#: changedetectionio/forms.py msgid "AI Change Summary" msgstr "" #: changedetectionio/blueprint/tags/form.py changedetectionio/forms.py -msgid "How this prompt combines with the inherited one" +msgid "Change Summary prompt - Append or Replace the default?" msgstr "" #: changedetectionio/blueprint/tags/form.py changedetectionio/forms.py @@ -3195,6 +3211,10 @@ msgstr "" msgid "Append to the inherited prompt" msgstr "" +#: changedetectionio/forms.py +msgid "AI enabled for this watch?" +msgstr "" + #: changedetectionio/forms.py msgid "CSS/JSONPath/JQ/XPath Filters" msgstr "Filtri CSS/JSONPath/JQ/XPath" @@ -4522,11 +4542,20 @@ msgid "Enter search term..." msgstr "" #: changedetectionio/templates/edit/include_llm_intent.html -msgid "AI" +msgid "" +"On – every watch in this group uses the AI settings below, unless it fills in its own. " +"Off – no AI for any watch in this group. Leave it to each watch – this " +"group has no say; each watch uses its own AI settings." msgstr "" #: changedetectionio/templates/edit/include_llm_intent.html -msgid "AI — Notify when…" +#, python-format +msgid "Group %(name)s decides this: AI is ON for every watch in that group." +msgstr "" + +#: changedetectionio/templates/edit/include_llm_intent.html +#, python-format +msgid "Group %(name)s decides this: AI is OFF for every watch in that group." msgstr "" #: changedetectionio/templates/edit/include_llm_intent.html @@ -4612,6 +4641,10 @@ msgstr "" msgid "Describe the price change: old price, new price, percentage difference." msgstr "" +#: changedetectionio/templates/edit/include_llm_intent.html +msgid "AI" +msgstr "" + #: changedetectionio/templates/edit/include_llm_intent.html #, python-format msgid "" diff --git a/changedetectionio/translations/ja/LC_MESSAGES/messages.po b/changedetectionio/translations/ja/LC_MESSAGES/messages.po index 96adf9586..3f947220a 100644 --- a/changedetectionio/translations/ja/LC_MESSAGES/messages.po +++ b/changedetectionio/translations/ja/LC_MESSAGES/messages.po @@ -1337,6 +1337,22 @@ msgstr "タグの色" msgid "Must be a hex colour, for example #4f8ef7" msgstr "16進数のカラーコードを指定してください(例: #4f8ef7)" +#: changedetectionio/blueprint/tags/form.py +msgid "AI for watches in this group" +msgstr "" + +#: changedetectionio/blueprint/tags/form.py +msgid "On, use the settings below" +msgstr "" + +#: changedetectionio/blueprint/tags/form.py +msgid "Off for every watch" +msgstr "" + +#: changedetectionio/blueprint/tags/form.py +msgid "Leave it to each watch" +msgstr "" + #: changedetectionio/blueprint/tags/form.py msgid "Tag name" msgstr "タグ名" @@ -3192,16 +3208,16 @@ msgid "Use global settings for time between check and scheduler." msgstr "チェック間隔とスケジューラーにはグローバル設定を使用する。" #: changedetectionio/forms.py -msgid "AI Change Intent" +msgid "AI Change Intent - Notify me when.." msgstr "" #: changedetectionio/blueprint/settings/templates/settings_llm_tab.html changedetectionio/blueprint/ui/templates/diff.html -#: changedetectionio/forms.py changedetectionio/templates/edit/include_llm_intent.html +#: changedetectionio/forms.py msgid "AI Change Summary" msgstr "" #: changedetectionio/blueprint/tags/form.py changedetectionio/forms.py -msgid "How this prompt combines with the inherited one" +msgid "Change Summary prompt - Append or Replace the default?" msgstr "" #: changedetectionio/blueprint/tags/form.py changedetectionio/forms.py @@ -3212,6 +3228,10 @@ msgstr "" msgid "Append to the inherited prompt" msgstr "" +#: changedetectionio/forms.py +msgid "AI enabled for this watch?" +msgstr "" + #: changedetectionio/forms.py msgid "CSS/JSONPath/JQ/XPath Filters" msgstr "CSS/JSONPath/JQ/XPath フィルタ" @@ -4553,11 +4573,20 @@ msgid "Enter search term..." msgstr "検索語を入力..." #: changedetectionio/templates/edit/include_llm_intent.html -msgid "AI" +msgid "" +"On – every watch in this group uses the AI settings below, unless it fills in its own. " +"Off – no AI for any watch in this group. Leave it to each watch – this " +"group has no say; each watch uses its own AI settings." msgstr "" #: changedetectionio/templates/edit/include_llm_intent.html -msgid "AI — Notify when…" +#, python-format +msgid "Group %(name)s decides this: AI is ON for every watch in that group." +msgstr "" + +#: changedetectionio/templates/edit/include_llm_intent.html +#, python-format +msgid "Group %(name)s decides this: AI is OFF for every watch in that group." msgstr "" #: changedetectionio/templates/edit/include_llm_intent.html @@ -4643,6 +4672,10 @@ msgstr "" msgid "Describe the price change: old price, new price, percentage difference." msgstr "" +#: changedetectionio/templates/edit/include_llm_intent.html +msgid "AI" +msgstr "" + #: changedetectionio/templates/edit/include_llm_intent.html #, python-format msgid "" diff --git a/changedetectionio/translations/ko/LC_MESSAGES/messages.mo b/changedetectionio/translations/ko/LC_MESSAGES/messages.mo index 8470818a63147b772acc01591d058f284eb2a1cc..16c4b5a450e373fddb920edb2afb00ce38452a28 100644 GIT binary patch delta 16038 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 Wjw9&@-`ug_Ms?4QZ+;l~;r{{S!7d8` delta 16135 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 diff --git a/changedetectionio/translations/ko/LC_MESSAGES/messages.po b/changedetectionio/translations/ko/LC_MESSAGES/messages.po index 831d07504..b91ca21eb 100644 --- a/changedetectionio/translations/ko/LC_MESSAGES/messages.po +++ b/changedetectionio/translations/ko/LC_MESSAGES/messages.po @@ -1338,6 +1338,22 @@ msgstr "태그 색상" msgid "Must be a hex colour, for example #4f8ef7" msgstr "16진수 색상이어야 합니다. 예: #4f8ef7" +#: changedetectionio/blueprint/tags/form.py +msgid "AI for watches in this group" +msgstr "" + +#: changedetectionio/blueprint/tags/form.py +msgid "On, use the settings below" +msgstr "" + +#: changedetectionio/blueprint/tags/form.py +msgid "Off for every watch" +msgstr "" + +#: changedetectionio/blueprint/tags/form.py +msgid "Leave it to each watch" +msgstr "" + #: changedetectionio/blueprint/tags/form.py msgid "Tag name" msgstr "태그 이름" @@ -3183,16 +3199,16 @@ msgid "Use global settings for time between check and scheduler." msgstr "확인 간격 및 예약 실행에 전역 설정 사용" #: changedetectionio/forms.py -msgid "AI Change Intent" -msgstr "AI 판단 기준" +msgid "AI Change Intent - Notify me when.." +msgstr "" #: changedetectionio/blueprint/settings/templates/settings_llm_tab.html changedetectionio/blueprint/ui/templates/diff.html -#: changedetectionio/forms.py changedetectionio/templates/edit/include_llm_intent.html +#: changedetectionio/forms.py msgid "AI Change Summary" msgstr "AI 변경 요약" #: changedetectionio/blueprint/tags/form.py changedetectionio/forms.py -msgid "How this prompt combines with the inherited one" +msgid "Change Summary prompt - Append or Replace the default?" msgstr "" #: changedetectionio/blueprint/tags/form.py changedetectionio/forms.py @@ -3203,6 +3219,10 @@ msgstr "" msgid "Append to the inherited prompt" msgstr "" +#: changedetectionio/forms.py +msgid "AI enabled for this watch?" +msgstr "" + #: changedetectionio/forms.py msgid "CSS/JSONPath/JQ/XPath Filters" msgstr "CSS/JSONPath/JQ/XPath 필터" @@ -4530,12 +4550,21 @@ msgid "Enter search term..." msgstr "검색어를 입력하세요..." #: changedetectionio/templates/edit/include_llm_intent.html -msgid "AI" -msgstr "AI" +msgid "" +"On – every watch in this group uses the AI settings below, unless it fills in its own. " +"Off – no AI for any watch in this group. Leave it to each watch – this " +"group has no say; each watch uses its own AI settings." +msgstr "" #: changedetectionio/templates/edit/include_llm_intent.html -msgid "AI — Notify when…" -msgstr "AI - 다음 경우 알림" +#, python-format +msgid "Group %(name)s decides this: AI is ON for every watch in that group." +msgstr "" + +#: changedetectionio/templates/edit/include_llm_intent.html +#, python-format +msgid "Group %(name)s decides this: AI is OFF for every watch in that group." +msgstr "" #: changedetectionio/templates/edit/include_llm_intent.html msgid "" @@ -4620,6 +4649,10 @@ msgstr "추가되거나 취소된 이벤트를 요약하세요. 최대 두 문 msgid "Describe the price change: old price, new price, percentage difference." msgstr "가격 변경을 설명하세요: 이전 가격, 새 가격, 비율 차이." +#: changedetectionio/templates/edit/include_llm_intent.html +msgid "AI" +msgstr "AI" + #: changedetectionio/templates/edit/include_llm_intent.html #, python-format msgid "" diff --git a/changedetectionio/translations/messages.pot b/changedetectionio/translations/messages.pot index 3a040829f..dc3c06558 100644 --- a/changedetectionio/translations/messages.pot +++ b/changedetectionio/translations/messages.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: changedetection.io 0.55.8\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2026-08-26 11:14+0200\n" +"POT-Creation-Date: 2026-09-01 19:10+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -1329,6 +1329,22 @@ msgstr "" msgid "Must be a hex colour, for example #4f8ef7" msgstr "" +#: changedetectionio/blueprint/tags/form.py +msgid "AI for watches in this group" +msgstr "" + +#: changedetectionio/blueprint/tags/form.py +msgid "On, use the settings below" +msgstr "" + +#: changedetectionio/blueprint/tags/form.py +msgid "Off for every watch" +msgstr "" + +#: changedetectionio/blueprint/tags/form.py +msgid "Leave it to each watch" +msgstr "" + #: changedetectionio/blueprint/tags/form.py msgid "Tag name" msgstr "" @@ -3172,16 +3188,16 @@ msgid "Use global settings for time between check and scheduler." msgstr "" #: changedetectionio/forms.py -msgid "AI Change Intent" +msgid "AI Change Intent - Notify me when.." msgstr "" #: changedetectionio/blueprint/settings/templates/settings_llm_tab.html changedetectionio/blueprint/ui/templates/diff.html -#: changedetectionio/forms.py changedetectionio/templates/edit/include_llm_intent.html +#: changedetectionio/forms.py msgid "AI Change Summary" msgstr "" #: changedetectionio/blueprint/tags/form.py changedetectionio/forms.py -msgid "How this prompt combines with the inherited one" +msgid "Change Summary prompt - Append or Replace the default?" msgstr "" #: changedetectionio/blueprint/tags/form.py changedetectionio/forms.py @@ -3192,6 +3208,10 @@ msgstr "" msgid "Append to the inherited prompt" msgstr "" +#: changedetectionio/forms.py +msgid "AI enabled for this watch?" +msgstr "" + #: changedetectionio/forms.py msgid "CSS/JSONPath/JQ/XPath Filters" msgstr "" @@ -4519,11 +4539,20 @@ msgid "Enter search term..." msgstr "" #: changedetectionio/templates/edit/include_llm_intent.html -msgid "AI" +msgid "" +"On – every watch in this group uses the AI settings below, unless it fills in its own. " +"Off – no AI for any watch in this group. Leave it to each watch – this " +"group has no say; each watch uses its own AI settings." msgstr "" #: changedetectionio/templates/edit/include_llm_intent.html -msgid "AI — Notify when…" +#, python-format +msgid "Group %(name)s decides this: AI is ON for every watch in that group." +msgstr "" + +#: changedetectionio/templates/edit/include_llm_intent.html +#, python-format +msgid "Group %(name)s decides this: AI is OFF for every watch in that group." msgstr "" #: changedetectionio/templates/edit/include_llm_intent.html @@ -4609,6 +4638,10 @@ msgstr "" msgid "Describe the price change: old price, new price, percentage difference." msgstr "" +#: changedetectionio/templates/edit/include_llm_intent.html +msgid "AI" +msgstr "" + #: changedetectionio/templates/edit/include_llm_intent.html #, python-format msgid "" diff --git a/changedetectionio/translations/pl/LC_MESSAGES/messages.mo b/changedetectionio/translations/pl/LC_MESSAGES/messages.mo index 467254d5a2fa687b6bdb29c1170926d69540316b..1686f7003b6a2f1eba3edb68d0974a411423404a 100644 GIT binary patch delta 18675 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 Jg(u7W{{!F`Zg&6x delta 18770 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 K)oJMqp7(!$j+EyB diff --git a/changedetectionio/translations/pl/LC_MESSAGES/messages.po b/changedetectionio/translations/pl/LC_MESSAGES/messages.po index 452f591be..819e032f0 100644 --- a/changedetectionio/translations/pl/LC_MESSAGES/messages.po +++ b/changedetectionio/translations/pl/LC_MESSAGES/messages.po @@ -1451,6 +1451,22 @@ msgstr "Kolor etykiety" msgid "Must be a hex colour, for example #4f8ef7" msgstr "Musi być kolorem szesnastkowym, na przykład #4f8ef7" +#: changedetectionio/blueprint/tags/form.py +msgid "AI for watches in this group" +msgstr "" + +#: changedetectionio/blueprint/tags/form.py +msgid "On, use the settings below" +msgstr "" + +#: changedetectionio/blueprint/tags/form.py +msgid "Off for every watch" +msgstr "" + +#: changedetectionio/blueprint/tags/form.py +msgid "Leave it to each watch" +msgstr "" + #: changedetectionio/blueprint/tags/form.py msgid "Tag name" msgstr "Nazwa tagu" @@ -3332,16 +3348,16 @@ msgid "Use global settings for time between check and scheduler." msgstr "W przypadku funkcji sprawdzania i harmonogramu należy stosować ustawienia globalne dotyczące czasu." #: changedetectionio/forms.py -msgid "AI Change Intent" -msgstr "Intencja zmian AI" +msgid "AI Change Intent - Notify me when.." +msgstr "" #: changedetectionio/blueprint/settings/templates/settings_llm_tab.html changedetectionio/blueprint/ui/templates/diff.html -#: changedetectionio/forms.py changedetectionio/templates/edit/include_llm_intent.html +#: changedetectionio/forms.py msgid "AI Change Summary" msgstr "Podsumowanie zmian AI" #: changedetectionio/blueprint/tags/form.py changedetectionio/forms.py -msgid "How this prompt combines with the inherited one" +msgid "Change Summary prompt - Append or Replace the default?" msgstr "Jak ten prompt łączy się z odziedziczonym" #: changedetectionio/blueprint/tags/form.py changedetectionio/forms.py @@ -3352,6 +3368,10 @@ msgstr "Zastąp odziedziczony prompt" msgid "Append to the inherited prompt" msgstr "Dołącz do odziedziczonego promptu" +#: changedetectionio/forms.py +msgid "AI enabled for this watch?" +msgstr "" + #: changedetectionio/forms.py msgid "CSS/JSONPath/JQ/XPath Filters" msgstr "Filtry CSS/JSONPath/JQ/XPath" @@ -4702,12 +4722,21 @@ msgid "Enter search term..." msgstr "Wpisz szukane hasło..." #: changedetectionio/templates/edit/include_llm_intent.html -msgid "AI" -msgstr "Sztuczna inteligencja" +msgid "" +"On – every watch in this group uses the AI settings below, unless it fills in its own. " +"Off – no AI for any watch in this group. Leave it to each watch – this " +"group has no say; each watch uses its own AI settings." +msgstr "" #: changedetectionio/templates/edit/include_llm_intent.html -msgid "AI — Notify when…" -msgstr "Sztuczna inteligencja — Powiadom, gdy…" +#, python-format +msgid "Group %(name)s decides this: AI is ON for every watch in that group." +msgstr "" + +#: changedetectionio/templates/edit/include_llm_intent.html +#, python-format +msgid "Group %(name)s decides this: AI is OFF for every watch in that group." +msgstr "" #: changedetectionio/templates/edit/include_llm_intent.html msgid "" @@ -4804,6 +4833,10 @@ msgstr "Podsumuj, jakie wydarzenia zostały dodane lub odwołane. Maksymalnie dw msgid "Describe the price change: old price, new price, percentage difference." msgstr "Opisz zmianę ceny: stara cena, nowa cena, różnica procentowa." +#: changedetectionio/templates/edit/include_llm_intent.html +msgid "AI" +msgstr "Sztuczna inteligencja" + #: changedetectionio/templates/edit/include_llm_intent.html #, python-format msgid "" diff --git a/changedetectionio/translations/pt_BR/LC_MESSAGES/messages.po b/changedetectionio/translations/pt_BR/LC_MESSAGES/messages.po index 161d22b34..29b4e4617 100644 --- a/changedetectionio/translations/pt_BR/LC_MESSAGES/messages.po +++ b/changedetectionio/translations/pt_BR/LC_MESSAGES/messages.po @@ -1355,6 +1355,22 @@ msgstr "" msgid "Must be a hex colour, for example #4f8ef7" msgstr "Deve ser uma cor hexadecimal, por exemplo #4f8ef7" +#: changedetectionio/blueprint/tags/form.py +msgid "AI for watches in this group" +msgstr "" + +#: changedetectionio/blueprint/tags/form.py +msgid "On, use the settings below" +msgstr "" + +#: changedetectionio/blueprint/tags/form.py +msgid "Off for every watch" +msgstr "" + +#: changedetectionio/blueprint/tags/form.py +msgid "Leave it to each watch" +msgstr "" + #: changedetectionio/blueprint/tags/form.py msgid "Tag name" msgstr "" @@ -3223,16 +3239,16 @@ msgid "Use global settings for time between check and scheduler." msgstr "Usar configurações globais para o tempo entre verificações e agendador." #: changedetectionio/forms.py -msgid "AI Change Intent" +msgid "AI Change Intent - Notify me when.." msgstr "" #: changedetectionio/blueprint/settings/templates/settings_llm_tab.html changedetectionio/blueprint/ui/templates/diff.html -#: changedetectionio/forms.py changedetectionio/templates/edit/include_llm_intent.html +#: changedetectionio/forms.py msgid "AI Change Summary" msgstr "" #: changedetectionio/blueprint/tags/form.py changedetectionio/forms.py -msgid "How this prompt combines with the inherited one" +msgid "Change Summary prompt - Append or Replace the default?" msgstr "" #: changedetectionio/blueprint/tags/form.py changedetectionio/forms.py @@ -3243,6 +3259,10 @@ msgstr "" msgid "Append to the inherited prompt" msgstr "" +#: changedetectionio/forms.py +msgid "AI enabled for this watch?" +msgstr "" + #: changedetectionio/forms.py msgid "CSS/JSONPath/JQ/XPath Filters" msgstr "Filtros CSS/JSONPath/JQ/XPath" @@ -4572,11 +4592,20 @@ msgid "Enter search term..." msgstr "Digite o termo de busca..." #: changedetectionio/templates/edit/include_llm_intent.html -msgid "AI" +msgid "" +"On – every watch in this group uses the AI settings below, unless it fills in its own. " +"Off – no AI for any watch in this group. Leave it to each watch – this " +"group has no say; each watch uses its own AI settings." msgstr "" #: changedetectionio/templates/edit/include_llm_intent.html -msgid "AI — Notify when…" +#, python-format +msgid "Group %(name)s decides this: AI is ON for every watch in that group." +msgstr "" + +#: changedetectionio/templates/edit/include_llm_intent.html +#, python-format +msgid "Group %(name)s decides this: AI is OFF for every watch in that group." msgstr "" #: changedetectionio/templates/edit/include_llm_intent.html @@ -4662,6 +4691,10 @@ msgstr "" msgid "Describe the price change: old price, new price, percentage difference." msgstr "" +#: changedetectionio/templates/edit/include_llm_intent.html +msgid "AI" +msgstr "" + #: changedetectionio/templates/edit/include_llm_intent.html #, python-format msgid "" diff --git a/changedetectionio/translations/ru/LC_MESSAGES/messages.mo b/changedetectionio/translations/ru/LC_MESSAGES/messages.mo index c367897201908a291572dffb6827b345d2b30188..f331881ec54ffad7122cb10cf40f34c3b79b4a42 100644 GIT binary patch delta 15832 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 – every watch in this group uses the AI settings below, unless it fills in its own. " +"Off – no AI for any watch in this group. Leave it to each watch – this " +"group has no say; each watch uses its own AI settings." +msgstr "" #: changedetectionio/templates/edit/include_llm_intent.html -msgid "AI — Notify when…" -msgstr "AI — Сообщить, когда…" +#, python-format +msgid "Group %(name)s decides this: AI is ON for every watch in that group." +msgstr "" + +#: changedetectionio/templates/edit/include_llm_intent.html +#, python-format +msgid "Group %(name)s decides this: AI is OFF for every watch in that group." +msgstr "" #: changedetectionio/templates/edit/include_llm_intent.html msgid "" @@ -4750,6 +4779,10 @@ msgstr "Подведите итог, какие события были доба msgid "Describe the price change: old price, new price, percentage difference." msgstr "Опишите изменение цены: старая цена, новая цена, процентная разница." +#: changedetectionio/templates/edit/include_llm_intent.html +msgid "AI" +msgstr "ИИ" + #: changedetectionio/templates/edit/include_llm_intent.html #, python-format msgid "" diff --git a/changedetectionio/translations/tr/LC_MESSAGES/messages.po b/changedetectionio/translations/tr/LC_MESSAGES/messages.po index d69da53fc..95f686a8c 100644 --- a/changedetectionio/translations/tr/LC_MESSAGES/messages.po +++ b/changedetectionio/translations/tr/LC_MESSAGES/messages.po @@ -1365,6 +1365,22 @@ msgstr "" msgid "Must be a hex colour, for example #4f8ef7" msgstr "Onaltılık bir renk olmalıdır, örneğin #4f8ef7" +#: changedetectionio/blueprint/tags/form.py +msgid "AI for watches in this group" +msgstr "" + +#: changedetectionio/blueprint/tags/form.py +msgid "On, use the settings below" +msgstr "" + +#: changedetectionio/blueprint/tags/form.py +msgid "Off for every watch" +msgstr "" + +#: changedetectionio/blueprint/tags/form.py +msgid "Leave it to each watch" +msgstr "" + #: changedetectionio/blueprint/tags/form.py msgid "Tag name" msgstr "" @@ -3226,16 +3242,16 @@ msgid "Use global settings for time between check and scheduler." msgstr "Kontrol arası süre ve zamanlayıcı için genel ayarları kullanın." #: changedetectionio/forms.py -msgid "AI Change Intent" +msgid "AI Change Intent - Notify me when.." msgstr "" #: changedetectionio/blueprint/settings/templates/settings_llm_tab.html changedetectionio/blueprint/ui/templates/diff.html -#: changedetectionio/forms.py changedetectionio/templates/edit/include_llm_intent.html +#: changedetectionio/forms.py msgid "AI Change Summary" msgstr "" #: changedetectionio/blueprint/tags/form.py changedetectionio/forms.py -msgid "How this prompt combines with the inherited one" +msgid "Change Summary prompt - Append or Replace the default?" msgstr "" #: changedetectionio/blueprint/tags/form.py changedetectionio/forms.py @@ -3246,6 +3262,10 @@ msgstr "" msgid "Append to the inherited prompt" msgstr "" +#: changedetectionio/forms.py +msgid "AI enabled for this watch?" +msgstr "" + #: changedetectionio/forms.py msgid "CSS/JSONPath/JQ/XPath Filters" msgstr "CSS/JSONPath/JQ/XPath Filtreleri" @@ -4577,11 +4597,20 @@ msgid "Enter search term..." msgstr "Arama terimini girin..." #: changedetectionio/templates/edit/include_llm_intent.html -msgid "AI" +msgid "" +"On – every watch in this group uses the AI settings below, unless it fills in its own. " +"Off – no AI for any watch in this group. Leave it to each watch – this " +"group has no say; each watch uses its own AI settings." msgstr "" #: changedetectionio/templates/edit/include_llm_intent.html -msgid "AI — Notify when…" +#, python-format +msgid "Group %(name)s decides this: AI is ON for every watch in that group." +msgstr "" + +#: changedetectionio/templates/edit/include_llm_intent.html +#, python-format +msgid "Group %(name)s decides this: AI is OFF for every watch in that group." msgstr "" #: changedetectionio/templates/edit/include_llm_intent.html @@ -4667,6 +4696,10 @@ msgstr "" msgid "Describe the price change: old price, new price, percentage difference." msgstr "" +#: changedetectionio/templates/edit/include_llm_intent.html +msgid "AI" +msgstr "" + #: changedetectionio/templates/edit/include_llm_intent.html #, python-format msgid "" diff --git a/changedetectionio/translations/uk/LC_MESSAGES/messages.po b/changedetectionio/translations/uk/LC_MESSAGES/messages.po index feeeea748..f9f946ce6 100644 --- a/changedetectionio/translations/uk/LC_MESSAGES/messages.po +++ b/changedetectionio/translations/uk/LC_MESSAGES/messages.po @@ -1345,6 +1345,22 @@ msgstr "" msgid "Must be a hex colour, for example #4f8ef7" msgstr "Має бути шістнадцятковий колір, наприклад #4f8ef7" +#: changedetectionio/blueprint/tags/form.py +msgid "AI for watches in this group" +msgstr "" + +#: changedetectionio/blueprint/tags/form.py +msgid "On, use the settings below" +msgstr "" + +#: changedetectionio/blueprint/tags/form.py +msgid "Off for every watch" +msgstr "" + +#: changedetectionio/blueprint/tags/form.py +msgid "Leave it to each watch" +msgstr "" + #: changedetectionio/blueprint/tags/form.py msgid "Tag name" msgstr "" @@ -3205,16 +3221,16 @@ msgid "Use global settings for time between check and scheduler." msgstr "Використовувати глобальні налаштування для часу між перевірками та планувальника." #: changedetectionio/forms.py -msgid "AI Change Intent" +msgid "AI Change Intent - Notify me when.." msgstr "" #: changedetectionio/blueprint/settings/templates/settings_llm_tab.html changedetectionio/blueprint/ui/templates/diff.html -#: changedetectionio/forms.py changedetectionio/templates/edit/include_llm_intent.html +#: changedetectionio/forms.py msgid "AI Change Summary" msgstr "" #: changedetectionio/blueprint/tags/form.py changedetectionio/forms.py -msgid "How this prompt combines with the inherited one" +msgid "Change Summary prompt - Append or Replace the default?" msgstr "" #: changedetectionio/blueprint/tags/form.py changedetectionio/forms.py @@ -3225,6 +3241,10 @@ msgstr "" msgid "Append to the inherited prompt" msgstr "" +#: changedetectionio/forms.py +msgid "AI enabled for this watch?" +msgstr "" + #: changedetectionio/forms.py msgid "CSS/JSONPath/JQ/XPath Filters" msgstr "Фільтри CSS/JSONPath/JQ/XPath" @@ -4554,11 +4574,20 @@ msgid "Enter search term..." msgstr "Введіть пошуковий запит..." #: changedetectionio/templates/edit/include_llm_intent.html -msgid "AI" +msgid "" +"On – every watch in this group uses the AI settings below, unless it fills in its own. " +"Off – no AI for any watch in this group. Leave it to each watch – this " +"group has no say; each watch uses its own AI settings." msgstr "" #: changedetectionio/templates/edit/include_llm_intent.html -msgid "AI — Notify when…" +#, python-format +msgid "Group %(name)s decides this: AI is ON for every watch in that group." +msgstr "" + +#: changedetectionio/templates/edit/include_llm_intent.html +#, python-format +msgid "Group %(name)s decides this: AI is OFF for every watch in that group." msgstr "" #: changedetectionio/templates/edit/include_llm_intent.html @@ -4644,6 +4673,10 @@ msgstr "" msgid "Describe the price change: old price, new price, percentage difference." msgstr "" +#: changedetectionio/templates/edit/include_llm_intent.html +msgid "AI" +msgstr "" + #: changedetectionio/templates/edit/include_llm_intent.html #, python-format msgid "" diff --git a/changedetectionio/translations/zh/LC_MESSAGES/messages.po b/changedetectionio/translations/zh/LC_MESSAGES/messages.po index 85afc8275..92f1aa2a5 100644 --- a/changedetectionio/translations/zh/LC_MESSAGES/messages.po +++ b/changedetectionio/translations/zh/LC_MESSAGES/messages.po @@ -1335,6 +1335,22 @@ msgstr "" msgid "Must be a hex colour, for example #4f8ef7" msgstr "必须是十六进制颜色,例如 #4f8ef7" +#: changedetectionio/blueprint/tags/form.py +msgid "AI for watches in this group" +msgstr "" + +#: changedetectionio/blueprint/tags/form.py +msgid "On, use the settings below" +msgstr "" + +#: changedetectionio/blueprint/tags/form.py +msgid "Off for every watch" +msgstr "" + +#: changedetectionio/blueprint/tags/form.py +msgid "Leave it to each watch" +msgstr "" + #: changedetectionio/blueprint/tags/form.py msgid "Tag name" msgstr "" @@ -3179,16 +3195,16 @@ msgid "Use global settings for time between check and scheduler." msgstr "检查间隔与调度时间使用全局设置。" #: changedetectionio/forms.py -msgid "AI Change Intent" +msgid "AI Change Intent - Notify me when.." msgstr "" #: changedetectionio/blueprint/settings/templates/settings_llm_tab.html changedetectionio/blueprint/ui/templates/diff.html -#: changedetectionio/forms.py changedetectionio/templates/edit/include_llm_intent.html +#: changedetectionio/forms.py msgid "AI Change Summary" msgstr "" #: changedetectionio/blueprint/tags/form.py changedetectionio/forms.py -msgid "How this prompt combines with the inherited one" +msgid "Change Summary prompt - Append or Replace the default?" msgstr "" #: changedetectionio/blueprint/tags/form.py changedetectionio/forms.py @@ -3199,6 +3215,10 @@ msgstr "" msgid "Append to the inherited prompt" msgstr "" +#: changedetectionio/forms.py +msgid "AI enabled for this watch?" +msgstr "" + #: changedetectionio/forms.py msgid "CSS/JSONPath/JQ/XPath Filters" msgstr "CSS/JSONPath/JQ/XPath 过滤器" @@ -4528,11 +4548,20 @@ msgid "Enter search term..." msgstr "输入搜索关键词..." #: changedetectionio/templates/edit/include_llm_intent.html -msgid "AI" +msgid "" +"On – every watch in this group uses the AI settings below, unless it fills in its own. " +"Off – no AI for any watch in this group. Leave it to each watch – this " +"group has no say; each watch uses its own AI settings." msgstr "" #: changedetectionio/templates/edit/include_llm_intent.html -msgid "AI — Notify when…" +#, python-format +msgid "Group %(name)s decides this: AI is ON for every watch in that group." +msgstr "" + +#: changedetectionio/templates/edit/include_llm_intent.html +#, python-format +msgid "Group %(name)s decides this: AI is OFF for every watch in that group." msgstr "" #: changedetectionio/templates/edit/include_llm_intent.html @@ -4618,6 +4647,10 @@ msgstr "" msgid "Describe the price change: old price, new price, percentage difference." msgstr "" +#: changedetectionio/templates/edit/include_llm_intent.html +msgid "AI" +msgstr "" + #: changedetectionio/templates/edit/include_llm_intent.html #, python-format msgid "" diff --git a/changedetectionio/translations/zh_Hant_TW/LC_MESSAGES/messages.po b/changedetectionio/translations/zh_Hant_TW/LC_MESSAGES/messages.po index a64bb70e1..2577b5484 100644 --- a/changedetectionio/translations/zh_Hant_TW/LC_MESSAGES/messages.po +++ b/changedetectionio/translations/zh_Hant_TW/LC_MESSAGES/messages.po @@ -1334,6 +1334,22 @@ msgstr "" msgid "Must be a hex colour, for example #4f8ef7" msgstr "必須是十六進位色碼,例如 #4f8ef7" +#: changedetectionio/blueprint/tags/form.py +msgid "AI for watches in this group" +msgstr "" + +#: changedetectionio/blueprint/tags/form.py +msgid "On, use the settings below" +msgstr "" + +#: changedetectionio/blueprint/tags/form.py +msgid "Off for every watch" +msgstr "" + +#: changedetectionio/blueprint/tags/form.py +msgid "Leave it to each watch" +msgstr "" + #: changedetectionio/blueprint/tags/form.py msgid "Tag name" msgstr "" @@ -3179,16 +3195,16 @@ msgid "Use global settings for time between check and scheduler." msgstr "檢查與排程時間使用全域設定。" #: changedetectionio/forms.py -msgid "AI Change Intent" +msgid "AI Change Intent - Notify me when.." msgstr "" #: changedetectionio/blueprint/settings/templates/settings_llm_tab.html changedetectionio/blueprint/ui/templates/diff.html -#: changedetectionio/forms.py changedetectionio/templates/edit/include_llm_intent.html +#: changedetectionio/forms.py msgid "AI Change Summary" msgstr "" #: changedetectionio/blueprint/tags/form.py changedetectionio/forms.py -msgid "How this prompt combines with the inherited one" +msgid "Change Summary prompt - Append or Replace the default?" msgstr "" #: changedetectionio/blueprint/tags/form.py changedetectionio/forms.py @@ -3199,6 +3215,10 @@ msgstr "" msgid "Append to the inherited prompt" msgstr "" +#: changedetectionio/forms.py +msgid "AI enabled for this watch?" +msgstr "" + #: changedetectionio/forms.py msgid "CSS/JSONPath/JQ/XPath Filters" msgstr "CSS / JSONPath / JQ / XPath 過濾器" @@ -4526,11 +4546,20 @@ msgid "Enter search term..." msgstr "輸入搜尋關鍵字 ..." #: changedetectionio/templates/edit/include_llm_intent.html -msgid "AI" +msgid "" +"On – every watch in this group uses the AI settings below, unless it fills in its own. " +"Off – no AI for any watch in this group. Leave it to each watch – this " +"group has no say; each watch uses its own AI settings." msgstr "" #: changedetectionio/templates/edit/include_llm_intent.html -msgid "AI — Notify when…" +#, python-format +msgid "Group %(name)s decides this: AI is ON for every watch in that group." +msgstr "" + +#: changedetectionio/templates/edit/include_llm_intent.html +#, python-format +msgid "Group %(name)s decides this: AI is OFF for every watch in that group." msgstr "" #: changedetectionio/templates/edit/include_llm_intent.html @@ -4616,6 +4645,10 @@ msgstr "" msgid "Describe the price change: old price, new price, percentage difference." msgstr "" +#: changedetectionio/templates/edit/include_llm_intent.html +msgid "AI" +msgstr "" + #: changedetectionio/templates/edit/include_llm_intent.html #, python-format msgid "" diff --git a/changedetectionio/worker.py b/changedetectionio/worker.py index 52b91cbcd..e63975d2f 100644 --- a/changedetectionio/worker.py +++ b/changedetectionio/worker.py @@ -455,15 +455,20 @@ async def async_update_worker(worker_id, q, notification_q, app, datastore, exec if changed_detected and watch.history_n >= 1: try: from changedetectionio.llm.evaluator import ( - evaluate_change, resolve_intent, resolve_llm_field, - summarise_change, _runtime_llm_config, + evaluate_change, llm_enabled_for_watch, resolve_intent, + resolve_llm_field, summarise_change, _runtime_llm_config, ) + # Per-watch (or group-wide) AI on/off — #4204. Checked before + # any diff work so a switched-off watch costs nothing. + _llm_on, _llm_on_source = llm_enabled_for_watch(watch, datastore) + if not _llm_on: + logger.debug(f"LLM disabled for {uuid} (by {_llm_on_source}) — skipping AI intent/summary") # _runtime_llm_config returns None (and logs a debug skip # message) when the master 'llm_enabled' toggle is off, so # the whole block — diff computation, status minitext, and # the two executor dispatches — is skipped, not just the # inner LLM lookups. - _llm_cfg = _runtime_llm_config(datastore) + _llm_cfg = _runtime_llm_config(datastore) if _llm_on else None if _llm_cfg: # Compute unified diff once — used by both intent and summary _watch_dates = list(watch.history.keys()) diff --git a/docs/api-spec.yaml b/docs/api-spec.yaml index 2fc7e03e4..ed91e1b1e 100644 --- a/docs/api-spec.yaml +++ b/docs/api-spec.yaml @@ -606,6 +606,17 @@ components: description: Logic operator - ALL (match all conditions) or ANY (match any condition) # AI / LLM + llm_backend_profile: + type: [boolean, 'null'] + default: true + description: | + Whether AI/LLM features are enabled. On a watch this is a plain on/off (default true). + On a tag/group it is ternary and is that group's only AI control: + - true: AI on for every watch in the group, and the group's `llm_intent` / + `llm_change_summary` are inherited by its watches (unless a watch sets its own) + - false: AI off for every watch in the group + - null (group default): the group has no say; each watch uses its own AI settings + (Reserved for selecting a named LLM profile in future - currently a plain on/off.) llm_intent: type: string maxLength: 2000