/* =========================================================
   GEXI — public/shell/gx-frontdoor.css   (FP-1 THE LANDING, the VISUAL half; lane H, 2026-10-17)
   THE OWNER-APPROVED FRONT PAGE (FRONT-PAGE-BUILD-SPEC FP-1, mock v15). S owns the markup, the data hooks, the door logic
   and the chat bar (FP-7 = composer.js + its CSS); THIS FILE owns how the landing looks (single lane per file, S-ACKed).
   Inert without S's .gx-fd markup. Every colour is an ALIAS of a core.css token (theme-aware: core.css switches the tokens
   on :root[data-theme] + prefers-color-scheme) — the one neutral exception is the cover-title GLASS, which must stay dark
   in BOTH themes so white text holds >= 4.5:1 on the LIGHTEST cover (see .gx-fd-cover-glass).
   THE LAWS (FP-1): ONE green per screen = the "Hi," only · motion settles (2 cycles, matching start/end, then rest) ·
   reduced motion = static · every tap target >= 44 px · NOTHING truncated (no ellipsis, at 360 px and 200% text) ·
   light AND dark both designed.
   ========================================================= */

.gx-fd {
  --gx-fd-ink: var(--ink);
  --gx-fd-ink-2: var(--ink-2);
  --gx-fd-muted: var(--muted);
  --gx-fd-line: var(--line);
  --gx-fd-card: var(--card-alt);
  --gx-fd-green: var(--brand-500);          /* THE ONE GREEN (the "Hi," only) */
  --gx-fd-hello-2nd: #2a78b0;               /* mock v15's hello partner (a BLUE, not a second green), light theme */
  --gx-fd-pad: 20px;                        /* mock v15's phone gutter (desktop: 24px below) */
  /* S's live fold (2026-10-17): inside the dock's centring column the landing must FILL the column, never shrink to its
     content (a 1237px cover row in a 375px phone). And it is a CONTAINER: the covers + the desktop grid key on the
     landing's OWN width (a pane beside the rail), never the viewport's. */
  width: 100%; min-width: 0; align-self: stretch; container-type: inline-size;
  display: flex; flex-direction: column; min-height: 100%;
  color: var(--gx-fd-ink);
  padding: 0 var(--gx-fd-pad) calc(var(--gx-fd-pad) + env(safe-area-inset-bottom, 0px));
  box-sizing: border-box;
}
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .gx-fd { --gx-fd-hello-2nd: #7cc7e3; } }
:root[data-theme="dark"] .gx-fd { --gx-fd-hello-2nd: #7cc7e3; }
.gx-fd *, .gx-fd *::before, .gx-fd *::after { box-sizing: border-box; }
/* NOTHING TRUNCATED, anywhere on the landing (E8): words wrap BETWEEN words, no ellipsis, no single-line clamps. A word is
   split only as the last resort when it alone is wider than its line (break-word); never "anywhere" (S's live fold: a
   118px cover broke "Start a webnovel" into "t a web nov el"). */
.gx-fd, .gx-fd * { text-overflow: clip; overflow-wrap: break-word; word-break: normal; hyphens: manual; }

/* ---- the top bar: menu · GEXI wordmark truly centred · sign in / avatar ---- */
.gx-fd-top {
  display: grid; grid-template-columns: 44px 1fr 44px; align-items: center;
  min-height: 56px; padding-top: env(safe-area-inset-top, 0px);
}
.gx-fd-top > :nth-child(2) { justify-self: center; text-align: center; }
.gx-fd-top button, .gx-fd-top a { min-width: 44px; min-height: 44px; display: inline-flex; align-items: center; justify-content: center; color: var(--gx-fd-ink); }

/* ---- the hello: line 1 "Hi," (or "Welcome back,") = THE ONE GREEN; line 2 neutral ---- */
.gx-fd-hello { margin: 22px 0 20px; line-height: 1.2; font-weight: 500; font-size: clamp(19px, 6.4cqi, 28px); letter-spacing: -0.01em; text-wrap: balance; }
.gx-fd-hello-1 {
  display: block; font-weight: 700; font-size: 1.42em; line-height: 1.08; margin-bottom: 2px;
  color: var(--gx-fd-green);
  /* mock v15: green → blue → green, so its START and END frames are the SAME colour (no jump at rest) */
  background-image: linear-gradient(90deg, var(--gx-fd-green) 0%, var(--gx-fd-hello-2nd) 50%, var(--gx-fd-green) 100%);
  background-size: 200% 100%; background-position: 0% 50%;
  -webkit-background-clip: text; background-clip: text; -webkit-text-fill-color: transparent;
  animation: gx-fd-hello 5s linear 0.3s 2 both;                    /* TWO cycles (mock: 5 s linear), then rest */
}
.gx-fd-hello-2 { display: block; color: var(--gx-fd-ink); }
@keyframes gx-fd-hello { 0% { background-position: 0% 50%; } 50% { background-position: 100% 50%; } 100% { background-position: 0% 50%; } }
@media (min-width: 960px) { .gx-fd-hello { text-align: center; font-size: 30px; } }

/* ---- the covers: a sideways row with snap (phone) / a grid (desktop); EQUAL weight — every cover the same size ---- */
.gx-fd-covers {
  /* FP-PHONE-412 (the owner's S25 Ultra, Chrome, 412px): TWO WHOLE, LABELLED covers side by side and the third peeking by
     the gutter, so no cover or title is ever cut at the screen edge (the height-led size made 216-261px covers there, the
     second one cut mid-title: "Bring my"). 100cqi = the landing's own width; 24px = the two 12px gaps around the second
     cover's right edge, so card 3 shows exactly --gx-fd-pad. Never TALLER than 44% of a short screen (S's 1280x860 check). */
  --gx-fd-cover-w: min(calc((100cqi - 24px) / 2), calc(44svh * 0.75));
  /* the row BLEEDS to both edges (the -pad margins below), so it may be 2 x pad wider than the landing; a plain 100% cap
     stopped it 32px short of the right edge (S's 393 check: the peek card cut at 333 of 365) */
  max-width: calc(100% + 2 * var(--gx-fd-pad)); min-width: 0;
  flex-shrink: 0;   /* never squeezed by the landing's flex column (S's 1280x860 check: the row shrank to 331 of 396px tall) */
  display: grid; grid-auto-flow: column; grid-auto-columns: var(--gx-fd-cover-w); gap: 12px;
  overflow-x: auto; overscroll-behavior-x: contain; scroll-snap-type: x mandatory; scroll-padding-inline: var(--gx-fd-pad);
  margin: 0 calc(-1 * var(--gx-fd-pad)); padding: 2px var(--gx-fd-pad) 10px;
  scrollbar-width: none; -webkit-overflow-scrolling: touch;
}
.gx-fd-covers::-webkit-scrollbar { display: none; }
.gx-fd-cover {
  position: relative; display: block; scroll-snap-align: start;
  aspect-ratio: 3 / 4; width: var(--gx-fd-cover-w); min-height: 44px;
  border-radius: 26px; overflow: hidden; background: var(--gx-fd-card);
  border: 0; padding: 0; cursor: pointer; text-align: center; color: inherit;
  font: inherit;   /* FD-COVER-FONT: a <button> takes the browser's button face unless told (WebKit drew the labels in serif) */
  box-shadow: 0 10px 26px -16px rgba(0, 0, 0, 0.55);
  -webkit-tap-highlight-color: transparent;
}
.gx-fd-cover:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; }
.gx-fd-cover-art { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; display: block; }
/* mock v15's bottom scrim: the picture darkens toward the title (it ADDS contrast; the glass alone already holds 4.5:1) */
.gx-fd-cover::before { content: ''; position: absolute; left: 0; right: 0; bottom: 0; height: 45%; z-index: 1; pointer-events: none;
  background: linear-gradient(to top, rgba(0, 0, 0, 0.5), transparent); }
/* THE TITLE GLASS — clear NEUTRAL glass inside the picture. Tuned on the LIGHTEST cover: white text over 62% near-black
   on a pure-white image composites to ~#676767 behind the text → ~5.8:1 (>= 4.5:1, E-contrast) in BOTH themes. A theme
   token would flip it light in light mode and fail on a bright cover, so this is the one neutral literal (not a brand
   colour: no green, no off-brand hue). */
.gx-fd-cover-glass {
  position: absolute; left: 8px; right: 8px; bottom: 8px; z-index: 2;
  padding: 10px 8px; border-radius: 18px; text-align: center;
  background: rgba(10, 10, 15, 0.62); color: #fff;                 /* mock 0.42 relied on the scrim; 0.62 holds 4.5:1 alone */
  border: 1px solid rgba(255, 255, 255, 0.28); box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.22);
  /* FP-P8-BLUR (D-2's speed budgets, A9: <= 3 blurred surfaces per screen, NONE on low-end): five covers = five blurs, so the
     label is a FLAT tint — the rgba(.62) above already holds 4.5:1 alone; nothing about colour or contrast changes */
  font-weight: 600; font-size: clamp(12.5px, 3.9cqi, 14.5px); line-height: 1.2;
  overflow: hidden;
}
/* the label sheen: TWO passes, then rest (the sweep ends off-glass, so the resting frame equals the first) */
.gx-fd-cover-glass::after {
  content: ''; position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(100deg, transparent 30%, rgba(255, 255, 255, 0.16) 50%, transparent 70%);
  transform: translateX(-120%);
  animation: gx-fd-sheen 1.8s ease-in-out 1s 2 both;
}
.gx-fd-cover:nth-child(2) .gx-fd-cover-glass::after { animation-delay: 1.5s; }
.gx-fd-cover:nth-child(3) .gx-fd-cover-glass::after { animation-delay: 2s; }
.gx-fd-cover:nth-child(4) .gx-fd-cover-glass::after { animation-delay: 2.5s; }
.gx-fd-cover:nth-child(5) .gx-fd-cover-glass::after { animation-delay: 3s; }
@keyframes gx-fd-sheen { from { transform: translateX(-120%); } to { transform: translateX(120%); } }

/* ---- open space, then the quiet suggestion line ("Spark a story", "Surprise me"): text + a line icon, NO boxes ---- */
.gx-fd-suggest {
  margin-top: auto; padding-top: 20px; margin-inline: -6px;
  display: flex; flex-wrap: wrap; gap: 2px; align-items: center;   /* WRAPS — never truncates */
}
.gx-fd-suggest-item {
  display: inline-flex; align-items: center; gap: 8px; min-height: 44px; padding: 0 12px; border-radius: 999px;
  background: none; border: 0; color: var(--gx-fd-muted); font: inherit; font-weight: 500; font-size: 0.95rem; cursor: pointer;
}
.gx-fd-suggest-item:hover, .gx-fd-suggest-item:focus-visible { background: var(--gx-fd-card); color: var(--gx-fd-ink); }
.gx-fd-suggest-item svg { width: 18px; height: 18px; flex: none; stroke: currentColor; fill: none; }

/* ---- the door question (a SHELL surface, never a fake brain message) + its chips ---- */
/* the door renders inside the dock's empty column too (outside .gx-fd), so it carries its OWN front-door tokens — the same
   core tokens as .gx-fd — or the question inherits the dock's muted grey (prod e90ce829: rgb(107,107,130) on the dark page) */
.gx-fd-door { margin: 14px 0 6px; --gx-fd-ink: var(--ink); --gx-fd-ink-2: var(--ink-2); --gx-fd-muted: var(--muted); --gx-fd-line: var(--line); --gx-fd-card: var(--card-alt); }
.gx-fd-door-q { margin: 0 0 10px; font-size: 17px; line-height: 1.5; color: var(--gx-fd-ink); }
.gx-fd-chips { display: flex; flex-wrap: wrap; gap: 8px; }
.gx-fd-chip {
  min-height: 44px; padding: 10px 14px; border-radius: 999px;
  border: 1px solid var(--line-strong, var(--gx-fd-line)); background: transparent; color: var(--gx-fd-ink);
  font: inherit; font-size: 14px; line-height: 1.3; text-align: left; cursor: pointer; white-space: normal;
}
.gx-fd-chip:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; }

/* ---- the promise line (signed-out only; S renders it only then) ---- */
.gx-fd-promise { margin: 6px 0 0; text-align: center; font-size: 0.8rem; line-height: 1.45; color: var(--gx-fd-muted); }

/* ---- returning visitors: the same page; the hello's first line is "Welcome back," (S's copy), still the one green ---- */
.gx-fd[data-fd-state="returning"] .gx-fd-hello-1 { font-size: 1.3em; }   /* "Welcome back," is longer than "Hi," */

/* ---- desktop: a centred column; one menu only (the rail's) ---- */
@media (min-width: 960px) {
  .gx-fd { max-width: 960px; margin: 0 auto; --gx-fd-pad: 24px; }
  .gx-fd-top > :first-child { visibility: hidden; }          /* the rail carries the menu on desktop */
}
/* ---- FP-PHONE-412: on a PHONE the landing's row reaches BOTH SCREEN EDGES (mock v15's shelf). The landing sits inside the
   dock's thread (12px) and empty column (16px, overflow hidden), so the row's bleed stopped 28px inside the screen and cut
   the second cover there. While the landing is on screen (the frame scope below), those two side paddings go to 0 and the
   landing's own 20px gutter is the page edge; the composer is outside the thread and keeps its own. ---- */
@media (max-width: 639px) {
  body:has(.gx-dock-empty .gx-fd) #gx-shell .gx-dock-thread,
  body:has(.gx-dock-empty .gx-fd) #gx-shell .gx-dock-empty.cv-empty { padding-left: 0; padding-right: 0; }
}
/* THE MESSAGE BAR SITS AT THE BOTTOM (the owner: "the bottom search/talk bar is sitting high") — fixed at its source on EVERY
   screen, not here: gx-sandbox.css reserves the 76px lip space only while a panel is MOUNTED, and views/app-shell.html's
   viewport says interactive-widget=resizes-content, so on Android the 100dvh shell shrinks above an open keyboard. */

/* ---- the GRID (all covers reachable), keyed on the LANDING's own width (a container query, never the viewport): from
   640px, FIVE equal columns in ONE row (~130x173 in the shell's ~736px chat column). S's re-checks: a 4-column grid made
   4+1 covers in two rows, pushing the hints + the promise UNDER the composer (unreachable) and orphaning the fifth cover;
   one row keeps "five equal covers", no orphan, and everything above the composer. Titles wrap BETWEEN words. Narrower
   (phones) keep the sideways snap row. ---- */
@container (min-width: 640px) {
  .gx-fd-covers {
    grid-auto-flow: row; grid-template-columns: repeat(5, minmax(0, 1fr)); grid-auto-columns: auto;
    overflow: visible; scroll-snap-type: none; margin: 0; padding: 2px 0 10px; max-width: 100%;
  }
  .gx-fd-cover { width: 100%; }
}

/* ---- FP-5 THE LIVING FIRST CARD: the webnovel cover's sample frames + its line written over the picture (frontDoor.js
   FP5_LIVING_ON; two muted plays, then a rest on the last frame with the full line). Under the title glass, never over it. ---- */
.gx-fd-live { position: absolute; inset: 0; z-index: 1; pointer-events: none; }
.gx-fd-live-frame { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.gx-fd-live-line {
  position: absolute; left: 12px; right: 12px; top: 42%;
  color: #fff; font-weight: 500; font-size: clamp(12px, 3.6cqi, 14px); line-height: 1.3; text-align: left;
  text-shadow: 0 1px 8px rgba(0, 0, 0, 0.7); min-height: 2.6em;
}
/* FP-5 HOLD TO HEAR: while a cover's line plays, a visible ring (no motion needed to see it) */
.gx-fd-cover.is-hearing { box-shadow: 0 0 0 3px var(--gx-fd-ink), 0 10px 26px -16px rgba(0, 0, 0, 0.55); }
.gx-fd-cover { -webkit-touch-callout: none; -webkit-user-select: none; user-select: none; }   /* a long press never selects text or opens the phone's menu */

/* ---- THE HELLO aligns like mock v15: left on phones, centred from 640px of the landing (the desktop shelf) ---- */
.gx-fd-hello { text-align: left; }
@container (min-width: 640px) { .gx-fd-hello { text-align: center; } }

/* ---- THE LANDING'S FRAME (mock v15), scoped to the landing ONLY: the shell's header + rail look as the mock shows them
   while the front door is on screen, and return to normal the moment a conversation starts (the selector stops matching).
   The coordinator's MORNING-FIRST-SCREEN read, 2026-10-17: ---- */
/* (1) a 3-control top bar: menu · GEXI · Sign in — Back has nowhere to go, "New" IS this screen, and the theme moves into
   the ☰ rail's Tools ("Theme", .gx-rail-theme, S's FP-1b markup — reachable everywhere, the capability kept) */
body:has(.gx-dock-empty .gx-fd) .gx-hd-back,
body:has(.gx-dock-empty .gx-fd) .gx-hd-new { display: none; }
/* the header's theme toggle hides ONLY when the rail's "Theme" item EXISTS on the page (the Keeper's capability-guard note):
   if S's rail item is ever absent, the header toggle stays — there is never a landing with no theme control */
body:has(.gx-dock-empty .gx-fd):has(.gx-rail-theme) .gx-hd-theme { display: none; }
/* (2) ONE green per screen = the "Hi," only: every other accent on the landing turns neutral */
body:has(.gx-dock-empty .gx-fd) .gx-hd-wallet-ic,
body:has(.gx-dock-empty .gx-fd) .gx-rail-place-ic,
body:has(.gx-dock-empty .gx-fd) .gx-rail-new-ic,
body:has(.gx-dock-empty .gx-fd) .gx-rail-label { color: var(--gx-fd-ink-2, var(--ink-2)); }
/* (4) no "GEXI can make mistakes" on the landing (the promise line speaks there); it returns with the first turn */
body:has(.gx-dock-empty .gx-fd) .cv-disclaimer { display: none; }

/* ---- REDUCED MOTION = STATIC: no gradient run, no sheen; the hello rests on its plain green ---- */
@media (prefers-reduced-motion: reduce) {
  .gx-fd-hello-1 { animation: none; background-image: none; -webkit-text-fill-color: currentColor; }
  .gx-fd-cover-glass::after { animation: none; display: none; }
  .gx-fd-covers { scroll-behavior: auto; }
}

/* A11Y-H2 (A-H-9; the coordinator's nod 2026-10-19) — light theme: the "Hi," green at AA-large. brand-500 #10b981 on #fafafd
   is 2.43:1; brand-700 #047857 is 5.26:1. The same one green, one shade deeper; dark (10.58:1) is untouched. */
:root:not([data-theme="dark"]) .gx-fd { --gx-fd-green: var(--brand-700); }
