/* ============================================================
   rift · world.css — token layer, phase 0 starter
   ------------------------------------------------------------
   Copied verbatim from the design system's tokens/ on 2026-08-19:
     D:/DESIGN/RIFT Design System/tokens/
   Files, in the DS's own import order: typography.css, palette.css, spacing.css, motion.css, theme-dark.css, theme-light.css
   Source of truth is still D:/DESIGN — re-read SKILL.md / readme /
   tokens there before building. Resets, base layouts and component
   CSS were deliberately NOT copied: layout is this world's own job.

   Google Fonts @import lines were removed (rule: fonts are self-hosted,
   see docs/04-world-contract.md §fonts). The families each token file
   expected are listed right where the import used to be.
   ============================================================ */

/* ---------- tokens/typography.css ---------- */
/* Type — fonts + scale */

/* [phase-0] Google Fonts import removed. Self-host these families
   (see docs/04-world-contract.md §fonts): Space Grotesk, Chakra Petch, DM Serif Display, Rajdhani, Share Tech Mono, Shippori Mincho, Zen Kaku Gothic New */

:root {
  /* Families — display is general headings, wordmark is reserved for big
     glitch wordmarks (RIFT). Italic is the lone serif accent. */
  --font-display: "Space Grotesk", system-ui, sans-serif;
  --font-wordmark: "Chakra Petch", "Space Grotesk", sans-serif;
  --font-italic: "DM Serif Display", "Space Grotesk", serif;
  --font-ui: "Rajdhani", system-ui, sans-serif;
  --font-mono: "Share Tech Mono", ui-monospace, Menlo, monospace;
  --font-jp: "Shippori Mincho", "Yu Mincho", serif;
  --font-jp-ui: "Zen Kaku Gothic New", sans-serif;

  /* Scale */
  --text-xs: 11px;
  --text-sm: 13px;
  --text-base: 15px;
  --text-lg: 18px;
  --text-xl: 24px;
  --text-2xl: 32px;
  --text-3xl: 42px;
  --text-4xl: 56px;
  --text-5xl: 72px;

  /* Weights */
  --weight-light: 300;
  --weight-regular: 400;
  --weight-medium: 500;
  --weight-semibold: 600;
  --weight-bold: 700;
}

/* ---------- tokens/palette.css ---------- */
/* Raw palette — theme-independent. The semantic layer in
   theme-dark.css / theme-light.css maps these to surface/ink/glass tokens. */

:root {
  /* Cool spectrum — midnight → ice */
  --midnight: #0A1230;
  --slate:    #54668D;
  --steel:    #7B8BB0;
  --royal:    #5C7BFF;
  --cobalt:   #3F86E0;
  --sky:      #6BB6F0;
  --ice:      #8FD2F5;
  --aqua:     #8AD8D0;
  --aurora:   #B8DCFF;

  /* Status */
  --ok:   #4DCB97;
  --warn: #ECB85F;
  --bad:  #FF7480;

  /* Chromatic edge — default pair (sky × royal). Override via data-accent. */
  --glitch-ca: var(--sky);
  --glitch-cb: var(--royal);
}

/* Accent re-channels — scope on any wrapper:
   <main data-accent="royal"> … </main>
   Each pair is an opponent-color duotone for .rift-glitch and accent halos. */

/* royal — sky × royal. Tonal, quiet. The default. */
[data-accent="royal"] {
  --glitch-ca: var(--sky);
  --glitch-cb: var(--royal);
}
/* aqua — aqua × royal. Soft, cool-on-cool. */
[data-accent="aqua"] {
  --glitch-ca: var(--aqua);
  --glitch-cb: var(--royal);
}

/* ---------- tokens/spacing.css ---------- */
/* Spacing (4px grid) + radius */

:root {
  --sp-1:  4px;
  --sp-2:  8px;
  --sp-3:  12px;
  --sp-4:  16px;
  --sp-5:  20px;
  --sp-6:  24px;
  --sp-8:  32px;
  --sp-10: 40px;
  --sp-12: 48px;
  --sp-16: 64px;
  --sp-20: 80px;

  --r-xs:   6px;
  --r-sm:   10px;
  --r-md:   14px;
  --r-lg:   18px;
  --r-xl:   24px;
  --r-2xl:  32px;
  --r-pill: 999px;
}

/* ---------- tokens/motion.css ---------- */
/* Motion — easing curves, durations, glow primitives. */

:root {
  --ease-out:  cubic-bezier(0.22, 1, 0.36, 1); /* @kind other */
  --ease-rise: cubic-bezier(0.16, 1, 0.30, 1); /* @kind other */

  --dur-fast: 140ms; /* @kind other */
  --dur-base: 320ms; /* @kind other */
  --dur-slow: 720ms; /* @kind other */

  /* Glow primitives — used by .rift-dot and accent halos. */
  --glow-ice:   0 0 12px rgba(143, 210, 245, 0.50);
  --glow-royal: 0 0 16px rgba( 92, 123, 255, 0.50);
  --glow-ok:    0 0  8px rgba( 77, 203, 151, 0.50);
  --glow-warn:  0 0  8px rgba(236, 184,  95, 0.50);
  --glow-bad:   0 0  8px rgba(255, 116, 128, 0.50);
}

/* ---------- tokens/theme-dark.css ---------- */
/* Semantic layer — DARK (default).
   Toggle by setting `data-theme="light"` on <html>, <body>, or a wrapper. */

:root,
[data-theme="dark"] {
  color-scheme: dark;

  --canvas: radial-gradient(125% 90% at 50% -10%, #1A2F58 0%, #0A1633 46%, #050A1C 100%); /* @kind other */
  --grid: rgba(184, 220, 255, 0.05);

  /* Surfaces */
  --bg-base:     #070C1B;
  --bg-surface:  #0E1830;
  --bg-elevated: #15233F;
  --bg-sunken:   #050A18;

  /* Ink (text) */
  --ink-1: #EDF2FF;
  --ink-2: #A7B4D2;
  --ink-3: #6B7896;
  --ink-4: #3E4866;

  /* Glass */
  --glass-1-bg:     hsla(220, 48%, 16%, 0.22);
  --glass-2-bg:     hsla(220, 52%, 20%, 0.30);
  --glass-3-bg:     hsla(220, 56%, 24%, 0.24);
  --glass-border:   hsla(200, 80%, 85%, 0.20);
  --glass-inner-hi: rgba(255, 255, 255, 0.10);

  /* Lines */
  --line-1:      rgba(184, 220, 255, 0.07);
  --line-2:      rgba(184, 220, 255, 0.13);
  --line-strong: rgba(184, 220, 255, 0.24);

  /* Shadows — layered (tight contact + wider ambient). On near-black canvas
     the contrast comes from heavy alphas on pure black, not navy tint. */
  --shadow-sm:   0  2px  4px      rgba(0, 0, 0, 0.32), 0  4px 12px -2px  rgba(0, 0, 0, 0.22);
  --shadow-md:   0  4px  8px      rgba(0, 0, 0, 0.38), 0 12px 24px -4px  rgba(0, 0, 0, 0.32);
  --shadow-lg:   0  8px 16px      rgba(0, 0, 0, 0.45), 0 24px 48px -8px  rgba(0, 0, 0, 0.45);
  --shadow-xl:   0 12px 24px      rgba(0, 0, 0, 0.50), 0 40px 80px -12px rgba(0, 0, 0, 0.60);
  --shadow-glow: 0  8px 32px -8px rgba(92, 123, 255, 0.55);

  /* Ambient FX */
  --scan-line:   rgba(237, 242, 255, 0.045);
  --frame-color: var(--ice);
}

/* ---------- tokens/theme-light.css ---------- */
/* Semantic layer — LIGHT (daybreak / 黎明).
   Pure token override: no component code changes. */

[data-theme="light"] {
  color-scheme: light;

  --canvas: radial-gradient(125% 90% at 50% -10%, #FFFFFF 0%, #E8F0FD 46%, #D2E0F6 100%); /* @kind other */
  --grid: rgba(34, 64, 128, 0.07);

  /* Surfaces */
  --bg-base:     #EAF1FC;
  --bg-surface:  #F4F8FF;
  --bg-elevated: #FAFCFF;
  --bg-sunken:   #DCE7F8;

  /* Ink */
  --ink-1: #0A1430;
  --ink-2: #3E4F76;
  --ink-3: #6B7896;
  --ink-4: #A6B6D4;

  /* Slight palette re-balance for legibility on light */
  --royal:  #3F5BE6;
  --cobalt: #2E6FD6;

  /* Glass */
  --glass-1-bg:     hsla(214, 74%, 99%, 0.38);
  --glass-2-bg:     hsla(214, 68%, 98%, 0.52);
  --glass-3-bg:     hsla(214, 62%, 97%, 0.42);
  --glass-border:   rgba( 40,  72, 130, 0.20);
  --glass-inner-hi: rgba(255, 255, 255, 0.90);

  /* Lines */
  --line-1:      rgba(20, 45, 95, 0.08);
  --line-2:      rgba(20, 45, 95, 0.15);
  --line-strong: rgba(20, 45, 95, 0.30);

  /* Shadows — layered (tight contact + wider ambient). Blue-tinted but with
     real alpha so depth reads on near-white surfaces. */
  --shadow-sm:   0  1px  2px      rgba(20, 45, 95, 0.10), 0  2px  6px      rgba(20, 45, 95, 0.08);
  --shadow-md:   0  3px  6px      rgba(20, 45, 95, 0.14), 0  8px 16px -2px rgba(20, 45, 95, 0.14);
  --shadow-lg:   0  6px 12px      rgba(20, 45, 95, 0.18), 0 20px 32px -8px rgba(20, 45, 95, 0.22);
  --shadow-xl:   0 10px 20px      rgba(20, 45, 95, 0.22), 0 32px 56px -12px rgba(20, 45, 95, 0.32);
  --shadow-glow: 0 10px 32px -8px rgba(63, 91, 230, 0.40);

  /* Ambient FX */
  --scan-line:   rgba(20, 45, 95, 0.05);
  --frame-color: var(--cobalt);

  /* Lighten the cyan halo for light backgrounds */
  --glow-ice: 0 0 12px rgba(63, 120, 200, 0.40);
}

/* ============================================================
   phase 1 — the seam
   ------------------------------------------------------------
   One idea holds this world together: the DS's chromatic edge is
   not decoration here, it is the layout. A single vertical seam
   splits the page. Left of it is midnight — what each project was
   when it was only an idea (its first commit). Right of it is
   daybreak — what actually runs now. Drag the seam and you choose
   how much of each you are willing to look at.

   The page is rendered twice into two identical layers. They differ
   only in theme: the night copy is lit midnight, the day copy daybreak
   and clipped to whatever lies right of the seam. Identical DOM and
   identical layout means the seam cuts through glyphs, not between
   them — which is exactly what the DS's chromatic edge looks like.
   ============================================================ */

/* ---------- the DS's signature FX ----------
   Copied verbatim from D:/DESIGN/RIFT Design System/effects.css on
   2026-09-01. Phase 0 brought over tokens/ only, on the grounds that layout
   is each world's own job — but the chromatic glitch, the tactical frame and
   the kanji watermark are not layout, they are the brand's three non-colour
   signatures, and the world contract requires one of each on the first
   screen. The DS's own reduced-motion block is deliberately NOT copied: it
   kills every animation on the page with `*`, and this world defines its own
   still version further down. */

.rift-glitch {
  --ca: var(--glitch-ca);
  --cb: var(--glitch-cb);
  position: relative;
  display: inline-block;
}
.rift-glitch::before,
.rift-glitch::after {
  content: attr(data-text);
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  z-index: -1;
  white-space: inherit;
}
.rift-glitch::before { color: var(--ca); transform: translate(-0.055em,  0.01em); }
.rift-glitch::after  { color: var(--cb); transform: translate( 0.055em, -0.01em); }

[data-glitch="off"] .rift-glitch::before,
[data-glitch="off"] .rift-glitch::after { opacity: 0; }

[data-glitch="subtle"] .rift-glitch::before { transform: translate(-0.025em, 0); opacity: 0.5; }
[data-glitch="subtle"] .rift-glitch::after  { transform: translate( 0.025em, 0); opacity: 0.5; }

/* ── TACTICAL FRAME ── corner brackets around any box. */
.rift-frame { position: relative; }
.rift-frame::before {
  content: "";
  position: absolute;
  inset: calc(-1 * var(--frame-overhang, 0px));
  pointer-events: none;
  background:
    linear-gradient(var(--frame-color), var(--frame-color)) top    left  / var(--frame-len, 18px) var(--frame-thickness, 1.5px) no-repeat,
    linear-gradient(var(--frame-color), var(--frame-color)) top    left  / var(--frame-thickness, 1.5px) var(--frame-len, 18px) no-repeat,
    linear-gradient(var(--frame-color), var(--frame-color)) top    right / var(--frame-len, 18px) var(--frame-thickness, 1.5px) no-repeat,
    linear-gradient(var(--frame-color), var(--frame-color)) top    right / var(--frame-thickness, 1.5px) var(--frame-len, 18px) no-repeat,
    linear-gradient(var(--frame-color), var(--frame-color)) bottom left  / var(--frame-len, 18px) var(--frame-thickness, 1.5px) no-repeat,
    linear-gradient(var(--frame-color), var(--frame-color)) bottom left  / var(--frame-thickness, 1.5px) var(--frame-len, 18px) no-repeat,
    linear-gradient(var(--frame-color), var(--frame-color)) bottom right / var(--frame-len, 18px) var(--frame-thickness, 1.5px) no-repeat,
    linear-gradient(var(--frame-color), var(--frame-color)) bottom right / var(--frame-thickness, 1.5px) var(--frame-len, 18px) no-repeat;
}

/* ── KANJI WATERMARK ── big faded brand mark behind content. */
.rift-mark { position: relative; isolation: isolate; }
.rift-mark::before {
  content: attr(data-mark);
  position: absolute;
  font-family: var(--font-jp);
  font-weight: 700;
  font-size: clamp(140px, 18vw, 280px);
  line-height: 0.85;
  color: var(--ink-1);
  opacity: 0.045;
  letter-spacing: 0.06em;
  white-space: nowrap;
  pointer-events: none;
  z-index: -1;
  right: -0.05em;
  bottom: -0.18em;
}

/* ---------- self-hosted type (see fonts/, subset from npmmirror) ---------- */
@font-face {
  font-family: "Space Grotesk";
  src: url("fonts/SpaceGrotesk-400.woff2") format("woff2");
  font-weight: 400; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "Space Grotesk";
  src: url("fonts/SpaceGrotesk-500.woff2") format("woff2");
  font-weight: 500; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "Space Grotesk";
  src: url("fonts/SpaceGrotesk-700.woff2") format("woff2");
  font-weight: 700; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "Chakra Petch";
  src: url("fonts/ChakraPetch-700.woff2") format("woff2");
  font-weight: 700; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "DM Serif Display";
  src: url("fonts/DMSerifDisplay-400-italic.woff2") format("woff2");
  font-weight: 400; font-style: italic; font-display: swap;
}
@font-face {
  font-family: "Rajdhani";
  src: url("fonts/Rajdhani-500.woff2") format("woff2");
  font-weight: 500; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "Rajdhani";
  src: url("fonts/Rajdhani-600.woff2") format("woff2");
  font-weight: 600; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "Share Tech Mono";
  src: url("fonts/ShareTechMono-400.woff2") format("woff2");
  font-weight: 400; font-style: normal; font-display: swap;
}
/* Chinese occurs inside the real data (descriptions, commit messages), so the
   SC face is subset to exactly the glyphs projects.json contains. */
@font-face {
  font-family: "Noto Sans SC";
  src: url("fonts/NotoSansSC-400-sub.woff2") format("woff2");
  font-weight: 400; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "Noto Sans SC";
  src: url("fonts/NotoSansSC-500-sub.woff2") format("woff2");
  font-weight: 500; font-style: normal; font-display: swap;
}
/* two glyphs, for the 裂隙 watermark and nothing else */
@font-face {
  font-family: "Shippori Mincho";
  src: url("fonts/ShipporiMincho-700-mark.woff2") format("woff2");
  font-weight: 700; font-style: normal; font-display: swap;
}

:root {
  --font-display: "Space Grotesk", "Noto Sans SC", system-ui, sans-serif;
  --font-wordmark: "Chakra Petch", "Space Grotesk", sans-serif;
  --font-italic: "DM Serif Display", "Space Grotesk", serif;
  --font-ui: "Rajdhani", "Noto Sans SC", system-ui, sans-serif;
  --font-mono: "Share Tech Mono", "Noto Sans SC", ui-monospace, Menlo, monospace;
  --font-jp: "Shippori Mincho", "Noto Sans SC", serif;
}

/* ---------- the stage ---------- */
html { background: #070C1B; }

.yo-stage {
  /* seam state, written by world.js:
     --seam    0..1 fraction of the stage width
     --seam-px the same in pixels
     --idea-op / --prod-op  how much of each aspect survives at this seam */
  --seam: 0.52;
  --seam-px: 52vw;
  --clip-px: 52vw;
  --idea-op: 1;
  --prod-op: 1;
  --pad-l: 48px;
  --pad-r: 40px;
  --head-w: 292px;

  position: fixed;
  inset: 0;
  overflow: hidden;
  background:
    linear-gradient(var(--grid) 1px, transparent 1px) 0 0 / 72px 72px,
    linear-gradient(90deg, var(--grid) 1px, transparent 1px) 0 0 / 72px 72px,
    var(--canvas);
  color: var(--ink-1);
  font-family: var(--font-ui);
  font-weight: var(--weight-medium);
  font-size: var(--text-base);
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
}
.yo-stage ::selection { background: rgba(92, 123, 255, 0.35); color: #EDF2FF; }

/* ---------- scroll: inside the stage, never the body ---------- */
.r-scroll {
  position: absolute;
  inset: 0;
  overflow-y: auto;
  overflow-x: hidden;
  scrollbar-width: none;
}
.r-scroll::-webkit-scrollbar { width: 0; height: 0; }
.r-doc { position: relative; min-height: 100%; }

/* ---------- the two lightings ---------- */
.r-layer--night { position: relative; z-index: 1; }
.r-layer--day {
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
  clip-path: inset(0 0 0 var(--clip-px, var(--seam-px)));
  background:
    linear-gradient(var(--grid) 1px, transparent 1px) 0 0 / 72px 72px,
    linear-gradient(90deg, var(--grid) 1px, transparent 1px) 0 0 / 72px 72px,
    var(--canvas);
  color: var(--ink-1);
}
/* The night copy carries the royal ghost, the day copy the sky ghost, so the
   seam is where the duotone actually separates. */
.r-layer--night { --glitch-ca: var(--royal); --glitch-cb: var(--royal); }
.r-layer--day   { --glitch-ca: var(--sky);   --glitch-cb: var(--cobalt); }

/* ---------- hero ---------- */
.r-hero {
  position: relative;
  padding: clamp(56px, 9vh, 96px) var(--pad-r) clamp(40px, 6vh, 72px) var(--pad-l);
}
/* The one 裂隙 watermark this screen is allowed. The DS anchors it in a
   corner; here it goes into the open ground on the daybreak side, which is
   the only large empty area the hero has — and the seam cuts through it like
   everything else. */
.r-hero.rift-mark::before {
  right: 5vw;
  top: 42%;
  bottom: auto;
  font-size: clamp(120px, 15vw, 236px);
  opacity: 0.06;
}

.r-eyebrow {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: 0.26em;
  text-transform: uppercase;
  color: var(--ink-3);
  margin-bottom: var(--sp-5);
}

/* The one tactical frame this screen is allowed: L-brackets around the claim
   itself. It is duplicated into both lightings, so the seam splits the
   brackets into ice on the left and cobalt on the right. */
.r-word.rift-frame {
  --frame-len: 30px;
  --frame-thickness: 1.5px;
  --frame-overhang: 22px;
}
.r-word {
  font-family: var(--font-wordmark);
  font-weight: 700;
  font-size: clamp(52px, 13.5vw, 208px);
  line-height: 0.92;
  letter-spacing: -0.02em;
  margin: 0;
  color: var(--ink-1);
}
.r-word .rift-glitch { display: inline-block; }

/* The hero splits on the same seam the rows do: the claim on the night side,
   the evidence on the day side. Drag toward daybreak and the poem goes with
   the rest of the ideas. */
.r-hero-foot {
  display: grid;
  grid-template-columns:
    max(0px, calc(var(--seam-px) - var(--pad-l)))
    minmax(0, 1fr);
  align-items: end;
  margin-top: var(--sp-10);
  column-gap: 0;
}

.r-poem {
  font-family: var(--font-italic);
  font-style: italic;
  font-size: clamp(18px, 2.1vw, 30px);
  line-height: 1.35;
  color: var(--ink-2);
  max-width: 26ch;
  padding-right: var(--sp-8);
  opacity: var(--idea-op);
  transition: opacity var(--dur-base) var(--ease-out);
}

/* the live line — the most recent real commit, resolved at load */
.r-live {
  font-family: var(--font-mono);
  font-size: var(--text-sm);
  color: var(--ink-3);
  padding-left: var(--sp-4);
  min-width: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 0 var(--sp-2);
  align-items: baseline;
  opacity: var(--prod-op);
  transition: opacity var(--dur-base) var(--ease-out);
}
.r-live-label { color: var(--ink-4); }
.r-live-msg { color: var(--ice); }
.r-live-age { color: var(--ink-3); }

/* ---------- ps: the projects, as processes ---------- */
.r-ps {
  position: relative;
  padding: 0 var(--pad-r) clamp(80px, 16vh, 180px) 0;
}

.r-rows {
  list-style: none;
  margin: 0;
  padding: 0;
}

.r-ps-head,
.r-row {
  display: grid;
  grid-template-columns:
    var(--head-w)
    max(0px, calc(var(--seam-px) - var(--pad-l) - var(--head-w)))
    minmax(0, 1fr);
  align-items: baseline;
  padding-left: var(--pad-l);
}

.r-ps-head {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--ink-4);
  padding-bottom: var(--sp-3);
  border-bottom: 1px solid var(--line-1);
  margin-bottom: var(--sp-2);
}
.r-ps-head .r-h-idea { text-align: right; padding-right: var(--sp-4); opacity: var(--idea-op); }
.r-ps-head .r-h-prod { padding-left: var(--sp-4); opacity: var(--prod-op); }

.r-row {
  position: relative;
  padding-top: var(--sp-4);
  padding-bottom: var(--sp-4);
  border-bottom: 1px solid var(--line-1);
  /* --drift is the crossing: each row slides right as it rises up the
     viewport, so it travels across the pinned seam on its way past. */
  transform: translateX(var(--drift, 0px));
  transition: background-color var(--dur-base) var(--ease-out);
}
.r-row.is-hot { background: rgba(92, 123, 255, 0.055); }

/* head — always present. A process keeps its name in any light. */
.r-head {
  display: flex;
  align-items: baseline;
  gap: var(--sp-3);
  min-width: 0;
  padding-right: var(--sp-4);
}
.r-state {
  font-family: var(--font-mono);
  font-size: var(--text-sm);
  width: 1.1em;
  flex: none;
  color: var(--ink-3);
}
.r-state[data-state="R"] { color: var(--ok); text-shadow: var(--glow-ok); }
.r-state[data-state="S"] { color: var(--steel); }
.r-state[data-state="T"] { color: var(--ink-4); }
.r-state[data-state="4"] { color: var(--ink-4); }
.r-name {
  font-family: var(--font-display);
  font-weight: 500;
  font-size: var(--text-base);
  color: var(--ink-1);
  text-decoration: none;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  border-bottom: 1px solid transparent;
}
.r-name:hover,
.r-name:focus-visible { border-bottom-color: var(--ice); outline: none; }
.r-name:focus-visible { color: var(--ice); }

/* idea — the left aspect, right-aligned so it leans on the seam */
.r-idea {
  text-align: right;
  padding-right: var(--sp-4);
  min-width: 0;
  overflow: hidden;
  opacity: var(--idea-op);
  transition: opacity var(--dur-base) var(--ease-out);
}
.r-idea-msg {
  display: block;
  font-family: var(--font-mono);
  font-size: var(--text-sm);
  color: var(--ink-2);
  white-space: nowrap;
  overflow: hidden;
  /* An overflowing first commit is cut where it meets the seam: the idea runs
     out exactly where reality starts. */
  text-overflow: ellipsis;
  text-align: right;
}
.r-idea-date {
  display: block;
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--ink-4);
  margin-top: 2px;
  letter-spacing: 0.08em;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.r-idea--none .r-idea-msg { color: var(--ink-4); font-style: normal; }

/* product — the right aspect */
.r-prod {
  padding-left: var(--sp-4);
  min-width: 0;
  overflow: hidden;
  opacity: var(--prod-op);
  transition: opacity var(--dur-base) var(--ease-out);
}
.r-prod-msg {
  display: block;
  font-family: var(--font-mono);
  font-size: var(--text-sm);
  color: var(--ink-2);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.r-prod-meta {
  display: block;
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--ink-4);
  margin-top: 2px;
  letter-spacing: 0.06em;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.r-prod-meta b { font-weight: 400; color: var(--steel); }
.r-prod-live {
  color: var(--ice);
  text-decoration: none;
  border-bottom: 1px solid rgba(143, 210, 245, 0.35);
}
.r-prod-live:hover { border-bottom-color: var(--ice); }
.r-prod--none .r-prod-msg { color: var(--ink-4); }

/* forks read differently on purpose: their default branch is upstream's work,
   so the row shows her pull requests instead of commits she did not write. */
.r-row[data-kind="fork"] .r-name { color: var(--ink-2); }
.r-upstream {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--ink-4);
}

/* ---------- the seam ---------- */
.r-seam {
  position: absolute;
  top: 0;
  bottom: 0;
  left: var(--seam-px);
  width: 0;
  z-index: 6;
}
.r-seam-line {
  position: absolute;
  top: 0;
  bottom: 0;
  left: -1px;
  width: 2px;
  background: linear-gradient(
    to bottom,
    rgba(143, 210, 245, 0) 0%,
    rgba(143, 210, 245, 0.75) 12%,
    rgba(92, 123, 255, 0.95) 50%,
    rgba(143, 210, 245, 0.75) 88%,
    rgba(143, 210, 245, 0) 100%);
  box-shadow: 0 0 14px rgba(92, 123, 255, 0.55), 0 0 34px rgba(107, 182, 240, 0.22);
}
/* The DS's one sanctioned infinite loop. In this world the chromatic edge IS
   the seam, so the seam is what tears. */
.r-seam-line::after {
  content: "";
  position: absolute;
  inset: 0;
  background: inherit;
  animation: r-seam-tear 6.5s infinite;
}
@keyframes r-seam-tear {
  0%, 46%, 100% { transform: translateX(0); clip-path: inset(0); opacity: 0; }
  47%           { transform: translateX(-3px); clip-path: inset(18% 0 62% 0); opacity: 0.9; }
  49%           { transform: translateX(2px);  clip-path: inset(58% 0 24% 0); opacity: 0.9; }
  51%           { transform: translateX(0);    clip-path: inset(0); opacity: 0; }
  88%           { transform: translateX(0);    opacity: 0; }
  89%           { transform: translateX(2px);  clip-path: inset(70% 0 12% 0); opacity: 0.8; }
  91%           { transform: translateX(0);    clip-path: inset(0); opacity: 0; }
}

.r-seam-grip {
  position: absolute;
  top: 0;
  bottom: 0;
  left: -16px;
  width: 32px;
  cursor: ew-resize;
  touch-action: none;
  -webkit-tap-highlight-color: transparent;
}
.r-seam-grip::before {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: 6px;
  height: 46px;
  margin: -23px 0 0 -3px;
  border-radius: var(--r-pill);
  background: var(--glass-2-bg);
  border: 1px solid var(--glass-border);
  box-shadow: inset 0 1px 0 var(--glass-inner-hi), var(--glow-royal);
  transition: height var(--dur-base) var(--ease-rise), background var(--dur-base);
}
.r-seam-grip:hover::before,
.r-seam-grip:focus-visible::before { height: 74px; margin-top: -37px; }
.r-seam-grip:focus-visible { outline: none; }
.r-seam-grip:focus-visible::before { border-color: var(--royal); }
.yo-stage[data-dragging] .r-seam-grip::before { height: 96px; margin-top: -48px; }
.yo-stage[data-dragging] { cursor: ew-resize; }

/* the seam's own reading of itself — sits just off the line, near the bottom */
.r-seam-read {
  position: absolute;
  left: 12px;
  right: auto;
  bottom: 22px;
  padding: 5px 10px;
  border-radius: var(--r-sm);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: 0.12em;
  white-space: nowrap;
  color: var(--ice);
  pointer-events: none;
  /* This sits above both lightings — drag the seam far enough and daybreak
     runs underneath it — so it cannot borrow either theme's glass. One
     material that reads on both grounds: a dark chip with an ice rim. */
  background: rgba(7, 12, 27, 0.62);
  border: 1px solid rgba(143, 210, 245, 0.28);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.10);
  -webkit-backdrop-filter: blur(14px) saturate(170%);
  backdrop-filter: blur(14px) saturate(170%);
}

/* ---------- the one scan layer ---------- */
.r-scan {
  position: absolute;
  inset: 0;
  z-index: 8;
  pointer-events: none;
  background: repeating-linear-gradient(
    to bottom,
    transparent 0,
    transparent 2px,
    var(--scan-line) 2px,
    var(--scan-line) 3px);
}

/* ---------- the closed surface, and the tear ---------- */
.r-plate {
  position: absolute;
  inset: 0;
  z-index: 30;
}
.r-plate-half {
  position: absolute;
  inset: 0;
  background:
    linear-gradient(var(--grid) 1px, transparent 1px) 0 0 / 72px 72px,
    linear-gradient(90deg, var(--grid) 1px, transparent 1px) 0 0 / 72px 72px,
    var(--canvas);
  will-change: transform;
  transition: transform var(--dur-slow) var(--ease-out);
}
.r-plate-half--l { clip-path: inset(0 calc(100% - var(--seam-px)) 0 0); }
.r-plate-half--r { clip-path: inset(0 0 0 var(--seam-px)); }
.r-plate-hair {
  position: absolute;
  top: 0;
  bottom: 0;
  left: var(--seam-px);
  width: 1px;
  margin-left: -0.5px;
  background: linear-gradient(
    to bottom,
    rgba(143, 210, 245, 0) 0%,
    rgba(143, 210, 245, 0.30) 50%,
    rgba(143, 210, 245, 0) 100%);
  transition: opacity var(--dur-base) var(--ease-out),
              box-shadow var(--dur-base) var(--ease-out);
}
/* the moment before it opens */
.yo-stage[data-tearing] .r-plate-hair {
  box-shadow: 0 0 18px rgba(143, 210, 245, 0.75), 0 0 48px rgba(92, 123, 255, 0.45);
}
html[data-open] .r-plate-half--l { transform: translateX(-101%); }
html[data-open] .r-plate-half--r { transform: translateX(101%); }
html[data-open] .r-plate-hair { opacity: 0; }
html[data-open] .r-plate { pointer-events: none; }

/* ---------- return key: this world's material is glass with an ice rim ---------- */
.yo-return {
  color: var(--ice);
  width: 44px;
  height: 44px;
  display: grid;
  place-items: center;
  border-radius: var(--r-md);
  /* same reasoning as .r-seam-read: it floats over whichever lighting the
     seam happens to have put under it */
  background: rgba(7, 12, 27, 0.62);
  border: 1px solid rgba(143, 210, 245, 0.28);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.10), var(--shadow-md);
  -webkit-backdrop-filter: blur(14px) saturate(170%);
  backdrop-filter: blur(14px) saturate(170%);
  z-index: 40;
  transition: border-color var(--dur-base), box-shadow var(--dur-base), color var(--dur-base);
}
.yo-return:hover {
  color: #EDF2FF;
  border-color: rgba(143, 210, 245, 0.55);
  box-shadow: inset 0 1px 0 var(--glass-inner-hi), var(--shadow-lg), var(--glow-ice);
}
.yo-return:focus-visible {
  outline: 2px solid var(--royal);
  outline-offset: 2px;
}

/* ---------- 390: the seam stays, the columns don't ----------
   A phone is too narrow to hold an idea and its product side by side, so the
   row stacks and the seam stops being a column boundary — it stays a
   lighting boundary. Dragging it there tips the whole page between midnight
   and daybreak instead of showing you the gap between them. */
@media (max-width: 720px) {
  .yo-stage {
    --pad-l: 20px;
    --pad-r: 20px;
    --head-w: 100%;
  }
  .r-ps { padding-right: var(--pad-r); }
  .r-ps-head { display: none; }
  .r-row {
    grid-template-columns: minmax(0, 1fr);
    row-gap: var(--sp-2);
    padding-right: var(--pad-r);
  }
  .r-head { padding-right: 0; }
  .r-idea { text-align: left; padding-right: 0; }
  .r-idea-msg { text-align: left; }
  .r-prod { padding-left: 0; }
  .r-word { font-size: clamp(44px, 15vw, 92px); }
  /* the brackets have to come inside the gutter or they widen the document */
  .r-word.rift-frame { --frame-overhang: 12px; --frame-len: 20px; }
  .r-poem { font-size: var(--text-lg); max-width: none; }
  /* the watermark drops below the wordmark instead of sitting behind it —
     there is no open ground to put it in at this width */
  .r-hero.rift-mark::before {
    right: auto;
    left: 50%;
    top: auto;
    bottom: -6%;
    transform: translateX(-50%);
    font-size: 108px;
    opacity: 0.05;
  }
}

/* ---------- reduced motion: the still version ----------
   The world opens already torn, the seam does not tear on its own, and rows
   do not drift as they pass it. Everything the seam does on drag still works
   — that is information, not decoration. */
@media (prefers-reduced-motion: reduce) {
  .r-plate-half { transition: none; }
  .r-seam-line::after { animation: none; opacity: 0; }
  .r-row { transform: none; }
  .r-idea, .r-prod, .r-row, .r-seam-grip::before, .yo-return { transition: none; }
}

/* ---------- entering this world: the monitor snapshot tears open ----------
   The shell's default is a cross-fade of the two monitor snapshots. Here the
   old snapshot holds its ground and the new one arrives from behind the seam
   instead, so the morph and the tear read as one motion. */
html:active-view-transition-type(to-rift)::view-transition-old(monitor) {
  animation: r-vt-old var(--dur-slow) var(--ease-out) both;
}
html:active-view-transition-type(to-rift)::view-transition-new(monitor) {
  animation: r-vt-new var(--dur-slow) var(--ease-out) both;
}
@keyframes r-vt-old {
  0%   { opacity: 1; }
  62%  { opacity: 1; }
  100% { opacity: 0; }
}
@keyframes r-vt-new {
  0%   { opacity: 0; }
  46%  { opacity: 0; }
  100% { opacity: 1; }
}

/* Past three quarters of the way across there is no room to the right of the
   seam, so the readout hangs on its other side. */
.r-seam[data-read="left"] .r-seam-read { left: auto; right: 12px; }
