/* ============================================================
   VARIABLES
   ============================================================ */
:root {
  --sans: "Helvetica Neue", "Helvetica", "Arial", system-ui, sans-serif;
  --mono: "SFMono-Regular", "SF Mono", Menlo, Consolas, monospace;

  --cream:       #00102b;
  --cream-2:     #00102b;
  --ink:         #f5f2ec;
  --muted:       #9d9590;
  --hair:        rgba(245,242,236,0.12);
  --hair-2:      rgba(245,242,236,0.20);
  --accent:      #4a8fff;
  --accent-soft: rgba(74,143,255,0.18);
}

body.light-mode {
  --cream:       #f5f2ec;
  --cream-2:     #f5f2ec;
  --ink:         #2f2a25;
  --muted:       #837b70;
  --hair:        rgba(47,42,37,0.12);
  --hair-2:      rgba(47,42,37,0.20);
  --accent:      #2f6ed0;
  --accent-soft: rgba(47,110,208,0.18);
}

/* ============================================================
   RESET
   ============================================================ */
* { margin: 0; padding: 0; box-sizing: border-box; -webkit-tap-highlight-color: transparent; }
html { scroll-behavior: smooth; }
/* Form controls don't inherit page font by default in any browser —
   without this, Windows/Linux Chrome and Firefox render buttons in
   Segoe UI / sans-serif instead of the site's Helvetica Neue stack. */
button, input, select, textarea { font: inherit; color: inherit; }
button { background: none; border: none; }
body {
  font-family: var(--sans);
  background: var(--cream);
  color: var(--ink);
  -webkit-font-smoothing: antialiased;
  animation: pageFadeIn 0.45s ease-out both;
}

@keyframes pageFadeIn {
  from { opacity: 0; }
  to   { opacity: 1; }
}

/* ============================================================
   IMAGE LOAD FADE-IN
   components.js tags any <img> that isn't already loaded/cached with
   .img-fade before it finishes loading, then adds .is-loaded once it has
   (load or error). Only images actually still loading get the class, so
   there's never a flash of hidden content — and with loading="lazy" now
   on most images site-wide, this turns the scattered pop-in as each one
   finishes downloading into a uniform, staggered fade instead.
   ============================================================ */
img.img-fade { opacity: 0; transition: opacity 0.45s ease; }
img.img-fade.is-loaded { opacity: 1; }
@media (prefers-reduced-motion: reduce) {
  img.img-fade { opacity: 1; transition: none; }
}

/* ============================================================
   TEXT SELECTION — inverted (background/text swap)
   ============================================================ */
::selection { background: var(--ink); color: var(--cream); }
::-moz-selection { background: var(--ink); color: var(--cream); }

/* ============================================================
   PARTICLE CANVAS
   ============================================================ */
#particles-global {
  position: fixed;
  top: 0; left: 0;
  width: 100%; height: 100%;
  pointer-events: none;
  /* Negative, not 0: a *positioned* element at z-index:0 still paints
     above any plain, non-positioned content (like a bare <div> image
     frame), regardless of DOM order — that's what let particles render
     on top of case-study images instead of behind them. Negative keeps
     this strictly a backdrop layer under everything, always. */
  z-index: -1;
  transition: opacity 0.4s ease;
}

/* ============================================================
   BRAND MARKS — orbit "c" and orbit "dot"
   ============================================================ */
@keyframes orbSpin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }

.oc { position: relative; display: inline-block; width: 0.62em; height: 0.62em; }
.oc svg { width: 100%; height: 100%; overflow: visible; display: block; }
.oc__arc   { fill: none; stroke: currentColor; stroke-width: 13; stroke-linecap: round; }
.oc__ghost { fill: none; stroke: var(--accent); stroke-width: 2.5; stroke-linecap: round; opacity: 0.3; stroke-dasharray: 2 7; }
.oc__e     { position: absolute; inset: 0; display: block; animation: orbSpin 3.6s linear infinite; }
.oc__e circle { fill: var(--accent); }

.od { position: relative; display: inline-block; width: 0.34em; height: 0.34em; margin-left: 0.05em; }
.od svg { width: 100%; height: 100%; overflow: visible; display: block; }
.od__ring { fill: none; stroke: var(--accent); stroke-width: 7; opacity: 0.5; }
.od__e    { position: absolute; inset: 0; display: block; animation: orbSpin 3.6s linear infinite; }
.od__e circle { fill: var(--accent); }

.mark {
  display: inline-flex; align-items: flex-end; line-height: 1;
  font-weight: 600; letter-spacing: -0.02em; color: var(--ink);
  font-size: 36px; text-decoration: none;
}
.mark .oc { margin-left: 0.015em; margin-bottom: 0.01em; }

/* ============================================================
   SITE HEADER (inner pages)
   ============================================================ */
.site-header {
  position: relative; z-index: 2;
  padding: 34px 44px;
  display: flex; justify-content: space-between; align-items: center;
}

/* ============================================================
   NAV CONTACT (top-right corner, shared by home + inner pages)
   ============================================================ */
.nav-contact { display: flex; flex-direction: column; align-items: flex-end; gap: 2px; }
.nav-contact__email,
.nav-contact__phone {
  font-size: 16px; color: var(--ink); text-decoration: none; transition: color 0.2s;
}
@media (hover: hover) {
  .nav-contact__email:hover,
  .nav-contact__phone:hover { color: var(--accent); }
}

@media (max-width: 768px) {
  .site-header { padding: 24px 28px; }
  .nav-contact__email,
  .nav-contact__phone { font-size: 15px; }
}

/* ============================================================
   LANGUAGE SELECT (Google Translate, custom-styled)
   The real Google widget renders into #google_translate_element, kept
   hidden — this <select> is our own, driven by JS to trigger it. See
   assets/js/components.js for the wiring.
   ============================================================ */
.nav-lang {
  margin-top: 6px;
  /* Stretch to the column's full width and right-align the select inside
     it via flexbox, rather than relying on the select's own shrink-to-fit
     width lining up with align-items:flex-end on .nav-contact — mobile
     browsers render native <select> intrinsic width differently (extra
     reserved space for the dropdown affordance) which threw off the
     right edge there even though desktop matched. This ties the select's
     right edge to the column's right edge directly, independent of
     whatever width the select renders at on a given device. */
  align-self: stretch;
  display: flex;
  justify-content: flex-end;
}
.nav-lang__select {
  /* Frame always shown in the "active" (hover/focus) look, per request —
     a resting state that reads as plain muted text would blend into the
     phone/email links above it and go unnoticed as an interactive control.
     No fill though: the site background should show through, only the
     border is highlighted. */
  appearance: none; -webkit-appearance: none;
  background: transparent;
  border: 1px solid var(--accent);
  border-radius: 100px;
  color: var(--ink);
  font-family: inherit; font-size: 12px; letter-spacing: 0.06em;
  /* Browsers size a <select> to fit its longest option, not just whichever
     one happens to be selected — so with left-aligned text, picking a
     short name like "Italian" left a big gap before the chevron and never
     reached the phone/email's right edge above it. Right-aligning the text
     and moving the chevron to the left side instead means the text's right
     edge always sits at this same fixed distance from the pill's right
     border, however long the selected name is — and since that border is
     itself right-edge-aligned with the phone/email above (same flex-end
     column), the two now visually line up regardless of selection. */
  text-align: right;
  padding: 4px 12px 4px 22px;
  max-width: 130px;
  cursor: pointer;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'%3E%3Cpath d='M1 1l4 4 4-4' fill='none' stroke='%234a8fff' stroke-width='1.4' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: left 9px center;
}
.nav-lang__select:focus { outline: none; }
.nav-lang__select option { font-weight: 400; color: var(--ink); background: var(--cream); }

/* The real Google widget must stay genuinely laid out (not display:none)
   or it never finishes rendering its internal <select class="goog-te-combo">
   that we drive — display:none was silently breaking translation entirely.
   Pushed off-screen instead, which keeps layout/rendering intact. */
.gt-offscreen { position: absolute; top: -9999px; left: -9999px; }

/* Google Translate cleanup: hide everything Google injects except the
   actual page-text substitution — the top "this page has been translated"
   bar is a cross-origin iframe we cannot restyle, so it's removed rather
   than themed, and the body offset it would otherwise reserve is reset. */
.goog-te-banner-frame,
.goog-te-gadget-icon,
#goog-gt-tt, .goog-tooltip,
.goog-tooltip:hover,
.goog-text-highlight { display: none !important; background: none !important; box-shadow: none !important; }
body { top: 0px !important; }
.goog-te-gadget { height: 0; overflow: hidden; }

/* ============================================================
   BACKGROUND MUSIC TOGGLE
   ============================================================ */
#music-toggle {
  position: fixed; right: 24px; bottom: 24px; z-index: 200;
  width: 40px; height: 40px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  background: rgba(0,16,43,0.72);
  border: 1.5px solid var(--accent);
  cursor: pointer;
  -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px);
  transition: background 0.2s ease, transform 0.15s ease;
}
#music-toggle:active { transform: scale(0.93); }
@media (hover: hover) {
  #music-toggle:hover { background: rgba(74,143,255,0.22); }
}
#music-toggle .bars { display: flex; align-items: flex-end; gap: 2.5px; height: 13px; }
#music-toggle .bars span {
  display: block; width: 2.5px; background: var(--accent); border-radius: 2px;
  height: 5px; transition: height 0.2s ease;
}
#music-toggle.is-playing .bars span { animation: musicBar 2.6s ease-in-out infinite; }
#music-toggle .bars span:nth-child(1) { animation-delay: 0s; }
#music-toggle .bars span:nth-child(2) { animation-delay: 0.4s; }
#music-toggle .bars span:nth-child(3) { animation-delay: 0.8s; }
#music-toggle .bars span:nth-child(4) { animation-delay: 1.2s; }
@keyframes musicBar {
  0%, 100% { height: 5px; }
  50% { height: 13px; }
}
@media (max-width: 640px) {
  #music-toggle { right: 16px; bottom: 16px; width: 36px; height: 36px; }
}
