/* ============================================================================
   AI-Generated Signal Detector — "Identify content made with <brand> AI"

   RESPONSIVE SYSTEM — four design bands, mobile-first (min-width only):

     Mobile    0–767px      base rules, no media query
     Tablet    768–1279px   @media (min-width: 768px)
     Desktop   1280–1727px  @media (min-width: 1280px)
     Wide      1728px+      @media (min-width: 1728px)

   A band change is a *composition* change (single vs. two-column foot, sheet vs.
   dialog, page gutters, fan geometry). Everything inside a band stays fluid:
   band tokens interpolate from this band's Figma value to the next band's start
   value, so 767→768, 1279→1280 and 1727→1728 have no size jump.

   The interpolation uses two 0px→1px "ramps" that act as unitless multipliers:
     --m-ramp  0 at ≤420 → 1 at 768   (mobile band)
     --t-ramp  0 at 768  → 1 at 1280  (tablet band)
   A value that goes A→B is then `calc(A + var(--m-ramp) * (B - A))`.

   ≤640px and ≤420px are component-level safety nets (long localized words,
   smallest phones) — NOT design modes.

   Figma references: Mobile 375 · Tablet 768 · Desktop 1440 · Wide 1920.
   ========================================================================== */

:root {
  /* ---- Palette / elevation ---- */
  --accent: #2b5db9;
  --ink: #000000;
  --ink-soft: #2b2c30;
  --muted: rgba(0, 0, 0, 0.6);
  --muted-2: rgba(0, 0, 0, 0.48);
  --line: rgba(0, 0, 0, 0.1);
  --line-soft: rgba(0, 0, 0, 0.06);
  --bg: #ffffff;
  --field: rgba(0, 0, 0, 0.05);
  --card: #ffffff;
  --green: #5ad795;
  --blue: #0075DC; /* Figma no-signal icon */
  --red: #ef4444;
  --red-soft: #fdecec;
  --shadow-sm: 0 1px 2px rgba(16, 18, 24, 0.06);
  --shadow-md: 0 6px 40px rgba(0, 0, 0, 0.05);
  --shadow-lg: 0 30px 70px -30px rgba(16, 18, 24, 0.35);
  --radius-card: 40px;
  --radius-panel: 36px;
  --radius-inner: 18px;
  --radius-pill: 40px;

  /* ---- Type ---- */
  --font: "TikTok Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
    Helvetica, Arial, sans-serif;
  /* Figma's "Display" / "Text" are one variable family at different optical
     sizes, so the split lives in font-variation-settings, not in the stack. */
  --font-display: var(--font);
  --font-text: var(--font);

  /* ---- Appear / entrance (staggered on html.is-ready) ---- */
  --ap-opacity: 0;
  --ap-scale: 1;
  --ap-blur: 4px;
  --ap-rotate: 0deg;
  --ap-skew-x: 0deg;
  --ap-skew-y: 0deg;
  --ap-x: 0px;
  --ap-y: 12px;
  --ap-dur: 600ms;
  --ap-ease: cubic-bezier(0.25, 0.1, 0.25, 1);
  --ap-step: 100ms;
  --ap-delay: 0ms;

  /* ======================================================================
     BAND TOKENS — Mobile (0–767). Values ramp to the tablet start value.
     ====================================================================== */
  --m-ramp: calc(clamp(0px, 100vw - 420px, 348px) / 348);

  /* Page shell */
  --page-maxw: 100%;
  --page-gutter: 16px;
  --nav-min-h: calc(64px + var(--m-ramp) * 16);
  --nav-pad-x: calc(16px + var(--m-ramp) * 32);
  --nav-title-size: calc(16px + var(--m-ramp) * 4);
  --nav-beta-size: calc(12px + var(--m-ramp) * 4);

  /* Hero */
  --hero-title-size: calc(40px + var(--m-ramp) * 8);
  --hero-title-pad-x: calc(32px + var(--m-ramp) * 16);
  --hero-title-pad-t: calc(40px + var(--m-ramp) * 56);
  --stage-maxw: 100%;
  --stage-pad-x: 12px;
  --stage-pad-t: calc(64px + var(--m-ramp) * 32);
  --fan-w: 200px; /* Figma card asset size in every band */
  --fan-stack-w: calc(120px + var(--m-ramp) * 80);
  --fan-overlap: calc(160px - var(--m-ramp) * 40);

  /* Card shell */
  --card-maxw: 672px;
  --card-min-h: calc(480px + var(--m-ramp) * 44);
  --card-min-h-idle: calc(602px + var(--m-ramp) * 21);
  --card-min-h-progress: calc(497px + var(--m-ramp) * 157);
  --card-min-h-result: calc(692px + var(--m-ramp) * 72);
  --card-pad: 8px; /* dual-shell: white outer ring around the panel */

  /* Idle (dashed) panel */
  --idle-pad-x: calc(16px + var(--m-ramp) * 8);
  --idle-pad-t: calc(64px + var(--m-ramp) * 32);
  --idle-pad-b: calc(64px + var(--m-ramp) * 16);
  --idle-gap: calc(40px + var(--m-ramp) * 24);
  --dz-gap: 40px;
  --content-col: 100%; /* dropzone / chip / result column */
  --legal-col: 100%;

  /* Non-idle (black) panel. --panel-padding-x is the single source of truth for
     the card-foot full-bleed margin — never hardcode negative margins. */
  --panel-padding-x: calc(6px + var(--m-ramp) * 15);
  --panel-padding-y: calc(64px + var(--m-ramp) * 32);
  --panel-border-w: 4px;

  /* Status block */
  --icon-size: calc(64px + var(--m-ramp) * 32);
  --icon-glyph: calc(32px + var(--m-ramp) * 16);
  --title-size: calc(32px + var(--m-ramp) * 8);
  --body-size: calc(14px + var(--m-ramp) * 2);
  --hint-size: calc(28px + var(--m-ramp) * 8);
  /* Same measure as the tablet band: below ~560 the panel is narrower anyway, so
     this only keeps the 767→768 line breaks identical. */
  --sub-max-w: 522px;

  /* File chip */
  --chip-thumb: calc(36px + var(--m-ramp) * 48);
  --chip-name: calc(14px + var(--m-ramp) * 8);
  --chip-sub: calc(12px + var(--m-ramp) * 4);
  --chip-gap: calc(8px + var(--m-ramp) * 16);
  --chip-pad-y: calc(16px + var(--m-ramp) * 4);
  --chip-pad-l: calc(12px + var(--m-ramp) * 8);
  --chip-pad-r: calc(12px + var(--m-ramp) * 20);
  --chip-radius: calc(12px + var(--m-ramp) * 4);
  --chip-min-h: calc(68px + var(--m-ramp) * 56);

  /* Buttons */
  --btn-font: calc(16px + var(--m-ramp) * 2);
  --btn-min-h: 52px;
  --cta-min-w: calc(136px + var(--m-ramp) * 60);
  --cancel-size: calc(16px + var(--m-ramp) * 6);
  --cancel-weight: 700;

  /* Feedback foot */
  --foot-gap: 24px;
  --foot-space: 64px; /* content → divider */
  --foot-pad-x: calc(6px + var(--m-ramp) * 26);
  --foot-label-size: calc(20px + var(--m-ramp) * 4);

  /* FAQ / footer */
  --faq-col: 100%;
  --faq-gutter: 16px;
  --faq-pad-t: 120px;
  --footer-pad-t: 64px;
  --footer-pad-b: 32px;
}

/* Self-hosted TikTok Sans (OFL, see static/fonts/OFL.txt). The family ships with
   us rather than from fonts.gstatic.com. The src is relative on purpose: it must
   resolve next to this sheet whether that is /static/ (local dev) or the CDN
   prefix (deployed), and _build_index_html rewrites it when the sheet is inlined.
   One variable file per subset carries wght 400–700 *and* the opsz axis, which
   is what `font-variation-settings: "opsz" …` needs — the old static instances
   silently ignored it. Figma's two names (Display / Text) are the same family at
   different opsz, so both tokens point here. */
@font-face {
  font-family: "TikTok Sans";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url(fonts/tiktok-sans-latin.woff2) format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "TikTok Sans";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url(fonts/tiktok-sans-latin-ext.woff2) format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* ---- Reset / document ----------------------------------------------------- */
* { box-sizing: border-box; }

/* The `hidden` attribute must always win, even over author rules that set a
   `display` (e.g. .modal-overlay{display:flex}, .detail-toggle{display:inline-flex}).
   Without this, JS toggling `.hidden` can't actually hide those elements. */
[hidden] { display: none !important; }

html, body {
  margin: 0;
  padding: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font-text);
  font-variation-settings: "opsz" 14;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

body {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  /* No overflow-x:hidden here — only .content clips (the fan-art bleed band),
     so real overflow bugs elsewhere stay visible. */
}

/* Boot gate: hide the page until fonts + config settle, then fade in once.
   Avoids fonts/images/config each painting a different partial first frame.
   The delayed animation is the failsafe: app.js normally adds .is-ready, but it
   ships from the CDN, so if that request never runs (blocked, offline, JS off)
   the page must still reveal itself instead of staying invisible forever. */
html:not(.is-ready) body {
  opacity: 0;
  animation: boot-failsafe 0s 2.5s forwards;
}
@keyframes boot-failsafe { to { opacity: 1; } }
html.is-ready body {
  opacity: 1;
  transition: opacity .15s ease;
}

/* ---- Appear entrance ------------------------------------------------------ */
.ap {
  opacity: var(--ap-opacity);
  filter: blur(var(--ap-blur));
  transform:
    translate(var(--ap-x), var(--ap-y))
    scale(var(--ap-scale))
    rotate(var(--ap-rotate))
    skew(var(--ap-skew-x), var(--ap-skew-y));
  transition:
    opacity var(--ap-dur) var(--ap-ease) var(--ap-delay),
    filter var(--ap-dur) var(--ap-ease) var(--ap-delay),
    transform var(--ap-dur) var(--ap-ease) var(--ap-delay);
  will-change: opacity, filter, transform;
}
html.is-ready .ap,
.ap.in {
  opacity: 1;
  /* `blur(0)` still installs a filter containing block on Safari and has been
     observed to blank child <img> paints (esp. blob: thumbs inside .card). */
  filter: none;
  transform: none;
  will-change: auto;
}
/* Stagger order: title → card → fans → FAQ → footer */
.ap-d0 { --ap-delay: 0ms; }
.ap-d1 { --ap-delay: calc(var(--ap-step) * 1); }
.ap-d2 { --ap-delay: calc(var(--ap-step) * 2); }
.ap-d3 { --ap-delay: calc(var(--ap-step) * 3); }
.ap-d4 { --ap-delay: calc(var(--ap-step) * 4); }
.ap-d5 { --ap-delay: calc(var(--ap-step) * 5); }

a { color: inherit; }
.link { color: var(--ink); font-weight: 700; text-decoration: none; }
.link:hover { color: var(--accent); text-decoration: underline; text-underline-offset: 2px; }

/* ---- Responsive copy toggles (flip at the mobile → tablet band edge) ------ */
/* show-lg / show-sm                — long vs. short FAQ heading
   show-gt-mobile / show-mobile-only — "Upload file" vs. "Choose file" etc. */
.show-lg,
.show-gt-mobile { display: none; }
.show-sm,
.show-mobile-only { display: inline; }
div.show-mobile-only,
.dz-title-mobile { display: block; }
.dz-title-line { display: block; }

/* ---- Site nav (Figma Navigation/Global — all bands) ----------------------- */
.site-nav {
  display: flex;
  flex-direction: row;
  align-items: center;
  padding: 16px var(--nav-pad-x);
  gap: 8px;
  width: 100%;
  min-height: var(--nav-min-h);
  background: #fff;
  flex: none;
}
.site-nav-label {
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: flex-start;
  flex-wrap: wrap;
  gap: 8px;
  padding: 0 0 4px;
  min-width: 0;
}
.site-nav-title {
  font-family: var(--font);
  font-weight: 700;
  font-size: var(--nav-title-size);
  line-height: 1.5;
  letter-spacing: -0.02em;
  color: #000;
  overflow-wrap: break-word;
}
.site-nav-beta {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 4px 12px;
  min-height: 28px;
  background: rgba(0, 0, 0, 0.05);
  border-radius: 9999px;
  font-family: var(--font-text);
  font-weight: 700;
  font-size: var(--nav-beta-size);
  line-height: 1.5;
  color: rgba(0, 0, 0, 0.48);
  flex: none;
}

/* ---- Page layout ---------------------------------------------------------- */
/* Full-width clip band. The rotated fan art bleeds outside the 1440 stage by
   design, so the only edge allowed to cut it is the window edge — hence the clip
   lives here (as wide as the page) and not on .hero-stage, and not on <body>.
   The Figma frame measure moves to the children that need it (title / footer). */
.content {
  flex: 1;
  width: 100%;
  margin: 0 auto;
  min-width: 0;
  padding: 0; /* top spacing lives on .hero-title (Figma Tab Header) */
  overflow-x: clip;
  overflow-y: visible;
}

.hero { position: relative; }

.hero-title {
  position: relative;
  z-index: 5; /* above .hero-stage / .card so the brand tooltip isn't covered */
  text-align: center;
  font-family: var(--font-display);
  font-size: var(--hero-title-size);
  line-height: 1.05;
  font-weight: 700;
  letter-spacing: -0.02em;
  font-variation-settings: "opsz" 36;
  margin: 0 auto;
  max-width: var(--page-maxw); /* .content is full-bleed, so keep the title measure here */
  padding: var(--hero-title-pad-t) var(--hero-title-pad-x) 0;
  overflow-wrap: break-word;
}
.hero-title-line { display: block; }
.hero-brand-hotspot {
  position: relative;
  display: block;
  /* Full title width so the tip's left:50% stays put while the typed length changes. */
  width: 100%;
  max-width: 100%;
  margin: 0 auto;
  cursor: pointer;
  outline: none;
}
.hero-brand-hotspot.is-static { cursor: default; }
.hero-brand-hotspot.is-static:hover .hero-brand-tip,
.hero-brand-tip[hidden] { display: none !important; }
.hero-title-accent {
  display: block;
  text-align: center;
  color: var(--muted-2);
  min-height: 1.05em; /* keep layout steady while typing / deleting */
  min-width: 5ch;
}
/* Blinking caret while the brand typewriter runs (see startHeroCarousel). */
.hero-title-accent.is-typing::after {
  content: "";
  display: inline-block;
  width: 0.06em;
  height: 0.85em;
  margin-left: 0.06em;
  background: currentColor;
  vertical-align: -0.05em;
  animation: heroCaret 1.06s step-end infinite;
}
@keyframes heroCaret { 50% { opacity: 0; } }
.hero-brand-tip {
  position: absolute;
  left: 50%;
  top: calc(100% + 10px);
  transform: translateX(-50%) translateY(4px);
  z-index: 30;
  padding: 10px 14px;
  border-radius: 8px;
  background: #2b2c30;
  color: #fff;
  font-size: 13px;
  font-weight: 500;
  line-height: 1.35;
  letter-spacing: 0;
  max-width: min(420px, 92vw);
  white-space: normal;
  text-align: center;
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: opacity .15s ease, transform .15s ease, visibility .15s;
}
.hero-brand-tip::before {
  content: "";
  position: absolute;
  left: 50%;
  bottom: 100%;
  transform: translateX(-50%);
  border: 6px solid transparent;
  border-bottom-color: #2b2c30;
}
.hero-brand-hotspot:hover .hero-brand-tip {
  opacity: 1;
  visibility: visible;
  transform: translateX(-50%) translateY(0);
}

/* ---- Upload stage + design fan art ---------------------------------------- */
/* Cards are --fan-w × 4/3 at ±15°. Row spacing uses the *rotated* AABB
   (~309.34 at 200px), not the unrotated height — Figma rows are 309.34. */
.hero-stage {
  position: relative;
  z-index: 1; /* below .hero-title (tooltip) */
  isolation: isolate; /* keep fan z-index:-1 behind the card, not the page */
  width: 100%;
  max-width: var(--stage-maxw);
  margin: 0 auto;
  display: flex;
  justify-content: center;
  align-items: center;
  padding: var(--stage-pad-t) var(--stage-pad-x) 0;
  min-height: calc(var(--stage-pad-t) + var(--card-min-h-idle));
  height: auto; /* grow with the upload/result shells; fans stay top:0 */
  /* The ±15° fan cards pinned to the stack edges stick ~31px outside this box.
     That bleed is part of the art, so it must stay visible; .content clips it at
     the window edge instead. */
  overflow: visible;
}

.fan-stack {
  position: absolute;
  /* Figma pins the fan frame to top:0 — do NOT vertical-center, or it drifts
     when the card grows (uploading / result are taller than idle). */
  top: 0;
  width: var(--fan-stack-w);
  height: calc(3 * var(--fan-frame-h) - 2 * var(--fan-overlap));
  z-index: -1; /* always behind the upload/drag panel */
  pointer-events: none;
  user-select: none;
  --fan-img-h: calc(var(--fan-w) * 4 / 3);
  --fan-frame-h: calc(var(--fan-w) * sin(15deg) + var(--fan-img-h) * cos(15deg));
  --fan-step: calc(var(--fan-frame-h) - var(--fan-overlap));
  --fan-img-inset: calc((var(--fan-frame-h) - var(--fan-img-h)) / 2);
}
/* Figma space-between: the stacks pin to the stage's left / right edges. */
.fan-stack-left { left: 0; }
.fan-stack-right { right: 0; left: auto; }

.fan-card {
  position: absolute;
  width: var(--fan-w);
  height: var(--fan-img-h);
  aspect-ratio: 3 / 4;
  object-fit: cover;
  border-radius: 8px;
  box-shadow: none; /* Figma fan cards have no drop shadow */
  -webkit-user-drag: none;
  transform-origin: center center;
}
/* Left: -15° / 15° / -15°; right: 15° / -15° / 15°. `top` is the unrotated box;
   --fan-img-inset centers it inside the Figma row frame. */
.fan-stack-left .fan-card-a {
  top: var(--fan-img-inset); right: 20px;
  transform: rotate(-15deg);
}
.fan-stack-left .fan-card-b {
  top: calc(var(--fan-step) + var(--fan-img-inset)); left: 0;
  transform: rotate(15deg);
}
.fan-stack-left .fan-card-c {
  top: calc(2 * var(--fan-step) + var(--fan-img-inset)); right: 10px;
  transform: rotate(-15deg);
}
.fan-stack-right .fan-card-d {
  top: var(--fan-img-inset); left: 0;
  transform: rotate(15deg);
}
.fan-stack-right .fan-card-e {
  top: calc(var(--fan-step) + var(--fan-img-inset)); right: 0;
  transform: rotate(-15deg);
}
.fan-stack-right .fan-card-f {
  top: calc(2 * var(--fan-step) + var(--fan-img-inset)); left: 10px;
  transform: rotate(15deg);
}

/* ---- Card (morphing state container) -------------------------------------- */
/* Dual shell: white outer card (r40) + 8px ring + inner panel (r36). The panel
   is dashed while idle and solid black once a file is in flight. */
.card {
  position: relative;
  z-index: 1;
  width: 100%;
  max-width: var(--card-maxw);
  margin: 0 auto;
  min-width: 0;
  background-color: var(--card);
  border: 0;
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-md);
  padding: var(--card-pad);
  display: flex;
  flex-direction: column;
  justify-content: center;
  transition: border-color .15s, background-color .15s, box-shadow .15s;
  isolation: isolate;
  min-height: var(--card-min-h);
}

.state {
  position: relative;
  z-index: 1;
  border-radius: var(--radius-panel);
  text-align: center;
  width: 100%;
  min-width: 0;
}
.state-idle {
  display: flex;
  flex-direction: column;
  justify-content: center; /* Figma Panel: center content in the dashed area */
  align-items: center;
  flex: 1;
}
.state-progress,
.state-result {
  display: flex;
  flex-direction: column;
  align-items: center;
  flex: 1;
  width: 100%;
}
.state-progress { justify-content: center; }
/* Result flows from the top so the feedback foot can hug the panel bottom;
   error has no foot, so it stays optically centered. */
.state-result { justify-content: flex-start; }
.state-error { justify-content: center; }

/* Idle: dashed inner panel via ::after; the outer shell stays white r40. */
.card.is-idle {
  height: auto;
  min-height: var(--card-min-h-idle);
  max-height: none;
  border: 0;
  background-color: #fff;
  background-image: none;
}
.card.is-idle::after {
  content: "";
  position: absolute;
  inset: var(--card-pad);
  border-radius: var(--radius-panel);
  pointer-events: none;
  z-index: 0;
  /* Figma: 1px dashed rgba(0,0,0,0.48). `background-size: auto` lets the SVG take
     the element's exact box (no non-uniform stretch, which is what made the
     dashes look uneven on high-DPI phones).
     The rect is inset 1.5px so the whole 1px stroke sits a full pixel inside the
     SVG viewport. Centring it on the box edge (0.5px) puts the outer half of the
     bottom stroke outside the viewport, where it rasterises away completely once
     the panel is wider than ~600px on a 2x screen -- the bottom dashes vanish and
     only the corner arcs survive. A 1px inset saves the stroke from vanishing but
     still loses half of it at the bottom, so that edge renders half as thick and
     visibly paler than the other three. The 1px of slack is imperceptible. */
  background-image: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20width='100%25'%20height='100%25'%3E%3Crect%20x='1.5'%20y='1.5'%20width='calc(100%25%20-%203px)'%20height='calc(100%25%20-%203px)'%20rx='36'%20ry='36'%20fill='none'%20stroke='%23000000'%20stroke-opacity='0.48'%20stroke-width='1'%20stroke-dasharray='6%2c6'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-size: auto;
  transform: none;
}
.card.is-idle .state-idle {
  height: auto;
  min-height: calc(var(--card-min-h-idle) - 2 * var(--card-pad));
  padding: var(--idle-pad-t) var(--idle-pad-x) var(--idle-pad-b);
  gap: var(--idle-gap); /* upload block → legal notice */
}
.card.is-idle .dropzone { max-width: var(--content-col); }
.card.is-idle:has(.dropzone:hover) { background-color: #fafafa; }
.card.is-idle:has(.dropzone:focus-visible) {
  box-shadow:
    0 0 0 4px color-mix(in srgb, var(--accent) 16%, transparent),
    var(--shadow-md);
}

/* Drag-over (Figma Drag): panel fills rgba(0,0,0,0.05) + lighter dash, and the
   idle content swaps for the centered "Drag and drop…" hint. */
.card.is-idle.is-dragging { z-index: 2; }
.card.is-idle.is-dragging::after {
  background-color: rgba(0, 0, 0, 0.05);
  /* Same 1.5px inset as the idle rect above, for the same reason. */
  background-image: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20width='100%25'%20height='100%25'%3E%3Crect%20x='1.5'%20y='1.5'%20width='calc(100%25%20-%203px)'%20height='calc(100%25%20-%203px)'%20rx='36'%20ry='36'%20fill='none'%20stroke='%23000000'%20stroke-opacity='0.2'%20stroke-width='1'%20stroke-dasharray='6%2c6'/%3E%3C/svg%3E");
}
.card.is-dragging .dropzone { transform: none; }
.card.is-dragging .dz-icon,
.card.is-dragging .dz-title,
.card.is-dragging .dz-help,
.card.is-dragging #uploadBtn,
.card.is-dragging .dz-legal {
  opacity: 0;
  pointer-events: none;
}
.card.is-dragging .dz-drop-hint { opacity: 1; }

/* Non-idle: solid black panel inside the same white shell. */
.card:not(.is-idle) {
  height: auto;
  max-height: none;
  min-height: var(--card-min-h);
  border: 0;
  background: #fff;
}
.card:not(.is-idle) > .state {
  padding: var(--panel-padding-y) var(--panel-padding-x);
}
.card:has(#stateUploading:not([hidden])),
.card:has(#stateVerifying:not([hidden])) { min-height: var(--card-min-h-progress); }
.card:has(#stateResult.is-detected:not([hidden])),
.card:has(#stateResult.is-none:not([hidden])) { min-height: var(--card-min-h-result); }

.card > .state-uploading,
.card > .state-verifying,
.card:has(#stateResult.is-detected:not([hidden])) > .state-result,
.card:has(#stateResult.is-none:not([hidden])) > .state-result {
  border: var(--panel-border-w) solid #000;
  background: #fff;
  box-sizing: border-box;
}
.card > .state-uploading,
.card > .state-verifying { min-height: calc(var(--card-min-h-progress) - 2 * var(--card-pad)); }
.card:has(#stateResult.is-detected:not([hidden])) > .state-result,
.card:has(#stateResult.is-none:not([hidden])) > .state-result {
  min-height: calc(var(--card-min-h-result) - 2 * var(--card-pad));
  /* The feedback foot supplies the bottom inset (it bleeds to the panel edge). */
  padding-bottom: 0;
}

/* ---- Dropzone ------------------------------------------------------------- */
.dropzone {
  position: relative;
  border: 0;
  border-radius: var(--radius-inner);
  padding: 0;
  cursor: pointer;
  transition: transform .15s;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--dz-gap);
  width: 100%;
  min-width: 0;
  margin: 0 auto;
  flex: 1;
}
.dropzone:focus-visible { outline: none; }
.dz-icon {
  width: var(--icon-size);
  height: var(--icon-size);
  border-radius: 50%;
  flex: none;
  display: inline-grid;
  place-items: center;
  background: var(--field);
  color: var(--ink);
  overflow: clip;
  transition: opacity .2s ease;
}
.dz-icon img {
  width: var(--icon-glyph);
  height: var(--icon-glyph);
  object-fit: contain;
  display: block;
}
.dz-title {
  font-family: var(--font-display);
  font-size: var(--title-size);
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1.05;
  font-variation-settings: "opsz" 36;
  margin: 0;
  max-width: 100%;
  /* Localized headings must wrap rather than widen the panel. */
  white-space: normal;
  overflow-wrap: break-word;
  transition: opacity .2s ease;
}
.dz-help {
  font-family: var(--font-text);
  color: var(--muted);
  font-size: var(--body-size);
  margin: 0 auto;
  max-width: 100%;
  line-height: 1.5;
  font-variation-settings: "opsz" 14;
  overflow-wrap: break-word;
  transition: opacity .2s ease;
}
/* Outside .dropzone so Terms / Privacy don't open the file picker. */
.dz-legal {
  font-family: var(--font-text);
  font-size: var(--body-size);
  font-weight: 400;
  line-height: 1.5;
  color: rgba(0, 0, 0, 0.6);
  text-align: center;
  max-width: var(--legal-col);
  width: 100%;
  margin: 0 auto;
  padding: 0;
  font-variation-settings: "opsz" 14;
  overflow-wrap: break-word;
  transition: opacity .2s ease;
}
.dz-legal-link {
  display: inline;
  margin: 0;
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  font-weight: 700;
  color: #000;
  text-decoration: underline;
  text-underline-offset: 2px;
  cursor: pointer;
}
.dz-legal-link:hover { opacity: 0.72; }
/* Sibling of dropzone/legal — centers in the whole dashed panel. */
.dz-drop-hint {
  position: absolute;
  inset: 0 var(--idle-pad-x);
  display: grid;
  place-items: center;
  margin: 0;
  font-family: var(--font-display);
  font-size: var(--hint-size);
  font-weight: 400;
  letter-spacing: 0;
  line-height: 1.05;
  font-variation-settings: "opsz" 36;
  color: rgba(0, 0, 0, 0.48);
  text-align: center;
  opacity: 0;
  pointer-events: none;
  transition: opacity .2s ease;
  z-index: 2;
}

/* ---- Buttons -------------------------------------------------------------- */
/* min-height (not height) + max-width:100% so longer localized labels can wrap
   inside the pill instead of overflowing the panel. */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  border: 0;
  cursor: pointer;
  font-family: var(--font-text);
  font-weight: 700;
  font-size: var(--btn-font);
  padding: 14px 24px;
  border-radius: var(--radius-pill);
  min-height: var(--btn-min-h);
  max-width: 100%;
  white-space: normal;
  overflow-wrap: break-word;
  font-variation-settings: "opsz" 14;
  transition: transform .12s, background .15s, opacity .2s ease;
}
.btn:active { transform: translateY(1px); }
.btn-primary {
  background: var(--ink);
  color: #fff;
  min-width: min(var(--cta-min-w), 100%);
}
.btn-primary:hover { background: #26272b; }
.btn-primary:disabled { background: #c9ccd1; cursor: not-allowed; }
.btn-ghost { background: var(--field); color: var(--ink); font-size: 14.5px; min-height: 0; }
.btn-ghost:hover { background: #eceef0; }
.card.is-idle .btn-primary { border: 1px solid #000; }
.link-btn {
  background: none;
  border: 0;
  cursor: pointer;
  font-family: inherit;
  font-size: 16px;
  font-weight: 400;
  color: var(--ink);
  max-width: 100%;
  text-decoration: underline;
  text-underline-offset: 3px;
  overflow-wrap: break-word;
}
.link-btn:hover { color: var(--ink); opacity: 0.72; }

/* ---- Status blocks (uploading / verifying / result / error) ---------------- */
.status-icon {
  width: var(--icon-size);
  height: var(--icon-size);
  border-radius: 50%;
  flex: none;
  display: inline-grid;
  place-items: center;
  margin: 0 auto 40px;
  background: var(--field);
  color: var(--ink);
}
.status-icon svg,
.status-icon img {
  width: var(--icon-glyph);
  height: var(--icon-glyph);
}
.status-icon-bare { width: auto; height: auto; background: none; margin-bottom: 24px; }
.status-icon-bare svg { width: auto; height: auto; }
.status-icon.success { background: #0BE09B; color: #fff; }
.status-icon.none { background: var(--blue); color: #E7F4FF; }
.status-icon.error { background: var(--red-soft); color: var(--red); }
.state-progress .status-icon { background: rgba(0, 0, 0, 0.05); color: #000; }
.state-progress .status-icon .spinner-lg {
  width: calc(var(--icon-glyph) * 5 / 6);
  height: calc(var(--icon-glyph) * 5 / 6);
  border-width: 2.5px;
  border-color: #e3e5e9;
  border-top-color: #000;
}
.status-title {
  font-family: var(--font-display);
  font-size: var(--title-size);
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1.05;
  font-variation-settings: "opsz" 36;
  margin: 0;
  max-width: 100%;
  white-space: normal;
  overflow-wrap: break-word;
}
.status-sub {
  font-family: var(--font-text);
  color: var(--muted);
  font-size: var(--body-size);
  margin: 24px auto 0;
  max-width: var(--sub-max-w);
  line-height: 1.5;
  font-variation-settings: "opsz" 14;
  overflow-wrap: break-word;
}
.status-sub .sys { color: var(--ink); font-weight: 700; }

/* Wraps icon → Cancel in the progress states. */
.progress-body {
  display: flex;
  flex-direction: column;
  align-items: center;
  align-self: stretch;
  width: 100%;
  min-width: 0;
}

/* ---- File chip ------------------------------------------------------------ */
/* One definition for every state; only the band tokens change. height is never
   fixed — min-height plus min-width:0 children keeps the size text readable. */
.file-row {
  display: flex;
  align-items: center;
  gap: var(--chip-gap);
  background: #fff;
  border: 1px solid var(--line);
  border-radius: var(--chip-radius);
  padding: var(--chip-pad-y) var(--chip-pad-r) var(--chip-pad-y) var(--chip-pad-l);
  margin: 40px auto 0;
  text-align: left;
  width: 100%;
  max-width: var(--content-col);
  min-width: 0;
  height: auto;
  min-height: var(--chip-min-h);
  overflow: visible; /* never clip .file-sub */
}
.result-file {
  width: 100%;
  max-width: var(--content-col);
  margin-top: 40px;
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
}
.result-file .file-row { margin-top: 0; }
.file-thumb {
  width: var(--chip-thumb);
  height: var(--chip-thumb);
  border-radius: 8px;
  flex: none;
  display: grid;
  place-items: center;
  overflow: hidden;
  background: rgba(0, 0, 0, 0.05);
  color: var(--muted);
}
.file-thumb img, .file-thumb video { width: 100%; height: 100%; object-fit: cover; }
.file-meta {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: stretch;
  gap: 4px;
  min-width: 0;
  flex: 1;
  height: auto;
  max-height: none;
  overflow: visible; /* the ellipsis lives on .file-name only */
}
.file-name {
  display: block;
  min-width: 0;
  max-width: 100%;
  font-family: var(--font);
  font-weight: 500;
  font-size: var(--chip-name);
  line-height: 1.25;
  color: #000;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.file-sub {
  font-family: var(--font);
  font-weight: 400;
  font-size: var(--chip-sub);
  line-height: 1.25;
  color: rgba(0, 0, 0, 0.4);
  margin-top: 0;
  overflow: visible;
}
.mini-spinner { width: 20px; height: 20px; flex: none; }
.state-progress .file-thumb .mini-spinner {
  width: calc(var(--chip-thumb) * 5 / 18);
  height: calc(var(--chip-thumb) * 5 / 18);
  border-width: 1.5px;
}

/* ---- Spinners ------------------------------------------------------------- */
.spinner, .mini-spinner {
  display: inline-block;
  border-radius: 50%;
  border: 2.4px solid #e3e5e9;
  border-top-color: var(--ink);
  animation: spin .8s linear infinite;
}
.spinner { width: 22px; height: 22px; }
.spinner-lg { width: 40px; height: 40px; border-width: 3px; }
@keyframes spin { to { transform: rotate(360deg); } }

/* ---- Result detail -------------------------------------------------------- */
/* Phase 1: "View details" is not shipping — keep the markup for later. */
#detailToggle,
#detailList { display: none !important; }
.detail-toggle {
  background: none; border: 0; cursor: pointer; font-family: inherit; flex: none;
  display: inline-flex; align-items: center; gap: 4px; color: var(--muted);
  font-size: 13px; font-weight: 600;
}
.detail-toggle:hover { color: var(--ink); }
.detail-toggle .chev { transition: transform .2s; width: 16px; height: 16px; }
.detail-toggle.open .chev { transform: rotate(180deg); }
.detail-list {
  text-align: left; margin-top: 10px; border: 1px solid var(--line);
  border-radius: 14px; padding: 6px 14px;
}
.detail-item { display: flex; gap: 10px; padding: 12px 0; border-top: 1px solid var(--line-soft); }
.detail-item:first-child { border-top: 0; }
.detail-check { flex: none; color: var(--green); margin-top: 1px; }
.detail-text { font-size: 13px; }
.detail-text b { font-weight: 700; }
.detail-text span { display: block; color: var(--muted); margin-top: 2px; font-size: 12.5px; line-height: 1.5; }

/* ---- Result CTA + cancel -------------------------------------------------- */
.upload-another {
  margin-top: 40px;
  width: auto;
  min-width: min(198px, 100%);
  font-size: 16px;
  font-weight: 700;
  border: 1px solid rgba(0, 0, 0, 0.1);
}
/* Minimum gap to the feedback divider; the foot's auto top margin eats the rest. */
.state-result:not(.state-error) .upload-another { margin-bottom: var(--foot-space); }
.cancel-btn {
  display: inline-block;
  margin-top: 40px;
  padding: 1px 0;
  font-family: var(--font-text);
  font-weight: var(--cancel-weight);
  font-size: var(--cancel-size);
  line-height: 1.5;
  text-decoration: underline;
  text-underline-offset: 3px;
  color: #000;
  background: none;
  border: 0;
}
.cancel-btn:hover { opacity: 0.72; color: #000; }

/* ---- Feedback foot -------------------------------------------------------- */
/* Full-bleed divider: the negative margin is always --panel-padding-x, so the
   foot can never overhang the panel in any band. margin-top:auto pins it to the
   panel bottom when the result content is shorter than the shell min-height. */
.card-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: var(--foot-gap);
  margin: auto calc(-1 * var(--panel-padding-x)) 0;
  padding: 24px var(--foot-pad-x) 32px;
  border-top: 1px solid var(--line);
  align-self: stretch;
  width: auto;
  max-width: none;
  min-width: 0;
}
.card-foot-ask {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: var(--foot-gap);
  flex: 1;
  width: 100%;
  min-width: 0;
}
/* Stacked when the label + button no longer fit one row (syncCardFootAskLayout). */
.card-foot.is-stacked,
.card-foot-ask.is-stacked {
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
}
.card-foot.is-stacked .card-foot-label,
.card-foot.is-stacked .card-foot-thanks,
.card-foot-ask.is-stacked .card-foot-label { text-align: center; }
.card-foot-ask.is-stacked .share-feedback { justify-content: center; }
/* Thanks keeps the Ask label's start edge side-by-side; centers only if stacked. */
.card-foot:not(.is-stacked) .card-foot-thanks {
  text-align: left;
  align-self: flex-start;
  margin-inline-end: auto;
}
.card-foot.is-stacked .card-foot-thanks {
  text-align: center;
  align-self: center;
  margin-inline-end: 0;
}
.card-foot-label,
.card-foot-thanks {
  font-family: var(--font-display);
  font-size: var(--foot-label-size);
  font-weight: 700;
  letter-spacing: -0.01em;
  line-height: 1.2;
  color: #000;
  min-width: 0;
  overflow-wrap: break-word;
}
.share-feedback {
  width: auto;
  min-width: min(178px, 100%);
  max-width: 100%;
  min-height: 44px;
  padding: 12px 16px;
  gap: 4px;
  border-radius: 8px;
  background: rgba(0, 0, 0, 0.05);
  font-family: var(--font-text);
  font-size: 16px;
  font-weight: 700;
  line-height: 1.43;
  justify-content: center;
  flex-shrink: 0;
}
.share-feedback svg,
.share-feedback img {
  width: 20px;
  height: 20px;
  flex-shrink: 0;
  display: block;
}

/* ---- FAQ ------------------------------------------------------------------ */
.faq {
  position: relative;
  z-index: 0; /* stay under the card shadow */
  max-width: var(--faq-col);
  width: 100%;
  margin: 0 auto;
  padding: var(--faq-pad-t) var(--faq-gutter) 0;
}
.faq-heading {
  font-family: var(--font-display);
  font-size: 24px;
  font-weight: 700;
  letter-spacing: -0.01em;
  line-height: 1.2;
  font-variation-settings: "opsz" 24;
  margin: 0 0 32px;
  text-align: center;
  overflow-wrap: break-word;
}
.faq-item {
  border: 1px solid var(--line);
  border-radius: 8px;
  overflow: hidden;
  background: #fff;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  /* Keep L/R pad fixed so the answer width (and line breaks) never reflow mid-animation. */
  padding: 0 24px;
  transition:
    padding-top .4s cubic-bezier(0.25, 0.1, 0.25, 1),
    padding-bottom .4s cubic-bezier(0.25, 0.1, 0.25, 1),
    border-color .15s ease;
}
.faq-item + .faq-item { margin-top: 16px; }
/* Figma Accordion/Content (open): pad 24 24 48, gap 48 Q→A */
.faq-item.open { padding-top: 24px; padding-bottom: 48px; }
.faq-q {
  width: 100%; display: flex; align-items: center; gap: 16px; cursor: pointer;
  background: none; border: 0; font-family: var(--font-text); text-align: left;
  /* Vertical only — horizontal inset comes from .faq-item */
  padding: 24px 0; font-size: 16px; font-weight: 700; color: var(--ink);
  line-height: 1.5;
  font-variation-settings: "opsz" 14;
  transition: padding .4s cubic-bezier(0.25, 0.1, 0.25, 1);
}
.faq-item.open .faq-q { padding: 0; }
.faq-q .q-text { flex: 1; min-width: 0; overflow-wrap: break-word; }
.faq-chev { flex: none; width: 20px; height: 20px; display: inline-grid; place-items: center; }
/* Inline SVG rather than an <img>: app.js builds the FAQ markup and ships from
   the CDN, where a /static/… reference would resolve against the wrong origin. */
.faq-chev::before {
  content: "";
  width: 12px;
  height: 8px;
  background: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20width='12'%20height='7.41'%20viewBox='0%200%2012%207.41'%3E%3Cpath%20d='M10.59%200L6%204.58L1.41%200L0%201.41L6%207.41L12%201.41L10.59%200Z'%20fill='%23000000'/%3E%3C/svg%3E") center / contain no-repeat;
  transition: transform .35s cubic-bezier(0.25, 0.1, 0.25, 1);
}
.faq-item.open .faq-chev::before { transform: rotate(180deg); }
/* Height via grid 0fr→1fr only — no opacity/x shift (avoids "text morphing"). */
.faq-a {
  display: grid;
  grid-template-rows: 0fr;
  margin-top: 0;
  padding: 0;
  transition:
    grid-template-rows .4s cubic-bezier(0.25, 0.1, 0.25, 1),
    margin-top .4s cubic-bezier(0.25, 0.1, 0.25, 1);
}
.faq-item.open .faq-a { grid-template-rows: 1fr; margin-top: 48px; }
.faq-a-inner { min-height: 0; overflow: hidden; }
.faq-a, .faq-a * {
  color: var(--ink);
  font-family: var(--font-text);
  font-size: 16px;
  line-height: 1.5;
  font-weight: 400;
  font-variation-settings: "opsz" 14;
  overflow-wrap: break-word;
}
.faq-a a { color: var(--accent); }
.faq-a strong { color: var(--ink); font-weight: 700; }
.faq-a ul { margin: 0; padding-left: 24px; list-style: disc; }
.faq-a li { margin: 0 0 16px; }
.faq-a li:last-child { margin-bottom: 0; }
.faq-a li::marker { color: var(--ink); }
.faq-a p { margin: 0 0 16px; }
.faq-a p:last-child { margin-bottom: 0; }

/* ---- Footer --------------------------------------------------------------- */
.site-footer {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: flex-start;
  gap: 32px;
  width: 100%;
  max-width: var(--page-maxw);
  margin: 0 auto;
  padding: var(--footer-pad-t) var(--page-gutter) var(--footer-pad-b);
  color: var(--ink);
  font-size: 16px;
  text-align: left;
}
.footer-left { display: inline-flex; flex-direction: column; align-items: flex-start; gap: 0; margin: 0; }
.footer-copy {
  display: inline-flex;
  align-items: center;
  gap: 12px;
  color: var(--ink);
  font-family: var(--font-text);
  font-size: 16px;
  font-weight: 500;
  line-height: 1.25;
  font-variation-settings: "opsz" 14;
}
.footer-copyright-icon { width: 18px; height: 18px; object-fit: contain; display: block; }

/* ---- Toasts (Figma Top Toast) --------------------------------------------- */
.toast-stack {
  position: fixed;
  top: 56px;
  left: 0;
  right: 0;
  z-index: 100; /* above the legal / feedback modals */
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  padding: 0 16px;
  pointer-events: none;
}
.toast {
  display: flex;
  flex-direction: row;
  justify-content: center;
  align-items: center;
  min-height: 48px;
  max-width: min(520px, 100%);
  padding: 12px 16px;
  gap: 8px;
  border-radius: 14px;
  /* Figma: white 10% wash over rgba(37,37,37,0.9) + blur */
  background:
    linear-gradient(0deg, rgba(255, 255, 255, 0.1), rgba(255, 255, 255, 0.1)),
    rgba(37, 37, 37, 0.9);
  backdrop-filter: blur(30px);
  -webkit-backdrop-filter: blur(30px);
  color: #f6f6f6;
  font-family: var(--font);
  font-size: 17px;
  font-weight: 400;
  line-height: 1.3;
  text-align: center;
  filter: drop-shadow(0 12px 50px rgba(0, 0, 0, 0.15));
  pointer-events: auto;
  animation: toastIn .22s ease;
  overflow-wrap: break-word;
}
@keyframes toastIn { from { opacity: 0; transform: translateY(-8px); } }
@keyframes fade { from { opacity: 0; } }
@keyframes pop { from { opacity: 0; transform: translateY(10px) scale(.98); } }
@keyframes sheetUp {
  from { opacity: 0; transform: translateY(24px); }
  to { opacity: 1; transform: translateY(0); }
}

/* ---- Legal dialog (Terms / Privacy) --------------------------------------- */
/* Mobile band = Figma bottom sheet. The tablet band promotes it to a dialog. */
.legal-overlay {
  position: fixed;
  inset: 0;
  z-index: 90;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  align-items: stretch;
  padding: 0;
  background: rgba(0, 0, 0, 0.5);
  animation: fade .15s ease;
}
.legal-dialog {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  width: 100%;
  max-width: none;
  max-height: min(580px, 90vh);
  padding: 0 0 max(16px, env(safe-area-inset-bottom, 0px));
  gap: 0;
  background: #fff;
  border-radius: 26px 26px 0 0;
  box-shadow: none;
  animation: sheetUp .22s ease;
}
.legal-x {
  position: absolute;
  /* Figma Nav End: 42×44 hit area, 8px from the dialog right edge */
  top: 0;
  right: 8px;
  width: 42px;
  height: 44px;
  display: grid;
  place-items: center;
  margin: 0;
  padding: 10px 8px;
  border: 0;
  background: none;
  color: #000;
  cursor: pointer;
  z-index: 2;
}
.legal-x:hover { opacity: 0.7; }
.legal-title {
  font-family: var(--font-display);
  font-size: 24px;
  font-weight: 700;
  line-height: 1.2;
  letter-spacing: -0.01em;
  margin: 44px 16px 0; /* below the 44px X row */
  padding-right: 0;
  align-self: stretch;
  text-align: center;
  color: #000;
  overflow-wrap: break-word;
}
.legal-scroll {
  flex: 1 1 auto;
  align-self: center;
  width: calc(100% - 32px);
  margin: 20px 16px 0;
  min-height: 120px;
  overflow: auto;
  padding: 16px 12px;
  background: rgba(0, 0, 0, 0.05);
  border-radius: 16px;
  -webkit-overflow-scrolling: touch;
}
.legal-body {
  font-family: var(--font);
  font-size: 14px;
  font-weight: 400;
  line-height: 1.5;
  color: #000;
  text-align: left;
  overflow-wrap: break-word;
}
.legal-body p { margin: 0 0 16px; }
.legal-body p:last-child { margin-bottom: 0; }
.legal-body ul { margin: 0; padding-left: 1.25em; }
.legal-body li + li { margin-top: 16px; }
.legal-actions {
  display: flex;
  justify-content: stretch;
  align-items: center;
  align-self: center;
  width: calc(100% - 32px);
  margin: 20px 16px 0;
  flex: none;
}
.legal-close-btn {
  width: 100%;
  min-width: 0;
  min-height: 52px;
  padding: 8px 20px;
  border-radius: 999px;
  font-family: var(--font);
  font-size: 16px;
  font-weight: 600;
  line-height: 1.3;
  justify-content: center;
}

/* ---- Feedback modal ------------------------------------------------------- */
/* Mobile band = Figma bottom sheet. The tablet band promotes it to a 560 dialog. */
.modal-overlay {
  position: fixed;
  inset: 0;
  z-index: 80;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  align-items: stretch;
  padding: 0;
  background: rgba(0, 0, 0, 0.5);
  animation: fade .15s ease;
}
.modal {
  display: flex;
  flex-direction: column;
  width: 100%;
  max-width: none;
  max-height: min(90vh, 640px);
  margin: 0;
  padding: 0;
  background: #fff;
  border-radius: 26px 26px 0 0;
  box-shadow: none;
  overflow: hidden;
  animation: sheetUp .22s ease;
}
.fb-form {
  display: flex;
  flex-direction: column;
  gap: 0;
  width: 100%;
  min-height: 0;
  flex: 1;
  /* Short viewports (small phone in landscape, 200% zoom) must still reach Submit. */
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
}
.modal-nav {
  display: flex;
  justify-content: flex-end;
  align-items: center;
  height: 52px;
  margin: 0;
  padding: 4px 8px;
  flex: none;
}
.modal-close {
  width: 28px;
  height: 28px;
  display: grid;
  place-items: center;
  margin: 0;
  padding: 4px;
  border: 0;
  border-radius: 100px;
  background: rgba(0, 0, 0, 0.05);
  color: rgba(0, 0, 0, 0.65);
  cursor: pointer;
  flex: none;
}
.modal-close:hover { background: rgba(0, 0, 0, 0.08); color: #000; }
/* `display: contents` hoists caption + body children into the sheet column so
   the title / sub / field / actions can be spaced independently. */
.modal-caption,
.fb-body { display: contents; }
.modal-caption h2 {
  font-family: var(--font-display);
  font-size: 24px;
  font-weight: 700;
  letter-spacing: -0.01em;
  line-height: 1.2;
  margin: 0;
  padding: 0 16px;
  text-align: center;
  color: #000;
  flex: none;
  overflow-wrap: break-word;
}
.modal-sub {
  margin: 20px 16px 12px;
  padding: 0;
  font-family: var(--font);
  font-size: 14px;
  font-weight: 400;
  line-height: 1.3;
  color: #000;
  text-align: center;
  flex: none;
  overflow-wrap: break-word;
}
.fb-field {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  align-items: stretch;
  gap: 8px;
  flex: none;
  width: auto;
  min-width: 0;
  height: 146px;
  min-height: 146px;
  /* Bottom margin clears the 2px focus ring so Submit never sits on the border. */
  margin: 0 16px 16px;
  padding: 16px;
  background: rgba(0, 0, 0, 0.05);
  border-radius: 16px;
}
.fb-field:focus-within { box-shadow: 0 0 0 2px #000; }
#fbText {
  width: 100%;
  flex: 1 1 auto;
  min-height: 0;
  max-height: none;
  border: 0;
  border-radius: 0;
  padding: 0;
  font-family: var(--font);
  font-size: 16px; /* ≥16px keeps iOS from zooming on focus */
  line-height: 1.3;
  resize: none;
  color: var(--ink);
  background: transparent;
}
#fbText::placeholder { font-size: 16px; color: rgba(0, 0, 0, 0.34); }
#fbText:focus { outline: none; box-shadow: none; }
.fb-meta {
  display: flex;
  justify-content: flex-end;
  align-items: center;
  gap: 10px;
  margin: 0;
  padding: 0;
  width: 100%;
  min-height: 8px;
}
.fb-error { color: var(--red); font-weight: 600; font-size: 12px; margin-right: auto; }
.fb-count {
  color: rgba(0, 0, 0, 0.48);
  font-family: var(--font-text);
  font-size: 13px;
  font-weight: 400;
  line-height: 1.2;
  text-align: right;
  margin-left: auto;
}
.fb-actions {
  display: flex;
  justify-content: flex-end;
  align-items: center;
  gap: 0;
  margin: 0;
  /* Extra top pad + safe area so the full-width Submit clears the field ring
     and the sheet edge. */
  padding: 4px 20px max(20px, env(safe-area-inset-bottom, 0px));
  width: 100%;
  background: #fff;
  flex: none;
}
.fb-actions .btn {
  min-width: 0;
  min-height: 48px;
  padding: 14px 24px;
  border-radius: 40px;
  font-size: 16px;
  font-weight: 700;
  line-height: 1.5;
}
.fb-cancel { display: none; } /* mobile sheet has an X instead */
.fb-actions #fbSubmit {
  width: 100%;
  min-width: 0;
  min-height: 52px;
  padding: 8px 20px;
  border-radius: 999px;
  font-family: var(--font);
  font-size: 16px;
  font-weight: 600;
  line-height: 1.3;
  justify-content: center;
}
#fbSubmit:disabled { opacity: 0.4; cursor: not-allowed; }
.fb-thanks { text-align: center; padding: 26px 10px 14px; }
.fb-check {
  width: 52px; height: 52px; border-radius: 50%; display: inline-grid;
  place-items: center; background: color-mix(in srgb, var(--green) 14%, #fff);
  color: var(--green);
}
.fb-thanks p { font-weight: 700; margin: 14px 0 0; }

/* ============================================================================
   COMPONENT SAFETY NETS — not design bands.
   These only harden individual components inside the mobile band; they never
   redefine layout tokens or composition.
   ========================================================================== */

/* Long localized words / compounds must break instead of widening the card. */
@media (max-width: 640px) {
  .hero-title,
  .dz-title,
  .status-title,
  .card-foot-label,
  .card-foot-thanks,
  .faq-q .q-text { overflow-wrap: anywhere; }
}

/* 320-class phones: pills and long URLs must stay inside their column. */
@media (max-width: 420px) {
  .btn { padding-inline: 20px; }
  .faq-a,
  .faq-a *,
  .legal-body,
  .status-sub { overflow-wrap: anywhere; }
}

/* ============================================================================
   BAND 2 — TABLET (768–1279)
   Composition: wider page gutters, side-by-side footer, desktop-style dialogs,
   full-size status/chip metrics. Sizes ramp to the desktop start values.
   ========================================================================== */
@media (min-width: 768px) {
  :root {
    --t-ramp: calc(clamp(0px, 100vw - 768px, 512px) / 512);

    /* Page shell */
    --page-maxw: 100%;
    --page-gutter: 32px;
    --nav-min-h: 80px;
    --nav-pad-x: 48px;
    --nav-title-size: 20px;
    --nav-beta-size: 16px;

    /* Hero */
    --hero-title-size: calc(48px + var(--t-ramp) * 22.4);
    --hero-title-pad-x: calc(48px + var(--t-ramp) * 99.2);
    --hero-title-pad-t: 96px;
    --stage-maxw: 100%;
    --stage-pad-x: 48px; /* Figma Feature Highlight inset */
    --stage-pad-t: calc(96px - var(--t-ramp) * 32);
    --fan-stack-w: calc(200px + var(--t-ramp) * 80);
    --fan-overlap: calc(120px - var(--t-ramp) * 4);

    /* Card shell — 672 at 768 (matches the mobile cap), 1000 from 1096 up. */
    --card-maxw: min(1000px, calc(100vw - 96px));
    --card-min-h: calc(524px + var(--t-ramp) * 16);
    --card-min-h-idle: 623px;
    --card-min-h-progress: 654px;
    --card-min-h-result: 764px;

    /* Panels */
    --idle-pad-x: calc(24px + var(--t-ramp) * 40);
    --idle-pad-t: 96px;
    --idle-pad-b: 80px;
    --idle-gap: 64px;
    --content-col: calc(608px + var(--t-ramp) * 264);
    --legal-col: calc(608px + var(--t-ramp) * 248);
    --panel-padding-x: calc(21px + var(--t-ramp) * 35);
    --panel-padding-y: 96px;

    /* Status block */
    --icon-size: 96px;
    --icon-glyph: 48px;
    --title-size: 40px;
    --body-size: 16px;
    --hint-size: 36px;
    --sub-max-w: 522px;

    /* File chip */
    --chip-thumb: 84px;
    --chip-name: 22px;
    --chip-sub: 16px;
    --chip-gap: 24px;
    --chip-pad-y: 20px;
    --chip-pad-l: 20px;
    --chip-pad-r: 32px;
    --chip-radius: 16px;
    --chip-min-h: 124px;

    /* Buttons */
    --btn-font: 18px;
    --cta-min-w: 196px;
    --cancel-size: 22px;
    --cancel-weight: 500;

    /* Feedback foot */
    --foot-gap: 32px;
    --foot-pad-x: 32px;
    --foot-label-size: 24px;

    /* FAQ / footer */
    --faq-col: 704px;
    --faq-gutter: 32px;
    --faq-pad-t: 120px;
    --footer-pad-t: 48px;
    --footer-pad-b: 16px;
  }

  /* Copy toggles: long FAQ heading, "Upload file" / "Drag and drop…". */
  .show-lg,
  .show-gt-mobile { display: inline; }
  div.show-gt-mobile { display: block; }
  .show-sm,
  .show-mobile-only,
  .dz-title-mobile { display: none !important; }

  /* Footer becomes a single row. */
  .site-footer {
    flex-direction: row;
    align-items: center;
    gap: 16px;
  }
  .footer-left { flex-direction: row; align-items: center; gap: 32px; }

  /* Legal: bottom sheet → centered alert dialog. */
  .legal-overlay {
    justify-content: center;
    align-items: center;
    padding: 0 48px;
  }
  .legal-dialog {
    max-width: 672px;
    max-height: 480px;
    padding: 32px 24px;
    gap: 20px;
    border-radius: 32px;
    box-shadow:
      0 419px 168px rgba(0, 0, 0, 0.02),
      0 236px 141px rgba(0, 0, 0, 0.07),
      0 105px 105px rgba(0, 0, 0, 0.13),
      0 26px 58px rgba(0, 0, 0, 0.15);
    animation: pop .18s ease;
  }
  .legal-title {
    margin: 0;
    padding-right: 48px; /* clear the X */
    text-align: left;
  }
  .legal-scroll {
    width: auto;
    align-self: stretch;
    margin: 0;
    min-height: 0;
  }
  .legal-actions {
    width: auto;
    align-self: stretch;
    margin: 0;
    justify-content: flex-end;
  }
  .legal-close-btn {
    width: auto;
    min-width: 92px;
    min-height: 48px;
    padding: 14px 24px;
    border-radius: 40px;
    font-family: var(--font-text);
    font-size: 16px;
    font-weight: 700;
  }

  /* Feedback: bottom sheet → centered dialog (Figma 560×324). */
  .modal-overlay {
    justify-content: center; /* must override the sheet's flex-end */
    align-items: center;
    padding: 20px;
  }
  .modal {
    display: block;
    max-width: 560px;
    min-height: 324px;
    max-height: none;
    padding: 32px 24px;
    border-radius: 32px;
    overflow: visible;
    box-shadow:
      0 419px 168px rgba(0, 0, 0, 0.02),
      0 236px 141px rgba(0, 0, 0, 0.07),
      0 105px 105px rgba(0, 0, 0, 0.13),
      0 26px 58px rgba(0, 0, 0, 0.15);
    animation: pop .18s ease;
  }
  .fb-form { gap: 32px; flex: none; overflow: visible; }
  .modal-nav { display: none; } /* dialog closes via Cancel / Esc */
  .modal-caption { display: block; }
  .modal-caption h2 { padding: 0; text-align: left; }
  .fb-body {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 16px;
    width: 100%;
  }
  .modal-sub { margin: 0; text-align: left; line-height: 1.5; }
  .fb-field {
    width: 100%;
    height: auto;
    min-height: 105px;
    margin: 0;
  }
  #fbText { font-size: 14px; line-height: 1.5; min-height: 65px; }
  #fbText::placeholder { font-size: 14px; color: rgba(0, 0, 0, 0.6); }
  .fb-count { font-size: 12px; color: rgba(0, 0, 0, 0.6); }
  .fb-actions { padding: 0; gap: 10px; }
  .fb-cancel {
    display: inline-flex;
    background: #fff;
    color: #000;
    border: 1px solid #000;
  }
  .fb-cancel:hover { background: rgba(0, 0, 0, 0.04); }
  .fb-actions #fbSubmit {
    width: auto;
    min-width: 0;
    min-height: 48px;
    padding: 14px 24px;
    border-radius: 40px;
    font-family: var(--font-text);
    font-size: 16px;
    font-weight: 700;
  }
}

/* ============================================================================
   BAND 3 — DESKTOP (1280–1727)
   Composition: page column caps at the 1440 Figma frame, stage loses its
   gutters (fans sit at the frame edges), card locks to 1000.
   ========================================================================== */
@media (min-width: 1280px) {
  :root {
    --page-maxw: 1440px;
    --page-gutter: 48px;

    --hero-title-size: clamp(48px, 5.5vw, 80px);
    --hero-title-pad-x: clamp(48px, 11.5vw, 165px);
    --stage-maxw: 1440px;
    --stage-pad-x: 0px;
    --stage-pad-t: 64px;
    --fan-stack-w: 280px;
    --fan-overlap: 116px;

    --card-maxw: 1000px;
    --card-min-h: 540px;

    --idle-pad-x: 64px;
    --content-col: 872px;
    --legal-col: 856px;
    --panel-padding-x: 56px;

    --faq-col: 658px;
    --faq-gutter: 0px;
    --faq-pad-t: 96px;
    --footer-pad-b: 32px;
  }

  /* Desktop alert dialog is narrower than the tablet one (Figma 560). */
  .legal-overlay { padding: 20px; }
  .legal-dialog { max-width: 560px; }
}

/* ============================================================================
   BAND 4 — WIDE (1728+)
   Composition: page / title / footer span the 1920 Figma frame while the upload
   stage stays on the 1440 frame, so the card never drifts from the fan art.
   ========================================================================== */
@media (min-width: 1728px) {
  :root {
    --page-maxw: 1920px;
    --hero-title-size: 80px;
    --hero-title-pad-x: 165px;
    --stage-maxw: 1440px;
  }
}

/* ---- Reduced motion ------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  * { animation: none !important; transition: none !important; }
  html.is-ready body { transition: none; }
  .ap {
    opacity: 1 !important;
    filter: none !important;
    transform: none !important;
  }
}


