/* Aibödes public site: shared Almanac foundation for / and /privacy.

   Source of truth for every value here is the product design system
   (design/DIRECTION.md §0 and §5, Almanac). This file carries only the
   slice the public site needs: ground/ink/semantic tokens with their dark
   values, the dawn register, the two faces, and the base element styles.
   Page-specific layout stays in each page's own <style>.

   Cascade layers (the same pattern as the product prototype). The
   reduced-motion layer wins because its declarations are !important: an
   important declaration beats every normal one, layered or not (that
   includes Umlauti's injected, unlayered <style>), whatever its
   specificity. Declaring it last does NOT help: for !important rules the
   layer order inverts, so the last layer is the weakest. Keep !important
   off animation and transition in the earlier layers, or they would beat
   it. */
@layer tokens, base, page, reduced-motion;

/* ------------------------------------------------------------------ fonts
   Self-hosted (CSP: default-src 'self' covers fonts; no Google request at
   runtime). Both are SIL Open Font License 1.1; the licence texts sit next
   to the files in /assets/fonts/. Neither family declares a Reserved Font
   Name, so the Google Fonts latin subsets keep their family names.

   - Archivo: the variable font, both axes kept (wght 100-900, wdth 62-125%).
     The ranges below are load-bearing: without `font-stretch: 62% 125%` the
     browser treats the face as normal-width only, the wordmark's 112% width
     silently falls back to 100%, and Umlauti's canvas calibration would
     measure a different ö from the one drawn.
   - Fraunces: a static instance (opsz 144, wght 380, SOFT 30, WONK 0), the
     sky voice. Roman only: DESIGN.md bans italic flourish halves on
     headlines, so the italic file would be dead weight. */
@font-face {
  font-family: "Archivo";
  src: url("/assets/fonts/archivo-latin-var.woff2") format("woff2");
  font-weight: 100 900;
  font-stretch: 62% 125%;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Fraunces";
  src: url("/assets/fonts/fraunces-latin-380.woff2") format("woff2");
  font-weight: 380;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* Metric-matched fallbacks: while the real faces load (font-display: swap),
   text is set in a local face scaled to the same advance widths, so the swap
   does not re-wrap lines and shift the page (CLS). size-adjust is the ratio
   of advance widths over a sample sentence (canvas measureText, Chromium,
   400 weight), and the overrides are each face's own ascent and descent
   divided by that ratio. Arial and Georgia were measured; the other local
   names are near-metric stand-ins. */
@font-face {
  font-family: "Archivo fallback";
  src: local("Arial"), local("Helvetica Neue"), local("Helvetica");
  size-adjust: 98.5%;
  ascent-override: 89.3%;
  descent-override: 21.3%;
  line-gap-override: 0%;
}
@font-face {
  font-family: "Fraunces fallback";
  src: local("Georgia"), local("Times New Roman");
  size-adjust: 84%;
  ascent-override: 116.7%;
  descent-override: 31%;
  line-gap-override: 0%;
}

@layer tokens {
  :root {
    color-scheme: light dark;
    --ground: #FAFAF7; --ground-2: #F0F0EB; --ground-3: #E5E5DE;
    --ink: #1C1A18; --ink-2: #47433D; --ink-3: #625D55;
    --line: #DEDAD1; --line-2: #C9C4B8;
    /* Control edges (input borders, outline pills): WCAG 1.4.11 asks 3:1 for
       the boundary that identifies a control. --line-2 is a decorative
       hairline (1.66:1) and stays one; this is 3.8:1 on --ground and 3.5:1
       on --ground-2, where the share buttons sit. */
    --ctl: #857F75;
    --button: #1C1A18; --button-ink: #FAFAF7;
    --sun: #FFC83D; --sun-deep: #EFA300; --sun-rim: #A86C00; --sun-soft: #FFF1C6;
    --ok: #17704A; --ok-bg: #DDF0E5;
    --warn: #8A5800; --warn-bg: #FBEBC9;
    --risk: #A93225; --risk-bg: #F9DFDA;
    /* The offer board's two marks (r2b): solid ink is what the seller keeps,
       hatching is what comes out of the price. */
    --keep: #1C1A18;
    --hatch: repeating-linear-gradient(135deg, color-mix(in srgb, var(--ink-3) 58%, transparent) 0 1.4px, transparent 1.4px 5.5px);
    --f-display: "Fraunces", "Fraunces fallback", "Iowan Old Style", Georgia, serif;
    --f-text: "Archivo", "Archivo fallback", ui-sans-serif, system-ui, sans-serif;
    --ease: cubic-bezier(.2, .8, .2, 1);
    --quick: 160ms; --medium: 360ms; --slow: 720ms;
    --gut: 40px; --max: 1200px;
    --r-chip: 8px; --r-field: 14px; --r-panel: 22px;
    /* Umlauti's own tokens (CHARACTER.md §Anatomy): the lit tone, its rim on
       dawn skies, sparkle colour and the knob's keyhole. */
    --um-lit: #FFC83D; --um-rim: rgba(168, 108, 0, .6); --um-spark: #EFA300; --um-hole: #10262B;
  }
  /* Dawn: the front door's time of day (DIRECTION §5.2 and §0.2). It has no
     dark variant on this site, on purpose: the home page's sky is drawn
     around a dawn render that does not change with the colour scheme, and
     the privacy page keeps the same sky so moving between the two never
     changes the time of day. Only the ground below the horizon goes dark. */
  [data-register="dawn"] {
    --sky-a: #F2AFA2; --sky-b: #FFD6BC; --sky-ink: #2A1A17; --sky-ink-2: #6A3529;
    --hz: rgba(42, 26, 23, .38);
    /* The sky behind the render, sampled from the render's own sky
       (r2b build_page.py), so the faded seam never shows. */
    --render-sky: linear-gradient(180deg, #F3B4A2 0%, #F5B8A5 12%, #F6BFA9 25%, #F8C6AB 38%, #FBCBAE 50%, #FBD1AF 62%, #FDD6B1 75%, #FED9B1 88%, #FFDAB2 100%);
    /* Below the render's horizon the sky turns to a near-ground haze, so
       the lawn's faded left edge melts into near-ground, not into peach.
       Both pages' wide skies (home .entry, privacy .masthead) end on it. */
    --haze: rgba(250, 238, 226, .8);
    --haze-end: #FAF4EC;
  }
  /* Dark ground: a near-white haze would meet #121315 in a hard band at the
     horizon. The sky stays dawn, but its haze ends on the render's own
     bottom peach (render-sky at 100%), so the step down to the lit ground
     (.horizon::after below) is from a warm tone, not from white. Set here
     so both pages share one dark horizon. (The home page's phone and
     tablet skies are drawn separately and already end on that peach.) */
  @media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) [data-register="dawn"] { --haze: rgba(254, 216, 178, .55); --haze-end: #FCD2AE; }
  }
  :root[data-theme="dark"] [data-register="dawn"] { --haze: rgba(254, 216, 178, .55); --haze-end: #FCD2AE; }
  @media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) {
      --ground: #121315; --ground-2: #1A1C1F; --ground-3: #24272B;
      --ink: #F2F0EB; --ink-2: #CBC6BD; --ink-3: #A39E95;
      --line: #2D3034; --line-2: #3C4045; --ctl: #6E727A;
      --button: #F2F0EB; --button-ink: #121315;
      --sun-soft: #3A2F10;
      --ok: #5FD39A; --ok-bg: #12301F; --warn: #F2BE55; --warn-bg: #33270C; --risk: #FF8C7A; --risk-bg: #3A1914;
      --keep: #F2F0EB;
    }
  }
  :root[data-theme="dark"] {
    --ground: #121315; --ground-2: #1A1C1F; --ground-3: #24272B;
    --ink: #F2F0EB; --ink-2: #CBC6BD; --ink-3: #A39E95;
    --line: #2D3034; --line-2: #3C4045; --ctl: #6E727A;
    --button: #F2F0EB; --button-ink: #121315;
    --sun-soft: #3A2F10;
    --ok: #5FD39A; --ok-bg: #12301F; --warn: #F2BE55; --warn-bg: #33270C; --risk: #FF8C7A; --risk-bg: #3A1914;
    --keep: #F2F0EB;
  }
  @media (max-width: 760px) { :root { --gut: 16px; } }
}

@layer base {
  *, *::before, *::after { box-sizing: border-box; }
  html { -webkit-text-size-adjust: 100%; text-size-adjust: 100%; }
  body {
    margin: 0;
    background: var(--ground);
    color: var(--ink);
    font: 400 18px/1.55 var(--f-text);
    font-stretch: 100%;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    overflow-x: hidden;
    min-height: 100vh;
    min-height: 100dvh;
    display: flex;
    flex-direction: column;
  }
  h1, h2, h3, p, ul, ol, figure { margin: 0; padding: 0; }
  img { display: block; max-width: 100%; }
  button, input { font: inherit; color: inherit; }
  button { cursor: pointer; }
  a { color: inherit; }
  /* One focus ring everywhere: 3px in the current text colour, so it holds
     contrast on the sky and the ground alike. */
  :focus-visible { outline: 3px solid currentColor; outline-offset: 3px; border-radius: 6px; }
  .num { font-variant-numeric: tabular-nums lining-nums; font-stretch: 74%; }

  /* -- the sky: one register field, a film grain so it never reads as a bare
        CSS gradient (DIRECTION §0.2 Imagery), and its own ink. */
  .sky {
    position: relative;
    color: var(--sky-ink);
    padding: 0 var(--gut);
    background: linear-gradient(180deg, var(--sky-a), var(--sky-b));
    isolation: isolate;
  }
  .sky::before {
    content: "";
    position: absolute;
    inset: 0;
    z-index: -1;
    pointer-events: none;
    opacity: .1;
    mix-blend-mode: soft-light;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 .9 0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  }
  /* -- the stand: the Bayard house at dawn (design/art, Blender) standing on
        the page horizon at the right. The render is cut along its sidewalk
        line (--cut, a fraction of the art's height) and that line sits
        exactly on the sky's bottom edge, so the house stands on the ruler
        instead of sinking into it. --hy is the render's own horizon
        (design/art/aibodes-bayard-dawn-wide.json, horizon_y). Each page sets
        the stand's height and bottom offset. */
  .stand {
    --cut: .875;
    --hy: .64581;
    position: absolute;
    z-index: 0;
    right: 0;
    aspect-ratio: 16 / 9;
    pointer-events: none;
    overflow: hidden;
    clip-path: inset(0 0 calc(100% - var(--cut) * 100%) 0);
    /* Three mask layers: a top fade (so the render's sky melts into the
       CSS sky when the art is shorter than the sky), intersected with two
       left fades. Above the render's horizon the edge fades over 14%;
       below it the lawn fades out much further left (clear until 10%,
       solid from 34%), so sky text never sits on grass: sky text is
       measured against the worst pixel under it (DIRECTION §4 rule 16). */
    -webkit-mask-image: linear-gradient(180deg, transparent 0, #000 18%), linear-gradient(90deg, transparent 0, #000 14%), linear-gradient(90deg, transparent 0, transparent 10%, #000 34%);
    mask-image: linear-gradient(180deg, transparent 0, #000 18%), linear-gradient(90deg, transparent 0, #000 14%), linear-gradient(90deg, transparent 0, transparent 10%, #000 34%);
    -webkit-mask-size: 100% 100%, 100% calc(var(--hy) * 100%), 100% calc((1 - var(--hy)) * 100% + 1px);
    mask-size: 100% 100%, 100% calc(var(--hy) * 100%), 100% calc((1 - var(--hy)) * 100% + 1px);
    -webkit-mask-position: 0 0, 0 0, 0 100%;
    mask-position: 0 0, 0 0, 0 100%;
    -webkit-mask-repeat: no-repeat;
    mask-repeat: no-repeat;
    -webkit-mask-composite: source-in, source-over;
    mask-composite: intersect, add;
  }
  .stand img { position: absolute; inset: 0; width: 100%; height: 100%; max-width: none; object-fit: cover; }

  /* The horizon: one hairline where the sky meets the ground. */
  .horizon { position: relative; height: 1.5px; background: color-mix(in srgb, var(--sky-ink) 30%, transparent); }
  /* Dark ground under a dawn sky. The sky stays dawn, so without help its
     pale bottom edge would meet #121315 in a bare cut and the hairline
     would vanish into whichever side is darker. Two parts:
     - the line is a 2px rule in the sky's own ink, so it reads as a drawn
       edge against the pale sky above and the lit ground below;
     - below it the dawn's warm tone (--sky-b) spills onto the ground and
       fades to the ground colour over 200px on an eased curve, starting
       at 52% so the step down from the peach sky is small; the ground is
       lit where it meets the sky instead of starting black.
     The fade is absolutely placed and paints at z-index -1 (above the
     page background, below the ground's content), so it moves nothing.
     Text on it keeps AA: the lede sits ~50px down, where the mix is about
     20% dawn on #121315 (6.8:1 for --ink-2). */
  .horizon::after {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    top: 100%;
    height: 200px;
    z-index: -1;
    pointer-events: none;
    background: linear-gradient(180deg,
      color-mix(in srgb, var(--sky-b) 52%, transparent) 0,
      color-mix(in srgb, var(--sky-b) 30%, transparent) 10%,
      color-mix(in srgb, var(--sky-b) 15%, transparent) 30%,
      color-mix(in srgb, var(--sky-b) 6%, transparent) 62%,
      transparent 100%);
    opacity: 0;
  }
  @media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) .horizon { height: 2px; background: color-mix(in srgb, var(--sky-ink-2) 80%, transparent); }
    :root:not([data-theme="light"]) .horizon::after { opacity: 1; }
  }
  :root[data-theme="dark"] .horizon { height: 2px; background: color-mix(in srgb, var(--sky-ink-2) 80%, transparent); }
  :root[data-theme="dark"] .horizon::after { opacity: 1; }
  .in { max-width: var(--max); margin: 0 auto; position: relative; }

  /* -- the wordmark at nav size: Archivo 820 at 108% width, the product nav's
        setting, so the ö reads the same here as in the app. */
  .wm {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
    font: 820 25px/1 var(--f-text);
    font-stretch: 108%;
    letter-spacing: -.025em;
    color: inherit;
    text-decoration: none;
  }

  /* -- type roles */
  .t1 {
    font-family: var(--f-display);
    font-weight: 380;
    line-height: 1.02;
    letter-spacing: -.024em;
    font-variant-numeric: lining-nums;
    text-wrap: balance;
  }
  .t2 {
    font-family: var(--f-display);
    font-weight: 380;
    font-size: clamp(30px, 3.3vw, 44px);
    line-height: 1.08;
    letter-spacing: -.02em;
    text-wrap: balance;
  }
  .t3 { font: 650 22px/1.2 var(--f-text); font-stretch: 94%; letter-spacing: -.012em; }
  .src { font-size: 16px; line-height: 1.5; color: var(--ink-3); }

  /* -- buttons: ink pills, verbs on the label (DIRECTION §5.4 radii, §4 rule 10
        targets). The secondary style is an outline at the same height floor. */
  .btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 10px;
    min-height: 54px;
    padding: 0 26px;
    border-radius: 999px;
    border: 0;
    background: var(--button);
    color: var(--button-ink);
    font: 620 17px/1.1 var(--f-text);
    text-decoration: none;
    white-space: nowrap;
    transition: transform var(--quick) var(--ease), opacity var(--quick) var(--ease), box-shadow var(--quick) var(--ease);
  }
  .btn:active { transform: scale(.98); }
  /* The ring follows the ink, not the label: on a filled pill the label
     colour is the ground's, which would draw an invisible ring. */
  .btn:focus-visible { outline-color: var(--ink); }
  /* Disabled keeps a solid fill: its label is a status ("Checking…"), so it
     must stay readable (9:1 light, 11:1 dark), not fade to 3.4:1. */
  .btn:disabled { background: var(--ink-2); cursor: default; transform: none; }
  .btn.sec {
    min-height: 48px;
    padding: 0 20px;
    background: transparent;
    color: var(--ink);
    box-shadow: inset 0 0 0 1.5px var(--ctl);
    font-weight: 560;
    font-size: 16px;
  }
  .btn.sec:hover { box-shadow: inset 0 0 0 1.5px var(--ink-3); }

  /* -- footer, shared by both pages */
  .foot {
    padding: 0 var(--gut) 40px;
    color: var(--ink-3);
    font-size: 16px;
    line-height: 1.5;
  }
  .foot .in { border-top: 1px solid var(--line); padding-top: 28px; display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 8px 32px; }
  .foot .sign { font-family: var(--f-display); font-weight: 380; font-size: 24px; line-height: 1.2; letter-spacing: -.012em; color: var(--ink); }
  .foot ul { list-style: none; display: flex; flex-wrap: wrap; align-items: center; gap: 0 20px; }
  /* Links keep the underline (CalOPPA "conspicuous" privacy link, B&P
     §22577(b)(3)) and get a 44px tall hit area without growing the line. */
  .foot a { display: inline-flex; align-items: center; min-height: 44px; color: var(--ink-2); text-decoration: underline; text-underline-offset: 3px; overflow-wrap: anywhere; }
  .foot a:hover { color: var(--ink); text-decoration-thickness: 2px; }
}

/* Reduced motion: no transitions and no animations anywhere on the site
   (DIRECTION §5.5). Umlauti follows the same preference itself, live. */
@layer reduced-motion {
  @media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
      animation: none !important;
      transition: none !important;
      scroll-behavior: auto !important;
    }
  }
}
