/* tru3self — first run.
 *
 * Peter, 2026-08-18: "Top priority is rebuilding the UI, the front page. The
 * website needs to look good. And then once you start using True Self, the
 * first page needs to take you through all of the simplest data prompts."
 *
 * Loaded AFTER app.css and scoped to .fr-* so nothing in the existing app is
 * restyled by accident. The old markup is still in the page, untouched, because
 * app.js binds to it without null guards — this is a new surface in front of a
 * working engine, not a rewrite of one.
 *
 * The design argument, in one line: a person landing here should have exactly
 * one thing to look at and exactly one thing to do. Everything else — the
 * options, the reassurance, the roadmap of what unlocks later — is present but
 * subordinate, because a screen of equals is a screen nobody acts on.
 */

/* ── THE COLOUR SYSTEM ─────────────────────────────────────────────────────
 *
 * SOURCE OF TRUTH: Peter's FINAL Electric Blue brand pack, delivered 20 Aug.
 * The raw tokens live in web/pwa/brand/colors.css and are linked into every
 * page; nothing below invents a colour, it only gives the brand's colours the
 * names this stylesheet already uses. The pack's own README is explicit:
 * "Electric neon light blue. No teal." The aqua this file used until today
 * (#20DDEB, and #1CD3FF before it) is exactly the teal it forbids, so every
 * one of them moved onto Ice Blue and its family.
 *
 * Why map instead of sprinkling hexes: the semantic names are what the rules
 * below actually reference. Redefining a dozen variables moves the whole
 * surface at once, and the next brand change is a dozen lines again rather
 * than a search-and-replace across a stylesheet nobody can hold in their head.
 *
 * The two blues alternate on purpose — Ice Blue leads, Voltage Blue answers.
 * Voltage Blue is a FILL and a BORDER, never body text: it measures 3.2:1 on
 * Midnight, which is below the 4.5:1 a sentence needs. On a Voltage Blue fill,
 * Soft White measures 6.0:1 and reads fine. tools/audit-brand.js computes both
 * rather than trusting this comment.
 */
:root {
  --fr-bg: var(--tru-midnight, #020814);        /* the canvas the pack prescribes */
  --fr-bg-2: var(--tru-deep-ocean, #071B33);    /* cards, panels, elevated surfaces */
  --fr-ink: var(--tru-soft-white, #F8FCFD);     /* primary text */
  /* Two steps of quieter ink. Neither is a brand token — the pack names one
     text colour — so they are neutrals pulled toward the blue, chosen against
     the 4.5:1 floor on BOTH backgrounds: mute is 6.4:1 on Midnight and 5.5:1
     on Deep Ocean, dim is 5.7:1 and 5.0:1. The old dim (#5b6478) was 3.4:1
     and failed on both, which is why it moved rather than being kept. */
  --fr-mute: #8792a8;
  --fr-dim: #7b8aa3;
  /* Hairlines are Ring Cyan, held inside the pack's 25–45% band. */
  --fr-line: rgba(125, 236, 255, .30);
  --fr-line-strong: rgba(125, 236, 255, .45);
  --fr-cyan: var(--tru-electric-ice-blue, #5ED5FF);   /* PRIMARY accent */
  --fr-volt: var(--tru-voltage-blue, #0048FF);        /* SECONDARY, alternates with it */
  --fr-azure: var(--tru-electric-azure, #00A4FF);     /* micro-accent: status dots only */
  --fr-ring: var(--tru-ring-cyan, #7DECFF);           /* fine rules, subtle highlights */
  --fr-grad: var(--tru-electric-gradient, linear-gradient(90deg, #5ED5FF 0%, #0048FF 100%));
  /* The electric glow. Low alpha on purpose: a glow is decoration, and the
     legibility underneath it has to stand on its own. */
  --fr-glow: 0 0 0 1px rgba(94, 213, 255, .22), 0 12px 38px -16px rgba(94, 213, 255, .55);
  --fr-ember: #ff8a3d;
  --fr-green: #4ade9b;
  --fr-radius: 18px;
  --fr-max: 560px;
  --fr-ease: cubic-bezier(.22, .9, .3, 1);
}

/* Keyboard users get the same quality of attention the mouse gets. One ring,
   in Ice Blue, on everything focusable — not a browser default outline on half
   the controls and nothing on the other half. */
body.fr-on :focus-visible {
  outline: 2px solid var(--fr-cyan);
  outline-offset: 3px;
}

/* Nothing on this page moves for someone who has asked the OS for stillness.
   The emblem never animates for anyone: the pack forbids altering it. */
@media (prefers-reduced-motion: reduce) {
  body.fr-on *, body.fr-on *::before, body.fr-on *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
    scroll-behavior: auto !important;
  }
}

/* Mobile first, and mobile-real: the safe-area insets matter more than the
   breakpoints do, because the primary button lives near the home indicator. */
body.fr-on {
  margin: 0;
  background: var(--fr-bg);
  color: var(--fr-ink);
  font: 16px/1.5 -apple-system, BlinkMacSystemFont, "SF Pro Text", "Segoe UI", Inter, system-ui, sans-serif;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
}

/* The old page is still in the DOM for app.js. It is not for looking at. */
body.fr-on > .trustbar,
body.fr-on > header.top,
body.fr-on > footer.foot,
body.fr-on > main.wrap > section.hero { display: none !important; }
body.fr-on .fr-legacy { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

/* Two ambient light sources, behind everything, so the page has depth without
   a single image to download — and they are the two brand blues, not one blue
   and an orange. Ice Blue on the left, Voltage Blue answering on the right:
   the alternation the pack asks for, stated once at the largest scale on the
   page and then never shouted again. */
.fr-shell {
  position: relative;
  min-height: 100svh;
  padding:
    calc(env(safe-area-inset-top) + 18px)
    calc(env(safe-area-inset-right) + 20px)
    calc(env(safe-area-inset-bottom) + 28px)
    calc(env(safe-area-inset-left) + 20px);
  display: flex; flex-direction: column; align-items: center;
  isolation: isolate;
}
.fr-shell::before {
  content: ''; position: fixed; inset: -30% -30% auto -30%; height: 78vh; z-index: -1;
  background:
    radial-gradient(50% 55% at 30% 22%, rgba(94, 213, 255, .18), transparent 70%),
    radial-gradient(45% 50% at 78% 8%, rgba(0, 72, 255, .22), transparent 72%);
  filter: blur(6px);
  pointer-events: none;
}
.fr-shell::after {
  content: ''; position: fixed; inset: 0; z-index: -1; pointer-events: none;
  background: radial-gradient(120% 90% at 50% 0%, transparent 40%, var(--fr-bg) 92%);
}

.fr-wrap { width: 100%; max-width: var(--fr-max); margin: 0 auto; }

/* ── masthead ─────────────────────────────────────────────────────────────── */
/* The utility row — lock chip, account chip, language. It sits ABOVE the logo
   and it is a ROW, not a column: the column cost 89px of the first screen and
   the wordmark needs that height more than the chips need the air. */
.fr-top {
  display: flex; align-items: center; justify-content: flex-end;
  gap: 10px; margin-bottom: 16px;
}
/* ── THE LOGO ─────────────────────────────────────────────────────────────
   Peter's final brand set, 20 Aug: the wordmark is the masthead. It runs the
   full width of the column (capped at 340px, which is the whole content width
   of a 390px phone) with the official tagline under it at a quieter 260px.
   Both are transparent PNGs on the near-black canvas, so no plate is needed. */
.fr-brand {
  display: flex; flex-direction: column; align-items: center; gap: 7px;
  margin: 0 0 20px;
}
.fr-wordmark {
  display: block; width: 100%; max-width: 340px; height: auto;
}
/* Peter, 20 Aug: the tagline runs the SAME width as the wordmark — "as wide as
   from the T to the I", directly underneath it. */
.fr-tagimg {
  display: block; width: 100%; max-width: 340px; height: auto; opacity: .96;
}
/* THE GLOBE LEADS, AT THE LARGEST SIZE THAT KEEPS THE ASK ON SCREEN.
 *
 * Peter picked this off a four-way render on 20 Aug (options at 336 / 288 / 230
 * / 182px). 288px is the widest the mark can be while the whole first tile
 * still finishes above the 844px fold of a 390px iPhone — measured, not
 * guessed: at 336px the tile bottomed out at 875px, at 288px it lands at 827px.
 * A bigger logo that pushes the one thing we are asking for off the screen is a
 * worse logo. Wider phones and desktops have room to spare either way. */
.fr-globe {
  /* Peter, 20 Aug (second pass): back to the LARGEST of the four rendered
   * options — "have it be the old option that was biggest." 380px cap renders
   * 336px wide on a 390px phone; the first tile lands just under the fold,
   * which he accepted as the trade for the presence. */
  display: block; width: 96%; max-width: 380px; height: auto; margin: 0 auto 6px;
}
/* The three words a stranger opened the sheet to check. */
.sheet-keep {
  font-size: 30px; font-weight: 800; letter-spacing: .04em; line-height: 1.1;
  color: var(--fr-ink); margin: 0 0 10px;
}
.fr-lock {
  display: inline-flex; align-items: center; gap: 7px;
  background: rgba(255, 255, 255, .05); border: 1px solid var(--fr-line);
  color: var(--fr-mute); font-size: 12px; font-weight: 520;
  padding: 7px 12px; border-radius: 999px; cursor: pointer;
  transition: color .18s, border-color .18s, background .18s;
}
.fr-lock:hover { color: var(--fr-ink); border-color: rgba(255, 255, 255, .2); }
/* The affordance, made visible: underlined, tinted, and unmistakably a control.
   Without it the chip read as a status badge and the disclosure it opens — the
   full list of what is kept — was never opened by anyone. */
.fr-lock s {
  text-decoration: none; color: var(--fr-cyan); border-bottom: 1px solid currentColor;
  padding-bottom: 1px; font-weight: 560;
}
/* Kept to one line and one size on a phone: the chip is a doorway, not a
   banner, and two wrapped lines of it push the first ask down the screen. */
.fr-lock { max-width: 62vw; font-size: 11.5px; padding: 6px 11px; line-height: 1.35; text-align: left; }
@media (max-width: 420px) { .fr-lock { font-size: 11px; gap: 6px; } }
.fr-lock:hover s { color: var(--fr-ink); }
/* THE DOT ON "ONLY ON YOUR DEVICE" IS GREEN, AND HAS TO BE (Peter, 21 Aug).
 *
 * The Electric Blue migration remapped this to Electric Azure as a "micro
 * accent", which made it the same family as every other blue thing on the
 * screen. It is not decoration: it is a STATUS light, and it is making one
 * claim — nothing is leaving this device, right now. Blue reads as brand;
 * green reads as good, and a status colour has exactly one job.
 *
 * #4ADE9B is the pack's approved good/status green (--fr-green), so this stays
 * inside the palette rather than reaching outside it. The glow is the same
 * colour at the same spread the azure dot had — only the hue changed. */
.fr-lock b { width: 6px; height: 6px; border-radius: 50%; background: var(--fr-green); box-shadow: 0 0 10px var(--fr-green); }

/* ── the account chip ─────────────────────────────────────────────────────
   Sits beside the lock chip, same weight as it: an offer, not a gate. It is
   deliberately not styled as a primary button — the primary action on this
   screen is connecting a source, and a sign-in that outshouts it would read as
   a wall in front of a product whose whole claim is that there isn't one. */
.fr-acct { display: inline-flex; flex-direction: column; align-items: flex-end; gap: 4px; }
.fr-acct-go, .fr-acct-in {
  display: inline-flex; align-items: center; gap: 6px;
  background: rgba(255, 255, 255, .05); border: 1px solid var(--fr-line);
  color: var(--fr-mute); font: inherit; font-size: 12px; font-weight: 560;
  padding: 7px 12px; border-radius: 999px;
  transition: color .18s, border-color .18s, background .18s;
}
.fr-acct-go { cursor: pointer; }
.fr-acct-go:hover:not(:disabled) { color: var(--fr-ink); border-color: var(--fr-cyan); }
.fr-acct-go:disabled { opacity: .6; cursor: default; }
.fr-acct-in b { color: var(--fr-cyan); font-weight: 700; }
.fr-acct-err { margin: 0; max-width: 230px; text-align: right; font-size: 11px; color: var(--fr-mute); }
.fr-acct-link {
  background: none; border: 0; padding: 0; cursor: pointer;
  font: inherit; font-size: 11px; color: var(--fr-dim); text-decoration: underline;
}
.fr-acct-link:hover { color: var(--fr-ink); }
.fr-acct-new { display: inline-flex; gap: 5px; }
.fr-acct-new input {
  width: 160px; padding: 6px 10px; border-radius: 999px;
  border: 1px solid var(--fr-line); background: rgba(255, 255, 255, .04);
  color: var(--fr-ink); font: inherit; font-size: 12px;
}
.fr-acct-new button {
  padding: 6px 12px; border-radius: 999px; cursor: pointer; font: inherit; font-size: 12px; font-weight: 600;
  border: 1px solid var(--fr-cyan); background: transparent; color: var(--fr-cyan);
}
.fr-acct-new button:disabled { opacity: .6; cursor: default; }

/* ── hero ─────────────────────────────────────────────────────────────────── */
.fr-eyebrow {
  font-size: 11px; font-weight: 640; letter-spacing: .14em; text-transform: uppercase;
  color: var(--fr-cyan); opacity: .85; margin: 0 0 14px;
}
.fr-h1 {
  margin: 0 0 14px;
  font-size: clamp(34px, 10.5vw, 52px); line-height: 1.03;
  letter-spacing: -.035em; font-weight: 700;
}
/* THE SPECIAL WORDS. The pack's treatment for them is Ice Blue with an
 * electric glow, so the two words the headline is actually about run the brand
 * gradient — Ring Cyan into Ice Blue into Voltage Blue — instead of the old
 * cyan→violet→orange sweep, which was three hues the brand does not own.
 * This is large text (34–52px, weight 700), so the 3:1 large-text floor
 * applies rather than 4.5:1; the darkest point of the sweep is Voltage Blue at
 * 3.2:1 on Midnight, and it lands on the tail of the last letter. */
.fr-h1 em {
  font-style: normal;
  background: linear-gradient(96deg, var(--fr-ring) 0%, var(--fr-cyan) 46%, var(--fr-volt) 100%);
  -webkit-background-clip: text; background-clip: text; color: transparent;
}
.fr-lede { margin: 0 0 14px; color: var(--fr-mute); font-size: 16.5px; max-width: 44ch; }
.fr-lede b { color: var(--fr-ink); font-weight: 580; }
/* THE DEAL LINE (Peter, 20 Aug: "five credits for free, not three").
 *
 * One line, and it has to read as a fact rather than as a promotion — so no
 * badge, no pill, no fill. It borrows the lede's measure and sits one step
 * brighter than it: enough to be read, not enough to compete with the headline
 * above it. The lede's old 30px bottom margin moved down here, so everything
 * below the hero starts exactly where it was audited. */
.fr-deal {
  margin: 0 0 30px; max-width: 44ch;
  font-size: 14px; line-height: 1.45; font-weight: 560;
  color: var(--fr-ink); opacity: .92;
}

/* ── the step ─────────────────────────────────────────────────────────────── */
.fr-step { margin-bottom: 12px; margin-top: 24px; }
.fr-step-head {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 12px; margin: 0 0 12px;
}
.fr-step-n { font-size: 12px; font-weight: 620; letter-spacing: .1em; text-transform: uppercase; color: var(--fr-dim); }
.fr-step-why { font-size: 13px; color: var(--fr-mute); }
/* The drag sentence is for a pointer; a finger cannot drag a file onto a page. */
/* THE FOUR BEATS, UP FRONT — Peter, 2026-09-10. The scannable ten-second
   version of the story below: one line each, numbered, label then detail. */
.fr-beats {
  list-style: none; counter-reset: beat; margin: 0 0 14px; padding: 0;
  display: grid; gap: 9px; max-width: 46ch;
}
.fr-beats li {
  counter-increment: beat; position: relative; padding-left: 34px;
  font-size: 15px; line-height: 1.45; color: var(--fr-mute);
}
.fr-beats li::before {
  content: counter(beat); position: absolute; left: 0; top: 1px;
  width: 24px; height: 24px; border-radius: 50%; display: grid; place-items: center;
  font-size: 12px; font-weight: 660; color: var(--fr-cyan);
  background: rgba(94, 213, 255, .1); border: 1px solid rgba(94, 213, 255, .28);
}
.fr-beats b { color: var(--fr-ink); font-weight: 600; letter-spacing: -.01em; }

.fr-drag { font-size: 13px; color: var(--fr-mute); margin: -4px 0 10px; }
@media (hover: none) and (pointer: coarse) { .fr-drag { display: none; } }
/* The mirror of .fr-drag — Peter, 2026-09-10: tell a phone user a computer is
   easier. Shown ONLY where .fr-drag is hidden (coarse pointer / no hover). */
.fr-desk-hint { display: none; }
@media (hover: none) and (pointer: coarse) {
  .fr-desk-hint { display: block; font-size: 13px; color: var(--fr-mute); margin: 8px 0 2px; max-width: 44ch; }
}
.fr-oautherr-why { margin: 6px 0 0; font-size: 12.5px; color: var(--fr-mute); }
.fr-chip-ic { margin-right: 6px; opacity: .85; font-size: 1.05em; line-height: 1; }

/* THE PRIMARY ACTION. One per screen, always — and the highest-intent surface
 * on the product, so this is where the electric gradient is allowed to live.
 *
 * It is a WASH, not a fill. A solid Ice-Blue-to-Voltage-Blue button cannot
 * carry one label colour honestly: dark ink reads 11.9:1 at the Ice end and
 * 3.2:1 at the Voltage end, light ink does the reverse. So the gradient runs
 * at low alpha over Deep Ocean, the label stays Soft White at better than
 * 12:1, and the electricity comes from the edge and the glow instead. The
 * gradient is still the real thing — Ice Blue on the left, Voltage Blue on
 * the right — just not at a strength that costs anyone a word.
 *
 * The rail down the left edge is the gradient at full strength, which is where
 * a gradient belongs: on a surface with nothing written on it. */
.fr-primary {
  position: relative; display: flex; align-items: center; gap: 14px; width: 100%;
  text-align: left; cursor: pointer; overflow: hidden;
  padding: 18px 18px 18px 21px; border-radius: var(--fr-radius);
  border: 1px solid rgba(94, 213, 255, .40);
  background:
    linear-gradient(96deg, rgba(94, 213, 255, .20), rgba(0, 72, 255, .20)),
    var(--fr-bg-2);
  color: var(--fr-ink); font: inherit;
  box-shadow: var(--fr-glow), inset 0 1px 0 rgba(255, 255, 255, .07);
  transition: transform .16s var(--fr-ease), box-shadow .22s, border-color .22s, background .22s;
}
.fr-primary::before {
  content: ''; position: absolute; left: 0; top: 0; bottom: 0; width: 3px;
  background: linear-gradient(180deg, var(--tru-electric-ice-blue, #5ED5FF), var(--tru-voltage-blue, #0048FF));
}
/* Hover flips which blue leads. That is the alternation as an interaction, not
   as a second colour scheme — same two hues, opposite ends. */
.fr-primary:hover {
  transform: translateY(-1px);
  border-color: rgba(94, 213, 255, .62);
  background:
    linear-gradient(96deg, rgba(0, 72, 255, .26), rgba(94, 213, 255, .26)),
    var(--fr-bg-2);
  box-shadow: 0 0 0 1px rgba(94, 213, 255, .3), 0 16px 44px -16px rgba(94, 213, 255, .7);
}
.fr-primary:active { transform: translateY(1px) scale(.995); }
.fr-primary:focus-visible { outline: 2px solid var(--fr-cyan); outline-offset: 3px; }
.fr-primary[disabled] { opacity: .55; cursor: progress; }

.fr-ic {
  flex: 0 0 42px; height: 42px; border-radius: 12px; display: grid; place-items: center;
  background: rgba(255, 255, 255, .07); border: 1px solid var(--fr-line);
  font-size: 18px; line-height: 1;
}
.fr-body { flex: 1 1 auto; min-width: 0; }
.fr-title { display: block; font-size: 17px; font-weight: 620; letter-spacing: -.01em; }
.fr-sub { display: block; font-size: 13.5px; color: var(--fr-mute); margin-top: 3px; }
.fr-because {
  display: inline-flex; align-items: center; gap: 5px; margin-top: 7px;
  font-size: 12px; font-weight: 560; color: var(--fr-green);
  background: rgba(74, 222, 155, .1); border: 1px solid rgba(74, 222, 155, .22);
  padding: 3px 8px; border-radius: 999px;
}
/* The same proof on a chip, one glyph wide: the reason is on the tile it opens
   into (title= carries it for a hover). Green because it is good news — the
   inbox said you have this — and green is what .fr-because already means. */
.fr-because-glyph { color: var(--fr-green); font-size: .9em; margin-left: 2px; }
.fr-chip-proven { border-color: rgba(74, 222, 155, .35); }
/* THE REWARD, IN RING CYAN. It was ember orange, which was the only warm thing
   left on an otherwise disciplined electric page and read as a warning rather
   than a bonus. Ring Cyan is the pack's "fine highlight" and is a step off the
   Ice Blue of the title beside it, so the badge stays distinct without
   introducing a hue the brand does not own. Orange still means WARNING here —
   .fr-sub-warn keeps it, and that is the whole point of not spending it on
   good news. */
.fr-reward {
  flex: 0 0 auto; align-self: flex-start;
  font-size: 12px; font-weight: 640; color: var(--fr-ring);
  background: rgba(125, 236, 255, .10); border: 1px solid rgba(125, 236, 255, .34);
  padding: 4px 9px; border-radius: 999px; white-space: nowrap;
}
.fr-effort { display: block; font-size: 11.5px; color: var(--fr-dim); margin-top: 8px; }
/* The primary tile's electric wash lifts its background to rgb(20,49,67), and
   the two quiet inks that read fine on Midnight fall to 4.3:1 and 3.9:1 on top
   of it — under the floor, on the one button the whole screen is for. They get
   a step lighter INSIDE the tile only: 6.2:1 there, and nothing else moves.
   This is what "a glow is not a substitute for contrast" costs in practice. */
.fr-primary .fr-sub, .fr-primary .fr-effort { color: #A3B0C6; }

/* Alternates. Deliberately quieter — they are a way out, not a choice. */
.fr-alts { display: grid; gap: 8px; margin-top: 10px; }
.fr-alt {
  display: flex; align-items: center; gap: 12px; width: 100%; text-align: left;
  cursor: pointer; padding: 13px 14px; border-radius: 14px;
  border: 1px solid var(--fr-line); background: rgba(255, 255, 255, .028);
  color: var(--fr-ink); font: inherit;
  transition: background .18s, border-color .18s, transform .16s var(--fr-ease);
}
/* THE ALTERNATION, SECOND BEAT. The primary tile above leads with Ice Blue;
   the alternates answer in Voltage Blue. Same family, opposite end, and it is
   only ever an edge and a wash here — these are a way out, not a choice, and
   the moment they glow as hard as the primary the screen has two answers. */
.fr-alt:hover {
  background: linear-gradient(96deg, rgba(0, 72, 255, .16), rgba(0, 72, 255, .07)), rgba(255, 255, 255, .02);
  border-color: rgba(0, 72, 255, .75);
}
.fr-alt:active { transform: scale(.99); }
.fr-alt .fr-ic { flex-basis: 34px; height: 34px; font-size: 15px; border-radius: 10px; }
.fr-alt .fr-title { font-size: 14.5px; font-weight: 560; }
.fr-alt .fr-sub { font-size: 12.5px; }

/* The email line: a way in, not a tile. It carried a subtitle and a three-line
   warning badge and pushed itself off a 390x844 phone — so the one alternative
   the first screen is supposed to show beside the file drop was the one thing
   you had to scroll for. Same button, one third the height. */
.fr-alt-quiet { padding: 9px 12px; }
.fr-alt-quiet .fr-ic { flex-basis: 26px; height: 26px; font-size: 13px; border-radius: 8px; }
.fr-alt-quiet .fr-title { font-size: 14px; }
.fr-alt-quiet .fr-sub { font-size: 11.5px; margin-top: 1px; }
.fr-sub-warn { color: var(--fr-ember); opacity: .92; }

/* ── the ladder rail: what is coming, so "later" is a promise not a mystery ── */
.fr-later {
  margin-top: 22px; padding-top: 18px; border-top: 1px dashed var(--fr-line);
}
.fr-later-h {
  font-size: 12px; font-weight: 600; letter-spacing: .06em; text-transform: uppercase;
  color: var(--fr-dim); margin: 0 0 10px;
}
.fr-chips { display: flex; flex-wrap: wrap; gap: 7px; }
.fr-chip {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 12px; color: var(--fr-dim);
  border: 1px solid var(--fr-line); border-radius: 999px; padding: 5px 11px;
  background: rgba(255, 255, 255, .02);
}
.fr-chip::before { content: '🔒'; font-size: 9px; opacity: .5; filter: grayscale(1); }
/* Chips for things you could do RIGHT NOW are buttons, and must not wear a lock. */
.fr-chip.fr-open {
  cursor: pointer; font: inherit; font-size: 12px; color: var(--fr-mute);
  transition: color .16s, border-color .16s, background .16s;
}
.fr-chip.fr-open::before { content: '+'; font-size: 12px; opacity: .7; filter: none; color: var(--fr-cyan); }
.fr-chip.fr-open:hover { color: var(--fr-ink); border-color: rgba(94, 213, 255, .35); background: rgba(94, 213, 255, .07); }
.fr-chip.fr-done { color: var(--fr-green); border-color: rgba(74, 222, 155, .28); background: rgba(74, 222, 155, .07); }
.fr-chip.fr-done::before { content: '✓'; opacity: 1; }

/* ── progress: lenses, not a source count ────────────────────────────────── */
/* A Deep Ocean panel with a single Ring Cyan hairline, which is the card the
   pack prescribes: elevated dark surface, border in the 25–45% band. */
.fr-prog {
  margin-top: 26px; padding: 18px; border-radius: var(--fr-radius);
  border: 1px solid var(--fr-line); background: var(--fr-bg-2);
}
.fr-prog-top { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; margin-bottom: 14px; }
/* THE NUMBER. The pack's treatment for a figure that matters: Ice Blue, with a
   close electric glow behind it. Ice Blue on Deep Ocean is 10.3:1, so the glow
   is doing what a glow should — adding light to something already legible,
   rather than standing in for contrast it does not have. */
.fr-pct {
  font-size: 30px; font-weight: 700; letter-spacing: -.03em; line-height: 1;
  color: var(--fr-cyan);
  text-shadow: 0 0 14px rgba(94, 213, 255, .45), 0 0 34px rgba(0, 164, 255, .28);
}
.fr-pct span { font-size: 15px; font-weight: 560; color: var(--fr-mute); margin-left: 2px; text-shadow: none; }
.fr-pct-cap { font-size: 12.5px; color: var(--fr-mute); text-align: right; max-width: 22ch; }

.fr-lenses { display: grid; grid-template-columns: repeat(7, 1fr); gap: 6px; }
.fr-lens { text-align: center; }
.fr-lens-bar {
  height: 42px; border-radius: 7px; overflow: hidden; position: relative;
  background: rgba(255, 255, 255, .05); border: 1px solid var(--fr-line);
}
/* THE METER FILL. A surface with nothing written on it, which is exactly where
   the electric gradient earns its keep: Ice Blue at the top of the column,
   Voltage Blue at the base, so a full lens reads as a bolt rather than a bar. */
.fr-lens-fill {
  position: absolute; left: 0; right: 0; bottom: 0; height: 0%;
  background: linear-gradient(180deg, var(--tru-electric-ice-blue, #5ED5FF), var(--tru-voltage-blue, #0048FF));
  box-shadow: 0 0 12px -2px rgba(94, 213, 255, .55);
  transition: height .7s var(--fr-ease);
}
.fr-lens.fr-dark .fr-lens-bar { border-style: dashed; }
.fr-lens-l {
  display: block; margin-top: 6px; font-size: 9.5px; letter-spacing: .02em;
  color: var(--fr-dim); white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.fr-lens.fr-lit .fr-lens-l { color: var(--fr-mute); }

/* THE CREDIT BADGE. High intent — it is the number a person is here to grow —
   so it gets the gradient, as a HAIRLINE rather than a fill: the two-layer
   padding-box/border-box trick paints Ice Blue → Voltage Blue in a 1px ring
   around a Deep Ocean pill, which a plain `border-image` cannot do on a
   rounded corner. The label sits on Deep Ocean at 5.5:1 and the count is Ice
   Blue at 10.3:1, so nothing about this depends on the glow. */
.fr-credits {
  display: inline-flex; align-items: center; gap: 8px; margin-top: 14px;
  font-size: 13.5px; color: var(--fr-mute);
  padding: 7px 14px; border-radius: 999px;
  border: 1px solid transparent;
  background:
    linear-gradient(var(--fr-bg-2), var(--fr-bg-2)) padding-box,
    var(--fr-grad) border-box;
}
.fr-credits b {
  color: var(--fr-cyan); font-size: 16px; font-weight: 680;
  text-shadow: 0 0 12px rgba(94, 213, 255, .5);
}

/* ── the running log: "we need to log all those in" made visible ─────────── */
.fr-log { margin-top: 20px; }
.fr-log-h { font-size: 12px; letter-spacing: .06em; text-transform: uppercase; color: var(--fr-dim); margin: 0 0 8px; }
.fr-log ol { list-style: none; margin: 0; padding: 0; display: grid; gap: 6px; }
.fr-log li {
  display: flex; align-items: center; gap: 10px; font-size: 13.5px; color: var(--fr-mute);
  padding: 9px 12px; border-radius: 11px;
  background: rgba(74, 222, 155, .06); border: 1px solid rgba(74, 222, 155, .16);
  animation: fr-in .45s var(--fr-ease) both;
}
.fr-log li i { font-style: normal; color: var(--fr-green); }
.fr-log li b { color: var(--fr-ink); font-weight: 580; flex: 0 0 auto; }
.fr-log li em { font-style: normal; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.fr-log li s { text-decoration: none; margin-left: auto; color: var(--fr-dim); font-size: 11.5px; white-space: nowrap; }
@keyframes fr-in { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }

/* ── footers, notes, escapes ─────────────────────────────────────────────── */
.fr-note { margin-top: 18px; font-size: 12.5px; color: var(--fr-dim); }
.fr-skip {
  display: block; margin: 18px auto 0; background: none; border: 0; cursor: pointer;
  color: var(--fr-dim); font: inherit; font-size: 13.5px; text-decoration: underline;
  text-underline-offset: 3px; text-decoration-color: var(--fr-line);
}
.fr-skip:hover { color: var(--fr-mute); }
/* The tagline as a sign-off. Set in the brand's own aqua for the two words the
   logo tints, so the words and the image agree even though only one is a file. */
.fr-signoff {
  margin: 40px 0 0; font-size: 13px; font-weight: 560; letter-spacing: .02em;
  color: var(--fr-mute);
}
.fr-foot { margin-top: 10px; font-size: 11.5px; color: var(--fr-dim); line-height: 1.6; }

/* The quiet Google re-prompt. Deliberately not a tile and not an error: the
   permission expiring is normal, and the fix is one tap. */
.fr-relink {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  width: 100%; margin-top: 12px; padding: 10px 13px; border-radius: 12px;
  border: 1px solid var(--fr-line); background: rgba(255, 255, 255, .028);
  color: var(--fr-mute); font: inherit; font-size: 12.5px; text-align: left; cursor: pointer;
}
.fr-relink:hover { color: var(--fr-ink); border-color: rgba(255, 255, 255, .18); }
.fr-relink s { text-decoration: none; color: var(--fr-cyan); white-space: nowrap; font-weight: 560; }

.fr-err {
  margin-top: 12px; padding: 11px 13px; border-radius: 12px; font-size: 13px;
  color: #ffd7c2; background: rgba(255, 138, 61, .1); border: 1px solid rgba(255, 138, 61, .28);
}

/* ── THE FOLD, WHICH IS 844px AND IS NOT NEGOTIABLE ───────────────────────
   A phone is 390x844. The two controls the first screen exists to offer — the
   file drop, and the quiet way in through Google — have to be reachable
   without a scroll, because a stranger decides in the first screenful and a
   control they have not seen cannot be pressed. Measured, not guessed: before
   this the email line finished at 885px, forty-one pixels into territory
   nobody looks at.

   Nothing here hides anything. It takes the air out of a hero that was sized
   for a laptop and puts it back on a screen a third the height.

   20 Aug: the wordmark arrived and it is 74px tall — so the air came out of the
   masthead too. The chips went from a stacked column (89px) to one row (46px),
   the shell lost six pixels off the top, and every margin between the logo and
   the primary button gave back two to eight. Nothing was hidden and nothing was
   reordered; the email alternative still lands above 844. */
@media (max-width: 480px) {
  .fr-shell { padding-top: calc(env(safe-area-inset-top) + 12px); }
  /* The lock chip is capped so it and the language pills share one line —
     235 + 8 + 111 overflowed a 350px column by four pixels. */
  .fr-lock { max-width: 226px; }
  .fr-top { margin-bottom: 8px; }
  /* The tagline lockup and the hero eyebrow are both uppercase and both
     letterspaced, so a tight gap made them read as one two-line block.
     The air between them is bought back out of the h1 and the alts. */
  .fr-brand { gap: 6px; margin-bottom: 20px; }
  .fr-wordmark { max-width: 340px; }
  .fr-tagimg { max-width: 260px; }
  .fr-eyebrow { margin-bottom: 6px; }
  .fr-h1 { font-size: clamp(29px, 8.5vw, 38px); margin-bottom: 8px; }
  .fr-lede { font-size: 15.5px; margin-bottom: 6px; }
  .fr-deal { font-size: 13.5px; margin-bottom: 8px; }
  .fr-beats { gap: 8px; margin-bottom: 10px; }
  .fr-beats li { font-size: 14px; padding-left: 30px; }
  .fr-step { margin-top: 8px; }
  .fr-step-head { margin-bottom: 6px; }
  /* Untouched: every tap target on this screen is exactly the size it was
     audited at. The logo was paid for out of whitespace, not out of buttons. */
  .fr-primary { padding: 15px 16px; }
  .fr-effort { margin-top: 6px; }
  .fr-alts { gap: 6px; margin-top: 8px; }
  .fr-alt { padding: 11px 13px; }
  .fr-alt-quiet { padding: 8px 12px; }
}

/* ── wider screens: it is still one column, just calmer ──────────────────── */
@media (min-width: 720px) {
  .fr-shell { padding-top: 44px; }
  .fr-wrap { max-width: 620px; }
  /* There is room here, so the logo takes it. */
  .fr-wordmark { max-width: 420px; }
  .fr-tagimg { max-width: 320px; }
  .fr-brand { margin-bottom: 28px; }
  .fr-lede { font-size: 17.5px; }
}

@media (prefers-reduced-motion: reduce) {
  .fr-primary, .fr-alt, .fr-lens-fill, .fr-log li { transition: none; animation: none; }
}

/* ── how it works: the three beats ────────────────────────────────────────
   Below the ask on purpose. Someone ready to connect shouldn't scroll past an
   explanation to do it; someone who isn't ready needs it there when they look.
   Leading with the story optimizes for the visitor who was never going to act. */
/* …AND IT IS COLLAPSED. Four beats measured 1018px on a 390px phone: a full
   screen of explanation between the ask and the footer, on a page arguing that
   you can find out in three seconds by dropping a file. One tap opens it. */
.fr-story {
  margin-top: 30px; padding-top: 24px; border-top: 1px solid var(--fr-line);
}
.fr-story-h {
  font-size: 13.5px; font-weight: 580; letter-spacing: -.01em; text-transform: none;
  color: var(--fr-mute); margin: 0; cursor: pointer; list-style: none;
}
.fr-story-h::-webkit-details-marker { display: none; }
.fr-story-h::after { content: ' ▾'; opacity: .6; }
.fr-story[open] .fr-story-h { margin-bottom: 18px; }
.fr-story[open] .fr-story-h::after { content: ' ▴'; }
.fr-story-h:hover { color: var(--fr-ink); }
.fr-beat { display: flex; gap: 14px; margin-bottom: 20px; }
.fr-beat-n {
  flex: 0 0 26px; height: 26px; border-radius: 50%; display: grid; place-items: center;
  font-size: 12px; font-weight: 660; color: var(--fr-cyan);
  background: rgba(94, 213, 255, .1); border: 1px solid rgba(94, 213, 255, .28);
}
/* The lead beat carries no number, because it is not a step — it is the frame
   the three numbered steps happen inside, and numbering it "0" or "4" at the
   top of the list would make the sequence beneath it read as broken. It gets a
   rule under it instead, so the eye still knows where the steps begin. */
.fr-beat-lead {
  padding-bottom: 18px; margin-bottom: 20px;
  border-bottom: 1px solid var(--fr-line);
}
.fr-beat > div { min-width: 0; }
.fr-beat b {
  display: block; font-size: 15.5px; font-weight: 600; letter-spacing: -.012em;
  color: var(--fr-ink); margin-bottom: 4px;
}
.fr-beat p { margin: 0; font-size: 14px; color: var(--fr-mute); }
.fr-beat p b { display: inline; font-size: inherit; color: var(--fr-ink); font-weight: 580; margin: 0; }
/* Someone who read to the end just talked themselves into it. Making them
   scroll back up to act is how you lose them at the finish line. */
.fr-story-cta { margin-top: 24px; }
.fr-story-cta p {
  margin: 0 0 12px; text-align: center;
  font-size: 16px; font-weight: 580; color: var(--fr-ink); letter-spacing: -.01em;
}

.fr-foot a { color: var(--fr-mute); text-decoration: none; border-bottom: 1px solid var(--fr-line); }
.fr-foot a:hover { color: var(--fr-ink); }

/* ── the handoff into the breakdown ──────────────────────────────────────── */
.fr-breakdown {
  display: block; width: 100%; margin-top: 14px; padding: 15px 16px;
  border-radius: 14px; cursor: pointer; text-align: left; font: inherit;
  color: var(--fr-ink);
  background: linear-gradient(180deg, rgba(255,138,61,.16), rgba(255,138,61,.06));
  border: 1px solid rgba(255,138,61,.4);
  font-size: 15.5px; font-weight: 600; letter-spacing: -.01em;
  transition: transform .16s var(--fr-ease), border-color .2s;
}
.fr-breakdown:hover { transform: translateY(-1px); border-color: rgba(255,138,61,.65); }
.fr-breakdown:active { transform: translateY(1px); }
.fr-breakdown span {
  display: block; margin-top: 4px;
  font-size: 12.5px; font-weight: 480; color: var(--fr-mute);
}
.fr-credits-note { margin: 12px 0 0; font-size: 12.5px; color: var(--fr-dim); }

/* Never a one-way door. */
.fr-return {
  position: fixed; z-index: 60;
  left: calc(env(safe-area-inset-left) + 14px);
  bottom: calc(env(safe-area-inset-bottom) + 14px);
  padding: 10px 15px; border-radius: 999px; cursor: pointer; font: inherit;
  font-size: 13px; font-weight: 560; color: var(--fr-ink);
  background: rgba(9,13,24,.94); border: 1px solid rgba(255,255,255,.16);
  box-shadow: 0 8px 26px -10px rgba(0,0,0,.85);
  backdrop-filter: blur(10px);
}
.fr-return:hover { border-color: rgba(94, 213, 255,.45); }
body.fr-on .fr-return { display: none; }

/* ── what a freshly-connected source actually said ───────────────────────── */
.fr-found {
  margin-top: 20px; padding: 16px 18px; border-radius: 16px;
  background: rgba(94, 213, 255,.06); border: 1px solid rgba(94, 213, 255,.22);
}
.fr-found ul { margin: 0; padding-left: 18px; }
.fr-found li { font-size: 14px; color: var(--fr-ink); margin-bottom: 6px; }
.fr-found-note { margin: 12px 0 0; font-size: 12px; color: var(--fr-dim); }

/* ── language ─────────────────────────────────────────────────────────────
   Beside the trust chip, because that is where Peter wanted it and because the
   two things a stranger wants to settle first are "is this safe" and "can I
   read it." Two written languages as pills; everything else behind the ＋,
   marked as coming rather than offered as if it works.

   Laid out as a wrapping ROW since the wordmark landed: the two chips fit one
   line on a 390px phone, and the 43px the old column spent is now the logo's. */
.fr-topright {
  display: flex; flex-direction: row; flex-wrap: wrap;
  align-items: center; justify-content: flex-end; gap: 8px;
}
.fr-lang { position: relative; display: inline-flex; gap: 3px; padding: 3px;
  background: rgba(255, 255, 255, .05); border: 1px solid var(--fr-line); border-radius: 999px; }
.fr-lang-pill {
  min-width: 32px; padding: 4px 9px; border: 0; border-radius: 999px; cursor: pointer;
  font: inherit; font-size: 11.5px; font-weight: 620; letter-spacing: .04em;
  color: var(--fr-dim); background: transparent;
  transition: color .16s, background .16s;
}
.fr-lang-pill:hover { color: var(--fr-ink); }
.fr-lang-pill.fr-on-lang { color: var(--fr-bg); background: var(--fr-cyan); }
.fr-lang-more { font-size: 13px; min-width: 26px; padding: 4px 6px; }

.fr-lang-sheet {
  position: absolute; top: calc(100% + 8px); right: 0; z-index: 70;
  width: 232px; max-height: 320px; overflow-y: auto; padding: 6px;
  background: #071B33; border: 1px solid rgba(255, 255, 255, .16); border-radius: 14px;
  box-shadow: 0 18px 44px -14px rgba(0, 0, 0, .9);
}
.fr-lang-row {
  display: flex; flex-direction: column; align-items: flex-start; gap: 1px;
  width: 100%; padding: 8px 10px; border: 0; border-radius: 9px; cursor: pointer;
  background: transparent; color: var(--fr-ink); font: inherit; text-align: left;
}
.fr-lang-row:hover { background: rgba(255, 255, 255, .07); }
.fr-lang-row b { font-size: 14px; font-weight: 580; }
.fr-lang-row span { font-size: 11.5px; color: var(--fr-dim); }
.fr-lang-row.fr-soon { cursor: default; opacity: .5; }
.fr-lang-row.fr-soon:hover { background: transparent; }

/* Said in the footer rather than hidden: the interface is translated, the
   analysis is not. Half-translating and staying quiet would be the worse move. */
.fr-partial { display: inline-block; margin-top: 6px; color: var(--fr-dim); font-style: italic; }

[dir="rtl"] .fr-topright { align-items: flex-start; }
[dir="rtl"] .fr-lang-sheet { right: auto; left: 0; }

.fr-merged {
  margin-left: auto; font-size: 11.5px; color: var(--fr-green);
  background: rgba(74, 222, 155, .1); border: 1px solid rgba(74, 222, 155, .24);
  padding: 3px 9px; border-radius: 999px; white-space: nowrap;
}

/* ── what you pay for, against whether you use it ─────────────────────────
   The one thing nobody else can say, so it sits above everything else — and
   renders not at all until both halves of the evidence exist. */
.fr-money {
  margin-top: 20px; padding: 18px; border-radius: 16px;
  background: linear-gradient(180deg, rgba(255,138,61,.1), rgba(255,138,61,.03));
  border: 1px solid rgba(255,138,61,.3);
}
.fr-money-head {
  margin: 0 0 12px; font-size: 17px; font-weight: 620; letter-spacing: -.015em;
  color: var(--fr-ink); line-height: 1.35;
}
.fr-money-rows { margin: 0; padding: 0; list-style: none; display: grid; gap: 7px; }
.fr-money-rows li {
  font-size: 13.5px; color: var(--fr-mute); padding-left: 14px; position: relative;
}
.fr-money-rows li::before {
  content: ''; position: absolute; left: 0; top: 8px;
  width: 5px; height: 5px; border-radius: 50%; background: var(--fr-dim);
}
.fr-money-rows li.fr-v-unused::before { background: var(--fr-ember); }
.fr-money-rows li.fr-v-barely::before { background: #ffd166; }
.fr-money .fr-found-note { margin-top: 12px; }

/* ── warning people about Google's warning ────────────────────────────────
   The unverified-app screen is a red triangle and a button that says BACK TO
   SAFETY. Dropped on someone cold it reads as evidence against the product.
   Said first, in our own words, it becomes a step we predicted. */
/* The scrim: a fixed, centered overlay so the confirmation can never land
   below the fold (the phone bug — see warningPanel() in firstrun.js). It is a
   child of #fr-main, but no ancestor sets transform/filter/perspective, so
   position:fixed pins to the viewport. Tapping the scrim (outside the card)
   dismisses; wire() binds that. */
.fr-warn-scrim {
  position: fixed; inset: 0; z-index: 1000;
  display: flex; align-items: center; justify-content: center;
  padding: 20px; box-sizing: border-box;
  background: rgba(4, 7, 14, .72);
  -webkit-backdrop-filter: blur(3px); backdrop-filter: blur(3px);
  animation: fr-scrim-in .16s ease-out;
  overflow-y: auto;
}
@keyframes fr-scrim-in { from { opacity: 0; } to { opacity: 1; } }
@keyframes fr-card-in { from { opacity: 0; transform: translateY(10px) scale(.985); } to { opacity: 1; transform: none; } }
.fr-warn {
  width: 100%; max-width: 460px; margin: auto;
  max-height: calc(100svh - 40px); overflow-y: auto;
  padding: 22px; border-radius: 18px;
  background: linear-gradient(180deg, rgba(38, 30, 16, .98), rgba(22, 20, 14, .98));
  border: 1px solid rgba(255,180,84,.40);
  box-shadow: 0 24px 70px -18px rgba(0,0,0,.85);
  animation: fr-card-in .2s ease-out;
}
@media (prefers-reduced-motion: reduce) {
  .fr-warn-scrim, .fr-warn { animation: none; }
}
.fr-warn-h {
  margin: 0 0 12px; font-size: 17.5px; font-weight: 640; letter-spacing: -.015em;
  color: var(--fr-ink);
}
.fr-warn p { margin: 0 0 12px; font-size: 14.5px; color: var(--fr-mute); }
.fr-warn-do {
  padding: 12px 14px; border-radius: 12px;
  background: rgba(0,0,0,.28); border: 1px solid var(--fr-line);
  color: var(--fr-ink) !important;
}
.fr-warn-do b { color: #ffd166; font-weight: 640; }
.fr-warn-what { font-size: 13px !important; color: var(--fr-dim) !important; }
.fr-warn-cta { margin-top: 16px; }
.fr-warn-go {
  justify-content: center; text-align: center; font-size: 15.5px; font-weight: 620;
  padding: 15px 18px;
}
.fr-warn-cta .fr-skip { margin-top: 12px; }

/* ── asking for the second inbox, out loud ────────────────────────────────
   It was a quiet alternate button, which is the same as not asking. */
.fr-ask2 {
  margin: 22px 0; padding: 20px; border-radius: 16px;
  background: linear-gradient(180deg, rgba(94, 213, 255,.09), rgba(94, 213, 255,.03));
  border: 1px solid rgba(94, 213, 255,.3);
}
.fr-ask2-h {
  margin: 0 0 10px; font-size: 18px; font-weight: 650; letter-spacing: -.02em;
  color: var(--fr-ink);
}
.fr-ask2 > p { margin: 0 0 16px; font-size: 14.5px; color: var(--fr-mute); }
.fr-ask2-cta .fr-skip { margin-top: 12px; }

/* ── the guided click-through ─────────────────────────────────────────────
   Peter, 2026-08-18: "we can guide them through that... we say where to click."

   Deliberately short and linear. A guide that scrolls is a guide that gets
   skimmed, and a skimmed guide is how somebody requests one year of Spotify
   history instead of all of it and never finds out. */
.fr-guide {
  position: relative;
  margin: 22px 0; padding: 22px 20px 18px; border-radius: 18px;
  background: linear-gradient(180deg, rgba(255,255,255,.05), rgba(255,255,255,.02));
  border: 1px solid rgba(255,255,255,.14);
}
.fr-guide-close {
  position: absolute; top: 12px; right: 12px;
  width: 30px; height: 30px; border-radius: 999px;
  background: rgba(255,255,255,.06); border: 1px solid rgba(255,255,255,.12);
  color: var(--fr-mute); font-size: 13px; line-height: 1; cursor: pointer;
}
.fr-guide-close:hover { color: var(--fr-ink); background: rgba(255,255,255,.1); }
.fr-guide-rung {
  margin: 0 0 6px; font-size: 11.5px; letter-spacing: .14em; text-transform: uppercase;
  color: var(--fr-accent, #5ED5FF); font-weight: 600;
}
.fr-guide-h {
  margin: 0 0 8px; font-size: 21px; font-weight: 660; letter-spacing: -.022em;
  color: var(--fr-ink);
}
.fr-guide-why { margin: 0 0 16px; font-size: 14.5px; line-height: 1.5; color: var(--fr-mute); }
.fr-guide-link { justify-content: space-between; margin-bottom: 16px; }

/* No verified link for this one. Showing the menu path is not a downgrade we
   apologise for — a link that 404s mid-flow is worse than reading four words. */
.fr-guide-path {
  margin: 0 0 16px; padding: 14px 16px; border-radius: 12px;
  background: rgba(255,255,255,.04); border: 1px dashed rgba(255,255,255,.18);
}
.fr-guide-path-h {
  margin: 0 0 6px; font-size: 11px; letter-spacing: .12em; text-transform: uppercase;
  color: var(--fr-mute);
}
.fr-guide-path-t { margin: 0; font-size: 14.5px; color: var(--fr-ink); font-weight: 560; }
.fr-guide-path-l {
  display: inline-block; margin-top: 10px; font-size: 13.5px;
  color: var(--fr-accent, #5ED5FF); text-decoration: none;
}
.fr-guide-path-l:hover { text-decoration: underline; }

.fr-guide-steps {
  margin: 0 0 16px; padding-left: 20px;
  font-size: 14.5px; line-height: 1.62; color: var(--fr-ink);
}
.fr-guide-steps li { margin-bottom: 7px; }
.fr-guide-steps li::marker { color: var(--fr-accent, #5ED5FF); font-weight: 700; }

.fr-guide-gotcha {
  margin: 0 0 16px; padding: 12px 14px; border-radius: 10px;
  font-size: 13.5px; line-height: 1.5;
  background: rgba(255,196,84,.08); border: 1px solid rgba(255,196,84,.26);
  color: #ffd79a;
}

/* The drop target. It never uploads — the file is read in this tab and the
   bytes are dropped. Saying so, right here, is the whole product in one line. */
.fr-drop {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 4px; padding: 26px 16px; margin-bottom: 14px;
  border-radius: 14px; cursor: pointer; text-align: center;
  border: 1.5px dashed rgba(94, 213, 255,.4); background: rgba(94, 213, 255,.05);
  transition: background .15s ease, border-color .15s ease;
}
.fr-drop:hover, .fr-drop.is-over { background: rgba(94, 213, 255,.12); border-color: rgba(94, 213, 255,.75); }
.fr-drop-input { position: absolute; width: 1px; height: 1px; opacity: 0; pointer-events: none; }
.fr-drop-t { font-size: 15px; font-weight: 600; color: var(--fr-ink); }
.fr-drop-s { font-size: 13px; color: var(--fr-mute); }

/* What we said back about the file they dropped. A wrong file is a sentence,
   never a red box — people will drop Netflix into the bank step, and that is
   a thing we wanted anyway. */
.fr-guide-said { margin: 0 0 14px; font-size: 13.5px; line-height: 1.5; }
.fr-guide-said.is-info { color: var(--fr-mute); }
.fr-guide-said.is-ok   { color: #7ee7a8; }
.fr-guide-said.is-warn { color: #ffd79a; }

.fr-guide-cta { margin-top: 4px; }
.fr-guide-cta .fr-skip { margin-top: 10px; }
.fr-guide-note { margin: 10px 0 0; font-size: 13px; color: var(--fr-mute); }
.fr-guide-privacy {
  margin: 14px 0 0; padding-top: 12px; font-size: 12.5px; color: var(--fr-mute);
  border-top: 1px solid rgba(255,255,255,.08);
}

/* ── the escalation ───────────────────────────────────────────────────────
   Shown once, when the easy work genuinely runs out. Up to here the product
   has been asking for taps; from here it is asking for a favour, and it should
   look like it knows the difference. */
.fr-escalate {
  margin: 24px 0; padding: 22px 20px; border-radius: 18px;
  background: linear-gradient(180deg, rgba(126,231,168,.09), rgba(126,231,168,.02));
  border: 1px solid rgba(126,231,168,.3);
}
.fr-escalate-helper {
  background: linear-gradient(180deg, rgba(180,140,255,.1), rgba(180,140,255,.03));
  border-color: rgba(180,140,255,.32);
}
.fr-escalate-h {
  margin: 0 0 10px; font-size: 19px; font-weight: 650; letter-spacing: -.02em;
  color: var(--fr-ink);
}
.fr-escalate-b { margin: 0 0 18px; font-size: 14.5px; line-height: 1.58; color: var(--fr-mute); }
.fr-escalate-cta .fr-primary { justify-content: center; text-align: center; }
.fr-escalate-cta .fr-skip { margin-top: 12px; }

@media (prefers-reduced-motion: reduce) {
  .fr-drop { transition: none; }
}

/* A one-line confirmation. Same slot as the error, opposite colour — and, like
   the error, it is render STATE, because anything appended outside the render
   loop gets erased by the next pass. */
.fr-note {
  margin: 0 0 16px; padding: 11px 14px; border-radius: 10px;
  font-size: 13.5px; line-height: 1.5;
  background: rgba(126,231,168,.09); border: 1px solid rgba(126,231,168,.26);
  color: #a8f0c4;
}

/* The folder scan. Same shape as the file drop, different promise — one click
   for potentially six sources, and the whole feature depends on the person
   believing we will not read the rest of the folder. */
.fr-drop-folder {
  border-color: rgba(126,231,168,.42); background: rgba(126,231,168,.06);
}
.fr-drop-folder:hover { background: rgba(126,231,168,.13); border-color: rgba(126,231,168,.78); }
#fr-folder-out { margin-top: 4px; }
#fr-folder-out .fr-guide-said { margin-bottom: 6px; }

/* ══ THE REVEAL ══════════════════════════════════════════════════════════════
   The one screen where the work becomes visible. Everything else in this
   product happens where nobody can see it. */
.rv { margin: 24px 0; }
.rv-head { margin-bottom: 22px; }
.rv-eyebrow {
  margin: 0 0 6px; font-size: 11.5px; letter-spacing: .15em; text-transform: uppercase;
  color: var(--fr-accent, #5ED5FF); font-weight: 600;
}
.rv-h { margin: 0 0 10px; font-size: 24px; font-weight: 660; letter-spacing: -.025em; color: var(--fr-ink); }
.rv-count { margin: 0; font-size: 15px; color: var(--fr-mute); }
.rv-count .rv-n {
  color: var(--fr-ink); font-variant-numeric: tabular-nums; font-weight: 650;
}
.rv-arrow { margin: 0 6px; color: var(--fr-accent, #5ED5FF); }

.rv-steps { list-style: none; margin: 0; padding: 0; }
.rv-step {
  display: flex; gap: 13px; padding: 15px 0;
  border-top: 1px solid rgba(255,255,255,.07);
  opacity: 0; transform: translateY(9px);
  transition: opacity .42s ease, transform .42s ease;
}
.rv-step.is-in { opacity: 1; transform: none; }
.rv-ic {
  flex: 0 0 26px; width: 26px; height: 26px; border-radius: 999px;
  display: grid; place-items: center; font-size: 12px;
  background: rgba(255,255,255,.06); border: 1px solid rgba(255,255,255,.12);
  color: var(--fr-mute);
}
.rv-personal .rv-ic { background: rgba(94, 213, 255,.16); border-color: rgba(94, 213, 255,.45); color: #7DECFF; }
.rv-declined .rv-ic { background: rgba(255,196,84,.13); border-color: rgba(255,196,84,.36); color: #ffd79a; }
.rv-body { flex: 1 1 auto; min-width: 0; }

.rv-label {
  margin: 0 0 5px; font-size: 11px; letter-spacing: .12em; text-transform: uppercase;
  color: var(--fr-mute); font-weight: 600;
}
.rv-text {
  margin: 0 0 6px; font-size: 15px; line-height: 1.55; color: var(--fr-ink);
}
.rv-kept .rv-text { font-weight: 600; }
.rv-why { margin: 0; font-size: 13.5px; line-height: 1.5; color: var(--fr-mute); }

/* The receipt behind each claim. This is the difference between "we
   personalised your prompt" and something a person can check in one second. */
.rv-facts { list-style: none; margin: 9px 0 0; padding: 0; }
.rv-facts li {
  padding: 6px 10px; margin-bottom: 5px; border-radius: 8px; font-size: 13.5px;
  background: rgba(94, 213, 255,.07); border: 1px solid rgba(94, 213, 255,.2);
}
.rv-facts b { color: var(--fr-ink); }
.rv-from { color: var(--fr-mute); }

.rv-unsourced, .rv-about {
  margin: 8px 0 0; font-size: 12.5px; line-height: 1.5; color: var(--fr-mute); font-style: italic;
}

.rv-route, .rv-receipt {
  display: block; padding: 18px 0;
  border-top: 1px solid rgba(255,255,255,.07);
  opacity: 0; transform: translateY(9px);
  transition: opacity .42s ease, transform .42s ease;
}
.rv-route.is-in, .rv-receipt.is-in { opacity: 1; transform: none; }

.rv-cost {
  margin: 0 0 10px; font-size: 19px; font-weight: 650; letter-spacing: -.02em;
  color: #7ee7a8;
}
.rv-quality { margin: 0 0 5px; font-size: 15px; line-height: 1.55; color: var(--fr-ink); }
.rv-basis { margin: 0; font-size: 12.5px; color: var(--fr-mute); }

/* Not small print. The sentence that makes the number above it worth believing. */
.rv-disclosure {
  margin: 14px 0 0; padding: 11px 13px; border-radius: 10px;
  font-size: 13px; line-height: 1.55; color: var(--fr-mute);
  background: rgba(255,255,255,.04); border: 1px solid rgba(255,255,255,.1);
}

.rv-full { margin-top: 18px; }
.rv-full summary {
  cursor: pointer; font-size: 13.5px; color: var(--fr-accent, #5ED5FF); list-style: none;
}
.rv-full summary::-webkit-details-marker { display: none; }
.rv-full summary::before { content: '▸ '; }
.rv-full[open] summary::before { content: '▾ '; }
.rv-pre {
  margin: 12px 0 0; padding: 15px; border-radius: 12px; overflow-x: auto;
  white-space: pre-wrap; word-break: break-word;
  font-size: 12.5px; line-height: 1.6; color: var(--fr-mute);
  background: rgba(0,0,0,.25); border: 1px solid rgba(255,255,255,.09);
}

/* ══ SHARING ════════════════════════════════════════════════════════════════
   Offered only after the product has visibly done something. Asking a stranger
   to recommend a thing they have not used is asking them to lie. */
.fr-share {
  margin: 24px 0; padding: 20px; border-radius: 16px;
  background: linear-gradient(180deg, rgba(180,140,255,.1), rgba(180,140,255,.03));
  border: 1px solid rgba(180,140,255,.3);
}
.fr-share-h {
  margin: 0 0 9px; font-size: 18px; font-weight: 650; letter-spacing: -.02em; color: var(--fr-ink);
}
.fr-share > p { margin: 0 0 16px; font-size: 14.5px; line-height: 1.55; color: var(--fr-mute); }
.fr-share-cta .fr-skip { margin-top: 11px; }
/* What they have earned, which has no ceiling. There used to be five dots here,
   one per invitation, and that shape said "you get five" — the opposite of what
   is true. */
.fr-share-earned {
  margin: 0 0 12px; font-size: 15px; color: var(--fr-mute);
}
.fr-share-earned b {
  font-size: 26px; font-weight: 680; letter-spacing: -.02em; color: #7ee7a8;
  font-variant-numeric: tabular-nums;
}

@media (prefers-reduced-motion: reduce) {
  .rv-step, .rv-route, .rv-receipt { transition: none; opacity: 1; transform: none; }
}

/* ══ FORGET ═════════════════════════════════════════════════════════════════
   A product whose whole argument is that your data is yours has to be able to
   take it away as well as give it back. Quiet, at the bottom, and two clicks —
   not a dialog chain that makes leaving feel like an argument. */
.fr-forget { margin: 34px 0 8px; text-align: center; }
.fr-forget-go {
  background: none; border: 0; cursor: pointer; padding: 8px;
  font-size: 13px; color: var(--fr-mute); text-decoration: underline;
  text-underline-offset: 3px; opacity: .75;
}
.fr-forget-go:hover { opacity: 1; color: var(--fr-ink); }
.fr-forget.is-armed {
  text-align: left; padding: 20px; border-radius: 16px;
  background: rgba(255,107,107,.07); border: 1px solid rgba(255,107,107,.3);
}
.fr-forget-h {
  margin: 0 0 9px; font-size: 18px; font-weight: 650; letter-spacing: -.02em; color: var(--fr-ink);
}
.fr-forget-b { margin: 0 0 16px; font-size: 14px; line-height: 1.55; color: var(--fr-mute); }
.fr-forget-yes {
  display: block; width: 100%; padding: 14px 18px; border-radius: 12px; cursor: pointer;
  font-size: 15px; font-weight: 620; color: #fff;
  background: rgba(255,107,107,.85); border: 1px solid rgba(255,107,107,1);
}
.fr-forget-yes:hover { background: #ff6b6b; }
.fr-forget-cta .fr-skip { margin-top: 11px; }


/* ── the ask box (ask.js) ─────────────────────────────────────────────── */
.fr-askbox { margin: 28px 0 8px; padding: 18px; border-radius: var(--fr-radius);
  border: 1px solid var(--fr-line); background: rgba(255, 255, 255, .025); }
.fr-ask-in { display: block; width: 100%; box-sizing: border-box; resize: vertical; min-height: 84px;
  padding: 12px 14px; border-radius: 12px; border: 1px solid var(--fr-line);
  background: rgba(0, 0, 0, .28); color: var(--fr-ink); font: inherit; font-size: 15.5px; line-height: 1.45; }
.fr-ask-in:focus { outline: 2px solid var(--fr-cyan); outline-offset: 1px; border-color: transparent; }
.fr-ask-row { display: flex; align-items: center; justify-content: space-between; gap: 14px; margin-top: 10px; }
.fr-ask-hint { font-size: 12.5px; color: var(--fr-mute); line-height: 1.45; }
.fr-ask-go, .fr-ask-force, .fr-ask-copy {
  flex: 0 0 auto; cursor: pointer; padding: 10px 18px; border-radius: 12px; font: inherit; font-weight: 620;
  border: 1px solid rgba(94, 213, 255, .38); color: var(--fr-ink);
  background: linear-gradient(180deg, rgba(94, 213, 255, .16), rgba(94, 213, 255, .06));
}
.fr-ask-go[disabled] { opacity: .55; cursor: progress; }
.fr-ask-wait { font-size: 13.5px; color: var(--fr-mute); margin: 12px 0 0; }
.fr-ask-leaving { margin: 16px 0 0; padding: 12px 14px; border-radius: 12px;
  border: 1px dashed rgba(94, 213, 255, .35); background: rgba(94, 213, 255, .05); }
.fr-ask-leaving-h { margin: 0 0 6px; font-size: 11.5px; font-weight: 620; letter-spacing: .1em;
  text-transform: uppercase; color: var(--fr-cyan); }
.fr-ask-leaving-line { margin: 0; font-size: 14px; line-height: 1.5; color: var(--fr-ink); }
.fr-ask-leaving-why { margin: 6px 0 0; font-size: 12.5px; color: var(--fr-mute); }
.fr-ask-answer { margin-top: 18px; }
.fr-ask-from { font-weight: 400; letter-spacing: 0; text-transform: none; color: var(--fr-mute); }
.fr-ask-text { font-size: 15px; line-height: 1.6; color: var(--fr-ink); white-space: normal; }
.fr-ask-prompt { white-space: pre-wrap; font-size: 13px; line-height: 1.5; color: var(--fr-ink);
  padding: 12px 14px; border-radius: 12px; border: 1px solid var(--fr-line); background: rgba(0, 0, 0, .28); }
.fr-ask-credits { font-size: 12.5px; color: var(--fr-mute); margin: 12px 0 0; }
.fr-ask-verdict { display: flex; align-items: center; gap: 8px; margin-top: 12px; font-size: 13px; color: var(--fr-mute); }
.fr-ask-verdict button { cursor: pointer; padding: 6px 12px; border-radius: 10px; font: inherit; font-size: 13px;
  border: 1px solid var(--fr-line); background: rgba(255, 255, 255, .05); color: var(--fr-ink); }
.fr-ask-stop { margin-top: 14px; padding: 12px 14px; border-radius: 12px; border: 1px solid rgba(255, 138, 61, .4);
  background: rgba(255, 138, 61, .06); font-size: 14px; line-height: 1.5; }
.fr-ask-stop-h { margin: 0 0 6px; font-weight: 620; }
.fr-ask-stop ul { margin: 8px 0 0; padding-left: 18px; }
/* THE GATE IS NOT AN ERROR (Peter, 20 Aug).
 *
 * .fr-ask-stop is drawn in warning orange because it is usually the end of
 * something — a budget, a balance. This one is the beginning of something, and
 * nothing has gone wrong: no credit was withheld, because none exists yet. So
 * it takes the brand's own cyan and reads as an invitation. */
.fr-ask-gate { border-color: rgba(0, 209, 255, .34); background: rgba(0, 209, 255, .06); }
.fr-ask-connect {
  margin-top: 8px; cursor: pointer; font: inherit; font-size: 13.5px; font-weight: 600;
  padding: 9px 14px; border-radius: 10px; border: 1px solid rgba(0, 209, 255, .45);
  background: rgba(0, 209, 255, .10); color: var(--fr-ink);
}
/* The free ways out are controls, not sentences. A person who has just been
 * stopped should not have to go and find the tile themselves. */
.fr-ask-opts { margin: 8px 0 0; padding-left: 18px; }
.fr-ask-opt-free a { color: var(--fr-ink); text-decoration: none; }
.fr-ask-opt-free a:hover b { text-decoration: underline; }
.fr-ask-opt-go {
  display: inline-block; margin-left: 6px; font-size: 12px; font-weight: 620;
  color: var(--fr-cyan); white-space: nowrap;
}


/* ── the waiting tray (pendingState) ──────────────────────────────────── */
.fr-waiting { margin: 24px 0 8px; }
.fr-wait-row { margin-bottom: 10px; padding: 14px 16px; border-radius: var(--fr-radius);
  border: 1px solid var(--fr-line); background: rgba(255, 255, 255, .025); }
.fr-wait-due { border-color: rgba(94, 213, 255, .4); background: rgba(94, 213, 255, .06); }
.fr-wait-lost { border-color: rgba(255, 138, 61, .35); background: rgba(255, 138, 61, .05); }
.fr-wait-top { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; }
.fr-wait-label { font-size: 15.5px; font-weight: 620; letter-spacing: -.01em; }
.fr-wait-when { font-size: 12px; color: var(--fr-dim); white-space: nowrap; }
.fr-wait-line { margin: 6px 0 0; font-size: 13.5px; line-height: 1.5; color: var(--fr-mute); }
.fr-wait-cta { display: flex; align-items: center; gap: 14px; margin-top: 10px; flex-wrap: wrap; }
.fr-wait-drop { flex: 0 0 auto; cursor: pointer; padding: 8px 14px; border-radius: 11px;
  font-size: 13.5px; font-weight: 560; color: var(--fr-ink);
  border: 1px solid rgba(94, 213, 255, .38);
  background: linear-gradient(180deg, rgba(94, 213, 255, .16), rgba(94, 213, 255, .06)); }
.fr-wait-cta .fr-skip { margin: 0; }

.fr-share-caveat { margin: 8px 0 0; font-size: 12.5px; line-height: 1.5; color: var(--fr-ember); }


/* ── the History panel (history-ui.js) ────────────────────────────────────
 *
 * Sits directly under the ask box because that is where the thing it holds
 * comes from. Same card language as .fr-askbox and .fr-wait-row — a new
 * surface has to look like it was always part of the product, or it reads as
 * bolted on and people distrust it. No new colours: the folder chips borrow
 * the cyan the ask box already uses for "this is the live thing".
 */
.fr-hist { margin: 14px 0 8px; padding: 14px 16px; border-radius: var(--fr-radius);
  border: 1px solid var(--fr-line); background: rgba(255, 255, 255, .025); }
.fr-hist-top { display: flex; align-items: center; justify-content: space-between; gap: 10px; flex-wrap: wrap; }
.fr-hist-toggle { cursor: pointer; border: 0; background: none; padding: 0; font: inherit;
  font-size: 12px; letter-spacing: .06em; text-transform: uppercase; color: var(--fr-dim); }
.fr-hist-toggle b { color: var(--fr-ink); font-size: 12px; }
.fr-hist-caret { color: var(--fr-cyan); }
.fr-hist-tools { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.fr-hist-mini { cursor: pointer; padding: 5px 11px; border-radius: 10px; font: inherit; font-size: 12.5px;
  border: 1px solid var(--fr-line); background: rgba(255, 255, 255, .05); color: var(--fr-ink); }
.fr-hist-mini:hover { border-color: rgba(94, 213, 255, .38); }
.fr-hist-danger { border-color: rgba(255, 107, 107, .35); color: #ffb3b3; }
.fr-hist-body { margin-top: 12px; }
.fr-hist-q { display: block; width: 100%; box-sizing: border-box; padding: 9px 12px; border-radius: 11px;
  border: 1px solid var(--fr-line); background: rgba(0, 0, 0, .28); color: var(--fr-ink); font: inherit; font-size: 14px; }
.fr-hist-q:focus { outline: 2px solid var(--fr-cyan); outline-offset: 1px; border-color: transparent; }
.fr-hist-chips { display: flex; flex-wrap: wrap; gap: 6px; margin: 10px 0 4px; }
.fr-hist-chip { cursor: pointer; padding: 5px 10px; border-radius: 999px; font: inherit; font-size: 12.5px;
  border: 1px solid var(--fr-line); background: rgba(255, 255, 255, .04); color: var(--fr-mute); }
.fr-hist-chip i { font-style: normal; margin-left: 6px; color: var(--fr-dim); font-size: 11.5px; }
.fr-hist-chip.is-on { border-color: rgba(94, 213, 255, .45); color: var(--fr-ink);
  background: linear-gradient(180deg, rgba(94, 213, 255, .16), rgba(94, 213, 255, .05)); }
.fr-hist-group { margin: 14px 0 4px; font-size: 11.5px; letter-spacing: .08em; text-transform: uppercase; color: var(--fr-dim); }
/* PROJECT › THREAD. The two levels are told apart by weight and indent alone —
   no new colours, no boxes inside boxes. A folder heading is the .fr-hist-group
   that was already here; a thread is a quieter line one step in. Anything
   louder and the panel starts to look like a file manager, which is the thing
   people are trying to get away from. */
.fr-hist-proj { margin-top: 4px; }
.fr-hist-head { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; flex-wrap: wrap; }
.fr-hist-head .fr-hist-group { flex: 1 1 auto; min-width: 0; margin-bottom: 2px; }
.fr-hist-group i { font-style: normal; margin-left: 8px; color: var(--fr-dim); letter-spacing: 0; }
.fr-hist-headtools { display: flex; align-items: center; gap: 6px; flex: 0 0 auto; }
.fr-hist-thread { margin: 8px 0 0 2px; padding-left: 10px; font-size: 12.5px; color: var(--fr-mute);
  border-left: 2px solid var(--fr-line); }
.fr-hist-thread i { font-style: normal; margin-left: 8px; color: var(--fr-dim); font-size: 11.5px; }
.fr-hist-rename { flex: 1 1 auto; min-width: 0; padding: 5px 9px; border-radius: 10px; font: inherit; font-size: 13px;
  border: 1px solid var(--fr-line); background: rgba(0, 0, 0, .3); color: var(--fr-ink); }
.fr-hist-rename:focus { outline: 2px solid var(--fr-cyan); outline-offset: 1px; border-color: transparent; }
.fr-hist-threadin { padding: 5px 9px; border-radius: 10px; font: inherit; font-size: 12.5px; max-width: 200px;
  border: 1px solid var(--fr-line); background: rgba(0, 0, 0, .3); color: var(--fr-ink); }
/* Said once. It borrows the cyan the ask box uses for "this is the live thing"
   rather than the ember kept for warnings — nothing here has gone wrong. */
.fr-hist-auto { margin: 10px 0 0; font-size: 12.5px; line-height: 1.5; color: var(--fr-mute); }
.fr-hist-auto .fr-hist-mini { margin-left: 6px; border-color: rgba(94, 213, 255, .38); }
.fr-hist-in { flex: 0 0 auto; font-size: 11.5px; color: var(--fr-cyan); opacity: .8;
  max-width: 40%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.fr-hist-row { border-top: 1px solid var(--fr-line); }
.fr-hist-row:first-of-type { border-top: 0; }
.fr-hist-title { display: flex; align-items: baseline; gap: 8px; width: 100%; text-align: left; cursor: pointer;
  border: 0; background: none; font: inherit; font-size: 14px; color: var(--fr-ink); padding: 10px 0; }
.fr-hist-t { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.fr-hist-title time { flex: 0 0 auto; font-size: 11.5px; color: var(--fr-dim); }
/* The pin marker must NOT be the flexible child, or a pinned row pushes its
   own title into the middle of the panel and looks broken. */
.fr-hist-pin { flex: 0 0 auto; color: var(--fr-ember); font-size: 10px; }
.fr-hist-detail { padding: 2px 0 14px; }
.fr-hist-label { margin: 8px 0 4px; font-size: 11px; letter-spacing: .08em; text-transform: uppercase; color: var(--fr-dim); }
.fr-hist-label span { letter-spacing: 0; text-transform: none; color: var(--fr-mute); }
.fr-hist-prompt, .fr-hist-answer { font-size: 14px; line-height: 1.55; color: var(--fr-ink);
  padding: 10px 12px; border-radius: 11px; border: 1px solid var(--fr-line); background: rgba(0, 0, 0, .24);
  max-height: 260px; overflow: auto; white-space: pre-wrap; }
.fr-hist-answer { white-space: normal; }
.fr-hist-cta { display: flex; align-items: center; gap: 8px; margin-top: 10px; flex-wrap: wrap; }
.fr-hist-move { padding: 5px 9px; border-radius: 10px; font: inherit; font-size: 12.5px;
  border: 1px solid var(--fr-line); background: rgba(0, 0, 0, .3); color: var(--fr-ink); }
.fr-hist-suggest { margin: 4px 0 8px; font-size: 13px; color: var(--fr-mute); }
.fr-hist-suggest b { color: var(--fr-ink); }
.fr-hist-empty { margin: 14px 0 2px; font-size: 13.5px; color: var(--fr-mute); }
.fr-hist-warn { margin: 10px 0 0; font-size: 12.5px; line-height: 1.5; color: var(--fr-ember); }

/* ── the Organizer card (organizer.js + history-ui.js) ────────────────────
 *
 * It sits at the TOP of the history card, above the toggle, and it is the one
 * thing on this screen that speaks first. So it is drawn quieter than
 * everything around it, not louder: no fill, no border of its own, no colour
 * that is not already in use. The only accent is the thin cyan rule down the
 * left, which is the same "this is the live thing" cyan the ask box and the
 * folder chips already use — an Organizer that announced itself with a badge
 * or an ember warning would be the intrusive version of exactly this feature.
 *
 * The reason line is dim and one step in, because it is the small print of the
 * sentence above it and should read as the small print.
 */
.fr-org { margin: 0 0 12px; padding-left: 11px; border-left: 2px solid rgba(94, 213, 255, .38); }
.fr-org-h { margin: 0 0 6px; font-size: 11px; letter-spacing: .08em; text-transform: uppercase; color: var(--fr-dim); }
.fr-org-n { margin-top: 10px; }
.fr-org-n:first-of-type { margin-top: 0; }
.fr-org-say { margin: 0; font-size: 14px; line-height: 1.5; color: var(--fr-ink); }
.fr-org-cta { display: flex; align-items: center; gap: 6px; margin-top: 7px; flex-wrap: wrap; }
.fr-org-x { color: var(--fr-mute); }
/* "why?" is a link, not a button: it explains rather than does, and giving it
   the same weight as the action would make every nudge look like two choices. */
.fr-org-why { cursor: pointer; border: 0; background: none; padding: 4px 2px; font: inherit; font-size: 12.5px;
  color: var(--fr-dim); text-decoration: underline; text-underline-offset: 2px; }
.fr-org-why:hover { color: var(--fr-mute); }
.fr-org-because { margin: 6px 0 0; font-size: 12.5px; line-height: 1.5; color: var(--fr-mute); }
.fr-org-note { margin: 10px 0 0; font-size: 12.5px; color: var(--fr-green); }

/* Tier two. The list of titles is the consent, so it is legible rather than a
   folded-away detail — you cannot agree to a payload you have to expand. */
.fr-org-think { margin: 8px 0 4px; padding: 11px 12px; border-radius: 12px;
  border: 1px solid var(--fr-line); background: rgba(0, 0, 0, .24); }
.fr-org-th { margin: 0 0 6px; font-size: 13.5px; color: var(--fr-ink); }
.fr-org-th2 { margin: 0 0 6px; font-size: 11px; letter-spacing: .08em; text-transform: uppercase; color: var(--fr-dim); }
.fr-org-priv { margin: 0 0 8px; font-size: 12.5px; line-height: 1.5; color: var(--fr-mute); }
.fr-org-titles, .fr-org-out { margin: 0 0 10px; padding-left: 18px; font-size: 13px; line-height: 1.6; color: var(--fr-ink); }
.fr-org-titles li { color: var(--fr-mute); }
.fr-org-edit { display: block; width: 100%; box-sizing: border-box; padding: 10px 12px; border-radius: 11px;
  border: 1px solid var(--fr-line); background: rgba(0, 0, 0, .24); color: var(--fr-ink);
  font: inherit; font-size: 14px; line-height: 1.55; resize: vertical; }
.fr-org-edit:focus { outline: 2px solid var(--fr-cyan); outline-offset: 1px; border-color: transparent; }

/* ── the ladder, 19 Aug ────────────────────────────────────────────────────
 *
 * Three tiles, one disclosure, one pass. Everything here exists to keep the
 * first screen at three decisions: the primary, two alternates, and a way to
 * say "not these" that is not a refusal.
 */

/* A pass is not a decline, and must not look like a button you are supposed to
   avoid — it is the second way up the ladder. Quiet, centred, reachable. */
.fr-pass {
  display: block; margin: 12px auto 0; padding: 8px 14px;
  background: none; border: 0; cursor: pointer; font: inherit;
  font-size: 12.5px; color: var(--fr-dim); text-decoration: underline;
  text-underline-offset: 3px; text-decoration-color: rgba(255, 255, 255, .18);
}
.fr-pass:hover { color: var(--fr-mute); }

/* Everything else, behind one summary. A <details> rather than a list, because
   the point of the ladder is that the other twelve things are NOT on screen. */
.fr-more { margin-top: 22px; padding-top: 18px; border-top: 1px dashed var(--fr-line); }
.fr-more-h {
  font-size: 12px; font-weight: 600; letter-spacing: .06em; text-transform: uppercase;
  color: var(--fr-dim); cursor: pointer; list-style: none; margin-bottom: 10px;
}
.fr-more-h::-webkit-details-marker { display: none; }
.fr-more-h::after { content: ' ▾'; opacity: .6; }
.fr-more[open] .fr-more-h::after { content: ' ▴'; }
.fr-more .fr-chips { margin-top: 10px; }
.fr-more-note {
  font-size: 12px; color: var(--fr-dim); margin: 16px 0 0; line-height: 1.5;
}
/* "Coming" is not "locked". A padlock says you have not earned it; these are
   ones WE cannot read yet, and the chip should say that and nothing else. */
.fr-chip-soon { opacity: .62; }
.fr-chip-soon::before { content: '…'; font-size: 12px; opacity: .7; filter: none; }

/* Google's warning, worn by the quiet email line rather than by the primary. */
.fr-because-warn {
  color: var(--fr-ember); background: rgba(255, 138, 61, .1);
  border-color: rgba(255, 138, 61, .24);
}

/* The next ask, sitting under the proof that earns it. */
.fr-nextbest {
  margin: 10px 0 0; font-size: 13.5px; color: var(--fr-mute);
}

/* Google said no. An alert, not an error page: one line, two ways on. */
.fr-oautherr {
  margin: 16px 0 0; padding: 14px 15px; border-radius: 14px;
  border: 1px solid rgba(255, 138, 61, .3); background: rgba(255, 138, 61, .08);
}
.fr-oautherr-h { margin: 0; font-size: 14.5px; font-weight: 620; color: var(--fr-ink); }
.fr-oautherr-p { margin: 6px 0 0; font-size: 13px; color: var(--fr-mute); line-height: 1.55; }
.fr-oautherr-cta { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 12px; }
.fr-oautherr-cta .fr-skip { margin: 0; }
