/* ============================================================================
   OBSIDIAN DESIGN LANGUAGE v2 — POLISH + ARRIVAL LAYER   (ledger row 119)
   Additive and opt-in. Load AFTER obsidian-design-language.css (v1) or any
   product CSS. Nothing here applies unless the root carries `.odl2`, so adding
   the file alone changes nothing on any product (zero-risk staging).

   Brand is unchanged: obsidian #08070A, gold #F1B43E, cream #F4E9D7, no green.
   What v2 adds is precision: tighter display tracking, a finer elevation ramp,
   a real "material" (gradient rim, inner top-light, grain), named motion
   curves, complete microstates, and the shared ARRIVAL choreography for the
   first 3 seconds of every surface.

   Performance contract: CSS-only, no fonts or images added, animates only
   transform / opacity / filter / background-position, all keyframes finish
   by 1.4s, prefers-reduced-motion gets a designed static path.
   ============================================================================ */

.odl2 {
  /* ---- type: tightened scale + tracking (display gets tighter as it grows) */
  --o2-fs-hero: clamp(2.625rem, 1.3rem + 5.6vw, 5.5rem);
  --o2-fs-h1:   clamp(2rem, 1.4rem + 2.6vw, 3.25rem);
  --o2-fs-h2:   clamp(1.5rem, 1.2rem + 1.3vw, 2.125rem);
  --o2-fs-h3:   1.25rem;
  --o2-fs-body: 1rem;
  --o2-fs-sm:   .875rem;
  --o2-fs-xs:   .75rem;
  --o2-track-hero: -.04em;
  --o2-track-h:    -.022em;
  --o2-track-body: -.006em;
  --o2-track-eyebrow: .16em;

  /* ---- spacing rhythm: 4px base, section rhythm on an 8-step ramp -------- */
  --o2-section: clamp(72px, 9vw, 136px);
  --o2-gutter:  clamp(16px, 4vw, 32px);
  --o2-maxw:    1200px;

  /* ---- radii: one family, nested radii = outer - padding ----------------- */
  --o2-r-xs: 6px; --o2-r-sm: 10px; --o2-r-md: 14px; --o2-r-lg: 20px; --o2-r-xl: 28px;

  /* ---- surfaces / materials ---------------------------------------------- */
  --o2-bg:        #08070A;
  --o2-surface:   #0F0D12;
  --o2-surface-2: #15121A;
  --o2-rim:       rgba(244,233,215,.08);   /* neutral hairline, gold reserved */
  --o2-rim-hi:    rgba(244,233,215,.14);
  --o2-rim-gold:  rgba(241,180,62,.32);
  --o2-toplight:  inset 0 1px 0 rgba(255,240,210,.06);

  /* ---- elevation: 4-step, two-layer (contact + ambient), dark-tuned ------ */
  --o2-e0: 0 0 0 1px var(--o2-rim);
  --o2-e1: 0 0 0 1px var(--o2-rim), 0 1px 2px rgba(0,0,0,.6), 0 2px 8px -2px rgba(0,0,0,.5);
  --o2-e2: 0 0 0 1px var(--o2-rim), 0 2px 4px rgba(0,0,0,.5), 0 12px 32px -8px rgba(0,0,0,.6);
  --o2-e3: 0 0 0 1px var(--o2-rim-hi), 0 4px 8px rgba(0,0,0,.5), 0 28px 64px -16px rgba(0,0,0,.75), 0 18px 48px -12px rgba(241,180,62,.10);

  /* ---- focus ------------------------------------------------------------- */
  --o2-focus: 0 0 0 2px var(--o2-bg), 0 0 0 4px rgba(241,180,62,.85);

  /* ---- motion: named curves + frequency buckets -------------------------- */
  --o2-ease:   cubic-bezier(.25,.74,.22,.99); /* THE curve (awards benchmark) */
  --o2-out:    var(--o2-ease);
  --o2-std:    var(--o2-ease);
  --o2-in:     var(--o2-ease);
  --o2-t-micro: 140ms;   /* hover / press / focus */
  --o2-t-ui:    240ms;   /* panels, tabs */
  --o2-t-arrive: 900ms;  /* first-3-seconds only */

  font-feature-settings: "ss01", "cv01", "cv11";
  text-rendering: optimizeLegibility;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

/* ---- typography polish --------------------------------------------------- */
.odl2 h1, .odl2 h2, .odl2 h3, .odl2 .o2-h { text-wrap: balance; letter-spacing: var(--o2-track-h); }
.odl2 p, .odl2 li { text-wrap: pretty; }
.odl2 .o2-hero-title { font-size: var(--o2-fs-hero); letter-spacing: var(--o2-track-hero); line-height: 1.02; }
.odl2 .o2-eyebrow { font-size: var(--o2-fs-xs); letter-spacing: var(--o2-track-eyebrow); text-transform: uppercase; font-weight: 600; color: var(--od-gold, #F1B43E); }
.odl2 .o2-lede { font-size: clamp(1.0625rem, 1rem + .4vw, 1.25rem); line-height: 1.55; color: var(--od-cream-dim, #C6BCA9); max-width: 60ch; }
.odl2 .o2-num, .odl2 [data-num] { font-variant-numeric: tabular-nums slashed-zero; }
.odl2 ::selection { background: rgba(241,180,62,.28); color: #fff; }

/* ---- layout -------------------------------------------------------------- */
.odl2 .o2-container { width: 100%; max-width: var(--o2-maxw); margin-inline: auto; padding-inline: var(--o2-gutter); }
.odl2 .o2-section { padding-block: var(--o2-section); }

/* ---- MATERIAL: obsidian glass card --------------------------------------- */
/* Gradient rim via mask (light catches the top edge), inner top-light, faint
   grain. One material for every card in the ecosystem.                      */
.odl2 .o2-card {
  position: relative; isolation: isolate;
  background: linear-gradient(180deg, var(--o2-surface-2), var(--o2-surface));
  border-radius: var(--o2-r-lg);
  box-shadow: var(--o2-e2), var(--o2-toplight), inset 0 0 0 1px rgba(241,180,62,.10);
}
.odl2 .o2-card::before {               /* gradient rim, brighter at the top */
  content: ""; position: absolute; inset: 0; border-radius: inherit; padding: 1px; z-index: -1;
  background: linear-gradient(180deg, rgba(244,233,215,.16), rgba(244,233,215,.04) 40%, rgba(241,180,62,.10));
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor; mask-composite: exclude;
  pointer-events: none;
}
/* pointer spotlight (optional, driven by --mx/--my from odl-arrival.js) */
.odl2 .o2-card[data-o2-spot]::after {
  content: ""; position: absolute; inset: 0; border-radius: inherit; pointer-events: none;
  background: radial-gradient(420px circle at var(--mx, 50%) var(--my, -20%), rgba(241,180,62,.07), transparent 60%);
  opacity: 0; transition: opacity var(--o2-t-ui) var(--o2-std);
}
.odl2 .o2-card[data-o2-spot]:hover::after { opacity: 1; }

/* ---- tactile microstates (every interactive element) --------------------- */
.odl2 a, .odl2 button, .odl2 [role="button"], .odl2 .o2-press {
  -webkit-tap-highlight-color: transparent;
}
.odl2 .o2-press, .odl2 .od-btn, .odl2 .o2-btn {
  transition: transform var(--o2-t-micro) var(--o2-std), background-color var(--o2-t-micro) var(--o2-std),
              border-color var(--o2-t-micro) var(--o2-std), color var(--o2-t-micro) var(--o2-std),
              filter var(--o2-t-micro) var(--o2-std);
}
.odl2 .o2-press:active, .odl2 .od-btn:active, .odl2 .o2-btn:active { transform: scale(.975); transition-duration: 60ms; }
.odl2 :focus-visible { outline: none; box-shadow: var(--o2-focus); border-radius: var(--o2-r-sm); }
.odl2 [disabled], .odl2 [aria-disabled="true"] { opacity: .45; cursor: not-allowed; }
.odl2 .o2-lift { transition: transform var(--o2-t-ui) var(--o2-out), box-shadow var(--o2-t-ui) var(--o2-out); }
@media (hover: hover) {
  .odl2 .o2-lift:hover { box-shadow: var(--o2-e3), var(--o2-toplight), inset 0 0 0 1px rgba(241,180,62,.22); }
}

/* FLAT GOLD, v2.1 -- ECOSYSTEM RULING 2026-10-10 (row 119). Supersedes the "gold leaf".
   The previous treatment was a vertical gradient fill plus a halo glow on a full pill. That
   compound is the most dated convention in SaaS UI: it reads as decoration applied to a button
   rather than a button that was designed, and it is the opposite of the "pristine" Foundable bar.
   The rule it broke: when a polish pass makes an element look MORE styled and LESS considered,
   the pass is wrong, not the element.
   GONE: the 180deg gradient, the 24px gold halo, and the white/brown bevel insets.
   KEPT: flat --od-gold, ink text, and a 1px contact shadow so it seats on obsidian rather than
   floating. Hover is colour-only (awards benchmark item 13).
   PILL KEPT DELIBERATELY: the Foundable teardown records pill buttons and 3-4 radii as part of
   what makes it pristine, so the radius was never the defect -- the gradient and the halo were.
   Flagged for Andrew; one line reverts it to a 10px rectangle if he wants the live shape back. */
.odl2 .o2-btn--gold {
  display: inline-flex; align-items: center; gap: 8px; height: 44px; padding: 0 20px;
  border: 0; border-radius: 999px; color: #1A1206; font-weight: 650; letter-spacing: -.005em;
  background: var(--od-gold, #F1B43E);
  box-shadow: 0 1px 2px rgba(0,0,0,.5);
  position: relative;
}
.odl2 .o2-btn--gold:hover { background: #F6C359; }
.odl2 .o2-btn--ghost {
  display: inline-flex; align-items: center; gap: 8px; height: 44px; padding: 0 18px; border-radius: 999px;
  background: rgba(244,233,215,.03); color: var(--od-cream, #F4E9D7);
  box-shadow: inset 0 0 0 1px var(--o2-rim-hi);
}
.odl2 .o2-btn--ghost:hover { background: rgba(244,233,215,.06); box-shadow: inset 0 0 0 1px var(--o2-rim-gold); }

/* ---- loading + empty states ---------------------------------------------- */
.odl2 .o2-skeleton {
  border-radius: var(--o2-r-sm);
  background: linear-gradient(90deg, rgba(244,233,215,.04) 0%, rgba(244,233,215,.08) 40%, rgba(244,233,215,.04) 80%) 0 0 / 200% 100%;
  animation: o2-shimmer 1.6s linear infinite;
}
@keyframes o2-shimmer { to { background-position: -200% 0; } }
.odl2 .o2-empty { display: grid; place-items: center; gap: 10px; padding: 48px 24px; text-align: center; color: var(--od-muted, #8B8397); border-radius: var(--o2-r-lg); box-shadow: inset 0 0 0 1px var(--o2-rim); }

/* ============================================================================
   ARRIVAL — the shared first-3-seconds choreography
   Markup: put data-o2-arrive on the hero container; children marked
   data-o2-a="1..6" rise in sequence. .o2-sweep on ONE gold element per view
   gets a single light pass. .o2-stage on the product shot tilts in.
   Timeline (ms):  80 eyebrow | 160 title | 260 lede |
                   360 actions | 420 product stage tilts in | 900 gold sweep |
                   ~1400 everything at rest. Nothing loops except the v1 ember.
   ============================================================================ */
@keyframes o2-rise   { from { opacity: 0; transform: translate3d(0,14px,0); filter: blur(6px); } to { opacity: 1; transform: none; filter: blur(0); } }
@keyframes o2-stage  { from { opacity: 0; transform: perspective(1400px) rotateX(9deg) translate3d(0,28px,0) scale(.975); } to { opacity: 1; transform: perspective(1400px) rotateX(0) translate3d(0,0,0) scale(1); } }
@keyframes o2-sweep  { from { background-position: 160% 0; } to { background-position: -60% 0; } }
@keyframes o2-dawn   { from { opacity: 0; } to { opacity: 1; } }

.odl2 [data-o2-arrive] [data-o2-a] { animation: o2-rise var(--o2-t-arrive) var(--o2-out) both; }
/* LCP-safe: the headline / largest element is NEVER opacity 0. It is painted
   on frame 1 and only settles (8px rise + blur clear) so LCP is unaffected.
   Learned from foundable.com: content never waits on animation.            */
@keyframes o2-settle { from { transform: translate3d(0,8px,0); filter: blur(3px); } to { transform: none; filter: blur(0); } }
.odl2 [data-o2-arrive] [data-o2-a="lcp"] { animation: o2-settle 700ms var(--o2-out) both; }
.odl2 [data-o2-arrive] [data-o2-a="1"] { animation-delay: 80ms; }
.odl2 [data-o2-arrive] [data-o2-a="2"] { animation-delay: 160ms; }
.odl2 [data-o2-arrive] [data-o2-a="3"] { animation-delay: 260ms; }
.odl2 [data-o2-arrive] [data-o2-a="4"] { animation-delay: 360ms; }
.odl2 [data-o2-arrive] [data-o2-a="5"] { animation-delay: 440ms; }
.odl2 [data-o2-arrive] [data-o2-a="6"] { animation-delay: 520ms; }
.odl2 [data-o2-arrive] .o2-stage { animation: o2-stage 1100ms var(--o2-out) 420ms both; transform-origin: 50% 0; will-change: transform, opacity; }
.odl2 [data-o2-arrive] { position: relative; }
.odl2 [data-o2-arrive] > * { position: relative; z-index: 1; }

/* the light sweep: a single specular pass across ONE gold element */
.odl2 .o2-sweep { position: relative; overflow: hidden; }
.odl2 .o2-sweep::after {
  content: ""; position: absolute; inset: 0; pointer-events: none; border-radius: inherit;
  background: linear-gradient(105deg, transparent 35%, rgba(255,250,235,.55) 50%, transparent 65%) 0 0 / 250% 100% no-repeat;
  mix-blend-mode: soft-light;
  animation: o2-sweep 1100ms var(--o2-out) 900ms both;
}
/* text variant (gold wordmark / hero em): gradient text gets the pass */
.odl2 .o2-sweep-text {
  background: linear-gradient(105deg, #C99A2C 0%, #F1B43E 30%, #FFF1C8 50%, #F1B43E 70%, #C99A2C 100%) 0 0 / 250% 100%;
  -webkit-background-clip: text; background-clip: text; color: transparent;
  animation: o2-sweep 1400ms var(--o2-out) 800ms both;
}

/* in-app arrival (apps/hub, where there is no hero): panels settle in */
.odl2 [data-o2-arrive="app"] [data-o2-a] { animation-duration: 600ms; }

/* ---- reduced motion: designed static path, feedback preserved ------------- */
@media (prefers-reduced-motion: reduce) {
  .odl2 [data-o2-arrive] [data-o2-a],
  .odl2 [data-o2-arrive] .o2-stage { animation: o2-dawn 200ms linear both; transform: none; filter: none; }
  .odl2 .o2-sweep::after { display: none; }
  .odl2 .o2-sweep-text { animation: none; background-position: 50% 0; }
  .odl2 .o2-skeleton { animation: none; }
}

/* ---- phone: same system, tighter rhythm, no hover-dependent affordances --- */
@media (max-width: 640px) {
  .odl2 .o2-card { border-radius: var(--o2-r-md); }
  .odl2 [data-o2-arrive] .o2-stage { animation-duration: 800ms; }
  .odl2 .o2-btn--gold, .odl2 .o2-btn--ghost { height: 48px; }   /* 48px touch target */
}

/* ============================================================================
   UNIFICATION (audit 2026-10-09): one gold, one stack, one radius scale,
   44px targets. These map the legacy variants onto the v2 decisions so a
   product only has to add `.odl2` to its root.
   ============================================================================ */
.odl2 {
  /* ONE font stack per role (brand already chose these in v1) */
  --o2-font-display: "Fraunces", ui-serif, Georgia, serif;
  --o2-font-body: "Hanken Grotesk", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --o2-font-mono: "IBM Plex Mono", ui-monospace, "SFMono-Regular", Menlo, monospace;
  /* ONE radius scale: 6 control-inner, 10 control, 14 card, 20 panel, pill */
  --o2-r-xs: 6px; --o2-r-sm: 10px; --o2-r-md: 14px; --o2-r-lg: 20px;
  font-family: var(--o2-font-body);
}
.odl2 h1, .odl2 h2, .odl2 .o2-display { font-family: var(--o2-font-display); font-weight: 450; font-optical-sizing: auto; }
/* ONE gold button: every legacy gold variant resolves to the v2.1 FLAT gold (see the ruling at
   `.o2-btn--gold` above). This is the selector that captures each product's own legacy class,
   so flattening here is what sweeps the treatment across every surface that loads this file. */
.odl2 .od-btn--gold, .odl2 .o2-btn--gold, .odl2 [data-o2-gold] {
  min-height: 44px; border: 0; border-radius: 999px; color: #1A1206; font-weight: 650;
  background: var(--od-gold, #F1B43E);
  box-shadow: 0 1px 2px rgba(0,0,0,.5);
}
.odl2 .od-btn--gold:hover, .odl2 [data-o2-gold]:hover { background: #F6C359; }
/* 44px minimum tap target on coarse pointers, without changing the visual size */
@media (pointer: coarse) {
  .odl2 a, .odl2 button, .odl2 [role="button"], .odl2 input[type="checkbox"], .odl2 input[type="radio"], .odl2 select, .odl2 summary {
    min-height: 44px; min-width: 44px;
  }
  .odl2 .o2-inline-link { min-height: 0; min-width: 0; padding-block: 12px; margin-block: -12px; } /* inline text links grow their hit area, not their box */
}
/* ONE sign-in gate pattern for every product wall */
.odl2 .o2-gate { min-height: 100dvh; display: grid; place-items: center; padding: var(--o2-gutter); padding-bottom: max(var(--o2-gutter), env(safe-area-inset-bottom)); }
.odl2 .o2-gate__card { width: min(420px, 100%); padding: 36px 32px 28px; display: grid; gap: 18px; }
.odl2 .o2-gate__mark { height: 28px; width: auto; margin-inline: auto; }
.odl2 .o2-gate__title { font-family: var(--o2-font-display); font-size: 1.75rem; letter-spacing: -.02em; line-height: 1.1; text-align: center; margin: 0; }
.odl2 .o2-gate__sub { text-align: center; color: var(--od-cream-dim, #C6BCA9); font-size: var(--o2-fs-sm); margin: -8px 0 4px; }
.odl2 .o2-gate__legal { text-align: center; font-size: var(--o2-fs-xs); color: #8B8397; }
.odl2 .o2-field { width: 100%; min-height: 44px; padding: 0 14px; border-radius: var(--o2-r-sm); border: 0;
  background: rgba(0,0,0,.35); color: var(--od-cream, #F4E9D7); font: inherit;
  box-shadow: inset 0 0 0 1px var(--o2-rim-hi); transition: box-shadow var(--o2-t-micro) var(--o2-std); }
.odl2 .o2-field:focus { outline: none; box-shadow: inset 0 0 0 1px rgba(241,180,62,.7), 0 0 0 4px rgba(241,180,62,.14); }
/* button-links never underline; page field never seams below the fold */
.odl2 a.o2-btn--gold, .odl2 a.o2-btn--ghost, .odl2 a.od-btn, .odl2 a.o2-press { text-decoration: none; }
html:has(> body.odl2) { background: #08070A; }
.odl2.odl { background-attachment: fixed; }

/* ---- (1) arrival curtain, from the awards benchmark ------------------------
   An obsidian layer BEHIND the content retracts bottom-up (scaleY, transform
   only) while the headline settles. Content sits above it, so text and LCP
   are painted on frame 1 (paint first, flourish after). Done by 1.2 s.     */
@keyframes o2-curtain { from { transform: scaleY(1); } to { transform: scaleY(0); } }
.odl2 [data-o2-arrive]:not([data-o2-arrive="app"])::after {
  content: ""; position: absolute; inset: 0; z-index: 0; pointer-events: none;
  background: var(--o2-bg); transform-origin: 50% 0;
  animation: o2-curtain 1200ms var(--o2-ease) 60ms both;
}
@media (prefers-reduced-motion: reduce) {
  .odl2 [data-o2-arrive]::after { animation: none; display: none; }
}
