/*
  Gabriel Airlines — base styles
  Reset, global element defaults and the small set of utility/component
  classes shared by every page (buttons, glass panels, form fields, alerts).
  Depends on assets/css/tokens.css being loaded first.
*/

* {
  box-sizing: border-box;
}

html {
  color-scheme: dark;
  scroll-behavior: smooth;
  overflow-x: hidden;
}

body {
  margin: 0;
  padding: 0;
  min-height: 100vh;
  overflow-x: hidden;
  font-family: var(--font-body);
  font-size: 1.05rem;
  color: var(--text-primary);
  background: var(--bg-void);
  position: relative;
  isolation: isolate;
}

/* ---------- premium background: mesh gradient + aurora + noise ---------- */
/* Three layers, all fixed so they never repaint on scroll: a slow drifting
   mesh gradient, a softer aurora wash, and a barely-there noise texture
   that keeps large flat dark areas from looking like a flat PNG. */

body::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -3;
  background:
    radial-gradient(ellipse 900px 600px at 15% -10%, var(--mesh-2), transparent 60%),
    radial-gradient(ellipse 900px 700px at 100% 0%, var(--mesh-1), transparent 55%),
    radial-gradient(ellipse 800px 600px at 50% 110%, var(--mesh-3), transparent 60%);
  background-repeat: no-repeat;
  animation: mesh-drift 26s var(--ease-standard) infinite alternate;
}

body::after {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -2;
  opacity: 0.5;
  mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='120' height='120'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/><feColorMatrix type='matrix' values='0 0 0 0 1  0 0 0 0 1  0 0 0 0 1  0 0 0 0.02 0'/></filter><rect width='100%25' height='100%25' filter='url(%23n)'/></svg>");
  background-size: 160px 160px;
}

@keyframes mesh-drift {
  from { transform: translate3d(0, 0, 0) scale(1); }
  to { transform: translate3d(-2%, 2%, 0) scale(1.06); }
}

@media (prefers-reduced-motion: reduce) {
  body::before {
    animation: none;
  }
}

h1, h2, h3 {
  font-family: var(--font-display);
  font-weight: 700;
  letter-spacing: -0.02em;
  margin: 0;
}

a {
  color: inherit;
}

.container {
  display: flex;
  flex-direction: column;
  align-items: center;
  min-height: 100vh;
}

/* ---------- utilities ---------- */

.hide {
  display: none !important;
}

.show-block {
  display: block !important;
}

.showflex {
  display: flex !important;
}

.fade {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  /* Needs to be dark enough to fully swallow whatever's behind it - a
     bright ambient glow (e.g. the Frota page's always-on .fleet-glow) was
     still visibly bleeding through at 0.72/blur(6px) in the gap around an
     open modal, so this went darker and blurrier. */
  background-color: rgba(3, 5, 10, 0.92);
  backdrop-filter: blur(14px);
  z-index: 10;
}

/* ---------- glass panel ---------- */

.glass-panel {
  position: relative;
  background: var(--glass-bg);
  border: 1px solid var(--glass-border);
  border-radius: var(--radius-xl);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  /* the inset highlight is what makes glass read as glass instead of just
     "blurry translucent grey" - an inset shadow (not a pseudo-element) so
     it never collides with .tilt-card/.tilt-ring, which need ::before/::after
     for their own effects on the same element */
  box-shadow: var(--shadow-panel), inset 0 1px 0 rgba(255, 255, 255, 0.14);
}

/* ---------- buttons ---------- */
/* --tx/--ty/--scale are driven by shared/js/motion.js (magnetic pull +
   press feedback); CSS only ever touches box-shadow/background on :hover
   so the two never fight over the `transform` property. */

.btn-primary,
.btn-ghost {
  --tx: 0px;
  --ty: 0px;
  --scale: 1;
  position: relative;
  overflow: hidden;
  isolation: isolate;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 1rem;
  letter-spacing: -0.01em;
  border-radius: var(--radius-pill);
  border: none;
  outline: none;
  cursor: pointer;
  padding: 14px 32px;
  transform: translate(var(--tx), var(--ty)) scale(var(--scale));
  transition: transform 0.2s var(--ease-premium),
    box-shadow var(--duration-base) var(--ease-standard),
    opacity var(--duration-fast) var(--ease-standard),
    background var(--duration-base) var(--ease-standard);
}

.btn-primary {
  color: #04121a;
  background: var(--accent-gradient-wide);
  background-size: 220% 220%;
  background-position: 0% 50%;
  box-shadow: 0 8px 24px var(--accent-glow);
  animation: btn-gradient-flow 7s ease infinite, btn-glow-pulse 3.5s ease-in-out infinite;
}

@keyframes btn-gradient-flow {
  0%, 100% { background-position: 0% 50%; }
  50% { background-position: 100% 50%; }
}

@keyframes btn-glow-pulse {
  0%, 100% { box-shadow: 0 8px 24px var(--accent-glow); }
  50% { box-shadow: 0 8px 34px rgba(34, 211, 238, 0.55); }
}

.btn-primary:hover {
  box-shadow: 0 14px 38px rgba(34, 211, 238, 0.5);
}

.btn-primary:disabled {
  cursor: not-allowed;
  opacity: 0.4;
  box-shadow: none;
  animation: none;
}

.btn-ghost {
  color: var(--text-primary);
  background: var(--glass-bg-strong);
  border: 1px solid var(--glass-border);
}

.btn-ghost:hover {
  background: rgba(255, 255, 255, 0.14);
  border-color: var(--glass-border-bright);
}

/* ripple - shared/js/motion.js adds .has-ripple to any clickable element
   it wires up, then injects a .ripple span at the click point on click */
.has-ripple {
  position: relative;
  overflow: hidden;
}

.has-ripple .ripple {
  position: absolute;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.45);
  transform: scale(0);
  animation: ripple-out 0.6s var(--ease-standard);
  pointer-events: none;
}

@keyframes ripple-out {
  to {
    transform: scale(3);
    opacity: 0;
  }
}

@media (prefers-reduced-motion: reduce) {
  .btn-primary {
    animation: none;
  }
}

/* ---------- form fields ---------- */

.field {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.field label {
  font-size: 0.85rem;
  color: var(--text-secondary);
  letter-spacing: 0.02em;
}

input,
select,
textarea {
  font-family: var(--font-body);
  color: var(--text-primary);
  background: var(--glass-bg-strong);
  border: 1px solid var(--glass-border);
  border-radius: var(--radius-md);
  padding: 12px 16px;
  font-size: 1rem;
  outline: none;
  transition: border-color var(--duration-fast) var(--ease-standard),
    box-shadow var(--duration-fast) var(--ease-standard);
}

input::placeholder,
textarea::placeholder {
  color: var(--text-muted);
}

input:focus,
select:focus,
textarea:focus {
  border-color: var(--accent-cyan);
  box-shadow: 0 0 0 3px rgba(34, 211, 238, 0.18);
}

select option {
  background: var(--bg-elevated);
  color: var(--text-primary);
}

input.has-error,
select.has-error {
  border-color: var(--danger);
  box-shadow: 0 0 0 3px rgba(255, 84, 112, 0.15);
}

/* ---------- alerts ---------- */

.alert-span {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  font-size: 0.9rem;
  color: var(--danger);
  text-align: center;
  margin-bottom: var(--space-3);
}

.alert-span::before {
  content: "\f071";
  font-family: "Font Awesome 6 Free";
  font-weight: 900;
}

/* ---------- word-by-word heading reveal ---------- */
/* shared/js/motion.js's initHeroWordReveal() wraps each word in these two
   spans - the outer clips overflow, the inner is what actually animates
   (translateY), which is what gives the "sliding up from behind a mask"
   look instead of a plain fade. */

.word-reveal-heading .word {
  display: inline-block;
  overflow: hidden;
  vertical-align: top;
  padding-bottom: 0.15em;
  margin-bottom: -0.15em;
}

.word-reveal-heading .word-inner {
  display: inline-block;
}

::selection {
  background: var(--accent-cyan);
  color: #04121a;
}

::-webkit-scrollbar {
  width: 10px;
}

::-webkit-scrollbar-track {
  background: transparent;
}

::-webkit-scrollbar-thumb {
  background: rgba(255, 255, 255, 0.15);
  border-radius: var(--radius-pill);
}
