diff --git a/base.html b/base.html
new file mode 100644
index 0000000..2fa5bef
--- /dev/null
+++ b/base.html
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+ Recon Ranger
+
+
+
+
+
+
+
+ {% block content %}{% endblock %}
+
+
+
+
+
\ No newline at end of file
diff --git a/dashboard.html b/dashboard.html
new file mode 100644
index 0000000..2d862fc
--- /dev/null
+++ b/dashboard.html
@@ -0,0 +1,36 @@
+{% extends "base.html" %}
+
+{% block content %}
+
+
{{ title }}
+
+ {% if results | length > 0 %}
+
+
+
+ {% for key in results[0].keys() %}
+ | {{ key }} |
+ {% endfor %}
+
+
+
+ {% for row in results %}
+
+ {% for key, value in row.items() %}
+ |
+ {% if key == 'Status' %}
+ {{ value }}
+ {% elif key == 'Flag' %}
+ {{ value }}
+ {% else %}
+ {{ value }}
+ {% endif %}
+ |
+ {% endfor %}
+
+ {% endfor %}
+
+
+ {% endif %}
+
+{% endblock %}
\ No newline at end of file
diff --git a/main.py b/main.py
new file mode 100644
index 0000000..d813d94
--- /dev/null
+++ b/main.py
@@ -0,0 +1,180 @@
+import uvicorn
+from fastapi import FastAPI, HTTPException, Query
+from fastapi.openapi.docs import get_swagger_ui_html
+from fastapi.staticfiles import StaticFiles
+from fastapi.responses import HTMLResponse
+from pydantic import BaseModel
+from typing import Literal
+from datetime import date
+
+
+# ── Models ────────────────────────────────────────────────────────────────────
+
+class Transaction(BaseModel):
+ transaction_id: str
+ date: date
+ account: str
+ amount: float
+ status: Literal["Matched", "Unmatched", "Pending"]
+ flag: Literal["None", "Duplicate", "Threshold Breach", "Manual Review"]
+
+
+class ReconSummary(BaseModel):
+ total: int
+ matched: int
+ unmatched: int
+ pending: int
+ flagged: int
+
+
+# ── Sample data ───────────────────────────────────────────────────────────────
+
+TRANSACTIONS: list[Transaction] = [
+ Transaction(transaction_id="TXN-001", date=date(2026, 4, 10), account="ACC-9821", amount=12400.00, status="Matched", flag="None"),
+ Transaction(transaction_id="TXN-002", date=date(2026, 4, 11), account="ACC-4473", amount=3750.50, status="Unmatched", flag="Duplicate"),
+ Transaction(transaction_id="TXN-003", date=date(2026, 4, 11), account="ACC-1190", amount=88200.00, status="Unmatched", flag="Threshold Breach"),
+ Transaction(transaction_id="TXN-004", date=date(2026, 4, 12), account="ACC-6654", amount=540.00, status="Matched", flag="None"),
+ Transaction(transaction_id="TXN-005", date=date(2026, 4, 13), account="ACC-3312", amount=21000.00, status="Pending", flag="Manual Review"),
+]
+
+
+# ── App ───────────────────────────────────────────────────────────────────────
+
+app = FastAPI(
+ title="Recon Ranger",
+ description="Financial crime reconciliation API — patrol your data landscape for inconsistencies.",
+ version="0.1.0",
+ docs_url=None,
+)
+app.mount("/static", StaticFiles(directory="static"), name="static")
+
+
+# ── Endpoints ─────────────────────────────────────────────────────────────────
+
+@app.get(
+ "/api/transactions",
+ response_model=list[Transaction],
+ summary="List transactions",
+ tags=["Transactions"],
+)
+async def list_transactions(
+ status: Literal["Matched", "Unmatched", "Pending"] | None = Query(None, description="Filter by status"),
+ flag: Literal["None", "Duplicate", "Threshold Breach", "Manual Review"] | None = Query(None, description="Filter by flag"),
+) -> list[Transaction]:
+ """Return all transactions, optionally filtered by status and/or flag."""
+ results = TRANSACTIONS
+ if status:
+ results = [t for t in results if t.status == status]
+ if flag:
+ results = [t for t in results if t.flag == flag]
+ return results
+
+
+@app.get(
+ "/api/transactions/{transaction_id}",
+ response_model=Transaction,
+ summary="Get a transaction",
+ tags=["Transactions"],
+)
+async def get_transaction(transaction_id: str) -> Transaction:
+ """Retrieve a single transaction by ID."""
+ for t in TRANSACTIONS:
+ if t.transaction_id == transaction_id:
+ return t
+ raise HTTPException(status_code=404, detail=f"{transaction_id} not found")
+
+
+@app.post(
+ "/api/transactions",
+ response_model=Transaction,
+ status_code=201,
+ summary="Submit a transaction",
+ tags=["Transactions"],
+)
+async def create_transaction(transaction: Transaction) -> Transaction:
+ """Submit a new transaction for reconciliation."""
+ for t in TRANSACTIONS:
+ if t.transaction_id == transaction.transaction_id:
+ raise HTTPException(status_code=409, detail=f"{transaction.transaction_id} already exists")
+ TRANSACTIONS.append(transaction)
+ return transaction
+
+
+@app.get(
+ "/api/summary",
+ response_model=ReconSummary,
+ summary="Reconciliation summary",
+ tags=["Reporting"],
+)
+async def get_summary() -> ReconSummary:
+ """Return aggregate counts across all transactions."""
+ return ReconSummary(
+ total=len(TRANSACTIONS),
+ matched=sum(1 for t in TRANSACTIONS if t.status == "Matched"),
+ unmatched=sum(1 for t in TRANSACTIONS if t.status == "Unmatched"),
+ pending=sum(1 for t in TRANSACTIONS if t.status == "Pending"),
+ flagged=sum(1 for t in TRANSACTIONS if t.flag != "None"),
+ )
+
+
+@app.delete(
+ "/api/transactions/{transaction_id}",
+ status_code=204,
+ summary="Delete a transaction",
+ tags=["Transactions"],
+)
+async def delete_transaction(transaction_id: str) -> None:
+ """Remove a transaction by ID."""
+ for i, t in enumerate(TRANSACTIONS):
+ if t.transaction_id == transaction_id:
+ TRANSACTIONS.pop(i)
+ return
+ raise HTTPException(status_code=404, detail=f"{transaction_id} not found")
+
+
+
+@app.get("/api/docs", include_in_schema=False)
+async def swagger_ui_dark() -> HTMLResponse:
+ base = get_swagger_ui_html(
+ openapi_url=app.openapi_url,
+ title="Recon Ranger — API Docs",
+ swagger_css_url="/static/api/swagger-ui.css",
+ )
+ html = base.body.decode()
+
+ # Inject dark theme + main site styles
+ html = html.replace(
+ "",
+ (
+ '\n'
+ '\n'
+ "\n"
+ ""
+ ),
+ )
+
+ # Inject the site nav bar before Swagger's root div
+ nav_html = """
+
+
+"""
+ html = html.replace("", "" + nav_html)
+ html = html.replace("", "
")
+
+ return HTMLResponse(html)
+
+
+if __name__ == "__main__":
+ uvicorn.run("main:app", host="0.0.0.0", port=8000, reload=True)
+
diff --git a/styles.css b/styles.css
new file mode 100644
index 0000000..fc31649
--- /dev/null
+++ b/styles.css
@@ -0,0 +1,167 @@
+*{
+ margin: 0;
+ padding: 0;
+ box-sizing: border-box;
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
+}
+::selection{
+ color: #000;
+ background: #fff;
+}
+nav{
+ position: fixed;
+ background: #1b1b1b;
+ width: 100%;
+ padding: 10px 0;
+ z-index: 12;
+}
+nav .menu{
+ max-width: 1250px;
+ margin: auto;
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding: 0 20px;
+}
+.menu .logo a{
+ text-decoration: none;
+ color: #fff;
+ font-size: 35px;
+ font-weight: 600;
+}
+.menu ul{
+ display: flex;
+}
+.menu ul li{
+ list-style: none;
+ margin-left: 7px;
+}
+.menu ul li:first-child{
+ margin-left: 0px;
+}
+.menu ul li a{
+ text-decoration: none;
+ color: #fff;
+ font-size: 18px;
+ font-weight: 500;
+ padding: 0px 15px;
+ border-radius: 5px;
+ transition: all 0.3s ease;
+}
+.menu ul li a:hover{
+ background-color: #fff;
+ color: #000;
+ padding: 10px 15px;
+}
+/* ── Body & layout ─────────────────────────────────────────── */
+body {
+ background: url(../images/recon_ranger_logo.png) no-repeat center center fixed;
+ background-size: cover;
+ color: #e2e8f0;
+ min-height: 100vh;
+ display: flex;
+ flex-direction: column;
+}
+body::before {
+ content: '';
+ position: fixed;
+ inset: 0;
+ background: rgba(0, 0, 0, 0.55);
+ z-index: 0;
+ pointer-events: none;
+}
+main {
+ flex: 1;
+ padding-top: 70px; /* clear fixed nav */
+ position: relative;
+ z-index: 1;
+}
+footer {
+ position: relative;
+ z-index: 1;
+ background: rgba(27, 27, 27, 0.85);
+ color: #888;
+ text-align: center;
+ padding: 18px 20px;
+ font-size: 14px;
+ letter-spacing: 0.03em;
+ border-top: 1px solid #2d2d2d;
+}
+
+/* ── Dashboard content container ────────────────────────── */
+.dashboard-container {
+ max-width: 1250px;
+ margin: 32px auto;
+ padding: 40px 24px 60px;
+ background: rgba(15, 17, 23, 0.45);
+ backdrop-filter: blur(6px);
+ border-radius: 12px;
+}
+.dashboard-container h1 {
+ font-size: 28px;
+ font-weight: 600;
+ color: #f1f5f9;
+ margin-bottom: 24px;
+ padding-bottom: 12px;
+ border-bottom: 2px solid #2d2d3a;
+ letter-spacing: 0.02em;
+}
+
+/* ── Data table ─────────────────────────────────────────── */
+.data-table {
+ width: 100%;
+ border-collapse: collapse;
+ font-size: 14px;
+ border-radius: 10px;
+ overflow: hidden;
+ box-shadow: 0 4px 24px rgba(0, 0, 0, 0.4);
+}
+.data-table thead {
+ background: #1b1b2e;
+}
+.data-table thead th {
+ padding: 14px 18px;
+ text-align: left;
+ font-size: 12px;
+ font-weight: 600;
+ text-transform: uppercase;
+ letter-spacing: 0.08em;
+ color: #94a3b8;
+ border-bottom: 1px solid #2d2d3a;
+ white-space: nowrap;
+}
+.data-table tbody tr {
+ background: #161622;
+ transition: background 0.15s ease;
+}
+.data-table tbody tr:nth-child(even) {
+ background: #1a1a28;
+}
+.data-table tbody tr:hover {
+ background: #252540;
+}
+.data-table tbody td {
+ padding: 13px 18px;
+ border-bottom: 1px solid #22222e;
+ color: #cbd5e1;
+ vertical-align: middle;
+}
+.data-table tbody tr:last-child td {
+ border-bottom: none;
+}
+
+/* ── Status badges ──────────────────────────────────────── */
+.badge {
+ display: inline-block;
+ padding: 3px 10px;
+ border-radius: 999px;
+ font-size: 12px;
+ font-weight: 600;
+ letter-spacing: 0.04em;
+ white-space: nowrap;
+}
+.badge-matched { background: rgba(34,197,94,0.15); color: #4ade80; }
+.badge-unmatched { background: rgba(239,68,68,0.15); color: #f87171; }
+.badge-pending { background: rgba(234,179,8,0.15); color: #facc15; }
+.badge-none { background: rgba(100,116,139,0.15); color: #94a3b8; }
+.badge-flag { background: rgba(249,115,22,0.15); color: #fb923c; }
diff --git a/swagger-dark.css b/swagger-dark.css
new file mode 100644
index 0000000..5a07858
--- /dev/null
+++ b/swagger-dark.css
@@ -0,0 +1,460 @@
+/* ══════════════════════════════════════════════════════════════
+ Recon Ranger — Swagger UI dark theme override
+ Matches the dashboard palette. Load AFTER swagger-ui.css.
+ ══════════════════════════════════════════════════════════════ */
+
+/* ── Page shell ──────────────────────────────────────────────── */
+body {
+ background: #0f1117;
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
+ 'Helvetica Neue', Arial, sans-serif;
+}
+
+/* Lift all Swagger content above the body::before dark overlay (z-index: 0).
+ Without this, the fixed overlay covers everything since Swagger's divs
+ have no stacking context of their own. */
+.swagger-ui,
+.swagger-ui-wrap {
+ position: relative;
+ z-index: 1;
+ color: #e2e8f0;
+}
+
+/* ── Global text fallback — catch any element Swagger sets to near-black ── */
+.swagger-ui p,
+.swagger-ui span,
+.swagger-ui div,
+.swagger-ui h1,
+.swagger-ui h2,
+.swagger-ui h3,
+.swagger-ui h4,
+.swagger-ui h5,
+.swagger-ui label,
+.swagger-ui li,
+.swagger-ui td,
+.swagger-ui th {
+ color: #e2e8f0;
+}
+
+/* ── Compound selectors with higher specificity in swagger-ui.css ────────
+ These all set dark text and need explicit overrides to win by load order. */
+.swagger-ui section h3,
+.swagger-ui section.models h4,
+.swagger-ui section.models h5,
+.swagger-ui .responses-inner h4,
+.swagger-ui .responses-inner h5,
+.swagger-ui .opblock-title_normal h4,
+.swagger-ui .opblock-title_normal p,
+.swagger-ui .opblock-description-wrapper h4,
+.swagger-ui .opblock-description-wrapper p,
+.swagger-ui .opblock-external-docs-wrapper h4,
+.swagger-ui .opblock-external-docs-wrapper p,
+.swagger-ui .opblock .opblock-section-header h4,
+.swagger-ui .opblock .opblock-section-header > label,
+.swagger-ui .dialog-ux .modal-ux-header h3,
+.swagger-ui .dialog-ux .modal-ux-content h4,
+.swagger-ui .dialog-ux .modal-ux-content p,
+.swagger-ui .errors-wrapper hgroup h4,
+.swagger-ui .errors-wrapper .errors h4,
+.swagger-ui .errors-wrapper .errors small,
+.swagger-ui .scopes h2,
+.swagger-ui .scopes h2 a,
+.swagger-ui table.model tr.description,
+.swagger-ui table.model tr.extension,
+.swagger-ui table.headers td,
+.swagger-ui table.headers .header-example,
+.swagger-ui table thead tr td,
+.swagger-ui table thead tr th {
+ color: #e2e8f0;
+}
+
+/* Empty-spec and fallback messages */
+.swagger-ui .opblock-tag-section p,
+.swagger-ui .fallback,
+.swagger-ui .info__tos,
+.swagger-ui .renderedMarkdown p,
+.swagger-ui .markdown p {
+ color: #cbd5e1;
+}
+
+/* ── Top bar ─────────────────────────────────────────────────── */
+.swagger-ui .topbar {
+ background: #1b1b1b;
+ padding: 10px 0;
+ border-bottom: 1px solid #2d2d3a;
+}
+
+.swagger-ui .topbar .download-url-wrapper input[type="text"] {
+ background: #161622;
+ border: 1px solid #2d2d3a;
+ color: #e2e8f0;
+ border-radius: 5px;
+}
+
+.swagger-ui .topbar .download-url-wrapper .download-url-button {
+ background: #252540;
+ color: #e2e8f0;
+ border: 1px solid #2d2d3a;
+ border-radius: 5px;
+}
+
+/* ── Info block ──────────────────────────────────────────────── */
+.swagger-ui .information-container {
+ background: rgba(15, 17, 23, 0.45);
+ backdrop-filter: blur(6px);
+ border-radius: 12px;
+ padding: 24px;
+ margin-bottom: 24px;
+ border: 1px solid #2d2d3a;
+}
+
+.swagger-ui .info .title,
+.swagger-ui .info h1,
+.swagger-ui .info h2,
+.swagger-ui .info h3 {
+ color: #f1f5f9;
+}
+
+.swagger-ui .info p,
+.swagger-ui .info li,
+.swagger-ui .info a {
+ color: #cbd5e1;
+}
+
+.swagger-ui .info a:hover {
+ color: #f1f5f9;
+}
+
+/* ── Scheme / server selector ────────────────────────────────── */
+.swagger-ui .scheme-container {
+ background: #161622;
+ border-radius: 8px;
+ border: 1px solid #2d2d3a;
+ box-shadow: none;
+ padding: 16px 24px;
+ margin-bottom: 16px;
+}
+
+.swagger-ui .scheme-container .schemes > label {
+ color: #94a3b8;
+}
+
+.swagger-ui select {
+ background: #1a1a28;
+ border: 1px solid #2d2d3a;
+ color: #e2e8f0;
+ border-radius: 5px;
+}
+
+/* ── Operation tag headers ───────────────────────────────────── */
+.swagger-ui .opblock-tag {
+ color: #f1f5f9;
+ border-bottom: 1px solid #2d2d3a;
+ font-size: 18px;
+ font-weight: 600;
+}
+
+.swagger-ui .opblock-tag:hover {
+ background: #1a1a28;
+ border-radius: 6px;
+}
+
+.swagger-ui .opblock-tag small {
+ color: #94a3b8;
+}
+
+/* ── Operation blocks (GET / POST / PUT / DELETE / PATCH) ────── */
+.swagger-ui .opblock {
+ border-radius: 8px;
+ border: 1px solid #2d2d3a;
+ margin-bottom: 8px;
+ box-shadow: none;
+}
+
+.swagger-ui .opblock .opblock-summary {
+ border-radius: 8px;
+}
+
+.swagger-ui .opblock .opblock-summary-description {
+ color: #94a3b8;
+}
+
+/* GET */
+.swagger-ui .opblock.opblock-get {
+ background: rgba(59, 130, 246, 0.08);
+ border-color: rgba(59, 130, 246, 0.35);
+}
+.swagger-ui .opblock.opblock-get .opblock-summary-method {
+ background: #3b82f6;
+}
+
+/* POST */
+.swagger-ui .opblock.opblock-post {
+ background: rgba(34, 197, 94, 0.08);
+ border-color: rgba(34, 197, 94, 0.35);
+}
+.swagger-ui .opblock.opblock-post .opblock-summary-method {
+ background: #22c55e;
+}
+
+/* PUT */
+.swagger-ui .opblock.opblock-put {
+ background: rgba(249, 115, 22, 0.08);
+ border-color: rgba(249, 115, 22, 0.35);
+}
+.swagger-ui .opblock.opblock-put .opblock-summary-method {
+ background: #f97316;
+}
+
+/* DELETE */
+.swagger-ui .opblock.opblock-delete {
+ background: rgba(239, 68, 68, 0.08);
+ border-color: rgba(239, 68, 68, 0.35);
+}
+.swagger-ui .opblock.opblock-delete .opblock-summary-method {
+ background: #ef4444;
+}
+
+/* PATCH */
+.swagger-ui .opblock.opblock-patch {
+ background: rgba(20, 184, 166, 0.08);
+ border-color: rgba(20, 184, 166, 0.35);
+}
+.swagger-ui .opblock.opblock-patch .opblock-summary-method {
+ background: #14b8a6;
+}
+
+/* ── Expanded opblock panels — use !important to beat vendor specificity ─── */
+.swagger-ui .opblock-body,
+.swagger-ui .opblock-section,
+.swagger-ui .opblock .opblock-section-header,
+.swagger-ui .opblock-section-header,
+.swagger-ui .table-container,
+.swagger-ui .parameters-container,
+.swagger-ui .body-param,
+.swagger-ui .body-param__text,
+.swagger-ui .body-param-options,
+.swagger-ui .responses-wrapper,
+.swagger-ui .responses-inner,
+.swagger-ui .response,
+.swagger-ui .live-responses-table,
+.swagger-ui .request-url,
+.swagger-ui .curl-command,
+.swagger-ui .curl-command pre,
+.swagger-ui .highlight-code,
+.swagger-ui .microlight,
+.swagger-ui .model-example,
+.swagger-ui .example-module-example,
+.swagger-ui .scheme-container,
+.swagger-ui section.models,
+.swagger-ui section.models .model-container,
+.swagger-ui section.models .model-container:hover,
+.swagger-ui section.models .model-box,
+.swagger-ui .model-box,
+.swagger-ui .model-box .json-schema-2020-12,
+.swagger-ui .model-box .json-schema-2020-12-accordion,
+.swagger-ui .model-box .json-schema-2020-12-expand-deep-button,
+.swagger-ui .model-container,
+.swagger-ui .json-schema-2020-12,
+.swagger-ui .json-schema-2020-12--embedded,
+.swagger-ui .json-schema-2020-12__constraint,
+.swagger-ui .json-schema-2020-12__constraint--string,
+.swagger-ui .json-schema-2020-12-accordion,
+.swagger-ui .json-schema-2020-12-expand-deep-button,
+.swagger-ui .model-hint,
+.swagger-ui .markdown pre,
+.swagger-ui .renderedMarkdown pre,
+.swagger-ui .dialog-ux .modal-ux,
+.swagger-ui .dialog-ux .modal-ux-header {
+ background: #161622 !important;
+ color: #cbd5e1 !important;
+}
+
+.swagger-ui .opblock-body pre,
+.swagger-ui pre.microlight,
+.swagger-ui .response pre {
+ background: #0f1117 !important;
+ color: #cbd5e1 !important;
+ border: 1px solid #2d2d3a;
+ border-radius: 6px;
+ padding: 12px 16px;
+}
+
+.swagger-ui code,
+.swagger-ui .renderedMarkdown code,
+.swagger-ui .markdown code,
+.swagger-ui .response-col_description code {
+ background: #0f1117 !important;
+ color: #94a3b8 !important;
+ border-radius: 4px;
+ padding: 1px 5px;
+}
+
+.swagger-ui .opblock-description-wrapper p,
+.swagger-ui .opblock-external-docs-wrapper p,
+.swagger-ui .opblock .opblock-section-header h4,
+.swagger-ui .opblock-section-header h4,
+.swagger-ui .opblock .opblock-section-header > label,
+.swagger-ui .opblock-section-header label {
+ color: #94a3b8;
+}
+
+/* ── Parameters table ────────────────────────────────────────── */
+.swagger-ui table {
+ border-collapse: collapse;
+ width: 100%;
+}
+
+.swagger-ui table thead tr {
+ background: #1b1b2e;
+ color: #94a3b8;
+ font-size: 12px;
+ text-transform: uppercase;
+ letter-spacing: 0.08em;
+}
+
+.swagger-ui table thead tr th,
+.swagger-ui table thead tr td {
+ color: #94a3b8;
+ border-bottom: 1px solid #2d2d3a;
+ padding: 12px 16px;
+}
+
+.swagger-ui table tbody tr {
+ background: #161622;
+}
+
+.swagger-ui table tbody tr:nth-child(even) {
+ background: #1a1a28;
+}
+
+.swagger-ui table tbody tr:hover {
+ background: #252540;
+}
+
+.swagger-ui table tbody tr td {
+ color: #cbd5e1;
+ border-bottom: 1px solid #22222e;
+ padding: 12px 16px;
+}
+
+.swagger-ui .parameter__name,
+.swagger-ui .parameter__type,
+.swagger-ui .parameter__deprecated,
+.swagger-ui .parameter__in {
+ color: #94a3b8;
+}
+
+.swagger-ui .parameter__name.required::after {
+ color: #f87171;
+}
+
+/* ── Input / textarea ────────────────────────────────────────── */
+.swagger-ui input[type="text"],
+.swagger-ui input[type="email"],
+.swagger-ui input[type="password"],
+.swagger-ui textarea {
+ background: #1a1a28;
+ border: 1px solid #2d2d3a;
+ color: #e2e8f0;
+ border-radius: 5px;
+}
+
+.swagger-ui input[type="text"]:focus,
+.swagger-ui textarea:focus {
+ border-color: #3b82f6;
+ outline: none;
+}
+
+/* ── Buttons ─────────────────────────────────────────────────── */
+.swagger-ui .btn {
+ border-radius: 5px;
+ font-weight: 500;
+ transition: all 0.2s ease;
+}
+
+.swagger-ui .btn.execute {
+ background: #3b82f6;
+ border-color: #3b82f6;
+ color: #fff;
+}
+
+.swagger-ui .btn.execute:hover {
+ background: #2563eb;
+ border-color: #2563eb;
+}
+
+.swagger-ui .btn.cancel {
+ background: transparent;
+ border-color: #f87171;
+ color: #f87171;
+}
+
+.swagger-ui .btn.try-out__btn {
+ border-color: #4ade80;
+ color: #4ade80;
+ background: transparent;
+}
+
+.swagger-ui .btn.try-out__btn.cancel {
+ border-color: #f87171;
+ color: #f87171;
+}
+
+.swagger-ui .btn.authorize {
+ background: rgba(34, 197, 94, 0.1);
+ border-color: #4ade80;
+ color: #4ade80;
+}
+
+/* ── Response section ────────────────────────────────────────── */
+.swagger-ui .response-col_status {
+ color: #4ade80;
+ font-weight: 600;
+}
+
+.swagger-ui .response-col_description__inner p {
+ color: #cbd5e1;
+}
+
+/* ── Models section ──────────────────────────────────────────── */
+.swagger-ui section.models h4 {
+ color: #f1f5f9;
+ border-bottom: 1px solid #2d2d3a;
+}
+
+.swagger-ui .model-title {
+ color: #94a3b8;
+}
+
+.swagger-ui .model {
+ color: #cbd5e1;
+}
+
+.swagger-ui .prop-type {
+ color: #4ade80;
+}
+
+.swagger-ui .prop-format {
+ color: #94a3b8;
+}
+
+/* ── Auth modal ──────────────────────────────────────────────── */
+.swagger-ui .dialog-ux .modal-ux {
+ border: 1px solid #2d2d3a;
+ border-radius: 12px;
+}
+
+.swagger-ui .dialog-ux .modal-ux-header {
+ border-bottom: 1px solid #2d2d3a;
+ border-radius: 12px 12px 0 0;
+}
+
+.swagger-ui .dialog-ux .modal-ux-header h3 {
+ color: #f1f5f9;
+}
+
+.swagger-ui .dialog-ux .modal-ux-content p,
+.swagger-ui .dialog-ux .modal-ux-content label {
+ color: #94a3b8;
+}