/* 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 gold-O wordmark. ONE component, used in every masthead,
 * header, footer, and embedded bar. The brand mark is the gold
 * "O"; the rest of the word takes the surrounding ink. Markup:
 *   <a class="oddly-wm"><span class="oddly-wm-o">o</span>ddly</a>
 * Size via --wm-size (default 20px). The 5-degree tilt matches
 * the canonical halo logomark.
 * ============================================================ */
.oddly-wm {
  --wm-size: 20px;
  font-family: var(--oddly-font-serif, Georgia, "Times New Roman", serif);
  font-optical-sizing: auto;
  font-size: var(--wm-size);
  font-weight: 600;
  letter-spacing: -0.02em;
  line-height: 1;
  color: var(--oddly-ink, #1A1A2E);
  text-decoration: none;
  display: inline-block;
}
.oddly-wm-o {
  color: var(--oddly-gold, #B08D57);
  display: inline-block;
  transform: rotate(5deg);
  transform-origin: 50% 60%;
}
/* on a dark surface the word goes cream; the O stays gold */
.oddly-wm--oninK,
.oddly-wm--onink { color: var(--oddly-canvas, #FAFAF7); }

/* ============================================================
 * 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).
 * Sharp corners, confident padding, 44px min touch target.
 * ============================================================ */
.obtn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  min-height: 44px;
  padding: 12px 22px;
  font-family: var(--oddly-font-sans, "Inter", system-ui, sans-serif);
  font-size: 14px;
  font-weight: 600;
  letter-spacing: 0.04em;
  line-height: 1;
  text-decoration: none;
  white-space: nowrap;
  border: 1px solid transparent;
  border-radius: 0;
  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-ink, #1A1A2E);
}
.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: 16px 30px; font-size: 15px; }
.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  -> Fraunces serif, the headline voice (var(--oddly-font-serif))
 *   heading  -> Fraunces serif, section titles
 *   body     -> Inter, 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. 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, "Inter", system-ui, sans-serif);
  font-size: var(--oddly-font-size-label, 11px);
  font-weight: 700;
  letter-spacing: var(--oddly-tracking-label, 0.08em);
  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;
}

/* ============================================================
 * Atmosphere plates (2026-06-23). Full-bleed photographic
 * environment plates that sit BEHIND a section's copy as a faint
 * warm atmosphere, under a cream veil that keeps the light-
 * dominant system and the ink text fully legible on top.
 *
 * Honesty guardrail (extends the FLOW note above): these plates
 * are ENVIRONMENT only. They depict a workspace (a desk, a mug, a
 * notebook, shipping parcels, a laptop with a BLANK screen): no
 * fabricated dashboard, metric, customer, review, or logo. The
 * real product proof stays the live .oi-* captures the pages carry.
 *
 * Markup: a decorative, aria-hidden layer placed as the FIRST
 * child of a positioned section, with the copy as a later sibling.
 *   <section class="... has-plate">
 *     <span class="t-plate" aria-hidden="true">
 *       <img class="t-plate-img" src="/assets/marketing/<slug>-1024.webp"
 *            srcset="/assets/marketing/<slug>-768.webp 768w,
 *                    /assets/marketing/<slug>-1024.webp 1024w"
 *            sizes="100vw" alt="" loading="lazy" decoding="async" width="1024" height="576">
 *     </span>
 *     ... copy ...
 *   </section>
 * The <img> carries loading="lazy" + srcset so below-the-fold
 * plates never block first paint and each viewport pulls only the
 * variant it needs. width/height are set to reserve the box and
 * keep cumulative layout shift at zero.
 * ============================================================ */
body.titan .has-plate { position: relative; isolation: isolate; }
body.titan .t-plate {
  position: absolute;
  /* Flow pass (2026-06-24): the plate box extends BELOW its section by
   * --plate-bleed so the feathered image (see .t-plate-img mask) dissolves
   * downward across the join, reading as one continuous graded atmosphere
   * rather than a photo that stops at the section seam. Horizontal edges stay
   * flush (inset 0 left/right) + overflow:hidden, so the off-canvas image never
   * adds horizontal scroll; only the bottom reaches into the next band. */
  --plate-bleed: clamp(40px, 6vw, 96px);
  inset: 0 0 calc(-1 * var(--plate-bleed)) 0;
  z-index: -1;
  overflow: hidden;
  pointer-events: none;
}
/* On a hero band the plate drops a layer deeper than the existing brand-o
 * watermark + palette glow (the ::before, z-index -1) so the photo is the
 * furthest-back atmosphere and the brand mark still reads on top of it. */
body.titan .hero .t-plate,
body.titan .t-band--hero .t-plate { z-index: -2; }
body.titan .t-plate-img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center 38%;
  /* the plate reads as a clear, premium warm atmosphere (dialled up
   * 2026-06-23 from 0.42: Kyle found the plates almost invisible under
   * the old veil), still a texture behind the copy, never a literal photo. */
  opacity: 0.6;
  /* Palette grade (2026-06-24 flow pass). Each source photo carries its own
   * colour temperature, so side by side they read as four unrelated stock
   * images. This collapses every plate to ONE brand palette: grayscale ->
   * sepia maps it to a single warm hue, hue-rotate swings that hue to the
   * brand teal, and the muted saturation lands it as a teal-cast warm neutral
   * that belongs with the cream canvas. The result is graded atmosphere, no
   * longer a legible "generic desk" photo, and identical across every plate. */
  filter: grayscale(1) sepia(1) hue-rotate(148deg) saturate(0.72) brightness(1.06) contrast(0.98);
  /* Downward bleed: feather the image into transparency at top and (longer)
   * bottom so it dissolves into the cream instead of cutting at a hard line.
   * The long bottom tail carries the dissolve into the --plate-bleed overhang,
   * so the atmosphere bleeds downward across the section join. */
  --plate-feather-top: 12%;
  --plate-feather-bottom: 46%;
  -webkit-mask-image: linear-gradient(180deg, transparent 0, #000 var(--plate-feather-top), #000 calc(100% - var(--plate-feather-bottom)), transparent 100%);
  mask-image: linear-gradient(180deg, transparent 0, #000 var(--plate-feather-top), #000 calc(100% - var(--plate-feather-bottom)), transparent 100%);
}
/* The cream veil: a wash over the plate so the cream canvas still
 * dominates and ink copy keeps full contrast. Denser at the edges
 * where the broadsheet rules and copy live, lighter through the
 * centre so the scene still breathes. Lightened 2026-06-23 (was
 * 78/62/80%) so the atmosphere reads clearly while the cream layer
 * still covers >=60% at the copy edges, keeping ink text WCAG-AA. */
body.titan .t-plate::after {
  content: "";
  position: absolute;
  inset: 0;
  background:
    linear-gradient(
      180deg,
      color-mix(in srgb, var(--oddly-canvas, #FAFAF7) 60%, transparent) 0%,
      color-mix(in srgb, var(--oddly-canvas, #FAFAF7) 40%, transparent) 42%,
      color-mix(in srgb, var(--oddly-canvas, #FAFAF7) 62%, transparent) 100%);
}
/* On a navy band the veil flips to ink so a plate can warm an ink
 * field without washing out the cream text. (Unused by default; the
 * landing keeps its navy panels clean, but the primitive supports it.) */
body.titan .t-band--navy .t-plate-img { opacity: 0.42; }
body.titan .t-band--navy .t-plate::after {
  background:
    linear-gradient(
      180deg,
      color-mix(in srgb, var(--oddly-ink, #1A1A2E) 68%, transparent) 0%,
      color-mix(in srgb, var(--oddly-ink, #1A1A2E) 52%, transparent) 45%,
      color-mix(in srgb, var(--oddly-ink, #1A1A2E) 70%, transparent) 100%);
}
@media (prefers-reduced-motion: no-preference) {
  /* the plate itself never animates: it is a static atmosphere layer */
  body.titan .t-plate-img { transition: none; }
}
