/* ============================================================================
   potato.css — YesPotato Instagram downloader
   ----------------------------------------------------------------------------
   MOBILE FIRST. Every base rule targets a ~360px phone; larger screens are
   additive via `min-width` queries only. There is not a single `max-width`
   media query in this file — if you add one you have broken the model.

   Palette: warm paper + ONE earthy terracotta accent. No gradients anywhere
   (deliberate: the previous amber→pink→violet ramp fought the cozy paper
   texture and made the UI feel louder than the product). Colour count is kept
   deliberately small — two surfaces, three text weights, one accent, three
   semantic hues.

   Contrast (verified, WCAG 2.1):
     light  accent #b5542f on #ffffff → 4.91:1   (AA normal text)
     light  #ffffff on accent #b5542f → 4.91:1   (AA button label)
     dark   accent #e8916a on #14120f → 7.82:1   (AAA)
     dark   #14120f on accent #e8916a → 7.82:1   (AAA button label)

   Structure
     1. Design tokens (light + dark)
     2. Reset, base, a11y, touch
     3. Layout primitives + buttons
     4. Header / drawer
     5. Hero + downloader
     6. Result cards
     7. Sections, cards, prose, FAQ
     8. App band + footer
     9. Ads
    10. Motion + reveal
    11. Breakpoints (min-width only)
    12. RTL + print
   ========================================================================= */

/* ── 1. Design tokens ─────────────────────────────────────────────────── */
:root {
  /* Soft mint-tinted paper. Not pure white — pure white reads clinical, and the
     faint green cast is what makes the teal accent feel settled rather than
     stuck on. */
  --bg: #f5faf9;
  --bg-alt: #ecf5f3;
  --surface: #ffffff;
  --surface-2: #f8fcfb;
  --surface-hover: #eaf5f2;
  --border: #dceae7;
  --border-strong: #c3d9d4;

  --text: #132420;
  --text-soft: #4a5c58;
  --text-muted: #5f706b;

  /* One primary: a deep, calm teal. Contrast-checked both directions. */
  --accent: #0d7d72;
  --accent-hover: #0a675e;
  --accent-soft: #e6f4f1;
  --accent-line: #bfe0d9;
  --on-accent: #ffffff;

  /* Secondaries. Emerald carries "verified//done", the soft yellow carries
     "heads-up" — neither is ever the only signal for anything. */
  --success: #067552;
  --success-soft: #e4f4ec;
  --warning: #7a5300;
  --warning-soft: #fdf3dd;
  --danger: #b3261e;
  --danger-soft: #fdecea;

  /* Light mode gets a gradient; dark mode deliberately does not (see below). */
  --bg-gradient: radial-gradient(
      120% 90% at 12% -10%,
      #e4f5f0 0%,
      transparent 55%
    ),
    radial-gradient(90% 70% at 100% 0%, #eaf7e6 0%, transparent 50%),
    radial-gradient(80% 60% at 50% 100%, #eef8f6 0%, transparent 60%);

  /* Glass. Only used on surfaces that float OVER content — never on a button,
     where translucency would eat the CTA's contrast. */
  --glass-bg: rgba(255, 255, 255, 0.72);
  --glass-border: rgba(255, 255, 255, 0.65);
  --glass-blur: saturate(160%) blur(14px);

  /* No glow in light mode: a glow on a pale background just looks like a smudge. */
  --glow: none;
  --glow-strong: none;

  --radius-sm: 10px;
  --radius: 14px;
  --radius-lg: 20px;
  --radius-pill: 999px;

  --shadow-xs: 0 1px 2px rgba(19, 46, 41, 0.05);
  --shadow-sm: 0 2px 6px rgba(19, 46, 41, 0.06);
  --shadow: 0 6px 18px rgba(19, 46, 41, 0.08);
  --shadow-lg: 0 16px 40px rgba(19, 46, 41, 0.12);

  /* Poppins is geometric and friendly, which suits the product; Inter stays for
     long-form body copy because Poppins' wide, round lowercase gets tiring
     across a 70-character measure. */
  --font: "Poppins", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
    "Helvetica Neue", Arial, "Noto Sans", sans-serif;
  --font-body: "Inter", var(--font);

  --wrap: 1120px;
  --wrap-narrow: 720px;
  --wrap-prose: 760px;
  --pad: 16px;
  --header-h: 58px;

  --ease: cubic-bezier(0.22, 0.61, 0.36, 1);
  --t-fast: 130ms var(--ease);
  --t: 220ms var(--ease);
}

[data-theme="dark"] {
  /* FLAT dark. No gradient anywhere — on an OLED panel a large dark gradient
     bands visibly, and the whole point of dark mode here is calm. Depth comes
     from surface steps and the accent glow instead. */
  --bg: #0d1214;
  --bg-alt: #111a1c;
  --surface: #141b1e;
  --surface-2: #182125;
  /* Hover is teal-tinted and a decisive step lighter, mirroring how the light
     theme tints toward mint on hover. */
  --surface-hover: #22463f;
  /* Edges are deliberately a BIGGER step than the light theme's.
     Matching the WCAG contrast *ratio* is misleading down here: the old
     #222e31 measured 1.247:1 against the surface versus light mode's 1.238:1 —
     ratio parity — yet it carried only 17 sRGB levels of separation against
     light mode's 27, and real displays crush near-black. Judged on ΔL* and raw
     sRGB step instead, these values land at ~1.6x the light theme's edge, which
     is what makes them actually visible. */
  --border: #374a50;
  --border-strong: #4f6a72;

  --text: #e6f0ee;
  --text-soft: #a7b8b4;
  --text-muted: #7d8f8b;

  /* Mint. Bright enough to read as neon against the flat near-black. */
  --accent: #5eead4;
  --accent-hover: #7df3e0;
  --accent-soft: #102a27;
  --accent-line: #1d3f3a;
  --on-accent: #062621;

  --success: #34d399;
  --success-soft: #10241d;
  --warning: #fcd34d;
  --warning-soft: #26200f;
  --danger: #ff8a80;
  --danger-soft: #2a1715;

  --bg-gradient: none;

  /* More opaque than the light theme's 0.72. A translucent panel over a
     near-black page composites almost everything toward the same value, which
     flattened the hover tint into invisibility. */
  --glass-bg: rgba(20, 27, 30, 0.9);
  --glass-border: rgba(94, 234, 212, 0.14);
  --glass-blur: saturate(140%) blur(14px);

  /* The neon: a coloured glow, used sparingly on the primary CTA, focus rings
     and active nav. This is what makes the flat dark theme feel alive. */
  --glow: 0 0 0 1px rgba(94, 234, 212, 0.22), 0 4px 20px rgba(94, 234, 212, 0.16);
  --glow-strong: 0 0 0 1px rgba(94, 234, 212, 0.4), 0 6px 28px rgba(94, 234, 212, 0.3);

  --shadow-xs: 0 1px 2px rgba(0, 0, 0, 0.45);
  --shadow-sm: 0 2px 8px rgba(0, 0, 0, 0.5);
  --shadow: 0 6px 20px rgba(0, 0, 0, 0.55);
  --shadow-lg: 0 16px 44px rgba(0, 0, 0, 0.65);
}

/* ── 2. Reset, base, a11y, touch ─────────────────────────────────────── */
*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: calc(var(--header-h) + 12px);
  /* Kill the grey/blue rectangle Android and iOS paint over a tapped element.
     It ignores border-radius, so on a pill button it flashes a hard rectangle
     — the single most "unfinished" looking thing on a mobile web app. */
  -webkit-tap-highlight-color: transparent;
}

body {
  margin: 0;
  background-color: var(--bg);
  /* Light mode only: --bg-gradient resolves to `none` under [data-theme="dark"],
     so the dark theme stays completely flat with no extra rule needed.
     `fixed` keeps the wash anchored to the viewport instead of scrolling as a
     visible seam down a long article page. */
  background-image: var(--bg-gradient);
  background-attachment: fixed;
  background-repeat: no-repeat;
  color: var(--text);
  font-family: var(--font-body);
  font-size: 16px;
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow-x: hidden;
}

/* Every interactive element: no tap rectangle, no 300ms click delay. */
a,
button,
summary,
label,
input,
select,
textarea,
[role="button"] {
  -webkit-tap-highlight-color: transparent;
}
a,
button,
summary,
[role="button"] {
  touch-action: manipulation;
}

h1,
h2,
h3,
h4 {
  font-family: var(--font);
  color: var(--text);
  letter-spacing: -0.018em;
  line-height: 1.24;
  margin: 0 0 0.6em;
  font-weight: 700;
  text-wrap: balance;
}

h1 {
  font-size: clamp(1.6rem, 6vw, 2.6rem);
  font-weight: 800;
}
h2 {
  font-size: clamp(1.3rem, 4.4vw, 1.9rem);
}
h3 {
  font-size: 1.05rem;
}

p {
  margin: 0 0 1.1em;
  color: var(--text-soft);
}

a {
  color: var(--accent);
  text-decoration: none;
  transition: color var(--t-fast);
}
a:hover {
  color: var(--accent-hover);
}

img,
video {
  max-width: 100%;
  height: auto;
  display: block;
}

button,
input,
select,
textarea {
  font: inherit;
  color: inherit;
}

button {
  cursor: pointer;
  border: 0;
  background: none;
}

ul,
ol {
  margin: 0 0 1.1em;
  padding-left: 1.25em;
}

/* The HTML `hidden` attribute must win.
   The UA stylesheet's `[hidden] { display: none }` comes from the *user-agent*
   origin, which loses to ANY author `display` declaration regardless of
   specificity. Several components below set `display: flex`, so without this
   rule they render even while marked hidden — which is what once showed the
   "Fetching…" spinner and the error box on first paint, and made hiding them
   again a no-op. `!important` is genuinely right here: nothing should ever
   out-rank `hidden`. */
[hidden] {
  display: none !important;
}

/* Keyboard users get a ring; mouse/touch users do not. Without the second
   rule, tapping a button on a phone leaves a persistent outline behind. */
:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 4px;
}
:focus:not(:focus-visible) {
  outline: none;
}

::selection {
  background: var(--accent-soft);
  color: var(--text);
}

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

.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 200;
  background: var(--surface);
  color: var(--text);
  padding: 12px 18px;
  border-radius: 0 0 var(--radius-sm) 0;
  box-shadow: var(--shadow);
}
.skip-link:focus {
  left: 0;
}

/* ── 3. Layout primitives + buttons ──────────────────────────────────── */
.wrap {
  width: 100%;
  max-width: var(--wrap);
  margin-inline: auto;
  padding-inline: var(--pad);
}
.wrap--narrow {
  max-width: var(--wrap-narrow);
}

.section {
  padding: 40px 0;
}
.section--alt {
  background: var(--bg-alt);
  border-block: 1px solid var(--border);
}

.section-head {
  max-width: 620px;
  margin: 0 auto 26px;
  text-align: center;
}
.section-head h2 {
  margin-bottom: 0.35em;
}
.section-head p {
  margin: 0;
  color: var(--text-muted);
  font-size: 0.98rem;
}

/* Buttons. Minimum 44px tall everywhere — Apple's and Google's touch-target
   floor, and the reason the old 38px icon buttons felt fiddly on a phone. */
.btn-primary {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 9px;
  min-height: 48px;
  padding: 13px 22px;
  border-radius: var(--radius-pill);
  background: var(--accent);
  color: var(--on-accent);
  font-family: var(--font);
  font-weight: 600;
  font-size: 1rem;
  transition: background var(--t-fast), transform var(--t-fast),
    box-shadow var(--t);
  /* In dark mode --glow is a mint halo; in light mode it resolves to `none` and
     only the paper shadow remains. One declaration serves both themes. */
  box-shadow: var(--shadow-sm), var(--glow);
  white-space: nowrap;
}
.btn-primary:hover {
  background: var(--accent-hover);
  color: var(--on-accent);
  box-shadow: var(--shadow), var(--glow-strong);
}
/* Press feedback replaces the tap rectangle we suppressed above: the button
   itself reacts, which reads as intentional rather than as a browser artefact. */
.btn-primary:active {
  transform: scale(0.975);
  box-shadow: var(--shadow-xs);
}
.btn-primary[disabled],
.btn-primary.is-busy {
  cursor: progress;
  opacity: 0.72;
}
.btn-block {
  width: 100%;
}

.btn-ghost {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 7px;
  min-height: 44px;
  padding: 10px 14px;
  border-radius: var(--radius-pill);
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text-soft);
  font-size: 0.9rem;
  font-weight: 600;
  transition: background var(--t-fast), color var(--t-fast),
    border-color var(--t-fast), transform var(--t-fast);
}
.btn-ghost:hover {
  background: var(--surface-hover);
  color: var(--text);
  border-color: var(--border-strong);
}
.btn-ghost:active {
  transform: scale(0.975);
}
.btn-icon {
  width: 44px;
  height: 44px;
  padding: 0;
  flex-shrink: 0;
}
.btn-sm {
  min-height: 38px;
  padding: 8px 13px;
  font-size: 0.84rem;
}

.link-btn {
  color: var(--accent);
  text-decoration: underline;
  text-underline-offset: 3px;
  padding: 0;
  font-size: inherit;
  word-break: break-all;
}

/* Spinner */
.spinner {
  width: 17px;
  height: 17px;
  border: 2.5px solid color-mix(in srgb, var(--on-accent) 35%, transparent);
  border-top-color: var(--on-accent);
  border-radius: 50%;
  animation: spin 0.7s linear infinite;
  display: none;
}
.spinner--inline {
  display: inline-block;
  border-color: var(--accent-line);
  border-top-color: var(--accent);
}
.is-busy .spinner {
  display: inline-block;
}
.is-busy .dl-submit-label {
  display: none;
}
@keyframes spin {
  to {
    transform: rotate(360deg);
  }
}

/* ── 4. Header / drawer ──────────────────────────────────────────────────
   GLASS, used with intent. Frosted translucency only earns its cost on
   surfaces that float over other content — the sticky header, the dropdown and
   the drawer. It is deliberately NOT applied to buttons: a translucent CTA
   picks up whatever is behind it, which is exactly how you lose the contrast
   the button needs to read as the primary action. */
.site-header {
  position: sticky;
  top: 0;
  z-index: 60;
  background: var(--glass-bg);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  border-bottom: 1px solid var(--border);
  /* The hairline highlight along the top edge is what makes frosted glass read
     as glass rather than as a flat translucent panel. */
  box-shadow: inset 0 1px 0 var(--glass-border);
}
@supports not (backdrop-filter: blur(1px)) {
  .site-header {
    background: var(--bg);
  }
}

.header-inner {
  display: flex;
  align-items: center;
  gap: 10px;
  height: var(--header-h);
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  color: var(--text);
  font-family: var(--font);
  font-weight: 800;
  font-size: 1.02rem;
  letter-spacing: -0.02em;
  flex-shrink: 0;
}
.brand:hover {
  color: var(--text);
}
.brand img {
  border-radius: 9px;
}

/* Primary nav is drawer-only on phones; it appears from the md breakpoint. */
.header-nav {
  display: none;
}
.header-nav-link {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  min-height: 36px;
  padding: 7px 12px;
  border-radius: var(--radius-pill);
  color: var(--text-soft);
  font-size: 0.875rem; /* 14px */
  line-height: 1.25;
  font-weight: 600;
  white-space: nowrap;
  transition: background var(--t-fast), color var(--t-fast);
}
.header-nav-link:hover,
.header-nav-link:focus-visible {
  background: var(--surface-hover);
  color: var(--text);
}
.header-nav-link.is-active {
  background: var(--accent-soft);
  color: var(--accent);
}
.header-nav-link i {
  font-size: 0.85em;
  opacity: 0.85;
}

.header-actions {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-inline-start: auto;
}

/* Theme icon swap */
[data-theme="light"] .icon-light,
[data-theme="dark"] .icon-dark {
  display: none;
}

/* Language dropdown */
.menu {
  position: relative;
  /* Flex, not the default block: a block wrapping an inline-flex button takes
     its height from the line box, which adds fractional descender space and
     would push the panel — and therefore every item edge inside it — onto a
     half-pixel offset. */
  display: flex;
  align-items: center;
}
.menu-btn-label {
  display: none;
}
.menu-panel {
  position: absolute;
  inset-inline-end: 0;
  top: calc(100% + 8px);
  min-width: 190px;
  padding: 6px;
  background: var(--glass-bg);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  /* No --glow here. Its first layer is a `0 0 0 1px` ring that sat immediately
     outside this panel's own 1px border, so the left and right edges rendered as
     two stacked lines while the second layer's 4px vertical offset shifted the
     halo downward — the edges looked thicker on the sides than on the top and
     bottom. The panel reads fine on its border and drop shadow alone. */
  box-shadow: var(--shadow-lg);
  opacity: 0;
  visibility: hidden;
  transform: translateY(-6px) scale(0.98);
  transform-origin: top right;
  transition: opacity var(--t-fast), transform var(--t-fast),
    visibility var(--t-fast);
  z-index: 70;
}
.menu.is-open .menu-panel {
  opacity: 1;
  visibility: visible;
  transform: translateY(0) scale(1);
}
.menu-panel--lang {
  max-height: 64vh;
  overflow-y: auto;
}
/* Nav items keep whole-pixel heights (an explicit integer min-height), which
   also gives them comfortable touch targets. The hover state is a pure COLOUR
   change — background tint plus text colour — with no border.
   A 1px border was tried and abandoned: at fractional display scaling (125%,
   150% Windows zoom) a 1px CSS edge lands on 1.25 or 1.5 device pixels and
   rounds differently on the horizontal and vertical sides, so it renders visibly
   uneven. The dark theme's hover tint is already ~4x the light theme's
   perceptual step, so it carries the state on its own. */
.menu-panel a {
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: 42px;
  padding: 9px 11px;
  border-radius: var(--radius-sm);
  color: var(--text-soft);
  font-size: 0.875rem; /* 14px */
  line-height: 1.25;
  font-weight: 500;
  transition: background var(--t-fast), color var(--t-fast);
}
.menu-panel a:hover,
.menu-panel a:focus-visible {
  background: var(--surface-hover);
  color: var(--text);
}
.menu-panel a.is-active {
  background: var(--accent-soft);
  color: var(--accent);
  font-weight: 600;
}
/* Two-letter language code, replacing the old flag emoji. Flags are a poor
   proxy for a language (and an emoji font lottery across platforms). */
.lang-code {
  flex-shrink: 0;
  min-width: 30px;
  padding: 2px 0;
  border-radius: 5px;
  background: var(--bg-alt);
  color: var(--text-muted);
  font-family: var(--font);
  font-size: 0.6875rem; /* 11px */
  line-height: 16px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-align: center;
  text-transform: uppercase;
}
.menu-panel a.is-active .lang-code,
.drawer-langs a.is-active .lang-code {
  background: var(--accent);
  color: var(--on-accent);
}
.chev {
  font-size: 0.6rem;
  transition: transform var(--t-fast);
}
.menu.is-open .chev {
  transform: rotate(180deg);
}

.hamburger {
  display: inline-flex;
}

/* Mobile drawer */
.drawer {
  position: fixed;
  inset: 0;
  z-index: 120;
  background: rgba(20, 16, 12, 0.55);
  backdrop-filter: blur(3px);
  display: flex;
  justify-content: flex-end;
  animation: fadeIn 0.18s var(--ease);
}
/* Hiding is handled by the global [hidden] rule near the top of this file. */
.drawer-panel {
  width: min(340px, 86vw);
  height: 100%;
  overflow-y: auto;
  overscroll-behavior: contain;
  background: var(--glass-bg);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  border-inline-start: 1px solid var(--border);
  padding: 14px;
  padding-bottom: max(14px, env(safe-area-inset-bottom));
  animation: slideIn 0.24s var(--ease);
}
.drawer-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 10px;
}
.drawer-title {
  font-family: var(--font);
  font-weight: 800;
  font-size: 1rem;
}
.drawer-nav {
  display: grid;
  gap: 2px;
}
.drawer-nav a {
  display: flex;
  align-items: center;
  gap: 12px;
  min-height: 46px;
  padding: 10px 12px;
  border-radius: var(--radius-sm);
  color: var(--text-soft);
  font-weight: 600;
  font-size: 0.9375rem; /* 15px exactly */
  line-height: 1.25;
  transition: background var(--t-fast), color var(--t-fast);
}
.drawer-nav a i {
  width: 18px;
  text-align: center;
  opacity: 0.8;
}
.drawer-nav a:hover,
.drawer-nav a:focus-visible {
  background: var(--surface-hover);
  color: var(--text);
}
.drawer-nav a.is-active {
  background: var(--accent-soft);
  color: var(--accent);
}
.drawer-nav--secondary a {
  font-weight: 500;
  font-size: 0.875rem; /* 14px */
}
.drawer-sep {
  height: 1px;
  background: var(--border);
  margin: 12px 0;
}
.drawer-langs {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 4px;
}
.drawer-langs a {
  display: flex;
  align-items: center;
  gap: 8px;
  min-height: 40px;
  padding: 8px 10px;
  border-radius: var(--radius-sm);
  font-size: 0.8125rem; /* 13px */
  line-height: 1.25;
  color: var(--text-soft);
  transition: background var(--t-fast), color var(--t-fast);
}
.drawer-langs a:hover,
.drawer-langs a:focus-visible {
  background: var(--surface-hover);
  color: var(--text);
}
.drawer-langs a.is-active {
  color: var(--accent);
  background: var(--accent-soft);
  font-weight: 600;
}

/* ── 5. Hero + downloader ────────────────────────────────────────────── */
.hero {
  position: relative;
  padding: 22px 0 32px;
}
.hero-inner {
  position: relative;
  text-align: center;
}

.crumbs {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  flex-wrap: wrap;
  justify-content: center;
  font-size: 0.76rem;
  color: var(--text-muted);
  margin-bottom: 14px;
}
.crumbs a {
  color: var(--text-muted);
}
.crumbs a:hover {
  color: var(--accent);
}
.crumbs i {
  font-size: 0.56rem;
  opacity: 0.6;
}

/* ONE-LINE TITLE.
   `--h1-ch` is a *weighted* character count of the string (CJK, Hangul and
   full-width glyphs counted double), written into the element by the template.
   Dividing the available inline size by it yields the largest type size that
   still fits on one line, so a single rule fits the title to one line in all
   eleven languages instead of a clamp hand-tuned until English happened to fit.

   0.6em is a deliberately conservative average glyph advance: the real figure
   for "Instagram Reels Downloader" in Plus Jakarta Sans ExtraBold is ~0.528em,
   so there is ~13% headroom for a fallback font loading wider.

   There is intentionally NO `white-space: nowrap` here. If the estimate is ever
   short — an unusually wide fallback font, a language we have not measured — a
   nowrap title overflows the viewport and forces a horizontal scrollbar, which
   is far worse than wrapping. With the adaptive size and no nowrap, a title
   that fits renders on one line by itself, and one that cannot fit above the
   readability floor wraps as balanced lines. Verified: "Instagram Reels
   Downloader" stays on one line down to a 320px screen. */
.hero-title {
  margin-bottom: 0.35em;
  color: var(--text);
  font-size: clamp(
    1.15rem,
    calc((min(100vw, var(--wrap)) - var(--pad) * 2) / (var(--h1-ch, 26) * 0.6)),
    2.7rem
  );
}

.hero-tagline {
  max-width: 60ch;
  margin: 0 auto 18px;
  font-size: 1rem;
  color: var(--text-soft);
}

/* TRUST STRIP.
   These four badges used to sit inside the hero, between the tagline and the
   field. The hero was carrying breadcrumb + title + tagline + four badges +
   form + result stage, which buried the one thing a visitor came to do. They
   now live in a slim band directly under the hero: still above the fold on
   desktop, still crawlable, but no longer competing with the input. */
.trust-bar {
  border-block: 1px solid var(--border);
  background: var(--surface-2);
}
.badges {
  list-style: none;
  padding: 12px 0;
  margin: 0;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 8px 18px;
}
.badges li {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font-size: 0.82rem;
  font-weight: 500;
  color: var(--text-soft);
}
.badges i {
  color: var(--success);
  font-size: 0.72rem;
}

/* THE DOWNLOAD FORM.
   Mobile: a single column — field on top, full-width submit under it. The old
   layout put `flex: 1 1 320px` on the field row, which on a 360px screen left
   the input itself about 140px wide once the icon and the Paste button had
   taken their share; that squeeze is what looked "distorted". Here the row is
   simply 100% wide, the input is `min-width: 0` (so it can shrink inside the
   flex row instead of forcing an overflow) and Paste collapses to an icon. */
.dl-form {
  display: flex;
  flex-direction: column;
  gap: 10px;
  max-width: 680px;
  margin: 0 auto;
}

.dl-input-row {
  display: flex;
  align-items: center;
  gap: 4px;
  width: 100%;
  min-width: 0;
  padding: 5px 6px 5px 13px;
  background: var(--surface);
  border: 1.5px solid var(--border);
  border-radius: var(--radius-pill);
  box-shadow: var(--shadow-sm);
  transition: border-color var(--t-fast), box-shadow var(--t-fast);
}
.dl-input-row:focus-within {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
}
.dl-input-row.has-error {
  border-color: var(--danger);
}

.dl-input-icon {
  display: grid;
  place-items: center;
  flex-shrink: 0;
  color: var(--text-muted);
  font-size: 1rem;
}

.dl-input {
  flex: 1 1 auto;
  /* Both of these matter: `min-width: 0` lets the field shrink inside the flex
     row rather than pushing its siblings out, and `width: 100%` stops the
     default ~170px intrinsic input width from setting a floor. */
  min-width: 0;
  width: 100%;
  border: 0;
  outline: 0;
  background: none;
  padding: 12px 2px;
  /* 16px exactly. Anything smaller makes iOS Safari zoom the whole page on
     focus, which is the other half of the "distorted on mobile" report. */
  font-size: 16px;
  text-overflow: ellipsis;
}
.dl-input::placeholder {
  color: var(--text-muted);
}

.dl-paste,
.dl-clear {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  flex-shrink: 0;
  width: 40px;
  height: 40px;
  padding: 0;
  border-radius: var(--radius-pill);
  background: var(--surface-hover);
  color: var(--text-soft);
  font-size: 0.86rem;
  font-weight: 600;
  transition: background var(--t-fast), color var(--t-fast),
    transform var(--t-fast);
}
.dl-paste:hover,
.dl-clear:hover {
  background: var(--accent-soft);
  color: var(--accent);
}
.dl-paste:active,
.dl-clear:active {
  transform: scale(0.93);
}
/* The word "Paste" only appears when there is room for it (sm breakpoint). */
.dl-paste-text {
  display: none;
}

.dl-submit {
  width: 100%;
}

/* Stage: status / error / results */
.dl-stage {
  max-width: 860px;
  margin: 18px auto 0;
  text-align: start;
}

.dl-status {
  display: flex;
  align-items: center;
  gap: 11px;
  padding: 14px 16px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
  font-size: 0.92rem;
  font-weight: 500;
  color: var(--text-soft);
  animation: rise 0.24s var(--ease);
}

.alert {
  display: flex;
  align-items: flex-start;
  flex-wrap: wrap;
  gap: 10px;
  padding: 14px 16px;
  border-radius: var(--radius);
  border: 1px solid transparent;
  font-size: 0.92rem;
  animation: rise 0.24s var(--ease);
}
.alert--error {
  background: var(--danger-soft);
  border-color: color-mix(in srgb, var(--danger) 30%, transparent);
  color: var(--text);
}
.alert--error > i {
  color: var(--danger);
  font-size: 1.1rem;
  margin-top: 3px;
}
.alert > div {
  flex: 1 1 200px;
  min-width: 0;
}
.alert strong {
  display: block;
  font-family: var(--font);
  margin-bottom: 3px;
}
.alert p {
  margin: 0;
  color: var(--text-soft);
  word-break: break-word;
}
.alert [data-retry] {
  flex-shrink: 0;
}

/* ── 6. Result ───────────────────────────────────────────────────────── */
.result-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow);
  overflow: hidden;
  animation: rise 0.3s var(--ease);
}

.result-head {
  display: flex;
  align-items: center;
  gap: 11px;
  padding: 13px 14px;
  border-bottom: 1px solid var(--border);
  background: var(--surface-2);
  flex-wrap: wrap;
}
.result-avatar {
  width: 42px;
  height: 42px;
  border-radius: 50%;
  object-fit: cover;
  background: var(--bg-alt);
  border: 2px solid var(--surface);
  box-shadow: 0 0 0 2px var(--accent-line);
  flex-shrink: 0;
}
.result-who {
  min-width: 0;
  flex: 1 1 140px;
}
.result-name {
  display: flex;
  align-items: center;
  gap: 6px;
  font-family: var(--font);
  font-weight: 700;
  font-size: 0.96rem;
  color: var(--text);
}
.result-name .verified {
  color: #3897f0;
  font-size: 0.8rem;
}
.result-sub {
  font-size: 0.78rem;
  color: var(--text-muted);
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
}
/* Mobile: the header actions take their own full-width row under the avatar. */
.result-actions {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
  width: 100%;
}
.result-actions .btn-primary,
.result-actions .btn-ghost {
  flex: 1 1 auto;
  justify-content: center;
}

.result-caption {
  padding: 12px 14px;
  font-size: 0.88rem;
  color: var(--text-soft);
  border-bottom: 1px solid var(--border);
  max-height: 120px;
  overflow-y: auto;
  white-space: pre-wrap;
  word-break: break-word;
}

.media-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 10px;
  padding: 12px;
  /* Thumbnails keep their own aspect ratio, so cards in a row can differ in
     height. Without this the grid stretches every card to the tallest one and
     leaves a hole under the shorter card's button. */
  align-items: start;
}

.media-item {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  overflow: hidden;
  background: var(--surface-2);
  display: flex;
  flex-direction: column;
  min-width: 0;
  transition: transform var(--t-fast), box-shadow var(--t);
}
.media-item:hover {
  transform: translateY(-2px);
  box-shadow: var(--shadow);
}

/* 4/5 is only the placeholder shape, used until the real one is known: the
   script sets `aspect-ratio` inline from the media's own dimensions (or, when
   Instagram didn't report them, from the loaded preview's intrinsic size). */
.media-thumb {
  position: relative;
  aspect-ratio: 4 / 5;
  background: var(--bg-alt);
  overflow: hidden;
}
/* `contain`, not `cover`: cover scales the frame up until the box is full and
   crops whatever overflows, which reads as a zoomed-in, cut-off preview. Contain
   fits the whole frame at its real aspect ratio. With the box already shaped like
   the media there is usually nothing to letterbox — this is the safety net for
   the cases where the poster image and the video it represents disagree. */
.media-thumb img,
.media-thumb video {
  width: 100%;
  height: 100%;
  object-fit: contain;
  object-position: center;
}
.media-type {
  position: absolute;
  top: 7px;
  inset-inline-start: 7px;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 3px 8px;
  border-radius: var(--radius-pill);
  background: rgba(16, 12, 9, 0.7);
  color: #fff;
  font-size: 0.66rem;
  font-weight: 600;
}
.media-quality {
  position: absolute;
  top: 7px;
  inset-inline-end: 7px;
  padding: 3px 8px;
  border-radius: var(--radius-pill);
  background: var(--accent);
  color: var(--on-accent);
  font-size: 0.64rem;
  font-weight: 700;
}
.media-play {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  color: #fff;
  font-size: 1.9rem;
  text-shadow: 0 2px 12px rgba(0, 0, 0, 0.5);
  background: rgba(16, 12, 9, 0.16);
  transition: background var(--t-fast), opacity var(--t-fast);
}
.media-item:hover .media-play {
  background: rgba(16, 12, 9, 0.28);
}

.media-body {
  padding: 10px;
  display: grid;
  gap: 7px;
}
.media-meta {
  font-size: 0.72rem;
  color: var(--text-muted);
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
}
.media-btns {
  display: grid;
  gap: 6px;
}
.media-btns .btn-primary {
  min-height: 42px;
  padding: 9px 12px;
  font-size: 0.85rem;
}
.media-mini {
  display: flex;
  gap: 6px;
}
.media-mini .btn-ghost {
  flex: 1;
  min-height: 38px;
  padding: 7px 6px;
  font-size: 0.76rem;
}

/* Alternate quality / codec picker */
.fmt {
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface);
  overflow: hidden;
}
.fmt summary {
  padding: 8px 11px;
  cursor: pointer;
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--text-muted);
  list-style: none;
}
.fmt summary::-webkit-details-marker {
  display: none;
}
.fmt summary:hover {
  background: var(--surface-hover);
  color: var(--text);
}
.fmt-list {
  border-top: 1px solid var(--border);
  display: grid;
}
.fmt-list a {
  display: flex;
  align-items: center;
  gap: 8px;
  min-height: 40px;
  padding: 8px 11px;
  font-size: 0.78rem;
  color: var(--text-soft);
  border-bottom: 1px solid var(--border);
}
.fmt-list a:last-child {
  border-bottom: 0;
}
.fmt-list a:hover {
  background: var(--accent-soft);
  color: var(--accent);
}
.fmt-q {
  font-weight: 700;
  min-width: 44px;
}
.fmt-c {
  color: var(--text-muted);
  font-size: 0.71rem;
}
.fmt-warn {
  margin-inline-start: auto;
  color: var(--warning);
  font-size: 0.71rem;
}

.result-foot {
  padding: 12px 14px 15px;
  border-top: 1px solid var(--border);
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
}
.result-note {
  font-size: 0.78rem;
  color: var(--text-muted);
  margin: 0;
  flex: 1 1 220px;
}

/* ── 7. Cards, steps, prose, FAQ ─────────────────────────────────────── */
.cards {
  display: grid;
  grid-template-columns: 1fr;
  gap: 12px;
}

.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 18px;
  box-shadow: var(--shadow-xs);
  transition: transform var(--t-fast), box-shadow var(--t),
    border-color var(--t-fast);
}
.card:hover {
  transform: translateY(-3px);
  box-shadow: var(--shadow);
  border-color: var(--border-strong);
}
.card h3 {
  margin-bottom: 0.4em;
}
.card p {
  margin: 0;
  font-size: 0.92rem;
}

.card-icon {
  display: grid;
  place-items: center;
  width: 42px;
  height: 42px;
  margin-bottom: 13px;
  border-radius: 12px;
  background: var(--accent-soft);
  color: var(--accent);
  font-size: 1.05rem;
}

.card--link {
  display: flex;
  flex-direction: column;
  color: inherit;
}
.card--link:hover {
  color: inherit;
}
.card-cta {
  margin-top: auto;
  padding-top: 12px;
  color: var(--accent);
  font-size: 0.85rem;
  font-weight: 700;
  display: inline-flex;
  align-items: center;
  gap: 7px;
}
.card-cta i {
  transition: transform var(--t-fast);
  font-size: 0.75rem;
}
.card--link:hover .card-cta i {
  transform: translateX(3px);
}

/* Steps */
/* Steps.
   The step count comes from locale data — currently three in all eleven
   languages. The 900px breakpoint used to declare `repeat(4, minmax(0,1fr))`,
   which left an empty fourth cell: every card was squeezed to 3/4 width and the
   row sat off-centre. `auto-fit` sizes to the actual number of items, and the
   capped max-width keeps three cards from stretching absurdly wide on desktop. */
.steps {
  list-style: none;
  padding: 0;
  margin: 0 auto;
  display: grid;
  grid-template-columns: 1fr;
  justify-content: center;
  gap: 12px;
}
.step {
  display: flex;
  gap: 13px;
  height: 100%;
  padding: 18px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-xs);
}
.step h3 {
  margin-bottom: 0.3em;
}
.step p {
  margin: 0;
  font-size: 0.92rem;
}
.step-num {
  flex-shrink: 0;
  width: 32px;
  height: 32px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: var(--accent-soft);
  color: var(--accent);
  border: 1px solid var(--accent-line);
  font-family: var(--font);
  font-weight: 800;
  font-size: 0.92rem;
}

/* Prose.
   CENTRED, single column. This used to be `1fr + 300px` with a sticky sidebar,
   which pushed the article text off-centre on every desktop screen — the page
   read as left-weighted even though `.wrap` itself was centred. The sidebar now
   holds only an ad slot, so it moves below the article and the reading column
   sits in the middle of the page where it belongs. */
.prose-wrap {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  justify-items: center;
  gap: 26px;
  align-items: start;
}
.prose {
  width: 100%;
  max-width: var(--wrap-prose);
  min-width: 0;
}
.prose h2 {
  margin-top: 1.6em;
  font-size: clamp(1.2rem, 4vw, 1.55rem);
}
.prose h2:first-child {
  margin-top: 0;
}
.prose h3 {
  margin-top: 1.3em;
}
.prose p,
.prose li {
  font-size: 1rem;
  color: var(--text-soft);
}
.prose a {
  text-decoration: underline;
  text-underline-offset: 2px;
}
.prose blockquote {
  margin: 1.4em 0;
  padding: 2px 0 2px 16px;
  border-inline-start: 3px solid var(--accent-line);
  color: var(--text-soft);
  font-style: italic;
}
.prose code {
  background: var(--bg-alt);
  padding: 2px 6px;
  border-radius: 6px;
  font-size: 0.88em;
  word-break: break-word;
}

.check-list,
.tip-list {
  list-style: none;
  padding: 0;
  display: grid;
  gap: 8px;
  margin-bottom: 1.4em;
}
.check-list li,
.tip-list li {
  display: flex;
  gap: 10px;
  align-items: flex-start;
  padding: 11px 13px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  font-size: 0.93rem;
  color: var(--text-soft);
}
/* Tinted, not plain: the emerald and yellow washes let the two list kinds be
   told apart at a glance without relying on the icon alone. */
.check-list li {
  background: var(--success-soft);
  border-color: color-mix(in srgb, var(--success) 22%, transparent);
}
.tip-list li {
  background: var(--warning-soft);
  border-color: color-mix(in srgb, var(--warning) 22%, transparent);
}
.check-list i {
  color: var(--success);
  margin-top: 4px;
}
.tip-list i {
  color: var(--warning);
  margin-top: 4px;
}

.aside {
  display: grid;
  gap: 16px;
  min-width: 0;
}

/* ── The app promo. Lives in its own band near the foot of the page. ──── */
.promo {
  padding: 20px;
  border-radius: var(--radius-lg);
  background: var(--surface);
  border: 1px solid var(--border);
  box-shadow: var(--shadow-sm);
}
.promo h3 {
  margin-bottom: 0.5em;
}
.promo p {
  font-size: 0.9rem;
}

.app-band {
  padding: 34px 0;
  background: var(--bg-alt);
  border-block: 1px solid var(--border);
}
.app-band-inner {
  display: grid;
  gap: 16px;
  align-items: center;
  text-align: center;
  max-width: 760px;
  margin-inline: auto;
}
.app-band-icon {
  display: grid;
  place-items: center;
  width: 54px;
  height: 54px;
  margin-inline: auto;
  border-radius: 16px;
  background: var(--accent-soft);
  color: var(--accent);
  border: 1px solid var(--accent-line);
  font-size: 1.5rem;
}
.app-band h2 {
  margin: 0;
  font-size: clamp(1.25rem, 4.4vw, 1.7rem);
}
.app-band p {
  margin: 0;
  font-size: 0.96rem;
  color: var(--text-soft);
}
.app-band-cta {
  display: flex;
  justify-content: center;
}

/* FAQ */
.faq {
  display: grid;
  gap: 8px;
}
.faq-item {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  overflow: hidden;
  transition: border-color var(--t-fast), box-shadow var(--t);
}
.faq-item[open] {
  border-color: var(--border-strong);
  box-shadow: var(--shadow-sm);
}
.faq-item summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 14px 16px;
  cursor: pointer;
  font-family: var(--font);
  font-weight: 600;
  font-size: 0.96rem;
  list-style: none;
}
.faq-item summary::-webkit-details-marker {
  display: none;
}
.faq-item summary:hover {
  background: var(--surface-hover);
}
.faq-item summary i {
  flex-shrink: 0;
  color: var(--accent);
  font-size: 0.76rem;
  transition: transform var(--t);
}
.faq-item[open] summary i {
  transform: rotate(45deg);
}
.faq-answer {
  padding: 0 16px 14px;
  animation: fadeIn 0.22s var(--ease);
}
.faq-answer p {
  margin: 0;
  font-size: 0.93rem;
}

/* ── 8. Footer ───────────────────────────────────────────────────────── */
.site-footer {
  background: var(--bg-alt);
  border-top: 1px solid var(--border);
  padding: 34px 0 22px;
  padding-bottom: max(22px, env(safe-area-inset-bottom));
}
.footer-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 24px;
  margin-bottom: 24px;
}
.footer-brand {
  min-width: 0;
}
.footer-tagline {
  font-size: 0.88rem;
  margin: 10px 0 14px;
  max-width: 34ch;
}
.footer-col h3 {
  font-size: 0.8rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--text-muted);
  margin-bottom: 10px;
}
.footer-col ul {
  list-style: none;
  padding: 0;
  margin: 0;
  display: grid;
  gap: 7px;
}
.footer-col a {
  display: inline-block;
  padding: 2px 0;
  color: var(--text-soft);
  font-size: 0.9rem;
}
.footer-col a:hover {
  color: var(--accent);
}
.play-badge img {
  border-radius: 8px;
}

/* The site-wide disclaimer. Given a real box rather than a grey footnote:
   an AdSense reviewer, and a visitor wondering whether this is legitimate,
   both need to find it without hunting. */
.disclaimer {
  margin: 0 0 14px;
  padding: 14px 16px;
  border: 1px solid var(--border);
  border-inline-start: 3px solid var(--accent);
  border-radius: var(--radius);
  background: var(--surface);
}
.disclaimer p {
  margin: 0;
  font-size: 0.82rem;
  line-height: 1.7;
  color: var(--text-soft);
}
.disclaimer strong {
  color: var(--text);
  font-family: var(--font);
  font-weight: 600;
}

.footer-disclaimer {
  font-size: 0.78rem;
  color: var(--text-muted);
  line-height: 1.6;
  border-top: 1px solid var(--border);
  padding-top: 16px;
  margin-bottom: 8px;
}
.footer-copy {
  font-size: 0.78rem;
  color: var(--text-muted);
  margin: 0;
  padding-top: 14px;
  border-top: 1px solid var(--border);
}

/* ── 9. Ads ──────────────────────────────────────────────────────────── */
.ad-slot {
  position: relative;
  margin: 22px auto;
  max-width: var(--wrap);
  padding-inline: var(--pad);
  text-align: center;
  min-height: 90px;
}
.ad-slot--in-article {
  margin: 28px 0;
  padding-inline: 0;
}
.ad-slot--sidebar {
  margin: 0;
  padding-inline: 0;
  min-height: 250px;
}
.ad-label {
  display: block;
  font-size: 0.62rem;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--text-muted);
  margin-bottom: 6px;
}

/* ── Misc ────────────────────────────────────────────────────────────── */
.toast {
  position: fixed;
  inset-inline: 0;
  bottom: max(18px, env(safe-area-inset-bottom));
  display: flex;
  justify-content: center;
  z-index: 200;
  pointer-events: none;
  padding-inline: var(--pad);
}
.toast span {
  background: var(--text);
  color: var(--bg);
  padding: 10px 18px;
  border-radius: var(--radius-pill);
  font-size: 0.86rem;
  font-weight: 600;
  box-shadow: var(--shadow-lg);
  animation: toastIn 0.24s var(--ease);
}

.empty-state {
  text-align: center;
  padding: 48px 16px;
  color: var(--text-muted);
}
.empty-state i {
  font-size: 2.2rem;
  margin-bottom: 12px;
  opacity: 0.5;
  display: block;
}

/* Blog */
.post-list {
  display: grid;
  grid-template-columns: 1fr;
  gap: 14px;
}
.post-card {
  display: flex;
  flex-direction: column;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  overflow: hidden;
  color: inherit;
  transition: transform var(--t-fast), box-shadow var(--t);
}
.post-card:hover {
  transform: translateY(-3px);
  box-shadow: var(--shadow);
  color: inherit;
}
.post-cover {
  aspect-ratio: 16 / 9;
  object-fit: cover;
  background: var(--bg-alt);
  width: 100%;
}
.post-body {
  padding: 16px;
  display: flex;
  flex-direction: column;
  flex: 1;
}
.post-meta {
  font-size: 0.76rem;
  color: var(--text-muted);
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
  margin-bottom: 8px;
}
.post-tags {
  display: flex;
  gap: 6px;
  flex-wrap: wrap;
  margin-top: auto;
  padding-top: 12px;
}
.post-tags span {
  font-size: 0.72rem;
  padding: 3px 9px;
  border-radius: var(--radius-pill);
  background: var(--accent-soft);
  color: var(--accent);
  font-weight: 600;
}

/* ── 10. Motion ──────────────────────────────────────────────────────── */
@keyframes rise {
  from {
    opacity: 0;
    transform: translateY(10px);
  }
}
@keyframes fadeIn {
  from {
    opacity: 0;
  }
}
@keyframes slideIn {
  from {
    transform: translateX(26px);
  }
}
@keyframes toastIn {
  from {
    opacity: 0;
    transform: translateY(12px);
  }
}

/* Scroll reveal. The element is only pre-hidden once JS has confirmed it can
   observe it (`.js-reveal` on <html>), so with JS off or broken the content is
   simply visible — a reveal animation must never be able to hide content. */
.js-reveal .reveal {
  opacity: 0;
  transform: translateY(14px);
  transition: opacity 0.5s var(--ease), transform 0.5s var(--ease);
  transition-delay: var(--reveal-delay, 0ms);
  will-change: opacity, transform;
}
.js-reveal .reveal.is-visible {
  opacity: 1;
  transform: none;
  will-change: auto;
}

/* ── 11. Breakpoints — min-width ONLY (mobile first) ────────────────── */

/* sm: large phones and up. Room for the Paste label and a 3-up media grid. */
@media (min-width: 480px) {
  .dl-paste {
    width: auto;
    padding: 0 14px;
    gap: 7px;
  }
  .dl-paste-text {
    display: inline;
  }
  .media-grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 12px;
  }
  .footer-grid {
    grid-template-columns: 1fr 1fr;
  }
}

/* md: small tablets. The submit button joins the field row. */
@media (min-width: 640px) {
  :root {
    --pad: 20px;
  }
  .section {
    padding: 56px 0;
  }
  .hero {
    padding: 30px 0 44px;
  }
  .dl-form {
    flex-direction: row;
    align-items: center;
  }
  .dl-input-row {
    flex: 1 1 auto;
  }
  .dl-submit {
    width: auto;
    flex: 0 0 auto;
    min-width: 150px;
  }
  .cards {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 16px;
  }
  .steps {
    grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
    gap: 16px;
    max-width: 720px;
  }
  .post-list {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 18px;
  }
  .result-head {
    flex-wrap: nowrap;
  }
  .result-actions {
    width: auto;
    margin-inline-start: auto;
  }
  .result-actions .btn-primary,
  .result-actions .btn-ghost {
    flex: 0 0 auto;
  }
  .media-grid {
    grid-template-columns: repeat(auto-fill, minmax(170px, 1fr));
    padding: 16px;
    gap: 14px;
  }
  .app-band {
    padding: 46px 0;
  }
  .app-band-inner {
    grid-template-columns: auto 1fr auto;
    text-align: start;
    gap: 22px;
    max-width: none;
  }
  .app-band-icon {
    margin-inline: 0;
  }
  .site-footer {
    padding-top: 46px;
  }
}

/* lg: the primary nav fits, so the drawer and hamburger retire. */
@media (min-width: 900px) {
  :root {
    --header-h: 64px;
  }
  .header-nav {
    display: flex;
    align-items: center;
    gap: 2px;
    margin-inline-start: auto;
    overflow-x: auto;
    scrollbar-width: none;
  }
  .header-nav::-webkit-scrollbar {
    display: none;
  }
  .header-actions {
    margin-inline-start: 6px;
  }
  .hamburger {
    display: none;
  }
  .menu-btn-label {
    display: inline;
  }
  .section {
    padding: 72px 0;
  }
  .section-head {
    margin-bottom: 40px;
  }
  .cards {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
  /* auto-fit, not a hard-coded column count: three steps in a four-column grid
     is what made these cards look broken. */
  .steps {
    grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
    max-width: 1000px;
  }
  .post-list {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
  .footer-grid {
    grid-template-columns: 1.6fr repeat(3, 1fr);
    gap: 30px;
  }
}

/* xl: nothing to re-flow — the article stays a single centred column at every
   width now. The aside (ad slot only) simply sits beneath it, centred too. */
@media (min-width: 1024px) {
  .aside {
    width: 100%;
    max-width: var(--wrap-prose);
  }
}

/* Fine pointers only: hover lifts are noise on a touch screen, where :hover
   sticks after a tap. */
@media (hover: none) {
  .card:hover,
  .media-item:hover,
  .post-card:hover {
    transform: none;
    box-shadow: var(--shadow-xs);
  }
}

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
  /* Never leave revealed content stuck at opacity 0. */
  .js-reveal .reveal {
    opacity: 1;
    transform: none;
  }
}

/* ── 12. RTL + print ─────────────────────────────────────────────────── */
[dir="rtl"] .card-cta i,
[dir="rtl"] .crumbs i {
  transform: scaleX(-1);
}
[dir="rtl"] .card--link:hover .card-cta i {
  transform: scaleX(-1) translateX(3px);
}
[dir="rtl"] .drawer {
  justify-content: flex-start;
}
[dir="rtl"] .drawer-panel {
  animation-name: slideInRtl;
}
[dir="rtl"] .menu-panel {
  transform-origin: top left;
}
@keyframes slideInRtl {
  from {
    transform: translateX(-26px);
  }
}

@media print {
  .site-header,
  .site-footer,
  .drawer,
  .ad-slot,
  .dl-form,
  .aside,
  .app-band {
    display: none !important;
  }
  body {
    background: #fff;
    color: #000;
  }
  .reveal {
    opacity: 1 !important;
    transform: none !important;
  }
}
