/* ============================================================================
   JULES  ·  V3 ELEVATION LAYER  ·  return 3, 24 Aug 2026

   Loads after jules-v3-tokens.css. TOKEN REFERENCES ONLY, no literals.

   THE INTEGRATION IS ONE CLASS. Every rule is scoped under .jv, so the
   current product is untouched until a template adds class="jv" to <body>
   (beside the existing j-frame). Removing the class restores return 2
   exactly. Three files ship the whole overhaul:
     css/jules-v3-tokens.css   css/jules-v3.css   js/jules-presence.js

   WHAT THIS LAYER DOES
     1  Material: panels gain machined depth, not glass. Sheen, bevel, lift.
     2  Hierarchy: every page opens with a masthead register.
     3  Presence: the mounts jules-presence.js fills.
     4  Arrival: one staggered rise per session, then the page settles.
     5  Restraint: nothing here moves beside a decision.
   ========================================================================== */

/* --- 1. MATERIAL ---------------------------------------------------------- */

.jv .k-panel,
.jv .j-card {
  background-color: var(--ink);
  background-image: var(--mat-sheen);
  box-shadow: var(--mat-lift);
}
.jv .k-panel::before { background: var(--mat-edge-lit); }

.jv .k-raised {
  background-image: linear-gradient(180deg, rgba(255,255,255,0.02), rgba(255,255,255,0) 55%);
  box-shadow: 0 1px 0 rgba(255,255,255,0.035) inset;
}

/* A well: where the record itself sits. Email bodies, evidence, payslips. */
.jv .k-sunken, .jv .jv-well {
  background: var(--void);
  border: 1px solid var(--line-soft);
  border-radius: var(--r-ctl);
  box-shadow: var(--mat-well);
}

/* The one decision on the page keeps its olive edge and now carries weight. */
.jv .k-decision { box-shadow: inset 3px 0 0 var(--olive); border-left: 0; padding-left: var(--s5); }

/* Header: the fixed instrument rail. A lit hairline, not a glow. */
.jv .k-header {
  background: linear-gradient(180deg, color-mix(in oklab, var(--carbon) 96%, white), var(--carbon));
  border-bottom: 1px solid var(--line-strong);
  box-shadow: 0 1px 0 rgba(255,255,255,0.03), 0 12px 32px -24px rgba(0,0,0,0.8);
}

.jv .j-rail { background: linear-gradient(90deg, var(--carbon), color-mix(in oklab, var(--carbon) 88%, var(--void))); }
.jv .j-navitem { transition: background var(--d-ui) var(--e-out), color var(--d-ui) var(--e-out); }
.jv .j-navitem[aria-current="page"] {
  background: linear-gradient(90deg, color-mix(in oklab, var(--raised) 92%, var(--olive)), var(--raised));
  box-shadow: inset 3px 0 0 var(--olive), 0 1px 0 rgba(255,255,255,0.04) inset;
}

.jv .j-mob {
  background: color-mix(in oklab, var(--carbon) 92%, black);
  box-shadow: 0 -14px 30px -20px rgba(0,0,0,0.85), 0 1px 0 rgba(255,255,255,0.04) inset;
}

/* Tables and row stacks: hairline discipline, deeper hover, top bevel. */
.jv .jx-person-row:hover,
.jv .j-step:hover { background: color-mix(in oklab, var(--ink) 88%, var(--raised)); }

/* --- 2. THE MASTHEAD REGISTER ---------------------------------------------
   Every page opens the same way: kicker, page name, one supporting line,
   and the presence on the right. The date is machine fact, so it is mono. */

.jv .jv-mast {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: var(--s3) var(--s5);
  align-items: center;
  padding-bottom: var(--s4);
  border-bottom: 1px solid var(--line);
  position: relative;
}
/* the settle mark: one short lit segment on the baseline, where the presence
   sits. Not the seam. The seam stays one per composition, at the join. */
.jv .jv-mast::after {
  content: "";
  position: absolute;
  right: 0; bottom: -1px;
  width: 132px; height: 1px;
  background: linear-gradient(to left, var(--human-38), transparent);
  pointer-events: none;
}
.jv .jv-mast-body { display: grid; gap: 6px; min-width: 0; }
.jv .jv-kicker {
  margin: 0;
  font-family: var(--font-mono);
  font-size: var(--t-kicker);
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--sage);
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
}
.jv .jv-kicker b { color: var(--sand); font-weight: 400; }
.jv .jv-kicker::before {
  content: "";
  width: 7px; height: 7px; flex: none;
  background: var(--human-24);
  border: 1px solid var(--human-38);
  transform: rotate(45deg);
}
.jv .jv-title {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--t-page);
  line-height: 1.02;
  letter-spacing: -0.022em;
  color: var(--sand);
}
.jv .jv-sub { margin: 2px 0 0; font-size: 14px; line-height: 1.55; color: var(--sage); max-width: 64ch; }
.jv .jv-mast-side { display: flex; align-items: center; gap: var(--s4); }

/* --- 3. SECTION REGISTER --------------------------------------------------
   Inside panels: a machined label row. Label left, count or link right. */
.jv .jv-sect {
  display: flex; align-items: center; gap: 10px;
  padding-bottom: 10px;
  border-bottom: 1px solid var(--line-soft);
  margin-bottom: var(--s4);
}
.jv .jv-sect > .k-label { font-size: var(--t-section); color: var(--sage); }
.jv .jv-sect::before { content: ""; width: 3px; height: 12px; background: var(--edge); flex: none; }
.jv .jv-sect[data-live]::before { background: var(--olive-lift); }
.jv .jv-sect[data-ask]::before { background: var(--amber); }
.jv .jv-sect > .jv-count {
  margin-left: auto;
  font-family: var(--font-mono); font-size: 11px; letter-spacing: 0.1em;
  color: var(--sage); font-variant-numeric: tabular-nums;
}

/* A fact register: numbers a decision reads. */
.jv .jv-fact { font-family: var(--font-mono); font-weight: 700; font-size: var(--t-fact); letter-spacing: -0.01em; font-variant-numeric: tabular-nums; color: var(--sand); }
.jv .jv-fact--lg { font-size: var(--t-fact-lg); }
.jv .jv-fact small { font-size: 0.55em; font-weight: 400; color: var(--sage); letter-spacing: 0.08em; }

/* --- 4. THE PRESENCE MOUNTS ------------------------------------------------
   jules-presence.js draws the portrait, ring and state word. These rules
   only size and place the mounts. One WebGL context per page, at most. */

.jv jules-presence { display: block; }
.jv jules-presence[variant="masthead"] { width: var(--pres-mast); height: var(--pres-mast); }
.jv jules-presence[variant="rail"] { width: var(--pres-rail); height: var(--pres-rail); }
.jv jules-presence[variant="empty"] { width: var(--pres-empty); height: var(--pres-empty); }
.jv jules-presence[variant="static"] { width: var(--pres-rail); height: var(--pres-rail); }

/* the rail card, upgraded: presence + word, still one card */
.jv .jv-rail-presence {
  display: flex; align-items: center; gap: 12px;
  padding: 12px;
  background: var(--raised);
  background-image: var(--mat-sheen);
  border: 1px solid var(--line);
  border-radius: var(--r-ctl);
  box-shadow: 0 1px 0 rgba(255,255,255,0.035) inset;
}
.jv .jv-rail-presence b {
  font-family: var(--font-display); font-weight: 800; font-size: 15px;
  letter-spacing: -0.03em; color: var(--sand);
}

/* the empty state: what is absent, why, and what fills it. Presence settles
   here because an empty desk is the one place her stillness IS the message. */
.jv .jv-empty {
  display: grid; justify-items: center; gap: var(--s4);
  padding: var(--s7) var(--s5) var(--s7);
  text-align: center;
}
.jv .jv-empty > h2 {
  margin: 0; font-family: var(--font-display); font-weight: 700;
  font-size: 22px; letter-spacing: -0.015em; color: var(--sand);
}
.jv .jv-empty > p { margin: 0; font-size: 14px; line-height: 1.6; color: var(--sage); max-width: 44ch; }

/* --- 5. ARRIVAL ------------------------------------------------------------
   jules-presence.js sets data-jv-arrive on <body> once per session. Sections
   rise once and settle. Nothing loops. Nothing moves after 900ms. */

@keyframes jv-arrive {
  from { opacity: 0; transform: translateY(var(--arrive-rise)); }
  to   { opacity: 1; transform: none; }
}
.jv[data-jv-arrive] .jx-main > * {
  animation: jv-arrive var(--d-arrive) var(--e-out) both;
}
.jv[data-jv-arrive] .jx-main > *:nth-child(2) { animation-delay: var(--arrive-stagger); }
.jv[data-jv-arrive] .jx-main > *:nth-child(3) { animation-delay: calc(var(--arrive-stagger) * 2); }
.jv[data-jv-arrive] .jx-main > *:nth-child(4) { animation-delay: calc(var(--arrive-stagger) * 3); }
.jv[data-jv-arrive] .jx-main > *:nth-child(5) { animation-delay: calc(var(--arrive-stagger) * 4); }
.jv[data-jv-arrive] .jx-main > *:nth-child(n+6) { animation-delay: calc(var(--arrive-stagger) * 5); }

/* State change on a row: work confirmed or complete. One pulse, then still. */
@keyframes jv-settle {
  0% { background-color: color-mix(in oklab, var(--ink) 82%, var(--olive-lift)); }
  100% { background-color: var(--ink); }
}
.jv [data-jv-settled] { animation: jv-settle 900ms var(--e-out) 1; }

/* Buttons: restrained, fast. Press feedback exists and is 90ms. */
.jv .k-btn { box-shadow: 0 1px 0 rgba(255,255,255,0.05) inset, 0 2px 6px -2px rgba(0,0,0,0.5); }
.jv .k-btn--primary { box-shadow: 0 1px 0 rgba(255,255,255,0.18) inset, 0 6px 16px -8px rgba(0,0,0,0.7); }
.jv .k-btn--quiet, .jv .k-btn--ghost { box-shadow: none; }

/* --- 6. RESTRAINT ----------------------------------------------------------
   Reduced motion: the arrival composes one frame, the settle pulse is a
   steady state, and jules-presence.js draws its still. Nothing is lost. */
@media (prefers-reduced-motion: reduce) {
  .jv[data-jv-arrive] .jx-main > * { animation: none; }
  .jv [data-jv-settled] { animation: none; }
}

/* At 390 the masthead keeps one row: presence shrinks, title wraps. */
@media (max-width: 767px) {
  .jv .jv-mast { grid-template-columns: minmax(0, 1fr) auto; padding-bottom: var(--s3); }
  .jv .jv-mast::after { width: 84px; }
  .jv .jv-sub { font-size: 13px; }
  /* A side that carries a wide control (the board's openings filter) takes its
     own row under the title instead of sitting over the subtitle. */
  .jv .jv-mast-side--stack { grid-column: 1 / -1; justify-content: flex-start; }
}

/* --- 7. THE CONTAINER CONTRACT, RESTORED -----------------------------------
   jules-components.css declares that .j-frame's width IS the viewport width,
   so a container query and a media query say the same thing. jules-app.css
   broke that contract with viewport media queries. This block restates those
   breakpoints as container queries under .jv, so a framed composition (a
   review board, a storyboard, a design sheet) behaves truthfully at any
   width. In production both fire together and agree. */
@container (max-width: 1023px) {
  .jv .j-rail { display: none !important; }
}
@container (max-width: 1100px) {
  .jv .jx-cols { grid-template-columns: minmax(0, 1fr); }
}
@container (max-width: 860px) {
  .jv .jx-person-row { grid-template-columns: 34px minmax(0, 1fr) auto; }
  .jv .jx-person-row > .jx-hide-md { display: none; }
  .jv .jx-seam { flex-direction: column; min-height: 0; }
  .jv .jx-seam-half + .jx-seam-half { padding-left: 18px; border-top: 1px solid var(--line); }
  .jv .jx-seam-mark { display: none; }
}
@container (max-width: 767px) {
  .jv [data-jx="hide-sm"] { display: none !important; }
  .jv .jx-main { padding-bottom: 84px; }
  .jv .j-mob { display: flex !important; position: fixed; left: 0; right: 0; bottom: 0; z-index: 50; }
  .jv .jx-board { flex-wrap: wrap; overflow-x: visible; }
  .jv .jx-board-col { width: 100%; }
  .jv .j-answers { grid-template-columns: minmax(0, 1fr); }
  .jv .jx-app { --pres-mast: 56px; --pres-empty: 128px; --t-fact: 19px; --pad: 16px; }
  .jv .jv-mast::after { width: 84px; }
  .jv .jv-mast-side--stack { grid-column: 1 / -1; justify-content: flex-start; }
}
@container (max-width: 620px) {
  .jv .jx-pay-approval { grid-template-columns: minmax(0, 1fr); }
  .jv .jx-pay-approval .k-btn { justify-content: center; width: 100%; }
}
