From 3bcc93267fb8962fceee1c7d5f338afd7456f828 Mon Sep 17 00:00:00 2001 From: Francis Secada Date: Mon, 2 Feb 2026 20:33:47 -0500 Subject: [PATCH] feat: add Tavily web search tool and comparative multi-entity SWOT MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add `search_web` tool backed by tavily-python for grounded research - Extend SWOT pipeline to accept a primary entity plus optional comparison entities; agent prompt drives comparative analysis when comparators are present - Add `primary_entity` / `comparison_entities` fields to SwotAnalysis model - Wire new form fields (primary + comparison inputs) through router → utils → run_agent - Render entity badges ("vs" header) in result template; fix pre-existing bug where iterating model.dict() leaked the `analysis` string into the SWOT card grid - Add comparison-input and entity-badge SCSS components; recompile CSS - Pin requires-python >=3.12 in pyproject.toml; lock tavily-python 0.7.21 Co-Authored-By: Claude Sonnet 4.5 --- .env.example | 3 + core_requirements.in | 1 + pyproject.toml | 2 + src/backend/core/consts.py | 45 +- src/backend/core/core.py | 2 + src/backend/core/tools.py | 77 ++- src/backend/site/router.py | 24 +- src/backend/site/utils.py | 15 +- src/frontend/scss/_components.scss | 83 +++ src/frontend/static/css/pygentic_ai.css | 2 +- src/frontend/static/css/pygentic_ai.css.map | 2 +- src/frontend/templates/home.html | 34 +- src/frontend/templates/result.html | 44 +- uv.lock | 562 +++++++++++++++++++- 14 files changed, 822 insertions(+), 74 deletions(-) diff --git a/.env.example b/.env.example index ff140e2..8246ca4 100644 --- a/.env.example +++ b/.env.example @@ -31,6 +31,9 @@ SQL_DIALECT=postgresql DEBUG=True SERVER_ENV=dev +# Tavily Web Search +TAVILY_API_KEY=your-tavily-api-key-here + # Reddit API Configuration (for intelligence gathering) REDDIT_MAX_INSIGHTS=5 REDDIT_MAX_INSIGHT_LENGTH=400 diff --git a/core_requirements.in b/core_requirements.in index b7e52fd..92e8c28 100644 --- a/core_requirements.in +++ b/core_requirements.in @@ -31,6 +31,7 @@ simplejson sqlalchemy_mixins sqlmodel sqlmodel-crud-utilities @ git+https://github.com/fsecada01/SQLModel-CRUD-Utilities@v0.0.1a1 +tavily-python typing-inspect uvicorn xmljson diff --git a/pyproject.toml b/pyproject.toml index 8bdaeb7..c3382f3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -74,6 +74,7 @@ classifiers = [ "Operating System :: OS Independent", ] version = "1.0.0b0" +requires-python = ">=3.12" dependencies = [ "aiofiles>=24.1.0", "aiomysql>=0.2.0", @@ -94,6 +95,7 @@ dependencies = [ "lxml[html-clean]>=5.3.0", "openai>=1.60.0", "praw>=7.8.1", + "tavily-python>=0.7.0", "psycopg>=3.2.4", "pydantic-ai[examples]>=0.0.18", "pydantic-settings>=2.7.1", diff --git a/src/backend/core/consts.py b/src/backend/core/consts.py index b86c069..78dbfa4 100644 --- a/src/backend/core/consts.py +++ b/src/backend/core/consts.py @@ -2,22 +2,35 @@ from backend.utils import get_val AI_MODEL = get_val("OPENAI_MODEL", "gpt-4o") default_system_prompt = """ -You are an advanced and intelligent AI assistant specializing in generating -comprehensive and detailed SWOT analyses for a variety of scenarios, topics, -or businesses. +You are an advanced AI assistant specializing in comprehensive SWOT analyses. +You have access to web search (search_web) and website scraping +(fetch_website_content) tools to gather real-world data before forming +conclusions. -Your task is to analyze given entities, situations, or contexts and organize -the information systematically into (typically provided as an URL value): -1. **Strengths**: Internal factors that give a competitive advantage or are beneficial. -2. **Weaknesses**: Internal factors that hinder performance or present challenges. -3. **Opportunities**: External factors that can be leveraged for growth or improvement. -4. **Threats**: External factors that pose risks or challenges. +When given a single entity: +- Research it thoroughly using search_web. If a URL is provided, also use + fetch_website_content to extract page details. +- Generate a detailed SWOT analysis grounded in the gathered intelligence. -Guidelines for your approach: -- Be concise yet descriptive in your explanation for each category. -- Consider internal factors for Strengths and Weaknesses (e.g., resources, -skills, limitations). -- Focus on external or environmental factors for Opportunities and Threats ( -e.g., market trends, competition, external risks). -- Provide additional context or examples to support your points when relevant. +When given a primary entity AND one or more comparison entities: +- Research ALL entities using search_web (and fetch_website_content for URLs). +- Generate a SWOT analysis FOCUSED on the primary entity. +- Weave comparative insights into every SWOT category — explicitly reference + how the primary entity stacks up against each competitor. +- The analysis (executive summary) must highlight key competitive + differentiators between the entities. + +SWOT Categories: +1. **Strengths**: Internal advantages of the primary entity (vs competitors). +2. **Weaknesses**: Internal disadvantages relative to competitors. +3. **Opportunities**: External factors the primary entity can leverage. +4. **Threats**: External risks, especially those posed by the compared entities. + +Output requirements: +- Populate primary_entity with exactly what was provided as the primary subject. +- Populate comparison_entities with the list of entities being compared against + (empty list if single-entity mode). +- Deliver at least 3 points per SWOT category. +- Back every point with specific evidence from your research. +- The analysis field must be a substantive executive summary (150+ characters). """ diff --git a/src/backend/core/core.py b/src/backend/core/core.py index 89063b9..1999d5f 100644 --- a/src/backend/core/core.py +++ b/src/backend/core/core.py @@ -16,6 +16,8 @@ from backend.utils import get_val class SwotAnalysis(Base): """SQLModel for SWOT Analysis Response Object""" + primary_entity: str + comparison_entities: list[str] = [] strengths: list[str] weaknesses: list[str] opportunities: list[str] diff --git a/src/backend/core/tools.py b/src/backend/core/tools.py index 527dd3f..2a55549 100644 --- a/src/backend/core/tools.py +++ b/src/backend/core/tools.py @@ -3,6 +3,7 @@ import asyncio import httpx from bs4 import BeautifulSoup as soup from pydantic_ai import ModelRetry, RunContext +from tavily import TavilyClient from backend.core.consts import AI_MODEL from backend.core.core import SwotAgentDeps, SwotAnalysis, swot_agent @@ -37,6 +38,43 @@ async def fetch_website_content( raise +@swot_agent.tool(prepare=report_tool_usage) +async def search_web( + _ctx: RunContext[SwotAgentDeps], + query: str, +) -> str: + """ + Searches the web using Tavily and returns a formatted summary of results. + Use this to research companies, products, market trends, or any topic. + + :param _ctx: RunContext[SwotAgentDeps] + :param query: str - the search query + :return: str - formatted search results with answer and top snippets + """ + logger.info(f"Tavily web search: {query}") + client = TavilyClient(api_key=get_val("TAVILY_API_KEY")) + + response = await asyncio.to_thread( + client.search, + query, + include_answer=True, + max_results=5, + ) + + parts = [] + if response.get("answer"): + parts.append(f"Summary: {response['answer']}") + + for r in response.get("results", []): + parts.append( + f"Title: {r['title']}\n" + f"URL: {r['url']}\n" + f"Content: {r.get('content', '')}" + ) + + return "\n\n".join(parts) if parts else "No results found." + + @swot_agent.tool(prepare=report_tool_usage) async def analyze_competition( ctx: RunContext[SwotAgentDeps], @@ -168,23 +206,46 @@ def validate_result( async def run_agent( - url: str, + primary_entity: str, + comparison_entities: list[str] | None = None, deps: SwotAgentDeps = SwotAgentDeps(), ) -> SwotAnalysis | Exception: """ - Runs the SWOT Analysis Agent + Runs the SWOT Analysis Agent. When comparison_entities is provided the + agent produces a comparative SWOT focused on primary_entity. - :param url: str + :param primary_entity: str - main subject (URL or company name) + :param comparison_entities: list[str] | None - entities to compare against :param deps: SwotAgentDeps :return: SwotAnalysis | Exception """ try: deps.tool_history = [] - result = await swot_agent.run( - f"Perform a comprehensive SWOT analysis for this product: {url}", - deps=deps, - ) - # logger.debug(f"Agent Result: {pformat(result.data.model_dump())}") + + if comparison_entities: + comp_str = ", ".join(comparison_entities) + prompt = ( + f"Perform a comparative SWOT analysis.\n" + f"Primary entity: {primary_entity}\n" + f"Compare against: {comp_str}\n\n" + f"Research every entity with search_web. If any entity " + f"looks like a URL, also call fetch_website_content on it.\n" + f"The SWOT must centre on {primary_entity} but explicitly " + f"contrast it with {comp_str} in each category.\n" + f'Set primary_entity to "{primary_entity}" and ' + f"comparison_entities to {comparison_entities} in your output." + ) + else: + prompt = ( + f"Perform a comprehensive SWOT analysis for: " + f"{primary_entity}\n" + f"Use search_web to research this entity. If it is a URL, " + f"also use fetch_website_content to gather details.\n" + f'Set primary_entity to "{primary_entity}" and ' + f"comparison_entities to an empty list in your output." + ) + + result = await swot_agent.run(prompt, deps=deps) if deps.update_status_func: await deps.update_status_func(deps.request, "Analysis Complete") diff --git a/src/backend/site/router.py b/src/backend/site/router.py index fc640d2..3b8e87f 100644 --- a/src/backend/site/router.py +++ b/src/backend/site/router.py @@ -41,11 +41,16 @@ user_frontend.mount( @user_frontend.post("/analyze", response_class=HTMLResponse) -async def analyze_url(request: Request, url: str = Form(...)) -> HTMLResponse: +async def analyze_url( + request: Request, + primary_entity: str = Form(...), + comparison_entities: str = Form(""), +) -> HTMLResponse: """ - Analyze a given URL using SWOT analysis agent + Kick off a SWOT analysis for one or more entities. :param request: - :param url: + :param primary_entity: main subject (URL or company name) + :param comparison_entities: comma-separated competitors (optional) :return: """ session_id = str(id(request)) @@ -58,9 +63,18 @@ async def analyze_url(request: Request, url: str = Form(...)) -> HTMLResponse: status_store[session_id].append(ANALYZING_MESSAGE) - logger.info(f"Starting new analysis with session ID: {session_id}") + comp_entities = [ + e.strip() for e in comparison_entities.split(",") if e.strip() + ] - task = asyncio.create_task(run_agent_with_progress(session_id, url)) + logger.info( + f"Starting analysis — session: {session_id}, " + f"primary: {primary_entity}, comparing: {comp_entities}" + ) + + task = asyncio.create_task( + run_agent_with_progress(session_id, primary_entity, comp_entities) + ) running_tasks.add(task) task.add_done_callback(running_tasks.discard) diff --git a/src/backend/site/utils.py b/src/backend/site/utils.py index 189db7f..1909d03 100644 --- a/src/backend/site/utils.py +++ b/src/backend/site/utils.py @@ -62,13 +62,16 @@ async def update_status(session_id: str, message: Any) -> None: ) -async def run_agent_with_progress(session_id, url): +async def run_agent_with_progress( + session_id, primary_entity, comparison_entities=None +): """ This provides ongoing progress updates for a running agent. A custom deps object is used to store the session_id value and then triggers the `run_agent` function :param session_id: str - :param url: str + :param primary_entity: str + :param comparison_entities: list[str] | None :return: None """ try: @@ -80,10 +83,14 @@ async def run_agent_with_progress(session_id, url): ), ) - result = await run_agent(url=url, deps=deps) + result = await run_agent( + primary_entity=primary_entity, + comparison_entities=comparison_entities, + deps=deps, + ) if not isinstance(result, Exception): - logger.info(f"Successfully analyzed URL: {url}") + logger.info(f"Successfully analyzed: {primary_entity}") logger.debug(pformat(f"Result object: {result}")) result_store[session_id] = result except Exception as e: diff --git a/src/frontend/scss/_components.scss b/src/frontend/scss/_components.scss index 7b473bd..7b91e69 100644 --- a/src/frontend/scss/_components.scss +++ b/src/frontend/scss/_components.scss @@ -192,6 +192,89 @@ } } +// Comparison Input +// =================================== +.comparison-input-group { + display: flex; + align-items: center; + background: white; + border-radius: $radius-full; + padding: 0.5rem; + margin-top: 0.75rem; + box-shadow: $shadow-lg; + transition: all $transition-base; + + &:focus-within { + box-shadow: 0 8px 20px rgba($brand-primary, 0.15); + } +} + +.comparison-icon { + padding: 0 1rem; + color: $neutral-400; + font-size: 1rem; +} + +.comparison-input { + flex: 1; + border: none; + outline: none; + padding: 0.75rem 1rem; + font-size: 0.9rem; + background: transparent; + color: $neutral-900; + + &::placeholder { + color: $neutral-400; + } +} + +// Entity Badges (Results Header) +// =================================== +.entity-header { + display: flex; + align-items: center; + justify-content: center; + flex-wrap: wrap; + gap: 0.5rem; +} + +.entity-header__vs { + font-weight: 700; + font-size: 0.85rem; + color: $neutral-600; + text-transform: uppercase; + letter-spacing: 0.05em; +} + +.entity-header__sep { + color: $neutral-400; +} + +.entity-badge { + display: inline-flex; + align-items: center; + padding: 0.4rem 0.9rem; + border-radius: $radius-full; + font-size: 0.875rem; + font-weight: 600; + + i { + margin-right: 0.35rem; + } + + &--primary { + background: $brand-primary; + color: white; + } + + &--comparison { + background: rgba($neutral-400, 0.1); + color: $neutral-600; + border: 1px solid rgba($neutral-400, 0.3); + } +} + // Smooth transitions for all interactive elements button, a, diff --git a/src/frontend/static/css/pygentic_ai.css b/src/frontend/static/css/pygentic_ai.css index d1ba66c..30cb825 100644 --- a/src/frontend/static/css/pygentic_ai.css +++ b/src/frontend/static/css/pygentic_ai.css @@ -2,4 +2,4 @@ * Pygentic AI - Main Stylesheet * Compiled from SCSS partials * Version: 1.0.0 - */@import"https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Space+Grotesk:wght@500;600;700&display=swap";body{font-family:"Inter",-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen,Ubuntu,Cantarell,sans-serif;font-feature-settings:"cv02","cv03","cv04","cv11";-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.title,.subtitle,h1,h2,h3,h4,h5,h6{font-family:"Space Grotesk","Inter",sans-serif;letter-spacing:-0.02em;font-weight:600}.hero-title{font-size:clamp(2.5rem,5vw,4rem);font-weight:700;background:linear-gradient(135deg, #8B5CF6 0%, #6D28D9 100%);-webkit-background-clip:text;-webkit-text-fill-color:rgba(0,0,0,0);background-clip:text;margin-bottom:1rem;line-height:1.1}@keyframes spin{from{transform:rotate(0deg)}to{transform:rotate(360deg)}}@keyframes float{0%,100%{transform:translateY(0px)}50%{transform:translateY(-10px)}}@keyframes pulse{0%,100%{box-shadow:0 0 0 0 rgba(139,92,246,.7)}50%{box-shadow:0 0 0 10px rgba(139,92,246,0)}}@keyframes slideUp{from{opacity:0;transform:translateY(20px)}to{opacity:1;transform:translateY(0)}}@keyframes fadeIn{from{opacity:0}to{opacity:1}}@keyframes shake{0%,100%{transform:translateX(0)}25%{transform:translateX(-10px)}75%{transform:translateX(10px)}}@keyframes iconPulse{0%,100%{transform:scale(1)}50%{transform:scale(1.1)}}@keyframes containerFadeIn{from{opacity:0;transform:translateY(30px)}to{opacity:1;transform:translateY(0)}}@keyframes statusFadeIn{from{opacity:0;transform:translateX(-10px)}to{opacity:1;transform:translateX(0)}}@keyframes statusPulse{0%,100%{box-shadow:0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -1px rgba(0,0,0,.06)}50%{box-shadow:0 4px 20px rgba(245,158,11,.3)}}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);white-space:nowrap;border-width:0}.skip-link{position:absolute;top:-40px;left:0;background:#8b5cf6;color:#fff;padding:.75rem 1.5rem;text-decoration:none;font-weight:600;z-index:10000;border-radius:0 0 12px 0;transition:top 150ms cubic-bezier(0.4, 0, 0.2, 1)}.skip-link:focus{top:0}.spinner-wrapper{position:fixed;top:0;left:0;width:100%;height:100%;background-color:hsla(0,0%,100%,.95);backdrop-filter:blur(8px);display:flex;justify-content:center;align-items:center;z-index:9999}.loading-content{text-align:center}.loader{border:4px solid rgba(139,92,246,.1);border-top:4px solid #8b5cf6;border-radius:50%;width:60px;height:60px;animation:spin .8s linear infinite;margin:0 auto}.loading-text{margin-top:1.5rem}.loading-text h3{font-size:1.25rem;font-weight:600;color:#111827;margin-bottom:.5rem}.loading-text p{font-size:.875rem;color:#4b5563}.search-container{max-width:800px;margin:0 auto;padding:2rem 1rem}.search-form{width:100%}.search-input-group{display:flex;align-items:center;background:#fff;border-radius:9999px;padding:.5rem;box-shadow:0 20px 25px -5px rgba(0,0,0,.1),0 10px 10px -5px rgba(0,0,0,.04);transition:all 300ms cubic-bezier(0.4, 0, 0.2, 1)}.search-input-group:focus-within{box-shadow:0 20px 40px rgba(139,92,246,.2);transform:translateY(-2px)}.search-icon{padding:0 1rem;color:#9ca3af;font-size:1.25rem}.search-input{flex:1;border:none;outline:none;padding:.875rem 1rem;font-size:1rem;background:rgba(0,0,0,0);color:#111827}.search-input::placeholder{color:#9ca3af}.search-button{background:#8b5cf6;color:#fff;border:none;border-radius:9999px;padding:.875rem 2rem;font-weight:600;font-size:1rem;cursor:pointer;display:flex;align-items:center;gap:.5rem;transition:all 300ms cubic-bezier(0.4, 0, 0.2, 1);white-space:nowrap}.search-button:hover{background:#7c3aed;transform:translateX(2px);box-shadow:0 10px 15px -3px rgba(0,0,0,.1),0 4px 6px -2px rgba(0,0,0,.05)}.search-button:active{transform:scale(0.95)}.search-button:focus{outline:2px solid #a78bfa;outline-offset:2px}.search-button.is-loading{position:relative;color:rgba(0,0,0,0);pointer-events:none}.search-button.is-loading::after{content:"";position:absolute;width:16px;height:16px;top:50%;left:50%;margin-left:-8px;margin-top:-8px;border:2px solid rgba(0,0,0,0);border-top-color:#fff;border-radius:50%;animation:spin .6s linear infinite}.search-help{margin-top:1rem;text-align:center;color:#4b5563;font-size:.875rem}.search-help i{margin-right:.25rem;color:#8b5cf6}button,a,input,.swot-card,.swot-card__icon{transition:all 300ms cubic-bezier(0.4, 0, 0.2, 1)}:focus-visible{outline:2px solid #8b5cf6;outline-offset:2px}.gradient-hero{background:linear-gradient(135deg, #667eea 0%, #764ba2 100%) !important;position:relative;overflow:hidden}.hero-icon img{filter:brightness(0) invert(1);animation:float 3s ease-in-out infinite}.hero-icon img:hover{animation:float 1s ease-in-out infinite;filter:brightness(0) invert(1) drop-shadow(0 0 20px rgba(255, 255, 255, 0.5))}.hero-cta .button{animation:pulse 2s infinite}.swot-grid{display:grid;grid-template-columns:repeat(auto-fit, minmax(300px, 1fr));gap:1.5rem;margin-top:2rem}.swot-card{background:#fff;border-radius:16px;padding:1.5rem;box-shadow:0 10px 15px -3px rgba(0,0,0,.1),0 4px 6px -2px rgba(0,0,0,.05);transition:all 300ms cubic-bezier(0.4, 0, 0.2, 1);border-top:4px solid var(--card-color);animation:slideUp .5s ease-out backwards}.swot-card:hover{transform:translateY(-4px);box-shadow:0 25px 50px -12px rgba(0,0,0,.25)}.swot-card:hover .swot-card__icon{animation:iconPulse .5s ease-out}.swot-card--strength{--card-color: #10B981}.swot-card--weakness{--card-color: #F59E0B}.swot-card--opportunity{--card-color: #3B82F6}.swot-card--threat{--card-color: #EF4444}.swot-card__header{display:flex;align-items:center;gap:.75rem;margin-bottom:1rem;padding-bottom:1rem;border-bottom:1px solid #e5e7eb}.swot-card__icon{width:48px;height:48px;border-radius:12px;background:var(--card-color);display:flex;align-items:center;justify-content:center;color:#fff;font-size:1.5rem;flex-shrink:0}.swot-card__title{font-weight:600;font-size:1.375rem;color:#111827;flex-grow:1;margin:0}.swot-card__count{background:#f3f4f6;padding:.25rem .75rem;border-radius:20px;font-size:.875rem;font-weight:600;color:#374151;flex-shrink:0}.swot-card__body{overflow:hidden}.swot-list{list-style:none;padding:0;margin:0}.swot-list__item{display:flex;align-items:flex-start;gap:.75rem;padding:.75rem 0;border-bottom:1px solid #f3f4f6;animation:fadeIn .3s ease-out backwards}.swot-list__item:last-child{border-bottom:none}.swot-list__item:nth-child(1){animation-delay:0.1s}.swot-list__item:nth-child(2){animation-delay:0.2s}.swot-list__item:nth-child(3){animation-delay:0.3s}.swot-list__item:nth-child(4){animation-delay:0.4s}.swot-list__item:nth-child(5){animation-delay:0.5s}.swot-list__item:nth-child(6){animation-delay:0.6s}.swot-list__item:nth-child(7){animation-delay:0.7s}.swot-list__item:nth-child(8){animation-delay:0.8s}.swot-list__item:nth-child(9){animation-delay:0.9s}.swot-list__item:nth-child(10){animation-delay:1s}.swot-list__bullet{width:6px;height:6px;border-radius:50%;background:var(--card-color);margin-top:.5rem;flex-shrink:0}.swot-list__text{flex:1;color:#374151;line-height:1.6}.swot-card:nth-child(1){animation-delay:0.1s}.swot-card:nth-child(2){animation-delay:0.2s}.swot-card:nth-child(3){animation-delay:0.3s}.swot-card:nth-child(4){animation-delay:0.4s}#result-container.animate-in{animation:containerFadeIn .6s ease-out}.status-timeline{position:relative;padding-left:2rem}.status-timeline::before{content:"";position:absolute;left:14px;top:24px;bottom:24px;width:2px;background:#e5e7eb}.status-item{position:relative;padding:1rem 0 1rem 2rem;animation:statusFadeIn .3s ease-out}.status-item--info .status-item__indicator,.status-item--info .status-item__header{color:#3b82f6}.status-item--loading .status-item__indicator,.status-item--loading .status-item__header{color:#f59e0b}.status-item--loading .status-item__content{animation:statusPulse 2s ease-in-out infinite}.status-item--success .status-item__indicator,.status-item--success .status-item__header{color:#10b981}.status-item--error .status-item__indicator,.status-item--error .status-item__header{color:#ef4444}.status-item__indicator{position:absolute;left:0;top:1.25rem;width:30px;height:30px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:1rem;background:#fff;box-shadow:0 0 0 4px #fff;z-index:1}.status-item__content{background:#fff;border-radius:12px;padding:1rem 1.25rem;box-shadow:0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -1px rgba(0,0,0,.06);transition:all 300ms cubic-bezier(0.4, 0, 0.2, 1)}.status-item:hover .status-item__content{box-shadow:0 10px 15px -3px rgba(0,0,0,.1),0 4px 6px -2px rgba(0,0,0,.05);transform:translateX(4px)}.status-item__header{font-weight:600;font-size:.875rem;text-transform:uppercase;letter-spacing:.05em;margin-bottom:.5rem}.status-item__message{color:#374151;line-height:1.6;font-size:.9375rem}.empty-state{display:flex;align-items:center;justify-content:center;min-height:400px;padding:3rem 1.5rem}.empty-state__content{text-align:center;max-width:500px}.empty-state__icon{width:120px;height:120px;margin:0 auto 2rem;border-radius:50%;background:linear-gradient(135deg, #F3F4F6 0%, #E5E7EB 100%);display:flex;align-items:center;justify-content:center;font-size:3rem;color:#9ca3af;animation:float 3s ease-in-out infinite}.empty-state__title{font-size:1.75rem;font-weight:600;color:#1f2937;margin-bottom:.75rem}.empty-state__description{font-size:1.125rem;color:#4b5563;line-height:1.6;margin-bottom:1.5rem}.empty-state__cta{display:inline-flex;align-items:center;gap:.5rem;padding:.875rem 2rem;background:#8b5cf6;color:#fff;border-radius:9999px;text-decoration:none;font-weight:600;transition:all 300ms cubic-bezier(0.4, 0, 0.2, 1);box-shadow:0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -1px rgba(0,0,0,.06)}.empty-state__cta:hover{background:#7c3aed;transform:translateY(-2px);box-shadow:0 10px 15px -3px rgba(0,0,0,.1),0 4px 6px -2px rgba(0,0,0,.05);color:#fff}.error-state{display:flex;align-items:center;justify-content:center;min-height:400px;padding:3rem 1.5rem}.error-state__content{text-align:center;max-width:500px}.error-state__icon{width:120px;height:120px;margin:0 auto 2rem;border-radius:50%;background:linear-gradient(135deg, #FEE2E2 0%, #FEF2F2 100%);display:flex;align-items:center;justify-content:center;font-size:3rem;color:#ef4444;animation:shake .5s ease-in-out}.error-state__title{font-size:1.75rem;font-weight:600;color:#1f2937;margin-bottom:.75rem}.error-state__description{font-size:1.125rem;color:#4b5563;line-height:1.6;margin-bottom:1.5rem}.error-state__details{background:#f3f4f6;border-radius:12px;padding:1rem;margin:1.5rem 0;font-family:"Courier New",monospace;font-size:.875rem;color:#374151;text-align:left;overflow-x:auto}.error-state__actions{display:flex;gap:1rem;justify-content:center;flex-wrap:wrap}.error-state__button{display:inline-flex;align-items:center;gap:.5rem;padding:.875rem 2rem;border-radius:9999px;font-weight:600;transition:all 300ms cubic-bezier(0.4, 0, 0.2, 1);box-shadow:0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -1px rgba(0,0,0,.06);cursor:pointer;border:none;text-decoration:none}.error-state__button--primary{background:#8b5cf6;color:#fff}.error-state__button--primary:hover{background:#7c3aed;transform:translateY(-2px);box-shadow:0 10px 15px -3px rgba(0,0,0,.1),0 4px 6px -2px rgba(0,0,0,.05);color:#fff}.error-state__button--secondary{background:#fff;color:#374151;border:2px solid #d1d5db}.error-state__button--secondary:hover{background:#f3f4f6;border-color:#9ca3af;transform:translateY(-2px);color:#1f2937}@media(max-width: 768px){.cell.is-col-span-2{grid-column:span 1}.swot-grid{grid-template-columns:1fr}.hero-title{font-size:2rem}.search-input-group{flex-direction:column;gap:.5rem;border-radius:20px;padding:1rem}.search-input{width:100%;text-align:center}.search-button{width:100%;justify-content:center}.swot-card__header{flex-wrap:wrap}.swot-card__count{order:-1;margin-left:auto}}@media(max-width: 480px){.swot-card{padding:1rem}.swot-card__icon{width:40px;height:40px;font-size:1.25rem}.swot-card__title{font-size:1.125rem}.hero-title{font-size:1.75rem}.status-timeline{padding-left:1.5rem}.status-item{padding-left:1.5rem}}:root{--brand-primary: #8B5CF6;--brand-primary-light: #A78BFA;--brand-primary-dark: #7C3AED;--swot-strength: #10B981;--swot-weakness: #F59E0B;--swot-opportunity: #3B82F6;--swot-threat: #EF4444;--neutral-50: #F9FAFB;--neutral-100: #F3F4F6;--neutral-200: #E5E7EB;--neutral-300: #D1D5DB;--neutral-400: #9CA3AF;--neutral-500: #6B7280;--neutral-600: #4B5563;--neutral-700: #374151;--neutral-800: #1F2937;--neutral-900: #111827;--shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05);--shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);--shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);--shadow-xl: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);--shadow-2xl: 0 25px 50px -12px rgba(0, 0, 0, 0.25);--transition-fast: 150ms cubic-bezier(0.4, 0, 0.2, 1);--transition-base: 300ms cubic-bezier(0.4, 0, 0.2, 1);--transition-slow: 500ms cubic-bezier(0.4, 0, 0.2, 1)}/*# sourceMappingURL=pygentic_ai.css.map */ + */@import"https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Space+Grotesk:wght@500;600;700&display=swap";body{font-family:"Inter",-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen,Ubuntu,Cantarell,sans-serif;font-feature-settings:"cv02","cv03","cv04","cv11";-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.title,.subtitle,h1,h2,h3,h4,h5,h6{font-family:"Space Grotesk","Inter",sans-serif;letter-spacing:-0.02em;font-weight:600}.hero-title{font-size:clamp(2.5rem,5vw,4rem);font-weight:700;background:linear-gradient(135deg, #8B5CF6 0%, #6D28D9 100%);-webkit-background-clip:text;-webkit-text-fill-color:rgba(0,0,0,0);background-clip:text;margin-bottom:1rem;line-height:1.1}@keyframes spin{from{transform:rotate(0deg)}to{transform:rotate(360deg)}}@keyframes float{0%,100%{transform:translateY(0px)}50%{transform:translateY(-10px)}}@keyframes pulse{0%,100%{box-shadow:0 0 0 0 rgba(139,92,246,.7)}50%{box-shadow:0 0 0 10px rgba(139,92,246,0)}}@keyframes slideUp{from{opacity:0;transform:translateY(20px)}to{opacity:1;transform:translateY(0)}}@keyframes fadeIn{from{opacity:0}to{opacity:1}}@keyframes shake{0%,100%{transform:translateX(0)}25%{transform:translateX(-10px)}75%{transform:translateX(10px)}}@keyframes iconPulse{0%,100%{transform:scale(1)}50%{transform:scale(1.1)}}@keyframes containerFadeIn{from{opacity:0;transform:translateY(30px)}to{opacity:1;transform:translateY(0)}}@keyframes statusFadeIn{from{opacity:0;transform:translateX(-10px)}to{opacity:1;transform:translateX(0)}}@keyframes statusPulse{0%,100%{box-shadow:0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -1px rgba(0,0,0,.06)}50%{box-shadow:0 4px 20px rgba(245,158,11,.3)}}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);white-space:nowrap;border-width:0}.skip-link{position:absolute;top:-40px;left:0;background:#8b5cf6;color:#fff;padding:.75rem 1.5rem;text-decoration:none;font-weight:600;z-index:10000;border-radius:0 0 12px 0;transition:top 150ms cubic-bezier(0.4, 0, 0.2, 1)}.skip-link:focus{top:0}.spinner-wrapper{position:fixed;top:0;left:0;width:100%;height:100%;background-color:hsla(0,0%,100%,.95);backdrop-filter:blur(8px);display:flex;justify-content:center;align-items:center;z-index:9999}.loading-content{text-align:center}.loader{border:4px solid rgba(139,92,246,.1);border-top:4px solid #8b5cf6;border-radius:50%;width:60px;height:60px;animation:spin .8s linear infinite;margin:0 auto}.loading-text{margin-top:1.5rem}.loading-text h3{font-size:1.25rem;font-weight:600;color:#111827;margin-bottom:.5rem}.loading-text p{font-size:.875rem;color:#4b5563}.search-container{max-width:800px;margin:0 auto;padding:2rem 1rem}.search-form{width:100%}.search-input-group{display:flex;align-items:center;background:#fff;border-radius:9999px;padding:.5rem;box-shadow:0 20px 25px -5px rgba(0,0,0,.1),0 10px 10px -5px rgba(0,0,0,.04);transition:all 300ms cubic-bezier(0.4, 0, 0.2, 1)}.search-input-group:focus-within{box-shadow:0 20px 40px rgba(139,92,246,.2);transform:translateY(-2px)}.search-icon{padding:0 1rem;color:#9ca3af;font-size:1.25rem}.search-input{flex:1;border:none;outline:none;padding:.875rem 1rem;font-size:1rem;background:rgba(0,0,0,0);color:#111827}.search-input::placeholder{color:#9ca3af}.search-button{background:#8b5cf6;color:#fff;border:none;border-radius:9999px;padding:.875rem 2rem;font-weight:600;font-size:1rem;cursor:pointer;display:flex;align-items:center;gap:.5rem;transition:all 300ms cubic-bezier(0.4, 0, 0.2, 1);white-space:nowrap}.search-button:hover{background:#7c3aed;transform:translateX(2px);box-shadow:0 10px 15px -3px rgba(0,0,0,.1),0 4px 6px -2px rgba(0,0,0,.05)}.search-button:active{transform:scale(0.95)}.search-button:focus{outline:2px solid #a78bfa;outline-offset:2px}.search-button.is-loading{position:relative;color:rgba(0,0,0,0);pointer-events:none}.search-button.is-loading::after{content:"";position:absolute;width:16px;height:16px;top:50%;left:50%;margin-left:-8px;margin-top:-8px;border:2px solid rgba(0,0,0,0);border-top-color:#fff;border-radius:50%;animation:spin .6s linear infinite}.search-help{margin-top:1rem;text-align:center;color:#4b5563;font-size:.875rem}.search-help i{margin-right:.25rem;color:#8b5cf6}.comparison-input-group{display:flex;align-items:center;background:#fff;border-radius:9999px;padding:.5rem;margin-top:.75rem;box-shadow:0 10px 15px -3px rgba(0,0,0,.1),0 4px 6px -2px rgba(0,0,0,.05);transition:all 300ms cubic-bezier(0.4, 0, 0.2, 1)}.comparison-input-group:focus-within{box-shadow:0 8px 20px rgba(139,92,246,.15)}.comparison-icon{padding:0 1rem;color:#9ca3af;font-size:1rem}.comparison-input{flex:1;border:none;outline:none;padding:.75rem 1rem;font-size:.9rem;background:rgba(0,0,0,0);color:#111827}.comparison-input::placeholder{color:#9ca3af}.entity-header{display:flex;align-items:center;justify-content:center;flex-wrap:wrap;gap:.5rem}.entity-header__vs{font-weight:700;font-size:.85rem;color:#4b5563;text-transform:uppercase;letter-spacing:.05em}.entity-header__sep{color:#9ca3af}.entity-badge{display:inline-flex;align-items:center;padding:.4rem .9rem;border-radius:9999px;font-size:.875rem;font-weight:600}.entity-badge i{margin-right:.35rem}.entity-badge--primary{background:#8b5cf6;color:#fff}.entity-badge--comparison{background:rgba(156,163,175,.1);color:#4b5563;border:1px solid rgba(156,163,175,.3)}button,a,input,.swot-card,.swot-card__icon{transition:all 300ms cubic-bezier(0.4, 0, 0.2, 1)}:focus-visible{outline:2px solid #8b5cf6;outline-offset:2px}.gradient-hero{background:linear-gradient(135deg, #667eea 0%, #764ba2 100%) !important;position:relative;overflow:hidden}.hero-icon img{filter:brightness(0) invert(1);animation:float 3s ease-in-out infinite}.hero-icon img:hover{animation:float 1s ease-in-out infinite;filter:brightness(0) invert(1) drop-shadow(0 0 20px rgba(255, 255, 255, 0.5))}.hero-cta .button{animation:pulse 2s infinite}.swot-grid{display:grid;grid-template-columns:repeat(auto-fit, minmax(300px, 1fr));gap:1.5rem;margin-top:2rem}.swot-card{background:#fff;border-radius:16px;padding:1.5rem;box-shadow:0 10px 15px -3px rgba(0,0,0,.1),0 4px 6px -2px rgba(0,0,0,.05);transition:all 300ms cubic-bezier(0.4, 0, 0.2, 1);border-top:4px solid var(--card-color);animation:slideUp .5s ease-out backwards}.swot-card:hover{transform:translateY(-4px);box-shadow:0 25px 50px -12px rgba(0,0,0,.25)}.swot-card:hover .swot-card__icon{animation:iconPulse .5s ease-out}.swot-card--strength{--card-color: #10B981}.swot-card--weakness{--card-color: #F59E0B}.swot-card--opportunity{--card-color: #3B82F6}.swot-card--threat{--card-color: #EF4444}.swot-card__header{display:flex;align-items:center;gap:.75rem;margin-bottom:1rem;padding-bottom:1rem;border-bottom:1px solid #e5e7eb}.swot-card__icon{width:48px;height:48px;border-radius:12px;background:var(--card-color);display:flex;align-items:center;justify-content:center;color:#fff;font-size:1.5rem;flex-shrink:0}.swot-card__title{font-weight:600;font-size:1.375rem;color:#111827;flex-grow:1;margin:0}.swot-card__count{background:#f3f4f6;padding:.25rem .75rem;border-radius:20px;font-size:.875rem;font-weight:600;color:#374151;flex-shrink:0}.swot-card__body{overflow:hidden}.swot-list{list-style:none;padding:0;margin:0}.swot-list__item{display:flex;align-items:flex-start;gap:.75rem;padding:.75rem 0;border-bottom:1px solid #f3f4f6;animation:fadeIn .3s ease-out backwards}.swot-list__item:last-child{border-bottom:none}.swot-list__item:nth-child(1){animation-delay:0.1s}.swot-list__item:nth-child(2){animation-delay:0.2s}.swot-list__item:nth-child(3){animation-delay:0.3s}.swot-list__item:nth-child(4){animation-delay:0.4s}.swot-list__item:nth-child(5){animation-delay:0.5s}.swot-list__item:nth-child(6){animation-delay:0.6s}.swot-list__item:nth-child(7){animation-delay:0.7s}.swot-list__item:nth-child(8){animation-delay:0.8s}.swot-list__item:nth-child(9){animation-delay:0.9s}.swot-list__item:nth-child(10){animation-delay:1s}.swot-list__bullet{width:6px;height:6px;border-radius:50%;background:var(--card-color);margin-top:.5rem;flex-shrink:0}.swot-list__text{flex:1;color:#374151;line-height:1.6}.swot-card:nth-child(1){animation-delay:0.1s}.swot-card:nth-child(2){animation-delay:0.2s}.swot-card:nth-child(3){animation-delay:0.3s}.swot-card:nth-child(4){animation-delay:0.4s}#result-container.animate-in{animation:containerFadeIn .6s ease-out}.status-timeline{position:relative;padding-left:2rem}.status-timeline::before{content:"";position:absolute;left:14px;top:24px;bottom:24px;width:2px;background:#e5e7eb}.status-item{position:relative;padding:1rem 0 1rem 2rem;animation:statusFadeIn .3s ease-out}.status-item--info .status-item__indicator,.status-item--info .status-item__header{color:#3b82f6}.status-item--loading .status-item__indicator,.status-item--loading .status-item__header{color:#f59e0b}.status-item--loading .status-item__content{animation:statusPulse 2s ease-in-out infinite}.status-item--success .status-item__indicator,.status-item--success .status-item__header{color:#10b981}.status-item--error .status-item__indicator,.status-item--error .status-item__header{color:#ef4444}.status-item__indicator{position:absolute;left:0;top:1.25rem;width:30px;height:30px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:1rem;background:#fff;box-shadow:0 0 0 4px #fff;z-index:1}.status-item__content{background:#fff;border-radius:12px;padding:1rem 1.25rem;box-shadow:0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -1px rgba(0,0,0,.06);transition:all 300ms cubic-bezier(0.4, 0, 0.2, 1)}.status-item:hover .status-item__content{box-shadow:0 10px 15px -3px rgba(0,0,0,.1),0 4px 6px -2px rgba(0,0,0,.05);transform:translateX(4px)}.status-item__header{font-weight:600;font-size:.875rem;text-transform:uppercase;letter-spacing:.05em;margin-bottom:.5rem}.status-item__message{color:#374151;line-height:1.6;font-size:.9375rem}.empty-state{display:flex;align-items:center;justify-content:center;min-height:400px;padding:3rem 1.5rem}.empty-state__content{text-align:center;max-width:500px}.empty-state__icon{width:120px;height:120px;margin:0 auto 2rem;border-radius:50%;background:linear-gradient(135deg, #F3F4F6 0%, #E5E7EB 100%);display:flex;align-items:center;justify-content:center;font-size:3rem;color:#9ca3af;animation:float 3s ease-in-out infinite}.empty-state__title{font-size:1.75rem;font-weight:600;color:#1f2937;margin-bottom:.75rem}.empty-state__description{font-size:1.125rem;color:#4b5563;line-height:1.6;margin-bottom:1.5rem}.empty-state__cta{display:inline-flex;align-items:center;gap:.5rem;padding:.875rem 2rem;background:#8b5cf6;color:#fff;border-radius:9999px;text-decoration:none;font-weight:600;transition:all 300ms cubic-bezier(0.4, 0, 0.2, 1);box-shadow:0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -1px rgba(0,0,0,.06)}.empty-state__cta:hover{background:#7c3aed;transform:translateY(-2px);box-shadow:0 10px 15px -3px rgba(0,0,0,.1),0 4px 6px -2px rgba(0,0,0,.05);color:#fff}.error-state{display:flex;align-items:center;justify-content:center;min-height:400px;padding:3rem 1.5rem}.error-state__content{text-align:center;max-width:500px}.error-state__icon{width:120px;height:120px;margin:0 auto 2rem;border-radius:50%;background:linear-gradient(135deg, #FEE2E2 0%, #FEF2F2 100%);display:flex;align-items:center;justify-content:center;font-size:3rem;color:#ef4444;animation:shake .5s ease-in-out}.error-state__title{font-size:1.75rem;font-weight:600;color:#1f2937;margin-bottom:.75rem}.error-state__description{font-size:1.125rem;color:#4b5563;line-height:1.6;margin-bottom:1.5rem}.error-state__details{background:#f3f4f6;border-radius:12px;padding:1rem;margin:1.5rem 0;font-family:"Courier New",monospace;font-size:.875rem;color:#374151;text-align:left;overflow-x:auto}.error-state__actions{display:flex;gap:1rem;justify-content:center;flex-wrap:wrap}.error-state__button{display:inline-flex;align-items:center;gap:.5rem;padding:.875rem 2rem;border-radius:9999px;font-weight:600;transition:all 300ms cubic-bezier(0.4, 0, 0.2, 1);box-shadow:0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -1px rgba(0,0,0,.06);cursor:pointer;border:none;text-decoration:none}.error-state__button--primary{background:#8b5cf6;color:#fff}.error-state__button--primary:hover{background:#7c3aed;transform:translateY(-2px);box-shadow:0 10px 15px -3px rgba(0,0,0,.1),0 4px 6px -2px rgba(0,0,0,.05);color:#fff}.error-state__button--secondary{background:#fff;color:#374151;border:2px solid #d1d5db}.error-state__button--secondary:hover{background:#f3f4f6;border-color:#9ca3af;transform:translateY(-2px);color:#1f2937}@media(max-width: 768px){.cell.is-col-span-2{grid-column:span 1}.swot-grid{grid-template-columns:1fr}.hero-title{font-size:2rem}.search-input-group{flex-direction:column;gap:.5rem;border-radius:20px;padding:1rem}.search-input{width:100%;text-align:center}.search-button{width:100%;justify-content:center}.swot-card__header{flex-wrap:wrap}.swot-card__count{order:-1;margin-left:auto}}@media(max-width: 480px){.swot-card{padding:1rem}.swot-card__icon{width:40px;height:40px;font-size:1.25rem}.swot-card__title{font-size:1.125rem}.hero-title{font-size:1.75rem}.status-timeline{padding-left:1.5rem}.status-item{padding-left:1.5rem}}:root{--brand-primary: #8B5CF6;--brand-primary-light: #A78BFA;--brand-primary-dark: #7C3AED;--swot-strength: #10B981;--swot-weakness: #F59E0B;--swot-opportunity: #3B82F6;--swot-threat: #EF4444;--neutral-50: #F9FAFB;--neutral-100: #F3F4F6;--neutral-200: #E5E7EB;--neutral-300: #D1D5DB;--neutral-400: #9CA3AF;--neutral-500: #6B7280;--neutral-600: #4B5563;--neutral-700: #374151;--neutral-800: #1F2937;--neutral-900: #111827;--shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05);--shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);--shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);--shadow-xl: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);--shadow-2xl: 0 25px 50px -12px rgba(0, 0, 0, 0.25);--transition-fast: 150ms cubic-bezier(0.4, 0, 0.2, 1);--transition-base: 300ms cubic-bezier(0.4, 0, 0.2, 1);--transition-slow: 500ms cubic-bezier(0.4, 0, 0.2, 1)}/*# sourceMappingURL=pygentic_ai.css.map */ diff --git a/src/frontend/static/css/pygentic_ai.css.map b/src/frontend/static/css/pygentic_ai.css.map index 5a4fa07..de87689 100644 --- a/src/frontend/static/css/pygentic_ai.css.map +++ b/src/frontend/static/css/pygentic_ai.css.map @@ -1 +1 @@ -{"version":3,"sourceRoot":"","sources":["../../scss/styles.scss","../../scss/_variables.scss","../../scss/_typography.scss","../../scss/_animations.scss","../../scss/_components.scss","../../scss/_layout.scss","../../scss/_states.scss","../../scss/_responsive.scss"],"names":[],"mappings":"AAAA;AAAA;AAAA;AAAA;AAAA,GCMQ,gICFR,KACE,YDIU,8FCHV,kDACA,mCACA,kCAGF,mCAGE,YDJa,mCCKb,uBACA,gBAIF,YACE,iCACA,gBACA,WDmBkB,kDClBlB,6BACA,sCACA,qBACA,mBACA,gBCxBF,gBACE,KACE,uBAEF,GACE,0BAIJ,iBACE,QACE,0BAEF,IACE,6BAIJ,iBACE,QACE,uCAEF,IACE,0CAIJ,mBACE,KACE,UACA,2BAEF,GACE,UACA,yBAIJ,kBACE,KACE,UAEF,GACE,WAIJ,iBACE,gCACA,gCACA,gCAGF,qBACE,QACE,mBAEF,IACE,sBAIJ,2BACE,KACE,UACA,2BAEF,GACE,UACA,yBAIJ,wBACE,KACE,UACA,4BAEF,GACE,UACA,yBAIJ,uBACE,QACE,WF3CQ,6DE6CV,IACE,2CCtFJ,SACE,kBACA,UACA,WACA,UACA,YACA,gBACA,sBACA,mBACA,eAGF,WACE,kBACA,UACA,OACA,WHVc,QGWd,WACA,sBACA,qBACA,gBACA,cACA,yBACA,kDAEA,iBACE,MAMJ,iBACE,eACA,MACA,OACA,WACA,YACA,qCACA,0BACA,aACA,uBACA,mBACA,aAGF,iBACE,kBAGF,QACE,qCACA,6BACA,kBACA,WACA,YACA,mCACA,cAGF,cACE,kBAEA,iBACE,kBACA,gBACA,MHnCU,QGoCV,oBAGF,gBACE,kBACA,MH5CU,QGkDd,kBACE,gBACA,cACA,kBAGF,aACE,WAGF,oBACE,aACA,mBACA,gBACA,cHvBY,OGwBZ,cACA,WHpDU,iEGqDV,kDAEA,iCACE,2CACA,2BAIJ,aACE,eACA,MH/EY,QGgFZ,kBAGF,cACE,OACA,YACA,aACA,qBACA,eACA,yBACA,MHrFY,QGuFZ,2BACE,MH7FU,QGiGd,eACE,WHtHc,QGuHd,WACA,YACA,cH1DY,OG2DZ,qBACA,gBACA,eACA,eACA,aACA,mBACA,UACA,kDACA,mBAEA,qBACE,WHnIiB,QGoIjB,0BACA,WHpGQ,+DGuGV,sBACE,sBAGF,qBACE,0BACA,mBAGF,0BACE,kBACA,oBACA,oBAEA,iCACE,WACA,kBACA,WACA,YACA,QACA,SACA,iBACA,gBACA,+BACA,sBACA,kBACA,mCAKN,aACE,gBACA,kBACA,MHtJY,QGuJZ,kBAEA,eACE,oBACA,MHjLY,QGsLhB,2CAKE,kDAIF,eACE,0BACA,mBCvMF,eACE,wEACA,kBACA,gBAIA,eACE,+BACA,wCAEA,qBACE,wCACA,8EAKN,kBACE,4BAKF,WACE,aACA,2DACA,IJiCW,OIhCX,WJiCW,KI9Bb,WACE,gBACA,cJkCU,KIjCV,QJ0BW,OIzBX,WJMU,+DILV,kDACA,uCACA,yCAEA,iBACE,2BACA,WJCS,kCICT,kCACE,iCAKJ,qBACE,sBAGF,qBACE,sBAGF,wBACE,sBAGF,mBACE,sBAIJ,mBACE,aACA,mBACA,WACA,mBACA,oBACA,gCAGF,iBACE,WACA,YACA,cJbU,KIcV,6BACA,aACA,mBACA,uBACA,WACA,iBACA,cAGF,kBACE,gBACA,mBACA,MJ7DY,QI8DZ,YACA,SAGF,kBACE,WJ3EY,QI4EZ,sBACA,cJhCU,KIiCV,kBACA,gBACA,MJ1EY,QI2EZ,cAGF,iBACE,gBAGF,WACE,gBACA,UACA,SAGF,iBACE,aACA,uBACA,WACA,iBACA,gCACA,wCAEA,4BACE,mBAKA,8BACE,qBADF,8BACE,qBADF,8BACE,qBADF,8BACE,qBADF,8BACE,qBADF,8BACE,qBADF,8BACE,qBADF,8BACE,qBADF,8BACE,qBADF,+BACE,mBAKN,mBACE,UACA,WACA,kBACA,6BACA,iBACA,cAGF,iBACE,OACA,MJvHY,QIwHZ,gBAKA,wBACE,qBADF,wBACE,qBADF,wBACE,qBADF,wBACE,qBAKJ,6BACE,uCAKF,iBACE,kBACA,kBAEA,yBACE,WACA,kBACA,UACA,SACA,YACA,UACA,WJzJU,QI6Jd,aACE,kBACA,yBACA,oCAIE,mFAEE,MJ9Ka,QImLf,yFAEE,MJvLU,QI0LZ,4CACE,8CAKF,yFAEE,MJpMU,QIyMZ,qFAEE,MJrMQ,QI0Md,wBACE,kBACA,OACA,YACA,WACA,YACA,kBACA,aACA,mBACA,uBACA,eACA,gBACA,0BACA,UAGF,sBACE,gBACA,cJ5KU,KI6KV,qBACA,WJxMU,6DIyMV,kDAGF,yCACE,WJ5MU,+DI6MV,0BAGF,qBACE,gBACA,kBACA,yBACA,qBACA,oBAGF,sBACE,MJrOY,QIsOZ,gBACA,mBCpQF,aACE,aACA,mBACA,uBACA,iBACA,oBAGF,sBACE,kBACA,gBAGF,mBACE,YACA,aACA,mBACA,kBACA,6DACA,aACA,mBACA,uBACA,eACA,MLGY,QKFZ,wCAGF,oBACE,kBACA,gBACA,cACA,qBAGF,0BACE,mBACA,MLRY,QKSZ,gBACA,qBAGF,kBACE,oBACA,mBACA,UACA,qBACA,WLxCc,QKyCd,WACA,cLqBY,OKpBZ,qBACA,gBACA,kDACA,WLZU,6DKcV,wBACE,WL/CiB,QKgDjB,2BACA,WLhBQ,+DKiBR,WAMJ,aACE,aACA,mBACA,uBACA,iBACA,oBAGF,sBACE,kBACA,gBAGF,mBACE,YACA,aACA,mBACA,kBACA,6DACA,aACA,mBACA,uBACA,eACA,MLrEY,QKsEZ,gCAGF,oBACE,kBACA,gBACA,MLhEY,QKiEZ,qBAGF,0BACE,mBACA,MLxEY,QKyEZ,gBACA,qBAGF,sBACE,WLnFY,QKoFZ,cLzCU,KK0CV,aACA,gBACA,oCACA,kBACA,MLnFY,QKoFZ,gBACA,gBAGF,sBACE,aACA,SACA,uBACA,eAGF,qBACE,oBACA,mBACA,UACA,qBACA,cL5DY,OK6DZ,gBACA,kDACA,WL5FU,6DK6FV,eACA,YACA,qBAEA,8BACE,WLpIY,QKqIZ,WAEA,oCACE,WLtIe,QKuIf,2BACA,WLvGM,+DKwGN,WAIJ,gCACE,gBACA,ML1HU,QK2HV,yBAEA,sCACE,WLpIQ,QKqIR,aLlIQ,QKmIR,2BACA,MLhIQ,QM/Bd,yBACE,oBACE,mBAGF,WACE,0BAGF,YACE,eAGF,oBACE,sBACA,UACA,cNqDQ,KMpDR,aAGF,cACE,WACA,kBAGF,eACE,WACA,uBAGF,mBACE,eAGF,kBACE,SACA,kBAKJ,yBACE,WACE,aAGF,iBACE,WACA,YACA,kBAGF,kBACE,mBAGF,YACE,kBAGF,iBACE,oBAGF,aACE,qBP3CJ,MAEE,yBACA,+BACA,8BAGA,yBACA,yBACA,4BACA,uBAGA,sBACA,uBACA,uBACA,uBACA,uBACA,uBACA,uBACA,uBACA,uBACA,uBAGA,6CACA,mFACA,qFACA,uFACA,oDAGA,sDACA,sDACA","file":"pygentic_ai.css"} \ No newline at end of file +{"version":3,"sourceRoot":"","sources":["../../scss/styles.scss","../../scss/_variables.scss","../../scss/_typography.scss","../../scss/_animations.scss","../../scss/_components.scss","../../scss/_layout.scss","../../scss/_states.scss","../../scss/_responsive.scss"],"names":[],"mappings":"AAAA;AAAA;AAAA;AAAA;AAAA,GCMQ,gICFR,KACE,YDIU,8FCHV,kDACA,mCACA,kCAGF,mCAGE,YDJa,mCCKb,uBACA,gBAIF,YACE,iCACA,gBACA,WDmBkB,kDClBlB,6BACA,sCACA,qBACA,mBACA,gBCxBF,gBACE,KACE,uBAEF,GACE,0BAIJ,iBACE,QACE,0BAEF,IACE,6BAIJ,iBACE,QACE,uCAEF,IACE,0CAIJ,mBACE,KACE,UACA,2BAEF,GACE,UACA,yBAIJ,kBACE,KACE,UAEF,GACE,WAIJ,iBACE,gCACA,gCACA,gCAGF,qBACE,QACE,mBAEF,IACE,sBAIJ,2BACE,KACE,UACA,2BAEF,GACE,UACA,yBAIJ,wBACE,KACE,UACA,4BAEF,GACE,UACA,yBAIJ,uBACE,QACE,WF3CQ,6DE6CV,IACE,2CCtFJ,SACE,kBACA,UACA,WACA,UACA,YACA,gBACA,sBACA,mBACA,eAGF,WACE,kBACA,UACA,OACA,WHVc,QGWd,WACA,sBACA,qBACA,gBACA,cACA,yBACA,kDAEA,iBACE,MAMJ,iBACE,eACA,MACA,OACA,WACA,YACA,qCACA,0BACA,aACA,uBACA,mBACA,aAGF,iBACE,kBAGF,QACE,qCACA,6BACA,kBACA,WACA,YACA,mCACA,cAGF,cACE,kBAEA,iBACE,kBACA,gBACA,MHnCU,QGoCV,oBAGF,gBACE,kBACA,MH5CU,QGkDd,kBACE,gBACA,cACA,kBAGF,aACE,WAGF,oBACE,aACA,mBACA,gBACA,cHvBY,OGwBZ,cACA,WHpDU,iEGqDV,kDAEA,iCACE,2CACA,2BAIJ,aACE,eACA,MH/EY,QGgFZ,kBAGF,cACE,OACA,YACA,aACA,qBACA,eACA,yBACA,MHrFY,QGuFZ,2BACE,MH7FU,QGiGd,eACE,WHtHc,QGuHd,WACA,YACA,cH1DY,OG2DZ,qBACA,gBACA,eACA,eACA,aACA,mBACA,UACA,kDACA,mBAEA,qBACE,WHnIiB,QGoIjB,0BACA,WHpGQ,+DGuGV,sBACE,sBAGF,qBACE,0BACA,mBAGF,0BACE,kBACA,oBACA,oBAEA,iCACE,WACA,kBACA,WACA,YACA,QACA,SACA,iBACA,gBACA,+BACA,sBACA,kBACA,mCAKN,aACE,gBACA,kBACA,MHtJY,QGuJZ,kBAEA,eACE,oBACA,MHjLY,QGuLhB,wBACE,aACA,mBACA,gBACA,cH5HY,OG6HZ,cACA,kBACA,WH3JU,+DG4JV,kDAEA,qCACE,2CAIJ,iBACE,eACA,MHpLY,QGqLZ,eAGF,kBACE,OACA,YACA,aACA,oBACA,gBACA,yBACA,MH1LY,QG4LZ,+BACE,MHlMU,QGwMd,eACE,aACA,mBACA,uBACA,eACA,UAGF,mBACE,gBACA,iBACA,MHjNY,QGkNZ,yBACA,qBAGF,oBACE,MHzNY,QG4Nd,cACE,oBACA,mBACA,oBACA,cHrLY,OGsLZ,kBACA,gBAEA,gBACE,oBAGF,uBACE,WH7PY,QG8PZ,WAGF,0BACE,gCACA,MH7OU,QG8OV,sCAKJ,2CAKE,kDAIF,eACE,0BACA,mBC1RF,eACE,wEACA,kBACA,gBAIA,eACE,+BACA,wCAEA,qBACE,wCACA,8EAKN,kBACE,4BAKF,WACE,aACA,2DACA,IJiCW,OIhCX,WJiCW,KI9Bb,WACE,gBACA,cJkCU,KIjCV,QJ0BW,OIzBX,WJMU,+DILV,kDACA,uCACA,yCAEA,iBACE,2BACA,WJCS,kCICT,kCACE,iCAKJ,qBACE,sBAGF,qBACE,sBAGF,wBACE,sBAGF,mBACE,sBAIJ,mBACE,aACA,mBACA,WACA,mBACA,oBACA,gCAGF,iBACE,WACA,YACA,cJbU,KIcV,6BACA,aACA,mBACA,uBACA,WACA,iBACA,cAGF,kBACE,gBACA,mBACA,MJ7DY,QI8DZ,YACA,SAGF,kBACE,WJ3EY,QI4EZ,sBACA,cJhCU,KIiCV,kBACA,gBACA,MJ1EY,QI2EZ,cAGF,iBACE,gBAGF,WACE,gBACA,UACA,SAGF,iBACE,aACA,uBACA,WACA,iBACA,gCACA,wCAEA,4BACE,mBAKA,8BACE,qBADF,8BACE,qBADF,8BACE,qBADF,8BACE,qBADF,8BACE,qBADF,8BACE,qBADF,8BACE,qBADF,8BACE,qBADF,8BACE,qBADF,+BACE,mBAKN,mBACE,UACA,WACA,kBACA,6BACA,iBACA,cAGF,iBACE,OACA,MJvHY,QIwHZ,gBAKA,wBACE,qBADF,wBACE,qBADF,wBACE,qBADF,wBACE,qBAKJ,6BACE,uCAKF,iBACE,kBACA,kBAEA,yBACE,WACA,kBACA,UACA,SACA,YACA,UACA,WJzJU,QI6Jd,aACE,kBACA,yBACA,oCAIE,mFAEE,MJ9Ka,QImLf,yFAEE,MJvLU,QI0LZ,4CACE,8CAKF,yFAEE,MJpMU,QIyMZ,qFAEE,MJrMQ,QI0Md,wBACE,kBACA,OACA,YACA,WACA,YACA,kBACA,aACA,mBACA,uBACA,eACA,gBACA,0BACA,UAGF,sBACE,gBACA,cJ5KU,KI6KV,qBACA,WJxMU,6DIyMV,kDAGF,yCACE,WJ5MU,+DI6MV,0BAGF,qBACE,gBACA,kBACA,yBACA,qBACA,oBAGF,sBACE,MJrOY,QIsOZ,gBACA,mBCpQF,aACE,aACA,mBACA,uBACA,iBACA,oBAGF,sBACE,kBACA,gBAGF,mBACE,YACA,aACA,mBACA,kBACA,6DACA,aACA,mBACA,uBACA,eACA,MLGY,QKFZ,wCAGF,oBACE,kBACA,gBACA,cACA,qBAGF,0BACE,mBACA,MLRY,QKSZ,gBACA,qBAGF,kBACE,oBACA,mBACA,UACA,qBACA,WLxCc,QKyCd,WACA,cLqBY,OKpBZ,qBACA,gBACA,kDACA,WLZU,6DKcV,wBACE,WL/CiB,QKgDjB,2BACA,WLhBQ,+DKiBR,WAMJ,aACE,aACA,mBACA,uBACA,iBACA,oBAGF,sBACE,kBACA,gBAGF,mBACE,YACA,aACA,mBACA,kBACA,6DACA,aACA,mBACA,uBACA,eACA,MLrEY,QKsEZ,gCAGF,oBACE,kBACA,gBACA,MLhEY,QKiEZ,qBAGF,0BACE,mBACA,MLxEY,QKyEZ,gBACA,qBAGF,sBACE,WLnFY,QKoFZ,cLzCU,KK0CV,aACA,gBACA,oCACA,kBACA,MLnFY,QKoFZ,gBACA,gBAGF,sBACE,aACA,SACA,uBACA,eAGF,qBACE,oBACA,mBACA,UACA,qBACA,cL5DY,OK6DZ,gBACA,kDACA,WL5FU,6DK6FV,eACA,YACA,qBAEA,8BACE,WLpIY,QKqIZ,WAEA,oCACE,WLtIe,QKuIf,2BACA,WLvGM,+DKwGN,WAIJ,gCACE,gBACA,ML1HU,QK2HV,yBAEA,sCACE,WLpIQ,QKqIR,aLlIQ,QKmIR,2BACA,MLhIQ,QM/Bd,yBACE,oBACE,mBAGF,WACE,0BAGF,YACE,eAGF,oBACE,sBACA,UACA,cNqDQ,KMpDR,aAGF,cACE,WACA,kBAGF,eACE,WACA,uBAGF,mBACE,eAGF,kBACE,SACA,kBAKJ,yBACE,WACE,aAGF,iBACE,WACA,YACA,kBAGF,kBACE,mBAGF,YACE,kBAGF,iBACE,oBAGF,aACE,qBP3CJ,MAEE,yBACA,+BACA,8BAGA,yBACA,yBACA,4BACA,uBAGA,sBACA,uBACA,uBACA,uBACA,uBACA,uBACA,uBACA,uBACA,uBACA,uBAGA,6CACA,mFACA,qFACA,uFACA,oDAGA,sDACA,sDACA","file":"pygentic_ai.css"} \ No newline at end of file diff --git a/src/frontend/templates/home.html b/src/frontend/templates/home.html index cbb18e6..db64fc5 100644 --- a/src/frontend/templates/home.html +++ b/src/frontend/templates/home.html @@ -14,7 +14,7 @@

Uncover strategic insights with generative AI.
- Transform any URL into actionable business intelligence. + Compare entities and generate actionable business intelligence.

@@ -33,21 +33,20 @@ role="search"> - + autocomplete="off" />