Files
maria_uslugi/form_index_recomender.php

640 lines
27 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
declare (strict_types = 1);
require_once __DIR__ . '/../includes/bootstrap_global.php';
// ===== Helpers header (identiques à index.php) =====
function is_client_logged_in(): bool
{
$role = $_SESSION['role'] ?? ($_SESSION['user_type'] ?? '');
if (! empty($_SESSION['user_id']) && $role === 'client') {
return true;
}
if (! empty($_SESSION['client_id'])) {
return true;
}
if (! empty($_SESSION['reference_id']) && $role === 'client') {
return true;
}
if (! empty($_SESSION['user_id']) && $role === 'praticien') {
return true;
}
if (! empty($_SESSION['praticien_id'])) {
return true;
}
if (! empty($_SESSION['reference_id']) && $role === 'praticien') {
return true;
}
return false;
}
function include_header_clean(string $absPath): void
{
global $translations, $lang;
ob_start();
include $absPath; // /public/includes/header.php
$buf = ob_get_clean() ?: '';
// 0) DOCTYPE + <html>…</html>
$buf = preg_replace('~<!doctype\s+html[^>]*>~i', '', $buf);
$buf = preg_replace('~</?html\b[^>]*>~i', '', $buf);
// 1) retirer <head>…</head> et <body> ouverts/fermés
$buf = preg_replace('~<head\b[^>]*>.*?</head>~is', '', $buf);
$buf = preg_replace('~</?body\b[^>]*>~i', '', $buf);
// 2) retirer les <link> CSS “globaux” pour éviter d’écraser la home
$buf = preg_replace('~<link[^>]+href="[^"]*(bootstrap[^"]*\.css|mobil_style\.css|site_style\.css|fonts\.googleapis)[^"]*"[^>]*>~i', '', $buf);
// 3) retirer le <script> Bootstrap CDN (on le charge déjà en bas de la page)
$buf = preg_replace('~<script[^>]+src="[^"]*bootstrap[^"]*bundle[^"]*\.js[^"]*"[^>]*>\s*</script>~i', '', $buf);
echo $buf; // garde <header> + tes scripts inline utiles
}
/* ---------- Utils ---------- */
function envget(string $k): string
{
return trim((string) ($_ENV[$k] ?? $_SERVER[$k] ?? getenv($k) ?? ''));
}
function t(array $translations, string $key, string $fallback = ''): string
{
$val = $translations[$key] ?? '';
if ($val === '') {
return $fallback;
}
return (string) $val;
}
$LOG_DIR = __DIR__ . '/tmp';
$LOG_FILE = $LOG_DIR . '/contact.log';
if (! is_dir($LOG_DIR)) {@mkdir($LOG_DIR, 0770, true);} // dossier local, pas servi publiquement
/* ---------- CSRF ---------- */
if (empty($_SESSION['pub_csrf'])) {
$_SESSION['pub_csrf'] = bin2hex(random_bytes(32));
}
$CSRF = $_SESSION['pub_csrf'];
// --- reCAPTCHA v2 (lecture robuste) ---
$rcCfg = [];
$cfgPath = __DIR__ . '/includes/recaptcha.php';
if (is_file($cfgPath)) {
$rcCfg = require $cfgPath; // ['site' => '...', 'secret' => '...']
}
$RECAPTCHA_SITE_KEY = trim((string) ($rcCfg['site'] ?? envget('RECAPTCHA_SITE_KEY') ?? ''));
$RECAPTCHA_SECRET_KEY = trim((string) ($rcCfg['secret'] ?? envget('RECAPTCHA_SECRET_KEY') ?? ''));
// Considère la clé "valide" si longueur réaliste (>= 20) – évite les faux négatifs
$HAS_SITE = (strlen($RECAPTCHA_SITE_KEY) >= 20);
$HAS_SECRET = (strlen($RECAPTCHA_SECRET_KEY) >= 20);
// (optionnel) forcer l’affichage en test: /contact.php?testcaptcha=1
if (($_GET['testcaptcha'] ?? '') === '1') {
$HAS_SITE = true;
}
/* ---------- État page ---------- */
$errors = [];
$sent = false;
/* ---------- POST ---------- */
if (($_SERVER['REQUEST_METHOD'] ?? '') === 'POST') {
// CSRF
if (! hash_equals($_SESSION['pub_csrf'] ?? '', $_POST['csrf'] ?? '')) {
$errors[] = t($translations, 'contact_err_security', 'Security error. Refresh and try again.');
}
// Honeypot anti-bot (Corrigé avec 'company' pour correspondre à votre HTML)
if (! empty($_POST['company'] ?? '')) {
$errors[] = t($translations, 'contact_err_spam', 'Spam suspected.');
}
// Données utilisateur
$name = trim($_POST['name'] ?? '');
$profession = trim($_POST['profession'] ?? '');
$city = trim($_POST['city'] ?? '');
$country = trim($_POST['country'] ?? '');
$phone = trim($_POST['phone'] ?? '');
$email = trim($_POST['email'] ?? '');
$site = trim($_POST['site'] ?? '');
$reason = trim($_POST['reason'] ?? '');
// Validations
if (mb_strlen($name) < 2) {
$errors[] = t($translations, 'contact_err_name', 'Please enter your name.');
}
if (mb_strlen($profession) < 2) {
$errors[] = t($translations, 'contact_err_profession', 'Please enter your profession.');
}
if (mb_strlen($city) < 2) {
$errors[] = t($translations, 'contact_err_city', 'Please enter your city.');
}
if (mb_strlen($country) < 2) {
$errors[] = t($translations, 'contact_err_country', 'Please enter your country.');
}
if ($phone === '' && $email === '' && $site === '') {
$errors[] = t($translations, 'contact_err_contact', 'Please provide at least one contact (phone, e-mail or website).');
}
if ($email !== '' && ! filter_var($email, FILTER_VALIDATE_EMAIL)) {
$errors[] = t($translations, 'contact_err_email', 'Please enter a valid email.');
}
if (mb_strlen($reason) < 10) {
$errors[] = t($translations, 'contact_err_reason', 'Reason is too short.');
}
// Envoi
if (! $errors) {
$to = 'contact@uslugi.fr';
$subjectPrefix = t($translations, 'contact_send_subject_prefix', 'Contact form message — ');
$subject = $subjectPrefix . $site;
$mailH3 = t($translations, 'contact_mail_h3', 'New message from uslugi.fr');
$lblName = t($translations, 'contact_mail_label_name', 'Name');
$lblProfession = t($translations, 'contact_mail_label_profession', 'Profession');
$lblCity = t($translations, 'contact_mail_label_city', 'City');
$lblCountry = t($translations, 'contact_mail_label_country', 'Country');
$lblPhone = t($translations, 'contact_mail_label_phone', 'Phone');
$lblEmail = t($translations, 'contact_mail_label_email', 'Email');
$lblSite = t($translations, 'contact_mail_label_site', 'Site');
$lblReason = t($translations, 'contact_mail_label_reason', 'Reason');
$html = '
<h3>' . htmlspecialchars($mailH3, ENT_QUOTES, 'UTF-8') . '</h3>
<p><strong>' . htmlspecialchars($lblName, ENT_QUOTES, 'UTF-8') . ':</strong> ' . htmlspecialchars($name) . '</p>
<p><strong>' . htmlspecialchars($lblProfession, ENT_QUOTES, 'UTF-8') . ':</strong> ' . htmlspecialchars($profession) . '</p>
<p><strong>' . htmlspecialchars($lblCity, ENT_QUOTES, 'UTF-8') . ':</strong> ' . htmlspecialchars($city) . '</p>
<p><strong>' . htmlspecialchars($lblCountry, ENT_QUOTES, 'UTF-8') . ':</strong> ' . htmlspecialchars($country) . '</p>
<p><strong>' . htmlspecialchars($lblPhone, ENT_QUOTES, 'UTF-8') . ':</strong> ' . htmlspecialchars($phone) . '</p>
<p><strong>' . htmlspecialchars($lblEmail, ENT_QUOTES, 'UTF-8') . ':</strong> ' . htmlspecialchars($email) . '</p>
<p><strong>' . htmlspecialchars($lblSite, ENT_QUOTES, 'UTF-8') . ':</strong> ' . htmlspecialchars($site) . '</p>
<p><strong>' . htmlspecialchars($lblReason, ENT_QUOTES, 'UTF-8') . ':</strong><br>' . nl2br(htmlspecialchars($reason)) . '</p>';
$text = $mailH3 . "\n"
. $lblName . ": $name\n"
. $lblProfession . ": $profession\n"
. $lblCity . ": $city\n"
. $lblCountry . ": $country\n"
. $lblPhone . ": $phone\n"
. $lblEmail . ": $email\n"
. $lblSite . ": $site\n\n"
. $lblReason . ":\n$reason\n";
try {
// From et Reply-To (tableaux) comme attendus par ton wrapper
$fromEmail = 'no-reply@uslugi.fr';
$fromName = 'USLUGI.FR';
$replyEmail = filter_var($email, FILTER_VALIDATE_EMAIL) ? $email : 'contact@uslugi.fr';
$replyName = trim($name . ' ' . $profession) ?: 'USLUGI.FR';
// Appel wrapper: retourne [bool $ok, ?string $err]
[$ok, $err] = uslugi_mail(
$to,
$subject,
$html,
$text,
[
'from' => [$fromEmail, $fromName],
'reply_to' => [$replyEmail, $replyName],
// 'bcc' => ['tonmail@gmail.com'],
]
);
if ($ok !== true) {
throw new RuntimeException('Wrapper mail send failed.');
}
// OK
$sent = true;
$_POST = [];
@file_put_contents($LOG_FILE, sprintf(
"[%s] OK to=%s subj=%s reply=%s ip=%s\n",
date('c'), $to, $site, $email, $_SERVER['REMOTE_ADDR'] ?? '-'
), FILE_APPEND);
} catch (Throwable $e) {
error_log('MAIL ERROR: ' . $e->getMessage());
@file_put_contents($LOG_FILE, sprintf(
"[%s] ERR to=%s subj=%s\n",
date('c'), $to, $site
), FILE_APPEND);
// Message utilisateur générique (jamais d’info sensible à l’écran)
$errors[] = t($translations, 'contact_err_send_failed', 'Failed to send message. Please try later.');
}
}
}
// Lang HTML
$langHtml = preg_match('~^[a-z]{2}(-[A-Z]{2})?$~', (string) ($lang ?? '')) ? (string) $lang : 'ru';
/*
* Formulaire de recommandation — à intégrer dans la page existante.
* Conserve les clés form_index_* déjà utilisées pour le titre, l'introduction,
* le bouton, les messages et les champs communs.
*/
$form_index_status = $form_index_status ?? null;
$form_index_message = $form_index_message ?? '';
$form_index_errors = $form_index_errors ?? [];
$form_index_old = $form_index_old ?? [
'name' => '',
'profession' => '',
'city' => '',
'country' => '',
'contact' => '',
'reason' => '',
];
function form_index_value(array $old, string $key): string
{
return htmlspecialchars((string) ($old[$key] ?? ''), ENT_QUOTES, 'UTF-8');
}
function form_index_text(array $translations, string $key, string $fallback): string
{
$value = $translations[$key] ?? '';
return htmlspecialchars($value !== '' ? (string) $value : $fallback, ENT_QUOTES, 'UTF-8');
}
?>
<!doctype html>
<html lang="<?php echo htmlspecialchars($langHtml, ENT_QUOTES, 'UTF-8') ?>">
<head>
<meta charset="UTF-8">
<title><?php echo htmlspecialchars($translations['seo_contact_title'], ENT_QUOTES, 'UTF-8') ?></title>
<meta name="description" content="<?php echo htmlspecialchars($translations['seo_contact_desc'], ENT_QUOTES, 'UTF-8') ?>">
<meta name="keywords" content="<?php echo htmlspecialchars($translations['seo_contact_keywords'], ENT_QUOTES, 'UTF-8') ?>">
<meta name="author" content="Uslugi.fr">
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" href="/css/bootstrap.min.css">
<link rel="stylesheet" href="<?php echo asset('/includes/site_style.css') ?>">
<link rel="stylesheet" href="<?php echo asset('/includes/custom_style.css') ?>">
<link rel="stylesheet" href="<?php echo asset('/includes/mobil_style.css') ?>">
<style>
/* HERO bleu et cadre */
.hero-contact{ background:#8CA9FF; padding: clamp(16px,4vw,32px); }
.contact-wrap{ max-width:980px; margin:0 auto; font-family:"Montserrat",system-ui,-apple-system,"Segoe UI",Roboto,Arial,sans-serif; }
.contact-frame{
background:#fff; border:1px solid #DFE4FF; border-radius:22px;
box-shadow:0 16px 40px rgba(56,55,139,.14);
padding:clamp(16px,3vw,28px);
}
.contact h1{ font-size:clamp(24px,5.6vw,34px); margin:0 0 10px; }
.contact p.muted{ color:#6b7280; margin:0 0 14px; }
/* Forme */
.form-label{ font-weight:600; }
.form-control{ border-radius:12px; padding:12px 14px; }
textarea.form-control{ min-height: 180px; }
/* Bouton rouge arrondi */
.btn-red{
--bs-btn-bg:#E03C3F; --bs-btn-border-color:#E03C3F;
--bs-btn-hover-bg:#c53637; --bs-btn-hover-border-color:#c53637;
--bs-btn-active-bg:#a62e2f; --bs-btn-active-border-color:#a62e2f;
--bs-btn-hover-color:#fff;
color:#fff; border-radius:9999px; padding:12px 22px;
}
</style>
<?php include_once __DIR__ . '/includes/tracking.php'; ?>
</head>
<body>
<?php if (is_client_logged_in()): ?>
<?php
require_once __DIR__ . '/public/includes/init_pr_cl.php';
include_header_clean(__DIR__ . '/public/includes/header.php'); ?>
<?php else: ?>
<header class="site-header">
<div class="container">
<div class="header-left">
<div class="brand">
<a href="/index.php"><img src="/public/uploads/img/logo_u.png"
alt="uslugi.fr"
class="logo-mobile"></a>
<a href="/index.php"><img src="/public/uploads/img/logo.png"
alt="uslugi.fr"
class="logo-desktop"></a>
</div>
<div class="lang-switch">
<?php require __DIR__ . '/includes/menu_langue.php'; ?>
</div>
</div>
<nav class="header-actions">
<a class="btn-login" href="/connexion.php">
<span class="d-sm-none"><?php echo htmlspecialchars($translations['btn_se_connecter'] ?? 'Connexion', ENT_QUOTES, 'UTF-8') ?></span>
<span class="d-none d-sm-inline"><?php echo htmlspecialchars($translations['ja_spec'] ?? 'Je suis spécialiste', ENT_QUOTES, 'UTF-8') ?></span>
</a>
<div class="dropdown">
<button
class="btn btn-logo rounded-circle d-inline-flex align-items-center justify-content-center question-btn"
type="button"
data-bs-toggle="dropdown"
data-bs-auto-close="true"
aria-expanded="false"
aria-label="<?php echo htmlspecialchars(t($translations, 'howitworks_help_aria', 'Help'), ENT_QUOTES, 'UTF-8') ?>">
?
</button>
<ul class="dropdown-menu dropdown-menu-end shadow help-menu menu-panel">
<li><a href="/how-it-work.php"><?php echo htmlspecialchars($translations['kak_rabotaet'] ?? 'Как это работает', ENT_QUOTES, 'UTF-8') ?></a></li>
<li><a href="/about.php"><?php echo htmlspecialchars($translations['pro_nas'] ?? 'О нас', ENT_QUOTES, 'UTF-8') ?></a></li>
<li><a href="/faq.php"><?php echo htmlspecialchars($translations['faq'] ?? 'FAQ', ENT_QUOTES, 'UTF-8') ?></a></li>
<li><a href="/contact.php"><?php echo htmlspecialchars($translations['nam_pisat'] ?? 'Написать нам', ENT_QUOTES, 'UTF-8') ?></a></li>
</ul>
</div>
</nav>
</div>
</header>
<?php endif; ?>
<section class="concierge-section" id="concierge-form">
<div class="concierge-inner">
<div class="concierge-heading">
<span class="label">
<?php echo form_index_text($translations, 'recom_badge', 'Бесплатно · Без регистрации'); ?>
</span>
<h2>
<?php echo form_index_text($translations, 'recom_title', 'Хотите порекомендовать нужного специалиста?'); ?>
</h2>
<p>
<?php echo form_index_text($translations, 'recom_intro', 'Опишите подробно специалиста, которого вы знаете, и мы свяжемся с ним, чтобы предложить разместить профиль на нашей платформе.'); ?>
</p>
</div>
<div class="concierge-card">
<div class="card-stripe"></div>
<?php
if ($sent) {
$form_index_status = 'success';
} elseif ($errors) {
$form_index_status = 'error';
$form_index_message = implode(' ', $errors);
$form_index_old = [
'name' => $name ?? '', 'profession' => $profession ?? '',
'city' => $city ?? '', 'country' => $country ?? '',
'phone' => $phone ?? '', 'email' => $email ?? '',
'site' => $site ?? '', 'reason' => $reason ?? '',
];
}
if ($form_index_status === 'success'): ?>
<div class="card-success" id="successState">
<div class="success-circle">✓</div>
<h3><?php echo form_index_text($translations, 'form_index_success_title', 'Спасибо за рекомендацию!'); ?></h3>
<p><?php echo form_index_text($translations, 'recom_success_text', 'Ваша рекомендация отправлена.'); ?></p>
</div>
<?php else: ?>
<div class="card-form" id="formState">
<?php if ($form_index_status === 'error' && $form_index_message !== ''): ?>
<div class="form-alert form-alert-error" role="alert">
<?php echo htmlspecialchars($form_index_message, ENT_QUOTES, 'UTF-8'); ?>
</div>
<?php endif; ?>
<form method="post" action="">
<input type="hidden" name="csrf" value="<?php echo htmlspecialchars($CSRF, ENT_QUOTES, 'UTF-8'); ?>">
<input type="hidden" name="form_index" value="1">
<div class="honeypot" aria-hidden="true">
<label for="form_index_company">Company</label>
<input type="text" name="company" id="form_index_company" tabindex="-1" autocomplete="off">
</div>
<div class="fields-grid">
<div class="field field-full">
<label for="f-name">
<?php echo form_index_text($translations, 'recom_fullname_label', 'Имя и фамилия'); ?>
<span class="req">*</span>
</label>
<input
type="text"
id="f-name"
name="name"
autocomplete="name"
required
value="<?php echo form_index_value($form_index_old, 'name'); ?>"
class="<?php echo ! empty($form_index_errors['name']) ? 'error' : ''; ?>"
placeholder="<?php echo form_index_text($translations, 'recom_fullname_placeholder', 'Имя и фамилия специалиста'); ?>"
>
</div>
<div class="field field-full">
<label for="f-profession">
<?php echo form_index_text($translations, 'recom_profession_label', 'Профессия / чем занимается'); ?>
<span class="req">*</span>
</label>
<input
type="text"
id="f-profession"
name="profession"
required
value="<?php echo form_index_value($form_index_old, 'profession'); ?>"
class="<?php echo ! empty($form_index_errors['profession']) ? 'error' : ''; ?>"
placeholder="<?php echo form_index_text($translations, 'recom_profession_placeholder', 'Например: адвокат, врач, переводчик…'); ?>"
>
</div>
<div class="field">
<label for="f-city">
<?php echo form_index_text($translations, 'recom_location_label', 'Город'); ?>
<span class="req">*</span>
</label>
<input
type="text"
id="f-city"
name="city"
required
value="<?php echo form_index_value($form_index_old, 'city'); ?>"
class="<?php echo ! empty($form_index_errors['city']) ? 'error' : ''; ?>"
placeholder="<?php echo form_index_text($translations, 'recom_location_placeholder', 'Город'); ?>"
>
</div>
<div class="field">
<label for="f-country">
<?php echo form_index_text($translations, 'recom_location_label', 'Страна'); ?>
<span class="req">*</span>
</label>
<input
type="text"
id="f-country"
name="country"
required
value="<?php echo form_index_value($form_index_old, 'country'); ?>"
class="<?php echo ! empty($form_index_errors['country']) ? 'error' : ''; ?>"
placeholder="<?php echo form_index_text($translations, 'recom_location_placeholder', 'Страна'); ?>"
>
</div>
<div class="field field-full">
<label for="f-phone">
<?php echo form_index_text($translations, 'recom_phone_label', 'Телефон / e-mail / сайт (что известно)'); ?>
</label>
<input
type="text"
id="f-phone"
name="phone"
value="<?php echo form_index_value($form_index_old, 'phone'); ?>"
class="<?php echo ! empty($form_index_errors['phone']) ? 'error' : ''; ?>"
placeholder="<?php echo form_index_text($translations, 'recom_phone_placeholder', 'Телефон'); ?>"
>
</div>
<div class="field field-full">
<label for="f-email">
<?php echo form_index_text($translations, 'recom_email_label', 'Телефон / e-mail / сайт (что известно)'); ?>
</label>
<input
type="text"
id="f-email"
name="email"
value="<?php echo form_index_value($form_index_old, 'email'); ?>"
class="<?php echo ! empty($form_index_errors['email']) ? 'error' : ''; ?>"
placeholder="<?php echo form_index_text($translations, 'recom_email_placeholder', 'E-mail'); ?>"
>
</div>
<div class="field field-full">
<label for="f-site">
<?php echo form_index_text($translations, 'recom_website_label', 'Телефон / e-mail / сайт (что известно)'); ?>
</label>
<input
type="text"
id="f-site"
name="site"
value="<?php echo form_index_value($form_index_old, 'site'); ?>"
class="<?php echo ! empty($form_index_errors['site']) ? 'error' : ''; ?>"
placeholder="<?php echo form_index_text($translations, 'recom_website_placeholder', 'Адрес сайта'); ?>"
>
</div>
<div class="field field-full">
<label for="f-reason">
<?php echo form_index_text($translations, 'recom_reason_label', 'Почему рекомендуете?'); ?>
<span class="req">*</span>
</label>
<textarea
id="f-reason"
name="reason"
required
maxlength="1000"
class="<?php echo ! empty($form_index_errors['reason']) ? 'error' : ''; ?>"
placeholder="<?php echo form_index_text($translations, 'recom_reason_placeholder', 'Коротко расскажите, почему вы рекомендуете этого специалиста…'); ?>"
><?php echo form_index_value($form_index_old, 'reason'); ?></textarea>
</div>
</div>
<button class="btn-submit" type="submit">
<?php echo form_index_text($translations, 'recom_submit', 'Отправить рекомендацию'); ?>
</button>
<p class="form-note">
<?php echo form_index_text($translations, 'recom_note', 'Пожалуйста, указывайте только известную вам информацию.'); ?>
</p>
</form>
</div>
<?php endif; ?>
</div>
</div>
</section>
<style>
.concierge-section {
font-family: 'Montserrat', sans-serif;
background: #f7f8fc;
padding: 52px 20px;
width: 100%;
}
.concierge-inner { max-width: 700px; margin: 0 auto; }
.concierge-heading { text-align: center; margin-bottom: 32px; }
.concierge-heading .label {
display: inline-block; font-size: 11px; font-weight: 700;
letter-spacing: .12em; text-transform: uppercase; color: #2e4db0;
background: #eef2fb; padding: 5px 14px; border-radius: 20px; margin-bottom: 14px;
}
.concierge-heading h2 {
font-size: clamp(20px, 4vw, 26px); font-weight: 700; color: #1e2d5a;
line-height: 1.3; margin: 0 0 10px;
}
.concierge-heading p {
font-size: 14px; color: #6b7280; line-height: 1.65;
max-width: 500px; margin: 0 auto;
}
.concierge-card {
background: #fff; border-radius: 20px; border: 1.5px solid #dde3f0;
box-shadow: 0 4px 24px rgba(30,45,90,.08); overflow: hidden;
}
.card-stripe { height: 4px; background: linear-gradient(90deg,#1e2d5a 0%,#2e4db0 100%); }
.card-form { padding: 32px 36px 36px; }
.fields-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; margin-bottom: 16px; }
.field-full { grid-column: 1 / -1; }
.field { display: flex; flex-direction: column; gap: 7px; min-width: 0; }
.field label {
font-size: 12px; font-weight: 600; color: #1e2d5a;
letter-spacing: .03em; text-transform: uppercase;
}
.field label .req { color: #2e4db0; margin-left: 2px; }
.card-form input, .card-form textarea {
box-sizing: border-box; width: 100%; font-family: 'Montserrat', sans-serif;
font-size: 14px; color: #1e2d5a; background: #f7f8fc;
border: 1.5px solid #dde3f0; border-radius: 8px; padding: 11px 14px;
outline: none; transition: border-color .18s,background .18s,box-shadow .18s;
}
.card-form input::placeholder, .card-form textarea::placeholder { color: #b0b8cc; }
.card-form input:focus, .card-form textarea:focus {
border-color: #2e4db0; background: #fff; box-shadow: 0 0 0 3px rgba(46,77,176,.09);
}
.card-form input.error, .card-form textarea.error { border-color: #d73a3a; background: #fff8f8; }
.card-form textarea { resize: vertical; min-height: 100px; line-height: 1.6; }
.btn-submit {
box-sizing: border-box; width: 100%; margin-top: 20px; background: #e03c3f; color: #fff;
font-family: 'Montserrat', sans-serif; font-size: 14px; font-weight: 700;
letter-spacing: .04em; border: 0; border-radius: 999px; padding: 14px 24px;
cursor: pointer; transition: background .18s,transform .12s,box-shadow .18s;
}
.btn-submit:hover { background: #c93639; box-shadow: 0 6px 20px rgba(30,45,90,.22); }
.btn-submit:active { transform: translateY(1px); }
.form-note { text-align: center; font-size: 11px; color: #6b7280; margin: 12px 0 0; line-height: 1.5; }
.form-alert { margin-bottom: 18px; padding: 12px 14px; border-radius: 10px; font-size: 14px; line-height: 1.5; }
.form-alert-error { background: #fff4f4; border: 1px solid #f0caca; color: #9f1d1d; }
.card-success { padding: 52px 36px; text-align: center; }
.success-circle {
width: 56px; height: 56px; border-radius: 50%; background: #1e2d5a;
display: flex; align-items: center; justify-content: center; margin: 0 auto 18px;
font-size: 24px; color: #fff;
}
.card-success h3 { font-size: 20px; font-weight: 700; color: #1e2d5a; margin: 0 0 10px; }
.card-success p { font-size: 14px; color: #6b7280; line-height: 1.65; max-width: 380px; margin: 0 auto; }
.honeypot { position: absolute; left: -9999px; opacity: 0; pointer-events: none; }
@media (max-width: 540px) {
.card-form { padding: 24px 20px 28px; }
.fields-grid { grid-template-columns: 1fr; }
.field-full { grid-column: auto; }
.card-success { padding: 36px 20px; }
.concierge-section { padding: 36px 16px; }
}
</style>