/* ============================================================
   THE MOSAIC — a parchment reading sheet that floats over the hub.

   Ported from the claude.ai/design project "Trading$yphers"
   (Perspectivas.html + frames.jsx + app.jsx) into vanilla CSS/JS.
   Clicking a journey link no longer ejects you from the hub: the
   reading opens ON TOP of the world you are already in, covering
   the header, sized to its own content, and draggable.

   Never labelled "essay" in the UI — it is the Mosaic.

   The border is NOT drawn here. js/mosaic.js generates it as an
   SVG path per rendered pixel size (ResizeObserver), which is what
   makes "only as big as needed" true — a fixed 9-slice border or a
   background image could not follow the content.

   Language: the sheet carries the essay's own `.l-pt`/`.l-en`
   pairs, hidden by the SAME `<html data-lang>` state js/lang.js
   sets from the site-wide `ts-lang` preference (essay.css:25-26).
   No third mechanism — the rules are only re-scoped to `.mosaic`
   so nothing else on the hub is affected.
   ============================================================ */

.mosaic {
  /* the paper */
  --paper1: #f7ecd2;
  --paper2: #e8d6ac;
  --ink:    #3d3020;
  --rubric: #b23a2e;         /* the close mark, and the rubricated caps */

  /* the frame's breathing room — the four treatments differ, and
     js/mosaic.js reads these back to derive its geometry insets, so
     changing a pad here moves the drawing with it. */
  --pad-x: 76px;
  --pad-y: 86px;

  position: fixed;
  inset: 0;
  /* above #site-chrome (40), #portal (400) and the mobile layer (9960,
     assets/ts-mobile.css) — its bottom-right companion diamond otherwise
     lands on top of the Water cipher at 375px. `aria-modal="true"` means
     nothing may sit over the sheet while it is open. */
  z-index: 10000;
  display: none;
}
.mosaic.on { display: block; }

/* ---------- hosted on a takeover page ----------
   js/mosaic.js sets this when it finds itself ON one of its own seven routes
   (arrived at by URL, bookmark, search result or another page's chrome). The
   page still SERVES its full content — that is what keeps it indexable, and it
   is what a reader sees if JS never runs — but once the sheet is up, the dark
   page underneath is hidden rather than left showing through the scrim.

   `visibility: hidden` and not `display: none` on purpose: the host page keeps
   its layout and its scroll height, so nothing reflows underneath, and the
   host's own scripts (a scrollspy, a reveal observer) keep operating on boxes
   that still have geometry instead of collapsing to zero and misbehaving. */
html[data-mosaic="hosted"],
html[data-mosaic="hosted"] body { overflow: hidden; }
html[data-mosaic="hosted"] body > *:not(.mosaic) { visibility: hidden; }

/* On paper the host document is what the reader actually asked for. Without
   this, printing a hosted page inherits a position:fixed, max-height-capped
   scroll box and the whitepaper prints one clipped screenful instead of its
   34 000 characters. Scoped to hosted, so printing the hub is unchanged. */
@media print {
  html[data-mosaic="hosted"],
  html[data-mosaic="hosted"] body { overflow: visible; }
  html[data-mosaic="hosted"] body > *:not(.mosaic) { visibility: visible; }
  html[data-mosaic="hosted"] .mosaic { display: none; }
}

/* ---------- the scrim ---------- */
.mo-scrim {
  position: absolute;
  inset: 0;
  background: rgba(4, 6, 10, 0.74);
  -webkit-backdrop-filter: blur(7px);
  backdrop-filter: blur(7px);
}

/* ---------- the anchor (centring + drag) ----------
   Two boxes on purpose: the anchor owns the position transform the
   drag writes into, the sheet owns the entrance animation. One
   element could not hold both without the rise fighting the drag. */
.mo-anchor {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(calc(-50% + var(--dx, 0px)), calc(-50% + var(--dy, 0px)));
  /* touch-action:none saiu daqui (mobile v1.3): a touch-action efetiva é a
     INTERSEÇÃO pela cadeia de ancestrais, e um none no anchor anulava o pan
     do .mo-body — a leitura não rolava ao dedo. O drag por mouse não depende
     de touch-action; o resize (.mo-size) mantém o próprio none. */
  /* No ring any more. It existed because the ciphers and the close mark hung
     15-16px outside the sheet and the drag clamp — which measures the anchor —
     would otherwise have pushed them off screen. The mark is gone and the
     ciphers moved inside, so the anchor's box is the sheet's box, and the 32px
     the ring cost the reading (see .mo-body) goes back to the reading. */
  padding: 0;
}

.mo-sheet {
  position: relative;
  /* 62vw is the design's sheetWidth. The 860px cap is NOT the design's — it
     caps at 1020px — and the divergence is deliberate: the design's reading is
     a hand-authored six-paragraph piece, ours is up to ~35 000 characters of
     continuous prose. At 1920 the measure here is already ~100 characters per
     line; 1020px would take it past 120. Height is where this sheet is allowed
     to grow (see .mo-body); width is where the reading would get worse. */
  width: clamp(300px, 62vw, 860px);
  cursor: grab;
}
.mosaic[data-dragging] .mo-sheet { cursor: grabbing; }

/* ---------- the paper ---------- */
.mo-paper {
  position: relative;
  border-radius: 2px;
  background: radial-gradient(120% 90% at 22% 12%, var(--paper1), var(--paper2) 78%, #c9b184);
  /* The design's exact stack. The -20px spread on the outer layer is the point:
     it pulls the halo into a tight band at the paper's edge instead of spilling
     it across the scrim, which is the only way the edge separates from a dark
     backdrop — and it keeps the halo from reaching the close mark and the two
     top ciphers, which sit on clean scrim. */
  box-shadow:
    0 40px 90px -20px rgba(0, 0, 0, 0.72),
    0 4px 14px rgba(0, 0, 0, 0.4),
    inset 0 0 70px rgba(122, 94, 52, 0.22);
  padding: var(--pad-y) var(--pad-x);
  overflow: hidden;
}

/* the fibre. An inline SVG data URI, so the sheet is self-contained —
   there is no asset to host and nothing to 404 on a cold cache. */
.mo-paper::after {
  content: '';
  position: absolute;
  inset: 0;
  pointer-events: none;
  border-radius: inherit;
  /* the design's four numbers: .85 / 3 / rect .5 / layer .14 — a coarser,
     lighter fibre than the port had been mixing at .82 / 4 / — / .17 */
  opacity: 0.14;
  mix-blend-mode: multiply;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='200' height='200' filter='url(%23n)' opacity='.5'/%3E%3C/svg%3E");
}

/* ---------- the frame ---------- */
.mo-frame {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  z-index: 2;
  overflow: visible;
}
.mo-frame path {
  fill: none;
  stroke: var(--ink);
  stroke-width: 1.05;
  stroke-linecap: round;
  stroke-linejoin: round;
  opacity: 0.78;
}
.mo-frame path.mo-fill {         /* the quadrant's corner dots */
  fill: var(--ink);
  stroke: none;
}

/* ONE treatment — the lectures flow IS the flourish (operator, 2026-08-10;
   the quadrant became the Console's circuit, js/syswin.js). Pads only;
   the drawing lives in js/mosaic.js. */
.mosaic[data-frame="flourish"] { --pad-x: 76px; --pad-y: 86px; }

/* ---------- the two skins ----------
   The paper colour belongs to the READING, not to the reader: papiro for
   the journeys, pure white for the whitepaper — the white paper reads on
   white. Same ink either way: the parchment browns hold 10:1+ on both
   grounds, so the flow stays one voice. */
.mosaic[data-skin="white"] {
  --paper1: #ffffff;
  --paper2: #e9ebf0;
}
.mosaic[data-skin="white"] .mo-paper {
  background: radial-gradient(120% 90% at 22% 12%, var(--paper1), var(--paper2) 82%, #d4d7de);
  box-shadow:
    0 40px 90px -20px rgba(0, 0, 0, 0.72),
    0 4px 14px rgba(0, 0, 0, 0.4),
    inset 0 0 70px rgba(120, 126, 140, 0.14);
}
.mosaic[data-skin="white"] .mo-paper::after { opacity: 0.08; }

/* ---------- the four corners ----------
   Navigation, not election (operator, 2026-08-10). Three parchment discs
   carry the flow's OTHER three readings as monograms — T · M · D · ◈ —
   and the top-right disc is the index, the level the old back mark
   reached. The current reading is simply not dealt, which is how a
   corner says where you are. */
.mo-cipher {
  position: absolute;
  z-index: 4;
  /* the disc scales with the frame's pads and stops at the design's 30px, so
     it shrinks with the gutter it lives in instead of overrunning it at 375px */
  --cipher: clamp(22px, calc(var(--pad-x) * 0.395), 30px);
  width: var(--cipher);
  height: var(--cipher);
  padding: 0;
  border: 1px solid rgba(61, 48, 32, 0.34);
  border-radius: 999px;
  background: linear-gradient(180deg, var(--paper1), var(--paper2));
  color: var(--ink);
  font-family: 'Cinzel', Georgia, serif;
  font-weight: 600;
  font-size: calc(var(--cipher) * 0.4);
  line-height: 1;
  cursor: pointer;
  /* an inlay's shadow, not a badge's */
  box-shadow: 0 1px 3px rgba(61, 48, 32, 0.28);
  transition: transform 200ms cubic-bezier(.2, .8, .25, 1),
              box-shadow 200ms ease, color 200ms ease, border-color 200ms ease;
}
/* hit-area de toque: 44px invisíveis em volta do disco — a 22px (≤720)
   os cantos são a navegação inteira da folha e ficavam metade do mínimo */
.mo-cipher::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: 44px;
  height: 44px;
  transform: translate(-50%, -50%);
  border-radius: 999px;
}
.mo-cipher:hover,
.mo-cipher:focus-visible { transform: scale(1.14); border-color: var(--rubric); color: var(--rubric); }
.mo-cipher:focus-visible { outline: 2px solid var(--rubric); outline-offset: 2px; }
/* the index corner speaks in lines, not letters */
.mo-index-c { font-family: 'Barlow', system-ui, sans-serif; font-weight: 400; }

/* Inset off the PADS, not off a constant: the drawing scales by
   k = pad/design-pad, so an inset in the same currency keeps the same
   relationship at every width. At 76 × 86 the lower discs sit 21 × 22 from
   the corner — left of where the bottom scroll wave begins (x = 63.5, k = 1).
   The top pair sits nearer the edge (0.14) to clear the top wave at y = 52
   AND the centred PT · EN above it. */
.mo-cipher[data-at="tl"] { top: calc(var(--pad-y) * 0.14); left: calc(var(--pad-x) * 0.28); }
.mo-cipher[data-at="tr"] { top: calc(var(--pad-y) * 0.14); right: calc(var(--pad-x) * 0.28); }
.mo-cipher[data-at="bl"] { bottom: calc(var(--pad-y) * 0.26); left: calc(var(--pad-x) * 0.28); }
.mo-cipher[data-at="br"] { bottom: calc(var(--pad-y) * 0.26); right: calc(var(--pad-x) * 0.28); }

/* ---------- the size corner ----------
   The very tip of the paper, below the BR disc — dragging it grows the
   sheet on BOTH sides at once (the anchor centres it), and the reading's
   ceiling with it. js/mosaic.js remembers the reader's choice. */
.mo-size {
  position: absolute;
  right: 1px;
  bottom: 1px;
  z-index: 5;
  width: 22px;
  height: 22px;
  padding: 4px;
  border: none;
  background: none;
  color: rgba(61, 48, 32, 0.4);
  cursor: nwse-resize;
  touch-action: none;
  transition: color 180ms ease;
}
.mo-size:hover { color: rgba(61, 48, 32, 0.85); }
.mo-size:focus-visible { outline: 2px solid var(--rubric); outline-offset: 2px; }
.mo-size svg { display: block; width: 14px; height: 14px; }
.mo-size path { fill: none; stroke: currentColor; stroke-width: 1.4; stroke-linecap: round; }

/* ---------- the reading ---------- */
.mo-body {
  position: relative;
  z-index: 1;
  /* o dedo rola a leitura (par do touch-action removido do .mo-anchor) */
  touch-action: pan-y;
  /* THE SIZING LAW. The design's is `max(220px, calc(94vh - 2 × padY))`
     (app.jsx) — 220px is a FLOOR on a term with no ceiling. The port had
     inverted it into a 660px CAP, which bound on every viewport taller than
     ~938px: at 1440×1080 every reading got the same 660px window whatever its
     length, and the whitepaper showed 5% of itself while 280px of screen sat
     empty. A flat `- 34px` also meant the elected frame changed the PAPER's
     height and gave the reader nothing back.

     Restoring `2 × var(--pad-y)` makes the sheet's footprint constant and lets
     a slimmer frame hand its saved padding to the reading — so clicking a
     corner cipher now means something. The port's extra `- 32px` paid for a
     16px .mo-anchor ring that no longer exists (2026-08-10), so the law is now
     the design's exactly. */
  max-height: max(220px, calc(94vh - 2 * var(--pad-y)));
  overflow-y: auto;
  overscroll-behavior: contain;     /* the hub behind must not scroll */
  scrollbar-width: thin;
  scrollbar-color: rgba(61, 48, 32, 0.4) transparent;
  /* the first and last 14px dissolve into the paper */
  -webkit-mask-image: linear-gradient(to bottom, transparent 0, #000 14px, #000 calc(100% - 14px), transparent 100%);
  mask-image: linear-gradient(to bottom, transparent 0, #000 14px, #000 calc(100% - 14px), transparent 100%);
  color: #3b2f1d;
  font-family: 'EB Garamond', 'Playfair Display', Georgia, serif;
  font-size: 1.02rem;
  line-height: 1.66;
  cursor: auto;                     /* the drag ignores this subtree */
}
.mo-body:focus { outline: none; }
.mo-body::-webkit-scrollbar { width: 6px; }
.mo-body::-webkit-scrollbar-track { background: transparent; }
.mo-body::-webkit-scrollbar-thumb {
  background: rgba(61, 48, 32, 0.34);
  border-radius: 999px;
}

/* Inheritance, stated. Element children inside the reading were resolving to
   the hub's `body` font (styles.css:22 · Inter) instead of the family their
   own parent sets — so a journey title, whose text lives inside `.l-pt`/`.l-en`
   spans, rendered in Inter while its heading was Cinzel; likewise `.kw` inside
   a package name and `<strong>` inside a formula. Every family rule below is
   at least as specific and comes later, so each still wins for its own element
   — this only fixes what its children do. */
.mo-body * { font-family: inherit; }

/* ═══════ CONTAINMENT ═══════
   Hosted on a takeover page, that page's OWN stylesheet is live alongside this
   one — and those sheets were written for a dark register. Their unscoped
   bare-tag rules land inside the reading and paint it for the wrong surface:
   `strong { color: #fff }` (whitepaper.css:131 · sinais.css:140 ·
   solucoes.css:85) alone turns 204 words across the site into white-on-cream,
   i.e. invisible. `em`, `code`, `th`, `td`, `blockquote` and the neon keyword
   colours do the same in their own way.

   So the sheet re-asserts its own surface. Every selector here is (0,1,1) or
   better, which beats a bare tag's (0,0,1) without an !important anywhere. On
   the hub none of those sheets are loaded and this whole block is a no-op —
   it costs nothing and it means the sheet is self-contained wherever it opens.

   This is deliberately a LIST OF TAGS, not a reset: the walk emits a known
   vocabulary, and anything new it starts emitting must be added here too. */
.mo-body strong,
.mo-body b        { color: inherit; font-weight: 600; white-space: normal; }
.mo-body em       { color: #6b4a1c; font-style: italic; }
.mo-body a        { background: none; }

/* `:where()`, NOT a bare compound — this one line is load-bearing.
   The hub's baseline for these tags is styles.css:17's `*{margin:0}`, so the
   containment value is 0, not a design number. And the specificity must STAY
   at (0,1,0): enough to beat a host sheet's bare `p{margin:0 0 18px}` (0,0,1),
   never enough to beat the sheet's OWN .mo-lede / .mo-mark / .mo-note /
   .mo-ref / .mo-meta / .mo-verse / .mo-eyebrow / .mo-cta / .mo-index-title /
   .mo-index-group, which are all (0,1,0) and come later. Written as a (0,1,1)
   compound it silently outranks all ten — on every page, the hub included. */
.mo-body :where(p, ul, ol, li) { margin: 0; }
.mo-body h2,
.mo-body h3       { padding-top: 0; border-top: none; background: none; }
.mo-body h3       { letter-spacing: normal; }

/* inline chips — the dark pages give these a filled block and a border */
.mo-body code,
.mo-body .opset,
.mo-body .glyph-inline {
  background: none;
  border: none;
  border-radius: 0;
  padding: 0;
}
.mo-body .opset {                       /* the sheet's own treatment, restated */
  padding: 0 4px;
  color: var(--rubric);
  background: rgba(178, 58, 46, 0.09);
  border-radius: 2px;
}
.mo-body .glyph-inline { color: var(--rubric); letter-spacing: 0.06em; }

/* The tier keywords are neon on #05070c — 1.3-2.5:1 on parchment, the green
   effectively invisible. `inherit` rather than a new colour, because the hub
   never loads sinais.css and already renders these words in the heading's ink:
   this is what makes the same reading look the same however you arrived. */
.mo-body .kw,
.mo-body .kw-d,
.mo-body .kw-m,
.mo-body .kw-t    { color: inherit; }

/* tables: bottom rules only, brown ink — never the dark page's full grid */
.mo-body table    { min-width: 0; width: 100%; font-size: inherit; line-height: inherit; }
.mo-body th,
.mo-body td       {
  border: none;
  border-bottom: 1px solid rgba(61, 48, 32, 0.16);
  padding: 7px 12px 7px 0;
  background: none;
  color: inherit;
}
.mo-body th       { color: rgba(61, 48, 32, 0.66); }

.mo-body blockquote {
  background: none;
  border: none;
  border-left: 1px solid rgba(61, 48, 32, 0.32);
  border-radius: 0;
  color: inherit;
  padding: 0 0 0 16px;
}

/* the solutions quad-nav survives into the jump rail carrying its own chrome */
.mo-jump .qn-glyph,
.mo-jump .qn-label,
.mo-jump .qn-el   {
  font-size: inherit;
  font-weight: inherit;
  letter-spacing: inherit;
  text-transform: none;
  color: inherit;
}

/* type — Cinzel is the sheet's revealed voice; it is scoped to
   `.mosaic` on purpose so the hub chrome keeps Barlow/Inter. */
.mo-body :where(h1, h2, h3, .mo-eyebrow, .mo-close, .mo-tier-name, .mo-rung-name) {
  font-family: 'Cinzel', 'Playfair Display', Georgia, serif;
  font-weight: 600;
  color: #2f2515;
}

.mo-eyebrow {
  font-size: 0.62rem;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  color: rgba(61, 48, 32, 0.6);
  margin-bottom: 14px;
}
/* the design tracks its Cinzel headings out (.sh-title .1em, .read h2 .04em);
   h3 is left alone — the design has no h3, and at 0.94rem it sits on prose */
.mo-body h1 { font-size: 1.72rem; line-height: 1.24; letter-spacing: 0.04em; margin: 0 0 12px; }
.mo-body h2 { font-size: 1.16rem; line-height: 1.3; letter-spacing: 0.04em; margin: 30px 0 10px; }
.mo-body h3 { font-size: 0.94rem; line-height: 1.3; margin: 0 0 6px; }
.mo-lede {
  font-size: 1.12rem;
  font-style: italic;
  color: rgba(59, 47, 29, 0.86);
  margin: 0 0 8px;
  text-wrap: pretty;
}
/* prose only — on .mo-body it would inherit into headings, table cells and
   the index entries, where balancing the last line is not wanted */
.mo-p { margin: 0 0 12px; text-wrap: pretty; }
.mo-body em { font-style: italic; color: #6b4a1c; }
.mo-body b, .mo-body strong { font-weight: 600; }

.mo-quote {
  margin: 14px 0 4px;
  padding-left: 16px;
  border-left: 1px solid rgba(61, 48, 32, 0.32);
  font-style: italic;
}
.mo-ref {
  margin: 0 0 14px;
  padding-left: 16px;
  font-size: 0.76rem;
  letter-spacing: 0.06em;
  color: rgba(61, 48, 32, 0.6);
}
.mo-note {
  margin: 10px 0 14px;
  padding: 10px 14px;
  background: rgba(122, 94, 52, 0.09);
  border-radius: 2px;
  font-size: 0.94rem;
}
.mo-body h2.mo-close {
  font-size: 1.24rem;
  text-align: center;
  margin: 34px 0 0;
}
.mo-verse { text-align: center; font-style: italic; margin: 22px 0; font-size: 1.08rem; }

/* the INPUT → PROC → OUTPUT run */
.mo-flow {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  margin: 14px 0;
  font-size: 0.78rem;
}
.mo-flow span { letter-spacing: 0.12em; text-transform: uppercase; }
.mo-flow .k { color: rgba(61, 48, 32, 0.5); }
.mo-flow .sep { color: rgba(61, 48, 32, 0.35); }

/* the three ecards */
.mo-card {
  margin: 14px 0;
  padding: 14px 16px;
  border: 1px solid rgba(61, 48, 32, 0.22);
  border-radius: 2px;
  background: rgba(255, 252, 240, 0.34);
}
.mo-card p { margin: 0; font-size: 0.95rem; }

/* the tier card */
.mo-tier {
  margin: 18px 0;
  padding: 16px 18px;
  border: 1px solid rgba(61, 48, 32, 0.3);
  border-top: 2px solid var(--rubric);
  border-radius: 2px;
  background: rgba(255, 252, 240, 0.42);
}
.mo-tier-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 12px;
  margin-bottom: 10px;
}
.mo-tier-name { font-size: 0.86rem; letter-spacing: 0.2em; text-transform: uppercase; }
.mo-tier-price { font-family: 'JetBrains Mono', monospace; font-size: 0.94rem; color: var(--rubric); }
.mo-tier ul { list-style: none; margin: 0 0 12px; padding: 0; }
.mo-tier li { position: relative; padding-left: 18px; font-size: 0.94rem; margin-bottom: 4px; }
.mo-tier li::before { content: '·'; position: absolute; left: 6px; color: var(--rubric); }

.mo-body a {
  color: #7a3a1c;
  text-decoration: none;
  border-bottom: 1px solid rgba(122, 58, 28, 0.4);
}
.mo-body a:hover { border-bottom-color: #7a3a1c; }
.mo-body a:focus-visible { outline: 2px solid var(--rubric); outline-offset: 2px; }

/* the ladder */
.mo-rung {
  display: grid;
  grid-template-columns: auto 1fr auto;
  gap: 4px 10px;
  align-items: baseline;
  padding: 8px 0;
  border-bottom: 1px solid rgba(61, 48, 32, 0.16);
}
.mo-rung-ic { color: rgba(61, 48, 32, 0.55); }
.mo-rung-name { font-size: 0.82rem; letter-spacing: 0.16em; text-transform: uppercase; }
.mo-rung-price { font-family: 'JetBrains Mono', monospace; font-size: 0.8rem; color: var(--rubric); }
.mo-rung p { grid-column: 2 / -1; margin: 0; font-size: 0.9rem; color: rgba(59, 47, 29, 0.82); }

/* ═══════ what the four paper pages bring ═══════
   Signals, Solutions, App and the Whitepaper carry block shapes the
   journeys never had. Each is re-set in the parchment register here —
   none of their own dark-page CSS crosses over. */

/* the invisible landing point a jump scrolls to */
.mo-at { display: block; height: 0; }

/* `:·: ⟨ terra ⟩` — the element signature over a solutions row */
.mo-mark {
  display: flex;
  align-items: baseline;
  gap: 10px;
  margin: 30px 0 2px;
  font-family: 'JetBrains Mono', monospace;
  font-size: 0.74rem;
  letter-spacing: 0.16em;
  color: rgba(61, 48, 32, 0.5);
}
.mo-mark .g { color: var(--rubric); letter-spacing: 0.1em; }

/* the whitepaper's dateline */
.mo-meta {
  margin: 0 0 16px;
  font-size: 0.76rem;
  letter-spacing: 0.08em;
  color: rgba(61, 48, 32, 0.58);
}

/* d = v · t — set apart, centred, in the data face */
.mo-formula {
  margin: 18px 0;
  padding: 12px 8px;
  text-align: center;
  font-family: 'JetBrains Mono', monospace;
  font-size: 1.02rem;
  letter-spacing: 0.02em;
  color: #2f2515;
  background: rgba(122, 94, 52, 0.07);
  border-top: 1px solid rgba(61, 48, 32, 0.16);
  border-bottom: 1px solid rgba(61, 48, 32, 0.16);
}

/* `[operator-set]` — a value the whitepaper deliberately does not fix */
.mo-body .opset {
  font-family: 'JetBrains Mono', monospace;
  font-size: 0.82em;
  padding: 0 4px;
  color: var(--rubric);
  background: rgba(178, 58, 46, 0.09);
  border-radius: 2px;
}
.mo-body code {
  font-family: 'JetBrains Mono', monospace;
  font-size: 0.88em;
  color: #6b4a1c;
}

.mo-list { margin: 0 0 14px; padding-left: 20px; }
.mo-list li { margin-bottom: 6px; }
.mo-list li::marker { color: rgba(61, 48, 32, 0.45); }

.mo-rule {
  height: 0;
  margin: 26px auto;
  width: 46%;
  border: none;
  border-top: 1px solid rgba(61, 48, 32, 0.24);
}

/* wide tables scroll inside their own box — the sheet never scrolls sideways */
.mo-table {
  margin: 16px 0;
  overflow-x: auto;
  overscroll-behavior-x: contain;
}
.mo-table table { width: 100%; border-collapse: collapse; font-size: 0.86rem; }
.mo-table th,
.mo-table td {
  padding: 7px 12px 7px 0;
  text-align: left;
  vertical-align: top;
  border-bottom: 1px solid rgba(61, 48, 32, 0.16);
}
.mo-table th {
  font-family: 'Cinzel', Georgia, serif;
  font-size: 0.74rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: rgba(61, 48, 32, 0.66);
}

/* the app's five tab cards */
.mo-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  gap: 10px;
  margin: 16px 0;
}
.mo-grid .mo-card { margin: 0; }

/* the signals package rows carry no bullets — the head IS the row */
.mo-tier-flat .mo-tier-head { margin-bottom: 0; }

/* "em estruturação" beside a heading */
.mo-badge {
  margin-left: 10px;
  padding: 2px 8px;
  border: 1px solid rgba(61, 48, 32, 0.3);
  border-radius: 999px;
  font-family: 'Barlow', system-ui, sans-serif;
  font-size: 0.6rem;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: rgba(61, 48, 32, 0.62);
  vertical-align: middle;
}

/* the six-shot storyboard standing in for the intro video */
.mo-shots { margin: 12px 0 18px; padding: 0; list-style: none; }
.mo-shots li {
  display: grid;
  grid-template-columns: auto auto 1fr;
  gap: 4px 10px;
  align-items: baseline;
  padding: 7px 0;
  border-bottom: 1px solid rgba(61, 48, 32, 0.14);
  font-size: 0.9rem;
}
.mo-shots .n { font-family: 'JetBrains Mono', monospace; font-size: 0.76rem; color: rgba(61, 48, 32, 0.45); }
.mo-shots .w {
  font-family: 'Cinzel', Georgia, serif;
  font-size: 0.72rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--rubric);
}
.mo-shots .l { grid-column: 3; }

.mo-cta { margin: 14px 0 4px; }
.mo-cta a {
  font-family: 'Barlow', system-ui, sans-serif;
  font-size: 0.84rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

/* ---------- jump lists ----------
   The whitepaper's chapter rail and the solutions quad-nav. Their hrefs
   point at a document the browser is not on, so they are buttons that
   scroll the reading instead of links that would leave it. */
.mo-jumps {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 14px;
  margin: 0 0 22px;
  padding-bottom: 16px;
  border-bottom: 1px solid rgba(61, 48, 32, 0.2);
}
.mo-jump-head {
  flex-basis: 100%;
  font-family: 'Cinzel', Georgia, serif;
  font-size: 0.62rem;
  letter-spacing: 0.28em;
  text-transform: uppercase;
  color: rgba(61, 48, 32, 0.5);
  margin-top: 4px;
}
.mo-jump {
  padding: 0;
  border: none;
  border-bottom: 1px solid rgba(122, 58, 28, 0.32);
  background: none;
  color: #7a3a1c;
  font: inherit;
  font-size: 0.86rem;
  cursor: pointer;
}
.mo-jump:hover { border-bottom-color: #7a3a1c; }
.mo-jump:focus-visible { outline: 2px solid var(--rubric); outline-offset: 2px; }
/* the solutions quad-nav packs glyph + label + element into one anchor; the
   whitepaper's chapters are plain text, so this only shows where it applies */
.mo-jump span + span { margin-left: 0.42em; }
.mo-jump .qn-glyph { color: var(--rubric); letter-spacing: 0.08em; }
.mo-jump .qn-el {
  font-size: 0.74em;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: rgba(61, 48, 32, 0.5);
}

/* ---------- the wide model (the whitepaper) ----------
   One route, one reason: ~34 000 characters under sixteen chapters. Stacked
   above an 860px reading that chapter list costs six lines before the first
   word and stops being navigation, so the sheet widens and the rail goes back
   beside the text — which is what whitepaper.html itself does.

   The extra width buys the RAIL, not a longer line: 1240 − 152 of padding −
   244 of rail and gutter leaves the prose at ~844px, the same measure the
   860px sheet sets. That is the whole argument for the number.

   Sticky works here because the rail is a grid ITEM: `align-items: start`
   shrinks its box to its content while its grid AREA — which is what sticky
   is constrained by — stays the full height of the row. */
.mosaic[data-wide] .mo-sheet { width: clamp(300px, 92vw, 1240px); }
.mo-split {
  display: grid;
  grid-template-columns: minmax(150px, 214px) 1fr;
  gap: 0 30px;
  align-items: start;
}
.mo-rail {
  position: sticky;
  top: 4px;                    /* clear of the .mo-body top mask */
  flex-direction: column;
  align-items: flex-start;
  gap: 5px 0;
  margin: 0;
  padding: 0 22px 0 0;
  border-bottom: none;
  border-right: 1px solid rgba(61, 48, 32, 0.2);
}
/* `.mo-jumps` sets this to 100% so a heading breaks the row; down a column
   that would be 100% of the HEIGHT instead. */
.mo-rail .mo-jump-head { flex-basis: auto; margin-top: 12px; }
.mo-rail .mo-jump-head:first-child { margin-top: 0; }
.mo-rail .mo-jump { text-align: left; }

/* Below this the rail cannot hold a readable measure beside the text, so the
   wide model folds back into the ordinary sheet — same markup, stacked. */
@media (max-width: 1080px) {
  .mosaic[data-wide] .mo-sheet { width: clamp(300px, 88vw, 860px); }
  .mo-split { display: block; }
  .mo-rail {
    position: static;
    flex-direction: row;
    align-items: baseline;
    gap: 6px 14px;
    margin: 0 0 22px;
    padding: 0 0 16px;
    border-right: none;
    border-bottom: 1px solid rgba(61, 48, 32, 0.2);
  }
  .mo-rail .mo-jump-head { flex-basis: 100%; }
}

/* ---------- the index (level 1) ---------- */
.mo-index-title {
  font-family: 'Cinzel', Georgia, serif;
  font-size: 0.68rem;
  letter-spacing: 0.42em;
  text-transform: uppercase;
  text-align: center;
  color: rgba(61, 48, 32, 0.55);
  margin-bottom: 22px;
}
.mo-entry {
  display: block;
  width: 100%;
  text-align: left;
  background: none;
  border: none;
  border-top: 1px solid rgba(61, 48, 32, 0.18);
  padding: 16px 4px;
  cursor: pointer;
  color: inherit;
  font: inherit;
}
.mo-entry:last-child { border-bottom: 1px solid rgba(61, 48, 32, 0.18); }
.mo-entry:hover, .mo-entry:focus-visible { background: rgba(122, 94, 52, 0.08); }
.mo-entry:focus-visible { outline: 2px solid var(--rubric); outline-offset: -2px; }
.mo-entry .g {
  font-family: 'Cinzel', Georgia, serif;
  font-size: 0.8rem;
  letter-spacing: 0.14em;
  color: var(--rubric);
}
.mo-entry .t {
  display: block;
  font-family: 'Cinzel', Georgia, serif;
  font-size: 1.06rem;
  color: #2f2515;
  margin: 2px 0 2px;
}
.mo-entry .d { display: block; font-style: italic; font-size: 0.92rem; color: rgba(59, 47, 29, 0.74); }

/* the index runs in two groups: the three journeys, then the four papers */
.mo-index-group {
  font-family: 'Cinzel', Georgia, serif;
  font-size: 0.6rem;
  letter-spacing: 0.32em;
  text-transform: uppercase;
  color: rgba(61, 48, 32, 0.45);
  margin: 22px 0 2px;
}
.mo-index-group:first-of-type { margin-top: 0; }
/* the group label already draws the line above its first entry */
.mo-index-group + .mo-entry { border-top: none; }

/* ---------- PT · EN, inside the sheet ----------
   The hub's own switch (styles.css `.lang-switch`), carried into the sheet and
   put where the hub puts it: the TOP LEFT. It has to live here rather than in
   the page chrome — the sheet is modal, so the page's switch is behind the
   scrim, and on a hosted page it is hidden outright.

   Same behaviour as the hub's, including the recessed-until-hover trick: the
   pair sits in shadow until you reach for it, then the WHOLE group lights at
   once, because the pair is the control. The colours are the parchment
   translation, not a copy — the hub lights `rgba(255,215,0,.9)` because it is
   gold on near-black; the same value on cream reads at 1.6:1, i.e. not at all.
   So the lit state runs down the same gold ramp to where it separates from the
   paper (#8a5f08 ≈ 4.6:1) and the shadowed state is ink rather than white. */
.mo-lang {
  position: absolute;
  /* Centred in the top gutter (2026-08-10): the top CORNERS belong to the
     navigation discs now, and the wave's midpoint ornament sits at y = 52 —
     so the centre above it, at 0.16, is the one clear ground. */
  top: calc(var(--pad-y) * 0.16);
  left: 50%;
  transform: translateX(-50%);
  z-index: 3;
  display: flex;
  align-items: center;
  gap: 4px;
  font-family: 'Barlow', system-ui, sans-serif;
  font-weight: 600;
  font-size: 13px;
  letter-spacing: 0.22em;
}
.mo-lang-sep { color: rgba(61, 48, 32, 0.28); transition: color 220ms ease; }
.mo-lang button {
  padding: 3px 2px;
  border: none;
  background: none;
  font: inherit;
  letter-spacing: 0.14em;
  color: rgba(61, 48, 32, 0.45);
  cursor: pointer;
  transition: color 220ms ease;
}
.mo-lang button.on { color: #8a5f08; }
.mo-lang button:focus-visible { outline: 2px solid var(--rubric); outline-offset: 2px; }

/* Gated on (hover: hover) exactly as the hub's is — a touch device can never
   fire :hover, so there the lit state IS the base and the control is never
   invisible. The focus-within twin does the same for a keyboard. */
@media (hover: hover) {
  .mo-lang button    { color: rgba(61, 48, 32, 0.16); }
  .mo-lang button.on { color: rgba(61, 48, 32, 0.34); }
  .mo-lang-sep       { color: rgba(61, 48, 32, 0.12); }

  .mo-lang:hover .mo-lang-sep,
  .mo-lang:focus-within .mo-lang-sep { color: rgba(138, 95, 8, 0.34); }
  .mo-lang:hover button,
  .mo-lang:focus-within button       { color: rgba(138, 95, 8, 0.55); }
  .mo-lang:hover button.on,
  .mo-lang:focus-within button.on    { color: #8a5f08; }
}

/* The back mark is gone (2026-08-10) — the top-right corner disc carries
   the index both ways now, so one control does what two did. */

/* ---------- language ----------
   The same `<html data-lang>` state essay.css:25-26 uses, re-scoped
   to the sheet. The essay markup arrives with its pairs intact, so
   the Mosaic and the hub can never disagree: there is one state. */
html[data-lang="pt"] .mosaic .l-en { display: none; }
html[data-lang="en"] .mosaic .l-pt { display: none; }

/* ---------- motion ---------- */
@keyframes mo-fade { from { opacity: 0; } to { opacity: 1; } }
@keyframes mo-rise {
  from { opacity: 0; transform: translateY(18px) scale(0.985); }   /* the design's 18px */
  to   { opacity: 1; transform: none; }
}
.mosaic.on .mo-scrim { animation: mo-fade 0.28s ease both; }
.mosaic.on .mo-sheet { animation: mo-rise 0.34s cubic-bezier(.2, .8, .25, 1) both; }
/* the rise must not replay under the pointer while the sheet is being moved */
.mosaic[data-dragging] .mo-sheet { animation: none; }

/* The design has no reduced-motion branch. This is ours: the sheet
   still arrives, it just arrives without travelling. */
@media (prefers-reduced-motion: reduce) {
  .mosaic.on .mo-scrim,
  .mosaic.on .mo-sheet { animation: mo-fade 0.01s linear both; }
  .mo-cipher { transition: box-shadow 200ms ease, color 200ms ease, border-color 200ms ease; }
  .mo-cipher:hover, .mo-cipher:focus-visible { transform: none; }
  .mo-lang button, .mo-lang-sep { transition: none; }
  .mo-body { scroll-behavior: auto; }
}

/* ---------- narrow ---------- */
@media (max-width: 720px) {
  /* 92vw now that nothing hangs outside the paper — the close mark was what
     the old 88 was leaving room for at 375px. */
  .mo-sheet,
  .mosaic[data-wide] .mo-sheet { width: min(92vw, 520px); }
  .mosaic[data-frame="flourish"] { --pad-x: 40px; --pad-y: 50px; }
  /* No max-height here on purpose. The base law is written in terms of
     var(--pad-y), and the four pads above are already the narrow ones — so it
     adapts by itself, and a second height law could only drift from the first.
     On a 375×812 phone that is ~631px of reading instead of the ~518px this
     block used to impose. */
  .mo-body { font-size: 0.98rem; }
  .mo-body h1 { font-size: 1.4rem; }

  /* The top gutter shrinks with k — PT · EN hugs the edge, centred as at
     desktop, and stays clear of the wave and both top discs. */
  .mo-lang { top: 4px; font-size: 11px; }
  .mo-lang button { padding: 2px 2px; }
}
