/* Tisso — tisso.com.br
   Dark techno-Apple stage carrying the app's own Nativo language.
   Tokens: the dark is the page's, the light values are the shipped app's (lib/theme.ts).

   MATERIA-2D craft pass (GATE-2 rework): the display scale comes DOWN and the air goes UP;
   the value ladder is rebuilt so display / lede / note are three visibly different steps;
   and no section is flat text on a flat colour any more — every band carries a soft room
   light, a grain tooth, a fading seam, and its objects sit on real elevation. */

@font-face {
  font-family: "Inter";
  src: url("fonts/inter-var-latin.woff2") format("woff2");
  font-weight: 300 900;
  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;
}
/* R9: the mono face is gone. The uppercase tracked-mono HUD voice was the one thing on the page
   that read as generated rather than designed; every annotation now speaks in the page's own text
   face, quietly, like an editorial caption. Codes keep their letterspacing — that is product truth. */

:root {
  /* the stage */
  --stage: #08090c;
  --stage-2: #12141b;        /* a panel is now a visibly different surface, not a 2% nudge */
  --stage-3: #1a1d26;
  --ink: #ffffff;            /* display only — the top of the ladder is pure */
  --ink-2: #b9bfcb;          /* lede / list text — 10.8:1, and clearly a step below display */
  --muted: #8a919f;          /* note / caption — 6.3:1 on the stage, 5.8:1 on a panel */
  --line: rgba(255, 255, 255, 0.09);
  --line-2: rgba(255, 255, 255, 0.16);

  /* the app's own values */
  --accent: #5856d6;         /* the ONE action colour — fill only on the dark */
  --accent-lift: #a5a3ff;    /* indigo when it must be text or hairline on the dark */
  --accent-deep: #4a48c4;    /* the same hue driven DOWN in value so it can be text on paper:
                                #5856D6 on the tinted chip measures 4.26:1 and fails the floor */
  --accent-tint: rgba(88, 86, 214, 0.16);
  --red: #ff3b30;
  --paper: #f2f2f7;          /* Nativo's ground — the single inversion */
  --paper-card: #ffffff;
  --paper-ink: #1c1c1e;
  --paper-muted: #4a4a4f;    /* the app's #8E8E93 raised to clear 4.5:1 on paper */
  --paper-line: rgba(60, 60, 67, 0.14);

  /* subject hues — data only, never decoration */
  --mat: #e5484d; --his: #d9820b; --cie: #2e9e63;
  --por: #0a7cff; --geo: #9a5cd0; --art: #189fa5;

  --r-group: 22px;           /* Nativo's grouped-card radius */
  --r-sm: 12px;
  --pad: clamp(20px, 5vw, 76px);
  --maxw: 1200px;
  --ease: cubic-bezier(.2, .8, .2, 1);

  /* ---- material ---- */
  /* one tooth of grain, tiled; the only "texture" asset on the page and it weighs ~330 bytes */
  --grain: 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='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='180' height='180' filter='url(%23n)'/%3E%3C/svg%3E");
  /* elevation: an ambient bed + a key drop + the 1px chamfer that catches the room light */
  --elev-1:
    inset 0 1px 0 rgba(255, 255, 255, .055),
    0 1px 2px rgba(0, 0, 0, .55),
    0 14px 30px -18px rgba(0, 0, 0, .9);
  --elev-2:
    inset 0 1px 0 rgba(255, 255, 255, .085),
    0 2px 6px rgba(0, 0, 0, .55),
    0 30px 60px -26px rgba(0, 0, 0, .95);
  --elev-paper:
    0 1px 1px rgba(28, 28, 30, .045),
    0 10px 22px -12px rgba(28, 28, 30, .16),
    0 30px 60px -34px rgba(28, 28, 30, .24);
  /* the glass family — the dock's recipe, reused wherever the page needs glass */
  --glass-bg: rgba(19, 21, 29, .72);
  --glass-blur: saturate(165%) blur(18px);
}

* { box-sizing: border-box; }
/* the UA's [hidden] rule loses to any author display value — .cfrag__done's display:block had been
   defeating hidden since R7 and the turma card stood under the code field the whole time. Law: */
[hidden] { display: none !important; }
::selection { background: rgba(88, 86, 214, .55); color: #fff; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
html, body { margin: 0; padding: 0; }
body {
  background: var(--stage);
  color: var(--ink);
  font-family: "Inter", system-ui, -apple-system, "Segoe UI", sans-serif;
  font-variation-settings: "opsz" 19;
  font-size: 17px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: clip;
}
img { display: block; max-width: 100%; }
a { color: inherit; }

.sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }

/* the boot veil: with JS on, the stage copy stays hidden for the parse-to-script gap so the
   static column never flashes before the live stage takes over. stage.js lifts it in its first
   statement; without JS the class never lands and the static column simply shows. */
html.boot .palco__copy { visibility: hidden; }

/* ---------- type ----------
   The display layer drops ~30% from the pre-GATE-2 scale and buys the difference back in air:
   an Apple product page is legible at three metres because of value and whitespace, not size. */
/* ---------- THE CAPTION VOICE ----------
   R9: one quiet idiom for every label, caption, count and kicker on the page. Sentence case, the
   page's own text face, 13px at weight 500 on --muted, the face's own optical tracking (-.005em)
   and nothing else: no uppercase, no letterspacing theatrics, no rule, no glyph, no pill, no
   border. It sits 13px under the thing it names with a 2px optical indent — a caption set beside a
   photograph in a magazine, which the eye passes over unless it wants the fact. Every annotation on
   the page is declared HERE, once, so the voice cannot drift member by member. */
.cap,
.artifact figcaption, .shard figcaption, .duo-shot figcaption, .status-shot figcaption,
.chaos figcaption, .lpiece figcaption, .webshot figcaption,
.rot__cap {
  font-size: 13px;
  font-weight: 500;
  letter-spacing: -.005em;
  line-height: 1.55;
  color: var(--muted);
}
/* a kicker is the same voice standing above a statement — a flat category word, nothing drawn
   beside it. The indigo hairline that used to lead it («—— privacidade») was caption furniture, and
   furniture is exactly what this pass removes. */
.eyebrow { color: var(--muted); display: block; margin: 0 0 22px; font-size: 13.5px; }

h1, h2, h3 { margin: 0; font-weight: 660; letter-spacing: -.038em; line-height: 1.02; font-variation-settings: "opsz" 32; }
h1 { font-size: clamp(38px, 5.4vw, 66px); letter-spacing: -.042em; }
h2 { font-size: clamp(30px, 3.5vw, 52px); }
h3 { font-size: clamp(18px, 1.35vw, 21px); letter-spacing: -.022em; line-height: 1.24; font-variation-settings: "opsz" 22; font-weight: 620; }
p { margin: 0; }
.lede {
  font-size: clamp(16.5px, 1.15vw, 18.5px); line-height: 1.62; color: var(--ink-2);
  max-width: 33em; letter-spacing: -.008em; font-variation-settings: "opsz" 19;
}
.note { font-size: 14.5px; line-height: 1.62; color: var(--muted); max-width: 36em; font-variation-settings: "opsz" 17; }

/* ---------- layout ---------- */
section { position: relative; }
.wrap { max-width: var(--maxw); margin: 0 auto; padding: 0 var(--pad); position: relative; z-index: 1; }
/* R9 spacing pass: the page keeps its float and loses the dead air. The gap between two bands
   was a flat 216px at 900px tall — a quarter of the viewport of nothing, and the void under
   #escola's struck chips was the worst of them. The padding is asymmetric now (a section opens
   with more air than it closes with), which reads as rhythm instead of as a hole. */
.band {
  padding: clamp(76px, 9.2vh, 120px) 0 clamp(60px, 7.2vh, 94px);
}
.band--tall { padding: clamp(98px, 12.4vh, 154px) 0 clamp(74px, 8.8vh, 114px); }

/* the room light — a wide, low, NEUTRAL wash (never a coloured blob; the brand forbids those).
   The pool peaks INSIDE the band and dies to nothing at both edges, so any two neighbouring
   sections meet at exactly the same value and the page reads as one continuous room with an arc
   of light travelling side to side — no seam, no ruled line, no panel edge. */
.band::before {
  content: ""; position: absolute; inset: 0; pointer-events: none; z-index: 0;
  /* the pool must reach ZERO before it reaches either clipped edge (0.62 × the vertical radius
     stays inside the centre's distance to both edges) — a pool that survives to the edge gets cut
     into exactly the ruled seam this replaced */
  background: radial-gradient(96% 46% at 14% 32%, rgba(255, 255, 255, .06), rgba(255, 255, 255, 0) 62%);
}
.band:nth-of-type(even)::before {
  background: radial-gradient(94% 46% at 86% 34%, rgba(255, 255, 255, .054), rgba(255, 255, 255, 0) 62%);
}
/* the tooth: a matte board is never a mathematically clean field */
.band::after {
  content: ""; position: absolute; inset: 0; pointer-events: none; z-index: 0;
  background-image: var(--grain);
  background-size: 180px 180px;
  /* screen, not overlay: overlay against a near-black ground is a no-op (2*base*blend with
     base~0.03 stays 0.03), so the tooth has to be ADDED as light, not multiplied in */
  opacity: .07;
  mix-blend-mode: screen;
}
.rule { height: 1px; background: var(--line); border: 0; margin: 0; }

/* ---------- the dock (the app's floating tab bar, doing the page's navigation) ---------- */
.dock {
  position: fixed;
  left: 50%;
  bottom: max(18px, env(safe-area-inset-bottom));
  transform: translateX(-50%);
  z-index: 60;
  display: flex;
  align-items: center;
  gap: 2px;
  padding: 6px;
  border-radius: 999px;
  background: var(--glass-bg);
  border: 1px solid var(--line-2);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .10), 0 2px 6px rgba(0, 0, 0, .5), 0 26px 60px -22px rgba(0, 0, 0, .95);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  max-width: calc(100vw - 24px);
}
.dock a {
  position: relative; z-index: 1;
  display: inline-block;
  padding: 9px 15px;
  border-radius: 999px;
  font-size: 13px;
  font-weight: 560;
  letter-spacing: -.01em;
  color: var(--ink-2);
  text-decoration: none;
  white-space: nowrap;
  transition: color .2s var(--ease);
}
.dock a:hover { color: var(--ink); }
.dock a[aria-current="true"] { color: #fff; }
.dock .dock-cta { color: var(--accent-lift); font-weight: 600; }
.dock .dock-cta:hover { color: #c6c4ff; }
.dock .dock-cta[aria-current="true"] { color: #fff; }

/* the liquid indicator — ONE pill of glass that carries the "you are here". It stretches toward
   the next section and settles onto it with a soft spring; over the CTA it takes the indigo. */
.dock-ind {
  position: absolute; top: 6px; bottom: 6px; left: 6px; width: 0; opacity: 0;
  border-radius: 999px; z-index: 0;
  background: rgba(255, 255, 255, .12);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .16), inset 0 -1px 0 rgba(255, 255, 255, .04);
  transition:
    left .42s cubic-bezier(.3, 1.35, .45, 1),
    width .42s cubic-bezier(.3, 1.35, .45, 1),
    background-color .3s var(--ease), box-shadow .3s var(--ease), opacity .3s var(--ease);
  will-change: left, width;
}
.dock-ind.is-stretch {
  transition: left .18s cubic-bezier(.3, .7, .4, 1), width .18s cubic-bezier(.3, .7, .4, 1),
    background-color .3s var(--ease), box-shadow .3s var(--ease);
}
.dock-ind.is-still { transition: none; }
.dock-ind.is-cta {
  background: var(--accent);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .24), 0 6px 16px -6px rgba(88, 86, 214, .8);
}
@media (prefers-reduced-motion: reduce) {
  .dock-ind { transition: none; }
}

/* ---------- buttons ---------- */
.btn {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 15px 26px;
  border-radius: 999px;
  font-size: 15.5px;
  font-weight: 600;
  letter-spacing: -.012em;
  text-decoration: none;
  border: 1px solid transparent;
  transition: transform .18s var(--ease), background-color .18s var(--ease), border-color .18s var(--ease), box-shadow .18s var(--ease);
}
.btn:active { transform: translateY(1px); }
.btn--fill {
  background: var(--accent); color: #fff;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .24), 0 10px 26px -12px rgba(88, 86, 214, .95);
}
.btn--fill:hover { background: #6a68e0; box-shadow: inset 0 1px 0 rgba(255, 255, 255, .28), 0 14px 32px -12px rgba(88, 86, 214, 1); }
.btn--ghost {
  border-color: var(--line-2); color: var(--ink);
  background: rgba(255, 255, 255, .028);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .06);
}
.btn--ghost:hover { border-color: rgba(255, 255, 255, .32); background: rgba(255, 255, 255, .05); }
.btn--paper {
  background: var(--accent); color: #fff;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .26), 0 10px 24px -10px rgba(88, 86, 214, .6);
}
.btn--paper:hover { background: #6a68e0; }
.btn--paper-ghost {
  border-color: rgba(60, 60, 67, .20); color: var(--paper-ink); background: #fff;
  box-shadow: var(--elev-paper);
}
.btn--paper-ghost:hover { border-color: rgba(60, 60, 67, .34); }

/* ---------- wordmark ---------- */
.wordmark {
  font-size: 20px; font-weight: 680; letter-spacing: -.042em;
  font-variation-settings: "opsz" 32;
}
.wordmark .dot { color: var(--accent-lift); }

/* ---------- top bar ----------
   Page navigation, and nothing else: the dock at the bottom carries the sections. It stands over
   the hero art with no ground of its own — no bar, no blur, no rule — so the stage is never boxed
   in. It scrolls away with the page, because a fixed strip would sit on the pinned scene the whole
   way down. */
.top {
  position: absolute; top: 0; left: 0; right: 0; z-index: 40;
  display: flex; align-items: center; justify-content: space-between; gap: 16px;
  padding: 26px var(--pad);
}
.top .site { color: var(--muted); }
a.wordmark { text-decoration: none; color: inherit; }

.topnav { display: flex; align-items: center; gap: clamp(14px, 1.9vw, 28px); }
.topnav a {
  font-size: 13.5px; font-weight: 540; letter-spacing: -.01em;
  color: var(--muted); text-decoration: none; white-space: nowrap;
  transition: color .2s var(--ease), border-color .2s var(--ease), background-color .2s var(--ease);
}
.topnav a:hover { color: var(--ink); }
.topnav a[aria-current="page"] { color: var(--ink-2); }
/* the one affordance in the bar: the door into the running app */
.topnav .topnav__in {
  padding: 8px 17px; border-radius: 999px; color: var(--ink);
  border: 1px solid var(--line-2);
  background: rgba(255, 255, 255, .028);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .06);
}
.topnav .topnav__in:hover { border-color: rgba(255, 255, 255, .32); background: rgba(255, 255, 255, .05); }

/* ---------- the stage's opening actions (see stage.css for the rest) ---------- */
.hero-actions { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 36px; }

/* ---------- generic grid pieces ---------- */
.cols { display: grid; gap: clamp(30px, 4vw, 60px); }
.cols--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.cols--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.cols--4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }

.panel {
  background: var(--stage-2);
  border: 1px solid var(--line);
  border-radius: var(--r-group);
  padding: clamp(22px, 2.4vw, 32px);
  box-shadow: var(--elev-1);
}
.panel h3 { margin-bottom: 12px; }

/* subject dot — the app's rule: a dot beside a real subject name, never decoration */
.sdot { width: 9px; height: 9px; border-radius: 999px; display: inline-block; vertical-align: middle; margin-right: 8px; }

/* R9: the ring glyph left the captions — it is brand (favicon, footer arc), not caption furniture.
   A caption is now just a caption. */

/* ---------- artifacts — real product pixels answering the section beside them ----------
   A FRAGMENT of a real capture (crop by presentation: the img is whole, the frame shows a region)
   standing in the air the display column leaves free. One per section, carrying the page's own
   caption voice, and the page's density where there was only type. */
.artifact {
  position: absolute; right: var(--pad); top: clamp(96px, 13vh, 170px);
  width: clamp(250px, 24vw, 340px); margin: 0; z-index: 0;
}
.frag {
  position: relative; overflow: hidden;
  border-radius: 18px;
  aspect-ratio: calc(600 * var(--cw)) / calc(1304 * var(--ch));
  background: var(--stage-2);
  border: 1px solid var(--line-2);
  box-shadow: var(--elev-2), 0 0 70px -20px rgba(165, 163, 255, .14);
}
.frag img {
  position: absolute; left: 0; top: 0;
  width: calc(100% / var(--cw)); max-width: none;
  transform: translate(calc(-100% * var(--cx)), calc(-100% * var(--cy)));
}
/* the fragment is lit like the devices: a hairline top chamfer catching the room */
.frag::after {
  content: ""; position: absolute; inset: 0; border-radius: inherit; pointer-events: none;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .12);
}
.artifact figcaption, .shard figcaption, .duo-shot figcaption, .status-shot figcaption,
.chaos figcaption, .lpiece figcaption, .webshot figcaption { margin-top: 13px; padding-left: 2px; max-width: 30em; }
@media (max-width: 1120px) {
  .artifact { position: static; width: min(100%, 330px); margin: 34px 0 6px; }
}

/* ---------- R5 — the shard system: fragments of real product pixels standing in the air ----------
   The same crop-by-presentation as .artifact, in two postures: in-flow under the copy it answers
   (.shard), and absolutely in a section's free air (.shard--air), riding the slow parallax layer.
   This is where the page's colour comes from: the app's own subject hues arrive as real pixels,
   never as painted decoration. */
.shard { margin: clamp(30px, 4vh, 48px) 0 0; width: min(100%, 360px); }
.shard .frag { border-radius: 14px; }
.shard--air {
  position: absolute; right: var(--pad); top: clamp(90px, 12vh, 160px);
  width: clamp(240px, 22vw, 320px); margin: 0; z-index: 0;
}
@media (max-width: 1120px) { .shard--air { display: none; } }

/* ---------- R6 — the delivered reminder, live ----------
   The one place a static crop stood in for a dynamic event: the banner is now built of the page's
   own glass and DROPS IN the way the real one did on the lock screen. This recreates OS chrome
   only — the app-screen pixels everywhere else stay real captures. */
.notif-shard { width: clamp(300px, 27vw, 392px); }
.notif {
  display: flex; align-items: center; gap: 12px;
  padding: 13px 15px;
  border-radius: 22px;
  background: rgba(44, 48, 62, .58);
  border: 1px solid rgba(255, 255, 255, .13);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .14), 0 2px 6px rgba(0, 0, 0, .4), 0 22px 48px -18px rgba(0, 0, 0, .85);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  opacity: 0;
}
.notif__icon {
  flex: none; width: 38px; height: 38px; border-radius: 9px;
  /* the favicon's figure, redrawn a step brighter: at 38px on dark glass the 16px-tuned
     stroke values read as a blank dark tile */
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 64 64'%3E%3Crect width='64' height='64' rx='14' fill='%23141726'/%3E%3Cellipse cx='32' cy='30' rx='21' ry='11.5' fill='none' stroke='%239a97ff' stroke-opacity='.85' stroke-width='3'/%3E%3Ccircle cx='32' cy='41.5' r='8' fill='%235856D6' opacity='.45'/%3E%3Ccircle cx='32' cy='41.5' r='5' fill='%23a5a3ff'/%3E%3C/svg%3E") center / cover no-repeat;
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .09), 0 1px 3px rgba(0, 0, 0, .4);
}
.notif__text { min-width: 0; }
.notif__text b, .notif__text > span {
  display: block; font-size: 13.5px; line-height: 1.35;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.notif__text b { font-weight: 640; letter-spacing: -.01em; color: #fff; }
.notif__text > span { color: rgba(235, 238, 248, .82); }
.notif__when {
  flex: none; align-self: flex-start; margin-left: auto; padding-top: 1px;
  font-size: 11.5px; color: rgba(235, 238, 248, .55);
}
@keyframes notif-in {
  0%   { opacity: 0; transform: translateY(-115%) scale(.97); }
  55%  { opacity: 1; transform: translateY(5%) scale(1.004); }
  78%  { transform: translateY(-1.6%) scale(1); }
  100% { opacity: 1; transform: none; }
}
.notif.live { animation: notif-in .9s cubic-bezier(.3, .8, .3, 1) both; }
@media (prefers-reduced-motion: reduce) {
  .notif { opacity: 1; }
  .notif.live { animation: none; }
}
/* this one air shard survives the narrow frame: it goes in-flow instead of vanishing */
@media (max-width: 1120px) {
  .notif-shard.shard--air { display: block; position: static; width: min(100%, 392px); margin: 34px 0 10px; }
}

/* the big pairs: copy beside the product at Apple scale */
.duo {
  display: grid; grid-template-columns: minmax(0, 1.12fr) minmax(0, .88fr);
  gap: clamp(36px, 5vw, 84px);
  margin-top: clamp(32px, 4.6vh, 58px);
  align-items: start;
}
.duo-shot { margin: 0; max-width: 360px; justify-self: end; width: 100%; }
.duo-shot figcaption { justify-content: flex-start; }
.duo-shot--frag { max-width: 430px; }
.head-duo {
  display: grid; grid-template-columns: minmax(0, 1.15fr) minmax(0, .85fr);
  gap: clamp(36px, 5vw, 84px);
  align-items: start;
}
@media (max-width: 900px) {
  .duo, .head-duo { grid-template-columns: minmax(0, 1fr); }
  .duo-shot { justify-self: start; max-width: 320px; }
  .duo-shot--frag { max-width: 360px; }
}

/* status: the third column is the product itself */
.cols--status { grid-template-columns: minmax(0, 1.3fr) minmax(0, 1fr); }
.status-shot { margin: 0; width: 100%; max-width: 440px; justify-self: center; }
@media (max-width: 900px) { .status-shot { max-width: 340px; justify-self: start; } }

/* ---------- R5 — the living ground ----------
   Fixed and composited: two pools of the brand's light breathing on long, decorrelated periods,
   and a dust field that only exists inside their reach. Plain alpha compositing, NOT
   mix-blend-mode: over a near-black ground screen() is numerically ~additive anyway (a+b-ab with
   b≈.03), and a blend mode forces the compositor off the fast path — the whole viewport re-blends
   every frame of the breathing, which under a software rasterizer taxes every signature on the
   page. A translucent promoted layer rasterizes once and composites as one quad. */
.atmo { position: fixed; inset: -14vh 0; z-index: 0; pointer-events: none; overflow: hidden; }
.atmo i { position: absolute; display: block; }
.atmo__a {
  width: 110vmax; height: 82vmax; left: -34vmax; top: -20vmax;
  background: radial-gradient(50% 50% at 50% 50%, rgba(88, 86, 214, .13), rgba(88, 86, 214, 0) 68%);
  animation: atmoA 17s ease-in-out infinite alternate;
  will-change: transform, opacity;
}
.atmo__b {
  width: 88vmax; height: 66vmax; right: -30vmax; top: 26vmax;
  background: radial-gradient(50% 50% at 50% 50%, rgba(165, 163, 255, .08), rgba(165, 163, 255, 0) 66%);
  animation: atmoB 23s ease-in-out infinite alternate;
  will-change: transform, opacity;
}
.atmo__dots {
  inset: 0;
  background-image: radial-gradient(rgba(226, 230, 255, .5) 1px, rgba(0, 0, 0, 0) 1.4px);
  background-size: 30px 30px;
  opacity: .068;
  -webkit-mask-image: radial-gradient(75% 60% at 62% 30%, #000, transparent 78%);
  mask-image: radial-gradient(75% 60% at 62% 30%, #000, transparent 78%);
}
@keyframes atmoA {
  from { transform: translate3d(0, 0, 0) scale(1); opacity: .82; }
  to   { transform: translate3d(6vmax, 4vmax, 0) scale(1.08); opacity: 1; }
}
@keyframes atmoB {
  from { transform: translate3d(0, 0, 0) scale(1.06); opacity: .7; }
  to   { transform: translate3d(-5vmax, -3vmax, 0) scale(1); opacity: 1; }
}
/* a signature in flight (lens swap) borrows the breathing's frames — the pause is imperceptible */
.perf-hot .atmo__a, .perf-hot .atmo__b { animation-play-state: paused; }
@media (prefers-reduced-motion: reduce) {
  .atmo__a, .atmo__b { animation: none; }
}

/* ---------- R5 — kernel vignettes: the scene leaking into the page ----------
   One-shot renders by the stage's own kernel (same mesh, same room, screens OFF), masked so the
   frame dissolves into the page's dark instead of arriving as a rectangle. They fade in when the
   render lands and simply never appear if WebGL2 is unavailable. */
.vign {
  position: absolute; pointer-events: none; z-index: 0;
  opacity: 0; transition: opacity 1.4s var(--ease);
  height: auto;
}
.vign.on { opacity: .82; }
.vign--arc {
  left: 0; right: 0; bottom: -104px; margin: 0 auto;
  width: min(860px, 88vw);
  -webkit-mask-image: radial-gradient(72% 82% at 50% 42%, #000 38%, transparent 72%);
  mask-image: radial-gradient(72% 82% at 50% 42%, #000 38%, transparent 72%);
}
.vign--arc.on { opacity: .6; }
.foot { position: relative; overflow: hidden; }
@media (max-width: 760px) { .vign--arc { display: none; } }

/* ---------- THE DEVICE — a real object, not a screenshot with rounded corners ----------
   A body with visible thickness (the rail gradient), a chamfer hairline where the room light
   catches the edge, a contact shadow under it, and the screen's own light spilling outward.
   Nothing is ever drawn OVER the product pixels: every effect lives on the body or below it. */
/* ---------- the desktop browser window ----------
   R11: the web client joins the page. Same license as the device bezel and the notification
   banner — the chrome is recreated page furniture, the pixels inside are the real app. */
.webshot { margin: clamp(34px, 4.6vh, 56px) 0 0; width: min(100%, 700px); }
.webshot--wide { width: min(100%, 860px); margin-top: clamp(38px, 5vh, 62px); }
.browser {
  position: relative; border-radius: 14px; background: var(--stage-2);
  border: 1px solid var(--line-2); box-shadow: var(--elev-2); overflow: hidden;
}
.browser::after {                      /* the same contact shadow the devices sit on */
  content: ""; position: absolute; left: 6%; right: 6%; bottom: -30px; height: 46px;
  background: radial-gradient(52% 50% at 50% 50%, rgba(0, 0, 0, .7), rgba(0, 0, 0, 0) 72%);
  filter: blur(10px); z-index: -1; pointer-events: none;
}
.browser__bar {
  display: grid; grid-template-columns: 1fr minmax(0, 260px) 1fr; align-items: center;
  padding: 9px 12px; border-bottom: 1px solid var(--line);
}
.browser__dots { display: flex; gap: 7px; justify-self: start; }
.browser__dots i { width: 10px; height: 10px; border-radius: 50%; }
.browser__dots i:nth-child(1) { background: #ff5f57; }
.browser__dots i:nth-child(2) { background: #febc2e; }
.browser__dots i:nth-child(3) { background: #28c840; }
.browser__url {
  justify-self: stretch; text-align: center; padding: 4px 14px; border-radius: 8px;
  background: rgba(255, 255, 255, .06);
  font-size: 12.5px; font-weight: 500; letter-spacing: -.005em; color: var(--muted);
}
.browser img { display: block; width: 100%; height: auto; }

.device { position: relative; display: block; }
.device::after {                       /* the contact shadow — it sits on something */
  content: ""; position: absolute; left: 8%; right: 8%; bottom: -26px; height: 44px;
  background: radial-gradient(52% 50% at 50% 50%, rgba(0, 0, 0, .78), rgba(0, 0, 0, 0) 72%);
  filter: blur(9px); z-index: 0; pointer-events: none;
}
.device__body {
  position: relative; z-index: 1;
  padding: 6px;
  border-radius: 42px;
  background: linear-gradient(148deg, #3a3f4c 0%, #171a22 22%, #0b0d12 55%, #202430 92%, #4a505f 100%);
  box-shadow:
    inset 0 0 0 1px rgba(255, 255, 255, .10),
    inset 0 1.5px 0 rgba(255, 255, 255, .26),
    inset 0 -1.5px 0 rgba(255, 255, 255, .08),
    0 2px 4px rgba(0, 0, 0, .6),
    0 30px 64px -26px rgba(0, 0, 0, .95),
    0 0 90px -26px rgba(214, 224, 255, .20);   /* the screen lighting the board around it */
}
.device__body img { border-radius: 36px; width: 100%; height: auto; }

/* ---------- three real screens, staged in depth ----------
   Frontal, so the product UI stays readable — the depth comes from scale, height and shadow
   weight, the way a product-family shot stages a set. */
.trio {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(24px, 3.4vw, 52px);
  margin-top: clamp(44px, 6.2vh, 76px);
  align-items: start;
  perspective: 2000px;
}
.shot { margin: 0; }
/* the side pair stands further back: scaled from its own base line, so it recedes without
   moving a single caption off the shared baseline (transform never touches layout) */
.shot:nth-child(1) .device__body, .shot:nth-child(3) .device__body { transform: scale(.93); transform-origin: 50% 100%; }
.shot:nth-child(2) .device__body { box-shadow:
    inset 0 0 0 1px rgba(255, 255, 255, .12),
    inset 0 1.5px 0 rgba(255, 255, 255, .3),
    inset 0 -1.5px 0 rgba(255, 255, 255, .09),
    0 2px 4px rgba(0, 0, 0, .6),
    0 44px 80px -28px rgba(0, 0, 0, 1),
    0 0 110px -24px rgba(214, 224, 255, .26); }
/* the same depth grammar as the stage, at a third of the amplitude */
.shot.rise { transform: translate3d(0, 26px, -120px); }
.shot.rise.in { transform: none; }
.shot.rise:nth-child(2) { transition-delay: .09s; }
.shot.rise:nth-child(3) { transition-delay: .18s; }
.shot figcaption {
  margin-top: clamp(26px, 3vh, 36px);
  font-size: 14.5px; line-height: 1.62; color: var(--muted); max-width: 30em;
}
/* a caption that runs to two lines opens on the screen it names — the same voice one value step
   up, the way a magazine sets the first words of a long caption. Not a label. */
.shot figcaption .cap {
  display: block; margin-bottom: 7px;
  color: var(--ink-2); font-size: 14.5px; font-weight: 600; letter-spacing: -.012em;
}

/* ---------- QUATRO LENTES — the permission stack ---------- */
.lens {
  display: grid; grid-template-columns: minmax(0, .8fr) minmax(0, 2.05fr);
  gap: clamp(30px, 4vw, 60px);
  margin-top: clamp(40px, 5.6vh, 72px);
  align-items: start;
}
/* The plates: depth is said with VALUE and shadow weight, never with a perspective transform — a
   translateZ stack scaled cards past their own grid rows and the selected plate overlapped its
   neighbours (the GATE-2 bug). A resting plate sits back in the dark; the chosen one comes up a
   step, gains the light and an indigo hairline, and nothing can ever collide. */
.lens-picker { position: relative; display: grid; gap: 12px; }
.plate {
  display: block; width: 100%; text-align: left; cursor: pointer;
  border: 1px solid var(--line); border-radius: var(--r-group);
  background: linear-gradient(180deg, #101219 0%, #0b0d12 100%);
  color: var(--ink-2);
  padding: 18px 22px;
  font: inherit;
  box-shadow: 0 1px 2px rgba(0, 0, 0, .5), 0 12px 26px -18px rgba(0, 0, 0, .9);
  transition: transform .28s var(--ease), background-color .28s var(--ease), border-color .28s var(--ease), box-shadow .28s var(--ease), color .28s var(--ease);
}
.plate-t { display: block; font-size: clamp(17px, 1.35vw, 20px); font-weight: 640; letter-spacing: -.024em; color: var(--ink); }
.plate-s { display: block; margin-top: 7px; font-size: 14px; line-height: 1.55; color: var(--muted); }
.plate:hover { border-color: var(--line-2); background: linear-gradient(180deg, #14171f 0%, #0e1015 100%); }
.plate[aria-selected="true"] {
  transform: translateX(6px);
  background: linear-gradient(180deg, #20242f 0%, #14171f 100%);
  border-color: rgba(165, 163, 255, .42);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, .10),
    0 2px 6px rgba(0, 0, 0, .5),
    0 30px 56px -26px rgba(0, 0, 0, 1);
}
.plate[aria-selected="true"] .plate-s { color: var(--ink-2); }

.lens-panel { display: grid; grid-template-columns: minmax(0, .82fr) minmax(0, 1fr); gap: clamp(28px, 3.4vw, 56px); align-items: start; }
.lens-device .device__body { border-radius: 38px; padding: 5px; }
.lens-device .device__body img { border-radius: 33px; }
/* R9: the count is a quiet line, not an outlined pill — the pill was pure HUD */
.lens-count { display: block; margin-bottom: 18px; color: var(--ink-2); font-size: 13.5px; max-width: 26em; }
.lens-rows { list-style: none; margin: 0; padding: 0; position: relative; height: 0; transition: height .34s var(--ease); }
.lens-rows li {
  position: absolute; left: 0; right: 0; top: 0;
  display: flex; align-items: baseline; gap: 12px; flex-wrap: wrap;
  height: 56px; padding-top: 16px;
  font-size: 15.5px; letter-spacing: -.01em; color: var(--ink-2);
  transition: transform .34s var(--ease), opacity .24s var(--ease);
  will-change: transform;
  background-image: linear-gradient(90deg, rgba(255, 255, 255, .13) 0%, rgba(255, 255, 255, .13) 72%, rgba(255, 255, 255, 0) 100%);
  background-size: 100% 1px; background-repeat: no-repeat; background-position: 0 0;
}
.lens-rows li .q { color: var(--muted); font-size: 13.5px; }
.lens-rows li.out { opacity: 0; pointer-events: none; }
.lens-foot { margin-top: 26px; }

@media (max-width: 1080px) {
  .lens { grid-template-columns: minmax(0, 1fr); }
  .lens-panel { grid-template-columns: minmax(0, .8fr) minmax(0, 1fr); }
}
@media (max-width: 720px) {
  .lens-panel { grid-template-columns: minmax(0, 1fr); }
  .lens-device { max-width: 250px; }
  .lens-rows li { height: 68px; }
}
@media (prefers-reduced-motion: reduce) {
  .plate, .plate[aria-selected="true"], .plate:hover { transform: none; transition: none; }
  .lens-rows li { transition: none; }
}

/* ---------- the ladder ---------- */
.steps { list-style: none; margin: clamp(40px, 5.6vh, 72px) 0 0; padding: 0; counter-reset: none; }
.steps li {
  position: relative;
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.25fr);
  gap: clamp(16px, 2.4vw, 44px); align-items: start;
  padding: clamp(24px, 2.8vh, 34px) 0;
  background-image: linear-gradient(90deg, rgba(255, 255, 255, .12) 0%, rgba(255, 255, 255, .12) 82%, rgba(255, 255, 255, 0) 100%);
  background-size: 100% 1px; background-repeat: no-repeat; background-position: 0 0;
}
.steps li:last-child { box-shadow: 0 1px 0 rgba(255, 255, 255, .05); }
.steps h3 { letter-spacing: -.026em; }
.steps .note { color: var(--ink-2); }

/* what the school does not have to do */
.nots { list-style: none; margin: 20px 0 0; padding: 0; display: flex; flex-wrap: wrap; gap: 10px; }
.nots li {
  color: var(--muted); font-size: clamp(14px, 1.2vw, 16px);
  padding: 9px 17px; border: 1px solid var(--line); border-radius: 999px;
  background: rgba(255, 255, 255, .022);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .05);
  text-decoration: line-through;
  text-decoration-color: rgba(255, 255, 255, .28);
  text-decoration-thickness: 1px;
}

/* ---------- the paper inversion — the one place the page stops arguing ----------
   The light section arrives as a SHEET: rounded shoulders, risen over the dark stage the way the
   app's own compose sheet rises over Próximos. The dark shows at its corners, so the flip reads as
   an object entering the room, not as two pages glued at a hard line. */
.paper {
  background: var(--paper); color: var(--paper-ink);
  border-radius: clamp(28px, 4vw, 48px) clamp(28px, 4vw, 48px) 0 0;
  margin-top: clamp(22px, 2.8vw, 36px);
  overflow: hidden;
  box-shadow: 0 -1px 0 rgba(255, 255, 255, .16), 0 -30px 80px -30px rgba(0, 0, 0, .8);
}
.paper::before {
  background:
    radial-gradient(84% 52% at 50% -18%, rgba(255, 255, 255, .8), rgba(255, 255, 255, 0) 60%),
    linear-gradient(180deg, rgba(255, 255, 255, .3) 0%, rgba(255, 255, 255, 0) 20%, rgba(28, 28, 30, .055) 100%);
}
.paper::after { opacity: .05; mix-blend-mode: multiply; }
.paper .lede { color: var(--paper-muted); }
.paper .note { color: var(--paper-muted); }
.paper .eyebrow { color: var(--paper-muted); }
.paper .rule { background: var(--paper-line); }
.card {
  background: var(--paper-card);
  border-radius: var(--r-group);
  border: 1px solid rgba(60, 60, 67, .07);
  box-shadow: var(--elev-paper);
  padding: clamp(24px, 2.6vw, 34px);
}
.card h3 { margin-bottom: 12px; }

/* ---------- the three things the group cannot say ---------- */
.miss-head { color: var(--muted); font-size: 13.5px; margin: clamp(42px, 5.6vh, 70px) 0 0; }
.miss { list-style: none; margin: 22px 0 0; padding: 0; }
.miss li {
  padding: clamp(18px, 2vh, 26px) 0;
  font-size: clamp(21px, 2.3vw, 33px); letter-spacing: -.028em; line-height: 1.1;
  font-weight: 620; font-variation-settings: "opsz" 32; color: var(--ink);
  background-image: linear-gradient(90deg, rgba(255, 255, 255, .13) 0%, rgba(255, 255, 255, .13) 66%, rgba(255, 255, 255, 0) 100%);
  background-size: 100% 1px; background-repeat: no-repeat; background-position: 0 0;
}
.miss li:last-child { box-shadow: 0 1px 0 rgba(255, 255, 255, .05); }

/* ---------- three guarantees, stated flat — hairline columns, not boxes ----------
   R14: two prose guarantees share the first row; the third spans the row as a duo — its words
   beside its live rot fragment — so the band closes on a demonstration, not an empty bottom. */
.guarantees {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0; margin-top: clamp(40px, 5.6vh, 72px);
  background-image: linear-gradient(90deg, rgba(255, 255, 255, .12) 0%, rgba(255, 255, 255, .12) 84%, rgba(255, 255, 255, 0) 100%);
  background-size: 100% 1px; background-repeat: no-repeat; background-position: 0 0;
}
.guarantees > div { padding: clamp(30px, 3.4vh, 44px) clamp(20px, 2.4vw, 44px) 0 0; position: relative; }
.guarantees > div + div { padding-left: clamp(20px, 2.4vw, 44px); }
.guarantees > div + div::before {
  content: ""; position: absolute; left: 0; top: 0; bottom: 18%; width: 1px;
  background: linear-gradient(180deg, rgba(255, 255, 255, .14), rgba(255, 255, 255, 0));
}
.guarantees h3 { margin-bottom: 14px; }
.guarantees .note { color: var(--ink-2); }
.guarantees > .g-wide {
  grid-column: 1 / -1; display: grid;
  grid-template-columns: minmax(0, 1.1fr) minmax(0, .9fr);
  gap: 0 clamp(24px, 3vw, 56px);
  padding-right: 0; margin-top: clamp(26px, 3vh, 40px);
  background-image: linear-gradient(90deg, rgba(255, 255, 255, .12) 0%, rgba(255, 255, 255, .12) 84%, rgba(255, 255, 255, 0) 100%);
  background-size: 100% 1px; background-repeat: no-repeat; background-position: 0 0;
}
.guarantees > .g-wide::before { content: none; }
.guarantees > .g-wide { padding-left: 0; }
.g-card { align-self: start; }
.g-card .rot { margin-top: 6px; }
@media (max-width: 900px) {
  .guarantees { grid-template-columns: minmax(0, 1fr); }
  .guarantees > div + div { padding-left: 0; }
  .guarantees > div + div::before {
    left: 0; right: 0; top: 0; bottom: auto; width: auto; height: 1px;
    background: linear-gradient(90deg, rgba(255, 255, 255, .12) 0%, rgba(255, 255, 255, .12) 70%, rgba(255, 255, 255, 0) 100%);
  }
  .guarantees > div { padding-right: 0; }
  .guarantees > .g-wide { display: block; margin-top: 0; }
}

/* ---------- status ---------- */
.col-head { color: var(--ink); font-size: 15px; font-weight: 620; letter-spacing: -.014em; margin-bottom: 24px; }
.ticks { list-style: none; margin: 0; padding: 0; }
.ticks li {
  position: relative; padding: 14px 0 14px 32px;
  font-size: 15.5px; line-height: 1.55; color: var(--ink-2); letter-spacing: -.01em;
  background-image: linear-gradient(90deg, rgba(255, 255, 255, .12) 0%, rgba(255, 255, 255, .12) 74%, rgba(255, 255, 255, 0) 100%);
  background-size: 100% 1px; background-repeat: no-repeat; background-position: 0 0;
}
.ticks li::before {
  content: ""; position: absolute; left: 1px; top: 22px;
  width: 13px; height: 7px; border-left: 1.5px solid var(--accent-lift); border-bottom: 1.5px solid var(--accent-lift);
  transform: rotate(-45deg);
}
.ticks strong { color: var(--ink); font-weight: 620; }

/* ---------- the list of nevers ----------
   The refusal is said quietly: the words stand a step dimmer than running text, and a thin
   NEUTRAL hairline is drawn through each one as the eye reaches it — a line through an item on a
   list, not a red correction. As the line completes, the word steps back a further half-tone:
   the light leaves it. */
.never { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; }
.never li {
  font-size: clamp(15px, 1.85vw, 26px); font-weight: 560; letter-spacing: -.028em; line-height: 1.34;
  font-variation-settings: "opsz" 30; color: #99a0ae;
  transition: color .5s var(--ease);
}
.never li.in { color: #848b99; }
.never .w { position: relative; white-space: nowrap; }
/* the line is drawn, not typed — it arrives with the eye, transform only. It sits at the OPTICAL
   middle of the word (.615em from the inline box's top): the eye takes a word's centre from the
   block its ascenders and its baseline make, not from the x-height alone, and this list is nearly
   all ascenders. That reads as a confident strike through caps and lowercase alike, and it is 2px
   solid so neither the grain nor a fractional zoom can fray it. */
.never .w::after {
  content: ""; position: absolute; left: -.04em; right: -.04em;
  top: calc(.615em - 1px); height: 2px; border-radius: 1px;
  background: rgba(226, 230, 240, .55);
  transform: scaleX(0); transform-origin: left center;
  transition: transform .5s var(--ease);
}
.never li.in .w::after { transform: scaleX(1); }
.never li::after { content: "\00B7"; display: inline-block; margin: 0 .38em; color: rgba(255, 255, 255, .20); }
.never li:last-child::after { content: ""; margin: 0; }

/* ---------- the planet of the nevers ----------
   The section's object: a sphere of triangles drawn ONLY in hairlines, turning slowly, with the
   eleven refusals in orbit around it. The words on the ring are the list itself — the same <li>s,
   the same strike, the same place in the tree — so the picture costs the reader nothing. Layout is
   handed to js/orbit.js by the .orbit--on switch; without it (no JS, no script) the list simply
   stands as a line of words the way it always did, and the empty canvas takes no space at all. */
.orbit { position: relative; margin: clamp(36px, 4.8vh, 60px) 0 0; }
.orbit__sky {
  position: absolute; left: 50%; top: 50%; z-index: 1;
  transform: translate(-50%, -50%);
  pointer-events: none;
  opacity: 0; transition: opacity 1.2s var(--ease);
}
/* the sandwich, and the whole point of the ring reading as a ring: far mesh, far words, near mesh,
   near words. A word on the back of the orbit is not dimmed into the distance, it is CROSSED by
   the hairlines that stand between it and the reader. Both canvases are theatre (aria-hidden) and
   neither takes a pointer, so a hand still lands on the word underneath. */
.orbit__sky--near { z-index: 3; }
.orbit--on .orbit__sky { opacity: 1; }
.orbit--on .never { position: absolute; inset: 0; display: block; pointer-events: none; }
.orbit--on .never li {
  position: absolute; left: 0; top: 0; z-index: 4;
  white-space: nowrap; pointer-events: auto;
  transform-origin: 50% 50%;
}
.orbit--on .never li.is-far { z-index: 2; }
/* the separator belongs to a line of words; on a ring there is no "next" to separate it from */
.orbit--on .never li::after { content: none; margin: 0; }

/* ---------- the ask (on paper) ---------- */
.ask {
  margin-top: clamp(42px, 5.6vh, 70px); padding-top: 34px;
  display: flex; flex-wrap: wrap; align-items: flex-start; gap: 22px 30px;
  background-image: linear-gradient(90deg, rgba(60, 60, 67, .18) 0%, rgba(60, 60, 67, .18) 74%, rgba(60, 60, 67, 0) 100%);
  background-size: 100% 1px; background-repeat: no-repeat; background-position: 0 0;
}
.ask-one { display: flex; flex-direction: column; gap: 12px; }
.cta-note { color: var(--paper-muted); }
.ask-note { flex: 1 1 320px; min-width: 260px; }
/* R15 — one door instead of two. A lone button in a row built for a pair reads as the leftover of
   a pair, so the survivor gets a column of its own: the button spans it, the address stands under
   it as the caption that names it, and the two sit level with the middle of the paragraph beside
   them instead of hanging off its first line. */
.ask--single { align-items: center; gap: 26px clamp(32px, 5vw, 70px); }
.ask--single .ask-one { flex: 0 0 auto; min-width: 250px; }
.ask--single .ask-one .btn { justify-content: center; }
.ask--single .cta-note { padding-left: 2px; }
.ask--single .ask-note { flex: 1 1 340px; }

/* ---------- /app — the three ways in ----------
   A quiet page: no stage, no kernel, no dock. Three panels of the page's own material, each one a
   platform, a caption that states its condition, and a single action. The card is the answer, so
   nothing is drawn around it. */
.page-app .band { padding-top: clamp(126px, 16vh, 186px); }
/* one room, not two: this page is a single band over a footer, so a band-scoped room light and
   grain tooth would simply end in a ruled step above the footer — exactly the seam the band rules
   elsewhere exist to avoid. Here they belong to the page instead. */
.page-app .band::before, .page-app .band::after { content: none; }
.page-app::before, .page-app::after {
  content: ""; position: fixed; inset: 0; pointer-events: none; z-index: 0;
}
.page-app::before {
  background: radial-gradient(96% 46% at 14% 32%, rgba(255, 255, 255, .06), rgba(255, 255, 255, 0) 62%);
}
.page-app::after {
  background-image: var(--grain); background-size: 180px 180px;
  opacity: .07; mix-blend-mode: screen;
}
.getlist { margin-top: clamp(40px, 5.4vh, 68px); }
.get { display: flex; flex-direction: column; gap: 12px; }
.get h3 { margin-bottom: 0; }
.get .cap { margin-top: -4px; }
/* the note takes the slack, so three cards of different copy lengths still land their buttons on
   one line */
.get .note { flex: 1 1 auto; max-width: none; }
.get .btn { align-self: flex-start; margin-top: 10px; }
.get-foot { margin-top: clamp(30px, 4vh, 46px); }

/* ---------- footer ---------- */
.foot {
  padding: 54px 0 clamp(120px, 16vh, 150px); color: var(--muted); font-size: 14px;
}
/* no dock underneath this one, so nothing has to be cleared */
.foot--slim { padding: clamp(44px, 6vh, 72px) 0 clamp(46px, 7vh, 78px); }
.foot a { color: var(--ink-2); text-decoration: none; }
/* the way back is the only link on the page that is not a button, so it wears the one mark that
   says link — and it has to be declared AFTER .foot a, which turns decoration off at the same
   specificity */
.foot--slim a { text-decoration: underline; text-decoration-color: rgba(255, 255, 255, .3); text-underline-offset: 5px; }
.foot--slim a:hover { color: var(--ink); text-decoration-color: rgba(255, 255, 255, .55); }
.foot-grid { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.2fr) auto; gap: clamp(24px, 4vw, 56px); align-items: start; }
.foot-site { color: var(--muted); }
@media (max-width: 900px) { .foot-grid { grid-template-columns: minmax(0, 1fr); } }

/* ---------- R7 — live interface fragments ----------
   The banner's language, extended: small excerpts of the product's real UI rebuilt as live DOM in
   the page's presentation layer. Nativo material (the app's white card) standing on the dark stage
   with the same border and indigo bloom as the real-pixel crops — siblings of the same family.
   App screens elsewhere remain real captures; a fragment is an excerpt, never a full screen. */

/* the shared card material */
.nfrag, .cfrag, .aviso, .flagc, .offr, .rot {
  background: var(--paper-card); color: var(--paper-ink);
  border-radius: 18px; border: 1px solid var(--line-2);
  box-shadow: var(--elev-2), 0 0 70px -20px rgba(165, 163, 255, .14);
}

/* --- the correction, assinada (confiança) --- */
.nfrag-shard { width: clamp(280px, 25vw, 356px); }
.nfrag { display: block; width: 100%; padding: 16px 18px 4px; cursor: pointer; text-align: left; font: inherit; transition: transform .3s var(--ease); }
.nfrag__t { display: flex; align-items: center; margin: 0 0 12px; font-size: 16.5px; font-weight: 640; letter-spacing: -.014em; }
.nfrag__row { display: flex; align-items: center; gap: 12px; padding: 12px 0 14px; border-top: 1px solid rgba(60, 60, 67, .10); border-radius: 10px; }
.nfrag__tile { flex: none; width: 32px; height: 32px; border-radius: 8px; position: relative; }
.nfrag__tile::after { content: ""; position: absolute; inset: 0; }
.nfrag__tile--cal { background: var(--accent-tint); }
.nfrag__tile--cal::after {
  background: var(--accent);
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Crect x='8' y='10' width='16' height='14' rx='2.5' fill='none' stroke='black' stroke-width='1.8'/%3E%3Cline x1='8' y1='15' x2='24' y2='15' stroke='black' stroke-width='1.8'/%3E%3Cline x1='12.5' y1='7.5' x2='12.5' y2='11' stroke='black' stroke-width='1.8' stroke-linecap='round'/%3E%3Cline x1='19.5' y1='7.5' x2='19.5' y2='11' stroke='black' stroke-width='1.8' stroke-linecap='round'/%3E%3C/svg%3E") center / contain no-repeat;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Crect x='8' y='10' width='16' height='14' rx='2.5' fill='none' stroke='black' stroke-width='1.8'/%3E%3Cline x1='8' y1='15' x2='24' y2='15' stroke='black' stroke-width='1.8'/%3E%3Cline x1='12.5' y1='7.5' x2='12.5' y2='11' stroke='black' stroke-width='1.8' stroke-linecap='round'/%3E%3Cline x1='19.5' y1='7.5' x2='19.5' y2='11' stroke='black' stroke-width='1.8' stroke-linecap='round'/%3E%3C/svg%3E") center / contain no-repeat;
}
.nfrag__tile--person { background: rgba(60, 60, 67, .10); }
.nfrag__tile--person::after {
  background: rgba(60, 60, 67, .62);
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Ccircle cx='16' cy='13' r='4' fill='none' stroke='black' stroke-width='1.8'/%3E%3Cpath d='M9 25c1.2-4 4-6 7-6s5.8 2 7 6' fill='none' stroke='black' stroke-width='1.8' stroke-linecap='round'/%3E%3C/svg%3E") center / contain no-repeat;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Ccircle cx='16' cy='13' r='4' fill='none' stroke='black' stroke-width='1.8'/%3E%3Cpath d='M9 25c1.2-4 4-6 7-6s5.8 2 7 6' fill='none' stroke='black' stroke-width='1.8' stroke-linecap='round'/%3E%3C/svg%3E") center / contain no-repeat;
}
.nfrag__label { font-size: 15.5px; letter-spacing: -.01em; }
.nfrag__val { margin-left: auto; position: relative; font-size: 15px; color: var(--paper-muted); white-space: nowrap; }
.nfrag__old, .nfrag__new { display: block; transition: transform .4s var(--ease), opacity .4s var(--ease); }
.nfrag__new { position: absolute; inset: 0; opacity: 0; transform: translateY(9px); }
.nfrag.played .nfrag__old { opacity: 0; transform: translateY(-9px); }
.nfrag.played .nfrag__new { opacity: 1; transform: none; transition-delay: .07s; }
@keyframes rowflash { 0% { background-color: rgba(88, 86, 214, 0); } 28% { background-color: rgba(88, 86, 214, .13); } 100% { background-color: rgba(88, 86, 214, 0); } }
.nfrag.playing .nfrag__row:not(.nfrag__row--sig) { animation: rowflash 1.05s var(--ease); }
.nfrag__sig { display: grid; grid-template-rows: 0fr; opacity: 0; transition: grid-template-rows .45s var(--ease) .26s, opacity .4s var(--ease) .32s; }
/* a replay resets INSTANTLY (no reverse choreography), then plays clean from zero */
.nfrag.still, .nfrag.still .nfrag__old, .nfrag.still .nfrag__new, .nfrag.still .nfrag__sig { transition: none !important; }
.nfrag__sig > div { overflow: hidden; min-height: 0; }
.nfrag.played .nfrag__sig { grid-template-rows: 1fr; opacity: 1; }
.nfrag__row--sig { padding-bottom: 16px; }
.nfrag__row--sig .nfrag__label { color: var(--paper-muted); }
/* like the notification: this air shard goes in-flow on narrow frames instead of vanishing */
@media (max-width: 1120px) {
  .nfrag-shard.shard--air { display: block; position: static; width: min(100%, 356px); margin: 34px 0 10px; }
}

/* --- the code, live (escola) --- */
.cfrag { padding: 14px; position: relative; }
.cfrag__enter { position: relative; }
.cfrag__in {
  width: 100%; border: 0; outline: 0; display: block;
  background: rgba(118, 118, 128, .12);
  border-radius: 12px; padding: 14px 16px;
  font: inherit; font-size: 20px; font-weight: 650; letter-spacing: .14em;
  color: var(--paper-ink); caret-color: var(--accent);
}
.cfrag__in:placeholder-shown { letter-spacing: 0; font-weight: 480; font-size: 16px; }
.cfrag__in::placeholder { color: rgba(60, 60, 67, .48); }
.cfrag__in:focus-visible { box-shadow: 0 0 0 2.5px var(--accent-tint), 0 0 0 1.5px var(--accent) inset; }
.cfrag__caret {
  position: absolute; top: 14px; bottom: 14px; width: 2px; border-radius: 1px;
  background: var(--accent); opacity: 0; pointer-events: none;
}
.cfrag__caret.on { animation: caret-blink 1.06s step-end infinite; }
@keyframes caret-blink { 0%, 55% { opacity: 1; } 56%, 100% { opacity: 0; } }
.cfrag__done { display: block; width: 100%; border: 0; cursor: pointer; background: transparent; text-align: left; padding: 8px 6px 6px; font: inherit; color: var(--paper-ink); border-radius: 12px; }

/* ---------- R9 — the code becomes the class, in three beats a reader can narrate ----------
   The old flip cut straight from a typed field to a finished card, and cause never reached effect.
   Now:
   1 ACCEPT (500ms) — the sixth character lands and the field TAKES it: the ring goes indigo, the
     code turns the action colour, and a check draws itself at the end of the field.
   2 HANDOFF (200ms) — the box is exchanged without the code moving. JS measures the field's text
     and starts the chip exactly on it (a FLIP: same left edge, same optical size), so as the grey
     field fades the letters stay put and only their container becomes a tag.
   3 UNFOLD (660ms) — the tag travels into the card's corner while 8º A · Colégio Anchieta grows
     out beneath it, the card's own height carried by a releasing min-height so nothing snaps.
   ~1.4s end to end. Under reduced motion the moment simply stands finished. */
.cfrag__in { transition: box-shadow .28s var(--ease), color .28s var(--ease); }
.cfrag.took .cfrag__in {
  box-shadow: 0 0 0 3px var(--accent-tint), 0 0 0 1.5px var(--accent) inset;
  color: var(--accent-deep);
}
/* the check: the page's own checkmark figure (the same two borders the status ticks are drawn
   from), springing in at the end of the field — the unmistakable "it took" */
.cfrag__ok {
  position: absolute; right: 17px; top: calc(50% - 8px);
  width: 15px; height: 8px;
  border-left: 2.5px solid var(--accent); border-bottom: 2.5px solid var(--accent);
  opacity: 0; transform: rotate(-45deg) scale(.3); transform-origin: 50% 50%;
  pointer-events: none;
  transition: opacity .16s var(--ease), transform .36s cubic-bezier(.3, 1.5, .4, 1);
}
.cfrag.took .cfrag__ok { opacity: 1; transform: rotate(-45deg) scale(1); }
/* the field leaves by fading, in place, under the chip that has already taken its letters */
.cfrag__enter.gone {
  position: absolute; left: 14px; right: 14px; top: 14px;
  opacity: 0; transform: scale(.985); transform-origin: left center; pointer-events: none;
  transition: opacity .2s var(--ease), transform .3s var(--ease);
}
.cfrag__chip {
  display: inline-block; padding: 3px 9px; border-radius: 7px;
  background: var(--accent-tint); color: var(--accent-deep);
  font-size: 13px; font-weight: 680; letter-spacing: .12em;
  transform-origin: left center;
  transition: transform .6s cubic-bezier(.3, 1.14, .4, 1), opacity .18s var(--ease);
}
.cfrag__body {
  display: grid; grid-template-rows: 1fr; opacity: 1;
  transition: grid-template-rows .48s var(--ease) .1s, opacity .4s var(--ease) .16s, transform .48s var(--ease) .16s;
}
.cfrag__bin { display: block; overflow: hidden; min-height: 0; }
.cfrag__bin b { display: block; margin-top: 9px; font-size: 22px; font-weight: 680; letter-spacing: -.02em; }
.cfrag__sub { display: block; margin-top: 3px; font-size: 14.5px; color: var(--paper-muted); }
/* The card holds the field's own height while the turma grows into it and only lets go once the
   content has already passed it (hence the delay — releasing the floor earlier makes the white
   surface dip before it grows, and a card that shrinks first tells the wrong story). */
.cfrag__done { transition: min-height .44s var(--ease) .26s; }
.cfrag__done.pre .cfrag__chip { opacity: 0; }
.cfrag__done.pre .cfrag__body { grid-template-rows: 0fr; opacity: 0; transform: translateY(6px); }
.cfrag__done.still, .cfrag__done.still .cfrag__chip, .cfrag__done.still .cfrag__body { transition: none !important; }
.cfrag__done:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* --- the aviso that answers (status) --- */
.aviso { padding: 18px 18px 16px; }
.aviso__head { margin: 0; font-size: 16px; font-weight: 640; letter-spacing: -.014em; line-height: 1.4; }
.aviso__chip {
  display: inline-block; vertical-align: 2px; margin-right: 8px;
  padding: 2.5px 8px; border-radius: 6px;
  background: var(--accent-tint); color: var(--accent-deep);
  font-size: 10.5px; font-weight: 700; letter-spacing: .05em; text-transform: uppercase;
}
.aviso__body { margin: 8px 0 0; font-size: 14.5px; line-height: 1.55; color: #3a3a3f; }
.aviso__meta { margin: 8px 0 0; font-size: 13px; color: var(--paper-muted); }
.aviso__ask {
  position: relative; display: grid; grid-template-columns: 1fr 1fr;
  margin-top: 14px; padding: 3px;
  background: #e9e9ee; border-radius: 12px;
}
.aviso__ask::before {
  content: ""; position: absolute; left: 50%; top: 20%; bottom: 20%; width: 1px;
  background: rgba(60, 60, 67, .18); transition: opacity .2s var(--ease);
}
.aviso__ask.answered::before { opacity: 0; }
.aviso__opt {
  position: relative; z-index: 1; border: 0; background: transparent; cursor: pointer;
  padding: 10px 0; border-radius: 9px;
  font: inherit; font-size: 15px; font-weight: 590; color: var(--paper-ink);
  transition: background-color .22s var(--ease), color .22s var(--ease), transform .12s var(--ease);
}
.aviso__opt:active { transform: scale(.97); }
.aviso__opt[aria-pressed="true"] { background: var(--accent); color: #fff; }
.aviso__opt:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.aviso__foot { margin: 10px 0 0; font-size: 13px; color: var(--paper-muted); }

/* --- the light interactivity pass: things respond to a hand ---
   Transform only, and never on a parallax-driven element (page.js owns those inline). */
@media (hover: hover) {
  .nfrag:hover, .cfrag:hover, .aviso:hover, .flagc:hover, .offr:hover, .rot:hover { transform: translateY(-3px); }
  .cfrag, .aviso, .flagc, .offr, .rot { transition: transform .3s var(--ease); }
  .trio .shot .device, .lens-device .device { transition: transform .38s var(--ease); }
  .trio .shot .device:hover, .lens-device .device:hover { transform: translateY(-5px); }
}
.nfrag:focus-visible { outline: 2px solid var(--accent-lift); outline-offset: 3px; }

/* ---------- R8 — the page under the reader's hands ----------
   The banner's language spread wide: the chaos itself runs live in #problema, a flag takes a real
   Dispensar, the professor's publication receives its Oficial mark, the turma code is revoked in
   front of the reader, and the stage's lead times answer the pointer. Everything
   IntersectionObserver-armed, transform/opacity, re-armed on full exit. */

/* --- the chaos stream (problema) --- */
.chaos { margin: clamp(30px, 4vh, 46px) 0 0; width: min(100%, 380px); }
.chaos__frame {
  position: relative; height: 252px; overflow: hidden;
  border-radius: 18px;
  background: var(--glass-bg);
  border: 1px solid var(--line-2);
  box-shadow: var(--elev-1);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  /* messages surface from below and drown past the top */
  -webkit-mask-image: linear-gradient(180deg, transparent 2%, #000 20%, #000 84%, transparent 98%);
  mask-image: linear-gradient(180deg, transparent 2%, #000 20%, #000 84%, transparent 98%);
  cursor: default;
}
/* R9 — the flood never stops and never restarts.
   NO vertical padding on the track: translateY(-50%) lands copy 2 exactly where copy 1 stood only
   if the track is exactly two copies tall. The old 18px padding-top rode inside the -50% and every
   wrap displaced the content by 9px — measured — and that was the one visible jerk. The mask owns
   the edges instead. flow-root, or the last bubble's margin-bottom escapes and shorts the height by
   half a gap.
   The animation is DECLARED always and merely held: leaving the section pauses it where it stands
   (a paused animation generates no frames, so idle cost is still zero) and coming back continues
   from that exact phase. Nothing on this page ever restarts the stream. */
.chaos__track {
  display: flow-root; padding: 0 16px; will-change: transform;
  animation: chaos-up 30s linear infinite;
  animation-play-state: paused;
}
.chaos.on .chaos__track { animation-play-state: running; }
@keyframes chaos-up { to { transform: translateY(-50%); } }
/* a hand (or a tap) holds the flood still — in place — and the buried answer lights */
.chaos__frame:hover .chaos__track, .chaos.paused .chaos__track { animation-play-state: paused; }
.cmsg {
  max-width: 82%; width: fit-content; margin: 0 0 7px;
  padding: 7.5px 12px; border-radius: 14px 14px 14px 5px;
  background: rgba(255, 255, 255, .075);
  font-size: 13.5px; line-height: 1.4; color: var(--ink-2); letter-spacing: -.005em;
}
.cmsg--right {
  margin-left: auto; border-radius: 14px 14px 5px 14px;
  background: rgba(88, 86, 214, .2); color: #d9dcea;
}
.cmsg--truth {
  border: 1px solid rgba(165, 163, 255, .34);
  transition: background-color .3s var(--ease), border-color .3s var(--ease), color .3s var(--ease);
}
.chaos__frame:hover .cmsg--truth, .chaos.paused .cmsg--truth {
  background: rgba(88, 86, 214, .30); border-color: var(--accent-lift); color: #fff;
}

/* --- the flag with a working Dispensar + the Oficial stamp (confiança) --- */
.live-pair {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(24px, 3vw, 44px); align-items: start;
  margin-top: clamp(38px, 5.4vh, 66px); max-width: 860px;
}
.lpiece { margin: 0; }
.flagc { padding: 16px 18px 14px; }
.flagc__t { display: flex; align-items: center; margin: 0; font-size: 16px; font-weight: 640; letter-spacing: -.014em; }
.flagc__m { margin: 9px 0 0; font-size: 14.5px; line-height: 1.5; color: #3a3a3f; }
.flagc__by { margin: 7px 0 0; font-size: 13px; color: var(--paper-muted); }
.flagc__grid { display: grid; grid-template-rows: 1fr; transition: grid-template-rows .4s var(--ease); }
.flagc__grid > .flagc__acts { overflow: hidden; min-height: 0; }
.flagc__acts { display: flex; gap: 10px; padding-top: 13px; }
.flagc__b {
  flex: 1; border: 0; cursor: pointer; padding: 10px 0; border-radius: 10px;
  font: inherit; font-size: 14.5px; font-weight: 600;
  background: var(--accent-tint); color: var(--accent-deep);
  transition: transform .12s var(--ease), opacity .2s var(--ease);
}
.flagc__b:active { transform: scale(.97); }
.flagc__b--x { background: rgba(255, 59, 48, .10); color: #d70015; }
.flagc__b:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.flagc.resolved .flagc__grid { grid-template-rows: 0fr; }
.flagc.resolved .flagc__acts { opacity: 0; pointer-events: none; transition: opacity .25s var(--ease); }
.flagc.resolved .flagc__m, .flagc.resolved .flagc__by { opacity: .45; transition: opacity .3s var(--ease); }
.flagc__done { margin: 12px 0 2px; font-size: 14px; font-weight: 600; color: var(--accent-deep); }
.flagc__done::before {
  content: ""; display: inline-block; width: 12px; height: 7px; margin-right: 8px;
  border-left: 2px solid var(--accent-deep); border-bottom: 2px solid var(--accent-deep);
  transform: rotate(-45deg) translateY(-2px);
}
@keyframes done-rise { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }
.flagc__done:not([hidden]) { animation: done-rise .4s var(--ease) both; }

.offr { padding: 16px 18px 14px; }
.offr__t { display: flex; align-items: center; flex-wrap: wrap; gap: 4px 0; margin: 0; font-size: 16px; font-weight: 640; letter-spacing: -.014em; }
.offr__by { margin: 7px 0 0; font-size: 13px; color: var(--paper-muted); }
.offr__badge {
  display: inline-block; margin-left: 10px; padding: 2.5px 8px; border-radius: 6px;
  background: var(--accent-tint); color: var(--accent-deep);
  font-size: 10.5px; font-weight: 700; letter-spacing: .05em; text-transform: uppercase;
  opacity: 0; transform: scale(1.6);
  transition: opacity .4s var(--ease), transform .45s cubic-bezier(.3, 1.4, .4, 1);
}
.offr__badge.in { opacity: 1; transform: none; }
@media (max-width: 760px) { .live-pair { grid-template-columns: minmax(0, 1fr); } }

/* --- the code revoked live (privacidade) --- */
.rot { margin-top: 26px; padding: 15px 16px 14px; max-width: 300px; }
.rot__h { display: block; margin-bottom: 8px; font-size: 12px; font-weight: 650; letter-spacing: .06em; text-transform: uppercase; color: var(--paper-muted); }
.rot__codes { display: grid; gap: 4px; }
.rot__code {
  position: relative; width: fit-content;
  font-size: 21px; font-weight: 680; letter-spacing: .13em; color: var(--paper-ink);
  transition: color .35s var(--ease);
}
/* the same ruler-straight line language as the anti-list, drawn left to right as the code dies */
.rot__code::after {
  content: ""; position: absolute; left: -.03em; right: .08em; top: 48%; height: 2px; border-radius: 1px;
  background: rgba(28, 28, 30, .55);
  transform: scaleX(0); transform-origin: left center;
  transition: transform .32s var(--ease);
}
.rot__code.dead { color: rgba(28, 28, 30, .34); }
.rot__code.dead::after { transform: scaleX(1); }
.rot__code.enter { opacity: 0; transform: translateY(8px); }
.rot__code.enter.live { opacity: 1; transform: none; transition: opacity .4s var(--ease) .18s, transform .45s cubic-bezier(.3, 1.3, .4, 1) .18s; }
.rot__btn {
  margin-top: 12px; border: 0; cursor: pointer; display: block; width: 100%;
  padding: 10px 0; border-radius: 10px;
  font: inherit; font-size: 14.5px; font-weight: 600;
  background: var(--accent-tint); color: var(--accent-deep);
  transition: transform .12s var(--ease);
}
.rot__btn:active { transform: scale(.98); }
.rot__btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.rot__cap { margin: 13px 0 0; padding-left: 2px; }

/* --- the checkmarks arrive in sequence (status) --- */
.ticks.armed li::before {
  opacity: 0; transform: rotate(-45deg) scale(.35); transform-origin: 40% 60%;
  transition: opacity .28s var(--ease), transform .3s cubic-bezier(.3, 1.3, .4, 1);
  transition-delay: calc(var(--i, 0) * 55ms);
}
.ticks.armed.play li::before { opacity: 1; transform: rotate(-45deg) scale(1); }

/* --- the ladder lights step by step (escola) --- */
.steps.armed li { opacity: .42; transition: opacity .55s var(--ease); }
.steps.armed li.lit { opacity: 1; }

/* --- the three asks deal in (piloto) --- */
#askCards.armed .card {
  opacity: 0; transform: translateY(26px) rotate(var(--r, 0deg));
  transition: opacity .5s var(--ease), transform .6s cubic-bezier(.3, 1.25, .4, 1);
  transition-delay: calc(var(--i, 0) * 95ms);
}
#askCards.armed.play .card { opacity: 1; transform: none; }

/* --- the anti-list answers a hand: the line steps back so the word reads, then re-strikes --- */
@media (hover: hover) {
  .never li.in .w:hover::after { transform: scaleX(0); transition-duration: .26s; }
}

/* ================= R10 — the two sections that were still being described =================
   #papeis showed its argument only to a reader who happened to click a plate, and #status stated
   its readiness in ticks. Both now demonstrate instead: the lens shows itself account by account
   until a hand takes it, and the school's own console populates in front of the tick that
   claims it. */

/* --- the lens shows itself (papeis) ---
   A thin line under the standing plate says the page is driving, not the reader. It exists only
   while the tour is running, so its disappearance IS the handover: the first touch ends the tour
   for good and the line goes with it. */
.plate { position: relative; overflow: hidden; }
.plate-bar {
  position: absolute; left: 0; bottom: 0; height: 2px; width: 100%;
  background: var(--accent-lift); opacity: 0;
  transform: scaleX(0); transform-origin: left center;
  pointer-events: none;
}
.plate.touring .plate-bar {
  opacity: .5; transform: scaleX(1);
  transition: transform var(--dwell, 3200ms) linear, opacity .22s var(--ease);
}

/* the screen swap is a WAKE, never a crossfade: the screen goes out, the capture is exchanged in
   the dark, and it comes back on. Two real UIs dissolved through each other would read as an
   invented UI — the same law the 3D stage swaps its textures under. */
.lens-device .device__body img { transition: opacity .17s var(--ease), transform .3s var(--ease); }
.lens-device.waking .device__body img { opacity: 0; transform: scale(.988); }

/* --- R10.1 — the Eu screen, live (privacidade) ---
   The claim is that the product asks a person for exactly two things, so the card hands the reader
   both of them: ONE check hops between the four offsets, and «Editar» opens the name in place.
   App ground, app groups, app values; an excerpt of Eu, never the whole screen. */
.efrag {
  background: var(--paper); color: var(--paper-ink);
  border-radius: 18px; border: 1px solid var(--line-2);
  box-shadow: var(--elev-2), 0 0 70px -20px rgba(165, 163, 255, .14);
  padding: 16px 14px;
}
.efrag__scr { margin: 0 0 15px; font-size: 30px; font-weight: 700; letter-spacing: -.032em; line-height: 1; }
.efrag__h {
  margin: 0 0 7px; padding-left: 5px;
  font-size: 11.5px; font-weight: 650; letter-spacing: .06em; text-transform: uppercase;
  color: var(--paper-muted);
}
.efrag__sub { margin: 0 0 7px; padding-left: 5px; font-size: 14px; color: var(--paper-muted); }
.efrag__g { background: var(--paper-card); border-radius: 16px; overflow: hidden; }
.efrag__g + .efrag__h { margin-top: 19px; }
.efrag__nrow { padding: 13px 15px 12px; }
.efrag__name, .efrag__nin {
  display: block; font-size: 23px; font-weight: 690; letter-spacing: -.022em;
  line-height: 1.24; color: var(--paper-ink);
}
.efrag__nin {
  width: 100%; border: 0; outline: 0; background: transparent; padding: 0;
  font-family: inherit; caret-color: var(--accent);
}
.efrag__note { display: block; margin-top: 3px; font-size: 14px; color: var(--paper-muted); }
.efrag__edit {
  position: relative; display: block; width: 100%; text-align: left;
  border: 0; cursor: pointer; font: inherit;
  padding: 12px 15px; background: transparent; color: var(--accent-deep);
  font-size: 16px; font-weight: 560;
  transition: background-color .16s var(--ease);
}
/* the app insets its group hairlines to the text, both here and between the offsets */
.efrag__edit::before {
  content: ""; position: absolute; left: 15px; right: 0; top: 0; height: 1px;
  background: var(--paper-line);
}
.efrag__edit:active, .efrag__edit[aria-pressed="true"] { background: rgba(88, 86, 214, .10); }
.efrag__edit:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.efrag__opts { position: relative; }
.efrag__opt {
  position: relative; display: block; width: 100%; text-align: left;
  border: 0; background: transparent; cursor: pointer; font: inherit;
  font-size: 16px; letter-spacing: -.01em; color: var(--paper-ink);
  padding: 13px 46px 13px 15px;
  transition: background-color .18s var(--ease);
}
.efrag__opt + .efrag__opt::before {
  content: ""; position: absolute; left: 15px; right: 0; top: 0; height: 1px;
  background: var(--paper-line);
}
@media (hover: hover) { .efrag__opt:hover { background: rgba(60, 60, 67, .045); } }
.efrag__opt:active { background: rgba(60, 60, 67, .085); }
.efrag__opt:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
/* ONE check, and it hops: the same figure the status ticks are drawn from, translated to the row
   the reader chose. JS writes the whole transform, so the travel and the draw are one spring. */
.efrag__check {
  position: absolute; right: 19px; top: 0; width: 15px; height: 8px;
  border-left: 2.5px solid var(--accent); border-bottom: 2.5px solid var(--accent);
  opacity: 0; transform-origin: 50% 50%; pointer-events: none;
  transition: transform .44s cubic-bezier(.3, 1.42, .4, 1), opacity .2s var(--ease);
}
.efrag.drawn .efrag__check { opacity: 1; }
.efrag.still .efrag__check { transition: none; }
/* the card arrives group by group — the ask is short, and it is legible that it is short */
.efrag.armed > * {
  opacity: 0; transform: translateY(11px);
  transition: opacity .5s var(--ease), transform .58s cubic-bezier(.3, 1.2, .4, 1);
  transition-delay: calc(var(--i, 0) * 70ms);
}
.efrag.armed.play > * { opacity: 1; transform: none; }

/* --- R10.1 — the school console, live (status) ---
   The tick above it says the console is built; this shows one. It populates on arrival and the
   participant count settles on the turma's real 12. Desvincular is destructive, so the page never
   presses it and a press here explains rather than performs. */
.kfrag {
  background: var(--paper); color: var(--paper-ink);
  border-radius: 16px; border: 1px solid var(--line-2);
  box-shadow: var(--elev-2), 0 0 70px -20px rgba(165, 163, 255, .14);
  padding: 14px 12px 12px;
}
.kfrag__scr { margin: 0 0 12px; font-size: 25px; font-weight: 700; letter-spacing: -.03em; line-height: 1.05; }
.kfrag__h {
  margin: 0 0 7px; padding-left: 5px;
  font-size: 11px; font-weight: 650; letter-spacing: .06em; text-transform: uppercase;
  color: var(--paper-muted);
}
.kfrag__g { background: var(--paper-card); border-radius: 14px; overflow: hidden; }
.kfrag__row { display: flex; align-items: center; gap: 10px; padding: 12px 14px; transition: background-color .18s var(--ease); }
.kfrag__cls { display: block; font-size: 17px; font-weight: 560; letter-spacing: -.014em; }
.kfrag__n { display: block; margin-top: 2px; font-size: 13.5px; font-weight: 400; color: var(--paper-muted); font-variant-numeric: tabular-nums; }
.kfrag__x {
  margin-left: auto; flex: none; border: 0; cursor: pointer; font: inherit;
  padding: 8px 8px; border-radius: 8px; background: transparent;
  font-size: 15px; font-weight: 560;
  /* the app's #FF3B30 driven down in value so destructive text clears the floor on paper — the
     same move --accent-deep makes for the indigo, and the one the flag's Excluir already made */
  color: #d70015;
  transition: background-color .16s var(--ease), transform .12s var(--ease);
}
@media (hover: hover) {
  .kfrag__row:hover { background: rgba(60, 60, 67, .035); }
  .kfrag__x:hover { background: rgba(255, 59, 48, .11); }
}
.kfrag__x:active { transform: scale(.96); background: rgba(255, 59, 48, .15); }
.kfrag__x:focus-visible { outline: 2px solid #d70015; outline-offset: 1px; }
.kfrag__said { margin: 11px 5px 2px; font-size: 13px; line-height: 1.45; color: var(--paper-muted); }
.kfrag__said:not([hidden]) { animation: done-rise .38s var(--ease) both; }
.kfrag.armed > * {
  opacity: 0; transform: translateY(9px);
  transition: opacity .46s var(--ease), transform .54s cubic-bezier(.3, 1.2, .4, 1);
  transition-delay: calc(var(--i, 0) * 80ms);
}
.kfrag.armed.play > * { opacity: 1; transform: none; }

/* the two new cards join the family that answers a hand */
@media (hover: hover) {
  .efrag, .kfrag { transition: transform .3s var(--ease); }
  .efrag:hover, .kfrag:hover { transform: translateY(-3px); }
}

/* --- the answer settles (status) --- */
@keyframes opt-settle { 0% { transform: scale(.93); } 58% { transform: scale(1.035); } 100% { transform: none; } }
.aviso__opt[aria-pressed="true"] { animation: opt-settle .44s var(--ease); }
.status-shot figcaption.said { animation: done-rise .4s var(--ease) both; }

/* ---------- reveals (opacity+transform only) ---------- */
.rise { opacity: 0; transform: translateY(20px); transition: opacity .62s var(--ease), transform .62s var(--ease); }
.rise.in { opacity: 1; transform: none; }
/* the parallax layer page.js drives — declared here so it degrades to nothing without JS */
[data-par] { will-change: transform; }

@media (max-width: 900px) {
  .cols--2, .cols--3, .cols--4, .cols--status { grid-template-columns: minmax(0, 1fr); }
  .top { padding: 18px var(--pad); }
  .trio { grid-template-columns: minmax(0, 1fr); gap: clamp(52px, 9vw, 76px); }
  .shot .device { max-width: 300px; }
  .shot:nth-child(1), .shot:nth-child(3) { padding-top: 0; }
  .shot:nth-child(1) .device__body, .shot:nth-child(3) .device__body { transform: none; }
  .steps li { grid-template-columns: minmax(0, 1fr); }
}
@media (max-width: 760px) {
  .dock a[data-opt] { display: none; }
  /* the two in-page anchors fold away first — the dock already reaches those sections. What must
     survive to the narrowest screen is the app and the way in, so those two stay. */
  .topnav a[data-opt] { display: none; }
  .topnav { gap: 16px; }
  .topnav .topnav__in { padding: 8px 15px; }
  .foot { padding-bottom: 132px; }
  .device__body { border-radius: 34px; padding: 5px; }
  .device__body img { border-radius: 29px; }
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .rise { opacity: 1; transform: none; transition: none; }
  .never .w::after { transform: scaleX(1); transition: none; }
  [data-par] { transform: none !important; }
  /* fragments stand in their honest final states; the controls still work, nothing travels */
  .nfrag, .cfrag, .aviso, .flagc, .offr, .rot,
  .nfrag__old, .nfrag__new, .nfrag__sig, .aviso__opt, .aviso__ask::before,
  .cfrag__in, .cfrag__chip, .cfrag__body, .cfrag__ok, .cfrag__enter, .cfrag__done,
  .flagc__grid, .flagc__acts, .flagc__m, .flagc__by, .rot__code, .rot__code::after, .offr__badge { transition: none; }
  /* the flood stands still and the answer is simply lit — the track is never doubled here */
  .chaos__track { animation: none; }
  .nfrag:hover, .cfrag:hover, .aviso:hover, .flagc:hover, .offr:hover, .rot:hover { transform: none; }
  /* R10 statics: the lens never tours (auto-changing content is exactly what this preference is
     asking us not to do), the screen swaps without a dip, and the two new cards stand finished —
     the check simply sits on the offset that is chosen and moves the instant one is picked. */
  .plate-bar { display: none; }
  .lens-device .device__body img, .lens-device.waking .device__body img { transition: none; opacity: 1; transform: none; }
  .efrag, .kfrag, .efrag > *, .kfrag > *, .efrag__check, .efrag__opt, .efrag__edit, .kfrag__row, .kfrag__x { transition: none; }
  .efrag:hover, .kfrag:hover { transform: none; }
  .aviso__opt[aria-pressed="true"], .kfrag__said:not([hidden]), .status-shot figcaption.said { animation: none; }
  /* R8 statics: the mark stands, the buried answer is simply lit, the codes swap without travel */
  .offr__badge { opacity: 1; transform: none; }
  .rot__code.enter { opacity: 1; transform: none; }
  .cmsg--truth { background: rgba(88, 86, 214, .30); border-color: var(--accent-lift); color: #fff; }
  * { animation-duration: .001ms !important; animation-iteration-count: 1 !important; }
}
