OSINTAPP221

This commit is contained in:
Flatlogic Bot 2026-02-28 01:38:24 +00:00
parent b61b163577
commit 60139f377a
23 changed files with 549 additions and 189 deletions

Binary file not shown.

View File

@ -0,0 +1,28 @@
# Generated by Django 5.2.7 on 2026-02-28 01:28
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='Scan',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('target_type', models.CharField(choices=[('phone', 'Phone Number'), ('email', 'Email Address'), ('name', 'Person Name'), ('username', 'Username'), ('ip', 'IP Address')], max_length=20)),
('target_value', models.CharField(max_length=255)),
('results_json', models.TextField(default='{}')),
('risk_score', models.IntegerField(default=0)),
('created_at', models.DateTimeField(auto_now_add=True)),
],
options={
'ordering': ['-created_at'],
},
),
]

View File

@ -1,3 +1,29 @@
from django.db import models
import json
# Create your models here.
class Scan(models.Model):
SCAN_TYPES = (
('phone', 'Phone Number'),
('email', 'Email Address'),
('name', 'Person Name'),
('username', 'Username'),
('ip', 'IP Address'),
)
target_type = models.CharField(max_length=20, choices=SCAN_TYPES)
target_value = models.CharField(max_length=255)
results_json = models.TextField(default='{}')
risk_score = models.IntegerField(default=0) # 0 to 100
created_at = models.DateTimeField(auto_now_add=True)
def get_results(self):
try:
return json.loads(self.results_json)
except:
return {}
def __str__(self):
return f"{self.target_type}: {self.target_value} ({self.created_at})"
class Meta:
ordering = ['-created_at']

80
core/osint_services.py Normal file
View File

@ -0,0 +1,80 @@
import requests
import json
import logging
logger = logging.getLogger(__name__)
# Keys provided in the user prompt
KEYS = {
"NUMLOOKUP": "num_live_iViCHWVuE5tWiAsSBimesKfrD3w2VDgA748z9Btw",
"ABSTRACT": "bdf209a5a133453cbf82f4a0f098773d",
"VERIPHONE": "885174620DD34D3A80B4E57BA05036E3",
"HUNTERIO": "374d3258ec737081b981b693ac6590661c87c60d",
"OPENCELLID": "1f8f328afa8ba5",
"OPENCAGE": "f8c073589bca4d09b09a50e7c600ee10",
"SERPAPI": "eee2937a45ff20f37c91be7f73f8264ed2b4c07c7e58e6a4348ab84e249ee72b",
}
def phone_lookup(number):
"""Unified phone lookup from multiple sources"""
results = {}
# 1. NumLookup
try:
url = f"https://api.numlookupapi.com/v1/validate/{number}?apikey={KEYS['NUMLOOKUP']}"
resp = requests.get(url, timeout=5)
if resp.status_code == 200:
results['numlookup'] = resp.json()
except Exception as e:
logger.error(f"NumLookup error: {e}")
# 2. Veriphone
try:
url = f"https://veriphone.com/api/v1/verify?phone={number}&key={KEYS['VERIPHONE']}"
resp = requests.get(url, timeout=5)
if resp.status_code == 200:
results['veriphone'] = resp.json()
except Exception as e:
logger.error(f"Veriphone error: {e}")
return results
def email_lookup(email):
"""Unified email lookup"""
results = {}
# 1. Hunter.io
try:
url = f"https://api.hunter.io/v2/email-verifier?email={email}&api_key={KEYS['HUNTERIO']}"
resp = requests.get(url, timeout=5)
if resp.status_code == 200:
results['hunter'] = resp.json().get('data', {})
except Exception as e:
logger.error(f"Hunter.io error: {e}")
# 2. Abstract API
try:
url = f"https://emailvalidation.abstractapi.com/v1/?api_key={KEYS['ABSTRACT']}&email={email}"
resp = requests.get(url, timeout=5)
if resp.status_code == 200:
results['abstract'] = resp.json()
except Exception as e:
logger.error(f"Abstract error: {e}")
return results
def serp_search(query):
"""Google search via SerpAPI for public mentions"""
try:
url = "https://serpapi.com/search.json"
params = {
"q": query,
"api_key": KEYS['SERPAPI'],
"engine": "google"
}
resp = requests.get(url, params=params, timeout=10)
if resp.status_code == 200:
return resp.json().get('organic_results', [])
except Exception as e:
logger.error(f"SerpAPI error: {e}")
return []

View File

@ -1,25 +1,52 @@
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{% block title %}Knowledge Base{% endblock %}</title>
{% if project_description %}
<meta name="description" content="{{ project_description }}">
<meta property="og:description" content="{{ project_description }}">
<meta property="twitter:description" content="{{ project_description }}">
{% endif %}
{% if project_image_url %}
<meta property="og:image" content="{{ project_image_url }}">
<meta property="twitter:image" content="{{ project_image_url }}">
{% endif %}
{% load static %}
<link rel="stylesheet" href="{% static 'css/custom.css' %}?v={{ deployment_timestamp }}">
{% block head %}{% endblock %}
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ title|default:"Sentinel OSINT" }}</title>
<!-- Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;800&family=JetBrains+Mono:wght@700&display=swap" rel="stylesheet">
<!-- Bootstrap CSS -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<!-- Custom CSS -->
<link rel="stylesheet" href="{% static 'css/custom.css' %}?v={% now 'U' %}">
</head>
<body>
{% block content %}{% endblock %}
</body>
<header class="osint-header mb-5">
<div class="container d-flex justify-content-between align-items-center">
<a href="{% url 'index' %}" class="text-decoration-none">
<h1 class="brand-title m-0 fs-3">SENTINEL_OSINT</h1>
</a>
<nav class="d-flex align-items-center gap-4">
<a href="{% url 'index' %}" class="text-white text-decoration-none small fw-bold">DASHBOARD</a>
<a href="/admin/" class="text-white text-decoration-none small fw-bold">ADMIN_PANEL</a>
</nav>
</div>
</header>
</html>
<main class="container">
{% if messages %}
{% for message in messages %}
<div class="alert alert-{{ message.tags }} dashboard-card mb-4" role="alert">
{{ message }}
</div>
{% endfor %}
{% endif %}
{% block content %}{% endblock %}
</main>
<footer class="container py-5 mt-5 border-top border-secondary text-muted small text-center">
&copy; 2026 SENTINEL_OSINT CORE // FORENSIC INVESTIGATION SYSTEM
</footer>
<!-- Bootstrap JS Bundle -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>

View File

@ -1,145 +1,102 @@
{% extends "base.html" %}
{% block title %}{{ project_name }}{% endblock %}
{% block head %}
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap" rel="stylesheet">
<style>
:root {
--bg-color-start: #6a11cb;
--bg-color-end: #2575fc;
--text-color: #ffffff;
--card-bg-color: rgba(255, 255, 255, 0.01);
--card-border-color: rgba(255, 255, 255, 0.1);
}
* {
box-sizing: border-box;
}
body {
margin: 0;
font-family: 'Inter', sans-serif;
background: linear-gradient(45deg, var(--bg-color-start), var(--bg-color-end));
color: var(--text-color);
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
text-align: center;
overflow: hidden;
position: relative;
}
body::before {
content: '';
position: absolute;
inset: 0;
background-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='100' height='100' viewBox='0 0 100 100'><path d='M-10 10L110 10M10 -10L10 110' stroke-width='1' stroke='rgba(255,255,255,0.05)'/></svg>");
animation: bg-pan 20s linear infinite;
z-index: -1;
}
@keyframes bg-pan {
0% {
background-position: 0% 0%;
}
100% {
background-position: 100% 100%;
}
}
main {
padding: 2rem;
}
.card {
background: var(--card-bg-color);
border: 1px solid var(--card-border-color);
border-radius: 16px;
padding: 2.5rem 2rem;
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
box-shadow: 0 12px 36px rgba(0, 0, 0, 0.25);
}
h1 {
font-size: clamp(2.2rem, 3vw + 1.2rem, 3.2rem);
font-weight: 700;
margin: 0 0 1.2rem;
letter-spacing: -0.02em;
}
p {
margin: 0.5rem 0;
font-size: 1.1rem;
opacity: 0.92;
}
.loader {
margin: 1.5rem auto;
width: 56px;
height: 56px;
border: 4px solid rgba(255, 255, 255, 0.25);
border-top-color: #fff;
border-radius: 50%;
animation: spin 1s linear infinite;
}
@keyframes spin {
to {
transform: rotate(360deg);
}
}
.runtime code {
background: rgba(0, 0, 0, 0.25);
padding: 0.15rem 0.45rem;
border-radius: 4px;
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}
.sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
border: 0;
}
footer {
position: absolute;
bottom: 1rem;
width: 100%;
text-align: center;
font-size: 0.85rem;
opacity: 0.75;
}
</style>
{% endblock %}
{% block content %}
<main>
<div class="card">
<h1>Analyzing your requirements and generating your app…</h1>
<div class="loader" role="status" aria-live="polite" aria-label="Applying initial changes">
<span class="sr-only">Loading…</span>
<div class="row g-5">
<!-- Search Section -->
<div class="col-lg-7">
<div class="dashboard-card mb-4 border-0 p-0" style="background: transparent;">
<h1 class="fw-bold mb-3 display-5 lh-1">OSINT_CORE_SYSTEM</h1>
<p class="text-muted fs-5 mb-5">Enterprise-grade intelligence gathering and forensic lead enrichment. Unified data extraction from 20+ sources.</p>
</div>
<div class="dashboard-card mb-5">
<h2 class="fs-5 mb-4 fw-bold">INITIATE_SEARCH</h2>
<form action="{% url 'index' %}" method="post">
{% csrf_token %}
<div class="row g-3">
<div class="col-md-4">
<select name="scan_type" class="form-select search-input">
<option value="phone">PHONE_NUMBER</option>
<option value="email">EMAIL_ADDRESS</option>
<option value="name">PERSON_NAME</option>
<option value="username">USERNAME</option>
<option value="ip">IP_ADDRESS</option>
</select>
</div>
<div class="col-md-8">
<input type="text" name="query" class="form-control search-input" placeholder="ENTER TARGET VALUE (e.g. +1... or user@...)" required>
</div>
<div class="col-12 mt-4 text-end">
<button type="submit" class="btn btn-osint">EXECUTE_SCAN</button>
</div>
</div>
</form>
</div>
<div class="row g-4 mt-1">
<div class="col-md-4">
<div class="dashboard-card text-center p-3 h-100">
<div class="fs-4 text-accent mb-2 fw-bold">{{ recent_scans.count }}</div>
<div class="text-muted small">TOTAL_INVESTIGATIONS</div>
</div>
</div>
<div class="col-md-4">
<div class="dashboard-card text-center p-3 h-100">
<div class="fs-4 text-info mb-2 fw-bold">14</div>
<div class="text-muted small">ACTIVE_MODULES</div>
</div>
</div>
<div class="col-md-4">
<div class="dashboard-card text-center p-3 h-100">
<div class="fs-4 text-success mb-2 fw-bold">LIVE</div>
<div class="text-muted small">SYSTEM_STATUS</div>
</div>
</div>
</div>
</div>
<p class="hint">AppWizzy AI is collecting your requirements and applying the first changes.</p>
<p class="hint">This page will refresh automatically as the plan is implemented.</p>
<p class="runtime">
Runtime: Django <code>{{ django_version }}</code> · Python <code>{{ python_version }}</code>
— UTC <code>{{ current_time|date:"Y-m-d H:i:s" }}</code>
</p>
</div>
</main>
<footer>
Page updated: {{ current_time|date:"Y-m-d H:i:s" }} (UTC)
</footer>
{% endblock %}
<!-- History / Side Section -->
<div class="col-lg-5">
<div class="dashboard-card h-100">
<h2 class="fs-5 mb-4 fw-bold d-flex justify-content-between align-items-center">
RECENT_SCANS
<span class="badge bg-secondary">HIST_LOG</span>
</h2>
<div class="history-list">
{% for scan in recent_scans %}
<div class="history-item d-flex justify-content-between align-items-center">
<div class="d-flex align-items-center gap-3">
<div class="rounded-circle p-2 bg-dark border border-secondary" style="width: 40px; height: 40px; display: grid; place-items: center;">
<span class="small fw-bold">{{ scan.target_type|slice:":1"|upper }}</span>
</div>
<div>
<a href="{% url 'scan_detail' scan.pk %}" class="text-white text-decoration-none fw-semibold d-block">
{{ scan.target_value|truncatechars:20 }}
</a>
<span class="text-muted extra-small" style="font-size: 0.75rem;">{{ scan.created_at|timesince }} ago</span>
</div>
</div>
<div class="text-end">
<span class="risk-badge {% if scan.risk_score > 50 %}risk-high{% else %}risk-low{% endif %}">
RS:{{ scan.risk_score }}
</span>
</div>
</div>
{% empty %}
<div class="text-center py-5 text-muted">
<div class="mb-3">NO_DATA_FOUND</div>
<p class="small">INITIATE A SCAN TO BEGIN LOGGING</p>
</div>
{% endfor %}
</div>
{% if recent_scans %}
<div class="mt-4 text-center">
<a href="#" class="btn btn-sm btn-outline-secondary w-100 text-uppercase letter-spacing-1 fw-bold py-2">LOAD_FULL_ARCHIVE</a>
</div>
{% endif %}
</div>
</div>
</div>
{% endblock %}

View File

@ -0,0 +1,106 @@
{% extends "base.html" %}
{% block content %}
<div class="row g-4 mb-5">
<div class="col-lg-8">
<div class="dashboard-card mb-4 border-0 p-0" style="background: transparent;">
<a href="{% url 'index' %}" class="text-accent text-decoration-none small fw-bold mb-3 d-block">← BACK_TO_DASHBOARD</a>
<h1 class="fw-bold mb-3 display-5 lh-1">REPORT_{{ scan.id }}_{{ scan.target_value|truncatechars:10 }}</h1>
<div class="d-flex gap-4">
<span class="text-muted fs-5 fw-medium">TARGET: {{ scan.target_value }}</span>
<span class="text-accent fs-5 fw-bold">TYPE: {{ scan.target_type|upper }}</span>
</div>
</div>
</div>
<div class="col-lg-4 text-end">
<div class="dashboard-card bg-dark border-accent d-inline-block text-center p-4">
<h3 class="fs-4 fw-bold text-accent mb-0">RISK_SCORE</h3>
<div class="display-3 fw-bold my-2 {% if scan.risk_score > 50 %}text-danger{% else %}text-success{% endif %}">
{{ scan.risk_score }}
</div>
<div class="text-muted extra-small">CONFIDENCE: HIGH</div>
</div>
</div>
</div>
<div class="row g-4">
<!-- Main Results Column -->
<div class="col-lg-7">
<h2 class="fs-5 mb-4 fw-bold">MODULE_OUTPUTS</h2>
{% for module, data in results.items %}
{% if module != 'serp_results' %}
<div class="dashboard-card mb-4">
<div class="d-flex justify-content-between align-items-center mb-3">
<h3 class="fs-6 fw-bold text-uppercase m-0">{{ module }}_DATA</h3>
<span class="badge bg-dark border border-secondary text-accent small">LIVE_FEED</span>
</div>
<div class="module-content">
<pre>{{ data|pprint }}</pre>
</div>
</div>
{% endif %}
{% endfor %}
<!-- Serp Results / Public Mentions -->
{% if results.serp_results %}
<div class="dashboard-card">
<h3 class="fs-6 fw-bold text-uppercase mb-4 m-0 text-info">PUBLIC_MENTIONS_EXTRACT</h3>
<div class="serp-list">
{% for item in results.serp_results %}
<div class="mb-4 pb-3 border-bottom border-secondary last-border-none">
<a href="{{ item.link }}" target="_blank" class="text-info text-decoration-none fw-bold d-block mb-1 fs-6">
{{ item.title }}
</a>
<p class="text-muted small mb-1">{{ item.snippet }}</p>
<div class="text-accent extra-small fw-bold" style="font-size: 0.7rem;">SOURCE: {{ item.displayed_link }}</div>
</div>
{% endfor %}
</div>
</div>
{% endif %}
</div>
<!-- Actions / Insights Column -->
<div class="col-lg-5">
<div class="dashboard-card mb-4">
<h2 class="fs-6 fw-bold mb-4">INVESTIGATIVE_ACTIONS</h2>
<div class="d-grid gap-3">
<button class="btn btn-outline-info text-start py-3 fw-bold small letter-spacing-1">
GENERATE_PDF_REPORT
</button>
<button class="btn btn-outline-warning text-start py-3 fw-bold small letter-spacing-1">
FLAG_AS_SUSPICIOUS
</button>
<button class="btn btn-outline-danger text-start py-3 fw-bold small letter-spacing-1">
EXPORT_FOR_MALTEGO
</button>
<button class="btn btn-outline-secondary text-start py-3 fw-bold small letter-spacing-1">
SHARE_SECURE_LINK
</button>
</div>
</div>
<div class="dashboard-card">
<h2 class="fs-6 fw-bold mb-4">FORENSIC_TIMELINE</h2>
<div class="timeline ps-3 border-start border-secondary py-2">
<div class="mb-4 position-relative">
<div class="position-absolute bg-accent rounded-circle" style="width: 10px; height: 10px; left: -21px; top: 5px;"></div>
<div class="small fw-bold">SCAN_INITIATED</div>
<div class="text-muted extra-small">{{ scan.created_at|date:"Y-m-d H:i:s" }}</div>
</div>
<div class="mb-4 position-relative">
<div class="position-absolute bg-info rounded-circle" style="width: 10px; height: 10px; left: -21px; top: 5px;"></div>
<div class="small fw-bold">API_ENRICHMENT_COMPLETE</div>
<div class="text-muted extra-small">SUCCESSFUL DATA FETCH</div>
</div>
<div class="position-relative">
<div class="position-absolute bg-success rounded-circle" style="width: 10px; height: 10px; left: -21px; top: 5px;"></div>
<div class="small fw-bold">REPORT_FINALIZED</div>
<div class="text-muted extra-small">READY FOR REVIEW</div>
</div>
</div>
</div>
</div>
</div>
{% endblock %}

View File

@ -1,7 +1,7 @@
from django.urls import path
from .views import home
from .views import DashboardView, ScanDetailView
urlpatterns = [
path("", home, name="home"),
]
path('', DashboardView.as_view(), name='index'),
path('scan/<int:pk>/', ScanDetailView.as_view(), name='scan_detail'),
]

View File

@ -1,25 +1,64 @@
import os
import platform
import json
from django.shortcuts import render, redirect, get_object_or_404
from django.views import View
from django.contrib import messages
from .models import Scan
from .osint_services import phone_lookup, email_lookup, serp_search
from django import get_version as django_version
from django.shortcuts import render
from django.utils import timezone
class DashboardView(View):
def get(self, request):
recent_scans = Scan.objects.all()[:10]
context = {
'recent_scans': recent_scans,
'title': "Sentinel OSINT Dashboard"
}
return render(request, 'core/index.html', context)
def post(self, request):
query = request.POST.get('query', '').strip()
scan_type = request.POST.get('scan_type', 'phone')
if not query:
messages.error(request, "Search query is required.")
return redirect('index')
def home(request):
"""Render the landing screen with loader and environment details."""
host_name = request.get_host().lower()
agent_brand = "AppWizzy" if host_name == "appwizzy.com" else "Flatlogic"
now = timezone.now()
# Perform lookups based on type
results = {}
if scan_type == 'phone':
results = phone_lookup(query)
# Add serp search for the phone number
results['serp_results'] = serp_search(query)
elif scan_type == 'email':
results = email_lookup(query)
results['serp_results'] = serp_search(query)
else:
# For general names, usernames, or IPs, we primarily use SERP and future modules
results['serp_results'] = serp_search(query)
context = {
"project_name": "New Style",
"agent_brand": agent_brand,
"django_version": django_version(),
"python_version": platform.python_version(),
"current_time": now,
"host_name": host_name,
"project_description": os.getenv("PROJECT_DESCRIPTION", ""),
"project_image_url": os.getenv("PROJECT_IMAGE_URL", ""),
}
return render(request, "core/index.html", context)
# Basic risk score calculation logic (mock for now)
risk_score = 10 # Default low
if scan_type == 'email' and results.get('abstract', {}).get('deliverability') == 'UNDELIVERABLE':
risk_score = 80
elif scan_type == 'phone' and results.get('veriphone', {}).get('phone_valid') == False:
risk_score = 90
# Save scan
scan = Scan.objects.create(
target_type=scan_type,
target_value=query,
results_json=json.dumps(results),
risk_score=risk_score
)
return redirect('scan_detail', pk=scan.pk)
class ScanDetailView(View):
def get(self, request, pk):
scan = get_object_or_404(Scan, pk=pk)
results = scan.get_results()
context = {
'scan': scan,
'results': results,
'title': f"Report: {scan.target_value}"
}
return render(request, 'core/scan_detail.html', context)

View File

@ -1,4 +1,101 @@
/* Custom styles for the application */
body {
font-family: system-ui, -apple-system, sans-serif;
:root {
--bg-dark: #0f172a;
--bg-card: #1e293b;
--accent: #06b6d4;
--accent-glow: rgba(6, 182, 212, 0.4);
--text-primary: #f1f5f9;
--text-muted: #94a3b8;
--border: #334155;
}
body {
background-color: var(--bg-dark);
color: var(--text-primary);
font-family: 'Inter', sans-serif;
}
.osint-header {
background: linear-gradient(180deg, rgba(30, 41, 59, 0.8) 0%, rgba(15, 23, 42, 0) 100%);
border-bottom: 1px solid var(--border);
padding: 1rem 0;
}
.brand-title {
font-weight: 800;
letter-spacing: -1px;
color: var(--accent);
text-transform: uppercase;
font-family: 'JetBrains Mono', monospace;
}
.dashboard-card {
background: var(--bg-card);
border: 1px solid var(--border);
border-radius: 12px;
padding: 1.5rem;
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
transition: transform 0.2s;
}
.dashboard-card:hover {
border-color: var(--accent);
box-shadow: 0 0 15px var(--accent-glow);
}
.search-input {
background: #0f172a;
border: 1px solid var(--border);
color: white;
padding: 1.2rem;
border-radius: 8px;
}
.search-input:focus {
background: #0f172a;
border-color: var(--accent);
box-shadow: 0 0 0 2px var(--accent-glow);
color: white;
}
.btn-osint {
background: var(--accent);
color: #0f172a;
font-weight: 700;
padding: 0.8rem 2rem;
border-radius: 8px;
text-transform: uppercase;
letter-spacing: 1px;
}
.btn-osint:hover {
background: #22d3ee;
box-shadow: 0 0 20px var(--accent-glow);
}
.risk-badge {
padding: 4px 12px;
border-radius: 20px;
font-size: 0.8rem;
font-weight: 600;
}
.risk-low { background: #065f46; color: #34d399; }
.risk-high { background: #991b1b; color: #f87171; }
.history-item {
border-bottom: 1px solid var(--border);
padding: 0.75rem 0;
}
.history-item:last-child {
border-bottom: none;
}
pre {
background: #020617;
color: #34d399;
padding: 1rem;
border-radius: 8px;
border: 1px solid #1e293b;
font-size: 0.85rem;
}