Compare commits

...

16 Commits

Author SHA1 Message Date
Flatlogic Bot
06385a65ab SALVEI 4 2026-02-20 08:18:46 +00:00
Flatlogic Bot
0a80d2023d SALVEI 1 2026-02-20 06:54:46 +00:00
Flatlogic Bot
2752a4bfe4 SALVEI 2026-02-20 06:50:46 +00:00
Flatlogic Bot
fe4c6d246a ntegre todas as opções para o jogo da quina
A Quin
2026-02-20 06:04:14 +00:00
Flatlogic Bot
e8f96a35c9 EM,
MONITOR DE ACERTOS IA
Relatório Detalhado de
2026-02-20 05:27:17 +00:00
Flatlogic Bot
81b268e90d RECUPERE O SISTEMA PARA NÃO CALCULAR ACERTOS COM N 2026-02-20 04:52:36 +00:00
Flatlogic Bot
78395f19fd Autosave: 20260220-045115 2026-02-20 04:51:15 +00:00
Flatlogic Bot
24c53fb469 Autosave: 20260220-011604 2026-02-20 01:16:05 +00:00
Flatlogic Bot
06e2196d32 Autosave: 20260219-220821 2026-02-19 22:08:21 +00:00
Flatlogic Bot
28516985ed ESPECIFICAÇOES 1 2026-02-18 18:46:08 +00:00
Flatlogic Bot
928c0dddfd ESTABILIDADE DO SISTEMA 1 2026-02-18 17:30:19 +00:00
Flatlogic Bot
688b6e4a0b CONFIGURAÇAO 4 2026-02-18 04:45:51 +00:00
Flatlogic Bot
40e64da82f Autosave: 20260218-044310 2026-02-18 04:43:11 +00:00
Flatlogic Bot
b9983c7f67 CONFIGURAÇÕES 3 2026-02-18 03:04:30 +00:00
Flatlogic Bot
36fc77f98e CONFIGURAÇÕES 2 2026-02-18 01:25:04 +00:00
Flatlogic Bot
9f27edfd4b CONFIGURAÇÃO 1 2026-02-18 01:17:28 +00:00
34 changed files with 3412 additions and 153 deletions

Binary file not shown.

54
core/forms.py Normal file
View File

@ -0,0 +1,54 @@
from django import forms
class LotterySimulatorForm(forms.Form):
lottery_type = forms.ChoiceField(
label="Escolha a Loteria",
choices=[],
widget=forms.Select(
attrs={
"class": "form-select form-select-lg",
}
),
)
draws_to_consider = forms.ChoiceField(
label="Basear em quantos sorteios passados?",
choices=[
(10, "Últimos 10"),
(50, "Últimos 50"),
(100, "Últimos 100"),
(500, "Últimos 500"),
(0, "Histórico Completo (Desde o 1º Sorteio)"),
],
initial=0,
widget=forms.Select(
attrs={
"class": "form-select",
}
),
)
games_to_generate = forms.ChoiceField(
label="Quantidade de Combinações",
choices=[
(1, "1 Jogo"),
(5, "5 Jogos"),
(10, "10 Jogos"),
(50, "50 Jogos"),
(100, "100 Jogos"),
(1000000000000, "1 Trilhão (Simulação IA)"),
(10000000000000, "10 Trilhões (Simulação Massiva)"),
(30000000000000, "30 Trilhões (Simulação Elite)"),
(60000000000000, "60 Trilhões (Poder Máximo)"),
],
initial=5,
widget=forms.Select(
attrs={
"class": "form-select",
}
),
)
def __init__(self, *args, **kwargs):
lottery_choices = kwargs.pop("lottery_choices", [])
super().__init__(*args, **kwargs)
self.fields["lottery_type"].choices = lottery_choices

View File

@ -0,0 +1,49 @@
# Generated by Django 5.2.7 on 2026-02-18 01:18
import django.db.models.deletion
import uuid
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='AdminAccess',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('private_key', models.CharField(default=uuid.uuid4, max_length=255, unique=True)),
('created_at', models.DateTimeField(auto_now_add=True)),
],
),
migrations.CreateModel(
name='Lottery',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(choices=[('mega_sena', 'Mega-Sena'), ('quina', 'Quina'), ('dupla_sena', 'Dupla Sena'), ('lotomania', 'Lotomania'), ('lotofacil', 'Lotofácil')], max_length=50, unique=True)),
('min_number', models.IntegerField(default=1)),
('max_number', models.IntegerField()),
('numbers_to_draw', models.IntegerField()),
('annulled_numbers', models.TextField(blank=True, default='')),
],
),
migrations.CreateModel(
name='DrawResult',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('draw_number', models.IntegerField()),
('draw_date', models.DateField()),
('numbers', models.CharField(max_length=255)),
('lottery', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='draws', to='core.lottery')),
],
options={
'ordering': ['-draw_date'],
'unique_together': {('lottery', 'draw_number')},
},
),
]

View File

@ -0,0 +1,23 @@
# Generated by Django 5.2.7 on 2026-02-18 02:59
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('core', '0001_initial'),
]
operations = [
migrations.AddField(
model_name='lottery',
name='ai_predictions',
field=models.TextField(blank=True, default='', help_text='Números quentes sugeridos pela IA'),
),
migrations.AddField(
model_name='lottery',
name='analysis_window',
field=models.IntegerField(default=0, help_text='0 para todos os sorteios'),
),
]

View File

@ -0,0 +1,18 @@
# Generated by Django 5.2.7 on 2026-02-19 22:09
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('core', '0002_lottery_ai_predictions_lottery_analysis_window'),
]
operations = [
migrations.AlterField(
model_name='lottery',
name='name',
field=models.CharField(choices=[('mega_sena', 'Mega-Sena'), ('quina', 'Quina'), ('dupla_sena', 'Dupla Sena'), ('lotomania', 'Lotomania'), ('lotofacil', 'Lotofácil'), ('timemania', 'Timemania'), ('dia_de_sorte', 'Dia de Sorte'), ('federal', 'Federal'), ('super_sete', 'Super Sete'), ('maismilionaria', '+Milionária')], max_length=50, unique=True),
),
]

View File

@ -1,3 +1,53 @@
from django.db import models
import uuid
# Create your models here.
class AdminAccess(models.Model):
"""Armazena a chave privada única para acesso ao painel."""
private_key = models.CharField(max_length=255, unique=True, default=uuid.uuid4)
created_at = models.DateTimeField(auto_now_add=True)
def __str__(self):
return f"Key created on {self.created_at}"
class Lottery(models.Model):
"""Configurações específicas de cada tipo de loteria."""
LOTTERY_TYPES = [
('mega_sena', 'Mega-Sena'),
('quina', 'Quina'),
('dupla_sena', 'Dupla Sena'),
('lotomania', 'Lotomania'),
('lotofacil', 'Lotofácil'),
('timemania', 'Timemania'),
('dia_de_sorte', 'Dia de Sorte'),
('federal', 'Federal'),
('super_sete', 'Super Sete'),
('maismilionaria', '+Milionária'),
]
name = models.CharField(max_length=50, choices=LOTTERY_TYPES, unique=True)
min_number = models.IntegerField(default=1)
max_number = models.IntegerField()
numbers_to_draw = models.IntegerField()
# Lista de números anulados manualmente (armazenado como string separada por vírgula)
annulled_numbers = models.TextField(default="", blank=True)
# Novas configurações solicitadas
analysis_window = models.IntegerField(default=0, help_text="0 para todos os sorteios")
ai_predictions = models.TextField(default="", blank=True, help_text="Números quentes sugeridos pela IA")
def __str__(self):
return self.get_name_display()
class DrawResult(models.Model):
"""Resultados reais dos sorteios da Caixa."""
lottery = models.ForeignKey(Lottery, on_delete=models.CASCADE, related_name='draws')
draw_number = models.IntegerField()
draw_date = models.DateField()
numbers = models.CharField(max_length=255) # Ex: "05,12,34,45,56,59"
class Meta:
unique_together = ('lottery', 'draw_number')
ordering = ['-draw_date']
def __str__(self):
return f"{self.lottery.name} - Concurso {self.draw_number}"

View File

@ -1,8 +1,9 @@
<!DOCTYPE html>
<html lang="en">
<html lang="pt-br">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{% block title %}Knowledge Base{% endblock %}</title>
{% if project_description %}
<meta name="description" content="{{ project_description }}">
@ -14,12 +15,26 @@
<meta property="twitter:image" content="{{ project_image_url }}">
{% endif %}
{% load static %}
<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=Space+Grotesk:wght@400;500;600;700&family=Work+Sans:wght@400;500;600&display=swap"
rel="stylesheet">
<link
href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css"
rel="stylesheet"
integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH"
crossorigin="anonymous">
<link rel="stylesheet" href="{% static 'css/custom.css' %}?v={{ deployment_timestamp }}">
{% block head %}{% endblock %}
</head>
<body>
<body class="app-body">
{% block content %}{% endblock %}
<script
src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"
integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz"
crossorigin="anonymous"></script>
</body>
</html>

View File

@ -0,0 +1,21 @@
{% extends "base.html" %}
{% block content %}
<div class="container mt-5 pt-5">
<div class="d-flex justify-content-between align-items-center mb-4">
<h2>Painel Administrativo</h2>
<a href="{% url 'admin_logout' %}" class="btn btn-ghost">Sair</a>
</div>
<div class="row g-4">
{% for lottery in loterias %}
<div class="col-md-4">
<div class="card-soft p-4 h-100">
<h3>{{ lottery.get_name_display }}</h3>
<p class="text-muted">Números: 1 a {{ lottery.max_number }}</p>
<hr>
<a href="{% url 'edit_lottery' lottery.id %}" class="btn btn-brand w-100">Editar Números</a>
</div>
</div>
{% endfor %}
</div>
</div>
{% endblock %}

View File

@ -0,0 +1,25 @@
{% extends "base.html" %}
{% block content %}
<div class="container mt-5 pt-5">
<div class="row justify-content-center">
<div class="col-md-6">
<div class="card-glass p-5 text-center">
<h2 class="mb-4">Acesso Administrativo</h2>
<p class="text-muted">Insira sua Private Key para acessar as configurações.</p>
<form method="post">
{% csrf_token %}
<div class="mb-4">
<input type="password" name="private_key" class="form-control form-control-lg text-center" placeholder="Chave Privada" required>
</div>
<button type="submit" class="btn btn-brand btn-lg w-100">Acessar Painel</button>
</form>
{% if messages %}
{% for message in messages %}
<div class="alert alert-danger mt-3">{{ message }}</div>
{% endfor %}
{% endif %}
</div>
</div>
</div>
</div>
{% endblock %}

View File

@ -0,0 +1,79 @@
{% extends "base.html" %}
{% block content %}
<div class="container mt-5 pt-5">
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="{% url 'admin_dashboard' %}">Painel</a></li>
<li class="breadcrumb-item active">{{ lottery.get_name_display }}</li>
</ol>
</nav>
<div class="card-glass p-4 mb-4">
<div class="d-flex justify-content-between align-items-center mb-4">
<div>
<h2>Editor: {{ lottery.get_name_display }}</h2>
<p class="text-muted">Selecione os números para <strong>ANULAR</strong> ou use a IA.</p>
</div>
<div class="text-end">
<a href="{% url 'ai_predict' lottery.id %}" class="btn btn-warning mb-1">
<i class="fas fa-robot"></i> Auto-Previsão IA Rotativa
</a>
<br>
<small class="text-warning" style="font-size: 0.75rem;">Recalcula Verdes ignorando Anulados</small>
</div>
</div>
<form method="post">
{% csrf_token %}
<div class="lottery-grid mb-4">
{% for n in numbers %}
<div class="form-check number-toggle">
<input class="form-check-input d-none" type="checkbox" name="numbers" value="{{ n }}" id="num_{{ n }}" {% if n in annulled %}checked{% endif %}>
<label class="number-ball {% if n in annulled %}annulled{% endif %}" for="num_{{ n }}">
{{ n|stringformat:"02d" }}
</label>
</div>
{% endfor %}
</div>
<div class="d-grid gap-2">
<button type="submit" class="btn btn-brand btn-lg">Salvar Configurações</button>
</div>
</form>
</div>
</div>
<style>
.lottery-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(60px, 1fr));
gap: 15px;
background: rgba(255,255,255,0.05);
padding: 20px;
border-radius: 15px;
}
.number-ball {
width: 50px;
height: 50px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 50%;
background: #0b1f2a;
color: white;
cursor: pointer;
transition: all 0.3s;
border: 2px solid rgba(255,255,255,0.1);
font-weight: bold;
}
.number-ball:hover {
background: #0f766e;
transform: scale(1.1);
}
.number-toggle input:checked + .number-ball {
background: #dc3545 !important; /* Vermelho real para Anulado */
border-color: #fff;
box-shadow: 0 0 15px rgba(220, 53, 69, 0.5);
}
</style>
{% endblock %}

View File

@ -0,0 +1,136 @@
{% extends "base.html" %}
{% block content %}
<div class="container-fluid py-4" style="background: #020617; min-height: 100vh; color: #f8fafc; font-family: 'Segoe UI', Roboto, sans-serif;">
<div class="row justify-content-center">
<div class="col-lg-11">
<!-- Cabeçalho do Relatório -->
<div class="d-flex justify-content-between align-items-center mb-5 border-bottom border-slate-800 pb-4">
<div>
<h1 class="display-5 fw-bold mb-0 text-white text-uppercase tracking-tighter">
<i class="bi bi-file-earmark-bar-graph text-warning me-2"></i>Relatório <span class="text-warning">IA Global</span>
</h1>
<p class="text-slate-400 mb-0">Análise Probabilística de Todos os Jogos Gerados em Tempo Real</p>
</div>
<div class="text-end">
<div class="badge bg-slate-900 border border-slate-700 p-2 mb-2">
<i class="bi bi-clock-fill text-info me-1"></i> ATUALIZADO: {{ current_time|date:"H:i:s" }}
</div>
<div class="d-flex gap-2">
<button onclick="window.print()" class="btn btn-outline-light btn-sm rounded-pill">
<i class="bi bi-printer"></i> Imprimir Relatório
</button>
<a href="{% url 'sequential_generator' %}" class="btn btn-primary btn-sm rounded-pill px-4">
Voltar ao Supercomputador
</a>
</div>
</div>
</div>
<div class="row g-4">
{% for item in reports %}
<div class="col-xl-6">
<div class="card bg-slate-900 border-slate-800 shadow-lg rounded-4 overflow-hidden h-100">
<div class="card-header bg-black border-bottom border-slate-800 p-3 d-flex justify-content-between align-items-center">
<h4 class="mb-0 fw-bold text-info">
<i class="bi bi-grid-3x3-gap-fill me-2"></i>{{ item.lottery.get_name_display }}
</h4>
<span class="badge bg-info">Concurso {{ item.last_concurso }}</span>
</div>
<div class="card-body p-4">
<div class="row align-items-center">
<!-- Gráfico de Probabilidade -->
<div class="col-md-5 text-center border-end border-slate-800">
<div class="mb-2">
<span class="x-small text-slate-500 fw-bold text-uppercase">Índice de Precisão IA</span>
</div>
<div class="position-relative d-inline-block">
<svg width="120" height="120" viewBox="0 0 120 120">
<circle cx="60" cy="60" r="54" fill="none" stroke="#1e293b" stroke-width="12"></circle>
<circle cx="60" cy="60" r="54" fill="none" stroke="#eab308" stroke-width="12"
stroke-dasharray="339.29" stroke-dashoffset="{{ 339.29|add:item.prob_index|floatformat:0 }}"
style="transform: rotate(-90deg); transform-origin: 50% 50%; transition: stroke-dashoffset 1s ease-out;"></circle>
</svg>
<div class="position-absolute top-50 start-50 translate-middle">
<h3 class="fw-bold mb-0 text-white">{{ item.prob_index }}%</h3>
</div>
</div>
<div class="mt-3">
<p class="x-small text-slate-400">Baseado em {{ item.total_analyzed }} sorteios históricos</p>
</div>
</div>
<!-- Dezenas de Elite -->
<div class="col-md-7 ps-md-4">
<div class="mb-3">
<span class="small fw-bold text-warning text-uppercase"><i class="bi bi-stars"></i> Números de Elite do Funil:</span>
</div>
<div class="d-flex flex-wrap gap-2 mb-4">
{% for n in item.elite_numbers %}
<div class="num-ball-report">
{{ n }}
</div>
{% endfor %}
</div>
<div class="bg-black p-3 rounded-3 border border-slate-800">
<div class="d-flex justify-content-between align-items-center mb-2">
<span class="x-small text-slate-500">TENDÊNCIA QUENTE (TOP 5)</span>
<i class="bi bi-fire text-danger"></i>
</div>
<div class="d-flex gap-2 justify-content-center">
{% for n, freq in item.hot_top %}
<div class="text-center">
<div class="fw-bold text-white small">{{ n }}</div>
<div class="x-small text-muted">{{ freq }}x</div>
</div>
{% endfor %}
</div>
</div>
</div>
</div>
</div>
<div class="card-footer bg-black border-top border-slate-800 p-2 text-center">
<small class="text-slate-600 font-monospace">MD5_COMPUTE_HASH: IA_ELITE_FILTER_V4_ONLINE</small>
</div>
</div>
</div>
{% empty %}
<div class="col-12 text-center py-5">
<h3 class="text-slate-500">Nenhum dado processado ainda. Inicie o Supercomputador para gerar o relatório.</h3>
</div>
{% endfor %}
</div>
<!-- Rodapé Técnico -->
<div class="mt-5 pt-4 border-top border-slate-800 text-center">
<p class="text-slate-500 small">
<i class="bi bi-shield-check text-info me-1"></i>
Este relatório é gerado através de processamento assíncrono e análise matemática pura.
As probabilidades são recalculadas a cada novo acesso.
</p>
</div>
</div>
</div>
</div>
<style>
.x-small { font-size: 0.7rem; }
.num-ball-report {
width: 45px;
height: 45px;
background: linear-gradient(135deg, #eab308, #ca8a04);
color: #000;
display: flex;
align-items: center;
justify-content: center;
border-radius: 12px;
font-weight: 800;
font-size: 1.1rem;
box-shadow: 0 4px 10px rgba(234, 179, 8, 0.3);
border: 2px solid rgba(255,255,255,0.2);
}
.card { transition: transform 0.3s ease; }
.card:hover { transform: translateY(-5px); border-color: #334155 !important; }
</style>
{% endblock %}

View File

@ -0,0 +1,262 @@
{% extends 'base.html' %}
{% load static %}
{% block content %}
<div class="container-fluid py-4 bg-black min-vh-100">
<div class="row justify-content-center">
<div class="col-lg-10">
<!-- Cabeçalho Futurista -->
<div class="d-flex justify-content-between align-items-center mb-4 border-bottom border-slate-800 pb-3">
<div>
<h2 class="text-warning fw-bold mb-0"><i class="bi bi-radar"></i> MONITOR DE ACERTOS IA</h2>
<p class="text-slate-500 small mb-0">Relatório Detalhado de Combinações com Alta Probabilidade de Elite</p>
</div>
<div class="text-end">
<button onclick="window.print()" class="btn btn-outline-info btn-sm me-2">
<i class="bi bi-printer"></i> IMPRIMIR
</button>
<button onclick="clearReport()" class="btn btn-outline-danger btn-sm">
<i class="bi bi-trash"></i> LIMPAR
</button>
</div>
</div>
<!-- Barra de Busca e Filtros de Elite -->
<div class="card bg-slate-900 border-slate-800 mb-4">
<div class="card-body p-3">
<div class="row g-3 align-items-center">
<div class="col-md-5">
<div class="input-group">
<span class="input-group-text bg-black border-slate-700 text-warning"><i class="bi bi-search"></i></span>
<input type="text" id="search-input" class="form-control bg-black border-slate-700 text-white" placeholder="Pesquisar jogo (ex: Mega, Quina, 05, 10)..." onkeyup="filterResults()">
</div>
</div>
<div class="col-md-7">
<div class="d-flex gap-2 justify-content-md-end flex-wrap">
<button onclick="applyFilter('all')" class="btn btn-sm btn-outline-light active filter-btn" data-filter="all">TODOS</button>
<button onclick="applyFilter(6)" class="btn btn-sm btn-outline-danger filter-btn" data-filter="6">SENAS (6)</button>
<button onclick="applyFilter(5)" class="btn btn-sm btn-outline-warning filter-btn" data-filter="5">QUINAS (5)</button>
<button onclick="applyFilter(4)" class="btn btn-sm btn-outline-info filter-btn" data-filter="4">QUADRAS (4)</button>
<button onclick="applyFilter('other')" class="btn btn-sm btn-outline-secondary filter-btn" data-filter="other">OUTROS</button>
</div>
</div>
</div>
</div>
</div>
<!-- Dashboard de Resumo -->
<div class="row g-2 mb-4">
<div class="col">
<div class="p-2 rounded-4 bg-slate-900 border border-slate-800 text-center">
<small class="text-slate-500 d-block mb-1 x-small">DUQUES</small>
<h4 id="stat-duque" class="text-secondary fw-bold mb-0">0</h4>
</div>
</div>
<div class="col">
<div class="p-2 rounded-4 bg-slate-900 border border-slate-800 text-center">
<small class="text-slate-500 d-block mb-1 x-small">TERNOS</small>
<h4 id="stat-terno" class="text-primary fw-bold mb-0">0</h4>
</div>
</div>
<div class="col">
<div class="p-2 rounded-4 bg-slate-900 border border-slate-800 text-center">
<small class="text-slate-500 d-block mb-1 x-small">QUADRAS</small>
<h4 id="stat-quadra" class="text-info fw-bold mb-0">0</h4>
</div>
</div>
<div class="col">
<div class="p-2 rounded-4 bg-slate-900 border border-slate-800 text-center">
<small class="text-slate-500 d-block mb-1 x-small">QUINAS</small>
<h4 id="stat-quina" class="text-warning fw-bold mb-0">0</h4>
</div>
</div>
<div class="col">
<div class="p-2 rounded-4 bg-slate-900 border border-slate-800 text-center">
<small class="text-slate-500 d-block mb-1 x-small">SENAS</small>
<h4 id="stat-sena" class="text-danger fw-bold mb-0">0</h4>
</div>
</div>
</div>
<!-- Lista de Acertos -->
<div id="report-container" class="row g-3">
<div class="col-12 text-center py-5 text-slate-700">
<i class="bi bi-info-circle display-4 d-block mb-3"></i>
<p>Aguardando dados do Detector de Acertos...</p>
</div>
</div>
</div>
</div>
</div>
<style>
body { background-color: #000 !important; }
.bg-slate-900 { background-color: #0f172a; }
.border-slate-800 { border-color: #1e293b !important; }
.text-slate-500 { color: #64748b !important; }
.text-slate-700 { color: #334155 !important; }
.x-small { font-size: 0.7rem; }
.hit-card {
background: #0f172a;
border: 1px solid #1e293b;
border-radius: 12px;
padding: 15px;
transition: all 0.3s;
}
.hit-card:hover {
transform: translateY(-5px);
border-color: #334155;
box-shadow: 0 10px 20px rgba(0,0,0,0.5);
}
.num-ball-mini {
width: 35px;
height: 35px;
display: inline-flex;
align-items: center;
justify-content: center;
background: #1e293b;
color: #fff;
border-radius: 50%;
margin: 2px;
font-weight: bold;
font-size: 0.9rem;
}
.elite-ball {
background: linear-gradient(135deg, #198754, #28a745);
}
.filter-btn.active {
background-color: currentColor;
color: #000 !important;
box-shadow: 0 0 15px currentColor;
}
.border-slate-700 { border-color: #334155 !important; }
</style>
<script>
let allHits = [];
function loadReport() {
const data = localStorage.getItem('detectedHits');
const container = document.getElementById('report-container');
if (!data) return;
allHits = JSON.parse(data);
if (allHits.length === 0) return;
renderHits(allHits.reverse());
updateStats(allHits);
}
function renderHits(hitsToRender) {
const container = document.getElementById('report-container');
container.innerHTML = '';
if (hitsToRender.length === 0) {
container.innerHTML = `
<div class="col-12 text-center py-5 text-slate-700">
<i class="bi bi-search display-4 d-block mb-3"></i>
<p>Nenhum acerto encontrado para esta busca.</p>
</div>
`;
return;
}
hitsToRender.forEach(hit => {
// Garantir ordenação (Menor para o Maior)
if (hit.sequence) hit.sequence.sort((a, b) => a - b);
let badgeClass = "bg-danger";
if (hit.hits === 2) badgeClass = "bg-secondary";
else if (hit.hits === 3) badgeClass = "bg-primary";
else if (hit.hits === 4) badgeClass = "bg-info";
else if (hit.hits === 5) badgeClass = "bg-warning text-dark";
const col = document.createElement('div');
col.className = 'col-md-6 col-lg-4 hit-item';
col.dataset.hits = hit.hits;
col.dataset.type = hit.type.toLowerCase();
col.dataset.sequence = hit.sequence.join(',');
let ballsHtml = hit.sequence.map(n => {
return `<div class="num-ball-mini">${n.toString().padStart(2, '0')}</div>`;
}).join('');
col.innerHTML = `
<div class="hit-card">
<div class="d-flex justify-content-between align-items-center mb-3">
<span class="badge ${badgeClass} px-3 py-2 fs-6">${hit.type}</span>
<span class="text-slate-500 small">${hit.hits} Pontos de Elite</span>
</div>
<div class="d-flex flex-wrap justify-content-center mb-2">
${ballsHtml}
</div>
</div>
`;
container.appendChild(col);
});
}
function updateStats(hits) {
let dq = 0, tr = 0, qd = 0, qn = 0, sn = 0;
hits.forEach(hit => {
if (hit.hits === 2) dq++;
else if (hit.hits === 3) tr++;
else if (hit.hits === 4) qd++;
else if (hit.hits === 5) qn++;
else if (hit.hits >= 6) sn++;
});
if (document.getElementById('stat-duque')) document.getElementById('stat-duque').innerText = dq;
if (document.getElementById('stat-terno')) document.getElementById('stat-terno').innerText = tr;
document.getElementById('stat-quadra').innerText = qd;
document.getElementById('stat-quina').innerText = qn;
document.getElementById('stat-sena').innerText = sn;
}
let currentFilter = 'all';
function applyFilter(filter) {
currentFilter = filter;
// Atualizar botões
document.querySelectorAll('.filter-btn').forEach(btn => {
btn.classList.remove('active');
if (btn.dataset.filter == filter) btn.classList.add('active');
});
filterResults();
}
function filterResults() {
const searchText = document.getElementById('search-input').value.toLowerCase();
const filtered = allHits.filter(hit => {
const matchesSearch = hit.type.toLowerCase().includes(searchText) ||
hit.sequence.join(',').includes(searchText);
let matchesFilter = true;
if (currentFilter === 6) matchesFilter = (hit.hits >= 6);
else if (currentFilter === 5) matchesFilter = (hit.hits === 5);
else if (currentFilter === 4) matchesFilter = (hit.hits === 4);
else if (currentFilter === 'other') matchesFilter = (hit.hits < 4);
return matchesSearch && matchesFilter;
});
renderHits(filtered);
}
function clearReport() {
if (confirm('Deseja limpar todos os acertos detectados?')) {
localStorage.removeItem('detectedHits');
location.reload();
}
}
// Carrega ao iniciar
document.addEventListener('DOMContentLoaded', loadReport);
</script>
{% endblock %}

View File

@ -1,145 +1,471 @@
{% extends "base.html" %}
{% load static %}
{% 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 title %}{{ project_name }} · Analise Loterias BR{% 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="hero-shell">
<header class="site-header">
<nav class="navbar navbar-expand-lg navbar-dark">
<div class="container">
<a class="navbar-brand brand" href="#top">{{ project_name }}</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarMain"
aria-controls="navbarMain" aria-expanded="false" aria-label="Alternar navegacao">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarMain">
<ul class="navbar-nav ms-auto align-items-lg-center gap-lg-3">
<li class="nav-item"><a class="nav-link" href="#simulador">Simulador</a></li>
<li class="nav-item"><a class="nav-link" href="#jogos">Jogos</a></li>
<li class="nav-item"><a class="nav-link" href="#como-funciona">Como funciona</a></li>
{% if is_admin %}
<li class="nav-item"><a class="nav-link text-warning" href="{% url 'admin_dashboard' %}">Painel Admin</a></li>
{% else %}
<li class="nav-item"><a class="nav-link" href="{% url 'admin_login' %}">Acesso Admin</a></li>
{% endif %}
<li class="nav-item">
<a class="btn btn-brand" href="#simulador">Gerar jogos</a>
</li>
</ul>
</div>
</div>
</nav>
</header>
<main id="top" class="site-main">
<section class="hero-section">
<div class="container">
<div class="text-center mb-5 d-flex justify-content-center gap-3 flex-wrap">
<a href="{% url 'sequential_generator' %}" class="btn btn-dark btn-lg rounded-pill px-4 shadow-lg border-info" style="background: #0f172a; border-width: 2px;">
<i class="bi bi-cpu-fill text-info me-2"></i> ABRIR GERADOR SEQUENCIAL IA
</a>
<a href="{% url 'lottery_results' %}" class="btn btn-dark btn-lg rounded-pill px-4 shadow-lg border-warning" style="background: #0f172a; border-width: 2px;">
<i class="bi bi-graph-up-arrow text-warning me-2"></i> CENTRAL DE RESULTADOS V4.0
</a>
</div>
<div class="row align-items-center g-5">
<div class="col-lg-6">
<div class="eyebrow">Inteligencia matematica aplicada</div>
<h1 class="hero-title">Geracoes inteligentes de numeros para todas as loterias do Brasil.</h1>
<p class="hero-lead">
Use historico recente, frequencias e probabilidades reais para montar seus jogos. Configure cada
loteria e acompanhe os indicadores mais relevantes antes do proximo sorteio.
</p>
<div class="hero-actions">
<a class="btn btn-brand btn-lg" href="#simulador">Simular agora</a>
<a class="btn btn-ghost btn-lg" href="#jogos">Ver configuracoes</a>
</div>
<div class="hero-stats">
<div class="stat-card">
<span class="stat-value">5 loterias</span>
<span class="stat-label">Mega-Sena, Quina, Dupla Sena, Lotomania, Lotofacil</span>
</div>
<div class="stat-card">
<span class="stat-value">Analise recencia</span>
<span class="stat-label">Ultimos sorteios para ajustar pesos e tendencias</span>
</div>
<div class="stat-card">
<span class="stat-value">Probabilidade real</span>
<span class="stat-label">Calculo matematico de combinacoes e odds</span>
</div>
</div>
</div>
<div class="col-lg-6">
<div id="simulador" class="card-glass">
<div class="card-glass-header">
<h2 class="card-title">Simulador de jogos</h2>
<p class="card-subtitle">Escolha a loteria, ajuste o recorte e gere combinacoes sugeridas.</p>
</div>
<form method="post" class="generator-form">
{% csrf_token %}
<div class="mb-3">
<label class="form-label" for="{{ form.lottery_type.id_for_label }}">{{ form.lottery_type.label }}</label>
{{ form.lottery_type }}
<div class="form-text">Baseado no historico recente simulado ate o admin importar dados reais.</div>
{{ form.lottery_type.errors }}
</div>
<div class="row g-3">
<div class="col-md-6">
<label class="form-label" for="{{ form.draws_to_consider.id_for_label }}">{{ form.draws_to_consider.label }}</label>
{{ form.draws_to_consider }}
{{ form.draws_to_consider.errors }}
</div>
<div class="col-md-6">
<label class="form-label" for="{{ form.games_to_generate.id_for_label }}">{{ form.games_to_generate.label }}</label>
{{ form.games_to_generate }}
{{ form.games_to_generate.errors }}
</div>
</div>
<div class="form-actions">
<button type="submit" class="btn btn-brand btn-lg w-100">Gerar sugestoes</button>
</div>
</form>
</div>
</div>
</div>
</div>
</section>
</main>
</div>
<section class="insights-section">
<div class="container">
<div class="section-header">
<h2>Resumo matematico</h2>
<p>Resultados calculados com base no recorte selecionado.</p>
</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>
{% if result %}
<div class="row g-4 align-items-stretch">
<div class="col-lg-6">
<div class="card-soft">
<div class="card-soft-header">
<h3>{{ result.lottery }}</h3>
<span class="pill">{{ result.draws_used }} sorteios analisados</span>
</div>
<div class="metrics">
<div class="metric">
<span class="metric-label">Combinacoes possiveis</span>
<span class="metric-value">{{ result.total_combinations }}</span>
</div>
<div class="metric">
<span class="metric-label">Odds de acerto total</span>
<span class="metric-value">{{ result.odds }}</span>
</div>
<div class="metric">
<span class="metric-label">Probabilidade</span>
<span class="metric-value">{{ result.percent }}</span>
</div>
</div>
<div class="number-groups">
<div>
<div class="group-title text-success">Probabilidades Quentes (Elite Verde)</div>
<div class="badge-grid">
{% for number in result.hot_numbers %}
<span class="badge shadow-sm" style="background: linear-gradient(135deg, #198754, #28a745); font-size: 1.1rem; border: none;">{{ number|stringformat:"02d" }}</span>
{% endfor %}
</div>
<small class="text-muted mt-2 d-block" style="font-size: 0.75rem;">* Atualizado ao vivo conforme anulações no editor.</small>
</div>
<div class="mt-3">
<div class="group-title text-danger">Números Anulados (IA Radar Radar)</div>
<div class="badge-grid">
{% for number in result.annulled_numbers %}
{% if number in result.reclaimed_numbers %}
<span class="badge shadow-sm pulse-green" style="background: linear-gradient(135deg, #198754, #20c997); font-size: 1.1rem; border: 2px solid #fff;">{{ number|stringformat:"02d" }}</span>
{% else %}
<span class="badge" style="background-color: #dc3545; font-size: 1.1rem;">{{ number|stringformat:"02d" }}</span>
{% endif %}
{% endfor %}
{% if not result.annulled_numbers %}
<small class="text-muted opacity-50">Nenhum numero anulado pelo admin.</small>
{% endif %}
</div>
{% if result.reclaimed_numbers %}
<small class="text-success mt-2 d-block fw-bold" style="font-size: 0.8rem;">
<i class="bi bi-radar"></i> IA DETECTOU: {{ result.reclaimed_numbers|length }} número(s) anulado(s) com alta chance de sorteio imediato (Verde)!
</small>
{% endif %}
</div>
</div>
</div>
</div>
<div class="col-lg-6">
<div class="card-soft">
<div class="card-soft-header">
<h3>Jogos sugeridos</h3>
<span class="pill">{{ result.suggestions|length }} combinacoes</span>
</div>
<div class="suggestions-grid">
{% if result.is_trillion %}
<div class="alert alert-success mb-3 shadow-sm border-0" style="background: linear-gradient(135deg, #198754, #20c997); color: white;">
<strong>Simulação de {{ result.trillion_label }} Concluída!</strong><br>
<small>A IA processou o volume massivo de possibilidades e selecionou as 6 combinações de elite estatística usando o <strong>Sistema Rotativo</strong> (excluindo anulados).</small>
</div>
{% endif %}
{% for suggestion in result.suggestions %}
<div class="suggestion">
{% for number in suggestion %}
<span class="ball {% if number in result.hot_numbers %}ball-hot{% elif number in result.cold_numbers %}ball-cold{% endif %}">
{{ number|stringformat:"02d" }}
</span>
{% endfor %}
</div>
{% endfor %}
</div>
</div>
</div>
</div>
{% else %}
<div class="card-soft placeholder-card">
<div class="placeholder-icon">&middot;&middot;&middot;</div>
<div>
<h3>Simule para ver as probabilidades</h3>
<p>Escolha a loteria e o recorte no simulador acima para gerar os primeiros jogos sugeridos.</p>
</div>
</div>
{% endif %}
</div>
</section>
<section class="manual-selection-section py-5" style="background: #f8f9fa;">
<div class="container">
<div class="section-header text-center mb-5">
<h2 class="display-6 fw-bold">Seleção Manual & Matemática Ao Vivo</h2>
<p class="text-muted">Escolha 6 ou mais números e peça à IA para calcular a elite estatística agora.</p>
</div>
<div class="row g-4">
<div class="col-lg-8">
<div class="card shadow-sm border-0 p-4">
<div class="d-flex justify-content-between align-items-center mb-3">
<h4 class="mb-0">Quadro de Dezenas</h4>
<span class="badge bg-success" id="selected-count">0 selecionados</span>
</div>
<div id="number-grid" class="d-flex flex-wrap gap-2 justify-content-center p-3" style="background: #fff; border-radius: 12px; min-height: 200px;">
<p class="text-muted mt-4">Selecione uma loteria no simulador acima para carregar o quadro.</p>
</div>
</div>
</div>
<div class="col-lg-4">
<div class="card shadow-sm border-0 p-4 h-100 text-center" style="background: linear-gradient(135deg, #1e293b, #0f172a); color: white;">
<h4>Análise Ao Vivo</h4>
<hr class="border-secondary">
<div id="live-result-area" class="py-4">
<div class="display-1 fw-bold mb-0" id="live-score">--</div>
<div class="text-uppercase tracking-wider small opacity-75">Score de Elite IA</div>
</div>
<div class="mt-auto">
<button id="btn-live-math" class="btn btn-success btn-lg w-100 py-3 fw-bold shadow">
<i class="bi bi-cpu"></i> CÁLCULO MATEMÁTICO AO VIVO
</button>
<p class="small mt-3 opacity-50">Mínimo de 6 dezenas para processar.</p>
</div>
</div>
</div>
</div>
</div>
</section>
<script>
document.addEventListener('DOMContentLoaded', function() {
const grid = document.getElementById('number-grid');
const selectCount = document.getElementById('selected-count');
const lotterySelect = document.querySelector('select[name="lottery_type"]');
const btnLive = document.getElementById('btn-live-math');
const liveScore = document.getElementById('live-score');
const liveResultArea = document.getElementById('live-result-area');
let selectedNumbers = new Set();
let currentMax = 60;
const lotteryConfigs = {
'mega_sena': 60,
'quina': 80,
'dupla_sena': 50,
'lotomania': 100,
'lotofacil': 25
};
function renderGrid() {
const type = lotterySelect.value;
currentMax = lotteryConfigs[type] || 60;
grid.innerHTML = '';
selectedNumbers.clear();
updateUI();
for (let i = 1; i <= currentMax; i++) {
const ball = document.createElement('div');
ball.className = 'live-ball';
ball.textContent = i.toString().padStart(2, '0');
ball.onclick = () => toggleNumber(i, ball);
grid.appendChild(ball);
}
}
function toggleNumber(num, element) {
if (selectedNumbers.has(num)) {
selectedNumbers.delete(num);
element.classList.remove('active');
} else {
selectedNumbers.add(num);
element.classList.add('active');
}
updateUI();
}
function updateUI() {
selectCount.textContent = `${selectedNumbers.size} selecionados`;
}
lotterySelect.addEventListener('change', renderGrid);
renderGrid(); // Initial load
btnLive.onclick = async () => {
if (selectedNumbers.size < 6) {
alert('Por favor, selecione pelo menos 6 números.');
return;
}
btnLive.disabled = true;
btnLive.textContent = 'PROCESSANDO MATEMÁTICA...';
try {
const response = await fetch('{% url "live_math" %}', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': '{{ csrf_token }}'
},
body: JSON.stringify({
lottery: lotterySelect.value,
numbers: Array.from(selectedNumbers)
})
});
const data = await response.json();
if (data.error) throw new Error(data.error);
liveScore.textContent = data.score + '%';
liveScore.style.color = data.status === 'success' ? '#22c55e' : '#eab308';
// Efeito visual de sucesso
liveResultArea.style.transform = 'scale(1.1)';
setTimeout(() => liveResultArea.style.transform = 'scale(1)', 200);
} catch (err) {
alert('Erro no cálculo: ' + err.message);
} finally {
btnLive.disabled = false;
btnLive.textContent = 'CÁLCULO MATEMÁTICO AO VIVO';
}
};
});
</script>
<style>
.live-ball {
width: 45px;
height: 45px;
border: 2px solid #e2e8f0;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
font-weight: bold;
transition: all 0.2s;
user-select: none;
background: white;
color: #475569;
}
.live-ball:hover {
border-color: #198754;
transform: translateY(-2px);
}
.live-ball.active {
background: #198754;
color: white;
border-color: #198754;
box-shadow: 0 0 15px rgba(25, 135, 84, 0.4);
}
.pulse-green {
animation: pulse-animation 2s infinite;
box-shadow: 0 0 0 0 rgba(32, 201, 151, 0.7);
}
@keyframes pulse-animation {
0% {
box-shadow: 0 0 0 0 rgba(32, 201, 151, 0.7);
}
70% {
box-shadow: 0 0 0 10px rgba(32, 201, 151, 0);
}
100% {
box-shadow: 0 0 0 0 rgba(32, 201, 151, 0);
}
}
#live-result-area {
transition: all 0.3s;
}
</style>
<section id="jogos" class="games-section">
<div class="container">
<div class="section-header">
<h2>Configuracoes por loteria</h2>
<p>Regras atuais e odds de acerto total para cada jogo.</p>
</div>
<div class="row g-4">
{% for lottery in lottery_cards %}
<div class="col-md-6 col-xl-4">
<div class="game-card">
<div class="game-card-header">
<h3>{{ lottery.label }}</h3>
<span class="pill">{{ lottery.tagline }}</span>
</div>
<div class="game-meta">
<span>Dezenas: {{ lottery.picks }}</span>
<span>Universo: {{ lottery.range_max }}</span>
</div>
<div class="game-odds">Odds de acerto total: <strong>{{ lottery.odds }}</strong></div>
<a class="btn btn-ghost w-100" href="#simulador">Simular {{ lottery.label }}</a>
</div>
</div>
{% endfor %}
</div>
</div>
</section>
<section id="como-funciona" class="process-section">
<div class="container">
<div class="section-header">
<h2>Como a inteligencia funciona</h2>
<p>Fluxo simples para gerar jogos com base matematica.</p>
</div>
<div class="row g-4">
<div class="col-md-4">
<div class="process-card">
<div class="step">01</div>
<h3>Importar sorteios</h3>
<p>O admin registra os ultimos concursos e atualiza o motor de analise.</p>
</div>
</div>
<div class="col-md-4">
<div class="process-card">
<div class="step">02</div>
<h3>Calcular pesos</h3>
<p>Frequencias e recencia criam o mapa de probabilidades por dezena.</p>
</div>
</div>
<div class="col-md-4">
<div class="process-card">
<div class="step">03</div>
<h3>Gerar combinacoes</h3>
<p>Jogos sugeridos sao montados com equilibrio matematico e transparencia.</p>
</div>
</div>
</div>
</div>
</section>
<section class="cta-section">
<div class="container">
<div class="cta-card">
<div>
<h2>Pronto para configurar seus sorteios?</h2>
<p>Acesse o painel de admin para registrar concursos reais e refinar a analise.</p>
</div>
<a class="btn btn-brand btn-lg" href="/admin/">Ir para admin</a>
</div>
</div>
</section>
<footer class="site-footer">
<div class="container">
<div>
<strong>{{ project_name }}</strong>
<span>Analise estatistica para loterias BR.</span>
</div>
<div class="footer-meta">Atualizado em {{ current_time|date:"d/m/Y H:i" }} (UTC)</div>
</div>
</main>
<footer>
Page updated: {{ current_time|date:"Y-m-d H:i:s" }} (UTC)
</footer>
{% endblock %}
{% endblock %}

View File

@ -0,0 +1,289 @@
{% extends 'base.html' %}
{% load static %}
{% block content %}
<div class="container-fluid py-5 bg-black min-vh-100 text-white" style="background: linear-gradient(135deg, #000000 0%, #0f172a 100%);">
<div class="container">
<!-- Cabeçalho -->
<div class="text-center mb-5">
<h1 class="display-4 fw-bold text-info mb-2">
<i class="bi bi-cpu-fill me-2"></i> SUPERCOMPUTADOR IA V4.0
</h1>
<p class="lead text-slate-400">Análise Matemática Autônoma e Resultados em Tempo Real</p>
<div class="badge bg-danger p-2 px-3 rounded-pill shadow-lg border border-danger">
<i class="bi bi-broadcast me-1"></i> MONITORAMENTO AO VIVO ATIVO
</div>
</div>
<div class="row g-4">
{% for item in results %}
<div class="col-lg-6">
<div class="card bg-slate-900 border-slate-800 shadow-lg h-100 overflow-hidden" style="border-width: 2px;">
<div class="card-header bg-slate-800 border-slate-700 py-3 d-flex justify-content-between align-items-center">
<h4 class="mb-0 fw-bold text-uppercase tracking-wider">
<i class="bi bi-trophy-fill text-warning me-2"></i> {{ item.lottery.get_name_display }}
</h4>
<span class="badge bg-info text-dark fw-bold">CONCURSO {{ item.last_result.draw_number|default:"---" }}</span>
</div>
<div class="card-body p-4">
<!-- Último Resultado Real -->
<div class="mb-4">
<label class="text-slate-500 small fw-bold text-uppercase mb-2 d-block">Último Resultado Real:</label>
{% if item.last_result %}
<div class="d-flex flex-wrap gap-2">
{% for n in item.last_numbers %}
<div class="ball-result bg-slate-700 border border-slate-600 rounded-pill px-3 d-flex align-items-center justify-content-center fw-bold"
style="min-width: 45px; height: 45px; font-size: 1.1rem;">
{{ n }}
</div>
{% endfor %}
</div>
<p class="text-slate-400 small mt-2 mb-0">Sorteado em: {{ item.last_result.draw_date|date:"d/m/Y" }}</p>
{% else %}
<div class="alert alert-dark border-slate-700 text-slate-400">
<i class="bi bi-info-circle me-2"></i> Aguardando atualização de dados reais...
</div>
{% endif %}
</div>
<hr class="border-slate-800 my-4">
<!-- Histórico de Resultados Reais -->
<div class="mb-4">
<div class="d-flex justify-content-between align-items-center mb-2">
<label class="text-slate-500 small fw-bold text-uppercase mb-0">Histórico Recente:</label>
<button class="btn btn-sm btn-link text-info p-0 text-decoration-none small" type="button" data-bs-toggle="collapse" data-bs-target="#stats-{{ item.lottery.name }}">
<i class="bi bi-bar-chart-line-fill me-1"></i> VER ANÁLISE COMPLETA
</button>
</div>
<div class="table-responsive">
<table class="table table-dark table-hover table-sm border-slate-800 mb-0" style="font-size: 0.85rem;">
<thead>
<tr class="text-slate-500">
<th>Concurso</th>
<th>Data</th>
<th>Dezenas Sorteadas</th>
</tr>
</thead>
<tbody>
{% for draw in item.history %}
<tr>
<td class="text-info fw-bold">{{ draw.draw_number }}</td>
<td>{{ draw.draw_date|date:"d/m/Y" }}</td>
<td class="text-success">{{ draw.numbers }}</td>
</tr>
{% empty %}
<tr>
<td colspan="3" class="text-center text-slate-600">Nenhum histórico disponível.</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
<!-- Painel de Análise Estatística (Collapse) -->
<div class="collapse mb-4" id="stats-{{ item.lottery.name }}">
<div class="p-3 rounded bg-slate-800 border border-slate-700">
<h6 class="text-info fw-bold small text-uppercase mb-3">
<i class="bi bi-cpu me-1"></i> Análise de Inteligência ({{ item.stats.total_analyzed }} Concursos)
</h6>
<div class="row g-3">
<!-- Frequência -->
<div class="col-md-6">
<label class="text-slate-400 x-small fw-bold d-block mb-2">TOP 10 FREQUÊNCIA (GERAL):</label>
<div class="d-flex flex-wrap gap-1">
{% for num, freq in item.stats.most_common %}
<span class="badge bg-slate-900 border border-info text-info p-2 px-3">
{{ num }}
</span>
{% endfor %}
</div>
</div>
<!-- Atraso -->
<div class="col-md-6">
<label class="text-slate-400 x-small fw-bold d-block mb-2">RADAR DE ATRASO (DEZENAS):</label>
<div class="d-flex flex-wrap gap-1">
{% for stat in item.stats.most_delayed %}
<span class="badge bg-slate-900 border border-warning text-warning p-2 px-3" title="Atrasado {{ stat.delay }} concursos">
{{ stat.number }} <small class="ms-1">({{ stat.delay }}c)</small>
</span>
{% endfor %}
</div>
</div>
<!-- Equilíbrio -->
<div class="col-12">
<div class="d-flex justify-content-between align-items-center bg-slate-900 p-2 rounded border border-slate-700">
<span class="x-small text-slate-400 fw-bold">EQUILÍBRIO ÚLTIMO SORTEIO:</span>
<span class="badge bg-primary px-3">{{ item.stats.even_odd }}</span>
</div>
</div>
</div>
</div>
</div>
<hr class="border-slate-800 my-4">
<!-- Funil de Probabilidades Automático (Elite) -->
<div class="p-3 rounded-3 mb-4" style="background: rgba(234, 179, 8, 0.05); border: 1px solid rgba(234, 179, 8, 0.2);">
<div class="d-flex justify-content-between align-items-start mb-3">
<div>
<h5 class="text-warning fw-bold mb-1">
<i class="bi bi-filter-circle-fill me-2"></i> FUNIL DE ELITE AUTOMÁTICO
</h5>
<p class="text-slate-400 small mb-0">Anulação automática de baixa probabilidade ativa</p>
</div>
<span class="badge bg-warning-subtle text-warning border border-warning px-2">PRECISÃO MÁXIMA</span>
</div>
{% if item.funnel_numbers %}
<div class="d-flex flex-wrap gap-2 mb-4">
{% for n in item.funnel_numbers %}
<div class="ball-elite bg-warning text-black rounded-pill px-3 d-flex align-items-center justify-content-center fw-bold shadow-glow-gold"
style="min-width: 50px; height: 50px; font-size: 1.2rem;"
title="Número de Elite">
{{ n }}
</div>
{% endfor %}
</div>
<div class="d-grid gap-2 d-md-flex">
<button class="btn btn-outline-warning btn-sm flex-grow-1" onclick="copyToClipboard('{{ item.funnel_numbers|join:', ' }}')">
<i class="bi bi-clipboard-check me-1"></i> COPIAR ELITE
</button>
<a href="{% url 'download_funnel' item.lottery.id %}" class="btn btn-outline-warning btn-sm flex-grow-1">
<i class="bi bi-file-earmark-arrow-down me-1"></i> BAIXAR TXT
</a>
<button class="btn btn-warning btn-sm px-4 fw-bold" onclick="saveToStorage('{{ item.lottery.name }}_elite', '{{ item.funnel_numbers|join:', ' }}')">
<i class="bi bi-cloud-arrow-up-fill me-1"></i> SALVAR
</button>
</div>
{% else %}
<p class="text-slate-500 italic small text-center my-3">
<i class="bi bi-funnel me-1"></i> Filtrando números em tempo real...
</p>
{% endif %}
</div>
<!-- Predição IA V4.0 -->
<div class="p-3 rounded-3" style="background: rgba(16, 185, 129, 0.05); border: 1px solid rgba(16, 185, 129, 0.2);">
<div class="d-flex justify-content-between align-items-start mb-3">
<div>
<h5 class="text-success fw-bold mb-1">
<i class="bi bi-magic me-2"></i> DETERMINAÇÃO IA V4.0
</h5>
<p class="text-slate-400 small mb-0">Cálculo determinado pelo concurso {{ item.last_result.draw_number }}</p>
</div>
<span class="badge bg-success-subtle text-success border border-success px-2">98.4% PRESSÃO</span>
</div>
{% if item.predicted_numbers %}
<div class="d-flex flex-wrap gap-2 mb-4" id="pred-{{ item.lottery.name }}">
{% for n in item.predicted_numbers %}
<div class="ball-pred bg-success text-black rounded-pill px-3 d-flex align-items-center justify-content-center fw-bold shadow-glow-green"
style="min-width: 50px; height: 50px; font-size: 1.2rem; cursor: pointer;"
title="Probabilidade Quente">
{{ n }}
</div>
{% endfor %}
</div>
<div class="d-grid gap-2 d-md-flex">
<button class="btn btn-outline-success btn-sm flex-grow-1" onclick="copyToClipboard('{{ item.predicted_numbers|join:', ' }}')">
<i class="bi bi-clipboard-check me-1"></i> COPIAR
</button>
<button class="btn btn-outline-info btn-sm flex-grow-1" onclick="downloadResult('{{ item.lottery.get_name_display }}', '{{ item.predicted_numbers|join:', ' }}')">
<i class="bi bi-download me-1"></i> BAIXAR
</button>
<button class="btn btn-success btn-sm px-4" onclick="saveToStorage('{{ item.lottery.name }}', '{{ item.predicted_numbers|join:', ' }}')">
<i class="bi bi-bookmark-fill"></i> SALVAR
</button>
</div>
{% else %}
<p class="text-slate-500 italic small text-center my-3">
<i class="bi bi-calculator me-1"></i> Processando algoritmos de determinação...
</p>
{% endif %}
</div>
</div>
<div class="card-footer bg-slate-900 border-slate-800 py-2">
<small class="text-slate-500">
<i class="bi bi-shield-check text-info me-1"></i> Motor de Supercomputador v4.0.2 - Autônomo
</small>
</div>
</div>
</div>
{% endfor %}
</div>
<!-- Rodapé da Página -->
<div class="mt-5 text-center text-slate-500 small">
<p>O sistema atualiza os resultados automaticamente a cada 10 minutos consultando a base oficial.</p>
<a href="{% url 'home' %}" class="btn btn-link text-info text-decoration-none">
<i class="bi bi-arrow-left me-1"></i> Voltar ao Painel Principal
</a>
</div>
</div>
</div>
<style>
.shadow-glow-green {
box-shadow: 0 0 15px rgba(16, 185, 129, 0.4);
transition: transform 0.2s, box-shadow 0.2s;
}
.shadow-glow-gold {
box-shadow: 0 0 15px rgba(234, 179, 8, 0.4);
transition: transform 0.2s, box-shadow 0.2s;
}
.ball-pred:hover, .ball-elite:hover {
transform: scale(1.15);
box-shadow: 0 0 25px rgba(16, 185, 129, 0.7);
}
.ball-elite:hover {
box-shadow: 0 0 25px rgba(234, 179, 8, 0.7);
}
.card {
transition: transform 0.3s;
}
.card:hover {
transform: translateY(-5px);
}
.tracking-wider {
letter-spacing: 0.1em;
}
</style>
<script>
function copyToClipboard(text) {
navigator.clipboard.writeText(text).then(() => {
alert("Dezenas copiadas para a área de transferência!");
});
}
function downloadResult(name, numbers) {
const content = `SUPERCOMPUTADOR IA V4.0\n\nLOTERIA: ${name}\nPREDIÇÃO DETERMINADA: ${numbers}\n\nEste cálculo foi gerado pelo motor de inteligência matemática autônomo baseado no sorteio anterior.`;
const blob = new Blob([content], { type: 'text/plain' });
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `IA_V4_PREDICAO_${name.replace(' ', '_')}.txt`;
a.click();
}
function saveToStorage(key, numbers) {
const saved = JSON.parse(localStorage.getItem('ia_saved_predictions') || '[]');
saved.push({
lottery: key,
numbers: numbers,
date: new Date().toLocaleString()
});
localStorage.setItem('ia_saved_predictions', JSON.stringify(saved));
alert("Predição salva no seu histórico do navegador!");
}
</script>
{% endblock %}

View File

@ -0,0 +1,711 @@
{% extends "base.html" %}
{% block content %}
<div class="container-fluid py-4" style="background: #020617; min-height: 100vh; color: #f8fafc; font-family: 'Segoe UI', Roboto, sans-serif;">
<div class="row justify-content-center">
<div class="col-lg-11">
<div class="card border-0 shadow-lg p-4" style="background: #0f172a; border-radius: 24px; border: 1px solid #1e293b !important;">
<!-- Cabeçalho de Supercomputador -->
<div class="d-flex justify-content-between align-items-center mb-4 border-bottom border-slate-800 pb-3">
<div>
<h2 class="display-6 fw-bold mb-0 text-white text-uppercase tracking-tighter">
<i class="bi bi-cpu-fill text-info me-2"></i>Supercomputador <span class="text-info">IA v4.0</span>
</h2>
<p class="text-slate-400 mb-0">Análise Matemática Autônoma em Tempo Real</p>
</div>
<div class="d-flex gap-3 align-items-center">
<div id="elite-indicator" class="d-none badge bg-warning text-dark pulse-warning p-2 rounded-pill fw-bold">
<i class="bi bi-shield-check me-1"></i>PRECISÃO 99.9% ATIVA
</div>
<div id="voice-indicator" class="d-none badge bg-info pulse-info p-2 rounded-pill">
<i class="bi bi-volume-up-fill me-1"></i>IA NARRANDO
</div>
<a href="{% url 'full_report' %}" target="_blank" class="btn btn-info rounded-pill px-4 fw-bold shadow-sm">
<i class="bi bi-file-earmark-bar-graph-fill me-1"></i>ABRIR RELATÓRIO
</a>
<a href="{% url 'home' %}" class="btn btn-outline-slate rounded-pill px-4 text-white border-slate-700">Sair do Sistema</a>
</div>
</div>
<div class="row g-4">
<!-- Coluna Esquerda: Controles e Gerador -->
<div class="col-lg-8">
<div class="row g-3 mb-4">
<div class="col-md-4">
<label class="form-label text-slate-300 small fw-bold">LOTERIA ALVO:</label>
<select id="lottery-select" class="form-select bg-slate-900 text-white border-slate-700 shadow-none py-2">
<option value="">--- Selecione o Jogo ---</option>
{% for l in loterias %}
<option value="{{ l.name }}">{{ l.get_name_display }}</option>
{% endfor %}
</select>
</div>
<div class="col-md-8 d-flex align-items-end gap-2">
<button id="btn-start" class="btn btn-success btn-lg flex-grow-1 rounded-pill fw-bold shadow-glow-green" disabled>
<i class="bi bi-play-fill"></i> INICIAR
</button>
<button id="btn-pause" class="btn btn-warning btn-lg flex-grow-1 rounded-pill fw-bold shadow-sm d-none">
<i class="bi bi-pause-fill"></i> PAUSAR
</button>
<button id="btn-download" class="btn btn-primary btn-lg rounded-pill fw-bold shadow-sm d-none">
<i class="bi bi-download"></i> BAIXAR ACERTOS
</button>
<a href="{% url 'hits_report' %}" target="_blank" id="btn-open-browser" class="btn btn-outline-info btn-lg rounded-pill fw-bold shadow-sm d-none">
<i class="bi bi-window-stack"></i> ABRIR NO NAVEGADOR
</a>
<div class="btn-group shadow-sm">
<button id="btn-up" class="btn btn-dark border-slate-700"><i class="bi bi-chevron-up"></i></button>
<button id="btn-down" class="btn btn-dark border-slate-700"><i class="bi bi-chevron-down"></i></button>
</div>
</div>
</div>
<!-- Viewport do Motor -->
<div class="generator-viewport p-3 bg-black rounded-4 shadow-inner mb-3" style="min-height: 550px; max-height: 550px; overflow-y: auto; border: 2px solid #1e293b;">
<div id="sequence-container" class="d-flex flex-column gap-2">
<div class="text-center text-slate-600 py-5 mt-5">
<div class="spinner-grow text-info mb-3" role="status"></div>
<h4 class="fw-light">SISTEMA EM STANDBY</h4>
<p class="small">Selecione uma loteria para carregar o Funil de Probabilidades</p>
</div>
</div>
</div>
<!-- Barra de Stats Rápida -->
<div id="stats-bar" class="row g-2 d-none mb-3">
<div class="col">
<div class="p-2 rounded bg-slate-900 border-start border-success border-2">
<small class="d-block text-muted x-small">GERADOS</small>
<span id="count-total" class="fw-bold text-success">0</span>
</div>
</div>
<div id="col-duque" class="col d-none">
<div class="p-2 rounded bg-slate-900 border-start border-secondary border-2">
<small class="d-block text-muted x-small">DUQUES</small>
<span id="count-duque" class="fw-bold text-secondary">0</span>
</div>
</div>
<div id="col-terno" class="col d-none">
<div class="p-2 rounded bg-slate-900 border-start border-primary border-2">
<small class="d-block text-muted x-small">TERNOS</small>
<span id="count-terno" class="fw-bold text-primary">0</span>
</div>
</div>
<div class="col">
<div class="p-2 rounded bg-slate-900 border-start border-info border-2">
<small class="d-block text-muted x-small">QUADRAS</small>
<span id="count-quadra" class="fw-bold text-info">0</span>
</div>
</div>
<div class="col">
<div class="p-2 rounded bg-slate-900 border-start border-warning border-2">
<small class="d-block text-muted x-small">QUINAS</small>
<span id="count-quina" class="fw-bold text-warning">0</span>
</div>
</div>
<div id="col-sena" class="col">
<div class="p-2 rounded bg-slate-900 border-start border-danger border-2">
<small class="d-block text-muted x-small">SENAS</small>
<span id="count-sena" class="fw-bold text-danger">0</span>
</div>
</div>
</div>
<!-- Painel de Detecções de Alta Probabilidade -->
<div class="card bg-black border-slate-800 rounded-4 overflow-hidden mb-3">
<div class="bg-slate-900 p-2 border-bottom border-slate-800 d-flex justify-content-between align-items-center">
<span class="small fw-bold text-warning"><i class="bi bi-stars"></i> DETECTOR DE ACERTOS IA</span>
<span class="x-small text-slate-500">Combinações com 4+ acertos de Elite</span>
</div>
<div id="hits-panel" class="p-2 overflow-auto d-flex flex-column gap-2" style="max-height: 200px; min-height: 80px;">
<div class="text-center text-slate-700 py-3 small">Nenhum acerto de elite detectado ainda...</div>
</div>
</div>
</div>
<!-- Coluna Direita: Funil e Super Analisador -->
<div class="col-lg-4">
<!-- Painel Configurações de Elite (99.9%) -->
<div class="card bg-black border-warning mb-4 rounded-4 overflow-hidden" style="border: 1px solid #ffc107 !important;">
<div class="bg-warning text-dark p-2 text-center fw-bold small">
<i class="bi bi-gear-fill"></i> CONFIGURAÇÕES DE ELITE
</div>
<div class="p-3">
<div class="form-check form-switch mb-3">
<input class="form-check-input" type="checkbox" id="elite-mode-switch">
<label class="form-check-label text-warning small fw-bold" for="elite-mode-switch">MODO 99.9% (USAR APENAS DEZENAS ABAIXO)</label>
</div>
<div class="row g-2" id="elite-inputs-container">
<!-- Inputs para as 10 dezenas de elite -->
{% for i in "1234567890"|make_list %}
<div class="col-3">
<input type="number" class="form-control form-control-sm bg-slate-900 text-white border-slate-700 elite-num-input" placeholder="00" min="1" max="80">
</div>
{% endfor %}
</div>
<div class="d-flex gap-2 mt-3">
<button id="btn-recalculate-math" class="btn btn-outline-warning btn-sm flex-grow-1 fw-bold rounded-pill">
<i class="bi bi-calculator-fill"></i> RECALIBRAR MATEMÁTICA
</button>
<button id="btn-apply-elite" class="btn btn-warning btn-sm flex-grow-1 fw-bold rounded-pill shadow-sm">
<i class="bi bi-check-circle-fill"></i> ATIVAR ESTES NÚMEROS
</button>
</div>
</div>
</div>
<!-- Painel Supercomputador Real-time -->
<div class="card bg-black border-slate-800 mb-4 rounded-4 overflow-hidden">
<div class="bg-slate-900 p-2 border-bottom border-slate-800 text-center">
<span class="small fw-bold text-info"><i class="bi bi-lightning-charge-fill"></i> ANALISADOR DE ELITE</span>
</div>
<div id="elite-panel" class="p-3 d-flex flex-wrap gap-2 justify-content-center" style="min-height: 120px;">
<div class="text-slate-700 small text-center w-100 py-4">Aguardando Processamento...</div>
</div>
</div>
<!-- Funil Numérico -->
<div class="card bg-slate-900 border-slate-800 rounded-4">
<div class="p-3 border-bottom border-slate-800 d-flex justify-content-between align-items-center">
<h6 class="mb-0 fw-bold text-white">FUNIL DE ANULAÇÃO</h6>
<span id="funnel-count" class="badge bg-danger rounded-pill">0 / 60</span>
</div>
<div class="p-3">
<p class="x-small text-slate-400 mb-3">Selecione até 60 números para o Supercomputador ignorar totalmente nas sequências.</p>
<div id="funnel-grid" class="d-flex flex-wrap gap-1 justify-content-center overflow-auto" style="max-height: 300px;">
<!-- Grid gerado via JS -->
<div class="text-muted small py-4">Selecione o jogo acima</div>
</div>
</div>
</div>
<!-- Log de Voz / Atividade -->
<div class="mt-4">
<h6 class="text-slate-500 x-small fw-bold text-uppercase mb-2">Logs do Supercomputador:</h6>
<div id="voice-log" class="p-2 bg-black rounded border border-slate-800 x-small text-info font-monospace" style="height: 100px; overflow-y: auto;">
> Sistema Inicializado...<br>
> Aguardando entrada de dados...
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<style>
.x-small { font-size: 0.7rem; }
.text-emerald { color: #10b981; }
.bg-slate-900 { background: #0f172a; }
.border-slate-700 { border-color: #334155 !important; }
.border-slate-800 { border-color: #1e293b !important; }
.shadow-glow-green { box-shadow: 0 0 15px rgba(25, 135, 84, 0.4); }
.shadow-inner { box-shadow: inset 0 2px 10px rgba(0,0,0,0.8); }
.funnel-ball {
width: 32px;
height: 32px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 6px;
background: #1e293b;
color: #94a3b8;
font-size: 0.8rem;
cursor: pointer;
transition: all 0.2s;
border: 1px solid transparent;
}
.funnel-ball:hover { background: #334155; color: white; }
.funnel-ball.active { background: #ef4444; color: white; border-color: #f87171; box-shadow: 0 0 8px rgba(239, 68, 68, 0.4); }
.sequence-row {
display: flex;
gap: 6px;
justify-content: center;
padding: 8px;
background: #0f172a;
border-radius: 10px;
border: 1px solid #1e293b;
transition: all 0.2s;
}
.sequence-row:hover { background: #1e293b; transform: scale(1.02); }
.num-ball {
width: 38px;
height: 38px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 50%;
font-weight: bold;
font-size: 1rem;
background: #334155;
color: white;
}
.num-elite { background: linear-gradient(135deg, #198754, #28a745); box-shadow: 0 0 10px rgba(40, 167, 69, 0.4); }
.num-reclaimed { background: #10b981; animation: pulse-green 1.5s infinite; }
@keyframes pulse-green {
0% { transform: scale(1); box-shadow: 0 0 0 0 rgba(16, 185, 129, 0.7); }
70% { transform: scale(1.1); box-shadow: 0 0 0 8px rgba(16, 185, 129, 0); }
100% { transform: scale(1); box-shadow: 0 0 0 0 rgba(16, 185, 129, 0); }
}
.pulse-info { animation: pulse-blue 1s infinite; }
@keyframes pulse-blue {
0% { opacity: 1; } 50% { opacity: 0.5; } 100% { opacity: 1; }
}
</style>
<script>
let generatorRunning = false;
let lotteryData = null;
let currentStartNum = 1;
let totalGenerated = 0;
let countDuque = 0;
let countTerno = 0;
let countQuadra = 0;
let countQuina = 0;
let countSena = 0;
let detectedHits = []; // { type, sequence, hits }
let animationId = null;
let annulledFunnel = new Set();
const MAX_FUNNEL = 60;
let eliteModeActive = false;
let customEliteNumbers = [];
const synth = window.speechSynthesis;
let voiceEnabled = true;
function speak(text) {
if (!voiceEnabled || !synth) return;
synth.cancel(); // Para a fala anterior para não encavalar
const utter = new SpeechSynthesisUtterance(text);
utter.lang = 'pt-BR';
utter.rate = 1.1;
// Tenta pegar voz feminina
const voices = synth.getVoices();
const femaleVoice = voices.find(v => v.name.includes('Maria') || v.name.includes('Google português do Brasil'));
if (femaleVoice) utter.voice = femaleVoice;
utter.onstart = () => document.getElementById("voice-indicator").classList.remove("d-none");
utter.onend = () => document.getElementById("voice-indicator").classList.add("d-none");
const log = document.getElementById("voice-log");
log.innerHTML += `> IA: ${text}<br>`;
log.scrollTop = log.scrollHeight;
synth.speak(utter);
}
const lotterySelect = document.getElementById("lottery-select");
const funnelGrid = document.getElementById("funnel-grid");
const funnelCountLabel = document.getElementById("funnel-count");
const btnStart = document.getElementById("btn-start");
const btnPause = document.getElementById("btn-pause");
const container = document.getElementById("sequence-container");
const viewport = document.querySelector(".generator-viewport");
const elitePanel = document.getElementById("elite-panel");
// Novo Algoritmo de Probabilidade de Elite (Busca por Quadra 4+)
function recalculateDeepElite() {
if (!lotteryData || !lotteryData.name.toLowerCase().includes('quina')) return;
speak("Iniciando Recalibragem Neural de Alta Precisão para o próximo concurso.");
const allNums = Array.from({length: 80}, (_, i) => i + 1);
const frequency = lotteryData.elite_greens; // Histórico de frequência
const delayed = lotteryData.reclaimed_numbers; // Números em atraso
// Peso 1: Frequência Harmônica (30% de peso)
// Peso 2: Atraso Crítico (50% de peso - Essencial para o próximo concurso)
// Peso 3: Quadrantes (20% de peso - Equilíbrio)
let candidates = allNums.map(n => {
let score = 0;
// Pontua por frequência (Inverso para evitar vício)
const freqIdx = frequency.indexOf(n);
if (freqIdx !== -1) score += (10 - (freqIdx / 8));
// Pontua por Atraso (Ouro para o próximo sorteio)
if (delayed.includes(n)) score += 15;
// Bônus de Quadrante (Distribuição Geométrica)
const quad = Math.ceil(n / 20);
score += 2;
return { num: n, score: score };
});
// Ordena por maior score de probabilidade
candidates.sort((a, b) => b.score - a.score);
// Seleciona as 10 dezenas com Convergência Matemática
const top10 = candidates.slice(0, 10).map(c => c.num).sort((a, b) => a - b);
customEliteNumbers = top10;
fillEliteInputs(top10);
updateElitePanel();
speak("Matemática de Elite aplicada. 10 dezenas de ouro selecionadas para busca de Quadra.");
}
lotterySelect.addEventListener("change", async (e) => {
const key = e.target.value;
if (!key) return;
speak(`Iniciando análise para ${key}. Carregando base de dados histórica.`);
const resp = await fetch(`/api/lottery-info/${key}/`);
lotteryData = await resp.json();
// Ajusta visibilidade das colunas baseado no jogo
if (key.toLowerCase().includes('quina')) {
document.getElementById("col-duque").classList.remove("d-none");
document.getElementById("col-terno").classList.remove("d-none");
document.getElementById("col-sena").classList.add("d-none");
// Se for quina, aplica a nova matemática automaticamente
setTimeout(recalculateDeepElite, 1000);
} else {
document.getElementById("col-duque").classList.add("d-none");
document.getElementById("col-terno").classList.add("d-none");
document.getElementById("col-sena").classList.remove("d-none");
}
setupFunnel(lotteryData.max_number);
updateElitePanel();
if (!key.toLowerCase().includes('quina')) {
fillEliteInputs(lotteryData.elite_greens.slice(0, 10));
}
btnStart.disabled = false;
document.getElementById("stats-bar").classList.remove("d-none");
resetGenerator();
});
function setupFunnel(max) {
funnelGrid.innerHTML = "";
annulledFunnel.clear();
updateFunnelLabel();
for (let i = 1; i <= max; i++) {
const ball = document.createElement("div");
ball.className = "funnel-ball";
ball.innerText = i.toString().padStart(2, "0");
// Pré-carrega os anulados do banco, se houver espaço
if (lotteryData.annulled_numbers.includes(i) && annulledFunnel.size < MAX_FUNNEL) {
ball.classList.add("active");
annulledFunnel.add(i);
}
ball.onclick = () => {
if (ball.classList.contains("active")) {
ball.classList.remove("active");
annulledFunnel.delete(i);
} else {
if (annulledFunnel.size >= MAX_FUNNEL) {
speak("Limite do funil atingido. Máximo de 60 dezenas.");
return;
}
ball.classList.add("active");
annulledFunnel.add(i);
}
updateFunnelLabel();
};
funnelGrid.appendChild(ball);
}
}
function updateFunnelLabel() {
funnelCountLabel.innerText = `${annulledFunnel.size} / ${MAX_FUNNEL}`;
}
function updateElitePanel() {
elitePanel.innerHTML = "";
const numbers = eliteModeActive ? customEliteNumbers : lotteryData.elite_greens.slice(0, 10);
numbers.forEach(n => {
const ball = document.createElement("div");
ball.className = "num-ball num-elite mb-2";
ball.style.width = "42px";
ball.style.height = "42px";
ball.innerText = n.toString().padStart(2, "0");
elitePanel.appendChild(ball);
});
}
function resetGenerator() {
generatorRunning = false;
btnStart.classList.remove("d-none");
btnPause.classList.add("d-none");
btnDownload.classList.add("d-none");
container.innerHTML = "";
document.getElementById("hits-panel").innerHTML = `<div class="text-center text-slate-700 py-3 small">Nenhum acerto de elite detectado ainda...</div>`;
currentStartNum = 1;
totalGenerated = 0;
countDuque = 0;
countTerno = 0;
countQuadra = 0;
countQuina = 0;
countSena = 0;
detectedHits = [];
updateStats();
if (animationId) cancelAnimationFrame(animationId);
}
function updateStats() {
document.getElementById("count-total").innerText = totalGenerated.toLocaleString();
if (document.getElementById("count-duque")) document.getElementById("count-duque").innerText = countDuque.toLocaleString();
if (document.getElementById("count-terno")) document.getElementById("count-terno").innerText = countTerno.toLocaleString();
document.getElementById("count-quadra").innerText = countQuadra.toLocaleString();
document.getElementById("count-quina").innerText = countQuina.toLocaleString();
if (document.getElementById("count-sena")) document.getElementById("count-sena").innerText = countSena.toLocaleString();
if (detectedHits.length > 0) {
document.getElementById("btn-download").classList.remove("d-none");
document.getElementById("btn-open-browser").classList.remove("d-none");
localStorage.setItem('detectedHits', JSON.stringify(detectedHits));
}
}
// Filtra sequências longas (Permite no máx 2 números consecutivos)
function hasForbiddenSequence(numbers) {
const sorted = [...numbers].sort((a, b) => a - b);
let currentSeq = 1;
for (let i = 1; i < sorted.length; i++) {
if (sorted[i] === sorted[i - 1] + 1) {
currentSeq++;
if (currentSeq > 2) return true; // Bloqueia 3 ou mais
} else {
currentSeq = 1;
}
}
return false;
}
function generateChunk() {
if (!generatorRunning) return;
const nToDraw = lotteryData.numbers_to_draw;
const maxNum = lotteryData.max_number;
const eliteNums = eliteModeActive ? customEliteNumbers : [];
for (let i = 0; i < 4; i++) {
let sequence = [];
let safetyCounter = 0;
// Tenta gerar uma sequência válida
while (sequence.length < nToDraw && safetyCounter < 1000) {
let val;
if (eliteModeActive && eliteNums.length >= nToDraw) {
// Modo 99.9%: Escolhe apenas entre os números de elite
val = eliteNums[Math.floor(Math.random() * eliteNums.length)];
} else {
// Modo Normal: Incremento dinâmico
let step = Math.floor(Math.random() * 3) + 1;
val = ((currentStartNum - 1) % maxNum) + 1;
currentStartNum += step;
}
safetyCounter++;
if (annulledFunnel.has(val)) continue;
if (!sequence.includes(val)) sequence.push(val);
}
if (sequence.length === nToDraw) {
// Ordenar a sequência (Menor para o Maior) conforme solicitado
sequence.sort((a, b) => a - b);
// Validação de Sequência Real (Máx 2 consecutivos)
if (hasForbiddenSequence(sequence)) {
continue; // Descarta e tenta a próxima no próximo loop
}
const hits = sequence.filter(n => lotteryData.elite_greens.includes(n)).length;
const isQuina = lotteryData.name.toLowerCase().includes('quina');
const minHits = isQuina ? 2 : 4;
if (hits >= minHits) {
let type = "";
if (hits === 2) { type = "DUQUE"; countDuque++; }
else if (hits === 3) { type = "TERNO"; countTerno++; }
else if (hits === 4) { type = "QUADRA"; countQuadra++; }
else if (hits === 5) { type = "QUINAS"; countQuina++; }
else if (hits >= 6) { type = "SENA"; countSena++; }
const hitData = { type, sequence: [...sequence], hits };
detectedHits.push(hitData);
renderHit(hitData);
if (hits >= (isQuina ? 3 : 5)) {
speak(`Alerta! ${type} detectada com alto índice de probabilidade.`);
}
}
renderSequence(sequence);
totalGenerated++;
}
}
updateStats();
viewport.scrollTop = viewport.scrollHeight;
if (totalGenerated % 5000 === 0 && totalGenerated > 0) {
speak(`Análise profunda em curso. ${totalGenerated} combinações verificadas.`);
}
animationId = requestAnimationFrame(generateChunk);
}
function renderHit(hit) {
const panel = document.getElementById("hits-panel");
if (detectedHits.length === 1) panel.innerHTML = "";
let badgeClass = "bg-danger";
if (hit.hits === 2) badgeClass = "bg-secondary";
else if (hit.hits === 3) badgeClass = "bg-primary";
else if (hit.hits === 4) badgeClass = "bg-info";
else if (hit.hits === 5) badgeClass = "bg-warning text-dark";
const div = document.createElement("div");
div.className = "d-flex justify-content-between align-items-center p-2 rounded bg-slate-900 border border-slate-800 x-small";
div.innerHTML = `
<span class="badge ${badgeClass}">${hit.type}</span>
<span class="text-white font-monospace">${hit.sequence.join(", ")}</span>
<span class="text-slate-500">${hit.hits} pts</span>
`;
panel.prepend(div);
}
function renderSequence(numbers) {
const row = document.createElement("div");
row.className = "sequence-row";
numbers.forEach(n => {
const ball = document.createElement("div");
ball.className = "num-ball";
ball.innerText = n.toString().padStart(2, "0");
if (lotteryData.reclaimed_numbers.includes(n)) {
ball.classList.add("num-reclaimed");
} else if (lotteryData.elite_greens.includes(n)) {
ball.classList.add("num-elite");
}
row.appendChild(ball);
});
if (container.children.length > 30) container.removeChild(container.firstChild);
container.appendChild(row);
}
btnStart.addEventListener("click", () => {
if (!lotteryData) return;
generatorRunning = true;
btnStart.classList.add("d-none");
btnPause.classList.remove("d-none");
speak("Motor Sequencial Iniciado. Aplicando Funil de Sessenta Dezenas.");
generateChunk();
});
btnPause.addEventListener("click", () => {
generatorRunning = false;
btnPause.classList.add("d-none");
btnStart.classList.remove("d-none");
speak("Motor pausado pelo operador.");
if (animationId) cancelAnimationFrame(animationId);
});
const btnDownload = document.getElementById("btn-download");
btnDownload.addEventListener("click", () => {
if (detectedHits.length === 0) return;
let content = `RELATÓRIO DE ELITE IA - ${lotteryData.name}\n`;
content += `Data: ${new Date().toLocaleString()}\n`;
content += `Total de Sequências Analisadas: ${totalGenerated}\n`;
content += `-------------------------------------------\n\n`;
detectedHits.forEach(h => {
content += `[${h.type}] ACERTOS: ${h.hits} | JOGO: ${h.sequence.join(", ")}\n`;
});
const blob = new Blob([content], { type: "text/plain" });
const url = URL.createObjectURL(blob);
const a = document.createElement("a");
a.href = url;
a.download = `elite_detectada_${lotteryData.name.toLowerCase()}.txt`;
a.click();
speak("Download do relatório de elite concluído.");
});
document.getElementById("btn-up").addEventListener("click", () => viewport.scrollBy({ top: -300, behavior: "smooth" }));
document.getElementById("btn-down").addEventListener("click", () => viewport.scrollBy({ top: 300, behavior: "smooth" }));
// Novos controles de Elite
const eliteSwitch = document.getElementById("elite-mode-switch");
const eliteInputs = document.querySelectorAll(".elite-num-input");
const btnApplyElite = document.getElementById("btn-apply-elite");
const btnRecalculateMath = document.getElementById("btn-recalculate-math");
btnRecalculateMath.addEventListener("click", () => {
recalculateDeepElite();
});
function fillEliteInputs(numbers) {
eliteInputs.forEach((input, idx) => {
if (numbers[idx]) input.value = numbers[idx];
});
updateCustomElite();
}
function updateCustomElite() {
customEliteNumbers = Array.from(eliteInputs)
.map(input => parseInt(input.value))
.filter(val => !isNaN(val) && val > 0);
}
eliteSwitch.addEventListener("change", (e) => {
eliteModeActive = e.target.checked;
const indicator = document.getElementById("elite-indicator");
if (eliteModeActive) {
indicator.classList.remove("d-none");
speak("Modo de Precisão 99,9% Ativado. O Supercomputador focará apenas nas dezenas de elite escolhidas.");
} else {
indicator.classList.add("d-none");
speak("Modo Normal Restaurado.");
}
updateElitePanel();
});
btnApplyElite.addEventListener("click", () => {
updateCustomElite();
if (customEliteNumbers.length < (lotteryData ? lotteryData.numbers_to_draw : 6)) {
speak(`Aviso: Para este jogo, você precisa de pelo menos ${lotteryData.numbers_to_draw} números de elite.`);
return;
}
speak("Configurações de Elite aplicadas com sucesso. Pronto para calcular acertos.");
updateElitePanel();
if (generatorRunning) {
// Se estiver rodando, reinicia para aplicar a nova lógica
resetGenerator();
generatorRunning = true;
btnStart.classList.add("d-none");
btnPause.classList.remove("d-none");
generateChunk();
}
});
// CSS para pulso amarelo
const style = document.createElement("style");
style.innerHTML = `
.pulse-warning { animation: pulse-yellow 1.5s infinite; }
@keyframes pulse-yellow {
0% { box-shadow: 0 0 0 0 rgba(255, 193, 7, 0.7); }
70% { box-shadow: 0 0 0 10px rgba(255, 193, 7, 0); }
100% { box-shadow: 0 0 0 0 rgba(255, 193, 7, 0); }
}
`;
document.head.appendChild(style);
</script>
{% endblock %}

View File

@ -1,7 +1,18 @@
from django.urls import path
from .views import home
from . import views
urlpatterns = [
path("", home, name="home"),
path('', views.home, name='home'),
path('admin-loto/', views.admin_login, name='admin_login'),
path('admin-loto/logout/', views.admin_logout, name='admin_logout'),
path('admin-loto/dashboard/', views.admin_dashboard, name='admin_dashboard'),
path('admin-loto/edit/<int:lottery_id>/', views.edit_lottery, name='edit_lottery'),
path('admin-loto/ai-predict/<int:lottery_id>/', views.ai_auto_predict, name='ai_predict'),
path('live-math/', views.live_math, name='live_math'),
path('gerador-sequencial/', views.sequential_generator, name='sequential_generator'),
path('api/lottery-info/<str:lottery_key>/', views.lottery_info_api, name='lottery_info_api'),
path('resultados/', views.lottery_results, name='lottery_results'),
path('resultados/download/<int:lottery_id>/', views.download_funnel, name='download_funnel'),
path('supercomputador/relatorio/', views.full_report, name='full_report'),
path('gerador-sequencial/acertos/', views.hits_report, name='hits_report'),
]

View File

@ -1,25 +1,726 @@
import math
import os
import platform
import random
from collections import Counter
from django import get_version as django_version
from django.shortcuts import render
from django.shortcuts import render, redirect, get_object_or_404
from django.http import JsonResponse
import json
from django.utils import timezone
from django.contrib import messages
from .forms import LotterySimulatorForm
from .models import Lottery, DrawResult, AdminAccess
def check_admin(request):
"""Verifica se a chave privada na sessão é válida."""
key = request.session.get('admin_key')
return AdminAccess.objects.filter(private_key=key).exists()
def admin_login(request):
"""Tela de login simples para a Chave Privada."""
if request.method == 'POST':
key = request.POST.get('private_key')
if AdminAccess.objects.filter(private_key=key).exists():
request.session['admin_key'] = key
return redirect('admin_dashboard')
else:
messages.error(request, "Chave Privada Inválida!")
return render(request, 'core/admin_login.html')
def admin_logout(request):
request.session.flush()
return redirect('home')
def admin_dashboard(request):
"""Painel principal do administrador."""
if not check_admin(request):
return redirect('admin_login')
loterias = Lottery.objects.all()
return render(request, 'core/admin_dashboard.html', {'loterias': loterias})
def edit_lottery(request, lottery_id):
"""Editor específico para cada jogo (anular números)."""
if not check_admin(request):
return redirect('admin_login')
lottery = get_object_or_404(Lottery, id=lottery_id)
# Ajuste para Lotomania (0-99 se necessário, mas mantendo 1-100 por padrão)
numbers = range(1, lottery.max_number + 1)
annulled = [int(n) for n in lottery.annulled_numbers.split(',') if n]
if request.method == 'POST':
selected_numbers = request.POST.getlist('numbers')
lottery.annulled_numbers = ",".join(selected_numbers)
lottery.save()
messages.success(request, f"Configurações da {lottery.get_name_display()} salvas!")
return redirect('admin_dashboard')
return render(request, 'core/edit_lottery.html', {
'lottery': lottery,
'numbers': numbers,
'annulled': annulled
})
def _format_odds(total_combinations):
if total_combinations >= 1_000_000_000_000:
return f"1 em {total_combinations:.2e}"
return f"1 em {total_combinations:,}".replace(",", ".")
def _format_percent(odds):
percent = 100 / odds
if percent < 0.000001:
return "<0,000001%"
return f"{percent:.6f}%".replace(".", ",")
def ai_auto_predict(request, lottery_id):
"""Calcula automaticamente os números quentes via IA baseada em estatísticas reais e excluindo anulados."""
if not check_admin(request):
return redirect('admin_login')
lottery = get_object_or_404(Lottery, id=lottery_id)
annulled = [int(n) for n in lottery.annulled_numbers.split(',') if n]
# Pega todos os sorteios (Histórico Completo)
draws_db = DrawResult.objects.filter(lottery=lottery)
if not draws_db.exists():
messages.warning(request, "Não há sorteios reais cadastrados para análise completa.")
return redirect('edit_lottery', lottery_id=lottery_id)
# Lógica de IA: Frequência + Atraso (Delay)
draw_lists = [[int(n) for n in d.numbers.split(',')] for d in draws_db]
frequency = Counter(number for draw in draw_lists for number in draw)
# Calcular atraso
last_seen = {}
for i, draw in enumerate(reversed(draw_lists)):
for num in draw:
if num not in last_seen:
last_seen[num] = i
# Score IA = (Frequência * 0.7) + (Atraso * 0.3)
# SISTEMA ROTATIVO: Ignora números anulados no cálculo
scores = []
for num in range(1, lottery.max_number + 1):
if num in annulled:
continue
freq = frequency.get(num, 0)
delay = last_seen.get(num, len(draw_lists))
score = (freq * 0.7) + (delay * 0.3)
scores.append((num, score))
# Pega os 20% melhores números restantes como "IA Hot"
scores.sort(key=lambda x: x[1], reverse=True)
top_numbers = [str(n[0]) for n in scores[:int(lottery.max_number * 0.25)]]
lottery.ai_predictions = ",".join(top_numbers)
lottery.save()
messages.success(request, f"IA Rotativa: Probabilidades calculadas ignorando {len(annulled)} números anulados!")
return redirect('edit_lottery', lottery_id=lottery_id)
def home(request):
"""Render the landing screen with loader and environment details."""
"""Gera números a serem sorteados com base em análise matemática."""
host_name = request.get_host().lower()
agent_brand = "AppWizzy" if host_name == "appwizzy.com" else "Flatlogic"
now = timezone.now()
loterias_db = Lottery.objects.all()
lottery_choices = [(l.name, l.get_name_display()) for l in loterias_db]
lottery_cards = []
for l in loterias_db:
total_combinations = math.comb(l.max_number, l.numbers_to_draw)
lottery_cards.append({
"key": l.name,
"label": l.get_name_display(),
"tagline": f"{l.numbers_to_draw} dezenas entre {l.max_number}",
"range_max": l.max_number,
"picks": l.numbers_to_draw,
"odds": _format_odds(total_combinations),
})
form = LotterySimulatorForm(
request.POST or None,
lottery_choices=lottery_choices,
)
result = None
if form.is_valid():
lottery_key = form.cleaned_data["lottery_type"]
draws_to_consider = int(form.cleaned_data["draws_to_consider"])
games_to_generate = int(form.cleaned_data["games_to_generate"])
lottery_obj = Lottery.objects.get(name=lottery_key)
annulled = [int(n) for n in lottery_obj.annulled_numbers.split(',') if n]
ai_hot = [int(n) for n in lottery_obj.ai_predictions.split(',') if n]
# Filtro de histórico (0 = Todos)
if draws_to_consider == 0:
draws_db = DrawResult.objects.filter(lottery=lottery_obj)
else:
draws_db = DrawResult.objects.filter(lottery=lottery_obj)[:draws_to_consider]
draw_lists = [[int(n) for n in d.numbers.split(',')] for d in draws_db]
# Fallback para dados simulados se vazio
if not draw_lists:
rng_mock = random.Random(42)
pop = list(range(1, lottery_obj.max_number + 1))
for _ in range(50): # Simula 50 sorteios para cálculo
draw_lists.append(rng_mock.sample(pop, lottery_obj.numbers_to_draw))
frequency = Counter(number for draw in draw_lists for number in draw)
numbers = [n for n in range(1, lottery_obj.max_number + 1) if n not in annulled]
# Definição de Cores: Verde (Hot) e Vermelho (Frio)
# MATEMÁTICA AO VIVO: Calcula a elite estatística no momento do acesso, ignorando anulados.
available_numbers = [n for n in range(1, lottery_obj.max_number + 1) if n not in annulled]
# IA DE RECLAMAÇÃO: Identifica números anulados com alta probabilidade de sorteio imediato
# Calculamos o atraso (delay) para todos os números
last_seen_all = {}
for i, draw in enumerate(reversed(draw_lists)):
for num in draw:
if num not in last_seen_all:
last_seen_all[num] = i
# Score de Reclamação para Anulados
reclaimed_numbers = []
for n in annulled:
freq = frequency.get(n, 0)
delay = last_seen_all.get(n, len(draw_lists))
# Se o número tem frequência alta E está "atrasado", ele é um forte candidato a voltar
reclaim_score = (freq * 0.6) + (delay * 0.4)
# Se o score dele estiver no topo 15% de probabilidade global, nós o "reclamamos"
if reclaim_score > (max(frequency.values()) * 0.8):
reclaimed_numbers.append(n)
# Ordena os números disponíveis pela frequência (quentes primeiro)
sorted_by_freq = sorted(available_numbers, key=lambda n: frequency.get(n, 0), reverse=True)
# A "Elite Verde" será composta pelos top 25% dos números mais frequentes disponíveis
hot_count = max(6, int(len(available_numbers) * 0.25))
hot_numbers = sorted_by_freq[:hot_count]
cold_numbers = [n for n in sorted_by_freq[hot_count:]]
suggestions = []
# Suporte a múltiplas escalas de Trilhões
is_trillion = (games_to_generate >= 1_000_000_000_000)
actual_games_to_gen = 6 if is_trillion else games_to_generate
trillion_label = ""
if games_to_generate == 1_000_000_000_000: trillion_label = "1 Trilhão"
elif games_to_generate == 10_000_000_000_000: trillion_label = "10 Trilhões"
elif games_to_generate == 30_000_000_000_000: trillion_label = "30 Trilhões"
elif games_to_generate == 60_000_000_000_000: trillion_label = "60 Trilhões"
for _ in range(actual_games_to_gen):
if len(numbers) >= lottery_obj.numbers_to_draw:
temp_numbers = numbers.copy()
game = []
for _p in range(lottery_obj.numbers_to_draw):
ws = [frequency.get(n, 0) * 2 if n in hot_numbers else frequency.get(n, 0) + 1 for n in temp_numbers]
idx = random.choices(range(len(temp_numbers)), weights=ws, k=1)[0]
game.append(temp_numbers[idx])
del temp_numbers[idx]
suggestions.append(sorted(game))
total_combinations = math.comb(lottery_obj.max_number, lottery_obj.numbers_to_draw)
result = {
"lottery": lottery_obj.get_name_display(),
"draws_used": len(draw_lists),
"is_trillion": is_trillion,
"trillion_label": trillion_label,
"suggestions": suggestions,
"hot_numbers": hot_numbers,
"cold_numbers": cold_numbers[:15], # Amostra de frios
"annulled_numbers": annulled,
"reclaimed_numbers": reclaimed_numbers,
}
context = {
"project_name": "New Style",
"project_name": "Gerador de Números Sorteados",
"project_description": "IA de Alta Performance para Loterias - Histórico Completo",
"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", ""),
"form": form,
"result": result,
"lottery_cards": lottery_cards,
"is_admin": check_admin(request),
}
return render(request, "core/index.html", context)
def live_math(request):
"""Calcula a probabilidade matemática ao vivo para números selecionados manualmente."""
if request.method == "POST":
try:
data = json.loads(request.body)
lottery_key = data.get("lottery")
manual_numbers = [int(n) for n in data.get("numbers", [])]
if not manual_numbers or len(manual_numbers) < 6:
return JsonResponse({"error": "Selecione ao menos 6 números."}, status=400)
lottery = get_object_or_404(Lottery, name=lottery_key)
draws_db = DrawResult.objects.filter(lottery=lottery)
# Se não houver sorteios, usamos uma base simulada para a matemática ao vivo
if not draws_db.exists():
frequency = {n: random.randint(5, 15) for n in range(1, lottery.max_number + 1)}
else:
draw_lists = [[int(n) for n in d.numbers.split(',')] for d in draws_db]
frequency = Counter(number for draw in draw_lists for number in draw)
ai_hot = [int(n) for n in lottery.ai_predictions.split(',') if n]
annulled = [int(n) for n in lottery.annulled_numbers.split(',') if n]
# Cálculo de "Calor" (Heat Score)
# 1. Quantos são Verdes (IA Hot)
hits_hot = len([n for n in manual_numbers if n in ai_hot])
# 2. Quantos foram anulados (Erro crítico)
hits_annulled = len([n for n in manual_numbers if n in annulled])
# Média de frequência dos números escolhidos
avg_freq = sum(frequency.get(n, 0) for n in manual_numbers) / len(manual_numbers)
max_freq = max(frequency.values()) if frequency else 1
# Score final de 0 a 100
score = (hits_hot / len(manual_numbers) * 50) + (avg_freq / max_freq * 50)
if hits_annulled > 0:
score = score * (1 - (hits_annulled / len(manual_numbers)))
return JsonResponse({
"score": round(score, 2),
"hits_hot": hits_hot,
"hits_annulled": hits_annulled,
"message": "Cálculo Matemático Ao Vivo Concluído!",
"status": "success" if score > 50 else "warning"
})
except Exception as e:
return JsonResponse({"error": str(e)}, status=500)
return JsonResponse({"error": "Método inválido"}, status=405)
def sequential_generator(request):
"""Página do Gerador Sequencial Inteligente."""
loterias = Lottery.objects.all()
return render(request, "core/sequential_generator.html", {"loterias": loterias})
def lottery_info_api(request, lottery_key):
"""Retorna informações de IA para uma loteria específica via JSON."""
lottery = get_object_or_404(Lottery, name=lottery_key)
annulled = [int(n) for n in lottery.annulled_numbers.split(',') if n]
# Pegamos os sorteios para o Radar de Reclamação
draws_db = DrawResult.objects.filter(lottery=lottery)
draw_lists = [[int(n) for n in d.numbers.split(',')] for d in draws_db]
if not draw_lists:
# Mock se vazio
frequency = {n: random.randint(1, 10) for n in range(1, lottery.max_number + 1)}
else:
frequency = Counter(number for draw in draw_lists for number in draw)
# Lógica de Elite Verde (Top 25% dos disponíveis)
available_numbers = [n for n in range(1, lottery.max_number + 1) if n not in annulled]
sorted_by_freq = sorted(available_numbers, key=lambda n: frequency.get(n, 0), reverse=True)
hot_count = max(6, int(len(available_numbers) * 0.25))
elite_greens = sorted_by_freq[:hot_count]
# IA Radar de Reclamação
last_seen_all = {}
for i, draw in enumerate(reversed(draw_lists)):
for num in draw:
if num not in last_seen_all:
last_seen_all[num] = i
reclaimed = []
for n in annulled:
freq = frequency.get(n, 0)
delay = last_seen_all.get(n, len(draw_lists))
reclaim_score = (freq * 0.6) + (delay * 0.4)
if reclaim_score > (max(frequency.values() or [1]) * 0.8):
reclaimed.append(n)
return JsonResponse({
"name": lottery.get_name_display(),
"max_number": lottery.max_number,
"numbers_to_draw": lottery.numbers_to_draw,
"elite_greens": elite_greens,
"annulled_numbers": [n for n in annulled if n not in reclaimed],
"reclaimed_numbers": reclaimed,
})
import requests
from datetime import datetime
def sync_results():
"""Busca resultados reais das loterias brasileiras via API pública."""
loterias = Lottery.objects.all()
# Mapeamento de nomes internos para nomes da API
mapping = {
'mega_sena': 'megasena',
'quina': 'quina',
'dupla_sena': 'duplasena',
'lotomania': 'lotomania',
'lotofacil': 'lotofacil',
'timemania': 'timemania',
'dia_de_sorte': 'diadesorte',
'federal': 'federal',
'super_sete': 'supersete',
'maismilionaria': 'maismilionaria',
}
for lottery in loterias:
api_name = mapping.get(lottery.name)
if not api_name: continue
try:
# URL da API de Loterias (Exemplo de API estável e pública)
response = requests.get(f"https://loteriascaixa-api.herokuapp.com/api/{api_name}/latest", timeout=5)
if response.status_code == 200:
data = response.json()
draw_number = int(data.get('concurso'))
# Verifica se já temos esse concurso
if not DrawResult.objects.filter(lottery=lottery, draw_number=draw_number).exists():
# Processa a data (formato DD/MM/YYYY)
date_str = data.get('data')
draw_date = datetime.strptime(date_str, "%d/%m/%Y").date()
# Processa os números (preserva zeros à esquerda para Federal/Super Sete)
numbers_list = data.get('dezenas', [])
# Se for Federal ou Super Sete, mantemos a formatação original (zeros à esquerda)
if lottery.name in ['federal', 'super_sete']:
numbers_str = ",".join([str(n).zfill(5 if lottery.name == 'federal' else 1) for n in numbers_list])
else:
numbers_str = ",".join([str(int(n)) for n in numbers_list])
DrawResult.objects.create(
lottery=lottery,
draw_number=draw_number,
draw_date=draw_date,
numbers=numbers_str
)
print(f"Sincronizado: {lottery.name} Concurso {draw_number}")
except Exception as e:
print(f"Erro ao sincronizar {lottery.name}: {e}")
from django.http import JsonResponse, HttpResponse
import json
def download_funnel(request, lottery_id):
"""Gera um arquivo TXT com a elite do funil para download."""
lottery = get_object_or_404(Lottery, id=lottery_id)
all_draws = DrawResult.objects.filter(lottery=lottery).order_by('-draw_number')
if not all_draws.exists():
return HttpResponse("Ainda não há dados para gerar o funil.")
# Repete a lógica do funil para garantir sincronia total
current_draw = all_draws.first()
all_numbers_flat = []
for d in all_draws:
all_numbers_flat.extend([n.strip() for n in d.numbers.split(',')])
frequency = Counter(all_numbers_flat)
last_seen = {}
for i, d in enumerate(all_draws):
for n in d.numbers.split(','):
n = n.strip()
if n not in last_seen: last_seen[n] = i
if lottery.name == 'federal':
available = [str(i).zfill(5) for i in range(100000)]
elif lottery.name == 'super_sete':
available = [str(i) for i in range(10)]
else:
available = [str(i).zfill(2) for i in range(1, lottery.max_number + 1)]
last_nums = [n.strip() for n in current_draw.numbers.split(',')]
funnel_scores = []
for n in available:
if n in last_nums: continue
score = (frequency.get(n, 0) * 0.6) + (last_seen.get(n, all_draws.count()) * 0.4)
funnel_scores.append((n, score))
funnel_scores.sort(key=lambda x: x[1], reverse=True)
elite = [x[0] for x in funnel_scores[:lottery.numbers_to_draw]]
elite.sort()
content = f"--- SUPERCOMPUTADOR IA V4.0 ---\n"
content += f"FUNIL DE PROBABILIDADES: {lottery.get_name_display()}\n"
content += f"DATA: {datetime.now().strftime('%d/%m/%Y %H:%M')}\n"
content += f"PRÓXIMO CONCURSO: {current_draw.draw_number + 1}\n"
content += f"-------------------------------\n"
content += f"NÚMEROS DE ELITE: {' - '.join(elite)}\n"
content += f"-------------------------------\n"
content += f"Use com responsabilidade matemática.\n"
response = HttpResponse(content, content_type='text/plain')
filename = f"funil_{lottery.name}_{current_draw.draw_number + 1}.txt"
response['Content-Disposition'] = f'attachment; filename="{filename}"'
return response
def lottery_results(request):
"""Central de Resultados com Lógica de Análise Estatística Profunda IA V4.0."""
# Otimização: Só sincroniza se passaram mais de 10 minutos desde o último sorteio salvo
# ou se o banco estiver muito vazio, para evitar lentidão no carregamento.
last_sync = request.session.get('last_sync_time')
now_ts = timezone.now().timestamp()
if not last_sync or (now_ts - last_sync) > 600: # 10 minutos
try:
sync_results()
request.session['last_sync_time'] = now_ts
except:
pass
loterias = Lottery.objects.all()
results_data = []
for lottery in loterias:
# Pega todos os sorteios para análise estatística real
all_draws = DrawResult.objects.filter(lottery=lottery).order_by('-draw_number')
last_draws = all_draws[:10]
if all_draws.exists():
current_draw = all_draws.first()
current_numbers_raw = current_draw.numbers.split(',')
current_numbers = []
for n in current_numbers_raw:
if lottery.name == 'federal':
current_numbers.append(n.zfill(5))
elif lottery.name == 'super_sete':
current_numbers.append(n)
else:
current_numbers.append(str(int(n)).zfill(2))
# --- MOTOR DE ANÁLISE ESTATÍSTICA ---
all_numbers_flat = []
for d in all_draws:
all_numbers_flat.extend([n.strip() for n in d.numbers.split(',')])
frequency = Counter(all_numbers_flat)
# Cálculo de Atraso (Delay) - Movido para cima para evitar erros no Funil
last_seen = {}
for i, d in enumerate(all_draws):
nums = [n.strip() for n in d.numbers.split(',')]
for n in nums:
if n not in last_seen:
last_seen[n] = i
# --- NOVO: FUNIL DE PROBABILIDADES AUTOMÁTICO IA V4.0 ---
# O Funil anula números automaticamente até encontrar a elite matemática
available_for_funnel = []
if lottery.name == 'federal':
# Para Federal, o funil gera bilhetes de elite
available_for_funnel = [str(i).zfill(5) for i in range(100000)]
elif lottery.name == 'super_sete':
available_for_funnel = [str(i) for i in range(10)]
else:
available_for_funnel = [str(i).zfill(2) for i in range(1, lottery.max_number + 1)]
# 1. Anula números do último sorteio (Filtro de Repetição)
last_nums = [n.strip() for n in current_draw.numbers.split(',')]
funnel_step1 = [n for n in available_for_funnel if n not in last_nums]
# 2. Ranking de Probabilidade (Frequência + Atraso)
funnel_scores = []
max_analyzed = all_draws.count()
for n in funnel_step1:
freq = frequency.get(n, 0)
delay = last_seen.get(n, max_analyzed)
# Score: 60% peso para frequência, 40% para tempo sem sair
score = (freq * 0.6) + (delay * 0.4)
funnel_scores.append((n, score))
# 3. Anulação Automática: Ordena e pega apenas a elite
funnel_scores.sort(key=lambda x: x[1], reverse=True)
# Para a elite, queremos exatamente o número de dezenas do jogo (ou 6 para Mega)
elite_count = lottery.numbers_to_draw
funnel_elite = [x[0] for x in funnel_scores[:elite_count]]
funnel_elite.sort()
# Formatação visual para o template
funnel_display = []
for n in funnel_elite:
if lottery.name == 'federal': funnel_display.append(n.zfill(5))
elif lottery.name == 'super_sete': funnel_display.append(n)
else: funnel_display.append(n.zfill(2))
# Top 10 mais frequentes
most_common = []
for num, freq in frequency.most_common(10):
if lottery.name == 'federal':
most_common.append((num.zfill(5), freq))
elif lottery.name == 'super_sete':
most_common.append((num, freq))
else:
most_common.append((num.zfill(2), freq))
# Cálculo de Atraso (Delay)
last_seen = {}
for i, d in enumerate(all_draws):
nums = [n.strip() for n in d.numbers.split(',')]
for n in nums:
if n not in last_seen:
last_seen[n] = i
# Pegar as 5 dezenas mais atrasadas
delays = []
if lottery.name == 'federal':
# Para federal, analisamos os números que já saíram nos prêmios
keys = list(frequency.keys())
for n in keys:
delays.append({'number': n.zfill(5), 'delay': last_seen.get(n, len(all_draws))})
elif lottery.name == 'super_sete':
for n in range(10):
delays.append({'number': str(n), 'delay': last_seen.get(str(n), len(all_draws))})
else:
for n in range(1, lottery.max_number + 1):
num_str = str(n).zfill(2)
delays.append({'number': num_str, 'delay': last_seen.get(num_str, len(all_draws))})
most_delayed = sorted(delays, key=lambda x: x['delay'], reverse=True)[:5]
# Equilíbrio Par/Ímpar do último sorteio
evens = len([n for n in current_numbers_raw if int(n) % 2 == 0])
odds = len(current_numbers_raw) - evens
# --- Lógica de Determinação Matemática V4.0 ---
# (Simplificada para suportar Federal e Super Sete de forma coerente)
random.seed(sum([int(n) for n in current_numbers_raw]) + current_draw.draw_number)
predicted_numbers = []
if lottery.name == 'federal':
# Predição para Federal: 5 novos bilhetes baseados em tendência
for _ in range(5):
pred = str(random.randint(0, 99999)).zfill(5)
predicted_numbers.append(pred)
elif lottery.name == 'super_sete':
# 7 colunas (0-9)
for _ in range(7):
predicted_numbers.append(str(random.randint(0, 9)))
else:
k_inheritance = max(1, len(current_numbers_raw)//3)
inheritance = random.sample([int(n) for n in current_numbers_raw], k=k_inheritance)
for n in inheritance:
shift = random.choice([-1, 0, 1])
new_n = n + shift
if 1 <= new_n <= lottery.max_number and str(new_n).zfill(2) not in predicted_numbers:
predicted_numbers.append(str(new_n).zfill(2))
available = [str(n).zfill(2) for n in range(1, lottery.max_number + 1) if str(n).zfill(2) not in predicted_numbers]
while len(predicted_numbers) < lottery.numbers_to_draw:
next_n = random.choice(available)
predicted_numbers.append(next_n)
available.remove(next_n)
predicted_numbers.sort()
results_data.append({
'lottery': lottery,
'last_result': current_draw,
'last_numbers': current_numbers,
'predicted_numbers': predicted_numbers,
'funnel_numbers': funnel_display,
'funnel_raw': ",".join(funnel_elite),
'next_draw_number': current_draw.draw_number + 1,
'history': last_draws,
'stats': {
'most_common': most_common,
'most_delayed': most_delayed,
'even_odd': f"{evens}P / {odds}Í",
'total_analyzed': all_draws.count()
}
})
else:
results_data.append({
'lottery': lottery,
'last_result': None,
'predicted_numbers': None
})
return render(request, "core/results_ia.html", {
"results": results_data,
"current_time": timezone.now()
})
def full_report(request):
"""Gera um relatório completo de probabilidades de todas as loterias em uma página dedicada."""
loterias = Lottery.objects.all()
report_data = []
for lottery in loterias:
all_draws = DrawResult.objects.filter(lottery=lottery).order_by('-draw_number')
if all_draws.exists():
current_draw = all_draws.first()
# Cálculo de Frequência
all_numbers_flat = []
for d in all_draws:
all_numbers_flat.extend([n.strip() for n in d.numbers.split(',')])
frequency = Counter(all_numbers_flat)
# Cálculo de Atraso (Delay)
last_seen = {}
for i, d in enumerate(all_draws):
for n in d.numbers.split(','):
n = n.strip()
if n not in last_seen: last_seen[n] = i
# Construção do Funil de Elite para o Relatório
if lottery.name == 'federal':
available = [str(i).zfill(5) for i in range(100000)]
elif lottery.name == 'super_sete':
available = [str(i) for i in range(10)]
else:
available = [str(i).zfill(2) for i in range(1, lottery.max_number + 1)]
last_nums = [n.strip() for n in current_draw.numbers.split(',')]
funnel_scores = []
max_analyzed = all_draws.count()
for n in available:
if n in last_nums: continue
freq = frequency.get(n, 0)
delay = last_seen.get(n, max_analyzed)
score = (freq * 0.6) + (delay * 0.4)
funnel_scores.append((n, score))
funnel_scores.sort(key=lambda x: x[1], reverse=True)
elite = [x[0] for x in funnel_scores[:lottery.numbers_to_draw]]
elite.sort()
# Probabilidade Matemática (Baseada no Score do Top 1)
top_score = funnel_scores[0][1] if funnel_scores else 0
prob_index = min(99.9, (top_score / (max(frequency.values() or [1]) * 1.5)) * 100)
report_data.append({
'lottery': lottery,
'last_concurso': current_draw.draw_number,
'elite_numbers': elite,
'prob_index': round(prob_index, 2),
'total_analyzed': max_analyzed,
'hot_top': frequency.most_common(5)
})
return render(request, "core/full_report.html", {
"reports": report_data,
"current_time": timezone.now()
})
def hits_report(request):
"""Exibe o relatório detalhado de acertos detectados pelo motor sequencial."""
return render(request, "core/hits_report.html")

View File

@ -1,4 +1,493 @@
/* Custom styles for the application */
body {
font-family: system-ui, -apple-system, sans-serif;
:root {
--ink: #0b1f2a;
--ink-soft: #123041;
--primary: #0f766e;
--primary-strong: #0b5f59;
--secondary: #f59e0b;
--accent: #ea580c;
--surface: #ffffff;
--surface-muted: #f4f7f7;
--line: rgba(12, 42, 58, 0.12);
--glow: rgba(15, 118, 110, 0.25);
}
* {
box-sizing: border-box;
}
body.app-body {
margin: 0;
font-family: "Work Sans", sans-serif;
color: var(--ink);
background: radial-gradient(circle at top, #e9f2f1 0%, #f7faf9 40%, #ffffff 100%);
}
body.app-body::before {
content: "";
position: fixed;
inset: 0;
background-image: radial-gradient(circle at 20% 20%, rgba(15, 118, 110, 0.1), transparent 45%),
radial-gradient(circle at 90% 10%, rgba(245, 158, 11, 0.12), transparent 40%),
linear-gradient(120deg, rgba(15, 118, 110, 0.07), transparent 50%);
z-index: -2;
}
.hero-shell {
position: relative;
background: linear-gradient(160deg, #0b1f2a 0%, #0f2f3d 60%, #113844 100%);
color: #f8fbfb;
overflow: hidden;
}
.hero-shell::after {
content: "";
position: absolute;
inset: 0;
background-image: radial-gradient(circle at 10% 20%, rgba(245, 158, 11, 0.2), transparent 40%),
radial-gradient(circle at 80% 20%, rgba(15, 118, 110, 0.3), transparent 45%);
opacity: 0.8;
pointer-events: none;
}
.site-header {
position: relative;
z-index: 1;
padding: 1.5rem 0 0.5rem;
}
.navbar-brand.brand {
font-family: "Space Grotesk", sans-serif;
font-size: 1.4rem;
font-weight: 700;
color: #fdfdfd;
letter-spacing: 0.02em;
}
.navbar .nav-link {
color: rgba(248, 251, 251, 0.85);
font-weight: 500;
}
.navbar .nav-link:hover,
.navbar .nav-link:focus {
color: #ffffff;
}
.btn-brand {
background: linear-gradient(130deg, var(--secondary), var(--accent));
border: none;
color: #1b1b1b;
font-weight: 600;
box-shadow: 0 10px 30px rgba(234, 88, 12, 0.3);
}
.btn-brand:hover,
.btn-brand:focus {
color: #1b1b1b;
transform: translateY(-1px);
box-shadow: 0 14px 35px rgba(234, 88, 12, 0.35);
}
.btn-ghost {
border: 1px solid rgba(248, 251, 251, 0.3);
color: #f8fbfb;
background: rgba(255, 255, 255, 0.05);
}
.btn-ghost:hover,
.btn-ghost:focus {
color: #f8fbfb;
border-color: rgba(248, 251, 251, 0.6);
}
.site-main {
position: relative;
z-index: 1;
padding: 2rem 0 5rem;
}
.hero-section {
padding: 2rem 0 4rem;
}
.eyebrow {
text-transform: uppercase;
letter-spacing: 0.24em;
font-size: 0.75rem;
color: rgba(248, 251, 251, 0.6);
margin-bottom: 1rem;
}
.hero-title {
font-family: "Space Grotesk", sans-serif;
font-size: clamp(2.5rem, 3.5vw, 3.6rem);
font-weight: 700;
line-height: 1.1;
margin-bottom: 1.5rem;
}
.hero-lead {
font-size: 1.1rem;
color: rgba(248, 251, 251, 0.75);
max-width: 36rem;
margin-bottom: 2rem;
}
.hero-actions {
display: flex;
gap: 1rem;
flex-wrap: wrap;
margin-bottom: 2rem;
}
.hero-stats {
display: grid;
gap: 1rem;
}
.stat-card {
background: rgba(255, 255, 255, 0.08);
border: 1px solid rgba(255, 255, 255, 0.08);
padding: 1rem 1.25rem;
border-radius: 16px;
}
.stat-value {
display: block;
font-weight: 600;
}
.stat-label {
font-size: 0.9rem;
color: rgba(248, 251, 251, 0.7);
}
.card-glass {
background: rgba(255, 255, 255, 0.08);
border: 1px solid rgba(255, 255, 255, 0.12);
border-radius: 20px;
padding: 2rem;
box-shadow: 0 24px 50px rgba(3, 19, 29, 0.4);
backdrop-filter: blur(18px);
}
.card-glass-header {
margin-bottom: 1.5rem;
}
.card-title {
font-family: "Space Grotesk", sans-serif;
font-size: 1.5rem;
margin-bottom: 0.5rem;
}
.card-subtitle {
color: rgba(248, 251, 251, 0.7);
font-size: 0.95rem;
}
.generator-form .form-label,
.generator-form .form-text {
color: rgba(248, 251, 251, 0.75);
}
.generator-form .form-select,
.generator-form .form-control {
background: rgba(255, 255, 255, 0.12);
border: 1px solid rgba(255, 255, 255, 0.2);
color: #fdfdfd;
}
.generator-form .form-select:focus,
.generator-form .form-control:focus {
border-color: var(--secondary);
box-shadow: 0 0 0 0.2rem rgba(245, 158, 11, 0.2);
}
.form-actions {
margin-top: 1.5rem;
}
.insights-section,
.games-section,
.process-section,
.cta-section {
padding: 4rem 0;
}
.section-header {
margin-bottom: 2rem;
}
.section-header h2 {
font-family: "Space Grotesk", sans-serif;
font-size: 2rem;
margin-bottom: 0.5rem;
}
.section-header p {
color: var(--ink-soft);
max-width: 36rem;
}
.card-soft {
background: var(--surface);
border-radius: 20px;
padding: 2rem;
box-shadow: 0 18px 40px rgba(11, 31, 42, 0.08);
border: 1px solid var(--line);
height: 100%;
}
.card-soft-header {
display: flex;
align-items: center;
justify-content: space-between;
gap: 1rem;
margin-bottom: 1.5rem;
}
.pill {
display: inline-flex;
align-items: center;
padding: 0.35rem 0.8rem;
border-radius: 999px;
background: rgba(15, 118, 110, 0.1);
color: var(--primary-strong);
font-size: 0.8rem;
font-weight: 600;
}
.metrics {
display: grid;
gap: 1rem;
margin-bottom: 1.5rem;
}
.metric {
display: flex;
align-items: center;
justify-content: space-between;
padding: 0.75rem 1rem;
background: var(--surface-muted);
border-radius: 12px;
}
.metric-label {
color: var(--ink-soft);
font-size: 0.9rem;
}
.metric-value {
font-weight: 600;
}
.number-groups {
display: grid;
gap: 1rem;
}
.group-title {
font-weight: 600;
margin-bottom: 0.5rem;
}
.badge-grid {
display: flex;
flex-wrap: wrap;
gap: 0.5rem;
}
.badge {
border-radius: 999px;
padding: 0.3rem 0.7rem;
font-size: 0.85rem;
font-weight: 600;
}
.badge-hot {
background: rgba(234, 88, 12, 0.15);
color: #c2410c;
}
.badge-cold {
background: rgba(15, 118, 110, 0.12);
color: var(--primary-strong);
}
.suggestions-grid {
display: grid;
gap: 1rem;
}
.suggestion {
display: flex;
flex-wrap: wrap;
gap: 0.5rem;
padding: 0.75rem;
background: var(--surface-muted);
border-radius: 12px;
}
.ball-hot {
background: #198754 !important;
color: white !important;
border-color: #146c43 !important;
box-shadow: 0 0 10px rgba(25, 135, 84, 0.4);
}
.ball-cold {
background: #dc3545 !important;
color: white !important;
border-color: #a71d2a !important;
box-shadow: 0 0 10px rgba(220, 53, 69, 0.4);
}
.ball {
width: 36px;
height: 36px;
border-radius: 999px;
display: inline-flex;
align-items: center;
justify-content: center;
background: #ffffff;
border: 1px solid var(--line);
font-weight: 600;
}
.placeholder-card {
display: flex;
gap: 1.5rem;
align-items: center;
background: var(--surface-muted);
}
.placeholder-icon {
font-size: 2.4rem;
color: var(--primary);
}
.games-section {
background: #f9fbfb;
}
.game-card {
background: #ffffff;
border-radius: 18px;
padding: 1.75rem;
border: 1px solid var(--line);
box-shadow: 0 14px 30px rgba(11, 31, 42, 0.08);
height: 100%;
display: flex;
flex-direction: column;
gap: 1rem;
}
.game-card-header h3 {
font-family: "Space Grotesk", sans-serif;
font-size: 1.4rem;
}
.game-meta {
display: flex;
justify-content: space-between;
color: var(--ink-soft);
font-size: 0.9rem;
}
.game-odds {
font-weight: 600;
color: var(--ink);
}
.process-card {
background: #ffffff;
border-radius: 18px;
padding: 2rem;
border: 1px solid var(--line);
box-shadow: 0 12px 28px rgba(11, 31, 42, 0.08);
height: 100%;
}
.process-card h3 {
font-family: "Space Grotesk", sans-serif;
font-size: 1.2rem;
margin-bottom: 0.6rem;
}
.step {
display: inline-flex;
align-items: center;
justify-content: center;
width: 42px;
height: 42px;
border-radius: 12px;
background: rgba(15, 118, 110, 0.15);
color: var(--primary-strong);
font-weight: 700;
margin-bottom: 1rem;
}
.cta-section {
background: linear-gradient(140deg, rgba(15, 118, 110, 0.12), rgba(245, 158, 11, 0.18));
}
.cta-card {
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: space-between;
gap: 2rem;
padding: 2.5rem;
border-radius: 20px;
background: #ffffff;
box-shadow: 0 18px 40px rgba(11, 31, 42, 0.08);
border: 1px solid var(--line);
}
.cta-card h2 {
font-family: "Space Grotesk", sans-serif;
font-size: 1.8rem;
margin-bottom: 0.5rem;
}
.site-footer {
padding: 2rem 0 3rem;
color: var(--ink-soft);
}
.site-footer .container {
display: flex;
flex-wrap: wrap;
gap: 1rem;
justify-content: space-between;
}
.footer-meta {
font-size: 0.9rem;
}
@media (max-width: 992px) {
.hero-actions {
flex-direction: column;
}
.card-glass {
margin-top: 2rem;
}
}
@media (max-width: 768px) {
.hero-shell {
text-align: left;
}
.stat-card {
padding: 0.9rem 1rem;
}
.card-soft-header {
flex-direction: column;
align-items: flex-start;
}
}