/* ============================================================
   VEXT LABS · Brand direction "Proposal A" (Yahya Vision, creative
   direction phase) — proposal-a.css
   Packet: BRAND-PROPOSAL-A-20260819

   Founder decision 2026-08-19: this direction SUPERSEDES Porcelain
   Futurism as the governing brand. Porcelain / LUXLIQ / FACET / Meadow
   are lineage. Sequencing: vextlabs.ai first, then juwel.ai marketing,
   the OS shell last (after 4 September) — restyling the live product on
   launch week is where things break.

   NOT IN SCOPE, BY FOUNDER INSTRUCTION: the logo and the symbol. They
   are undecided. Nothing in this file draws a mark. The wordmark is set
   in type and `.pa-mark` is an EMPTY reserved slot — see the note there.

   VARIABLE-FIRST. Every colour, size and family below is a token. No
   component in this system may hardcode a value; swapping the direction
   must be an edit to this file alone.
   ============================================================ */

:root {
  /* ---- Proposal A palette, as labelled on the deck ---------------- */
  --pa-grey:   #F3F3F4;   /* deck: F3F3F4 */
  --pa-black:  #000000;   /* deck: 000000 */
  --pa-white:  #F9FAF4;   /* deck: F9FAF4 — warm off-white, not pure */
  --pa-cream:  #F9F3E5;   /* deck: F9F3E5 */
  --pa-orange: #FF3814;   /* deck: FF3814 */

  /* ---- The accent. READ THIS BEFORE CHANGING ANYTHING ------------
     The deck labels this swatch `87C6E1`, but that hex is a pale BLUE
     and the swatch as supplied renders MAGENTA. Founder confirmed
     2026-08-19 that the magenta is correct and the label is a typo.

     HONEST LABEL: the value below is a VISUAL ESTIMATE read off the
     supplied artwork, NOT a measured sample — the reference reached us
     as an image in conversation, not a file whose pixels could be read.
     It is deliberately isolated to this one token: when the exact hex
     comes back from Yahya, change this line and nothing else.  */
  --pa-magenta: #F98CF9;  /* UNCONFIRMED ESTIMATE — awaiting exact value */

  /* Deck label preserved so the discrepancy stays visible in code
     rather than living only in a chat log. Not referenced anywhere. */
  --pa-magenta-deck-label: #87C6E1;

  /* ---- Semantic roles (components use THESE, never the raws) ------ */
  --pa-bg:            var(--pa-white);
  --pa-bg-inverse:    var(--pa-black);
  --pa-surface:       var(--pa-cream);
  --pa-text:          var(--pa-black);
  --pa-text-inverse:  var(--pa-white);
  --pa-text-muted:    color-mix(in srgb, var(--pa-black) 62%, transparent);
  --pa-text-muted-inverse: color-mix(in srgb, var(--pa-white) 68%, transparent);
  --pa-action:        var(--pa-orange);
  --pa-action-text:   var(--pa-white);
  --pa-accent:        var(--pa-magenta);
  --pa-hair:          color-mix(in srgb, var(--pa-black) 12%, transparent);
  --pa-hair-inverse:  color-mix(in srgb, var(--pa-white) 18%, transparent);

  /* ---- Type -------------------------------------------------------
     The real families are pending from Yahya. Each stack below leads
     with a var() placeholder so dropping in the licensed face is one
     line per family, then falls back to the closest widely-available
     equivalent so the page is never unstyled.

     Observed in the direction:
       display  a high-contrast old-style/transitional SERIF
       body     a geometric grotesque SANS
       script   a casual handwritten face, used ONCE as an aside  */
  --pa-font-display: var(--pa-font-display-licensed, "Iowan Old Style", "Palatino Linotype", Palatino, "Book Antiqua", Georgia, serif);
  --pa-font-body:    var(--pa-font-body-licensed, ui-sans-serif, "Helvetica Neue", Inter, "Segoe UI", system-ui, sans-serif);
  --pa-font-script:  var(--pa-font-script-licensed, "Bradley Hand", "Segoe Script", cursive);
  --pa-font-mono:    ui-monospace, "SF Mono", Menlo, monospace;

  /* Fluid display scale. Ratio holds at every width, so the hero never
     needs a per-breakpoint override. */
  --pa-step--1: clamp(0.82rem, 0.80rem + 0.10vw, 0.90rem);
  --pa-step-0:  clamp(1.00rem, 0.96rem + 0.18vw, 1.12rem);
  --pa-step-1:  clamp(1.25rem, 1.15rem + 0.45vw, 1.55rem);
  --pa-step-2:  clamp(1.60rem, 1.35rem + 1.10vw, 2.30rem);
  --pa-step-3:  clamp(2.10rem, 1.55rem + 2.40vw, 3.40rem);
  --pa-step-4:  clamp(2.30rem, 1.40rem + 3.80vw, 4.20rem);
  --pa-step-5:  clamp(2.90rem, 1.60rem + 5.20vw, 5.60rem);

  --pa-lh-tight: 0.98;
  --pa-lh-snug:  1.12;
  --pa-lh-body:  1.55;

  /* ---- Space, radius, motion -------------------------------------- */
  --pa-s1: 4px;  --pa-s2: 8px;  --pa-s3: 12px; --pa-s4: 16px;
  --pa-s5: 24px; --pa-s6: 32px; --pa-s7: 48px; --pa-s8: 72px;
  --pa-s9: 112px; --pa-s10: 160px;
  --pa-measure: 62ch;
  --pa-gutter: clamp(20px, 5vw, 88px);
  --pa-maxw: 1440px;

  /* The mosaic tile: a rounded square. This radius IS the brand's
     signature shape and every tile inherits it. */
  --pa-tile: 28px;
  --pa-tile-radius: 7px;
  --pa-tile-gap: 2px;

  --pa-radius-sm: 6px;
  --pa-radius:    10px;
  --pa-radius-lg: 18px;

  --pa-ease: cubic-bezier(0.22, 0.61, 0.36, 1);
}

/* ---- Base ------------------------------------------------------- */
.pa {
  background: var(--pa-bg);
  color: var(--pa-text);
  font-family: var(--pa-font-body);
  font-size: var(--pa-step-0);
  line-height: var(--pa-lh-body);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}
.pa *, .pa *::before, .pa *::after { box-sizing: border-box; }

/* Inverse is a scope, not a theme: set roles once, and every component
   inside is correct without knowing where it sits. */
.pa-inverse {
  background: var(--pa-bg-inverse);
  color: var(--pa-text-inverse);
  --pa-text: var(--pa-text-inverse);
  --pa-text-muted: var(--pa-text-muted-inverse);
  --pa-hair: var(--pa-hair-inverse);
}

.pa-wrap { max-width: var(--pa-maxw); margin-inline: auto; padding-inline: var(--pa-gutter); }
.pa-section { padding-block: var(--pa-s9); }
.pa-section--tight { padding-block: var(--pa-s7); }

/* ---- Type primitives -------------------------------------------- */
.pa-display {
  font-family: var(--pa-font-display);
  font-weight: 400;
  font-size: var(--pa-step-5);
  line-height: var(--pa-lh-tight);
  letter-spacing: -0.018em;
  margin: 0;
  text-wrap: balance;
}
.pa-display--sm { font-size: var(--pa-step-4); }
.pa-h2 {
  font-family: var(--pa-font-display);
  font-weight: 400;
  font-size: var(--pa-step-3);
  line-height: var(--pa-lh-snug);
  letter-spacing: -0.012em;
  margin: 0;
  text-wrap: balance;
}
.pa-lede {
  font-size: var(--pa-step-1);
  line-height: 1.45;
  max-width: 46ch;
  margin: 0;
  color: var(--pa-text-muted);
  text-wrap: pretty;
}
.pa-body { max-width: var(--pa-measure); margin: 0; text-wrap: pretty; }
.pa-eyebrow {
  font-family: var(--pa-font-mono);
  font-size: var(--pa-step--1);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--pa-text-muted);
  margin: 0;
}
/* Used sparingly. In the direction it appears exactly once, as an aside. */
.pa-script {
  font-family: var(--pa-font-script);
  font-size: var(--pa-step-1);
  letter-spacing: 0.02em;
  color: var(--pa-text);
}

/* ---- Wordmark ---------------------------------------------------- */
/* The MARK (the X symbol) is undecided and is NOT drawn here. This slot
   is reserved and renders nothing until a decision lands; the wordmark
   carries identity on its own in the meantime. Do not fill this with a
   stand-in glyph — a placeholder mark read as a real one is exactly how
   an undecided symbol becomes decided by accident. */
.pa-mark { display: none; }
.pa-wordmark {
  font-family: var(--pa-font-body);
  font-weight: 650;
  font-size: var(--pa-step-1);
  letter-spacing: -0.02em;
  color: var(--pa-text);
  text-decoration: none;
  display: inline-flex;
  align-items: center;
  gap: var(--pa-s2);
  min-height: 44px;   /* it is a link home, so it needs a real hit area too */
}

/* ---- Actions — orange is the act -------------------------------- */
.pa-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--pa-s2);
  min-height: 48px;                     /* comfortable touch target */
  padding: 0 var(--pa-s5);
  font: inherit;
  /* 19px/700 is not a style choice, it is the AA boundary -- see note above. */
  font-size: 1.1875rem;
  font-weight: 700;
  letter-spacing: -0.005em;
  color: var(--pa-action-text);
  background: var(--pa-action);
  border: 1px solid var(--pa-action);
  border-radius: var(--pa-radius-sm);
  cursor: pointer;
  text-decoration: none;
  transition: transform .18s var(--pa-ease), filter .18s var(--pa-ease);
}
.pa-btn:hover { filter: brightness(1.06); }
.pa-btn:active { transform: translateY(1px); }
.pa-btn:focus-visible { outline: 3px solid var(--pa-accent); outline-offset: 3px; }

.pa-btn--ghost {
  color: var(--pa-text);
  background: transparent;
  border-color: var(--pa-hair);
}
.pa-btn--ghost:hover { border-color: var(--pa-text); filter: none; }

/* ---- The mosaic -------------------------------------------------
   The signature visual: a grid of rounded tiles in orange and magenta.
   Built as a CSS grid of empty spans so it needs no image asset, no
   network request, and scales to any container. Tile colour is applied
   by juwel mosaic JS (deterministic, fixed seed) or by nth-child
   fallbacks below so it is never blank with JS off. */
.pa-mosaic {
  display: grid;
  grid-template-columns: repeat(var(--pa-mosaic-cols, 12), minmax(0, 1fr));
  gap: var(--pa-tile-gap);
  width: 100%;
  /* NO aspect-ratio here on purpose. Constraining the container's height AND
     giving each tile aspect-ratio:1 fights: the row box ends up taller than the
     square tile inside it and the grid reads as stripes with gutters between
     rows. Letting the height fall out of (cell width x row count) keeps the
     tiles touching, which is what makes it read as one mass. */
}
.pa-mosaic i {
  display: block;
  aspect-ratio: 1;
  border-radius: var(--pa-tile-radius);
  background: transparent;
}
/* The full-bleed field is the one case that must cover a box of a fixed
   height, so there the tiles stretch instead of staying square. */
.pa-field > .pa-mosaic i { aspect-ratio: auto; height: 100%; }
.pa-mosaic i[data-t="o"] { background: var(--pa-orange); }
.pa-mosaic i[data-t="m"] { background: var(--pa-accent); }
/* JS-off fallback: still reads as the brand rather than an empty box. */
.pa-mosaic:not([data-painted]) i:nth-child(3n+1)  { background: var(--pa-orange); }
.pa-mosaic:not([data-painted]) i:nth-child(4n+2)  { background: var(--pa-accent); }

/* A mosaic used as a field behind content.
   Layering is done with POSITIVE z-index on both children rather than pushing
   the art to z-index:-1. A negative-z child inside an `isolation:isolate`
   stacking context did not paint at all here -- the section rendered as an
   empty band while the DOM and geometry both measured correct, which is the
   worst kind of bug to debug. Two positive layers cannot do that. */
.pa-field { position: relative; overflow: hidden; background: var(--pa-black); }
.pa-field > .pa-mosaic {
  position: absolute; inset: 0; z-index: 0; height: 100%;
  grid-auto-rows: 1fr;   /* rows share the height, so the field always covers */
}
.pa-field > .pa-wrap { position: relative; z-index: 1; }

/* ---- Quote card, as in the direction ---------------------------- */
.pa-quote {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--pa-s5);
  max-width: 760px;
  margin-inline: auto;
  padding: var(--pa-s6) var(--pa-s7);
  background: var(--pa-cream);
  color: var(--pa-black);
  border-radius: var(--pa-radius-lg);
  box-shadow: 0 18px 60px rgb(0 0 0 / 0.18);
}
.pa-quote p {
  font-family: var(--pa-font-display);
  font-size: var(--pa-step-2);
  line-height: var(--pa-lh-snug);
  letter-spacing: -0.01em;
  margin: 0;
  text-wrap: balance;
}

/* ---- Layout helpers --------------------------------------------- */
.pa-split {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--pa-s8);
  align-items: center;
}
@media (min-width: 900px) {
  .pa-split { grid-template-columns: 1.15fr 0.85fr; gap: var(--pa-s9); }
}
.pa-stack > * + * { margin-top: var(--pa-s5); }

/* A headline that should cross both columns of a .pa-split. Without this the
   hero sets 33 characters of 90px serif inside a ~600px column and wraps to
   four ragged lines. */
.pa-span-all { grid-column: 1 / -1; }
@media (min-width: 900px) { .pa-hero-copy { max-width: 46ch; } }
.pa-rule { height: 1px; background: var(--pa-hair); border: 0; margin: 0; }

/* ---- Accessibility ---------------------------------------------- */
.pa-sr {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap;
}
.pa :focus-visible { outline: 3px solid var(--pa-accent); outline-offset: 2px; }

@media (prefers-reduced-motion: reduce) {
  .pa *, .pa *::before, .pa *::after {
    animation-duration: .001ms !important;
    transition-duration: .001ms !important;
  }
}

/* ---- Navigation links ------------------------------------------------
   Measured at 375px: bare inline links rendered 20px tall, well under the
   44px minimum touch target, and the header nav wrapped "Open source" onto
   two lines in a 40px-wide box. These rules give every nav/footer link a
   real hit area and let the header nav wrap as a row instead of squeezing. */
.pa-nav {
  display: flex;
  align-items: center;
  gap: var(--pa-s3);
  flex-wrap: wrap;
  justify-content: flex-end;
  font-size: var(--pa-step--1);
}
.pa-nav a, .pa-navlink {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding-inline: var(--pa-s2);
  color: var(--pa-text-muted);
  text-decoration: none;
  white-space: nowrap;
}
.pa-nav a:hover, .pa-navlink:hover { color: var(--pa-text); }
.pa-nav a.pa-btn { color: var(--pa-action-text); padding-inline: var(--pa-s4); }

@media (max-width: 560px) {
  /* Stack the header so the wordmark keeps its line and the nav gets its own. */
  .pa-header { flex-wrap: wrap; row-gap: var(--pa-s2); }
  .pa-nav { width: 100%; justify-content: flex-start; }
}
