diff --git a/changedetectionio/blueprint/add_watch_ui/__init__.py b/changedetectionio/blueprint/add_watch_ui/__init__.py index 21f9847c..23bdd347 100644 --- a/changedetectionio/blueprint/add_watch_ui/__init__.py +++ b/changedetectionio/blueprint/add_watch_ui/__init__.py @@ -1,4 +1,5 @@ -from flask import Blueprint, render_template +from flask import Blueprint, render_template, request, jsonify, make_response +from loguru import logger from changedetectionio import forms from changedetectionio.auth_decorator import login_optionally_required @@ -6,7 +7,7 @@ from changedetectionio.store import ChangeDetectionStore def construct_blueprint(datastore: ChangeDetectionStore): - add_watch_ui_blueprint = Blueprint('add_watch_ui', __name__, template_folder="templates") + add_watch_ui_blueprint = Blueprint('add_watch_ui', __name__, template_folder="templates", static_folder="static") @add_watch_ui_blueprint.route("/", methods=['GET']) @login_optionally_required @@ -24,4 +25,64 @@ def construct_blueprint(datastore: ChangeDetectionStore): llm_intent_watch_placeholder=LLM_INTENT_WATCH_PLACEHOLDER, ) + @add_watch_ui_blueprint.route("/snapshot", methods=['GET']) + @login_optionally_required + def add_watch_ui_snapshot(): + """One-shot live fetch of an arbitrary URL for the Add Watch visual selector. + + Reuses the same browser machinery as Browser Steps (browsersteps_live_ui + + the dedicated async loop) but without needing a persisted watch - we just + connect, "Goto site", grab the screenshot + xpath element data, then tear + the browser down again. Element selection then happens client-side on the + returned data, exactly like the watch Edit page's visual selector. + """ + import base64 + from changedetectionio.blueprint.browser_steps import ( + run_async_in_browser_loop, + _close_session_resources, + acquire_browser_for_fetcher, + ) + from changedetectionio.browser_steps.browser_steps import browsersteps_live_ui + + url = (request.args.get('url') or '').strip() + if not url or not url.lower().startswith(('http://', 'https://')): + return make_response('Please enter a valid http(s):// URL', 400) + + # Use whatever fetcher the application is configured to use by default + # (e.g. CloakBrowser, Playwright/sockpuppet) so the preview matches real checks. + fetcher_name = datastore.data['settings']['application'].get('fetch_backend', 'html_requests') + logger.debug(f"Add-watch snapshot: fetching '{url}' using system default fetcher '{fetcher_name}'") + + async def _fetch_snapshot(): + keepalive_ms = 30 * 1000 + browser, playwright_context = await acquire_browser_for_fetcher( + fetcher_name, proxy=None, keepalive_ms=keepalive_ms + ) + + stepper = browsersteps_live_ui(playwright_browser=browser, proxy=None, start_url=url) + session = {'browserstepper': stepper, 'browser': browser, 'playwright_context': playwright_context} + try: + await stepper.connect(proxy=None) + await stepper.call_action(action_name="Goto site", selector=None, optional_value=None) + return await stepper.get_current_state() + finally: + await _close_session_resources(session, label=' for add-watch snapshot') + + try: + (screenshot, xpath_data) = run_async_in_browser_loop(_fetch_snapshot()) + except Exception as e: + logger.error(f"Add-watch snapshot fetch failed for {url}: {e}") + if 'ECONNREFUSED' in str(e): + return make_response('Unable to start the Playwright Browser session, is sockpuppetbrowser running? ' + 'The live preview needs a fetcher that supports Javascript and screenshots.', 502) + return make_response(str(e).splitlines()[0] if str(e) else 'Could not fetch the page', 502) + + if not screenshot: + return make_response('Could not capture a screenshot for that URL', 502) + + return jsonify({ + "screenshot": f"data:image/jpeg;base64,{base64.b64encode(screenshot).decode('ascii')}", + "xpath_data": xpath_data, + }) + return add_watch_ui_blueprint diff --git a/changedetectionio/blueprint/add_watch_ui/static/add-watch.js b/changedetectionio/blueprint/add_watch_ui/static/add-watch.js new file mode 100644 index 00000000..8c7c35f4 --- /dev/null +++ b/changedetectionio/blueprint/add_watch_ui/static/add-watch.js @@ -0,0 +1,87 @@ +// Add Watch UI glue: fetch a live snapshot for the entered URL and drive the +// shared visual selector (window.initVisualSelector from visual-selector.js). + +$(document).ready(() => { + const $url = $('#url'); + const $go = $('#add-watch-go'); + const $emptyState = $('#add-watch-empty-state'); + const $spinner = $('#add-watch-spinner'); + const $error = $('#add-watch-error'); + const $wrapper = $('#selector-wrapper'); + const $xpathRow = $('#selector-current-xpath'); + const $byElement = $('#by-element-toggle'); + const $clear = $('#clear-selector'); + const $includeFilters = $('#include_filters'); + + const vs = window.initVisualSelector({ + $canvas: $('#selector-canvas'), + $includeFilters: $includeFilters, + $background: $('#selector-background'), + $xpathDisplay: $('#selector-current-xpath span'), + $fetchingNotice: $('#add-watch-spinner .fetching-update-notice'), + $wrapper: $wrapper, + $clearButton: $clear, + enableSelection: false, // off until the user opts into "Select by element" + processorIsImage: false, + // The snapshot comes from the live browser-steps capture, so scale X by the page + // CSS width (browser_width) like browser-steps.js - handles device-scale-factor != 1. + scaleByBrowserWidth: true, + }); + + function showState(which) { + // which: 'empty' | 'loading' | 'error' | 'ready' + $emptyState.toggle(which === 'empty'); + $spinner.toggle(which === 'loading'); + $error.toggle(which === 'error'); + const ready = which === 'ready'; + $wrapper.toggle(ready); + $xpathRow.toggle(ready && $byElement.is(':checked')); + $clear.toggle(ready && $byElement.is(':checked')); + } + + function fetchSnapshot() { + const url = ($url.val() || '').trim(); + if (!url) { + $url.focus(); + return; + } + + showState('loading'); + + $.ajax({ + url: add_watch_snapshot_url, + data: {url: url}, + dataType: 'json', + }).done((data) => { + showState('ready'); + vs.load({screenshotSrc: data.screenshot, xpathData: data.xpath_data}); + }).fail((xhr) => { + const msg = (xhr && xhr.responseText) ? xhr.responseText : 'Could not fetch a preview for that URL.'; + $error.text(msg); + showState('error'); + }); + } + + $go.on('click', fetchSnapshot); + + // Enter in the URL box should fetch a preview, not submit the whole form + $url.on('keydown', (e) => { + if (e.key === 'Enter') { + e.preventDefault(); + fetchSnapshot(); + } + }); + + // "Select by element" toggles live hover/click element selection + $byElement.on('change', function () { + const on = $(this).is(':checked'); + vs.setSelectionEnabled(on); + $xpathRow.toggle(on && $wrapper.is(':visible')); + $clear.toggle(on && $wrapper.is(':visible')); + if (!on) { + $includeFilters.val(''); + } + }); + + showState('empty'); +}); diff --git a/changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html b/changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html index 4aef12d2..eb9233ec 100644 --- a/changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html +++ b/changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html @@ -2,42 +2,94 @@ {%- block content -%} {%- from '_helpers.html' import render_simple_field, render_field, render_nolabel_field -%} -
+
- + + + +
{{ _('Add a new web page change detection watch') }} -
- {{ render_nolabel_field(form.url, placeholder="https://...", required=true) }} - {{ render_nolabel_field(form.watch_submit_button, title=_("Watch this URL!") ) }} - {{ render_nolabel_field(form.edit_and_watch_submit_button, title=_("Edit first then Watch") ) }} + + +
+ {{ render_nolabel_field(form.url, placeholder="https://...", required=true, class="pure-input-1") }} +
- {% if llm_configured %} -
- -
- {% endif %} -
- {{ render_field(form.tags, value='', placeholder=_("Watch group / tag"), class="transparent-field") }} -
-
- {{ render_simple_field(form.processor) }} + +
+ + +
+
+ + {{ _('Enter a URL to get started!') }} + {{ _('Enter a URL in the input box above to get started.') }} +
+ + + + + + + + +
+ + +
+
+ {{ render_simple_field(form.processor) }} +
+ +
+ + {{ _('Hover & click the preview to watch just one part of the page.') }} + +
+ + {% if llm_configured %} +
+ + +
+ {% endif %} + +
+ {{ render_field(form.tags, value='', placeholder=_("Watch group / tag"), class="transparent-field") }} +
+ +
+ {{ render_nolabel_field(form.watch_submit_button, title=_("Watch this URL!")) }} + {{ render_nolabel_field(form.edit_and_watch_submit_button, title=_("Edit first then Watch")) }} +
+
+
-
-
-

{{ _('Live activity') }}

-

{{ _('Recent additions and live check status will appear here.') }}

-
- {{ _('Waiting for activity…') }} -
-
-
+ + + + {%- endblock -%} diff --git a/changedetectionio/blueprint/browser_steps/__init__.py b/changedetectionio/blueprint/browser_steps/__init__.py index 8666b345..58be9a95 100644 --- a/changedetectionio/blueprint/browser_steps/__init__.py +++ b/changedetectionio/blueprint/browser_steps/__init__.py @@ -131,6 +131,47 @@ async def _close_session_resources(session_data, label=''): logger.warning(f"Error stopping playwright context{label}: {e}") +async def acquire_browser_for_fetcher(fetcher_name, proxy=None, keepalive_ms=None): + """Acquire a Playwright browser for the given fetcher backend. + + Mirrors normal fetching: fetchers that launch their own browser (e.g. CloakBrowser) + provide get_browsersteps_browser(); otherwise we connect over CDP to the configured + Playwright/sockpuppetbrowser driver. Returns (browser, playwright_context). + """ + from changedetectionio import content_fetchers + from playwright.async_api import async_playwright + + logger.debug(f"acquire_browser_for_fetcher: requested fetcher='{fetcher_name}', proxy={'yes' if proxy else 'no'}, keepalive_ms={keepalive_ms}") + + browser = None + playwright_context = None + + # If the fetcher has its own browser launch (runs locally rather than via CDP), use it. + fetcher_class = getattr(content_fetchers, fetcher_name, None) if fetcher_name else None + if fetcher_class and hasattr(fetcher_class, 'get_browsersteps_browser'): + logger.debug(f"acquire_browser_for_fetcher: fetcher '{fetcher_name}' provides its own browser, launching locally") + result = await fetcher_class.get_browsersteps_browser(proxy=proxy, keepalive_ms=keepalive_ms) + if result is not None: + browser, playwright_context = result + logger.info(f"acquire_browser_for_fetcher: using fetcher-specific browser for '{fetcher_name}'") + else: + logger.debug(f"acquire_browser_for_fetcher: '{fetcher_name}' returned no browser, falling back to CDP") + else: + logger.debug(f"acquire_browser_for_fetcher: fetcher '{fetcher_name}' has no get_browsersteps_browser(), using CDP") + + # Default: connect to the remote Playwright/sockpuppetbrowser via CDP + if browser is None: + base_url = os.getenv('PLAYWRIGHT_DRIVER_URL', '').strip('"') + logger.debug(f"acquire_browser_for_fetcher: connecting over CDP to '{base_url}' for fetcher '{fetcher_name}'") + playwright_context = await async_playwright().start() + a = "?" if '?' not in base_url else '&' + connect_url = base_url + a + f"timeout={keepalive_ms}" + browser = await playwright_context.chromium.connect_over_cdp(connect_url, timeout=keepalive_ms) + logger.info(f"acquire_browser_for_fetcher: connected over CDP for fetcher '{fetcher_name}'") + + return browser, playwright_context + + def cleanup_expired_sessions(): """Remove expired browsersteps sessions and cleanup their resources""" global browsersteps_sessions, browsersteps_watch_to_session @@ -222,36 +263,14 @@ def construct_blueprint(datastore: ChangeDetectionStore): proxy['password'] = parsed.password logger.debug(f"Browser Steps: UUID {watch_uuid} selected proxy {proxy_url}") - # Resolve the fetcher class for this watch so we can ask it to launch its own browser + # Resolve the fetcher backend for this watch so we can ask it to launch its own browser # if it supports that (e.g. CloakBrowser, which runs locally rather than via CDP) watch = datastore.data['watching'][watch_uuid] - from changedetectionio import content_fetchers fetcher_name = watch.get_fetch_backend or 'system' if fetcher_name == 'system': fetcher_name = datastore.data['settings']['application'].get('fetch_backend', 'html_requests') - fetcher_class = getattr(content_fetchers, fetcher_name, None) - browser = None - playwright_context = None - - # If the fetcher has its own browser launch for the live steps UI, use it. - # get_browsersteps_browser(proxy, keepalive_ms) returns (browser, playwright_context_or_None) - # or None to fall back to the default CDP path. - if fetcher_class and hasattr(fetcher_class, 'get_browsersteps_browser'): - result = await fetcher_class.get_browsersteps_browser(proxy=proxy, keepalive_ms=keepalive_ms) - if result is not None: - browser, playwright_context = result - logger.debug(f"Browser Steps: using fetcher-specific browser for '{fetcher_name}'") - - # Default: connect to the remote Playwright/sockpuppetbrowser via CDP - if browser is None: - playwright_instance = async_playwright() - playwright_context = await playwright_instance.start() - base_url = os.getenv('PLAYWRIGHT_DRIVER_URL', '').strip('"') - a = "?" if '?' not in base_url else '&' - base_url += a + f"timeout={keepalive_ms}" - browser = await playwright_context.chromium.connect_over_cdp(base_url, timeout=keepalive_ms) - logger.debug(f"Browser Steps: using CDP connection to {base_url}") + browser, playwright_context = await acquire_browser_for_fetcher(fetcher_name, proxy=proxy, keepalive_ms=keepalive_ms) browsersteps_start_session['browser'] = browser browsersteps_start_session['playwright_context'] = playwright_context diff --git a/changedetectionio/blueprint/settings/templates/settings.html b/changedetectionio/blueprint/settings/templates/settings.html index e6f5747c..9ae1da9f 100644 --- a/changedetectionio/blueprint/settings/templates/settings.html +++ b/changedetectionio/blueprint/settings/templates/settings.html @@ -288,6 +288,10 @@ nav {{ render_field(form.application.form.pager_size) }} {{ _('Number of items per page in the watch overview list, 0 to disable.') }}
+
+ {{ render_field(form.application.form.ui.form.timeago_format) }} + {{ _('How "Last Checked" and "Last Changed" times are shown in the watch overview list.') }} +
diff --git a/changedetectionio/blueprint/ui/views.py b/changedetectionio/blueprint/ui/views.py index 903087b5..0535d74b 100644 --- a/changedetectionio/blueprint/ui/views.py +++ b/changedetectionio/blueprint/ui/views.py @@ -30,6 +30,11 @@ def construct_blueprint(datastore: ChangeDetectionStore, update_q, queuedWatchMe extras = {'paused': add_paused, 'processor': processor} if llm_intent: extras['llm_intent'] = llm_intent + + # Filters picked with the Add Watch visual selector ("by element" mode) + include_filters = [l.strip() for l in request.form.get('include_filters', '').split('\n') if l.strip()] + if include_filters: + extras['include_filters'] = include_filters new_uuid = datastore.add_watch(url=url, tag=request.form.get('tags','').strip(), extras=extras) if new_uuid: diff --git a/changedetectionio/blueprint/watchlist/templates/watch-overview.html b/changedetectionio/blueprint/watchlist/templates/watch-overview.html index 6a725dd1..c28e5c3d 100644 --- a/changedetectionio/blueprint/watchlist/templates/watch-overview.html +++ b/changedetectionio/blueprint/watchlist/templates/watch-overview.html @@ -220,7 +220,7 @@ window.watchOverviewI18n = { #
- +
@@ -350,6 +350,16 @@ window.watchOverviewI18n = { {{ price }} {{ cur }} {%- endif -%} + {%- set price_change_pct = restock.get_price_change_percent() -%} + {%- if price_change_pct is not none -%} + {%- set prev_price = restock.get_prev_price() -%} + {%- set prev_disp = (prev_price|format_number_locale ~ ' ' ~ cur) if prev_price is number else prev_price -%} + {%- if price_change_pct < 0 -%} + ▼ {{ '%g'|format(price_change_pct) }}% + {%- else -%} + ▲ +{{ '%g'|format(price_change_pct) }}% + {%- endif -%} + {%- endif -%} {%- endif -%} {%- elif not watch.has_restock_info -%} {{ _('No information') }} diff --git a/changedetectionio/flask_app.py b/changedetectionio/flask_app.py index f8155f85..7e9c506e 100644 --- a/changedetectionio/flask_app.py +++ b/changedetectionio/flask_app.py @@ -268,24 +268,26 @@ def _jinja2_filter_datetime(watch_obj, format="%Y-%m-%d %H:%M:%S"): if watch_obj['last_checked'] == 0: return gettext('Not yet') - locale = get_timeago_locale(str(get_locale())) + short = datastore.data['settings']['application'].get('ui', {}).get('timeago_format') == 'short' + locale = get_timeago_locale(str(get_locale()), short=short) try: return timeago.format(int(watch_obj['last_checked']), time.time(), locale) except: # Fallback to English if locale not supported by timeago - return timeago.format(int(watch_obj['last_checked']), time.time(), 'en') + return timeago.format(int(watch_obj['last_checked']), time.time(), 'en_short' if short else 'en') @app.template_filter('format_timestamp_timeago') def _jinja2_filter_datetimestamp(timestamp, format="%Y-%m-%d %H:%M:%S"): if not timestamp: return gettext('Not yet') - locale = get_timeago_locale(str(get_locale())) + short = datastore.data['settings']['application'].get('ui', {}).get('timeago_format') == 'short' + locale = get_timeago_locale(str(get_locale()), short=short) try: return timeago.format(int(timestamp), time.time(), locale) except: # Fallback to English if locale not supported by timeago - return timeago.format(int(timestamp), time.time(), 'en') + return timeago.format(int(timestamp), time.time(), 'en_short' if short else 'en') @app.template_filter('pagination_slice') diff --git a/changedetectionio/forms.py b/changedetectionio/forms.py index 7f1fbc47..d2804d39 100644 --- a/changedetectionio/forms.py +++ b/changedetectionio/forms.py @@ -1074,6 +1074,9 @@ class globalSettingsApplicationUIForm(Form): socket_io_enabled = BooleanField(_l('Realtime UI Updates Enabled'), default=True, validators=[validators.Optional()]) favicons_enabled = BooleanField(_l('Favicons Enabled'), default=True, validators=[validators.Optional()]) use_page_title_in_list = BooleanField(_l('Use page in watch overview list')) #BooleanField=True + timeago_format = SelectField(_l('Relative time format'), + choices=[('long', _l('Long (1 minute ago)')), ('short', _l('Short (1m ago)'))], + default='long', validators=[validators.Optional()]) # datastore.data['settings']['application'].. class globalSettingsApplicationForm(commonSettingsForm): diff --git a/changedetectionio/languages.py b/changedetectionio/languages.py index aa4428df..935d5d6a 100644 --- a/changedetectionio/languages.py +++ b/changedetectionio/languages.py @@ -6,7 +6,7 @@ import os from pathlib import Path -def get_timeago_locale(flask_locale): +def get_timeago_locale(flask_locale, short=False): """ Convert Flask-Babel locale codes to timeago library locale codes. @@ -23,10 +23,19 @@ def get_timeago_locale(flask_locale): Args: flask_locale (str): Flask-Babel locale code (e.g., 'cs', 'zh', 'pt') + short (bool): Return a compact "1m ago" style locale instead of "1 minute ago". + timeago only ships 'en_short'; the other short locales are registered + by register_short_timeago_locales() below. Unsupported languages fall + back to 'en_short' so short mode is always honoured. Returns: - str: timeago library locale code (e.g., 'en', 'zh_CN', 'pt_PT') + str: timeago library locale code (e.g., 'en', 'zh_CN', 'pt_PT', 'de_short') """ + if short: + # Short forms are translated through the normal gettext (.po/.mo) workflow rather than + # timeago's bundled per-language tables; build + register the table for this locale. + return register_short_timeago_locale(flask_locale) + locale_map = { 'zh': 'zh_CN', # Chinese Simplified # timeago library just hasn't been updated to use the more modern locale naming convention, before BCP 47 / RFC 5646. @@ -45,6 +54,82 @@ def get_timeago_locale(flask_locale): } return locale_map.get(flask_locale, flask_locale) + +# --- Short ("1m ago") timeago locales ------------------------------------------------- +# +# timeago only ships 'en_short' and resolves a locale by name via +# __import__('timeago.locales.<name>'), which checks sys.modules first. So we register a table +# at runtime per locale. Rather than hard-code a table per language, the short strings are +# routed through the normal gettext (.po/.mo) workflow: the rows below are wrapped in +# lazy_gettext (_l) so `python setup.py extract_messages` picks them up, and they resolve to +# the active locale when rendered. Translators maintain the short forms in messages.po just +# like every other string. +# +# 14 rows of (past, future) following timeago's index order: +# now, Ns, 1m, Nm, 1h, Nh, 1d, Nd, 1w, Nw, 1mo, Nmo, 1yr, Nyr ('%s' = the number) +# The English source strings double as the gettext msgids. + +def _build_short_timeago_rows(): + from flask_babel import lazy_gettext as _l + return [ + (_l('just now'), _l('right now')), + (_l('%ss ago'), _l('in %ss')), + (_l('1m ago'), _l('in 1m')), + (_l('%sm ago'), _l('in %sm')), + (_l('1h ago'), _l('in 1h')), + (_l('%sh ago'), _l('in %sh')), + (_l('1d ago'), _l('in 1d')), + (_l('%sd ago'), _l('in %sd')), + (_l('1w ago'), _l('in 1w')), + (_l('%sw ago'), _l('in %sw')), + (_l('1mo ago'), _l('in 1mo')), + (_l('%smo ago'), _l('in %smo')), + (_l('1yr ago'), _l('in 1yr')), + (_l('%syr ago'), _l('in %syr')), + ] + + +_short_timeago_rows = None +_registered_short_locales = set() + + +def register_short_timeago_locale(flask_locale): + """ + Build the short timeago table for `flask_locale` from the gettext catalog and register it + under a synthetic name so timeago.format(..., <name>) can use it. Returns the locale name + to hand to timeago (falls back to the bundled 'en_short' if anything goes wrong). + + The table is resolved with flask_babel.force_locale so it is correct regardless of which + locale is active, and cached per language so the gettext lookups happen only once each. + """ + name = 'cd_short_' + str(flask_locale).replace('-', '_') + if name in _registered_short_locales: + return name + + try: + import sys + import types + import timeago.locales as timeago_locales + from flask_babel import force_locale + + global _short_timeago_rows + if _short_timeago_rows is None: + _short_timeago_rows = _build_short_timeago_rows() + + with force_locale(str(flask_locale)): + table = [[str(past), str(future)] for past, future in _short_timeago_rows] + + mod_name = 'timeago.locales.' + name + mod = types.ModuleType(mod_name) + mod.LOCALE = table + sys.modules[mod_name] = mod + setattr(timeago_locales, name, mod) + _registered_short_locales.add(name) + return name + except Exception: + # Outside an app context, or any unexpected failure -> bundled English short locale. + return 'en_short' + # Language metadata: flag icon CSS class and native name # Using flag-icons library: https://flagicons.lipis.dev/ LANGUAGE_DATA = { diff --git a/changedetectionio/model/App.py b/changedetectionio/model/App.py index c40f182c..76c297a0 100644 --- a/changedetectionio/model/App.py +++ b/changedetectionio/model/App.py @@ -78,7 +78,8 @@ class model(dict): 'use_page_title_in_list': True, 'open_diff_in_new_tab': True, 'socket_io_enabled': True, - 'favicons_enabled': True + 'favicons_enabled': True, + 'timeago_format': 'long', # 'long' = "1 minute ago", 'short' = "1m ago" }, } } diff --git a/changedetectionio/processors/restock_diff/__init__.py b/changedetectionio/processors/restock_diff/__init__.py index 9b659ec9..99e3571a 100644 --- a/changedetectionio/processors/restock_diff/__init__.py +++ b/changedetectionio/processors/restock_diff/__init__.py @@ -45,7 +45,8 @@ class Restock(dict): 'in_stock': None, 'price': None, 'currency': None, - 'original_price': None + 'original_price': None, + 'prev_price': None # price at the previous check, for the watch-list up/down arrow (display only) } # Initialize the dictionary with default values @@ -66,6 +67,31 @@ class Restock(dict): super().__setitem__(key, value) + def get_prev_price(self): + """Price at the previous check. Falls back to original_price for watches + saved before prev_price existed. Returns a float or None.""" + prev = self.get('prev_price') + if prev is None: + prev = self.get('original_price') + return prev + + def get_price_change_percent(self): + """Signed % change of the current price vs the previous price, rounded to one + decimal place (e.g. -18.0, 5.3). Returns None when it can't be computed - + no/zero previous price, non-numeric values, or no change.""" + try: + price = float(self.get('price')) + prev = self.get_prev_price() + prev = float(prev) if prev is not None else None + except (TypeError, ValueError): + return None + + if prev is None or prev == 0: + return None + + pct = round((price - prev) / prev * 100.0, 1) + return pct if pct != 0 else None + def get_price_from_history_str(history_str): m = _price_re.search(history_str) if not m: diff --git a/changedetectionio/processors/restock_diff/plugins/llm_restock.py b/changedetectionio/processors/restock_diff/plugins/llm_restock.py index be328edb..ba6e0ba4 100644 --- a/changedetectionio/processors/restock_diff/plugins/llm_restock.py +++ b/changedetectionio/processors/restock_diff/plugins/llm_restock.py @@ -86,7 +86,7 @@ SYSTEM_PROMPT = ( 'No markdown, no backticks, no explanation — pure JSON only.' ) -_MAX_CONTENT_CHARS = 8_000 +_MAX_CONTENT_CHARS = 20_000 def _extract_jsonld(html_content: str) -> str: diff --git a/changedetectionio/processors/restock_diff/processor.py b/changedetectionio/processors/restock_diff/processor.py index ecf6b132..763456e8 100644 --- a/changedetectionio/processors/restock_diff/processor.py +++ b/changedetectionio/processors/restock_diff/processor.py @@ -564,10 +564,14 @@ class perform_site_check(difference_detection_processor): # Main detection method fetched_md5 = None - # store original price if not set - if itemprop_availability and itemprop_availability.get('price') and not itemprop_availability.get('original_price'): - itemprop_availability['original_price'] = itemprop_availability.get('price') - update_obj['restock']["original_price"] = itemprop_availability.get('price') + # Original price = the price at the FIRST check. Set it once and then preserve it across + # every later check (display only) so the watch list can show "first seen" alongside the + # current price. (Previously this was re-set to the current price on every check.) + old_original_price = (watch.get('restock') or {}).get('original_price') + if old_original_price is not None: + update_obj['restock']['original_price'] = old_original_price + elif update_obj['restock'].get('price') is not None: + update_obj['restock']['original_price'] = update_obj['restock'].get('price') if not self.fetcher.instock_data and not itemprop_availability.get('availability') and not itemprop_availability.get('price'): raise ProcessorException( @@ -594,6 +598,18 @@ class perform_site_check(difference_detection_processor): logger.warning(f"Setting instock to FALSE, scraper found '{self.fetcher.instock_data}' in the body but metadata reported not-in-stock") update_obj['restock']["in_stock"] = False + # Remember the price from *before the last actual price change* so the watch list can + # show a persistent up/down arrow. Only bump prev_price when the price really changed - + # otherwise an unchanged check would overwrite it and we'd lose the comparison point. + # Display only - not part of the snapshot/md5, so it never affects change detection. + old_restock = watch.get('restock') or {} + old_price = old_restock.get('price') + new_price = update_obj['restock'].get('price') + if new_price is not None and old_price is not None and new_price != old_price: + update_obj['restock']['prev_price'] = old_price # price moved: remember what we moved from + else: + update_obj['restock']['prev_price'] = old_restock.get('prev_price') # unchanged: keep the existing reference + # What we store in the snapshot price = update_obj.get('restock').get('price') if update_obj.get('restock').get('price') else "" snapshot_content = f"In Stock: {update_obj.get('restock').get('in_stock')} - Price: {price}" diff --git a/changedetectionio/realtime/socket_server.py b/changedetectionio/realtime/socket_server.py index e47f21eb..0e5989fb 100644 --- a/changedetectionio/realtime/socket_server.py +++ b/changedetectionio/realtime/socket_server.py @@ -1,6 +1,5 @@ -import timeago from flask_socketio import SocketIO -from flask_babel import gettext, get_locale +from flask_babel import gettext import time import os @@ -8,7 +7,6 @@ from loguru import logger from blinker import signal from changedetectionio import strtobool -from changedetectionio.languages import get_timeago_locale class SignalHandler: @@ -144,7 +142,7 @@ def handle_watch_update(socketio, **kwargs): # Emit the watch update to all connected clients from changedetectionio.flask_app import update_q - from changedetectionio.flask_app import _jinja2_filter_datetime + from changedetectionio.flask_app import _jinja2_filter_datetime, _jinja2_filter_datetimestamp from changedetectionio import worker_pool # Get list of watches that are currently running @@ -165,7 +163,8 @@ def handle_watch_update(socketio, **kwargs): 'has_error': True if error_texts else False, 'has_favicon': True if watch.get_favicon_filename() else False, 'history_n': watch.history_n, - 'last_changed_text': timeago.format(int(watch.last_changed), time.time(), get_timeago_locale(str(get_locale()))) if watch.history_n >= 2 and int(watch.last_changed) > 0 else gettext('Not yet'), + # Uses the same filter as the server-rendered list so the long/short (timeago_format) setting is honoured. + 'last_changed_text': _jinja2_filter_datetimestamp(int(watch.last_changed)) if watch.history_n >= 2 and int(watch.last_changed) > 0 else gettext('Not yet'), 'last_checked': watch.get('last_checked'), 'last_checked_text': _jinja2_filter_datetime(watch), 'notification_muted': True if watch.get('notification_muted') else False, diff --git a/changedetectionio/static/js/visual-selector.js b/changedetectionio/static/js/visual-selector.js index efb456e9..62b8bb0a 100644 --- a/changedetectionio/static/js/visual-selector.js +++ b/changedetectionio/static/js/visual-selector.js @@ -1,10 +1,34 @@ // Copyright (C) 2021 Leigh Morresi (dgtlmoon@gmail.com) // All rights reserved. // yes - this is really a hack, if you are a front-ender and want to help, please get in touch! +// +// Refactored into a reusable factory: window.initVisualSelector(opts) +// - edit.html drives it from stored screenshot + xpath-data URLs (auto-init at bottom of file) +// - the Add Watch UI drives it from inline snapshot data fetched on demand +// Both share the same hover/highlight/select core. -let runInClearMode = false; +window.initVisualSelector = function (opts) { + // ---- DOM references (passed in, no globals) ---- + const $selectorCanvasElem = opts.$canvas; + const $includeFiltersElem = opts.$includeFilters; + const $selectorBackgroundElem = opts.$background; + const $selectorCurrentXpathElem = opts.$xpathDisplay; // the inner <span> + const $fetchingUpdateNoticeElem = opts.$fetchingNotice || $(); + const $selectorWrapperElem = opts.$wrapper; + const $clearSelectorElem = opts.$clearButton || $(); -$(document).ready(() => { + // edit.html supplies an AJAX url for the element data; the add-watch UI supplies data inline + const xpathDataUrl = opts.xpathDataUrl; + const isImageProcessor = !!opts.processorIsImage; + // Stored watch screenshots are DPR-1, so X scales by the screenshot's natural width. + // The live browser-steps capture (used by Add Watch) may render at device-scale-factor != 1, + // so its X must scale by the page's CSS width (browser_width) instead - exactly like + // browser-steps.js does. Y always scales by the screenshot's natural height. + const scaleByBrowserWidth = !!opts.scaleByBrowserWidth; + + // ---- state ---- + let runInClearMode = false; + let selectionEnabled = opts.enableSelection !== false; let currentSelections = []; let currentSelection = null; let appendToList = false; @@ -22,16 +46,6 @@ $(document).ready(() => { let drawnBox = null; let resizeHandle = null; const HANDLE_SIZE = 8; - const isImageProcessor = $('input[value="image_ssim_diff"]').is(':checked'); - - - // Global jQuery selectors with "Elem" appended - const $selectorCanvasElem = $('#selector-canvas'); - const $includeFiltersElem = $("#include_filters"); - const $selectorBackgroundElem = $("img#selector-background"); - const $selectorCurrentXpathElem = $("#selector-current-xpath span"); - const $fetchingUpdateNoticeElem = $('.fetching-update-notice'); - const $selectorWrapperElem = $("#selector-wrapper"); // Color constants const FILL_STYLE_HIGHLIGHT = 'rgba(205,0,0,0.35)'; @@ -40,14 +54,10 @@ $(document).ready(() => { const FILL_STYLE_REDLINE = 'rgba(255,0,0, 0.1)'; const STROKE_STYLE_REDLINE = 'rgba(225,0,0,0.9)'; - $('#visualselector-tab').click(() => { - $selectorBackgroundElem.off('load'); - currentSelections = []; - bootstrapVisualSelector(); - }); - function clearReset() { - ctx.clearRect(0, 0, c.width, c.height); + if (ctx) { + ctx.clearRect(0, 0, c.width, c.height); + } if ($includeFiltersElem.val().length) { alert("Existing filters under the 'Filters & Triggers' tab were cleared."); @@ -87,23 +97,18 @@ $(document).ready(() => { } }); - $('#clear-selector').on('click', () => { + $clearSelectorElem.on('click', () => { clearReset(); }); - // So if they start switching between visualSelector and manual filters, stop it from rendering old filters - $('li.tab a').on('click', () => { - runInClearMode = true; - }); - if (!window.location.hash || window.location.hash !== '#visualselector') { - $selectorBackgroundElem.attr('src', ''); - return; - } + // ---- public: (re)load a screenshot + element data into the selector ---- + // source = { screenshotSrc: <url|dataURI>, xpathData: <object|undefined> } + function load(source) { + currentSelections = []; + runInClearMode = false; - bootstrapVisualSelector(); - - function bootstrapVisualSelector() { $selectorBackgroundElem + .off("load error") .on("error", () => { $fetchingUpdateNoticeElem.html("<strong>Ooops!</strong> The VisualSelector tool needs at least one fetched page, please unpause the watch and/or wait for the watch to complete fetching and then reload this page.") .css('color', '#bb0000'); @@ -111,16 +116,24 @@ $(document).ready(() => { }) .on('load', () => { console.log("Loaded background..."); - c = document.getElementById("selector-canvas"); + c = $selectorCanvasElem[0]; xctx = c.getContext("2d"); ctx = c.getContext("2d"); - fetchData(); + if (source.xpathData) { + // Inline data (add-watch snapshot) - no extra round trip needed + applyElementData(source.xpathData); + } else { + fetchData(); + } $selectorCanvasElem.off("mousemove mousedown"); - }) - .attr("src", screenshot_url); + }); - let s = `${$selectorBackgroundElem.attr('src')}?${new Date().getTime()}`; - $selectorBackgroundElem.attr('src', s); + // data: URIs must be used verbatim; real URLs get a cache-buster + let src = source.screenshotSrc; + if (src && src.indexOf('data:') !== 0) { + src = `${src}?${new Date().getTime()}`; + } + $selectorBackgroundElem.attr("src", src); } function alertIfFilterNotFound() { @@ -139,28 +152,32 @@ $(document).ready(() => { $fetchingUpdateNoticeElem.html("Fetching element data.."); $.ajax({ - url: watch_visual_selector_data_url, + url: xpathDataUrl, context: document.body }).done((data) => { - $fetchingUpdateNoticeElem.html("Rendering.."); - selectorData = data; - - sortScrapedElementsBySize(); - console.log(`Reported browser width from backend: ${data['browser_width']}`); - - // Little sanity check for the user, alert them if something missing - alertIfFilterNotFound(); - - setScale(); - reflowSelector(); - - // Initialize draw mode after everything is set up - initializeDrawMode(); - - $fetchingUpdateNoticeElem.fadeOut(); + applyElementData(data); }); } + function applyElementData(data) { + $fetchingUpdateNoticeElem.html("Rendering.."); + selectorData = data; + + sortScrapedElementsBySize(); + console.log(`Reported browser width from backend: ${data['browser_width']}`); + + // Little sanity check for the user, alert them if something missing + alertIfFilterNotFound(); + + setScale(); + reflowSelector(); + + // Initialize draw mode after everything is set up + initializeDrawMode(); + + $fetchingUpdateNoticeElem.fadeOut(); + } + function updateFiltersText() { // Assuming currentSelections is already defined and contains the selections let uniqueSelections = new Set(currentSelections.map(sel => (sel[0] === '/' ? `xpath:${sel.xpath}` : sel.xpath))); @@ -184,8 +201,16 @@ $(document).ready(() => { $selectorWrapperElem.attr('width', selectorImageRect.width); $('#visual-selector-heading').css('max-width', selectorImageRect.width + "px") - xScale = selectorImageRect.width / selectorImage.naturalWidth; - yScale = selectorImageRect.height / selectorImage.naturalHeight; + if (scaleByBrowserWidth && selectorData && selectorData['browser_width']) { + // xpath box coords are CSS pixels (getBoundingClientRect) and the scraper reports + // browser_width = window.innerWidth (also CSS px). The screenshot is displayed with a + // preserved aspect ratio, so a single uniform factor (displayed width / page CSS width) + // maps both axes in sync, regardless of the capture's device-pixel-ratio. + xScale = yScale = selectorImageRect.width / selectorData['browser_width']; + } else { + xScale = selectorImageRect.width / selectorImage.naturalWidth; + yScale = selectorImageRect.height / selectorImage.naturalHeight; + } ctx.strokeStyle = STROKE_STYLE_HIGHLIGHT; ctx.fillStyle = FILL_STYLE_REDLINE; @@ -194,8 +219,57 @@ $(document).ready(() => { $("#selector-current-xpath").css('max-width', selectorImageRect.width); } + function bindElementHandlers() { + // Store handler references for later use + elementHandlers.handleMouseMove = handleMouseMove.debounce(5); + elementHandlers.handleMouseDown = handleMouseDown.debounce(5); + elementHandlers.handleMouseLeave = highlightCurrentSelected.debounce(5); + + $selectorCanvasElem.bind('mousemove', elementHandlers.handleMouseMove); + $selectorCanvasElem.bind('mousedown', elementHandlers.handleMouseDown); + $selectorCanvasElem.bind('mouseleave', elementHandlers.handleMouseLeave); + } + + function handleMouseMove(e) { + if (!e.offsetX && !e.offsetY) { + const targetOffset = $(e.target).offset(); + e.offsetX = e.pageX - targetOffset.left; + e.offsetY = e.pageY - targetOffset.top; + } + + ctx.fillStyle = FILL_STYLE_HIGHLIGHT; + + selectorData['size_pos'].forEach(sel => { + if (e.offsetY > sel.top * yScale && e.offsetY < sel.top * yScale + sel.height * yScale && + e.offsetX > sel.left * yScale && e.offsetX < sel.left * yScale + sel.width * yScale) { + setCurrentSelectedText(sel.xpath); + drawHighlight(sel); + currentSelections.push(sel); + currentSelection = sel; + highlightCurrentSelected(); + currentSelections.pop(); + } + }) + } + + function setCurrentSelectedText(s) { + $selectorCurrentXpathElem[0].innerHTML = s; + } + + function drawHighlight(sel) { + ctx.strokeRect(sel.left * xScale, sel.top * yScale, sel.width * xScale, sel.height * yScale); + ctx.fillRect(sel.left * xScale, sel.top * yScale, sel.width * xScale, sel.height * yScale); + } + + function handleMouseDown() { + // If we are in 'appendToList' mode, grow the list, if not, just 1 + currentSelections = appendToList ? [...currentSelections, currentSelection] : [currentSelection]; + highlightCurrentSelected(); + updateFiltersText(); + } + function reflowSelector() { - $(window).resize(() => { + $(window).off('resize.visualselector').on('resize.visualselector', () => { setScale(); highlightCurrentSelected(); }); @@ -217,57 +291,13 @@ $(document).ready(() => { highlightCurrentSelected(); updateFiltersText(); - // Store handler references for later use - elementHandlers.handleMouseMove = handleMouseMove.debounce(5); - elementHandlers.handleMouseDown = handleMouseDown.debounce(5); - elementHandlers.handleMouseLeave = highlightCurrentSelected.debounce(5); - - $selectorCanvasElem.bind('mousemove', elementHandlers.handleMouseMove); - $selectorCanvasElem.bind('mousedown', elementHandlers.handleMouseDown); - $selectorCanvasElem.bind('mouseleave', elementHandlers.handleMouseLeave); - - function handleMouseMove(e) { - if (!e.offsetX && !e.offsetY) { - const targetOffset = $(e.target).offset(); - e.offsetX = e.pageX - targetOffset.left; - e.offsetY = e.pageY - targetOffset.top; - } - - ctx.fillStyle = FILL_STYLE_HIGHLIGHT; - - selectorData['size_pos'].forEach(sel => { - if (e.offsetY > sel.top * yScale && e.offsetY < sel.top * yScale + sel.height * yScale && - e.offsetX > sel.left * yScale && e.offsetX < sel.left * yScale + sel.width * yScale) { - setCurrentSelectedText(sel.xpath); - drawHighlight(sel); - currentSelections.push(sel); - currentSelection = sel; - highlightCurrentSelected(); - currentSelections.pop(); - } - }) + if (selectionEnabled) { + bindElementHandlers(); } - - - function setCurrentSelectedText(s) { - $selectorCurrentXpathElem[0].innerHTML = s; - } - - function drawHighlight(sel) { - ctx.strokeRect(sel.left * xScale, sel.top * yScale, sel.width * xScale, sel.height * yScale); - ctx.fillRect(sel.left * xScale, sel.top * yScale, sel.width * xScale, sel.height * yScale); - } - - function handleMouseDown() { - // If we are in 'appendToList' mode, grow the list, if not, just 1 - currentSelections = appendToList ? [...currentSelections, currentSelection] : [currentSelection]; - highlightCurrentSelected(); - updateFiltersText(); - } - } function highlightCurrentSelected() { + if (!xctx) return; xctx.fillStyle = FILL_STYLE_GREYED_OUT; xctx.strokeStyle = STROKE_STYLE_REDLINE; xctx.lineWidth = 3; @@ -279,6 +309,29 @@ $(document).ready(() => { }); } + // Toggle hover/click element selection on the fly (Add Watch "by element" mode) + function setSelectionEnabled(enabled) { + selectionEnabled = enabled; + if (!c) return; // not loaded yet, will respect the flag in reflowSelector + + if (enabled) { + if (!drawMode) { + bindElementHandlers(); + if ($selectorCurrentXpathElem.length) { + $selectorCurrentXpathElem[0].innerHTML = 'Hover over elements to select'; + } + } + } else { + $selectorCanvasElem.unbind('mousemove mousedown mouseleave'); + currentSelections = []; + $includeFiltersElem.val(''); + highlightCurrentSelected(); + if ($selectorCurrentXpathElem.length) { + $selectorCurrentXpathElem[0].innerHTML = ''; + } + } + } + // ============= BOX DRAWING MODE (for image_ssim_diff processor) ============= function initializeDrawMode() { @@ -646,4 +699,53 @@ $(document).ready(() => { drawStartX = x; drawStartY = y; } -}); \ No newline at end of file + + // ---- public API ---- + return { + load: load, + clear: clearReset, + setSelectionEnabled: setSelectionEnabled, + markClearMode: function () { runInClearMode = true; } + }; +}; + + +// --------------------------------------------------------------------------- +// Auto-init for the watch Edit page (edit.html), preserving previous behaviour. +// Detected by the presence of the `screenshot_url` global that edit.html sets. +// --------------------------------------------------------------------------- +$(document).ready(() => { + if (typeof screenshot_url === 'undefined') { + return; // Not the edit page - the Add Watch UI inits the selector itself + } + + const isImageProcessor = $('input[value="image_ssim_diff"]').is(':checked'); + + const vs = window.initVisualSelector({ + $canvas: $('#selector-canvas'), + $includeFilters: $("#include_filters"), + $background: $("img#selector-background"), + $xpathDisplay: $("#selector-current-xpath span"), + $fetchingNotice: $('.fetching-update-notice'), + $wrapper: $("#selector-wrapper"), + $clearButton: $('#clear-selector'), + xpathDataUrl: watch_visual_selector_data_url, + enableSelection: true, + processorIsImage: isImageProcessor, + }); + + $('#visualselector-tab').click(() => { + vs.load({screenshotSrc: screenshot_url}); + }); + + // So if they start switching between visualSelector and manual filters, stop it from rendering old filters + $('li.tab a').on('click', () => { + vs.markClearMode(); + }); + + if (window.location.hash === '#visualselector') { + vs.load({screenshotSrc: screenshot_url}); + } else { + $("img#selector-background").attr('src', ''); + } +}); diff --git a/changedetectionio/static/styles/scss/parts/_add-watch.scss b/changedetectionio/static/styles/scss/parts/_add-watch.scss new file mode 100644 index 00000000..a41ffeb9 --- /dev/null +++ b/changedetectionio/static/styles/scss/parts/_add-watch.scss @@ -0,0 +1,179 @@ +/* Add Watch UI - 3-pane workspace (top: URL+Go, left: live visual selector, right: options) */ + +#add-watch-ui { + + /* TOP : URL input + Go */ + #add-watch-url-row { + display: flex; + gap: 0.5rem; + align-items: stretch; + margin-bottom: 1rem; + + // render_nolabel_field wraps the input in a <span> + > span { + flex: 1 1 auto; + min-width: 0; + + input { + width: 100%; + } + } + + #add-watch-go { + flex: 0 0 auto; + white-space: nowrap; + } + } + + /* PANES */ + #add-watch-panes { + display: flex; + gap: 1rem; + align-items: stretch; + + @media (max-width: 900px) { + flex-direction: column; + } + } + + /* LEFT : live visual-selector preview */ + #add-watch-selector-pane { + flex: 1 1 62%; + min-width: 0; + min-height: 380px; + position: relative; + overflow: auto; // the pane scrolls for tall snapshots, NOT the wrapper - keeps img+canvas aligned + border: 1px solid var(--color-background-tab); + border-radius: 6px; + background: rgba(0, 0, 0, 0.15); + padding: 0.75rem; + + // Transient states fill and centre over the whole pane (only one is visible at a time) + #add-watch-empty-state, + #add-watch-spinner, + #add-watch-error { + position: absolute; + inset: 0; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: 0.6rem; + text-align: center; + padding: 2rem 1rem; + } + + #add-watch-empty-state { + opacity: 0.8; + + svg { + opacity: 0.55; + } + + strong { + font-size: 1.05rem; + } + + span { + font-size: 0.85rem; + opacity: 0.8; + max-width: 32ch; + } + } + + #add-watch-spinner { + gap: 1.2rem; + + .spinner { + font-size: 5px; // scales the em-based spinner up a little + } + + .fetching-update-notice { + font-size: 0.85rem; + opacity: 0.85; + } + } + + #add-watch-error { + color: #ffb4b4; + font-size: 0.9rem; + word-break: break-word; + } + + // Pin the highlight canvas exactly over the screenshot. The shared selector CSS + // (parts/_visualselector.scss) positions the img absolutely + canvas in-flow inside + // an overflow-y:scroll wrapper, whose scrollbar gutter offsets the two in this + // narrower pane. Here the img drives the layout (in normal flow) and the canvas is + // overlaid on top, so they stay pixel-aligned regardless of scrollbars. + #selector-wrapper { + position: relative; + display: block; + width: 100%; + max-height: none; + overflow: visible; + text-align: left; + + > img { + position: relative; + display: block; + max-width: 100%; + height: auto; + z-index: 4; + } + + > canvas { + position: absolute; + top: 0; + left: 0; + max-width: none; + z-index: 5; + } + } + } + + /* RIGHT : options */ + #add-watch-options-pane { + flex: 0 0 34%; + min-width: 0; + display: flex; + flex-direction: column; + gap: 1.1rem; + + @media (max-width: 900px) { + flex: 1 1 auto; + } + + .add-watch-option-group { + label { + display: inline-block; + } + } + + #by-element-toggle-group { + .pure-form-message-inline { + display: block; + margin-top: 0.25rem; + font-size: 0.8rem; + opacity: 0.8; + } + + #clear-selector { + margin-top: 0.5rem; + } + } + + #quick-watch-llm-intent { + label { + display: block; + margin-bottom: 0.35rem; + } + } + + #add-watch-submit-row { + display: flex; + flex-wrap: wrap; + gap: 0.5rem; + margin-top: auto; // push the create buttons to the bottom of the pane + } + } +} diff --git a/changedetectionio/static/styles/scss/styles.scss b/changedetectionio/static/styles/scss/styles.scss index 567ff11d..5e6d0ea8 100644 --- a/changedetectionio/static/styles/scss/styles.scss +++ b/changedetectionio/static/styles/scss/styles.scss @@ -20,6 +20,7 @@ @use "parts/conditions_table"; @use "parts/socket"; @use "parts/visualselector"; +@use "parts/add-watch"; @use "parts/widgets"; @use "parts/diff_image"; @use "parts/modal"; @@ -210,12 +211,7 @@ body.spinner-active { } section.content { - @media only screen and (max-width: $desktop-wide-breakpoint) { - padding-top: 80px; - } - @media only screen and (min-width: $desktop-wide-breakpoint) { - padding-top: 100px; - } + padding-top: 80px; padding-bottom: 1em; flex-direction: column; @@ -1058,6 +1054,24 @@ ul { @extend .inline-tag; } +/* Price up/down indicator next to the restock price, e.g. "▼ -18%" */ +.price-change { + white-space: nowrap; + font-weight: 700; + font-size: 90%; + margin-left: 4px; + vertical-align: middle; + + /* Price dropped = good for a shopper = green; price rose = red */ + &.down { + color: var(--color-background-button-green); + } + + &.up { + color: var(--color-background-button-error); + } +} + #chrome-extension-link { img { height: 21px; diff --git a/changedetectionio/static/styles/styles.css b/changedetectionio/static/styles/styles.css index 42bb6e01..96117854 100644 --- a/changedetectionio/static/styles/styles.css +++ b/changedetectionio/static/styles/styles.css @@ -1 +1 @@ -ul#top-right-menu{list-style:none;margin:0;padding:0;display:grid;gap:.8rem;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 .8rem;-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}: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);--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-grey-350);--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-icon-github-hover: var(--color-grey-300);--color-watch-table-error: var(--color-dark-red);--color-watch-table-row-text: var(--color-grey-100);--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)}html[data-darkmode=true]{--color-link: #59bdfb;--color-text: var(--color-white);--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);--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-icon-github-hover: var(--color-grey-700);--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 img{opacity:.3}html[data-darkmode=true] .watch-table .watch-controls .state-on img{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 #1b98f8;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}a.github-link{color:var(--color-text-menu-heading);margin:0;padding:0;height:1.8rem;display:block}a.github-link svg{fill:currentColor;height:100%}a.github-link:hover{color:var(--color-icon-github-hover)}.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)}.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:.8rem;grid-auto-flow:column;grid-auto-columns:max-content;align-items:center}#overlay{opacity:.95;position:fixed;width:350px;max-width:100%;height:100%;top:0;right:-350px;background-color:var(--color-table-stripe);z-index:2;transform:translateX(0);transition:transform .5s ease}#overlay.visible{transform:translateX(-100%)}#overlay .content{font-size:.875rem;padding:1rem;margin-top:5rem;max-width:400px;color:var(--color-watch-table-row-text)}#heartpath{height:1.6rem;width:1.6rem;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)}#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 .right{opacity:.5;transition:opacity .6s ease;margin-left:auto;text-align:right}body.has-queue #stats_row .right{opacity:1}.watch-table{width:100%;font-size:var(--body-main-text-size)}.watch-table .checkbox-uuid{text-align:center}.watch-table .checkbox-uuid>*{vertical-align:middle}.watch-table td,.watch-table th{vertical-align:middle}.watch-table tr{color:var(--color-watch-table-row-text)}.watch-table tr.unviewed{font-weight:bold}.watch-table tr td.inline.title-col{width:100%}.watch-table 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:.8rem}.watch-table tr td.inline.title-col .grid-wrapper>.favicon{grid-column:1}.watch-table tr td.inline.title-col .grid-wrapper>.watch-text-info{grid-column:2}.watch-table tr td.inline.title-col .grid-wrapper>.status-icons{grid-column:3}.watch-table tr td.inline.title-col .grid-wrapper>.restock-info-wrap{grid-column:4}@media only screen and (max-width: 1200px){.watch-table tr td.inline.title-col .grid-wrapper>.restock-info-wrap{grid-column:1/-1;justify-self:center}}.watch-table tr .watch-text-info{line-height:1.5}.watch-table tr.checking-now td:first-child{position:relative}.watch-table tr.checking-now td:first-child::before{content:"";position:absolute;top:0;bottom:0;left:0;width:3px;background-color:#293eff}.watch-table tr.checking-now td.last-checked .spinner-wrapper{display:inline-block !important}.watch-table tr.checking-now td.last-checked .innertext{display:none !important}.watch-table tr.queued a.recheck{display:none !important}.watch-table tr.queued a.already-in-queue-button{display:inline-block !important}.watch-table tr.paused a.pause-toggle.state-on{display:inline !important}.watch-table tr.paused a.pause-toggle.state-off{display:none !important}.watch-table tr.notification_muted a.mute-toggle.state-on{display:inline !important}.watch-table tr.notification_muted a.mute-toggle.state-off{display:none !important}.watch-table tr.has-error .error-text{display:block !important;color:var(--color-watch-table-error)}.watch-table tr.single-history a.preview-link{display:inline-block !important}.watch-table tr.multiple-history a.history-link{display:inline-block !important}.watch-table tr.has-favicon.unviewed img.favicon{opacity:1 !important}.watch-table td.buttons{font-size:12px;white-space:nowrap}.watch-table td.title-col{word-break:break-all;white-space:normal}.watch-table td.last-changed,.watch-table td.last-checked{text-align:center}.watch-table td a.external::after{content:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAQElEQVR42qXKwQkAIAxDUUdxtO6/RBQkQZvSi8I/pL4BoGw/XPkh4XigPmsUgh0626AjRsgxHTkUThsG2T/sIlzdTsp52kSS1wAAAABJRU5ErkJggg==);margin:0 3px 0 5px}.watch-table td.watch-controls>div{display:flex;justify-content:space-between;align-items:center}.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}.watch-table img.favicon:hover{outline:2px solid color-mix(in srgb, var(--color-watch-table-row-text) 50%, transparent);outline-offset:1px;border-radius:4px}#watch-table-wrapper{display:inline-block;width:100%}#watch-table-wrapper #list-related-buttons{text-align:right;padding-top:1rem;margin-block-start:0;margin-block-end:0;padding-inline-start:0;margin:0}#watch-table-wrapper #list-related-buttons li{display:inline-block}#watch-table-wrapper #list-related-buttons a{border-top-left-radius:5px;border-top-right-radius:5px;border-bottom-left-radius:0;border-bottom-right-radius:0}#watch-table-wrapper.has-error #list-related-buttons #post-list-with-errors{display:inline-block !important}#watch-table-wrapper.has-unread-changes #list-related-buttons #post-list-unread,#watch-table-wrapper.has-unread-changes #list-related-buttons #post-list-mark-views,#watch-table-wrapper.has-unread-changes #list-related-buttons #post-list-unread{display:inline-block !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)}@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}}@media(min-width: 1600px){.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%}.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}}#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;width:190px;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;transition:width .08s ease-out}body.actionsidebar-minimal .action-sidebar-inner:hover,body.actionsidebar-minimal .action-sidebar-inner:focus-within{width:190px;transition:width .22s cubic-bezier(0.2, 0.7, 0.2, 1)}body.actionside-bar-on .action-sidebar-inner{width:190px;transition:none}.action-sidebar-list{list-style:none;padding-right:0;padding-left:.4rem;margin:0;display:flex;flex-direction:column;gap:0}.action-sidebar-li{list-style:none;margin:0;position:relative;color:var(--color-white)}.action-sidebar-li>:first-child{padding-left:.4rem}.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;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;width:100%;height:42px;font-size:var(--body-main-text-size);border-radius:8px;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:.6rem;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}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 .action-sidebar-list{gap:1px}.mobile-menu-section .action-sidebar-item{position:relative;display:flex;align-items:center;justify-content:flex-start;gap:.85rem;width:100%;height:auto;padding:.75rem .75rem;border-radius:8px;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}#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:.5rem;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-text);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: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.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;font-size:.85rem;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)}.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{font-size:.95rem;width:1.1rem;text-align:center;flex-shrink:0;opacity:.8}.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 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{font-size:1.1rem;width:1.6rem;flex-shrink:0;text-align:center;padding-top:.05rem;opacity:.7}.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{font-size:1.15rem;flex-shrink:0;padding-top:.05rem;color:#c07800}.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}.content-wrapper{display:flex;gap:1rem;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;padding-right:1rem}}.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}.pure-table-even{background:var(--color-background)}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:hover{color:var(--color-icon-github-hover)}button.toggle-button svg{fill:currentColor}button.toggle-button .icon-light{display:block}.pure-menu-horizontal{background:var(--color-background);padding-top:5px;padding-bottom:5px;display:flex;justify-content:space-between;align-items:center}#pure-menu-horizontal-spinner{height:3px;background:linear-gradient(-75deg, #ff6000, #ff8f00, #ffdd00, #ed0000);background-size:400% 400%;width:100%;animation:gradient 200s ease infinite}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%}}.pure-menu-heading{color:var(--color-text-menu-heading);padding-left:.8rem}.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;flex-direction:column;display:flex;align-items:center;justify-content:center}@media only screen and (max-width: 980px){section.content{padding-top:80px}}@media only screen and (min-width: 980px){section.content{padding-top:100px}}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}.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}label:hover{cursor:pointer}.grey-form-border{border:1px solid var(--color-border-notification);padding:.5rem;border-radius:5px}#notification-error-log{border:1px solid var(--color-border-notification);padding:1rem;border-radius:5px;overflow-wrap:break-word}#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;margin-bottom:1em;max-width:100%}#new-watch-form #url::placeholder{font-weight:bold}#new-watch-form input{display:inline-block;margin-bottom:5px}#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-table-striped tr:nth-child(2n-1) td{background-color:var(--color-table-stripe)}.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:20px}.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}#checkbox-operations{background:var(--color-background-checkbox-operations);padding:1em;border-radius:10px;margin-bottom:1em;display:none}#checkbox-operations button{margin-bottom:3px;margin-top:3px;display:inline-flex;align-items:center}.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:var(--color-background-button-green);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}#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}#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:10px;padding:1.25rem}header{color:var(--color-white)}#heart-us svg{width:24px;height:24px;display:inline-block;vertical-align:middle;cursor:pointer} +ul#top-right-menu{list-style:none;margin:0;padding:0;display:grid;gap:.8rem;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 .8rem;-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}: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);--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-grey-350);--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-icon-github-hover: var(--color-grey-300);--color-watch-table-error: var(--color-dark-red);--color-watch-table-row-text: var(--color-grey-100);--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)}html[data-darkmode=true]{--color-link: #59bdfb;--color-text: var(--color-white);--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);--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-icon-github-hover: var(--color-grey-700);--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 img{opacity:.3}html[data-darkmode=true] .watch-table .watch-controls .state-on img{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 #1b98f8;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}a.github-link{color:var(--color-text-menu-heading);margin:0;padding:0;height:1.8rem;display:block}a.github-link svg{fill:currentColor;height:100%}a.github-link:hover{color:var(--color-icon-github-hover)}.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)}.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:.8rem;grid-auto-flow:column;grid-auto-columns:max-content;align-items:center}#overlay{opacity:.95;position:fixed;width:350px;max-width:100%;height:100%;top:0;right:-350px;background-color:var(--color-table-stripe);z-index:2;transform:translateX(0);transition:transform .5s ease}#overlay.visible{transform:translateX(-100%)}#overlay .content{font-size:.875rem;padding:1rem;margin-top:5rem;max-width:400px;color:var(--color-watch-table-row-text)}#heartpath{height:1.6rem;width:1.6rem;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)}#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 .right{opacity:.5;transition:opacity .6s ease;margin-left:auto;text-align:right}body.has-queue #stats_row .right{opacity:1}.watch-table{width:100%;font-size:var(--body-main-text-size)}.watch-table .checkbox-uuid{text-align:center}.watch-table .checkbox-uuid>*{vertical-align:middle}.watch-table td,.watch-table th{vertical-align:middle}.watch-table tr{color:var(--color-watch-table-row-text)}.watch-table tr.unviewed{font-weight:bold}.watch-table tr td.inline.title-col{width:100%}.watch-table 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:.8rem}.watch-table tr td.inline.title-col .grid-wrapper>.favicon{grid-column:1}.watch-table tr td.inline.title-col .grid-wrapper>.watch-text-info{grid-column:2}.watch-table tr td.inline.title-col .grid-wrapper>.status-icons{grid-column:3}.watch-table tr td.inline.title-col .grid-wrapper>.restock-info-wrap{grid-column:4}@media only screen and (max-width: 1200px){.watch-table tr td.inline.title-col .grid-wrapper>.restock-info-wrap{grid-column:1/-1;justify-self:center}}.watch-table tr .watch-text-info{line-height:1.5}.watch-table tr.checking-now td:first-child{position:relative}.watch-table tr.checking-now td:first-child::before{content:"";position:absolute;top:0;bottom:0;left:0;width:3px;background-color:#293eff}.watch-table tr.checking-now td.last-checked .spinner-wrapper{display:inline-block !important}.watch-table tr.checking-now td.last-checked .innertext{display:none !important}.watch-table tr.queued a.recheck{display:none !important}.watch-table tr.queued a.already-in-queue-button{display:inline-block !important}.watch-table tr.paused a.pause-toggle.state-on{display:inline !important}.watch-table tr.paused a.pause-toggle.state-off{display:none !important}.watch-table tr.notification_muted a.mute-toggle.state-on{display:inline !important}.watch-table tr.notification_muted a.mute-toggle.state-off{display:none !important}.watch-table tr.has-error .error-text{display:block !important;color:var(--color-watch-table-error)}.watch-table tr.single-history a.preview-link{display:inline-block !important}.watch-table tr.multiple-history a.history-link{display:inline-block !important}.watch-table tr.has-favicon.unviewed img.favicon{opacity:1 !important}.watch-table td.buttons{font-size:12px;white-space:nowrap}.watch-table td.title-col{word-break:break-all;white-space:normal}.watch-table td.last-changed,.watch-table td.last-checked{text-align:center}.watch-table td a.external::after{content:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAQElEQVR42qXKwQkAIAxDUUdxtO6/RBQkQZvSi8I/pL4BoGw/XPkh4XigPmsUgh0626AjRsgxHTkUThsG2T/sIlzdTsp52kSS1wAAAABJRU5ErkJggg==);margin:0 3px 0 5px}.watch-table td.watch-controls>div{display:flex;justify-content:space-between;align-items:center}.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}.watch-table img.favicon:hover{outline:2px solid color-mix(in srgb, var(--color-watch-table-row-text) 50%, transparent);outline-offset:1px;border-radius:4px}#watch-table-wrapper{display:inline-block;width:100%}#watch-table-wrapper #list-related-buttons{text-align:right;padding-top:1rem;margin-block-start:0;margin-block-end:0;padding-inline-start:0;margin:0}#watch-table-wrapper #list-related-buttons li{display:inline-block}#watch-table-wrapper #list-related-buttons a{border-top-left-radius:5px;border-top-right-radius:5px;border-bottom-left-radius:0;border-bottom-right-radius:0}#watch-table-wrapper.has-error #list-related-buttons #post-list-with-errors{display:inline-block !important}#watch-table-wrapper.has-unread-changes #list-related-buttons #post-list-unread,#watch-table-wrapper.has-unread-changes #list-related-buttons #post-list-mark-views,#watch-table-wrapper.has-unread-changes #list-related-buttons #post-list-unread{display:inline-block !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)}@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}}@media(min-width: 1600px){.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%}#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:1rem;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;overflow:auto;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%;max-height:none;overflow:visible;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 #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;margin-top: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}}#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;width:190px;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;transition:width .08s ease-out}body.actionsidebar-minimal .action-sidebar-inner:hover,body.actionsidebar-minimal .action-sidebar-inner:focus-within{width:190px;transition:width .22s cubic-bezier(0.2, 0.7, 0.2, 1)}body.actionside-bar-on .action-sidebar-inner{width:190px;transition:none}.action-sidebar-list{list-style:none;padding-right:0;padding-left:.4rem;margin:0;display:flex;flex-direction:column;gap:0}.action-sidebar-li{list-style:none;margin:0;position:relative;color:var(--color-white)}.action-sidebar-li>:first-child{padding-left:.4rem}.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;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;width:100%;height:42px;font-size:var(--body-main-text-size);border-radius:8px;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:.6rem;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}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 .action-sidebar-list{gap:1px}.mobile-menu-section .action-sidebar-item{position:relative;display:flex;align-items:center;justify-content:flex-start;gap:.85rem;width:100%;height:auto;padding:.75rem .75rem;border-radius:8px;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}#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:.5rem;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-text);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: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.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;font-size:.85rem;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)}.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{font-size:.95rem;width:1.1rem;text-align:center;flex-shrink:0;opacity:.8}.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 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{font-size:1.1rem;width:1.6rem;flex-shrink:0;text-align:center;padding-top:.05rem;opacity:.7}.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{font-size:1.15rem;flex-shrink:0;padding-top:.05rem;color:#c07800}.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}.content-wrapper{display:flex;gap:1rem;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;padding-right:1rem}}.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}.pure-table-even{background:var(--color-background)}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:hover{color:var(--color-icon-github-hover)}button.toggle-button svg{fill:currentColor}button.toggle-button .icon-light{display:block}.pure-menu-horizontal{background:var(--color-background);padding-top:5px;padding-bottom:5px;display:flex;justify-content:space-between;align-items:center}#pure-menu-horizontal-spinner{height:3px;background:linear-gradient(-75deg, #ff6000, #ff8f00, #ffdd00, #ed0000);background-size:400% 400%;width:100%;animation:gradient 200s ease infinite}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%}}.pure-menu-heading{color:var(--color-text-menu-heading);padding-left:.8rem}.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-top:80px;padding-bottom:1em;flex-direction:column;display:flex;align-items:center;justify-content:center}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}.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}label:hover{cursor:pointer}.grey-form-border{border:1px solid var(--color-border-notification);padding:.5rem;border-radius:5px}#notification-error-log{border:1px solid var(--color-border-notification);padding:1rem;border-radius:5px;overflow-wrap:break-word}#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;margin-bottom:1em;max-width:100%}#new-watch-form #url::placeholder{font-weight:bold}#new-watch-form input{display:inline-block;margin-bottom:5px}#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-table-striped tr:nth-child(2n-1) td{background-color:var(--color-table-stripe)}.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:20px}.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}#checkbox-operations{background:var(--color-background-checkbox-operations);padding:1em;border-radius:10px;margin-bottom:1em;display:none}#checkbox-operations button{margin-bottom:3px;margin-top:3px;display:inline-flex;align-items:center}.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:var(--color-background-button-green);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}#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:10px;padding:1.25rem}header{color:var(--color-white)}#heart-us svg{width:24px;height:24px;display:inline-block;vertical-align:middle;cursor:pointer} diff --git a/changedetectionio/store/updates.py b/changedetectionio/store/updates.py index f81c4967..30d7f983 100644 --- a/changedetectionio/store/updates.py +++ b/changedetectionio/store/updates.py @@ -25,7 +25,7 @@ except ImportError: HAS_ORJSON = False from ..html_tools import TRANSLATE_WHITESPACE_TABLE -from ..processors.restock_diff import Restock +from ..processors.restock_diff import Restock, get_price_from_history_str from ..blueprint.rss import RSS_CONTENT_FORMAT_DEFAULT from ..model import USE_SYSTEM_DEFAULT_NOTIFICATION_FORMAT_FOR_WATCH @@ -825,3 +825,17 @@ class DatastoreUpdatesMixin: self.data['settings']['application']['llm'] = llm logger.info("update_32: cleaned up obsolete max_tokens_per_check / renamed max_tokens_cumulative") + def update_39(self): + for uuid, watch in self.data['watching'].items(): + if watch.get('processor') != 'restock_diff': + continue + versions = list(watch.history.keys()) + if versions and len(versions) >= 2: + snapshot = watch.get_history_snapshot(timestamp=versions[-2]) + if snapshot: + prev_price = get_price_from_history_str(history_str=snapshot) + logger.debug(f"UUID {watch['uuid']} setting prev_price to '{prev_price}'") + watch['restock']['prev_price'] = prev_price + watch.commit() + + diff --git a/changedetectionio/tests/restock/test_restock.py b/changedetectionio/tests/restock/test_restock.py index c62deb70..9bfcd852 100644 --- a/changedetectionio/tests/restock/test_restock.py +++ b/changedetectionio/tests/restock/test_restock.py @@ -49,6 +49,84 @@ def set_back_in_stock_response(datastore_path): f.write(test_return_data) return None +def set_price_response(datastore_path, price): + # JSON-LD product offer so the price + availability are extracted deterministically + # without needing a real browser (extruct parses the raw HTML). + test_return_data = """<html> + <head> + <script type="application/ld+json"> + {"@context": "https://schema.org/", "@type": "Product", "name": "Test Product", + "offers": {"@type": "Offer", "priceCurrency": "USD", "price": "%s", + "availability": "https://schema.org/InStock"}} + </script> + </head> + <body> + <div id="sametext">Available!</div> + </body> + </html> + """ % price + + with open(os.path.join(datastore_path, "endpoint-content.txt"), "w") as f: + f.write(test_return_data) + return None + + +def test_restock_price_change_direction(client, live_server, measure_memory_usage, datastore_path): + """The watch list shows a green ▼/-% on a price drop and a red ▲/+% on a price rise, + and prev_price only moves when the price actually changes (it persists otherwise).""" + + def get_restock(client): + datastore = client.application.config.get('DATASTORE') + uuid = next(iter(datastore.data['watching'])) + return datastore.data['watching'][uuid]['restock'] + + set_price_response(datastore_path=datastore_path, price="100.00") + + # JSON-LD restock data is parsed by extruct over the in-process html_requests fetcher, + # so we can hit the live server on localhost directly (no Docker browser container needed). + test_url = url_for('test_endpoint', _external=True) + client.post( + url_for("ui.ui_views.form_quick_watch_add"), + data={"url": test_url, "tags": '', 'processor': 'restock_diff', 'fetch_backend': 'html_requests'}, + follow_redirects=True + ) + wait_for_all_checks(client) + + # First check: there is no previous price yet, so no up/down indicator should render + res = client.get(url_for("watchlist.index")) + assert b'processor-restock_diff' in res.data + assert b'price-change' not in res.data, "No price arrow should show on the very first check" + assert get_restock(client).get('prev_price') is None, "prev_price should be unset on the first check" + + # Price drops 100.00 -> 82.00 => -18%, expect a green down arrow + set_price_response(datastore_path=datastore_path, price="82.00") + client.get(url_for("ui.form_watch_checknow"), follow_redirects=True) + wait_for_all_checks(client) + res = client.get(url_for("watchlist.index")) + assert b'price-change down' in res.data, "Price drop should show a down arrow" + assert '▼'.encode('utf-8') in res.data + assert b'-18%' in res.data, "Price drop percentage should be shown" + assert float(get_restock(client).get('prev_price')) == 100.0, "prev_price should capture the price we moved from" + + # Price rises 82.00 -> 90.00 => +9.8%, expect an up arrow + set_price_response(datastore_path=datastore_path, price="90.00") + client.get(url_for("ui.form_watch_checknow"), follow_redirects=True) + wait_for_all_checks(client) + res = client.get(url_for("watchlist.index")) + assert b'price-change up' in res.data, "Price rise should show an up arrow" + assert '▲'.encode('utf-8') in res.data + assert b'+9.8%' in res.data, "Price rise percentage should be shown" + assert float(get_restock(client).get('prev_price')) == 82.0, "prev_price should update to the new previous price on a change" + + # Re-check with NO price change - prev_price must NOT be clobbered, so the arrow persists. + client.get(url_for("ui.form_watch_checknow"), follow_redirects=True) + wait_for_all_checks(client) + res = client.get(url_for("watchlist.index")) + assert b'price-change up' in res.data, "Arrow should persist across an unchanged check" + assert b'+9.8%' in res.data, "Percentage should persist across an unchanged check" + assert float(get_restock(client).get('prev_price')) == 82.0, "prev_price must stay put when the price is unchanged" + + # Add a site in paused mode, add an invalid filter, we should still have visual selector data ready def test_restock_detection(client, live_server, measure_memory_usage, datastore_path): diff --git a/changedetectionio/translations/cs/LC_MESSAGES/messages.mo b/changedetectionio/translations/cs/LC_MESSAGES/messages.mo index 19d32f1a..feb83250 100644 Binary files a/changedetectionio/translations/cs/LC_MESSAGES/messages.mo and b/changedetectionio/translations/cs/LC_MESSAGES/messages.mo differ diff --git a/changedetectionio/translations/cs/LC_MESSAGES/messages.po b/changedetectionio/translations/cs/LC_MESSAGES/messages.po index 0c658357..29aacb1c 100644 --- a/changedetectionio/translations/cs/LC_MESSAGES/messages.po +++ b/changedetectionio/translations/cs/LC_MESSAGES/messages.po @@ -23,16 +23,46 @@ msgid "Add a new web page change detection watch" msgstr "Přidejte nové sledování zjišťování změn webové stránky" #: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html -msgid "Watch this URL!" -msgstr "Monitorovat tuto URL!" +#: changedetectionio/blueprint/ui/templates/preview.html +msgid "Go" +msgstr "Přejít" #: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html -msgid "Edit first then Watch" -msgstr "Nejdříve upravit, poté sledovat" +msgid "Enter a URL to get started!" +msgstr "" #: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html -#: changedetectionio/templates/edit/include_llm_intent.html -msgid "AI — Notify when…" +msgid "Enter a URL in the input box above to get started." +msgstr "" + +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html +msgid "Fetching screenshot and element information…" +msgstr "" + +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html changedetectionio/blueprint/ui/templates/edit.html +msgid "Currently:" +msgstr "V současné době:" + +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html changedetectionio/blueprint/ui/templates/edit.html +msgid "Select by element" +msgstr "Vyberte podle prvku" + +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html +msgid "Hover & click the preview to watch just one part of the page." +msgstr "" + +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html changedetectionio/blueprint/ui/templates/edit.html +msgid "Clear selection" +msgstr "Jasný výběr" + +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html +msgid "What matters — when to notify me" +msgstr "" + +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html +msgid "" +"e.g. Notify me when products go in/out of stock, lead times change by more than a week, or new product variants " +"appear. Skip review additions." msgstr "" #: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html @@ -40,17 +70,13 @@ msgstr "" msgid "Watch group / tag" msgstr "Sledovat skupinu / Značka" -#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html changedetectionio/templates/sidebar-nav.html -msgid "Live activity" -msgstr "" +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html +msgid "Watch this URL!" +msgstr "Monitorovat tuto URL!" #: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html -msgid "Recent additions and live check status will appear here." -msgstr "" - -#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html -msgid "Waiting for activity…" -msgstr "" +msgid "Edit first then Watch" +msgstr "Nejdříve upravit, poté sledovat" #: changedetectionio/blueprint/backups/__init__.py msgid "A backup is already running, check back in a few minutes" @@ -765,6 +791,10 @@ msgstr "" msgid "Number of items per page in the watch overview list, 0 to disable." msgstr "" +#: changedetectionio/blueprint/settings/templates/settings.html +msgid "How \"Last Checked\" and \"Last Changed\" times are shown in the watch overview list." +msgstr "" + #: changedetectionio/blueprint/settings/templates/settings.html msgid "Tip" msgstr "Tip" @@ -2051,26 +2081,14 @@ msgstr "pro výběr více položek." msgid "Selection Mode:" msgstr "Režim výběru:" -#: changedetectionio/blueprint/ui/templates/edit.html -msgid "Select by element" -msgstr "Vyberte podle prvku" - #: changedetectionio/blueprint/ui/templates/edit.html msgid "Draw area" msgstr "Kreslit oblast" -#: changedetectionio/blueprint/ui/templates/edit.html -msgid "Clear selection" -msgstr "Jasný výběr" - #: changedetectionio/blueprint/ui/templates/edit.html msgid "One moment, fetching screenshot and element information.." msgstr "Okamžik, načítání snímku obrazovky a informací o prvku." -#: changedetectionio/blueprint/ui/templates/edit.html -msgid "Currently:" -msgstr "V současné době:" - #: changedetectionio/blueprint/ui/templates/edit.html msgid "Sorry, this functionality only works with fetchers that support Javascript and screenshots (such as playwright etc)." msgstr "" @@ -2155,10 +2173,6 @@ msgstr "Duplikovat a upravit" msgid "Select timestamp" msgstr "Vybrat časové razítko" -#: changedetectionio/blueprint/ui/templates/preview.html -msgid "Go" -msgstr "Přejít" - #: changedetectionio/blueprint/ui/templates/preview.html msgid "Current erroring screenshot from most recent request" msgstr "Aktuální chybový snímek obrazovky z posledního požadavku" @@ -2452,6 +2466,11 @@ msgstr "Není skladem" msgid "Price" msgstr "Cena" +#: changedetectionio/blueprint/watchlist/templates/watch-overview.html +#, python-format +msgid "Price change since previous price (%(prev)s)" +msgstr "" + #: changedetectionio/blueprint/watchlist/templates/watch-overview.html msgid "No information" msgstr "Žádné informace" @@ -3186,6 +3205,18 @@ msgstr "Povolit favikony" msgid "Use page <title> in watch overview list" msgstr "Použijte stránku <title> v přehledu sledování" +#: changedetectionio/forms.py +msgid "Relative time format" +msgstr "" + +#: changedetectionio/forms.py +msgid "Long (1 minute ago)" +msgstr "" + +#: changedetectionio/forms.py +msgid "Short (1m ago)" +msgstr "" + #: changedetectionio/forms.py msgid "API access token security check enabled" msgstr "Kontrola zabezpečení přístupového tokenu API povolena" @@ -3346,6 +3377,132 @@ msgstr "RegEx k extrahování" msgid "Extract as CSV" msgstr "Extrahujte data" +#: changedetectionio/languages.py +msgid "just now" +msgstr "právě teď" + +#: changedetectionio/languages.py +msgid "right now" +msgstr "za chvíli" + +#: changedetectionio/languages.py +#, python-format +msgid "%ss ago" +msgstr "před %ss" + +#: changedetectionio/languages.py +#, python-format +msgid "in %ss" +msgstr "za %ss" + +#: changedetectionio/languages.py +msgid "1m ago" +msgstr "před 1m" + +#: changedetectionio/languages.py +msgid "in 1m" +msgstr "za 1m" + +#: changedetectionio/languages.py +#, python-format +msgid "%sm ago" +msgstr "před %sm" + +#: changedetectionio/languages.py +#, python-format +msgid "in %sm" +msgstr "za %sm" + +#: changedetectionio/languages.py +msgid "1h ago" +msgstr "před 1h" + +#: changedetectionio/languages.py +msgid "in 1h" +msgstr "za 1h" + +#: changedetectionio/languages.py +#, python-format +msgid "%sh ago" +msgstr "před %sh" + +#: changedetectionio/languages.py +#, python-format +msgid "in %sh" +msgstr "za %sh" + +#: changedetectionio/languages.py +msgid "1d ago" +msgstr "před 1d" + +#: changedetectionio/languages.py +msgid "in 1d" +msgstr "za 1d" + +#: changedetectionio/languages.py +#, python-format +msgid "%sd ago" +msgstr "před %sd" + +#: changedetectionio/languages.py +#, python-format +msgid "in %sd" +msgstr "za %sd" + +#: changedetectionio/languages.py +msgid "1w ago" +msgstr "před 1týd" + +#: changedetectionio/languages.py +msgid "in 1w" +msgstr "za 1týd" + +#: changedetectionio/languages.py +#, python-format +msgid "%sw ago" +msgstr "před %stýd" + +#: changedetectionio/languages.py +#, python-format +msgid "in %sw" +msgstr "za %stýd" + +#: changedetectionio/languages.py +msgid "1mo ago" +msgstr "před 1měs" + +#: changedetectionio/languages.py +msgid "in 1mo" +msgstr "za 1měs" + +#: changedetectionio/languages.py +#, python-format +msgid "%smo ago" +msgstr "před %směs" + +#: changedetectionio/languages.py +#, python-format +msgid "in %smo" +msgstr "za %směs" + +#: changedetectionio/languages.py +msgid "1yr ago" +msgstr "před 1r" + +#: changedetectionio/languages.py +msgid "in 1yr" +msgstr "za 1r" + +#: changedetectionio/languages.py +#, python-format +msgid "%syr ago" +msgstr "před %sr" + +#: changedetectionio/languages.py +#, python-format +msgid "in %syr" +msgstr "za %sr" + #: changedetectionio/processors/extract.py msgid "No matches found while scanning all of the watch history for that RegEx." msgstr "" @@ -3974,6 +4131,10 @@ msgstr "" msgid "AI" msgstr "AI" +#: changedetectionio/templates/edit/include_llm_intent.html +msgid "AI — Notify when…" +msgstr "" + #: changedetectionio/templates/edit/include_llm_intent.html msgid "" "Describe what you care about. The AI evaluates every detected change against this and only notifies you when it " @@ -4318,6 +4479,10 @@ msgstr "" msgid "In queue" msgstr "" +#: changedetectionio/templates/sidebar-nav.html +msgid "Live activity" +msgstr "" + #: changedetectionio/templates/sidebar-nav.html msgid "A new version is available" msgstr "Je dostupná nová verze" diff --git a/changedetectionio/translations/de/LC_MESSAGES/messages.mo b/changedetectionio/translations/de/LC_MESSAGES/messages.mo index a91d18de..c8aeb99a 100644 Binary files a/changedetectionio/translations/de/LC_MESSAGES/messages.mo and b/changedetectionio/translations/de/LC_MESSAGES/messages.mo differ diff --git a/changedetectionio/translations/de/LC_MESSAGES/messages.po b/changedetectionio/translations/de/LC_MESSAGES/messages.po index 204dee2b..b4be8aa3 100644 --- a/changedetectionio/translations/de/LC_MESSAGES/messages.po +++ b/changedetectionio/translations/de/LC_MESSAGES/messages.po @@ -23,16 +23,46 @@ msgid "Add a new web page change detection watch" msgstr "Fügen Sie eine neue Überwachung zur Erkennung von Webseitenänderungen hinzu" #: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html -msgid "Watch this URL!" -msgstr "Diese URL überwachen!" +#: changedetectionio/blueprint/ui/templates/preview.html +msgid "Go" +msgstr "Gehen" #: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html -msgid "Edit first then Watch" -msgstr "Bearbeiten > Überwachen" +msgid "Enter a URL to get started!" +msgstr "" #: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html -#: changedetectionio/templates/edit/include_llm_intent.html -msgid "AI — Notify when…" +msgid "Enter a URL in the input box above to get started." +msgstr "" + +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html +msgid "Fetching screenshot and element information…" +msgstr "" + +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html changedetectionio/blueprint/ui/templates/edit.html +msgid "Currently:" +msgstr "Momentan:" + +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html changedetectionio/blueprint/ui/templates/edit.html +msgid "Select by element" +msgstr "Nach Element auswählen" + +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html +msgid "Hover & click the preview to watch just one part of the page." +msgstr "" + +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html changedetectionio/blueprint/ui/templates/edit.html +msgid "Clear selection" +msgstr "Auswahl löschen" + +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html +msgid "What matters — when to notify me" +msgstr "" + +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html +msgid "" +"e.g. Notify me when products go in/out of stock, lead times change by more than a week, or new product variants " +"appear. Skip review additions." msgstr "" #: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html @@ -40,17 +70,13 @@ msgstr "" msgid "Watch group / tag" msgstr "Gruppe / Label" -#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html changedetectionio/templates/sidebar-nav.html -msgid "Live activity" -msgstr "" +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html +msgid "Watch this URL!" +msgstr "Diese URL überwachen!" #: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html -msgid "Recent additions and live check status will appear here." -msgstr "" - -#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html -msgid "Waiting for activity…" -msgstr "" +msgid "Edit first then Watch" +msgstr "Bearbeiten > Überwachen" #: changedetectionio/blueprint/backups/__init__.py msgid "A backup is already running, check back in a few minutes" @@ -781,6 +807,10 @@ msgstr "" msgid "Number of items per page in the watch overview list, 0 to disable." msgstr "" +#: changedetectionio/blueprint/settings/templates/settings.html +msgid "How \"Last Checked\" and \"Last Changed\" times are shown in the watch overview list." +msgstr "" + #: changedetectionio/blueprint/settings/templates/settings.html msgid "Tip" msgstr "Tipp" @@ -2096,26 +2126,14 @@ msgstr "um mehrere Elemente auszuwählen." msgid "Selection Mode:" msgstr "Auswahlmodus:" -#: changedetectionio/blueprint/ui/templates/edit.html -msgid "Select by element" -msgstr "Nach Element auswählen" - #: changedetectionio/blueprint/ui/templates/edit.html msgid "Draw area" msgstr "Bereich zeichnen" -#: changedetectionio/blueprint/ui/templates/edit.html -msgid "Clear selection" -msgstr "Auswahl löschen" - #: changedetectionio/blueprint/ui/templates/edit.html msgid "One moment, fetching screenshot and element information.." msgstr "Einen Moment, Screenshot und Elementinformationen abrufen." -#: changedetectionio/blueprint/ui/templates/edit.html -msgid "Currently:" -msgstr "Momentan:" - #: changedetectionio/blueprint/ui/templates/edit.html msgid "Sorry, this functionality only works with fetchers that support Javascript and screenshots (such as playwright etc)." msgstr "" @@ -2202,10 +2220,6 @@ msgstr "Klonen und bearbeiten" msgid "Select timestamp" msgstr "Zeitstempel auswählen" -#: changedetectionio/blueprint/ui/templates/preview.html -msgid "Go" -msgstr "Gehen" - #: changedetectionio/blueprint/ui/templates/preview.html msgid "Current erroring screenshot from most recent request" msgstr "Aktueller fehlerhafter Screenshot aus der letzten Anfrage" @@ -2503,6 +2517,11 @@ msgstr "Nicht auf Lager" msgid "Price" msgstr "Preis" +#: changedetectionio/blueprint/watchlist/templates/watch-overview.html +#, python-format +msgid "Price change since previous price (%(prev)s)" +msgstr "" + #: changedetectionio/blueprint/watchlist/templates/watch-overview.html msgid "No information" msgstr "Keine Informationen" @@ -3238,6 +3257,18 @@ msgstr "Favicons Aktiviert" msgid "Use page <title> in watch overview list" msgstr "Verwenden Sie die Seite <title> in der Übersichtsliste der Beobachtungen" +#: changedetectionio/forms.py +msgid "Relative time format" +msgstr "" + +#: changedetectionio/forms.py +msgid "Long (1 minute ago)" +msgstr "" + +#: changedetectionio/forms.py +msgid "Short (1m ago)" +msgstr "" + #: changedetectionio/forms.py msgid "API access token security check enabled" msgstr "Sicherheitsüberprüfung des API-Zugriffstokens aktiviert" @@ -3398,6 +3429,132 @@ msgstr "RegEx zum Extrahieren" msgid "Extract as CSV" msgstr "Als CSV exportieren" +#: changedetectionio/languages.py +msgid "just now" +msgstr "gerade eben" + +#: changedetectionio/languages.py +msgid "right now" +msgstr "gleich" + +#: changedetectionio/languages.py +#, python-format +msgid "%ss ago" +msgstr "vor %ss" + +#: changedetectionio/languages.py +#, python-format +msgid "in %ss" +msgstr "in %ss" + +#: changedetectionio/languages.py +msgid "1m ago" +msgstr "vor 1Min" + +#: changedetectionio/languages.py +msgid "in 1m" +msgstr "in 1Min" + +#: changedetectionio/languages.py +#, python-format +msgid "%sm ago" +msgstr "vor %sMin" + +#: changedetectionio/languages.py +#, python-format +msgid "in %sm" +msgstr "in %sMin" + +#: changedetectionio/languages.py +msgid "1h ago" +msgstr "vor 1Std" + +#: changedetectionio/languages.py +msgid "in 1h" +msgstr "in 1Std" + +#: changedetectionio/languages.py +#, python-format +msgid "%sh ago" +msgstr "vor %sStd" + +#: changedetectionio/languages.py +#, python-format +msgid "in %sh" +msgstr "in %sStd" + +#: changedetectionio/languages.py +msgid "1d ago" +msgstr "vor 1T" + +#: changedetectionio/languages.py +msgid "in 1d" +msgstr "in 1T" + +#: changedetectionio/languages.py +#, python-format +msgid "%sd ago" +msgstr "vor %sT" + +#: changedetectionio/languages.py +#, python-format +msgid "in %sd" +msgstr "in %sT" + +#: changedetectionio/languages.py +msgid "1w ago" +msgstr "vor 1Wo" + +#: changedetectionio/languages.py +msgid "in 1w" +msgstr "in 1Wo" + +#: changedetectionio/languages.py +#, python-format +msgid "%sw ago" +msgstr "vor %sWo" + +#: changedetectionio/languages.py +#, python-format +msgid "in %sw" +msgstr "in %sWo" + +#: changedetectionio/languages.py +msgid "1mo ago" +msgstr "vor 1Mon" + +#: changedetectionio/languages.py +msgid "in 1mo" +msgstr "in 1Mon" + +#: changedetectionio/languages.py +#, python-format +msgid "%smo ago" +msgstr "vor %sMon" + +#: changedetectionio/languages.py +#, python-format +msgid "in %smo" +msgstr "in %sMon" + +#: changedetectionio/languages.py +msgid "1yr ago" +msgstr "vor 1J" + +#: changedetectionio/languages.py +msgid "in 1yr" +msgstr "in 1J" + +#: changedetectionio/languages.py +#, python-format +msgid "%syr ago" +msgstr "vor %sJ" + +#: changedetectionio/languages.py +#, python-format +msgid "in %syr" +msgstr "in %sJ" + #: changedetectionio/processors/extract.py msgid "No matches found while scanning all of the watch history for that RegEx." msgstr "" @@ -4030,6 +4187,10 @@ msgstr "Suchbegriff eingeben..." msgid "AI" msgstr "" +#: changedetectionio/templates/edit/include_llm_intent.html +msgid "AI — Notify when…" +msgstr "" + #: changedetectionio/templates/edit/include_llm_intent.html msgid "" "Describe what you care about. The AI evaluates every detected change against this and only notifies you when it " @@ -4374,6 +4535,10 @@ msgstr "" msgid "In queue" msgstr "" +#: changedetectionio/templates/sidebar-nav.html +msgid "Live activity" +msgstr "" + #: changedetectionio/templates/sidebar-nav.html msgid "A new version is available" msgstr "" diff --git a/changedetectionio/translations/en_GB/LC_MESSAGES/messages.po b/changedetectionio/translations/en_GB/LC_MESSAGES/messages.po index 371b39cd..690f9a28 100644 --- a/changedetectionio/translations/en_GB/LC_MESSAGES/messages.po +++ b/changedetectionio/translations/en_GB/LC_MESSAGES/messages.po @@ -23,16 +23,46 @@ msgid "Add a new web page change detection watch" msgstr "" #: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html -msgid "Watch this URL!" +#: changedetectionio/blueprint/ui/templates/preview.html +msgid "Go" msgstr "" #: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html -msgid "Edit first then Watch" +msgid "Enter a URL to get started!" msgstr "" #: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html -#: changedetectionio/templates/edit/include_llm_intent.html -msgid "AI — Notify when…" +msgid "Enter a URL in the input box above to get started." +msgstr "" + +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html +msgid "Fetching screenshot and element information…" +msgstr "" + +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html changedetectionio/blueprint/ui/templates/edit.html +msgid "Currently:" +msgstr "" + +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html changedetectionio/blueprint/ui/templates/edit.html +msgid "Select by element" +msgstr "" + +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html +msgid "Hover & click the preview to watch just one part of the page." +msgstr "" + +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html changedetectionio/blueprint/ui/templates/edit.html +msgid "Clear selection" +msgstr "" + +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html +msgid "What matters — when to notify me" +msgstr "" + +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html +msgid "" +"e.g. Notify me when products go in/out of stock, lead times change by more than a week, or new product variants " +"appear. Skip review additions." msgstr "" #: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html @@ -40,16 +70,12 @@ msgstr "" msgid "Watch group / tag" msgstr "" -#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html changedetectionio/templates/sidebar-nav.html -msgid "Live activity" +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html +msgid "Watch this URL!" msgstr "" #: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html -msgid "Recent additions and live check status will appear here." -msgstr "" - -#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html -msgid "Waiting for activity…" +msgid "Edit first then Watch" msgstr "" #: changedetectionio/blueprint/backups/__init__.py @@ -763,6 +789,10 @@ msgstr "" msgid "Number of items per page in the watch overview list, 0 to disable." msgstr "" +#: changedetectionio/blueprint/settings/templates/settings.html +msgid "How \"Last Checked\" and \"Last Changed\" times are shown in the watch overview list." +msgstr "" + #: changedetectionio/blueprint/settings/templates/settings.html msgid "Tip" msgstr "" @@ -2047,26 +2077,14 @@ msgstr "" msgid "Selection Mode:" msgstr "" -#: changedetectionio/blueprint/ui/templates/edit.html -msgid "Select by element" -msgstr "" - #: changedetectionio/blueprint/ui/templates/edit.html msgid "Draw area" msgstr "" -#: changedetectionio/blueprint/ui/templates/edit.html -msgid "Clear selection" -msgstr "" - #: changedetectionio/blueprint/ui/templates/edit.html msgid "One moment, fetching screenshot and element information.." msgstr "" -#: changedetectionio/blueprint/ui/templates/edit.html -msgid "Currently:" -msgstr "" - #: changedetectionio/blueprint/ui/templates/edit.html msgid "Sorry, this functionality only works with fetchers that support Javascript and screenshots (such as playwright etc)." msgstr "" @@ -2151,10 +2169,6 @@ msgstr "" msgid "Select timestamp" msgstr "" -#: changedetectionio/blueprint/ui/templates/preview.html -msgid "Go" -msgstr "" - #: changedetectionio/blueprint/ui/templates/preview.html msgid "Current erroring screenshot from most recent request" msgstr "" @@ -2448,6 +2462,11 @@ msgstr "" msgid "Price" msgstr "" +#: changedetectionio/blueprint/watchlist/templates/watch-overview.html +#, python-format +msgid "Price change since previous price (%(prev)s)" +msgstr "" + #: changedetectionio/blueprint/watchlist/templates/watch-overview.html msgid "No information" msgstr "" @@ -3180,6 +3199,18 @@ msgstr "" msgid "Use page <title> in watch overview list" msgstr "" +#: changedetectionio/forms.py +msgid "Relative time format" +msgstr "" + +#: changedetectionio/forms.py +msgid "Long (1 minute ago)" +msgstr "" + +#: changedetectionio/forms.py +msgid "Short (1m ago)" +msgstr "" + #: changedetectionio/forms.py msgid "API access token security check enabled" msgstr "" @@ -3340,6 +3371,132 @@ msgstr "" msgid "Extract as CSV" msgstr "" +#: changedetectionio/languages.py +msgid "just now" +msgstr "" + +#: changedetectionio/languages.py +msgid "right now" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "%ss ago" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "in %ss" +msgstr "" + +#: changedetectionio/languages.py +msgid "1m ago" +msgstr "" + +#: changedetectionio/languages.py +msgid "in 1m" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "%sm ago" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "in %sm" +msgstr "" + +#: changedetectionio/languages.py +msgid "1h ago" +msgstr "" + +#: changedetectionio/languages.py +msgid "in 1h" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "%sh ago" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "in %sh" +msgstr "" + +#: changedetectionio/languages.py +msgid "1d ago" +msgstr "" + +#: changedetectionio/languages.py +msgid "in 1d" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "%sd ago" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "in %sd" +msgstr "" + +#: changedetectionio/languages.py +msgid "1w ago" +msgstr "" + +#: changedetectionio/languages.py +msgid "in 1w" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "%sw ago" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "in %sw" +msgstr "" + +#: changedetectionio/languages.py +msgid "1mo ago" +msgstr "" + +#: changedetectionio/languages.py +msgid "in 1mo" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "%smo ago" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "in %smo" +msgstr "" + +#: changedetectionio/languages.py +msgid "1yr ago" +msgstr "" + +#: changedetectionio/languages.py +msgid "in 1yr" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "%syr ago" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "in %syr" +msgstr "" + #: changedetectionio/processors/extract.py msgid "No matches found while scanning all of the watch history for that RegEx." msgstr "" @@ -3968,6 +4125,10 @@ msgstr "" msgid "AI" msgstr "" +#: changedetectionio/templates/edit/include_llm_intent.html +msgid "AI — Notify when…" +msgstr "" + #: changedetectionio/templates/edit/include_llm_intent.html msgid "" "Describe what you care about. The AI evaluates every detected change against this and only notifies you when it " @@ -4312,6 +4473,10 @@ msgstr "" msgid "In queue" msgstr "" +#: changedetectionio/templates/sidebar-nav.html +msgid "Live activity" +msgstr "" + #: changedetectionio/templates/sidebar-nav.html msgid "A new version is available" msgstr "" diff --git a/changedetectionio/translations/en_US/LC_MESSAGES/messages.po b/changedetectionio/translations/en_US/LC_MESSAGES/messages.po index edb518e7..f2f98bff 100644 --- a/changedetectionio/translations/en_US/LC_MESSAGES/messages.po +++ b/changedetectionio/translations/en_US/LC_MESSAGES/messages.po @@ -23,16 +23,46 @@ msgid "Add a new web page change detection watch" msgstr "" #: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html -msgid "Watch this URL!" +#: changedetectionio/blueprint/ui/templates/preview.html +msgid "Go" msgstr "" #: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html -msgid "Edit first then Watch" +msgid "Enter a URL to get started!" msgstr "" #: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html -#: changedetectionio/templates/edit/include_llm_intent.html -msgid "AI — Notify when…" +msgid "Enter a URL in the input box above to get started." +msgstr "" + +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html +msgid "Fetching screenshot and element information…" +msgstr "" + +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html changedetectionio/blueprint/ui/templates/edit.html +msgid "Currently:" +msgstr "" + +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html changedetectionio/blueprint/ui/templates/edit.html +msgid "Select by element" +msgstr "" + +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html +msgid "Hover & click the preview to watch just one part of the page." +msgstr "" + +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html changedetectionio/blueprint/ui/templates/edit.html +msgid "Clear selection" +msgstr "" + +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html +msgid "What matters — when to notify me" +msgstr "" + +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html +msgid "" +"e.g. Notify me when products go in/out of stock, lead times change by more than a week, or new product variants " +"appear. Skip review additions." msgstr "" #: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html @@ -40,16 +70,12 @@ msgstr "" msgid "Watch group / tag" msgstr "" -#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html changedetectionio/templates/sidebar-nav.html -msgid "Live activity" +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html +msgid "Watch this URL!" msgstr "" #: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html -msgid "Recent additions and live check status will appear here." -msgstr "" - -#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html -msgid "Waiting for activity…" +msgid "Edit first then Watch" msgstr "" #: changedetectionio/blueprint/backups/__init__.py @@ -763,6 +789,10 @@ msgstr "" msgid "Number of items per page in the watch overview list, 0 to disable." msgstr "" +#: changedetectionio/blueprint/settings/templates/settings.html +msgid "How \"Last Checked\" and \"Last Changed\" times are shown in the watch overview list." +msgstr "" + #: changedetectionio/blueprint/settings/templates/settings.html msgid "Tip" msgstr "" @@ -2047,26 +2077,14 @@ msgstr "" msgid "Selection Mode:" msgstr "" -#: changedetectionio/blueprint/ui/templates/edit.html -msgid "Select by element" -msgstr "" - #: changedetectionio/blueprint/ui/templates/edit.html msgid "Draw area" msgstr "" -#: changedetectionio/blueprint/ui/templates/edit.html -msgid "Clear selection" -msgstr "" - #: changedetectionio/blueprint/ui/templates/edit.html msgid "One moment, fetching screenshot and element information.." msgstr "" -#: changedetectionio/blueprint/ui/templates/edit.html -msgid "Currently:" -msgstr "" - #: changedetectionio/blueprint/ui/templates/edit.html msgid "Sorry, this functionality only works with fetchers that support Javascript and screenshots (such as playwright etc)." msgstr "" @@ -2151,10 +2169,6 @@ msgstr "" msgid "Select timestamp" msgstr "" -#: changedetectionio/blueprint/ui/templates/preview.html -msgid "Go" -msgstr "" - #: changedetectionio/blueprint/ui/templates/preview.html msgid "Current erroring screenshot from most recent request" msgstr "" @@ -2448,6 +2462,11 @@ msgstr "" msgid "Price" msgstr "" +#: changedetectionio/blueprint/watchlist/templates/watch-overview.html +#, python-format +msgid "Price change since previous price (%(prev)s)" +msgstr "" + #: changedetectionio/blueprint/watchlist/templates/watch-overview.html msgid "No information" msgstr "" @@ -3180,6 +3199,18 @@ msgstr "" msgid "Use page <title> in watch overview list" msgstr "" +#: changedetectionio/forms.py +msgid "Relative time format" +msgstr "" + +#: changedetectionio/forms.py +msgid "Long (1 minute ago)" +msgstr "" + +#: changedetectionio/forms.py +msgid "Short (1m ago)" +msgstr "" + #: changedetectionio/forms.py msgid "API access token security check enabled" msgstr "" @@ -3340,6 +3371,132 @@ msgstr "" msgid "Extract as CSV" msgstr "" +#: changedetectionio/languages.py +msgid "just now" +msgstr "" + +#: changedetectionio/languages.py +msgid "right now" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "%ss ago" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "in %ss" +msgstr "" + +#: changedetectionio/languages.py +msgid "1m ago" +msgstr "" + +#: changedetectionio/languages.py +msgid "in 1m" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "%sm ago" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "in %sm" +msgstr "" + +#: changedetectionio/languages.py +msgid "1h ago" +msgstr "" + +#: changedetectionio/languages.py +msgid "in 1h" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "%sh ago" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "in %sh" +msgstr "" + +#: changedetectionio/languages.py +msgid "1d ago" +msgstr "" + +#: changedetectionio/languages.py +msgid "in 1d" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "%sd ago" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "in %sd" +msgstr "" + +#: changedetectionio/languages.py +msgid "1w ago" +msgstr "" + +#: changedetectionio/languages.py +msgid "in 1w" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "%sw ago" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "in %sw" +msgstr "" + +#: changedetectionio/languages.py +msgid "1mo ago" +msgstr "" + +#: changedetectionio/languages.py +msgid "in 1mo" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "%smo ago" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "in %smo" +msgstr "" + +#: changedetectionio/languages.py +msgid "1yr ago" +msgstr "" + +#: changedetectionio/languages.py +msgid "in 1yr" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "%syr ago" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "in %syr" +msgstr "" + #: changedetectionio/processors/extract.py msgid "No matches found while scanning all of the watch history for that RegEx." msgstr "" @@ -3968,6 +4125,10 @@ msgstr "" msgid "AI" msgstr "" +#: changedetectionio/templates/edit/include_llm_intent.html +msgid "AI — Notify when…" +msgstr "" + #: changedetectionio/templates/edit/include_llm_intent.html msgid "" "Describe what you care about. The AI evaluates every detected change against this and only notifies you when it " @@ -4312,6 +4473,10 @@ msgstr "" msgid "In queue" msgstr "" +#: changedetectionio/templates/sidebar-nav.html +msgid "Live activity" +msgstr "" + #: changedetectionio/templates/sidebar-nav.html msgid "A new version is available" msgstr "" diff --git a/changedetectionio/translations/es/LC_MESSAGES/messages.po b/changedetectionio/translations/es/LC_MESSAGES/messages.po index d7f7d9af..4c12174f 100644 --- a/changedetectionio/translations/es/LC_MESSAGES/messages.po +++ b/changedetectionio/translations/es/LC_MESSAGES/messages.po @@ -19,16 +19,46 @@ msgid "Add a new web page change detection watch" msgstr "Agregar un nuevo monitor de detección de cambios en páginas web" #: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html -msgid "Watch this URL!" -msgstr "¡Monitoriza esta URL!" +#: changedetectionio/blueprint/ui/templates/preview.html +msgid "Go" +msgstr "Ir" #: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html -msgid "Edit first then Watch" -msgstr "Editar primero y luego monitorizar" +msgid "Enter a URL to get started!" +msgstr "" #: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html -#: changedetectionio/templates/edit/include_llm_intent.html -msgid "AI — Notify when…" +msgid "Enter a URL in the input box above to get started." +msgstr "" + +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html +msgid "Fetching screenshot and element information…" +msgstr "" + +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html changedetectionio/blueprint/ui/templates/edit.html +msgid "Currently:" +msgstr "Actualmente:" + +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html changedetectionio/blueprint/ui/templates/edit.html +msgid "Select by element" +msgstr "Seleccionar por elemento" + +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html +msgid "Hover & click the preview to watch just one part of the page." +msgstr "" + +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html changedetectionio/blueprint/ui/templates/edit.html +msgid "Clear selection" +msgstr "Borrar selección" + +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html +msgid "What matters — when to notify me" +msgstr "" + +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html +msgid "" +"e.g. Notify me when products go in/out of stock, lead times change by more than a week, or new product variants " +"appear. Skip review additions." msgstr "" #: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html @@ -36,17 +66,13 @@ msgstr "" msgid "Watch group / tag" msgstr "Ver grupo/etiqueta" -#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html changedetectionio/templates/sidebar-nav.html -msgid "Live activity" -msgstr "" +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html +msgid "Watch this URL!" +msgstr "¡Monitoriza esta URL!" #: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html -msgid "Recent additions and live check status will appear here." -msgstr "" - -#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html -msgid "Waiting for activity…" -msgstr "" +msgid "Edit first then Watch" +msgstr "Editar primero y luego monitorizar" #: changedetectionio/blueprint/backups/__init__.py msgid "A backup is already running, check back in a few minutes" @@ -799,6 +825,10 @@ msgstr "Habilitar o deshabilitar favicons junto a la lista de monitores" msgid "Number of items per page in the watch overview list, 0 to disable." msgstr "Número de elementos por página en la lista general de monitores, 0 para desactivar." +#: changedetectionio/blueprint/settings/templates/settings.html +msgid "How \"Last Checked\" and \"Last Changed\" times are shown in the watch overview list." +msgstr "" + #: changedetectionio/blueprint/settings/templates/settings.html msgid "Tip" msgstr "Consejo" @@ -2110,26 +2140,14 @@ msgstr "para seleccionar varios elementos." msgid "Selection Mode:" msgstr "Modo de selección:" -#: changedetectionio/blueprint/ui/templates/edit.html -msgid "Select by element" -msgstr "Seleccionar por elemento" - #: changedetectionio/blueprint/ui/templates/edit.html msgid "Draw area" msgstr "Área de dibujo" -#: changedetectionio/blueprint/ui/templates/edit.html -msgid "Clear selection" -msgstr "Borrar selección" - #: changedetectionio/blueprint/ui/templates/edit.html msgid "One moment, fetching screenshot and element information.." msgstr "Un momento, obteniendo captura de pantalla e información del elemento." -#: changedetectionio/blueprint/ui/templates/edit.html -msgid "Currently:" -msgstr "Actualmente:" - #: changedetectionio/blueprint/ui/templates/edit.html msgid "Sorry, this functionality only works with fetchers that support Javascript and screenshots (such as playwright etc)." msgstr "" @@ -2216,10 +2234,6 @@ msgstr "Clonar y editar" msgid "Select timestamp" msgstr "Seleccionar marca de tiempo" -#: changedetectionio/blueprint/ui/templates/preview.html -msgid "Go" -msgstr "Ir" - #: changedetectionio/blueprint/ui/templates/preview.html msgid "Current erroring screenshot from most recent request" msgstr "Captura de pantalla con error actual de la solicitud más reciente" @@ -2519,6 +2533,11 @@ msgstr "No en stock" msgid "Price" msgstr "Precio" +#: changedetectionio/blueprint/watchlist/templates/watch-overview.html +#, python-format +msgid "Price change since previous price (%(prev)s)" +msgstr "" + #: changedetectionio/blueprint/watchlist/templates/watch-overview.html msgid "No information" msgstr "Sin información" @@ -3253,6 +3272,18 @@ msgstr "Favicones habilitados" msgid "Use page <title> in watch overview list" msgstr "Usar <title> de la página en la lista general de monitores" +#: changedetectionio/forms.py +msgid "Relative time format" +msgstr "" + +#: changedetectionio/forms.py +msgid "Long (1 minute ago)" +msgstr "" + +#: changedetectionio/forms.py +msgid "Short (1m ago)" +msgstr "" + #: changedetectionio/forms.py msgid "API access token security check enabled" msgstr "Comprobación de seguridad del token de acceso API habilitada" @@ -3413,6 +3444,132 @@ msgstr "RegEx para extraer" msgid "Extract as CSV" msgstr "Extraer como CSV" +#: changedetectionio/languages.py +msgid "just now" +msgstr "" + +#: changedetectionio/languages.py +msgid "right now" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "%ss ago" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "in %ss" +msgstr "" + +#: changedetectionio/languages.py +msgid "1m ago" +msgstr "" + +#: changedetectionio/languages.py +msgid "in 1m" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "%sm ago" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "in %sm" +msgstr "" + +#: changedetectionio/languages.py +msgid "1h ago" +msgstr "" + +#: changedetectionio/languages.py +msgid "in 1h" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "%sh ago" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "in %sh" +msgstr "" + +#: changedetectionio/languages.py +msgid "1d ago" +msgstr "" + +#: changedetectionio/languages.py +msgid "in 1d" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "%sd ago" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "in %sd" +msgstr "" + +#: changedetectionio/languages.py +msgid "1w ago" +msgstr "" + +#: changedetectionio/languages.py +msgid "in 1w" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "%sw ago" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "in %sw" +msgstr "" + +#: changedetectionio/languages.py +msgid "1mo ago" +msgstr "" + +#: changedetectionio/languages.py +msgid "in 1mo" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "%smo ago" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "in %smo" +msgstr "" + +#: changedetectionio/languages.py +msgid "1yr ago" +msgstr "" + +#: changedetectionio/languages.py +msgid "in 1yr" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "%syr ago" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "in %syr" +msgstr "" + #: changedetectionio/processors/extract.py msgid "No matches found while scanning all of the watch history for that RegEx." msgstr "No se encontraron coincidencias al escanear todo el historial de visualización para esa expresión regular." @@ -4045,6 +4202,10 @@ msgstr "Introduzca el término de búsqueda..." msgid "AI" msgstr "" +#: changedetectionio/templates/edit/include_llm_intent.html +msgid "AI — Notify when…" +msgstr "" + #: changedetectionio/templates/edit/include_llm_intent.html msgid "" "Describe what you care about. The AI evaluates every detected change against this and only notifies you when it " @@ -4398,6 +4559,10 @@ msgstr "" msgid "In queue" msgstr "" +#: changedetectionio/templates/sidebar-nav.html +msgid "Live activity" +msgstr "" + #: changedetectionio/templates/sidebar-nav.html msgid "A new version is available" msgstr "" diff --git a/changedetectionio/translations/fr/LC_MESSAGES/messages.mo b/changedetectionio/translations/fr/LC_MESSAGES/messages.mo index 0203b547..52903d33 100644 Binary files a/changedetectionio/translations/fr/LC_MESSAGES/messages.mo and b/changedetectionio/translations/fr/LC_MESSAGES/messages.mo differ diff --git a/changedetectionio/translations/fr/LC_MESSAGES/messages.po b/changedetectionio/translations/fr/LC_MESSAGES/messages.po index 7c78b159..84e45e90 100644 --- a/changedetectionio/translations/fr/LC_MESSAGES/messages.po +++ b/changedetectionio/translations/fr/LC_MESSAGES/messages.po @@ -23,16 +23,46 @@ msgid "Add a new web page change detection watch" msgstr "Ajouter une nouvelle surveillance de détection de changement de page Web" #: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html -msgid "Watch this URL!" -msgstr "Surveillez cette URL !" +#: changedetectionio/blueprint/ui/templates/preview.html +msgid "Go" +msgstr "Aller" #: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html -msgid "Edit first then Watch" -msgstr "Modifier > Surveiller" +msgid "Enter a URL to get started!" +msgstr "" #: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html -#: changedetectionio/templates/edit/include_llm_intent.html -msgid "AI — Notify when…" +msgid "Enter a URL in the input box above to get started." +msgstr "" + +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html +msgid "Fetching screenshot and element information…" +msgstr "" + +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html changedetectionio/blueprint/ui/templates/edit.html +msgid "Currently:" +msgstr "Actuellement:" + +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html changedetectionio/blueprint/ui/templates/edit.html +msgid "Select by element" +msgstr "Sélectionner par élément" + +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html +msgid "Hover & click the preview to watch just one part of the page." +msgstr "" + +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html changedetectionio/blueprint/ui/templates/edit.html +msgid "Clear selection" +msgstr "Effacer la sélection" + +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html +msgid "What matters — when to notify me" +msgstr "" + +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html +msgid "" +"e.g. Notify me when products go in/out of stock, lead times change by more than a week, or new product variants " +"appear. Skip review additions." msgstr "" #: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html @@ -40,17 +70,13 @@ msgstr "" msgid "Watch group / tag" msgstr "Groupe / Étiquette" -#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html changedetectionio/templates/sidebar-nav.html -msgid "Live activity" -msgstr "" +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html +msgid "Watch this URL!" +msgstr "Surveillez cette URL !" #: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html -msgid "Recent additions and live check status will appear here." -msgstr "" - -#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html -msgid "Waiting for activity…" -msgstr "" +msgid "Edit first then Watch" +msgstr "Modifier > Surveiller" #: changedetectionio/blueprint/backups/__init__.py msgid "A backup is already running, check back in a few minutes" @@ -769,6 +795,10 @@ msgstr "" msgid "Number of items per page in the watch overview list, 0 to disable." msgstr "" +#: changedetectionio/blueprint/settings/templates/settings.html +msgid "How \"Last Checked\" and \"Last Changed\" times are shown in the watch overview list." +msgstr "" + #: changedetectionio/blueprint/settings/templates/settings.html msgid "Tip" msgstr "Astuce" @@ -2058,26 +2088,14 @@ msgstr "pour sélectionner plusieurs éléments." msgid "Selection Mode:" msgstr "Mode de sélection :" -#: changedetectionio/blueprint/ui/templates/edit.html -msgid "Select by element" -msgstr "Sélectionner par élément" - #: changedetectionio/blueprint/ui/templates/edit.html msgid "Draw area" msgstr "Zone de dessin" -#: changedetectionio/blueprint/ui/templates/edit.html -msgid "Clear selection" -msgstr "Effacer la sélection" - #: changedetectionio/blueprint/ui/templates/edit.html msgid "One moment, fetching screenshot and element information.." msgstr "Un instant, récupération de la capture d'écran et des informations sur les éléments." -#: changedetectionio/blueprint/ui/templates/edit.html -msgid "Currently:" -msgstr "Actuellement:" - #: changedetectionio/blueprint/ui/templates/edit.html msgid "Sorry, this functionality only works with fetchers that support Javascript and screenshots (such as playwright etc)." msgstr "" @@ -2162,10 +2180,6 @@ msgstr "Cloner et modifier" msgid "Select timestamp" msgstr "Sélectionnez l'horodatage" -#: changedetectionio/blueprint/ui/templates/preview.html -msgid "Go" -msgstr "Aller" - #: changedetectionio/blueprint/ui/templates/preview.html msgid "Current erroring screenshot from most recent request" msgstr "Capture d'écran erronée actuelle de la demande la plus récente" @@ -2459,6 +2473,11 @@ msgstr "Pas en stock" msgid "Price" msgstr "Prix" +#: changedetectionio/blueprint/watchlist/templates/watch-overview.html +#, python-format +msgid "Price change since previous price (%(prev)s)" +msgstr "" + #: changedetectionio/blueprint/watchlist/templates/watch-overview.html msgid "No information" msgstr "Aucune information" @@ -3193,6 +3212,18 @@ msgstr "Favicons Activés" msgid "Use page <title> in watch overview list" msgstr "Utiliser la page <title> dans la liste de présentation des moniteurs" +#: changedetectionio/forms.py +msgid "Relative time format" +msgstr "" + +#: changedetectionio/forms.py +msgid "Long (1 minute ago)" +msgstr "" + +#: changedetectionio/forms.py +msgid "Short (1m ago)" +msgstr "" + #: changedetectionio/forms.py msgid "API access token security check enabled" msgstr "Contrôle de sécurité du jeton d'accès à l'API activé" @@ -3353,6 +3384,132 @@ msgstr "RegEx à extraire" msgid "Extract as CSV" msgstr "Extraire des données" +#: changedetectionio/languages.py +msgid "just now" +msgstr "à l'instant" + +#: changedetectionio/languages.py +msgid "right now" +msgstr "bientôt" + +#: changedetectionio/languages.py +#, python-format +msgid "%ss ago" +msgstr "il y a %ss" + +#: changedetectionio/languages.py +#, python-format +msgid "in %ss" +msgstr "dans %ss" + +#: changedetectionio/languages.py +msgid "1m ago" +msgstr "il y a 1min" + +#: changedetectionio/languages.py +msgid "in 1m" +msgstr "dans 1min" + +#: changedetectionio/languages.py +#, python-format +msgid "%sm ago" +msgstr "il y a %smin" + +#: changedetectionio/languages.py +#, python-format +msgid "in %sm" +msgstr "dans %smin" + +#: changedetectionio/languages.py +msgid "1h ago" +msgstr "il y a 1h" + +#: changedetectionio/languages.py +msgid "in 1h" +msgstr "dans 1h" + +#: changedetectionio/languages.py +#, python-format +msgid "%sh ago" +msgstr "il y a %sh" + +#: changedetectionio/languages.py +#, python-format +msgid "in %sh" +msgstr "dans %sh" + +#: changedetectionio/languages.py +msgid "1d ago" +msgstr "il y a 1j" + +#: changedetectionio/languages.py +msgid "in 1d" +msgstr "dans 1j" + +#: changedetectionio/languages.py +#, python-format +msgid "%sd ago" +msgstr "il y a %sj" + +#: changedetectionio/languages.py +#, python-format +msgid "in %sd" +msgstr "dans %sj" + +#: changedetectionio/languages.py +msgid "1w ago" +msgstr "il y a 1sem" + +#: changedetectionio/languages.py +msgid "in 1w" +msgstr "dans 1sem" + +#: changedetectionio/languages.py +#, python-format +msgid "%sw ago" +msgstr "il y a %ssem" + +#: changedetectionio/languages.py +#, python-format +msgid "in %sw" +msgstr "dans %ssem" + +#: changedetectionio/languages.py +msgid "1mo ago" +msgstr "il y a 1mois" + +#: changedetectionio/languages.py +msgid "in 1mo" +msgstr "dans 1mois" + +#: changedetectionio/languages.py +#, python-format +msgid "%smo ago" +msgstr "il y a %smois" + +#: changedetectionio/languages.py +#, python-format +msgid "in %smo" +msgstr "dans %smois" + +#: changedetectionio/languages.py +msgid "1yr ago" +msgstr "il y a 1an" + +#: changedetectionio/languages.py +msgid "in 1yr" +msgstr "dans 1an" + +#: changedetectionio/languages.py +#, python-format +msgid "%syr ago" +msgstr "il y a %sans" + +#: changedetectionio/languages.py +#, python-format +msgid "in %syr" +msgstr "dans %sans" + #: changedetectionio/processors/extract.py msgid "No matches found while scanning all of the watch history for that RegEx." msgstr "" @@ -3983,6 +4140,10 @@ msgstr "" msgid "AI" msgstr "" +#: changedetectionio/templates/edit/include_llm_intent.html +msgid "AI — Notify when…" +msgstr "" + #: changedetectionio/templates/edit/include_llm_intent.html msgid "" "Describe what you care about. The AI evaluates every detected change against this and only notifies you when it " @@ -4327,6 +4488,10 @@ msgstr "" msgid "In queue" msgstr "" +#: changedetectionio/templates/sidebar-nav.html +msgid "Live activity" +msgstr "" + #: changedetectionio/templates/sidebar-nav.html msgid "A new version is available" msgstr "" diff --git a/changedetectionio/translations/it/LC_MESSAGES/messages.mo b/changedetectionio/translations/it/LC_MESSAGES/messages.mo index 6cfac14a..9c45d920 100644 Binary files a/changedetectionio/translations/it/LC_MESSAGES/messages.mo and b/changedetectionio/translations/it/LC_MESSAGES/messages.mo differ diff --git a/changedetectionio/translations/it/LC_MESSAGES/messages.po b/changedetectionio/translations/it/LC_MESSAGES/messages.po index 7c21ade9..09d6bf04 100644 --- a/changedetectionio/translations/it/LC_MESSAGES/messages.po +++ b/changedetectionio/translations/it/LC_MESSAGES/messages.po @@ -23,16 +23,46 @@ msgid "Add a new web page change detection watch" msgstr "Aggiungi un nuovo monitoraggio modifiche pagina web" #: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html -msgid "Watch this URL!" -msgstr "Monitora questo URL!" +#: changedetectionio/blueprint/ui/templates/preview.html +msgid "Go" +msgstr "Vai" #: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html -msgid "Edit first then Watch" -msgstr "Modifica > Monitora" +msgid "Enter a URL to get started!" +msgstr "" #: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html -#: changedetectionio/templates/edit/include_llm_intent.html -msgid "AI — Notify when…" +msgid "Enter a URL in the input box above to get started." +msgstr "" + +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html +msgid "Fetching screenshot and element information…" +msgstr "" + +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html changedetectionio/blueprint/ui/templates/edit.html +msgid "Currently:" +msgstr "" + +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html changedetectionio/blueprint/ui/templates/edit.html +msgid "Select by element" +msgstr "" + +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html +msgid "Hover & click the preview to watch just one part of the page." +msgstr "" + +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html changedetectionio/blueprint/ui/templates/edit.html +msgid "Clear selection" +msgstr "" + +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html +msgid "What matters — when to notify me" +msgstr "" + +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html +msgid "" +"e.g. Notify me when products go in/out of stock, lead times change by more than a week, or new product variants " +"appear. Skip review additions." msgstr "" #: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html @@ -40,17 +70,13 @@ msgstr "" msgid "Watch group / tag" msgstr "Gruppo / Etichetta" -#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html changedetectionio/templates/sidebar-nav.html -msgid "Live activity" -msgstr "" +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html +msgid "Watch this URL!" +msgstr "Monitora questo URL!" #: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html -msgid "Recent additions and live check status will appear here." -msgstr "" - -#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html -msgid "Waiting for activity…" -msgstr "" +msgid "Edit first then Watch" +msgstr "Modifica > Monitora" #: changedetectionio/blueprint/backups/__init__.py msgid "A backup is already running, check back in a few minutes" @@ -765,6 +791,10 @@ msgstr "" msgid "Number of items per page in the watch overview list, 0 to disable." msgstr "" +#: changedetectionio/blueprint/settings/templates/settings.html +msgid "How \"Last Checked\" and \"Last Changed\" times are shown in the watch overview list." +msgstr "" + #: changedetectionio/blueprint/settings/templates/settings.html msgid "Tip" msgstr "" @@ -2049,26 +2079,14 @@ msgstr "" msgid "Selection Mode:" msgstr "" -#: changedetectionio/blueprint/ui/templates/edit.html -msgid "Select by element" -msgstr "" - #: changedetectionio/blueprint/ui/templates/edit.html msgid "Draw area" msgstr "" -#: changedetectionio/blueprint/ui/templates/edit.html -msgid "Clear selection" -msgstr "" - #: changedetectionio/blueprint/ui/templates/edit.html msgid "One moment, fetching screenshot and element information.." msgstr "" -#: changedetectionio/blueprint/ui/templates/edit.html -msgid "Currently:" -msgstr "" - #: changedetectionio/blueprint/ui/templates/edit.html msgid "Sorry, this functionality only works with fetchers that support Javascript and screenshots (such as playwright etc)." msgstr "" @@ -2153,10 +2171,6 @@ msgstr "Clona e Modifica" msgid "Select timestamp" msgstr "" -#: changedetectionio/blueprint/ui/templates/preview.html -msgid "Go" -msgstr "Vai" - #: changedetectionio/blueprint/ui/templates/preview.html msgid "Current erroring screenshot from most recent request" msgstr "" @@ -2450,6 +2464,11 @@ msgstr "Non disponibile" msgid "Price" msgstr "Prezzo" +#: changedetectionio/blueprint/watchlist/templates/watch-overview.html +#, python-format +msgid "Price change since previous price (%(prev)s)" +msgstr "" + #: changedetectionio/blueprint/watchlist/templates/watch-overview.html msgid "No information" msgstr "Nessuna informazione" @@ -3182,6 +3201,18 @@ msgstr "Favicon attive" msgid "Use page <title> in watch overview list" msgstr "Usa <title> pagina nell'elenco osservati" +#: changedetectionio/forms.py +msgid "Relative time format" +msgstr "" + +#: changedetectionio/forms.py +msgid "Long (1 minute ago)" +msgstr "" + +#: changedetectionio/forms.py +msgid "Short (1m ago)" +msgstr "" + #: changedetectionio/forms.py msgid "API access token security check enabled" msgstr "Controllo sicurezza token API attivo" @@ -3342,6 +3373,132 @@ msgstr "RegEx da estrarre" msgid "Extract as CSV" msgstr "Estrai come CSV" +#: changedetectionio/languages.py +msgid "just now" +msgstr "proprio ora" + +#: changedetectionio/languages.py +msgid "right now" +msgstr "tra poco" + +#: changedetectionio/languages.py +#, python-format +msgid "%ss ago" +msgstr "%ss fa" + +#: changedetectionio/languages.py +#, python-format +msgid "in %ss" +msgstr "tra %ss" + +#: changedetectionio/languages.py +msgid "1m ago" +msgstr "1min fa" + +#: changedetectionio/languages.py +msgid "in 1m" +msgstr "tra 1min" + +#: changedetectionio/languages.py +#, python-format +msgid "%sm ago" +msgstr "%smin fa" + +#: changedetectionio/languages.py +#, python-format +msgid "in %sm" +msgstr "tra %smin" + +#: changedetectionio/languages.py +msgid "1h ago" +msgstr "1h fa" + +#: changedetectionio/languages.py +msgid "in 1h" +msgstr "tra 1h" + +#: changedetectionio/languages.py +#, python-format +msgid "%sh ago" +msgstr "%sh fa" + +#: changedetectionio/languages.py +#, python-format +msgid "in %sh" +msgstr "tra %sh" + +#: changedetectionio/languages.py +msgid "1d ago" +msgstr "1g fa" + +#: changedetectionio/languages.py +msgid "in 1d" +msgstr "tra 1g" + +#: changedetectionio/languages.py +#, python-format +msgid "%sd ago" +msgstr "%sg fa" + +#: changedetectionio/languages.py +#, python-format +msgid "in %sd" +msgstr "tra %sg" + +#: changedetectionio/languages.py +msgid "1w ago" +msgstr "1sett fa" + +#: changedetectionio/languages.py +msgid "in 1w" +msgstr "tra 1sett" + +#: changedetectionio/languages.py +#, python-format +msgid "%sw ago" +msgstr "%ssett fa" + +#: changedetectionio/languages.py +#, python-format +msgid "in %sw" +msgstr "tra %ssett" + +#: changedetectionio/languages.py +msgid "1mo ago" +msgstr "1mese fa" + +#: changedetectionio/languages.py +msgid "in 1mo" +msgstr "tra 1mese" + +#: changedetectionio/languages.py +#, python-format +msgid "%smo ago" +msgstr "%smesi fa" + +#: changedetectionio/languages.py +#, python-format +msgid "in %smo" +msgstr "tra %smesi" + +#: changedetectionio/languages.py +msgid "1yr ago" +msgstr "1anno fa" + +#: changedetectionio/languages.py +msgid "in 1yr" +msgstr "tra 1anno" + +#: changedetectionio/languages.py +#, python-format +msgid "%syr ago" +msgstr "%sanni fa" + +#: changedetectionio/languages.py +#, python-format +msgid "in %syr" +msgstr "tra %sanni" + #: changedetectionio/processors/extract.py msgid "No matches found while scanning all of the watch history for that RegEx." msgstr "" @@ -3970,6 +4127,10 @@ msgstr "" msgid "AI" msgstr "" +#: changedetectionio/templates/edit/include_llm_intent.html +msgid "AI — Notify when…" +msgstr "" + #: changedetectionio/templates/edit/include_llm_intent.html msgid "" "Describe what you care about. The AI evaluates every detected change against this and only notifies you when it " @@ -4314,6 +4475,10 @@ msgstr "" msgid "In queue" msgstr "" +#: changedetectionio/templates/sidebar-nav.html +msgid "Live activity" +msgstr "" + #: changedetectionio/templates/sidebar-nav.html msgid "A new version is available" msgstr "" diff --git a/changedetectionio/translations/ja/LC_MESSAGES/messages.po b/changedetectionio/translations/ja/LC_MESSAGES/messages.po index f89a77f8..95942d4f 100644 --- a/changedetectionio/translations/ja/LC_MESSAGES/messages.po +++ b/changedetectionio/translations/ja/LC_MESSAGES/messages.po @@ -24,16 +24,46 @@ msgid "Add a new web page change detection watch" msgstr "新しいウェブページ変更検知ウォッチを追加" #: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html -msgid "Watch this URL!" -msgstr "このURLをウォッチする!" +#: changedetectionio/blueprint/ui/templates/preview.html +msgid "Go" +msgstr "移動" #: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html -msgid "Edit first then Watch" -msgstr "編集してからウォッチ" +msgid "Enter a URL to get started!" +msgstr "" #: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html -#: changedetectionio/templates/edit/include_llm_intent.html -msgid "AI — Notify when…" +msgid "Enter a URL in the input box above to get started." +msgstr "" + +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html +msgid "Fetching screenshot and element information…" +msgstr "" + +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html changedetectionio/blueprint/ui/templates/edit.html +msgid "Currently:" +msgstr "現在:" + +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html changedetectionio/blueprint/ui/templates/edit.html +msgid "Select by element" +msgstr "要素で選択" + +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html +msgid "Hover & click the preview to watch just one part of the page." +msgstr "" + +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html changedetectionio/blueprint/ui/templates/edit.html +msgid "Clear selection" +msgstr "選択をクリア" + +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html +msgid "What matters — when to notify me" +msgstr "" + +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html +msgid "" +"e.g. Notify me when products go in/out of stock, lead times change by more than a week, or new product variants " +"appear. Skip review additions." msgstr "" #: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html @@ -41,17 +71,13 @@ msgstr "" msgid "Watch group / tag" msgstr "ウォッチグループ / タグ" -#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html changedetectionio/templates/sidebar-nav.html -msgid "Live activity" -msgstr "" +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html +msgid "Watch this URL!" +msgstr "このURLをウォッチする!" #: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html -msgid "Recent additions and live check status will appear here." -msgstr "" - -#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html -msgid "Waiting for activity…" -msgstr "" +msgid "Edit first then Watch" +msgstr "編集してからウォッチ" #: changedetectionio/blueprint/backups/__init__.py msgid "A backup is already running, check back in a few minutes" @@ -770,6 +796,10 @@ msgstr "ウォッチリスト横のファビコンを有効または無効にす msgid "Number of items per page in the watch overview list, 0 to disable." msgstr "ウォッチ一覧ページの1ページあたりの表示件数(0で無効化)。" +#: changedetectionio/blueprint/settings/templates/settings.html +msgid "How \"Last Checked\" and \"Last Changed\" times are shown in the watch overview list." +msgstr "" + #: changedetectionio/blueprint/settings/templates/settings.html msgid "Tip" msgstr "ヒント" @@ -2066,26 +2096,14 @@ msgstr "を使用します。" msgid "Selection Mode:" msgstr "選択モード:" -#: changedetectionio/blueprint/ui/templates/edit.html -msgid "Select by element" -msgstr "要素で選択" - #: changedetectionio/blueprint/ui/templates/edit.html msgid "Draw area" msgstr "エリアを描画" -#: changedetectionio/blueprint/ui/templates/edit.html -msgid "Clear selection" -msgstr "選択をクリア" - #: changedetectionio/blueprint/ui/templates/edit.html msgid "One moment, fetching screenshot and element information.." msgstr "少々お待ちください。スクリーンショットと要素情報を取得しています..." -#: changedetectionio/blueprint/ui/templates/edit.html -msgid "Currently:" -msgstr "現在:" - #: changedetectionio/blueprint/ui/templates/edit.html msgid "Sorry, this functionality only works with fetchers that support Javascript and screenshots (such as playwright etc)." msgstr "申し訳ありませんが、この機能はJavascriptとスクリーンショットをサポートするフェッチャー(playwrightなど)でのみ動作します。" @@ -2170,10 +2188,6 @@ msgstr "複製して編集" msgid "Select timestamp" msgstr "タイムスタンプを選択" -#: changedetectionio/blueprint/ui/templates/preview.html -msgid "Go" -msgstr "移動" - #: changedetectionio/blueprint/ui/templates/preview.html msgid "Current erroring screenshot from most recent request" msgstr "最新のリクエストからの現在のエラースクリーンショット" @@ -2467,6 +2481,11 @@ msgstr "在庫なし" msgid "Price" msgstr "価格" +#: changedetectionio/blueprint/watchlist/templates/watch-overview.html +#, python-format +msgid "Price change since previous price (%(prev)s)" +msgstr "" + #: changedetectionio/blueprint/watchlist/templates/watch-overview.html msgid "No information" msgstr "情報なし" @@ -3199,6 +3218,18 @@ msgstr "ファビコンを有効化" msgid "Use page <title> in watch overview list" msgstr "ウォッチ一覧リストでページの <title> を使用" +#: changedetectionio/forms.py +msgid "Relative time format" +msgstr "" + +#: changedetectionio/forms.py +msgid "Long (1 minute ago)" +msgstr "" + +#: changedetectionio/forms.py +msgid "Short (1m ago)" +msgstr "" + #: changedetectionio/forms.py msgid "API access token security check enabled" msgstr "APIアクセストークンのセキュリティチェックを有効化" @@ -3359,6 +3390,132 @@ msgstr "抽出する正規表現" msgid "Extract as CSV" msgstr "CSVとして抽出" +#: changedetectionio/languages.py +msgid "just now" +msgstr "" + +#: changedetectionio/languages.py +msgid "right now" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "%ss ago" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "in %ss" +msgstr "" + +#: changedetectionio/languages.py +msgid "1m ago" +msgstr "" + +#: changedetectionio/languages.py +msgid "in 1m" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "%sm ago" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "in %sm" +msgstr "" + +#: changedetectionio/languages.py +msgid "1h ago" +msgstr "" + +#: changedetectionio/languages.py +msgid "in 1h" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "%sh ago" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "in %sh" +msgstr "" + +#: changedetectionio/languages.py +msgid "1d ago" +msgstr "" + +#: changedetectionio/languages.py +msgid "in 1d" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "%sd ago" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "in %sd" +msgstr "" + +#: changedetectionio/languages.py +msgid "1w ago" +msgstr "" + +#: changedetectionio/languages.py +msgid "in 1w" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "%sw ago" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "in %sw" +msgstr "" + +#: changedetectionio/languages.py +msgid "1mo ago" +msgstr "" + +#: changedetectionio/languages.py +msgid "in 1mo" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "%smo ago" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "in %smo" +msgstr "" + +#: changedetectionio/languages.py +msgid "1yr ago" +msgstr "" + +#: changedetectionio/languages.py +msgid "in 1yr" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "%syr ago" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "in %syr" +msgstr "" + #: changedetectionio/processors/extract.py msgid "No matches found while scanning all of the watch history for that RegEx." msgstr "その正規表現についてウォッチ履歴全体をスキャンしましたが、一致するものが見つかりませんでした。" @@ -4001,6 +4158,10 @@ msgstr "検索語を入力..." msgid "AI" msgstr "" +#: changedetectionio/templates/edit/include_llm_intent.html +msgid "AI — Notify when…" +msgstr "" + #: changedetectionio/templates/edit/include_llm_intent.html msgid "" "Describe what you care about. The AI evaluates every detected change against this and only notifies you when it " @@ -4355,6 +4516,10 @@ msgstr "" msgid "In queue" msgstr "" +#: changedetectionio/templates/sidebar-nav.html +msgid "Live activity" +msgstr "" + #: changedetectionio/templates/sidebar-nav.html msgid "A new version is available" msgstr "新しいバージョンが利用可能です" diff --git a/changedetectionio/translations/ko/LC_MESSAGES/messages.mo b/changedetectionio/translations/ko/LC_MESSAGES/messages.mo index f75236fd..8eb5bf6c 100644 Binary files a/changedetectionio/translations/ko/LC_MESSAGES/messages.mo and b/changedetectionio/translations/ko/LC_MESSAGES/messages.mo differ diff --git a/changedetectionio/translations/ko/LC_MESSAGES/messages.po b/changedetectionio/translations/ko/LC_MESSAGES/messages.po index f77aec87..fe277237 100644 --- a/changedetectionio/translations/ko/LC_MESSAGES/messages.po +++ b/changedetectionio/translations/ko/LC_MESSAGES/messages.po @@ -23,34 +23,60 @@ msgid "Add a new web page change detection watch" msgstr "새 웹페이지 변경 감지 모니터링 추가" #: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html -msgid "Watch this URL!" -msgstr "이 URL 모니터링 추가" +#: changedetectionio/blueprint/ui/templates/preview.html +msgid "Go" +msgstr "이동" #: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html -msgid "Edit first then Watch" -msgstr "편집 후 모니터링 추가" +msgid "Enter a URL to get started!" +msgstr "" #: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html -#: changedetectionio/templates/edit/include_llm_intent.html -msgid "AI — Notify when…" -msgstr "AI - 다음 경우 알림" +msgid "Enter a URL in the input box above to get started." +msgstr "" + +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html +msgid "Fetching screenshot and element information…" +msgstr "" + +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html changedetectionio/blueprint/ui/templates/edit.html +msgid "Currently:" +msgstr "현재:" + +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html changedetectionio/blueprint/ui/templates/edit.html +msgid "Select by element" +msgstr "요소별로 선택" + +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html +msgid "Hover & click the preview to watch just one part of the page." +msgstr "" + +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html changedetectionio/blueprint/ui/templates/edit.html +msgid "Clear selection" +msgstr "선택 취소" + +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html +msgid "What matters — when to notify me" +msgstr "" + +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html +msgid "" +"e.g. Notify me when products go in/out of stock, lead times change by more than a week, or new product variants " +"appear. Skip review additions." +msgstr "" #: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html #: changedetectionio/blueprint/tags/templates/groups-overview.html msgid "Watch group / tag" msgstr "모니터링 그룹 / 태그" -#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html changedetectionio/templates/sidebar-nav.html -msgid "Live activity" -msgstr "" +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html +msgid "Watch this URL!" +msgstr "이 URL 모니터링 추가" #: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html -msgid "Recent additions and live check status will appear here." -msgstr "" - -#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html -msgid "Waiting for activity…" -msgstr "" +msgid "Edit first then Watch" +msgstr "편집 후 모니터링 추가" #: changedetectionio/blueprint/backups/__init__.py msgid "A backup is already running, check back in a few minutes" @@ -765,6 +791,10 @@ msgstr "모니터링 목록 옆 파비콘 표시 여부" msgid "Number of items per page in the watch overview list, 0 to disable." msgstr "모니터링 목록 페이지당 항목 수입니다. 0이면 비활성화됩니다." +#: changedetectionio/blueprint/settings/templates/settings.html +msgid "How \"Last Checked\" and \"Last Changed\" times are shown in the watch overview list." +msgstr "" + #: changedetectionio/blueprint/settings/templates/settings.html msgid "Tip" msgstr "팁" @@ -2057,26 +2087,14 @@ msgstr "사용하세요." msgid "Selection Mode:" msgstr "선택 모드:" -#: changedetectionio/blueprint/ui/templates/edit.html -msgid "Select by element" -msgstr "요소별로 선택" - #: changedetectionio/blueprint/ui/templates/edit.html msgid "Draw area" msgstr "그리기 영역" -#: changedetectionio/blueprint/ui/templates/edit.html -msgid "Clear selection" -msgstr "선택 취소" - #: changedetectionio/blueprint/ui/templates/edit.html msgid "One moment, fetching screenshot and element information.." msgstr "잠시만 기다려 주세요. 스크린샷과 요소 정보를 가져오는 중입니다." -#: changedetectionio/blueprint/ui/templates/edit.html -msgid "Currently:" -msgstr "현재:" - #: changedetectionio/blueprint/ui/templates/edit.html msgid "Sorry, this functionality only works with fetchers that support Javascript and screenshots (such as playwright etc)." msgstr "죄송합니다. 이 기능은 JavaScript와 스크린샷을 지원하는 가져오기 방식(예: Playwright 등)에서만 작동합니다." @@ -2161,10 +2179,6 @@ msgstr "복제 및 편집" msgid "Select timestamp" msgstr "타임스탬프 선택" -#: changedetectionio/blueprint/ui/templates/preview.html -msgid "Go" -msgstr "이동" - #: changedetectionio/blueprint/ui/templates/preview.html msgid "Current erroring screenshot from most recent request" msgstr "가장 최근 요청의 현재 오류 스크린샷" @@ -2458,6 +2472,11 @@ msgstr "재고 없음" msgid "Price" msgstr "가격" +#: changedetectionio/blueprint/watchlist/templates/watch-overview.html +#, python-format +msgid "Price change since previous price (%(prev)s)" +msgstr "" + #: changedetectionio/blueprint/watchlist/templates/watch-overview.html msgid "No information" msgstr "정보 없음" @@ -3190,6 +3209,18 @@ msgstr "파비콘 활성화" msgid "Use page <title> in watch overview list" msgstr "모니터링 목록에 페이지 <title> 사용" +#: changedetectionio/forms.py +msgid "Relative time format" +msgstr "" + +#: changedetectionio/forms.py +msgid "Long (1 minute ago)" +msgstr "" + +#: changedetectionio/forms.py +msgid "Short (1m ago)" +msgstr "" + #: changedetectionio/forms.py msgid "API access token security check enabled" msgstr "API 액세스 토큰 보안 확인 활성화" @@ -3350,6 +3381,132 @@ msgstr "추출할 정규식" msgid "Extract as CSV" msgstr "CSV로 추출" +#: changedetectionio/languages.py +msgid "just now" +msgstr "방금" + +#: changedetectionio/languages.py +msgid "right now" +msgstr "곧" + +#: changedetectionio/languages.py +#, python-format +msgid "%ss ago" +msgstr "%s초 전" + +#: changedetectionio/languages.py +#, python-format +msgid "in %ss" +msgstr "%s초 후" + +#: changedetectionio/languages.py +msgid "1m ago" +msgstr "1분 전" + +#: changedetectionio/languages.py +msgid "in 1m" +msgstr "1분 후" + +#: changedetectionio/languages.py +#, python-format +msgid "%sm ago" +msgstr "%s분 전" + +#: changedetectionio/languages.py +#, python-format +msgid "in %sm" +msgstr "%s분 후" + +#: changedetectionio/languages.py +msgid "1h ago" +msgstr "1시간 전" + +#: changedetectionio/languages.py +msgid "in 1h" +msgstr "1시간 후" + +#: changedetectionio/languages.py +#, python-format +msgid "%sh ago" +msgstr "%s시간 전" + +#: changedetectionio/languages.py +#, python-format +msgid "in %sh" +msgstr "%s시간 후" + +#: changedetectionio/languages.py +msgid "1d ago" +msgstr "1일 전" + +#: changedetectionio/languages.py +msgid "in 1d" +msgstr "1일 후" + +#: changedetectionio/languages.py +#, python-format +msgid "%sd ago" +msgstr "%s일 전" + +#: changedetectionio/languages.py +#, python-format +msgid "in %sd" +msgstr "%s일 후" + +#: changedetectionio/languages.py +msgid "1w ago" +msgstr "1주 전" + +#: changedetectionio/languages.py +msgid "in 1w" +msgstr "1주 후" + +#: changedetectionio/languages.py +#, python-format +msgid "%sw ago" +msgstr "%s주 전" + +#: changedetectionio/languages.py +#, python-format +msgid "in %sw" +msgstr "%s주 후" + +#: changedetectionio/languages.py +msgid "1mo ago" +msgstr "1개월 전" + +#: changedetectionio/languages.py +msgid "in 1mo" +msgstr "1개월 후" + +#: changedetectionio/languages.py +#, python-format +msgid "%smo ago" +msgstr "%s개월 전" + +#: changedetectionio/languages.py +#, python-format +msgid "in %smo" +msgstr "%s개월 후" + +#: changedetectionio/languages.py +msgid "1yr ago" +msgstr "1년 전" + +#: changedetectionio/languages.py +msgid "in 1yr" +msgstr "1년 후" + +#: changedetectionio/languages.py +#, python-format +msgid "%syr ago" +msgstr "%s년 전" + +#: changedetectionio/languages.py +#, python-format +msgid "in %syr" +msgstr "%s년 후" + #: changedetectionio/processors/extract.py msgid "No matches found while scanning all of the watch history for that RegEx." msgstr "해당 정규식으로 모든 모니터링 기록을 검사했지만 일치하는 항목을 찾지 못했습니다." @@ -3978,6 +4135,10 @@ msgstr "검색어를 입력하세요..." msgid "AI" msgstr "AI" +#: changedetectionio/templates/edit/include_llm_intent.html +msgid "AI — Notify when…" +msgstr "AI - 다음 경우 알림" + #: changedetectionio/templates/edit/include_llm_intent.html msgid "" "Describe what you care about. The AI evaluates every detected change against this and only notifies you when it " @@ -4332,6 +4493,10 @@ msgstr "" msgid "In queue" msgstr "" +#: changedetectionio/templates/sidebar-nav.html +msgid "Live activity" +msgstr "" + #: changedetectionio/templates/sidebar-nav.html msgid "A new version is available" msgstr "새 버전이 있습니다" diff --git a/changedetectionio/translations/messages.pot b/changedetectionio/translations/messages.pot index 8fd25a47..a7b4e35a 100644 --- a/changedetectionio/translations/messages.pot +++ b/changedetectionio/translations/messages.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: changedetection.io 0.55.7\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2026-06-03 13:26+0200\n" +"POT-Creation-Date: 2026-06-14 13:29+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Language-Team: LANGUAGE <LL@li.org>\n" @@ -22,16 +22,46 @@ msgid "Add a new web page change detection watch" msgstr "" #: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html -msgid "Watch this URL!" +#: changedetectionio/blueprint/ui/templates/preview.html +msgid "Go" msgstr "" #: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html -msgid "Edit first then Watch" +msgid "Enter a URL to get started!" msgstr "" #: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html -#: changedetectionio/templates/edit/include_llm_intent.html -msgid "AI — Notify when…" +msgid "Enter a URL in the input box above to get started." +msgstr "" + +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html +msgid "Fetching screenshot and element information…" +msgstr "" + +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html changedetectionio/blueprint/ui/templates/edit.html +msgid "Currently:" +msgstr "" + +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html changedetectionio/blueprint/ui/templates/edit.html +msgid "Select by element" +msgstr "" + +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html +msgid "Hover & click the preview to watch just one part of the page." +msgstr "" + +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html changedetectionio/blueprint/ui/templates/edit.html +msgid "Clear selection" +msgstr "" + +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html +msgid "What matters — when to notify me" +msgstr "" + +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html +msgid "" +"e.g. Notify me when products go in/out of stock, lead times change by more than a week, or new product variants " +"appear. Skip review additions." msgstr "" #: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html @@ -39,16 +69,12 @@ msgstr "" msgid "Watch group / tag" msgstr "" -#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html changedetectionio/templates/sidebar-nav.html -msgid "Live activity" +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html +msgid "Watch this URL!" msgstr "" #: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html -msgid "Recent additions and live check status will appear here." -msgstr "" - -#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html -msgid "Waiting for activity…" +msgid "Edit first then Watch" msgstr "" #: changedetectionio/blueprint/backups/__init__.py @@ -762,6 +788,10 @@ msgstr "" msgid "Number of items per page in the watch overview list, 0 to disable." msgstr "" +#: changedetectionio/blueprint/settings/templates/settings.html +msgid "How \"Last Checked\" and \"Last Changed\" times are shown in the watch overview list." +msgstr "" + #: changedetectionio/blueprint/settings/templates/settings.html msgid "Tip" msgstr "" @@ -2046,26 +2076,14 @@ msgstr "" msgid "Selection Mode:" msgstr "" -#: changedetectionio/blueprint/ui/templates/edit.html -msgid "Select by element" -msgstr "" - #: changedetectionio/blueprint/ui/templates/edit.html msgid "Draw area" msgstr "" -#: changedetectionio/blueprint/ui/templates/edit.html -msgid "Clear selection" -msgstr "" - #: changedetectionio/blueprint/ui/templates/edit.html msgid "One moment, fetching screenshot and element information.." msgstr "" -#: changedetectionio/blueprint/ui/templates/edit.html -msgid "Currently:" -msgstr "" - #: changedetectionio/blueprint/ui/templates/edit.html msgid "Sorry, this functionality only works with fetchers that support Javascript and screenshots (such as playwright etc)." msgstr "" @@ -2150,10 +2168,6 @@ msgstr "" msgid "Select timestamp" msgstr "" -#: changedetectionio/blueprint/ui/templates/preview.html -msgid "Go" -msgstr "" - #: changedetectionio/blueprint/ui/templates/preview.html msgid "Current erroring screenshot from most recent request" msgstr "" @@ -2447,6 +2461,11 @@ msgstr "" msgid "Price" msgstr "" +#: changedetectionio/blueprint/watchlist/templates/watch-overview.html +#, python-format +msgid "Price change since previous price (%(prev)s)" +msgstr "" + #: changedetectionio/blueprint/watchlist/templates/watch-overview.html msgid "No information" msgstr "" @@ -3179,6 +3198,18 @@ msgstr "" msgid "Use page <title> in watch overview list" msgstr "" +#: changedetectionio/forms.py +msgid "Relative time format" +msgstr "" + +#: changedetectionio/forms.py +msgid "Long (1 minute ago)" +msgstr "" + +#: changedetectionio/forms.py +msgid "Short (1m ago)" +msgstr "" + #: changedetectionio/forms.py msgid "API access token security check enabled" msgstr "" @@ -3339,6 +3370,132 @@ msgstr "" msgid "Extract as CSV" msgstr "" +#: changedetectionio/languages.py +msgid "just now" +msgstr "" + +#: changedetectionio/languages.py +msgid "right now" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "%ss ago" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "in %ss" +msgstr "" + +#: changedetectionio/languages.py +msgid "1m ago" +msgstr "" + +#: changedetectionio/languages.py +msgid "in 1m" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "%sm ago" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "in %sm" +msgstr "" + +#: changedetectionio/languages.py +msgid "1h ago" +msgstr "" + +#: changedetectionio/languages.py +msgid "in 1h" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "%sh ago" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "in %sh" +msgstr "" + +#: changedetectionio/languages.py +msgid "1d ago" +msgstr "" + +#: changedetectionio/languages.py +msgid "in 1d" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "%sd ago" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "in %sd" +msgstr "" + +#: changedetectionio/languages.py +msgid "1w ago" +msgstr "" + +#: changedetectionio/languages.py +msgid "in 1w" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "%sw ago" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "in %sw" +msgstr "" + +#: changedetectionio/languages.py +msgid "1mo ago" +msgstr "" + +#: changedetectionio/languages.py +msgid "in 1mo" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "%smo ago" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "in %smo" +msgstr "" + +#: changedetectionio/languages.py +msgid "1yr ago" +msgstr "" + +#: changedetectionio/languages.py +msgid "in 1yr" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "%syr ago" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "in %syr" +msgstr "" + #: changedetectionio/processors/extract.py msgid "No matches found while scanning all of the watch history for that RegEx." msgstr "" @@ -3967,6 +4124,10 @@ msgstr "" msgid "AI" msgstr "" +#: changedetectionio/templates/edit/include_llm_intent.html +msgid "AI — Notify when…" +msgstr "" + #: changedetectionio/templates/edit/include_llm_intent.html msgid "" "Describe what you care about. The AI evaluates every detected change against this and only notifies you when it " @@ -4311,6 +4472,10 @@ msgstr "" msgid "In queue" msgstr "" +#: changedetectionio/templates/sidebar-nav.html +msgid "Live activity" +msgstr "" + #: changedetectionio/templates/sidebar-nav.html msgid "A new version is available" msgstr "" diff --git a/changedetectionio/translations/pt_BR/LC_MESSAGES/messages.po b/changedetectionio/translations/pt_BR/LC_MESSAGES/messages.po index 48b1d228..2a3121b1 100644 --- a/changedetectionio/translations/pt_BR/LC_MESSAGES/messages.po +++ b/changedetectionio/translations/pt_BR/LC_MESSAGES/messages.po @@ -24,16 +24,46 @@ msgid "Add a new web page change detection watch" msgstr "Adicionar um novo monitoramento de detecção de mudança de página" #: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html -msgid "Watch this URL!" -msgstr "Monitorar esta URL!" +#: changedetectionio/blueprint/ui/templates/preview.html +msgid "Go" +msgstr "Ir" #: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html -msgid "Edit first then Watch" -msgstr "Editar primeiro, depois Monitorar" +msgid "Enter a URL to get started!" +msgstr "" #: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html -#: changedetectionio/templates/edit/include_llm_intent.html -msgid "AI — Notify when…" +msgid "Enter a URL in the input box above to get started." +msgstr "" + +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html +msgid "Fetching screenshot and element information…" +msgstr "" + +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html changedetectionio/blueprint/ui/templates/edit.html +msgid "Currently:" +msgstr "Atualmente:" + +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html changedetectionio/blueprint/ui/templates/edit.html +msgid "Select by element" +msgstr "Selecionar por elemento" + +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html +msgid "Hover & click the preview to watch just one part of the page." +msgstr "" + +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html changedetectionio/blueprint/ui/templates/edit.html +msgid "Clear selection" +msgstr "Limpar seleção" + +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html +msgid "What matters — when to notify me" +msgstr "" + +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html +msgid "" +"e.g. Notify me when products go in/out of stock, lead times change by more than a week, or new product variants " +"appear. Skip review additions." msgstr "" #: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html @@ -41,17 +71,13 @@ msgstr "" msgid "Watch group / tag" msgstr "Grupo / Tag de monitoramento" -#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html changedetectionio/templates/sidebar-nav.html -msgid "Live activity" -msgstr "" +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html +msgid "Watch this URL!" +msgstr "Monitorar esta URL!" #: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html -msgid "Recent additions and live check status will appear here." -msgstr "" - -#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html -msgid "Waiting for activity…" -msgstr "" +msgid "Edit first then Watch" +msgstr "Editar primeiro, depois Monitorar" #: changedetectionio/blueprint/backups/__init__.py msgid "A backup is already running, check back in a few minutes" @@ -786,6 +812,10 @@ msgstr "Ativar ou Desativar Favicons ao lado da lista de monitoramento" msgid "Number of items per page in the watch overview list, 0 to disable." msgstr "Número de itens por página na lista de visão geral, 0 para desativar." +#: changedetectionio/blueprint/settings/templates/settings.html +msgid "How \"Last Checked\" and \"Last Changed\" times are shown in the watch overview list." +msgstr "" + #: changedetectionio/blueprint/settings/templates/settings.html msgid "Tip" msgstr "Dica" @@ -2095,26 +2125,14 @@ msgstr "para selecionar múltiplos itens." msgid "Selection Mode:" msgstr "Modo de Seleção:" -#: changedetectionio/blueprint/ui/templates/edit.html -msgid "Select by element" -msgstr "Selecionar por elemento" - #: changedetectionio/blueprint/ui/templates/edit.html msgid "Draw area" msgstr "Desenhar área" -#: changedetectionio/blueprint/ui/templates/edit.html -msgid "Clear selection" -msgstr "Limpar seleção" - #: changedetectionio/blueprint/ui/templates/edit.html msgid "One moment, fetching screenshot and element information.." msgstr "Um momento, buscando screenshot e informações dos elementos..." -#: changedetectionio/blueprint/ui/templates/edit.html -msgid "Currently:" -msgstr "Atualmente:" - #: changedetectionio/blueprint/ui/templates/edit.html msgid "Sorry, this functionality only works with fetchers that support Javascript and screenshots (such as playwright etc)." msgstr "Desculpe, esta funcionalidade só funciona com fetchers que suportam Javascript e screenshots (como playwright, etc)." @@ -2199,10 +2217,6 @@ msgstr "Clonar e Editar" msgid "Select timestamp" msgstr "Selecionar data/hora" -#: changedetectionio/blueprint/ui/templates/preview.html -msgid "Go" -msgstr "Ir" - #: changedetectionio/blueprint/ui/templates/preview.html msgid "Current erroring screenshot from most recent request" msgstr "Screenshot de erro atual da solicitação mais recente" @@ -2498,6 +2512,11 @@ msgstr "Sem estoque" msgid "Price" msgstr "Preço" +#: changedetectionio/blueprint/watchlist/templates/watch-overview.html +#, python-format +msgid "Price change since previous price (%(prev)s)" +msgstr "" + #: changedetectionio/blueprint/watchlist/templates/watch-overview.html msgid "No information" msgstr "Sem informações" @@ -3230,6 +3249,18 @@ msgstr "Favicons Ativados" msgid "Use page <title> in watch overview list" msgstr "Usar <title> da página na lista de visão geral" +#: changedetectionio/forms.py +msgid "Relative time format" +msgstr "" + +#: changedetectionio/forms.py +msgid "Long (1 minute ago)" +msgstr "" + +#: changedetectionio/forms.py +msgid "Short (1m ago)" +msgstr "" + #: changedetectionio/forms.py msgid "API access token security check enabled" msgstr "Verificação de segurança do token de acesso à API ativada" @@ -3390,6 +3421,132 @@ msgstr "RegEx para extrair" msgid "Extract as CSV" msgstr "Extrair como CSV" +#: changedetectionio/languages.py +msgid "just now" +msgstr "" + +#: changedetectionio/languages.py +msgid "right now" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "%ss ago" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "in %ss" +msgstr "" + +#: changedetectionio/languages.py +msgid "1m ago" +msgstr "" + +#: changedetectionio/languages.py +msgid "in 1m" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "%sm ago" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "in %sm" +msgstr "" + +#: changedetectionio/languages.py +msgid "1h ago" +msgstr "" + +#: changedetectionio/languages.py +msgid "in 1h" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "%sh ago" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "in %sh" +msgstr "" + +#: changedetectionio/languages.py +msgid "1d ago" +msgstr "" + +#: changedetectionio/languages.py +msgid "in 1d" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "%sd ago" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "in %sd" +msgstr "" + +#: changedetectionio/languages.py +msgid "1w ago" +msgstr "" + +#: changedetectionio/languages.py +msgid "in 1w" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "%sw ago" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "in %sw" +msgstr "" + +#: changedetectionio/languages.py +msgid "1mo ago" +msgstr "" + +#: changedetectionio/languages.py +msgid "in 1mo" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "%smo ago" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "in %smo" +msgstr "" + +#: changedetectionio/languages.py +msgid "1yr ago" +msgstr "" + +#: changedetectionio/languages.py +msgid "in 1yr" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "%syr ago" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "in %syr" +msgstr "" + #: changedetectionio/processors/extract.py msgid "No matches found while scanning all of the watch history for that RegEx." msgstr "Nenhuma correspondência encontrada ao escanear todo o histórico de monitoramento para esse RegEx." @@ -4020,6 +4177,10 @@ msgstr "Digite o termo de busca..." msgid "AI" msgstr "" +#: changedetectionio/templates/edit/include_llm_intent.html +msgid "AI — Notify when…" +msgstr "" + #: changedetectionio/templates/edit/include_llm_intent.html msgid "" "Describe what you care about. The AI evaluates every detected change against this and only notifies you when it " @@ -4370,6 +4531,10 @@ msgstr "" msgid "In queue" msgstr "" +#: changedetectionio/templates/sidebar-nav.html +msgid "Live activity" +msgstr "" + #: changedetectionio/templates/sidebar-nav.html msgid "A new version is available" msgstr "" diff --git a/changedetectionio/translations/tr/LC_MESSAGES/messages.po b/changedetectionio/translations/tr/LC_MESSAGES/messages.po index da3ba75a..4bfb7f60 100644 --- a/changedetectionio/translations/tr/LC_MESSAGES/messages.po +++ b/changedetectionio/translations/tr/LC_MESSAGES/messages.po @@ -24,16 +24,46 @@ msgid "Add a new web page change detection watch" msgstr "Yeni bir web sayfası değişiklik tespiti izleyicisi ekle" #: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html -msgid "Watch this URL!" -msgstr "Bu URL'yi izle!" +#: changedetectionio/blueprint/ui/templates/preview.html +msgid "Go" +msgstr "Git" #: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html -msgid "Edit first then Watch" -msgstr "Önce Düzenle sonra İzle" +msgid "Enter a URL to get started!" +msgstr "" #: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html -#: changedetectionio/templates/edit/include_llm_intent.html -msgid "AI — Notify when…" +msgid "Enter a URL in the input box above to get started." +msgstr "" + +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html +msgid "Fetching screenshot and element information…" +msgstr "" + +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html changedetectionio/blueprint/ui/templates/edit.html +msgid "Currently:" +msgstr "Şu anda:" + +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html changedetectionio/blueprint/ui/templates/edit.html +msgid "Select by element" +msgstr "Öğeye göre seç" + +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html +msgid "Hover & click the preview to watch just one part of the page." +msgstr "" + +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html changedetectionio/blueprint/ui/templates/edit.html +msgid "Clear selection" +msgstr "Seçimi temizle" + +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html +msgid "What matters — when to notify me" +msgstr "" + +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html +msgid "" +"e.g. Notify me when products go in/out of stock, lead times change by more than a week, or new product variants " +"appear. Skip review additions." msgstr "" #: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html @@ -41,17 +71,13 @@ msgstr "" msgid "Watch group / tag" msgstr "İzleyici grubu / etiketi" -#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html changedetectionio/templates/sidebar-nav.html -msgid "Live activity" -msgstr "" +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html +msgid "Watch this URL!" +msgstr "Bu URL'yi izle!" #: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html -msgid "Recent additions and live check status will appear here." -msgstr "" - -#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html -msgid "Waiting for activity…" -msgstr "" +msgid "Edit first then Watch" +msgstr "Önce Düzenle sonra İzle" #: changedetectionio/blueprint/backups/__init__.py msgid "A backup is already running, check back in a few minutes" @@ -796,6 +822,10 @@ msgstr "İzleme listesinin yanındaki Favicon'ları Etkinleştir veya Devre Dı msgid "Number of items per page in the watch overview list, 0 to disable." msgstr "İzleyici genel bakış listesinde sayfa başına öğe sayısı, devre dışı bırakmak için 0." +#: changedetectionio/blueprint/settings/templates/settings.html +msgid "How \"Last Checked\" and \"Last Changed\" times are shown in the watch overview list." +msgstr "" + #: changedetectionio/blueprint/settings/templates/settings.html msgid "Tip" msgstr "İpucu" @@ -2098,26 +2128,14 @@ msgstr "birden çok öğe seçmek için." msgid "Selection Mode:" msgstr "Seçim Modu:" -#: changedetectionio/blueprint/ui/templates/edit.html -msgid "Select by element" -msgstr "Öğeye göre seç" - #: changedetectionio/blueprint/ui/templates/edit.html msgid "Draw area" msgstr "Çizim alanı" -#: changedetectionio/blueprint/ui/templates/edit.html -msgid "Clear selection" -msgstr "Seçimi temizle" - #: changedetectionio/blueprint/ui/templates/edit.html msgid "One moment, fetching screenshot and element information.." msgstr "Bir saniye, ekran görüntüsü ve öğe bilgileri getiriliyor.." -#: changedetectionio/blueprint/ui/templates/edit.html -msgid "Currently:" -msgstr "Şu anda:" - #: changedetectionio/blueprint/ui/templates/edit.html msgid "Sorry, this functionality only works with fetchers that support Javascript and screenshots (such as playwright etc)." msgstr "" @@ -2204,10 +2222,6 @@ msgstr "Klonla ve Düzenle" msgid "Select timestamp" msgstr "Zaman damgası seç" -#: changedetectionio/blueprint/ui/templates/preview.html -msgid "Go" -msgstr "Git" - #: changedetectionio/blueprint/ui/templates/preview.html msgid "Current erroring screenshot from most recent request" msgstr "En son istekten gelen mevcut hatalı ekran görüntüsü" @@ -2501,6 +2515,11 @@ msgstr "Stokta yok" msgid "Price" msgstr "Fiyat" +#: changedetectionio/blueprint/watchlist/templates/watch-overview.html +#, python-format +msgid "Price change since previous price (%(prev)s)" +msgstr "" + #: changedetectionio/blueprint/watchlist/templates/watch-overview.html msgid "No information" msgstr "Bilgi yok" @@ -3233,6 +3252,18 @@ msgstr "Favicon'lar Etkin" msgid "Use page <title> in watch overview list" msgstr "İzleyici genel bakış listesinde sayfa <title>'ını kullan" +#: changedetectionio/forms.py +msgid "Relative time format" +msgstr "" + +#: changedetectionio/forms.py +msgid "Long (1 minute ago)" +msgstr "" + +#: changedetectionio/forms.py +msgid "Short (1m ago)" +msgstr "" + #: changedetectionio/forms.py msgid "API access token security check enabled" msgstr "API erişim belirteci güvenlik kontrolü etkin" @@ -3393,6 +3424,132 @@ msgstr "Çıkarılacak RegEx" msgid "Extract as CSV" msgstr "CSV olarak çıkar" +#: changedetectionio/languages.py +msgid "just now" +msgstr "" + +#: changedetectionio/languages.py +msgid "right now" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "%ss ago" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "in %ss" +msgstr "" + +#: changedetectionio/languages.py +msgid "1m ago" +msgstr "" + +#: changedetectionio/languages.py +msgid "in 1m" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "%sm ago" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "in %sm" +msgstr "" + +#: changedetectionio/languages.py +msgid "1h ago" +msgstr "" + +#: changedetectionio/languages.py +msgid "in 1h" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "%sh ago" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "in %sh" +msgstr "" + +#: changedetectionio/languages.py +msgid "1d ago" +msgstr "" + +#: changedetectionio/languages.py +msgid "in 1d" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "%sd ago" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "in %sd" +msgstr "" + +#: changedetectionio/languages.py +msgid "1w ago" +msgstr "" + +#: changedetectionio/languages.py +msgid "in 1w" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "%sw ago" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "in %sw" +msgstr "" + +#: changedetectionio/languages.py +msgid "1mo ago" +msgstr "" + +#: changedetectionio/languages.py +msgid "in 1mo" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "%smo ago" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "in %smo" +msgstr "" + +#: changedetectionio/languages.py +msgid "1yr ago" +msgstr "" + +#: changedetectionio/languages.py +msgid "in 1yr" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "%syr ago" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "in %syr" +msgstr "" + #: changedetectionio/processors/extract.py msgid "No matches found while scanning all of the watch history for that RegEx." msgstr "Tüm izleme geçmişi o RegEx için taranırken hiçbir eşleşme bulunamadı." @@ -4025,6 +4182,10 @@ msgstr "Arama terimini girin..." msgid "AI" msgstr "" +#: changedetectionio/templates/edit/include_llm_intent.html +msgid "AI — Notify when…" +msgstr "" + #: changedetectionio/templates/edit/include_llm_intent.html msgid "" "Describe what you care about. The AI evaluates every detected change against this and only notifies you when it " @@ -4373,6 +4534,10 @@ msgstr "" msgid "In queue" msgstr "" +#: changedetectionio/templates/sidebar-nav.html +msgid "Live activity" +msgstr "" + #: changedetectionio/templates/sidebar-nav.html msgid "A new version is available" msgstr "" diff --git a/changedetectionio/translations/uk/LC_MESSAGES/messages.po b/changedetectionio/translations/uk/LC_MESSAGES/messages.po index a25cc4e9..1b70e446 100644 --- a/changedetectionio/translations/uk/LC_MESSAGES/messages.po +++ b/changedetectionio/translations/uk/LC_MESSAGES/messages.po @@ -22,16 +22,46 @@ msgid "Add a new web page change detection watch" msgstr "Додати нове завдання відстеження змін веб-сторінки" #: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html -msgid "Watch this URL!" -msgstr "Відстежувати цей URL!" +#: changedetectionio/blueprint/ui/templates/preview.html +msgid "Go" +msgstr "Перейти" #: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html -msgid "Edit first then Watch" -msgstr "Спочатку редагувати, потім Відстежувати" +msgid "Enter a URL to get started!" +msgstr "" #: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html -#: changedetectionio/templates/edit/include_llm_intent.html -msgid "AI — Notify when…" +msgid "Enter a URL in the input box above to get started." +msgstr "" + +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html +msgid "Fetching screenshot and element information…" +msgstr "" + +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html changedetectionio/blueprint/ui/templates/edit.html +msgid "Currently:" +msgstr "В даний час:" + +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html changedetectionio/blueprint/ui/templates/edit.html +msgid "Select by element" +msgstr "Вибір за елементом" + +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html +msgid "Hover & click the preview to watch just one part of the page." +msgstr "" + +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html changedetectionio/blueprint/ui/templates/edit.html +msgid "Clear selection" +msgstr "Очистити вибір" + +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html +msgid "What matters — when to notify me" +msgstr "" + +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html +msgid "" +"e.g. Notify me when products go in/out of stock, lead times change by more than a week, or new product variants " +"appear. Skip review additions." msgstr "" #: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html @@ -39,17 +69,13 @@ msgstr "" msgid "Watch group / tag" msgstr "Група / Тег відстеження" -#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html changedetectionio/templates/sidebar-nav.html -msgid "Live activity" -msgstr "" +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html +msgid "Watch this URL!" +msgstr "Відстежувати цей URL!" #: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html -msgid "Recent additions and live check status will appear here." -msgstr "" - -#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html -msgid "Waiting for activity…" -msgstr "" +msgid "Edit first then Watch" +msgstr "Спочатку редагувати, потім Відстежувати" #: changedetectionio/blueprint/backups/__init__.py msgid "A backup is already running, check back in a few minutes" @@ -776,6 +802,10 @@ msgstr "Увімкнути або вимкнути значки (фавікон msgid "Number of items per page in the watch overview list, 0 to disable." msgstr "Кількість елементів на сторінці у списку завдань, 0 для вимкнення." +#: changedetectionio/blueprint/settings/templates/settings.html +msgid "How \"Last Checked\" and \"Last Changed\" times are shown in the watch overview list." +msgstr "" + #: changedetectionio/blueprint/settings/templates/settings.html msgid "Tip" msgstr "Порада" @@ -2079,26 +2109,14 @@ msgstr "для вибору кількох елементів." msgid "Selection Mode:" msgstr "Режим вибору:" -#: changedetectionio/blueprint/ui/templates/edit.html -msgid "Select by element" -msgstr "Вибір за елементом" - #: changedetectionio/blueprint/ui/templates/edit.html msgid "Draw area" msgstr "Малювання області" -#: changedetectionio/blueprint/ui/templates/edit.html -msgid "Clear selection" -msgstr "Очистити вибір" - #: changedetectionio/blueprint/ui/templates/edit.html msgid "One moment, fetching screenshot and element information.." msgstr "Хвилинку, отримання скріншота та інформації про елементи..." -#: changedetectionio/blueprint/ui/templates/edit.html -msgid "Currently:" -msgstr "В даний час:" - #: changedetectionio/blueprint/ui/templates/edit.html msgid "Sorry, this functionality only works with fetchers that support Javascript and screenshots (such as playwright etc)." msgstr "Вибачте, ця функція працює лише із завантажувачами, що підтримують Javascript і скріншоти (наприклад, playwright)." @@ -2183,10 +2201,6 @@ msgstr "Клонувати та Редагувати" msgid "Select timestamp" msgstr "Виберіть мітку часу" -#: changedetectionio/blueprint/ui/templates/preview.html -msgid "Go" -msgstr "Перейти" - #: changedetectionio/blueprint/ui/templates/preview.html msgid "Current erroring screenshot from most recent request" msgstr "Поточний скріншот з помилкою з останнього запиту" @@ -2480,6 +2494,11 @@ msgstr "Немає в наявності" msgid "Price" msgstr "Ціна" +#: changedetectionio/blueprint/watchlist/templates/watch-overview.html +#, python-format +msgid "Price change since previous price (%(prev)s)" +msgstr "" + #: changedetectionio/blueprint/watchlist/templates/watch-overview.html msgid "No information" msgstr "Немає інформації" @@ -3212,6 +3231,18 @@ msgstr "Фавіконки увімкнено" msgid "Use page <title> in watch overview list" msgstr "Використовувати <title> сторінки у списку огляду завдань" +#: changedetectionio/forms.py +msgid "Relative time format" +msgstr "" + +#: changedetectionio/forms.py +msgid "Long (1 minute ago)" +msgstr "" + +#: changedetectionio/forms.py +msgid "Short (1m ago)" +msgstr "" + #: changedetectionio/forms.py msgid "API access token security check enabled" msgstr "Перевірку безпеки токена доступу API увімкнено" @@ -3372,6 +3403,132 @@ msgstr "RegEx для вилучення" msgid "Extract as CSV" msgstr "Вилучити як CSV" +#: changedetectionio/languages.py +msgid "just now" +msgstr "" + +#: changedetectionio/languages.py +msgid "right now" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "%ss ago" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "in %ss" +msgstr "" + +#: changedetectionio/languages.py +msgid "1m ago" +msgstr "" + +#: changedetectionio/languages.py +msgid "in 1m" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "%sm ago" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "in %sm" +msgstr "" + +#: changedetectionio/languages.py +msgid "1h ago" +msgstr "" + +#: changedetectionio/languages.py +msgid "in 1h" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "%sh ago" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "in %sh" +msgstr "" + +#: changedetectionio/languages.py +msgid "1d ago" +msgstr "" + +#: changedetectionio/languages.py +msgid "in 1d" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "%sd ago" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "in %sd" +msgstr "" + +#: changedetectionio/languages.py +msgid "1w ago" +msgstr "" + +#: changedetectionio/languages.py +msgid "in 1w" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "%sw ago" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "in %sw" +msgstr "" + +#: changedetectionio/languages.py +msgid "1mo ago" +msgstr "" + +#: changedetectionio/languages.py +msgid "in 1mo" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "%smo ago" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "in %smo" +msgstr "" + +#: changedetectionio/languages.py +msgid "1yr ago" +msgstr "" + +#: changedetectionio/languages.py +msgid "in 1yr" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "%syr ago" +msgstr "" + +#: changedetectionio/languages.py +#, python-format +msgid "in %syr" +msgstr "" + #: changedetectionio/processors/extract.py msgid "No matches found while scanning all of the watch history for that RegEx." msgstr "Збігів не знайдено під час сканування всієї історії цього завдання за даним RegEx." @@ -4002,6 +4159,10 @@ msgstr "Введіть пошуковий запит..." msgid "AI" msgstr "" +#: changedetectionio/templates/edit/include_llm_intent.html +msgid "AI — Notify when…" +msgstr "" + #: changedetectionio/templates/edit/include_llm_intent.html msgid "" "Describe what you care about. The AI evaluates every detected change against this and only notifies you when it " @@ -4350,6 +4511,10 @@ msgstr "" msgid "In queue" msgstr "" +#: changedetectionio/templates/sidebar-nav.html +msgid "Live activity" +msgstr "" + #: changedetectionio/templates/sidebar-nav.html msgid "A new version is available" msgstr "" diff --git a/changedetectionio/translations/zh/LC_MESSAGES/messages.mo b/changedetectionio/translations/zh/LC_MESSAGES/messages.mo index 281ca176..84cab79d 100644 Binary files a/changedetectionio/translations/zh/LC_MESSAGES/messages.mo and b/changedetectionio/translations/zh/LC_MESSAGES/messages.mo differ diff --git a/changedetectionio/translations/zh/LC_MESSAGES/messages.po b/changedetectionio/translations/zh/LC_MESSAGES/messages.po index ad375dc8..68588d7a 100644 --- a/changedetectionio/translations/zh/LC_MESSAGES/messages.po +++ b/changedetectionio/translations/zh/LC_MESSAGES/messages.po @@ -23,16 +23,46 @@ msgid "Add a new web page change detection watch" msgstr "新增网页变更监控" #: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html -msgid "Watch this URL!" -msgstr "监控此 URL!" +#: changedetectionio/blueprint/ui/templates/preview.html +msgid "Go" +msgstr "前往" #: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html -msgid "Edit first then Watch" -msgstr "先编辑,再监控" +msgid "Enter a URL to get started!" +msgstr "" #: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html -#: changedetectionio/templates/edit/include_llm_intent.html -msgid "AI — Notify when…" +msgid "Enter a URL in the input box above to get started." +msgstr "" + +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html +msgid "Fetching screenshot and element information…" +msgstr "" + +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html changedetectionio/blueprint/ui/templates/edit.html +msgid "Currently:" +msgstr "当前:" + +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html changedetectionio/blueprint/ui/templates/edit.html +msgid "Select by element" +msgstr "按元素选择" + +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html +msgid "Hover & click the preview to watch just one part of the page." +msgstr "" + +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html changedetectionio/blueprint/ui/templates/edit.html +msgid "Clear selection" +msgstr "清除选择" + +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html +msgid "What matters — when to notify me" +msgstr "" + +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html +msgid "" +"e.g. Notify me when products go in/out of stock, lead times change by more than a week, or new product variants " +"appear. Skip review additions." msgstr "" #: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html @@ -40,17 +70,13 @@ msgstr "" msgid "Watch group / tag" msgstr "分组 / 标签" -#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html changedetectionio/templates/sidebar-nav.html -msgid "Live activity" -msgstr "" +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html +msgid "Watch this URL!" +msgstr "监控此 URL!" #: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html -msgid "Recent additions and live check status will appear here." -msgstr "" - -#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html -msgid "Waiting for activity…" -msgstr "" +msgid "Edit first then Watch" +msgstr "先编辑,再监控" #: changedetectionio/blueprint/backups/__init__.py msgid "A backup is already running, check back in a few minutes" @@ -271,7 +297,8 @@ msgstr "未通过验证的 URL 会保留在文本框中。" msgid "Copy and Paste your Distill.io watch 'export' file, this should be a JSON file." msgstr "复制并粘贴 Distill.io 监控的“导出”文件(JSON)。" -# TN: CJK scripts degrade when italicized; emphasis is rendered with <strong> instead. +# TN: CJK scripts degrade when italicized; emphasis is rendered with <strong> +# instead. #. CJK fonts lack native italics; allow substitution with conventional local styling. dennis-ignore: W303 #: changedetectionio/blueprint/imports/templates/import.html msgid "" @@ -767,6 +794,10 @@ msgstr "在监控列表中启用或禁用站点图标" msgid "Number of items per page in the watch overview list, 0 to disable." msgstr "监控概览列表每页数量,0 为禁用。" +#: changedetectionio/blueprint/settings/templates/settings.html +msgid "How \"Last Checked\" and \"Last Changed\" times are shown in the watch overview list." +msgstr "" + #: changedetectionio/blueprint/settings/templates/settings.html msgid "Tip" msgstr "提示" @@ -2052,26 +2083,14 @@ msgstr "以选择多个项。" msgid "Selection Mode:" msgstr "选择模式:" -#: changedetectionio/blueprint/ui/templates/edit.html -msgid "Select by element" -msgstr "按元素选择" - #: changedetectionio/blueprint/ui/templates/edit.html msgid "Draw area" msgstr "框选区域" -#: changedetectionio/blueprint/ui/templates/edit.html -msgid "Clear selection" -msgstr "清除选择" - #: changedetectionio/blueprint/ui/templates/edit.html msgid "One moment, fetching screenshot and element information.." msgstr "稍等,正在获取截图和元素信息.." -#: changedetectionio/blueprint/ui/templates/edit.html -msgid "Currently:" -msgstr "当前:" - #: changedetectionio/blueprint/ui/templates/edit.html msgid "Sorry, this functionality only works with fetchers that support Javascript and screenshots (such as playwright etc)." msgstr "抱歉,此功能仅适用于支持 JavaScript 和截图的抓取器(如 Playwright 等)。" @@ -2156,10 +2175,6 @@ msgstr "克隆并编辑" msgid "Select timestamp" msgstr "选择时间戳" -#: changedetectionio/blueprint/ui/templates/preview.html -msgid "Go" -msgstr "前往" - #: changedetectionio/blueprint/ui/templates/preview.html msgid "Current erroring screenshot from most recent request" msgstr "最近请求的错误截图" @@ -2453,6 +2468,11 @@ msgstr "无库存" msgid "Price" msgstr "价格" +#: changedetectionio/blueprint/watchlist/templates/watch-overview.html +#, python-format +msgid "Price change since previous price (%(prev)s)" +msgstr "" + #: changedetectionio/blueprint/watchlist/templates/watch-overview.html msgid "No information" msgstr "暂无信息" @@ -3185,6 +3205,18 @@ msgstr "启用站点图标" msgid "Use page <title> in watch overview list" msgstr "在监控概览列表中使用页面 <title>" +#: changedetectionio/forms.py +msgid "Relative time format" +msgstr "" + +#: changedetectionio/forms.py +msgid "Long (1 minute ago)" +msgstr "" + +#: changedetectionio/forms.py +msgid "Short (1m ago)" +msgstr "" + #: changedetectionio/forms.py msgid "API access token security check enabled" msgstr "已启用 API 访问令牌安全检查" @@ -3345,6 +3377,132 @@ msgstr "用于提取的正则表达式" msgid "Extract as CSV" msgstr "提取为 CSV" +#: changedetectionio/languages.py +msgid "just now" +msgstr "刚刚" + +#: changedetectionio/languages.py +msgid "right now" +msgstr "一会儿" + +#: changedetectionio/languages.py +#, python-format +msgid "%ss ago" +msgstr "%s秒前" + +#: changedetectionio/languages.py +#, python-format +msgid "in %ss" +msgstr "%s秒后" + +#: changedetectionio/languages.py +msgid "1m ago" +msgstr "1分前" + +#: changedetectionio/languages.py +msgid "in 1m" +msgstr "1分后" + +#: changedetectionio/languages.py +#, python-format +msgid "%sm ago" +msgstr "%s分前" + +#: changedetectionio/languages.py +#, python-format +msgid "in %sm" +msgstr "%s分后" + +#: changedetectionio/languages.py +msgid "1h ago" +msgstr "1时前" + +#: changedetectionio/languages.py +msgid "in 1h" +msgstr "1时后" + +#: changedetectionio/languages.py +#, python-format +msgid "%sh ago" +msgstr "%s时前" + +#: changedetectionio/languages.py +#, python-format +msgid "in %sh" +msgstr "%s时后" + +#: changedetectionio/languages.py +msgid "1d ago" +msgstr "1天前" + +#: changedetectionio/languages.py +msgid "in 1d" +msgstr "1天后" + +#: changedetectionio/languages.py +#, python-format +msgid "%sd ago" +msgstr "%s天前" + +#: changedetectionio/languages.py +#, python-format +msgid "in %sd" +msgstr "%s天后" + +#: changedetectionio/languages.py +msgid "1w ago" +msgstr "1周前" + +#: changedetectionio/languages.py +msgid "in 1w" +msgstr "1周后" + +#: changedetectionio/languages.py +#, python-format +msgid "%sw ago" +msgstr "%s周前" + +#: changedetectionio/languages.py +#, python-format +msgid "in %sw" +msgstr "%s周后" + +#: changedetectionio/languages.py +msgid "1mo ago" +msgstr "1月前" + +#: changedetectionio/languages.py +msgid "in 1mo" +msgstr "1月后" + +#: changedetectionio/languages.py +#, python-format +msgid "%smo ago" +msgstr "%s月前" + +#: changedetectionio/languages.py +#, python-format +msgid "in %smo" +msgstr "%s月后" + +#: changedetectionio/languages.py +msgid "1yr ago" +msgstr "1年前" + +#: changedetectionio/languages.py +msgid "in 1yr" +msgstr "1年后" + +#: changedetectionio/languages.py +#, python-format +msgid "%syr ago" +msgstr "%s年前" + +#: changedetectionio/languages.py +#, python-format +msgid "in %syr" +msgstr "%s年后" + #: changedetectionio/processors/extract.py msgid "No matches found while scanning all of the watch history for that RegEx." msgstr "扫描全部监控历史未找到匹配该正则的内容。" @@ -3702,7 +3860,8 @@ msgstr "更多信息" msgid "Use <a target=\"newwindow\" href=\"%(url)s\">AppRise Notification URLs</a> for notification to just about any service!" msgstr "使用 <a target=\"newwindow\" href=\"%(url)s\">AppRise通知URL</a>,向几乎任何服务发送通知!" -# TN: CJK scripts degrade when italicized; emphasis is rendered with <strong> instead. +# TN: CJK scripts degrade when italicized; emphasis is rendered with <strong> +# instead. #. CJK fonts lack native italics; allow substitution with conventional local styling. dennis-ignore: W303 #: changedetectionio/templates/_common_fields.html msgid "<i>Please read the notification services wiki here for important configuration notes</i>" @@ -3974,6 +4133,10 @@ msgstr "输入搜索关键词..." msgid "AI" msgstr "" +#: changedetectionio/templates/edit/include_llm_intent.html +msgid "AI — Notify when…" +msgstr "" + #: changedetectionio/templates/edit/include_llm_intent.html msgid "" "Describe what you care about. The AI evaluates every detected change against this and only notifies you when it " @@ -4318,6 +4481,10 @@ msgstr "" msgid "In queue" msgstr "" +#: changedetectionio/templates/sidebar-nav.html +msgid "Live activity" +msgstr "" + #: changedetectionio/templates/sidebar-nav.html msgid "A new version is available" msgstr "" diff --git a/changedetectionio/translations/zh_Hant_TW/LC_MESSAGES/messages.mo b/changedetectionio/translations/zh_Hant_TW/LC_MESSAGES/messages.mo index 4b7e7b3f..dd030d42 100644 Binary files a/changedetectionio/translations/zh_Hant_TW/LC_MESSAGES/messages.mo and b/changedetectionio/translations/zh_Hant_TW/LC_MESSAGES/messages.mo differ diff --git a/changedetectionio/translations/zh_Hant_TW/LC_MESSAGES/messages.po b/changedetectionio/translations/zh_Hant_TW/LC_MESSAGES/messages.po index 758fefe9..31e62112 100644 --- a/changedetectionio/translations/zh_Hant_TW/LC_MESSAGES/messages.po +++ b/changedetectionio/translations/zh_Hant_TW/LC_MESSAGES/messages.po @@ -23,16 +23,46 @@ msgid "Add a new web page change detection watch" msgstr "新增網頁變更檢測任務" #: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html -msgid "Watch this URL!" -msgstr "監測此 URL!" +#: changedetectionio/blueprint/ui/templates/preview.html +msgid "Go" +msgstr "前往" #: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html -msgid "Edit first then Watch" -msgstr "先編輯後監測" +msgid "Enter a URL to get started!" +msgstr "" #: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html -#: changedetectionio/templates/edit/include_llm_intent.html -msgid "AI — Notify when…" +msgid "Enter a URL in the input box above to get started." +msgstr "" + +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html +msgid "Fetching screenshot and element information…" +msgstr "" + +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html changedetectionio/blueprint/ui/templates/edit.html +msgid "Currently:" +msgstr "目前:" + +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html changedetectionio/blueprint/ui/templates/edit.html +msgid "Select by element" +msgstr "按元素選擇" + +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html +msgid "Hover & click the preview to watch just one part of the page." +msgstr "" + +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html changedetectionio/blueprint/ui/templates/edit.html +msgid "Clear selection" +msgstr "清除選擇" + +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html +msgid "What matters — when to notify me" +msgstr "" + +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html +msgid "" +"e.g. Notify me when products go in/out of stock, lead times change by more than a week, or new product variants " +"appear. Skip review additions." msgstr "" #: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html @@ -40,17 +70,13 @@ msgstr "" msgid "Watch group / tag" msgstr "群組 / 標籤" -#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html changedetectionio/templates/sidebar-nav.html -msgid "Live activity" -msgstr "" +#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html +msgid "Watch this URL!" +msgstr "監測此 URL!" #: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html -msgid "Recent additions and live check status will appear here." -msgstr "" - -#: changedetectionio/blueprint/add_watch_ui/templates/add-watch-ui.html -msgid "Waiting for activity…" -msgstr "" +msgid "Edit first then Watch" +msgstr "先編輯後監測" #: changedetectionio/blueprint/backups/__init__.py msgid "A backup is already running, check back in a few minutes" @@ -271,7 +297,8 @@ msgstr "未通過驗證的 URL 將保留在文字區塊中。" msgid "Copy and Paste your Distill.io watch 'export' file, this should be a JSON file." msgstr "複製並貼上您的 Distill.io 監測任務「匯出」檔案,這應該是一個 JSON 檔案。" -# TN: CJK scripts degrade when italicized; emphasis is rendered with <strong> instead. +# TN: CJK scripts degrade when italicized; emphasis is rendered with <strong> +# instead. #. CJK fonts lack native italics; allow substitution with conventional local styling. dennis-ignore: W303 #: changedetectionio/blueprint/imports/templates/import.html msgid "" @@ -766,6 +793,10 @@ msgstr "" msgid "Number of items per page in the watch overview list, 0 to disable." msgstr "" +#: changedetectionio/blueprint/settings/templates/settings.html +msgid "How \"Last Checked\" and \"Last Changed\" times are shown in the watch overview list." +msgstr "" + #: changedetectionio/blueprint/settings/templates/settings.html msgid "Tip" msgstr "提示" @@ -2003,7 +2034,8 @@ msgid "" "lines against all history for this watch." msgstr "適用於內容僅會移動的網站,且您想知道何時新增了「新」內容,此功能會將新行與此監測任務的所有歷史記錄進行比較。" -# TN: CJK scripts degrade when italicized; UI label reference is wrapped in 「」 instead. +# TN: CJK scripts degrade when italicized; UI label reference is wrapped in 「」 +# instead. #. CJK fonts lack native italics; allow substitution with conventional local styling. dennis-ignore: W303 #: changedetectionio/blueprint/ui/templates/edit.html msgid "Helps reduce changes detected caused by sites shuffling lines around, combine with <i>check unique lines</i> below." @@ -2051,26 +2083,14 @@ msgstr "選擇多個項目。" msgid "Selection Mode:" msgstr "選擇模式:" -#: changedetectionio/blueprint/ui/templates/edit.html -msgid "Select by element" -msgstr "按元素選擇" - #: changedetectionio/blueprint/ui/templates/edit.html msgid "Draw area" msgstr "繪製區域" -#: changedetectionio/blueprint/ui/templates/edit.html -msgid "Clear selection" -msgstr "清除選擇" - #: changedetectionio/blueprint/ui/templates/edit.html msgid "One moment, fetching screenshot and element information.." msgstr "請稍候,正在抓取截圖和元素資訊.." -#: changedetectionio/blueprint/ui/templates/edit.html -msgid "Currently:" -msgstr "目前:" - #: changedetectionio/blueprint/ui/templates/edit.html msgid "Sorry, this functionality only works with fetchers that support Javascript and screenshots (such as playwright etc)." msgstr "抱歉,此功能僅適用於支援 Javascript 和截圖的抓取器(如 playwright 等)。" @@ -2155,10 +2175,6 @@ msgstr "複製並編輯" msgid "Select timestamp" msgstr "選擇時間戳記" -#: changedetectionio/blueprint/ui/templates/preview.html -msgid "Go" -msgstr "前往" - #: changedetectionio/blueprint/ui/templates/preview.html msgid "Current erroring screenshot from most recent request" msgstr "最近請求的目前錯誤截圖" @@ -2452,6 +2468,11 @@ msgstr "無庫存" msgid "Price" msgstr "價格" +#: changedetectionio/blueprint/watchlist/templates/watch-overview.html +#, python-format +msgid "Price change since previous price (%(prev)s)" +msgstr "" + #: changedetectionio/blueprint/watchlist/templates/watch-overview.html msgid "No information" msgstr "無資訊" @@ -3184,6 +3205,18 @@ msgstr "啟用網站圖示 (Favicons)" msgid "Use page <title> in watch overview list" msgstr "在監測概覽列表中使用頁面 <title>" +#: changedetectionio/forms.py +msgid "Relative time format" +msgstr "" + +#: changedetectionio/forms.py +msgid "Long (1 minute ago)" +msgstr "" + +#: changedetectionio/forms.py +msgid "Short (1m ago)" +msgstr "" + #: changedetectionio/forms.py msgid "API access token security check enabled" msgstr "已啟用 API 存取權杖安全檢查" @@ -3344,6 +3377,132 @@ msgstr "要提取的 RegEx" msgid "Extract as CSV" msgstr "提取為 CSV" +#: changedetectionio/languages.py +msgid "just now" +msgstr "剛剛" + +#: changedetectionio/languages.py +msgid "right now" +msgstr "一會兒" + +#: changedetectionio/languages.py +#, python-format +msgid "%ss ago" +msgstr "%s秒前" + +#: changedetectionio/languages.py +#, python-format +msgid "in %ss" +msgstr "%s秒後" + +#: changedetectionio/languages.py +msgid "1m ago" +msgstr "1分前" + +#: changedetectionio/languages.py +msgid "in 1m" +msgstr "1分後" + +#: changedetectionio/languages.py +#, python-format +msgid "%sm ago" +msgstr "%s分前" + +#: changedetectionio/languages.py +#, python-format +msgid "in %sm" +msgstr "%s分後" + +#: changedetectionio/languages.py +msgid "1h ago" +msgstr "1時前" + +#: changedetectionio/languages.py +msgid "in 1h" +msgstr "1時後" + +#: changedetectionio/languages.py +#, python-format +msgid "%sh ago" +msgstr "%s時前" + +#: changedetectionio/languages.py +#, python-format +msgid "in %sh" +msgstr "%s時後" + +#: changedetectionio/languages.py +msgid "1d ago" +msgstr "1天前" + +#: changedetectionio/languages.py +msgid "in 1d" +msgstr "1天後" + +#: changedetectionio/languages.py +#, python-format +msgid "%sd ago" +msgstr "%s天前" + +#: changedetectionio/languages.py +#, python-format +msgid "in %sd" +msgstr "%s天後" + +#: changedetectionio/languages.py +msgid "1w ago" +msgstr "1週前" + +#: changedetectionio/languages.py +msgid "in 1w" +msgstr "1週後" + +#: changedetectionio/languages.py +#, python-format +msgid "%sw ago" +msgstr "%s週前" + +#: changedetectionio/languages.py +#, python-format +msgid "in %sw" +msgstr "%s週後" + +#: changedetectionio/languages.py +msgid "1mo ago" +msgstr "1月前" + +#: changedetectionio/languages.py +msgid "in 1mo" +msgstr "1月後" + +#: changedetectionio/languages.py +#, python-format +msgid "%smo ago" +msgstr "%s月前" + +#: changedetectionio/languages.py +#, python-format +msgid "in %smo" +msgstr "%s月後" + +#: changedetectionio/languages.py +msgid "1yr ago" +msgstr "1年前" + +#: changedetectionio/languages.py +msgid "in 1yr" +msgstr "1年後" + +#: changedetectionio/languages.py +#, python-format +msgid "%syr ago" +msgstr "%s年前" + +#: changedetectionio/languages.py +#, python-format +msgid "in %syr" +msgstr "%s年後" + #: changedetectionio/processors/extract.py msgid "No matches found while scanning all of the watch history for that RegEx." msgstr "掃描此 RegEx 的所有監測歷史記錄時找不到相符項目。" @@ -3972,6 +4131,10 @@ msgstr "輸入搜尋關鍵字 ..." msgid "AI" msgstr "" +#: changedetectionio/templates/edit/include_llm_intent.html +msgid "AI — Notify when…" +msgstr "" + #: changedetectionio/templates/edit/include_llm_intent.html msgid "" "Describe what you care about. The AI evaluates every detected change against this and only notifies you when it " @@ -4316,6 +4479,10 @@ msgstr "" msgid "In queue" msgstr "" +#: changedetectionio/templates/sidebar-nav.html +msgid "Live activity" +msgstr "" + #: changedetectionio/templates/sidebar-nav.html msgid "A new version is available" msgstr ""