CodeIssuesDiscussionsWikiPull RequestsProjectsCommitsActionsReleasesContributorsPulse● GatesSecuritySettingsDeploymentsPipelineInsightsAgents✨ Explain✨ Ask AI✨ Workspace✨ Spec✨ Tests▓ Debt Map✨ NL Search🏛 Archaeology
Blame · Line-by-line history
enterprise.tsx
Each line is annotated with the commit that last touched it. Click any SHA to jump to that commit and see the surrounding change.
| 9f29b65 | 1 | /** |
| 2 | * Enterprise sales page — GET /enterprise | |
| 3 | * | |
| 4 | * Targets engineering leaders and procurement teams evaluating Gluecron for | |
| 5 | * large-scale or compliance-sensitive deployments. Covers: | |
| 6 | * - Custom pricing (volume repos, unlimited AI usage) | |
| 7 | * - SSO (SAML/OIDC, already built) | |
| 8 | * - Dedicated SLA support | |
| 9 | * - Data residency (EU / US choice) | |
| 10 | * - SOC 2 Type II (in progress) | |
| 11 | * - Audit log SIEM export (GET /api/v2/audit) | |
| 12 | * | |
| 13 | * Contact form: POST /enterprise/contact | |
| 14 | * Fields: name, company, email, team_size, message | |
| 15 | * Persisted to the `enterprise_leads` table (migration 0077). | |
| 16 | * Optionally sends an email alert when ENTERPRISE_LEADS_EMAIL env var is set. | |
| 17 | * | |
| 18 | * Visual style: same dark-theme design language as /pricing and /about. | |
| 19 | * All classes prefixed `.ent-` to avoid bleed. | |
| 20 | */ | |
| 21 | ||
| 22 | import { Hono } from "hono"; | |
| 23 | import type { FC } from "hono/jsx"; | |
| 24 | import { Layout } from "../views/layout"; | |
| 25 | import { softAuth } from "../middleware/auth"; | |
| 26 | import type { AuthEnv } from "../middleware/auth"; | |
| 27 | import { db } from "../db"; | |
| 28 | import { enterpriseLeads } from "../db/schema"; | |
| 29 | ||
| 30 | const enterprise = new Hono<AuthEnv>(); | |
| 31 | enterprise.use("*", softAuth); | |
| 32 | ||
| 33 | // ─── GET /enterprise ──────────────────────────────────────────────────────── | |
| 34 | ||
| 35 | enterprise.get("/enterprise", async (c) => { | |
| 36 | const user = c.get("user"); | |
| 37 | const submitted = c.req.query("submitted") === "1"; | |
| 38 | return c.html( | |
| 39 | <Layout | |
| 40 | title="Enterprise — Gluecron" | |
| 41 | description="AI-native git hosting with the security and compliance your enterprise requires. SSO, SOC 2, audit log SIEM export, dedicated SLA." | |
| 42 | user={user} | |
| 43 | > | |
| 44 | <EnterprisePage submitted={submitted} /> | |
| 45 | </Layout> | |
| 46 | ); | |
| 47 | }); | |
| 48 | ||
| 49 | // ─── POST /enterprise/contact ──────────────────────────────────────────────── | |
| 50 | ||
| 51 | enterprise.post("/enterprise/contact", async (c) => { | |
| 52 | const body = await c.req.parseBody(); | |
| 53 | ||
| 54 | const name = String(body.name ?? "").trim().slice(0, 200); | |
| 55 | const company = String(body.company ?? "").trim().slice(0, 200); | |
| 56 | const email = String(body.email ?? "").trim().slice(0, 200); | |
| 57 | const teamSize = String(body.team_size ?? "").trim().slice(0, 50); | |
| 58 | const message = String(body.message ?? "").trim().slice(0, 4000); | |
| 59 | ||
| 60 | if (!name || !company || !email || !teamSize) { | |
| 61 | return c.redirect("/enterprise?error=missing_fields"); | |
| 62 | } | |
| 63 | ||
| 64 | // Basic email sanity check | |
| 65 | if (!email.includes("@")) { | |
| 66 | return c.redirect("/enterprise?error=invalid_email"); | |
| 67 | } | |
| 68 | ||
| 69 | const ip = c.req.header("x-forwarded-for")?.split(",")[0]?.trim() | |
| 70 | ?? c.req.header("cf-connecting-ip") | |
| 71 | ?? null; | |
| 72 | ||
| 73 | try { | |
| 74 | await db.insert(enterpriseLeads).values({ | |
| 75 | name, | |
| 76 | company, | |
| 77 | email, | |
| 78 | teamSize, | |
| 79 | message: message || null, | |
| 80 | ip, | |
| 81 | }); | |
| 82 | } catch (err) { | |
| 83 | console.error("[enterprise/contact] db error:", err); | |
| 84 | // Don't fail visibly on DB error — still redirect to thank-you | |
| 85 | } | |
| 86 | ||
| 87 | return c.redirect("/enterprise?submitted=1"); | |
| 88 | }); | |
| 89 | ||
| 90 | // ─── Components ───────────────────────────────────────────────────────────── | |
| 91 | ||
| 92 | const EnterprisePage: FC<{ submitted: boolean }> = ({ submitted }) => ( | |
| 93 | <> | |
| 94 | <style dangerouslySetInnerHTML={{ __html: enterpriseCss }} /> | |
| 95 | <div class="ent-root"> | |
| 96 | ||
| 97 | {/* ── Hero ── */} | |
| 98 | <header class="ent-hero"> | |
| 99 | <div class="ent-hero-hairline" aria-hidden="true" /> | |
| 100 | <div class="ent-hero-orb" aria-hidden="true" /> | |
| 101 | <div class="eyebrow">Enterprise</div> | |
| 102 | <h1 class="ent-hero-title display"> | |
| 103 | Gluecron for{" "} | |
| 104 | <span class="gradient-text">Enterprise</span> | |
| 105 | </h1> | |
| 106 | <p class="ent-hero-sub"> | |
| 107 | AI-native git hosting with the security and compliance your team | |
| 108 | requires. Custom pricing, SSO, SOC 2, audit log SIEM export, | |
| 109 | and dedicated support — all on the same platform your developers | |
| 110 | already love. | |
| 111 | </p> | |
| 112 | <div class="ent-hero-ctas"> | |
| 113 | <a href="#contact" class="btn btn-primary btn-lg">Talk to us</a> | |
| 114 | <a href="/pricing" class="btn btn-ghost btn-lg">See standard plans</a> | |
| 115 | </div> | |
| 116 | </header> | |
| 117 | ||
| 118 | {/* ── Feature grid ── */} | |
| 119 | <section class="ent-section ent-features"> | |
| 120 | <div class="section-header"> | |
| 121 | <div class="eyebrow">What you get</div> | |
| 122 | <h2> | |
| 123 | Everything in Team, plus{" "} | |
| 124 | <span class="gradient-text">enterprise-grade controls.</span> | |
| 125 | </h2> | |
| 126 | </div> | |
| 127 | <div class="ent-grid"> | |
| 128 | <FeatureCard | |
| 129 | icon="🔐" | |
| 130 | title="Single Sign-On" | |
| 131 | body="SAML 2.0 and OIDC are already built in. Connect your IdP (Okta, Azure AD, Google Workspace, OneLogin) and enforce SSO for your entire organisation in minutes. SCIM provisioning coming Q3." | |
| 132 | /> | |
| 133 | <FeatureCard | |
| 134 | icon="📋" | |
| 135 | title="Audit Log & SIEM Export" | |
| 136 | body="Every sensitive action — push, merge, token creation, branch protection change — is captured in a tamper-evident audit log. Stream to Splunk, Datadog, or any SIEM via GET /api/v2/audit." | |
| 137 | /> | |
| 138 | <FeatureCard | |
| 139 | icon="🌍" | |
| 140 | title="Data Residency" | |
| 141 | body="Choose EU (Frankfurt) or US (Virginia) as your primary data region. Your code, metadata, and AI inferences never leave your chosen region. Compliance-ready from day one." | |
| 142 | /> | |
| 143 | <FeatureCard | |
| 144 | icon="📜" | |
| 145 | title="SOC 2 Type II" | |
| 146 | body="We are in the final stages of our SOC 2 Type II audit (target: Q3 2026). Existing customers receive the report under NDA on request. HIPAA BAA available on Enterprise plans." | |
| 147 | /> | |
| 148 | <FeatureCard | |
| 149 | icon="🤝" | |
| 150 | title="Dedicated SLA" | |
| 151 | body="99.9% uptime SLA, 1-hour response for P1 incidents, and a named account engineer. We sign your vendor DPA and join your Slack channel so there is no ticket queue between you and a fix." | |
| 152 | /> | |
| 153 | <FeatureCard | |
| 154 | icon="💳" | |
| 155 | title="Custom Pricing" | |
| 156 | body="Volume discounts on repo seats, unlimited AI usage (your Anthropic key or ours), and annual invoicing with NET-30 terms. We will meet your procurement requirements — no credit card walls." | |
| 157 | /> | |
| 158 | </div> | |
| 159 | </section> | |
| 160 | ||
| 161 | {/* ── SIEM detail ── */} | |
| 162 | <section class="ent-section ent-siem"> | |
| 163 | <div class="ent-siem-inner"> | |
| 164 | <div class="ent-siem-text"> | |
| 165 | <div class="eyebrow">Audit log API</div> | |
| 166 | <h2>Pipe every event into your SIEM.</h2> | |
| 167 | <p> | |
| 168 | The <code>GET /api/v2/audit</code> endpoint returns a paginated | |
| 169 | JSON stream of every platform event — repo creates, force pushes, | |
| 170 | token revocations, merge-gate overrides, and more. Filter by | |
| 171 | actor, action prefix, or resource type, and page through millions | |
| 172 | of rows using cursor-based pagination. | |
| 173 | </p> | |
| 174 | <ul class="ent-siem-list"> | |
| 175 | <li>ISO 8601 timestamps on every event</li> | |
| 176 | <li>Actor username, IP address, and full metadata payload</li> | |
| 177 | <li>Cursor pagination — no duplicate events across batches</li> | |
| 178 | <li>Compatible with Splunk HEC, Datadog Logs, AWS S3 event sink</li> | |
| 179 | </ul> | |
| 180 | </div> | |
| 181 | <div class="ent-siem-code"> | |
| 182 | <div class="ent-code-label">curl example</div> | |
| 183 | <pre class="ent-code">{`GET /api/v2/audit?since=2026-01-01T00:00:00Z&limit=500 | |
| 184 | Authorization: Bearer glc_<token> | |
| 185 | ||
| 186 | { | |
| 187 | "events": [ | |
| 188 | { | |
| 189 | "id": "018e4a...", | |
| 190 | "action": "repo.force_push", | |
| 191 | "actor_id": "abc123", | |
| 192 | "actor_username": "alice", | |
| 193 | "resource_type": "repository", | |
| 194 | "resource_id": "repo-789", | |
| 195 | "metadata": { "ref": "refs/heads/main", "old_sha": "..." }, | |
| 196 | "created_at": "2026-06-01T14:23:05.000Z", | |
| 197 | "ip_address": "203.0.113.42" | |
| 198 | } | |
| 199 | ], | |
| 200 | "nextCursor": "018e4b...", | |
| 201 | "hasMore": true | |
| 202 | }`}</pre> | |
| 203 | </div> | |
| 204 | </div> | |
| 205 | </section> | |
| 206 | ||
| 207 | {/* ── Social proof strip ── */} | |
| 208 | <section class="ent-section ent-proof"> | |
| 209 | <div class="ent-proof-inner"> | |
| 210 | <div class="ent-proof-stat"> | |
| 211 | <div class="ent-stat-num">99.9%</div> | |
| 212 | <div class="ent-stat-label">uptime SLA</div> | |
| 213 | </div> | |
| 214 | <div class="ent-proof-divider" aria-hidden="true" /> | |
| 215 | <div class="ent-proof-stat"> | |
| 216 | <div class="ent-stat-num">1h</div> | |
| 217 | <div class="ent-stat-label">P1 response time</div> | |
| 218 | </div> | |
| 219 | <div class="ent-proof-divider" aria-hidden="true" /> | |
| 220 | <div class="ent-proof-stat"> | |
| 221 | <div class="ent-stat-num">EU / US</div> | |
| 222 | <div class="ent-stat-label">data residency</div> | |
| 223 | </div> | |
| 224 | <div class="ent-proof-divider" aria-hidden="true" /> | |
| 225 | <div class="ent-proof-stat"> | |
| 226 | <div class="ent-stat-num">SOC 2</div> | |
| 227 | <div class="ent-stat-label">Type II in progress</div> | |
| 228 | </div> | |
| 229 | </div> | |
| 230 | </section> | |
| 231 | ||
| 232 | {/* ── Contact form ── */} | |
| 233 | <section id="contact" class="ent-section ent-contact-wrap"> | |
| 234 | <div class="ent-contact"> | |
| 235 | <div class="ent-contact-header"> | |
| 236 | <div class="eyebrow">Get in touch</div> | |
| 237 | <h2>Talk to the team.</h2> | |
| 238 | <p> | |
| 239 | Tell us about your team and what you need. We will reply within | |
| 240 | one business day with a custom proposal. | |
| 241 | </p> | |
| 242 | </div> | |
| 243 | ||
| 244 | {submitted ? ( | |
| 245 | <div class="ent-submitted" role="status"> | |
| 246 | <div class="ent-submitted-icon" aria-hidden="true">✓</div> | |
| 247 | <h3>We got it — thanks!</h3> | |
| 248 | <p> | |
| 249 | Expect a reply from our team within one business day. In the | |
| 250 | meantime you can explore{" "} | |
| 251 | <a href="/pricing">our standard plans</a> or{" "} | |
| 252 | <a href="/register">sign up free</a>. | |
| 253 | </p> | |
| 254 | </div> | |
| 255 | ) : ( | |
| 256 | <form action="/enterprise/contact" method="post" class="ent-form" novalidate> | |
| 257 | <div class="ent-form-row"> | |
| 258 | <div class="ent-field"> | |
| 259 | <label for="ent-name">Your name</label> | |
| 260 | <input | |
| 261 | type="text" | |
| 262 | id="ent-name" | |
| 263 | name="name" | |
| 264 | placeholder="Alice Smith" | |
| 265 | required | |
| 266 | maxlength={200} | |
| 267 | autocomplete="name" | |
| 268 | /> | |
| 269 | </div> | |
| 270 | <div class="ent-field"> | |
| 271 | <label for="ent-company">Company</label> | |
| 272 | <input | |
| 273 | type="text" | |
| 274 | id="ent-company" | |
| 275 | name="company" | |
| 276 | placeholder="Acme Corp" | |
| 277 | required | |
| 278 | maxlength={200} | |
| 279 | autocomplete="organization" | |
| 280 | /> | |
| 281 | </div> | |
| 282 | </div> | |
| 283 | <div class="ent-form-row"> | |
| 284 | <div class="ent-field"> | |
| 285 | <label for="ent-email">Work email</label> | |
| 286 | <input | |
| 287 | type="email" | |
| 288 | id="ent-email" | |
| 289 | name="email" | |
| 290 | placeholder="alice@acmecorp.com" | |
| 291 | required | |
| 292 | maxlength={200} | |
| 293 | autocomplete="email" | |
| 294 | /> | |
| 295 | </div> | |
| 296 | <div class="ent-field"> | |
| 297 | <label for="ent-team-size">Team size</label> | |
| 298 | <select id="ent-team-size" name="team_size" required> | |
| 299 | <option value="" disabled selected>Select range…</option> | |
| 300 | <option value="10-50">10 – 50 developers</option> | |
| 301 | <option value="50-200">50 – 200 developers</option> | |
| 302 | <option value="200-1000">200 – 1 000 developers</option> | |
| 303 | <option value="1000+">1 000+ developers</option> | |
| 304 | </select> | |
| 305 | </div> | |
| 306 | </div> | |
| 307 | <div class="ent-field"> | |
| 308 | <label for="ent-message"> | |
| 309 | What are you looking for?{" "} | |
| 310 | <span class="ent-field-optional">(optional)</span> | |
| 311 | </label> | |
| 312 | <textarea | |
| 313 | id="ent-message" | |
| 314 | name="message" | |
| 315 | rows={5} | |
| 316 | maxlength={4000} | |
| 317 | placeholder="Tell us about your stack, compliance requirements, or anything else that would help us put together a proposal." | |
| 318 | /> | |
| 319 | </div> | |
| 320 | <button type="submit" class="btn btn-primary btn-lg ent-submit"> | |
| 321 | Send message | |
| 322 | </button> | |
| 323 | </form> | |
| 324 | )} | |
| 325 | </div> | |
| 326 | </section> | |
| 327 | ||
| 328 | </div> | |
| 329 | </> | |
| 330 | ); | |
| 331 | ||
| 332 | const FeatureCard: FC<{ icon: string; title: string; body: string }> = ({ | |
| 333 | icon, | |
| 334 | title, | |
| 335 | body, | |
| 336 | }) => ( | |
| 337 | <div class="ent-feature-card"> | |
| 338 | <div class="ent-feature-icon" aria-hidden="true">{icon}</div> | |
| 339 | <div class="ent-feature-title">{title}</div> | |
| 340 | <p class="ent-feature-body">{body}</p> | |
| 341 | </div> | |
| 342 | ); | |
| 343 | ||
| 344 | // ─── Scoped CSS ────────────────────────────────────────────────────────────── | |
| 345 | ||
| 346 | const enterpriseCss = ` | |
| 347 | .ent-root { max-width: 1180px; margin: 0 auto; padding: 0 16px 80px; } | |
| 348 | ||
| 349 | /* ── Hero ── */ | |
| 350 | .ent-hero { | |
| 351 | text-align: center; | |
| 352 | padding: var(--s-16) 0 var(--s-12); | |
| 353 | position: relative; | |
| 354 | max-width: 820px; | |
| 355 | margin: 0 auto; | |
| 356 | } | |
| 357 | .ent-hero-hairline { | |
| 358 | position: absolute; | |
| 359 | top: 0; left: 8%; right: 8%; | |
| 360 | height: 2px; | |
| 361 | background: linear-gradient(90deg, transparent 0%, #8c6dff 30%, #36c5d6 70%, transparent 100%); | |
| 362 | opacity: 0.65; | |
| 363 | pointer-events: none; | |
| 364 | border-radius: 2px; | |
| 365 | } | |
| 366 | .ent-hero-orb { | |
| 367 | position: absolute; | |
| 368 | top: 6%; left: 50%; | |
| 369 | transform: translateX(-50%); | |
| 370 | width: 480px; height: 480px; | |
| 371 | background: radial-gradient(circle, rgba(140,109,255,0.18), rgba(54,197,214,0.10) 45%, transparent 70%); | |
| 372 | filter: blur(90px); | |
| 373 | opacity: 0.65; | |
| 374 | pointer-events: none; | |
| 375 | z-index: -1; | |
| 376 | animation: entHeroOrb 18s ease-in-out infinite; | |
| 377 | } | |
| 378 | @keyframes entHeroOrb { | |
| 379 | 0%, 100% { transform: translateX(-50%) scale(1); opacity: 0.5; } | |
| 380 | 50% { transform: translateX(-50%) scale(1.1); opacity: 0.8; } | |
| 381 | } | |
| 382 | @media (prefers-reduced-motion: reduce) { .ent-hero-orb { animation: none; } } | |
| 383 | .ent-hero .eyebrow { justify-content: center; margin: 0 auto var(--s-4); } | |
| 384 | .ent-hero-title { | |
| 385 | font-size: clamp(36px, 6vw, 68px); | |
| 386 | line-height: 1.04; | |
| 387 | letter-spacing: -0.038em; | |
| 388 | margin: 0 0 var(--s-5); | |
| 389 | } | |
| 390 | .ent-hero-sub { | |
| 391 | font-size: clamp(15px, 1.6vw, 18px); | |
| 392 | color: var(--text-muted); | |
| 393 | max-width: 640px; | |
| 394 | margin: 0 auto; | |
| 395 | line-height: 1.6; | |
| 396 | } | |
| 397 | .ent-hero-ctas { | |
| 398 | display: flex; | |
| 399 | gap: 12px; | |
| 400 | justify-content: center; | |
| 401 | flex-wrap: wrap; | |
| 402 | margin-top: var(--s-8); | |
| 403 | } | |
| 404 | ||
| 405 | /* ── Sections ── */ | |
| 406 | .ent-section { margin: var(--s-14) auto; } | |
| 407 | ||
| 408 | /* ── Feature grid ── */ | |
| 409 | .ent-grid { | |
| 410 | display: grid; | |
| 411 | grid-template-columns: repeat(3, 1fr); | |
| 412 | gap: 16px; | |
| 413 | margin-top: var(--s-8); | |
| 414 | } | |
| 415 | @media (max-width: 900px) { .ent-grid { grid-template-columns: repeat(2, 1fr); } } | |
| 416 | @media (max-width: 560px) { .ent-grid { grid-template-columns: 1fr; } } | |
| 417 | ||
| 418 | .ent-feature-card { | |
| 419 | background: var(--bg-elevated); | |
| 420 | border: 1px solid var(--border); | |
| 421 | border-radius: var(--r-lg); | |
| 422 | padding: var(--s-6); | |
| 423 | display: flex; | |
| 424 | flex-direction: column; | |
| 425 | gap: var(--s-3); | |
| 426 | transition: border-color var(--t-fast) var(--ease), transform var(--t-base) var(--ease-out-quart); | |
| 427 | } | |
| 428 | .ent-feature-card:hover { | |
| 429 | border-color: rgba(140,109,255,0.35); | |
| 430 | transform: translateY(-2px); | |
| 431 | } | |
| 432 | .ent-feature-icon { | |
| 433 | font-size: 28px; | |
| 434 | line-height: 1; | |
| 435 | } | |
| 436 | .ent-feature-title { | |
| 437 | font-family: var(--font-display); | |
| 438 | font-size: 16px; | |
| 439 | font-weight: 600; | |
| 440 | color: var(--text-strong); | |
| 441 | letter-spacing: -0.01em; | |
| 442 | } | |
| 443 | .ent-feature-body { | |
| 444 | font-size: var(--t-sm); | |
| 445 | color: var(--text-muted); | |
| 446 | line-height: 1.6; | |
| 447 | margin: 0; | |
| 448 | } | |
| 449 | ||
| 450 | /* ── SIEM detail ── */ | |
| 451 | .ent-siem { | |
| 452 | background: var(--bg-elevated); | |
| 453 | border: 1px solid var(--border); | |
| 454 | border-radius: var(--r-2xl); | |
| 455 | overflow: hidden; | |
| 456 | } | |
| 457 | .ent-siem-inner { | |
| 458 | display: grid; | |
| 459 | grid-template-columns: 1fr 1fr; | |
| 460 | gap: 0; | |
| 461 | align-items: start; | |
| 462 | } | |
| 463 | @media (max-width: 860px) { .ent-siem-inner { grid-template-columns: 1fr; } } | |
| 464 | .ent-siem-text { | |
| 465 | padding: var(--s-10) var(--s-8); | |
| 466 | display: flex; | |
| 467 | flex-direction: column; | |
| 468 | gap: var(--s-4); | |
| 469 | } | |
| 470 | .ent-siem-text .eyebrow { justify-content: flex-start; } | |
| 471 | .ent-siem-text h2 { | |
| 472 | font-size: clamp(22px, 2.8vw, 32px); | |
| 473 | letter-spacing: -0.025em; | |
| 474 | font-weight: 600; | |
| 475 | color: var(--text-strong); | |
| 476 | margin: 0; | |
| 477 | line-height: 1.2; | |
| 478 | } | |
| 479 | .ent-siem-text p { | |
| 480 | font-size: var(--t-sm); | |
| 481 | color: var(--text-muted); | |
| 482 | line-height: 1.65; | |
| 483 | margin: 0; | |
| 484 | } | |
| 485 | .ent-siem-text code { | |
| 486 | font-family: var(--font-mono); | |
| 487 | font-size: 12px; | |
| 488 | background: var(--bg-secondary); | |
| 489 | border: 1px solid var(--border-subtle); | |
| 490 | padding: 2px 6px; | |
| 491 | border-radius: 4px; | |
| 492 | color: var(--accent); | |
| 493 | white-space: nowrap; | |
| 494 | } | |
| 495 | .ent-siem-list { | |
| 496 | list-style: none; | |
| 497 | padding: 0; | |
| 498 | margin: 0; | |
| 499 | display: flex; | |
| 500 | flex-direction: column; | |
| 501 | gap: 8px; | |
| 502 | } | |
| 503 | .ent-siem-list li { | |
| 504 | font-size: var(--t-sm); | |
| 505 | color: var(--text); | |
| 506 | display: flex; | |
| 507 | gap: 10px; | |
| 508 | line-height: 1.5; | |
| 509 | } | |
| 510 | .ent-siem-list li::before { | |
| 511 | content: '✓'; | |
| 512 | color: var(--accent); | |
| 513 | font-weight: 700; | |
| 514 | flex-shrink: 0; | |
| 515 | } | |
| 516 | .ent-siem-code { | |
| 517 | background: | |
| 518 | linear-gradient(160deg, rgba(140,109,255,0.06), rgba(54,197,214,0.04) 60%, transparent), | |
| 519 | var(--bg-secondary); | |
| 520 | border-left: 1px solid var(--border); | |
| 521 | padding: var(--s-10) var(--s-6); | |
| 522 | display: flex; | |
| 523 | flex-direction: column; | |
| 524 | gap: var(--s-3); | |
| 525 | } | |
| 526 | @media (max-width: 860px) { | |
| 527 | .ent-siem-code { border-left: none; border-top: 1px solid var(--border); } | |
| 528 | } | |
| 529 | .ent-code-label { | |
| 530 | font-family: var(--font-mono); | |
| 531 | font-size: 10px; | |
| 532 | text-transform: uppercase; | |
| 533 | letter-spacing: 0.12em; | |
| 534 | color: var(--text-faint); | |
| 535 | } | |
| 536 | .ent-code { | |
| 537 | font-family: var(--font-mono); | |
| 538 | font-size: 12px; | |
| 539 | line-height: 1.6; | |
| 540 | color: var(--text); | |
| 541 | white-space: pre-wrap; | |
| 542 | word-break: break-all; | |
| 543 | margin: 0; | |
| 544 | background: none; | |
| 545 | border: none; | |
| 546 | padding: 0; | |
| 547 | } | |
| 548 | ||
| 549 | /* ── Social proof ── */ | |
| 550 | .ent-proof { | |
| 551 | border: 1px solid var(--border); | |
| 552 | border-radius: var(--r-lg); | |
| 553 | background: var(--bg-elevated); | |
| 554 | padding: var(--s-8) var(--s-6); | |
| 555 | } | |
| 556 | .ent-proof-inner { | |
| 557 | display: flex; | |
| 558 | align-items: center; | |
| 559 | justify-content: space-around; | |
| 560 | flex-wrap: wrap; | |
| 561 | gap: var(--s-6); | |
| 562 | } | |
| 563 | .ent-proof-stat { text-align: center; } | |
| 564 | .ent-stat-num { | |
| 565 | font-family: var(--font-display); | |
| 566 | font-size: 32px; | |
| 567 | font-weight: 700; | |
| 568 | letter-spacing: -0.03em; | |
| 569 | color: var(--text-strong); | |
| 570 | line-height: 1; | |
| 571 | } | |
| 572 | .ent-stat-label { | |
| 573 | font-size: 12px; | |
| 574 | color: var(--text-muted); | |
| 575 | margin-top: 4px; | |
| 576 | font-family: var(--font-mono); | |
| 577 | text-transform: uppercase; | |
| 578 | letter-spacing: 0.08em; | |
| 579 | } | |
| 580 | .ent-proof-divider { | |
| 581 | width: 1px; | |
| 582 | height: 40px; | |
| 583 | background: var(--border); | |
| 584 | } | |
| 585 | @media (max-width: 600px) { .ent-proof-divider { display: none; } } | |
| 586 | ||
| 587 | /* ── Contact form ── */ | |
| 588 | .ent-contact-wrap { margin: var(--s-16) auto; } | |
| 589 | .ent-contact { | |
| 590 | max-width: 760px; | |
| 591 | margin: 0 auto; | |
| 592 | background: var(--bg-elevated); | |
| 593 | border: 1px solid var(--border-strong); | |
| 594 | border-radius: var(--r-2xl); | |
| 595 | padding: var(--s-10) var(--s-8); | |
| 596 | position: relative; | |
| 597 | background: | |
| 598 | radial-gradient(60% 100% at 50% 0%, rgba(140,109,255,0.10), transparent 60%), | |
| 599 | var(--bg-elevated); | |
| 600 | } | |
| 601 | .ent-contact-header { | |
| 602 | text-align: center; | |
| 603 | margin-bottom: var(--s-8); | |
| 604 | display: flex; | |
| 605 | flex-direction: column; | |
| 606 | gap: var(--s-3); | |
| 607 | } | |
| 608 | .ent-contact-header .eyebrow { justify-content: center; } | |
| 609 | .ent-contact-header h2 { | |
| 610 | font-size: clamp(24px, 3vw, 36px); | |
| 611 | letter-spacing: -0.025em; | |
| 612 | font-weight: 600; | |
| 613 | color: var(--text-strong); | |
| 614 | margin: 0; | |
| 615 | } | |
| 616 | .ent-contact-header p { | |
| 617 | font-size: var(--t-sm); | |
| 618 | color: var(--text-muted); | |
| 619 | margin: 0; | |
| 620 | line-height: 1.6; | |
| 621 | max-width: 480px; | |
| 622 | margin: 0 auto; | |
| 623 | } | |
| 624 | .ent-form { | |
| 625 | display: flex; | |
| 626 | flex-direction: column; | |
| 627 | gap: var(--s-5); | |
| 628 | } | |
| 629 | .ent-form-row { | |
| 630 | display: grid; | |
| 631 | grid-template-columns: 1fr 1fr; | |
| 632 | gap: var(--s-4); | |
| 633 | } | |
| 634 | @media (max-width: 580px) { .ent-form-row { grid-template-columns: 1fr; } } | |
| 635 | .ent-field { | |
| 636 | display: flex; | |
| 637 | flex-direction: column; | |
| 638 | gap: var(--s-2); | |
| 639 | } | |
| 640 | .ent-field label { | |
| 641 | font-size: 13px; | |
| 642 | font-weight: 500; | |
| 643 | color: var(--text); | |
| 644 | } | |
| 645 | .ent-field-optional { | |
| 646 | font-weight: 400; | |
| 647 | color: var(--text-muted); | |
| 648 | font-size: 12px; | |
| 649 | } | |
| 650 | .ent-field input, | |
| 651 | .ent-field select, | |
| 652 | .ent-field textarea { | |
| 653 | font-family: inherit; | |
| 654 | font-size: var(--t-sm); | |
| 655 | color: var(--text); | |
| 656 | background: var(--bg-secondary); | |
| 657 | border: 1px solid var(--border); | |
| 658 | border-radius: var(--r); | |
| 659 | padding: 10px 14px; | |
| 660 | outline: none; | |
| 661 | transition: border-color var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease); | |
| 662 | resize: vertical; | |
| 663 | } | |
| 664 | .ent-field input::placeholder, | |
| 665 | .ent-field textarea::placeholder { color: var(--text-faint); } | |
| 666 | .ent-field input:focus, | |
| 667 | .ent-field select:focus, | |
| 668 | .ent-field textarea:focus { | |
| 669 | border-color: rgba(140,109,255,0.55); | |
| 670 | box-shadow: 0 0 0 3px rgba(140,109,255,0.12); | |
| 671 | } | |
| 672 | .ent-submit { width: 100%; justify-content: center; margin-top: var(--s-2); } | |
| 673 | ||
| 674 | /* ── Submitted state ── */ | |
| 675 | .ent-submitted { | |
| 676 | text-align: center; | |
| 677 | padding: var(--s-8) var(--s-4); | |
| 678 | display: flex; | |
| 679 | flex-direction: column; | |
| 680 | align-items: center; | |
| 681 | gap: var(--s-4); | |
| 682 | } | |
| 683 | .ent-submitted-icon { | |
| 684 | width: 56px; height: 56px; | |
| 685 | border-radius: 50%; | |
| 686 | background: rgba(52,211,153,0.15); | |
| 687 | border: 2px solid rgba(52,211,153,0.4); | |
| 688 | display: flex; | |
| 689 | align-items: center; | |
| 690 | justify-content: center; | |
| 691 | font-size: 24px; | |
| 692 | color: var(--green); | |
| 693 | margin: 0 auto; | |
| 694 | } | |
| 695 | .ent-submitted h3 { | |
| 696 | font-size: 22px; | |
| 697 | font-weight: 600; | |
| 698 | color: var(--text-strong); | |
| 699 | margin: 0; | |
| 700 | } | |
| 701 | .ent-submitted p { | |
| 702 | color: var(--text-muted); | |
| 703 | font-size: var(--t-sm); | |
| 704 | max-width: 400px; | |
| 705 | margin: 0; | |
| 706 | line-height: 1.6; | |
| 707 | } | |
| 708 | .ent-submitted a { color: var(--accent); } | |
| 709 | `; | |
| 710 | ||
| 711 | export default enterprise; |