/* oddly titan primitives. Shared visual-system layer (2026-06-15).
 *
 * The single source of truth for the "titan-grade" primitives that every
 * oddly surface consumes: the gold-O wordmark, one button system, and the
 * full-bleed section primitives. CC3 owns this file (marketing site); CC4
 * links it from the dashboard, embedded /app, and the shared component bar
 * so the surfaces share ONE wordmark and ONE button system instead of each
 * reinventing them. See briefs/visual-direction-titan-grade-2026-06-15.md.
 *
 * Built on the locked 52.0a tokens (/_shared/oddly-tokens.css), which every
 * surface already loads, so this file is portable: it declares no palette of
 * its own, only consumes --oddly-* with safe fallbacks. Anti-slop holds:
 * sharp corners, hairline borders over shadows, tabular numerals on figures,
 * teal as the one action color, gold earned not sprinkled.
 *
 * Page-scoped under .titan (added to <body>) so the overrides of existing
 * product classes (the marketing dashboard preview button) never reach the
 * live dashboard, which does not carry .titan.
 */

/* The wordmark component that used to live here (.oddly-wm / .oddly-wm-o) was
 * never adopted: it had zero call sites in any page or renderer, so it was a
 * fourth definition of the mark that shipped bytes and taught nobody anything.
 * The mark now has one home, /_shared/oddly-mark.css. */

/* ============================================================
 * One button system. primary (teal action), secondary (ink
 * outline), tertiary (text link with affordance), shopify (the
 * read-only hand-off, a quiet bordered button with the bag
 * glyph), gold (the single premium CTA used on ink panels).
 * Spine v2 (design-handoff-2026-07-02): soft 11px radius, 15px/600
 * base rising to the 16-17px CTA scale on --lg, no letter-spacing,
 * confident padding, 44px min touch target.
 * ============================================================ */
.obtn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  min-height: 44px;
  padding: var(--oddly-btn-pad-sm, 14px 22px);
  font-family: var(--oddly-font-sans, "Hanken Grotesk", system-ui, sans-serif);
  font-size: 15px;
  font-weight: var(--oddly-btn-weight, 600);
  line-height: 1;
  text-decoration: none;
  white-space: nowrap;
  border: 1px solid transparent;
  border-radius: var(--oddly-radius-btn, 11px);
  cursor: pointer;
  transition: background 140ms var(--oddly-ease, ease), color 140ms var(--oddly-ease, ease), border-color 140ms var(--oddly-ease, ease);
}
.obtn:focus-visible { outline: 2px solid var(--oddly-gold, #B08D57); outline-offset: 3px; }

.obtn--primary {
  background: var(--oddly-teal, #2C7873);
  color: var(--oddly-canvas, #FAFAF7);
  border-color: var(--oddly-teal, #2C7873);
}
.obtn--primary:hover {
  background: var(--oddly-teal-hover, #246059);
  border-color: var(--oddly-teal-hover, #246059);
  color: var(--oddly-canvas, #FAFAF7);
}

.obtn--secondary {
  background: transparent;
  color: var(--oddly-ink, #1A1A2E);
  border-color: var(--oddly-border-btn, rgba(26, 26, 46, 0.18));
}
.obtn--secondary:hover {
  background: var(--oddly-ink, #1A1A2E);
  color: var(--oddly-canvas, #FAFAF7);
}
/* secondary on an ink panel inverts: cream outline, fills cream */
.obtn--secondary.obtn--onink {
  color: var(--oddly-canvas, #FAFAF7);
  border-color: rgba(250, 250, 249, 0.55);
}
.obtn--secondary.obtn--onink:hover {
  background: var(--oddly-canvas, #FAFAF7);
  color: var(--oddly-ink, #1A1A2E);
  border-color: var(--oddly-canvas, #FAFAF7);
}

.obtn--tertiary {
  min-height: 0;
  padding: 4px 2px;
  background: transparent;
  color: var(--oddly-teal, #2C7873);
  border-color: transparent;
  letter-spacing: 0.01em;
}
.obtn--tertiary:hover { color: var(--oddly-teal-hover, #246059); }

/* The Shopify hand-off button. Read-only by design: a quiet bordered
 * button with the Shopify bag glyph, so "Open it in Shopify" reads as an
 * intentional, branded secondary action and never an alarming primary. */
.obtn--shopify {
  background: var(--oddly-surface, #FFFFFF);
  color: var(--oddly-ink, #1A1A2E);
  border-color: var(--oddly-border-strong, #D8D5CC);
  font-weight: 600;
}
.obtn--shopify:hover {
  border-color: var(--oddly-ink, #1A1A2E);
  background: var(--oddly-surface, #FFFFFF);
}
.obtn--shopify .obtn-bag,
.obtn--shopify::before {
  content: "";
  width: 15px;
  height: 15px;
  flex: 0 0 auto;
  background: currentColor;
  /* a simple shopping-bag silhouette, masked to currentColor */
  -webkit-mask: var(--obtn-bag-mask) center / contain no-repeat;
  mask: var(--obtn-bag-mask) center / contain no-repeat;
}
:root {
  --obtn-bag-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M6 8h12l-1 12H7L6 8zm3 0a3 3 0 0 1 6 0' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
}

.obtn--gold {
  background: var(--oddly-gold, #B08D57);
  color: var(--oddly-ink, #1A1A2E);
  border-color: var(--oddly-gold, #B08D57);
}
.obtn--gold:hover {
  background: var(--oddly-canvas, #FAFAF7);
  border-color: var(--oddly-canvas, #FAFAF7);
  color: var(--oddly-ink, #1A1A2E);
}

.obtn--lg { min-height: 52px; padding: var(--oddly-btn-pad, 17px 30px); font-size: var(--oddly-btn-font-size, 16px); }
.obtn--block { display: flex; width: 100%; }

/* ============================================================
 * Full-bleed section primitives. A .t-band spans edge to edge
 * and carries the section background; the .t-wrap inside holds
 * the content at a confident 1280px with generous, fluid
 * gutters. This is the "use the full page" fix: nothing floats
 * as a narrow centred column in a sea of white.
 * ============================================================ */
.t-band {
  width: 100%;
  background: var(--oddly-canvas, #FAFAF7);
}
/* The light bands carry a near-imperceptible paper grain over the flat colour
 * so the large cream fields feel tactile, not plastic. Navy and tint bands stay
 * clean. The grain is procedural noise (see /site/paper-grain.svg): it depicts
 * nothing and adds no fabricated content. */
.t-band--cream { background: url("/site/paper-grain.svg") repeat, var(--oddly-canvas, #FAFAF7); }
.t-band--sunken { background: url("/site/paper-grain.svg") repeat, var(--oddly-surface-sunken, #F4F2EC); }
.t-band--navy {
  background: var(--oddly-ink, #1A1A2E);
  color: var(--oddly-canvas, #FAFAF7);
}
/* the one allowed restrained tint, for a single hero band */
.t-band--tint {
  background:
    linear-gradient(160deg,
      color-mix(in srgb, var(--oddly-ink, #1A1A2E) 6%, transparent),
      color-mix(in srgb, var(--oddly-teal, #2C7873) 5%, transparent)),
    var(--oddly-canvas, #FAFAF7);
}
.t-wrap {
  max-width: 1280px;
  margin: 0 auto;
  padding-left: clamp(20px, 5vw, 56px);
  padding-right: clamp(20px, 5vw, 56px);
}
.t-wrap--narrow { max-width: 960px; }

.t-nums { font-variant-numeric: tabular-nums; }

/* ============================================================
 * The titan type scale + palette ration (FOUNDATION, 2026-06-23).
 *
 * Kyle's review: the marketing surface grew too many small-caps
 * label treatments (.tag, .hm-side, .bs-dollar-kind, .bs-run-label,
 * .filter-col h3, the close-step labels) at slightly different
 * sizes and tracking, and colour was sprinkled rather than rationed.
 * This locks the system centrally so every surface and the per-page
 * refinement rows that follow consume ONE scale, not many.
 *
 * Type scale (five voices, no more):
 *   display  -> Newsreader serif, the headline voice (var(--oddly-font-serif))
 *   heading  -> Newsreader serif, section titles
 *   body     -> Hanken Grotesk, var(--oddly-text-body)
 *   label    -> ONE small-caps style, the .t-label primitive below
 *   data     -> tabular numerals, .t-nums / mono
 *
 * Palette ration (gold is earned, never decoration):
 *   cream  -> the paper. Dominant field on every page.
 *   navy   -> accent BANDS only, with soft edges (see the transition above).
 *   teal   -> action and links ONLY (buttons, inline links, the one accent).
 *   gold   -> the brand "o" and hairline accents ONLY (the aperture, a seal,
 *             a single rule), never a fill or a section background.
 * ============================================================ */

/* The ONE label: a small-caps eyebrow / kicker, sized from the locked
 * label token so it cannot drift. Spine v2 widens the tracking to the
 * handoff's kicker spec (0.14em). Ink-muted on cream by default; the
 * --onink and --teal modifiers cover the two earned exceptions. */
.t-label {
  display: inline-block;
  font-family: var(--oddly-font-sans, "Hanken Grotesk", system-ui, sans-serif);
  font-size: var(--oddly-kicker-size, 11px);
  font-weight: var(--oddly-kicker-weight, 700);
  letter-spacing: var(--oddly-tracking-kicker, 0.14em);
  text-transform: uppercase;
  line-height: 1.4;
  color: var(--oddly-ink-secondary, #5A5A6E);
}
.t-label--onink { color: rgba(250, 250, 249, 0.7); }
.t-label--teal { color: var(--oddly-teal, #2C7873); }

/* ============================================================
 * Marketing dashboard preview: the "Open it in Shopify" snapshot
 * (a non-interactive .oi-btn span) adopts the shopify button look
 * so the preview matches the one button system. Scoped to
 * .titan .oi-frame so the LIVE product dashboard, which never
 * carries .titan, keeps its own button untouched (CC4's surface).
 * ============================================================ */
.titan .oi-frame .oi-btn-primary {
  background: var(--oddly-surface, #FFFFFF);
  color: var(--oddly-ink, #1A1A2E);
  border: 1px solid var(--oddly-border-strong, #D8D5CC);
  font-weight: 600;
  gap: 8px;
}
.titan .oi-frame .oi-btn-primary:hover {
  background: var(--oddly-surface, #FFFFFF);
  border-color: var(--oddly-ink, #1A1A2E);
  color: var(--oddly-ink, #1A1A2E);
}
.titan .oi-frame .oi-btn-primary::before {
  content: "";
  width: 14px;
  height: 14px;
  flex: 0 0 auto;
  background: currentColor;
  -webkit-mask: var(--obtn-bag-mask) center / contain no-repeat;
  mask: var(--obtn-bag-mask) center / contain no-repeat;
}

/* ============================================================
 * Titan FLOW primitives (2026-06-17). Atmosphere, section rhythm,
 * and scroll motion that turn stacked bands into one continuous
 * flow. All scoped under body.titan (the marketing surface) so
 * nothing reaches the live dashboard or embedded app.
 *
 * Honesty guardrail: the atmosphere layer is pure CSS gradient
 * texture in the locked brand palette. It depicts nothing: no
 * fabricated dashboards, metrics, customers, or logos. The real
 * product proof stays the captures the pages already carry.
 * ============================================================ */

/* Atmosphere: a restrained brand-palette glow behind hero bands. */
body.titan .t-band { position: relative; }
body.titan .t-band--hero { isolation: isolate; }
/* The hero atmosphere now layers the brand "o" mark (see /site/oddly-o-mark.svg)
 * as a large, faint watermark bleeding off the top-right, over the existing
 * brand-palette glow. It is the mark itself at low opacity, not imagery, and
 * sits behind the content (z-index -1). */
body.titan .t-band--hero::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background:
    url("/site/oddly-o-mark.svg") no-repeat right -150px top -170px / 540px auto,
    radial-gradient(120% 85% at 82% -12%, color-mix(in srgb, var(--oddly-teal, #2C7873) 12%, transparent), transparent 60%),
    radial-gradient(95% 70% at 6% 4%, color-mix(in srgb, var(--oddly-gold, #B08D57) 9%, transparent), transparent 55%);
}
/* a navy hero warms the ink field rather than washing it out */
body.titan .t-band--navy.t-band--hero::before {
  background:
    url("/site/oddly-o-mark.svg") no-repeat right -150px top -170px / 540px auto,
    radial-gradient(120% 95% at 85% -22%, color-mix(in srgb, var(--oddly-teal, #2C7873) 30%, transparent), transparent 62%),
    radial-gradient(80% 80% at 4% 112%, color-mix(in srgb, var(--oddly-gold, #B08D57) 18%, transparent), transparent 55%);
}
/* the landing keeps a bespoke .hero class: it gets the same air, but its
 * top-right brand-o is upgraded from the static watermark to the living
 * aperture (.t-aperture, see below), so here ::before carries only the
 * brand-palette glow and the o-mark layer is dropped to avoid doubling. */
body.titan .hero { position: relative; isolation: isolate; }
body.titan .hero::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background:
    radial-gradient(110% 80% at 88% -14%, color-mix(in srgb, var(--oddly-teal, #2C7873) 10%, transparent), transparent 58%),
    radial-gradient(90% 70% at 2% 2%, color-mix(in srgb, var(--oddly-gold, #B08D57) 8%, transparent), transparent 52%);
}

/* ============================================================
 * Signature hero motif: the living aperture (2026-06-23). The
 * brand "o" rendered as code-based art (see /site/oddly-aperture.svg):
 * concentric halo rings turning slowly around a six-blade iris and a
 * teal pupil. The gentle motion lives inside the SVG and is gated on
 * prefers-reduced-motion there, so embedding it as an <img> needs no
 * JS and falls back to a still halo. It is the ownable hero signature,
 * not decoration. Markup mirrors the atmosphere plate: a clipping span
 * (inset 0, overflow hidden) holds the mark bleeding off the top-right,
 * so nothing escapes the hero and horizontal overflow stays 0.
 *   <span class="t-aperture" aria-hidden="true">
 *     <img class="t-aperture-img" src="/site/oddly-aperture.svg" alt="" ...>
 *   </span>
 * z-index -1 sits above an atmosphere plate (-2) and below the copy.
 * ============================================================ */
body.titan .t-aperture {
  position: absolute;
  inset: 0;
  z-index: -1;
  overflow: hidden;
  pointer-events: none;
}
body.titan .t-aperture-img {
  position: absolute;
  top: clamp(-180px, -15vw, -96px);
  right: clamp(-150px, -11vw, -64px);
  width: clamp(340px, 44vw, 560px);
  height: auto;
}

/* Section rhythm (refined 2026-06-23, titan-flow refinement FOUNDATION).
 * Kyle's review of the previews: the site read as BOXED sections because the
 * joins between full-bleed bands were drawn as hard rules (a gold hairline
 * seam) and stamped with a second gold "o" ornament per join, so the brand
 * mark appeared twice on a screen and every band fenced itself off.
 *
 * The refined rule: same-colour bands flow with NO line at all (two cream
 * bands are one continuous field), and the only softening lives on the
 * cream<->navy join below, as a gradient blend rather than a drawn edge. The
 * gold "o" stays a single signature per view (the hero aperture); it is no
 * longer repeated on every section seam. */

/* Soft cream<->navy transition: a navy band lifts toward cream across its top
 * and bottom edges so the colour change reads as a blend, not a hard cut. The
 * lift is self-contained in the band background (no pseudo, no overflow, no
 * z-index against the content), and stays dark enough that cream copy keeps
 * full AA contrast. Heroes opt out: they carry their own atmosphere ::before
 * and a lighter edge would muddy it. */
body.titan main > .t-band--navy:not(.t-band--hero) {
  background:
    linear-gradient(
      180deg,
      color-mix(in srgb, var(--oddly-ink, #1A1A2E) 86%, var(--oddly-canvas, #FAFAF7)) 0,
      var(--oddly-ink, #1A1A2E) 72px,
      var(--oddly-ink, #1A1A2E) calc(100% - 72px),
      color-mix(in srgb, var(--oddly-ink, #1A1A2E) 86%, var(--oddly-canvas, #FAFAF7)) 100%);
}

/* Scroll motion: sections fade and rise as they enter the viewport.
 * The hidden state is gated on .flow-ready (added by oddly-nav.js)
 * so it never applies without JS, and the whole effect is disabled
 * for visitors who prefer reduced motion. Heroes are never hidden. */
@media (prefers-reduced-motion: no-preference) {
  body.titan.flow-ready [data-reveal],
  body.titan.flow-ready main > .t-band:not(.t-band--hero) > .t-wrap {
    opacity: 0;
    transform: translateY(20px);
    transition: opacity 620ms var(--oddly-ease, ease), transform 620ms var(--oddly-ease, ease);
  }
  body.titan.flow-ready [data-reveal].is-in,
  body.titan.flow-ready main > .t-band:not(.t-band--hero) > .t-wrap.is-in {
    opacity: 1;
    transform: none;
  }
}

/* ============================================================
 * Keyboard focus indicator: content links (a11y QA 2026-06-24,
 * WCAG 2.4.7). The shared chrome carries its own focus ring (see
 * oddly-chrome.css); this covers the in-CONTENT links, buttons and
 * the focusable hint trigger on every marketing page (the landing's
 * iron/filtered/close/proof links, the product-window link, subpage
 * body links), which previously showed no keyboard-focus state.
 *
 * One gold ring, matching the chrome and the landing CTAs, on
 * keyboard focus only (:focus-visible never fires on a mouse click,
 * so pointer/touch users are unaffected). Gold reads at >=3:1 on
 * both the cream canvas and the navy zones, meeting WCAG 1.4.11 for
 * the focus indicator. */
body.titan a:focus-visible,
body.titan button:focus-visible,
body.titan [tabindex="0"]:focus-visible {
  outline: 2px solid var(--oddly-gold, #B08D57);
  outline-offset: 3px;
  border-radius: 1px;
}
