/* ==========================================================================
   20/20 — the2020.app
   One stylesheet, no framework, no build step.

   The palette below is the app's default True Tone theme, lifted from
   src/theme/originalTheme.ts. These are the only colour definitions in the
   site — swap them here and the whole site follows.
   ========================================================================== */

/* --------------------------------------------------------------------------
   Fonts — the app's own, self-hosted.

   Outfit 700 for display and Inter for body is exactly what the app uses
   (app.json loads Outfit_700Bold; Inter 400/500 carry most of the UI). The
   files are converted from the TTFs already in node_modules/@expo-google-fonts,
   so the site and the app are running the identical typefaces rather than
   two that merely look similar.

   Self-hosted rather than pulled from Google, which means no third-party
   request on any page load. Both are SIL Open Font License — see
   assets/fonts/OFL-Inter.txt and OFL-Outfit.txt.
   -------------------------------------------------------------------------- */

@font-face {
  font-family: "Outfit";
  src: url("assets/fonts/outfit-700.woff") format("woff");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "Inter";
  src: url("assets/fonts/inter-400.woff") format("woff");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "Inter";
  src: url("assets/fonts/inter-500.woff") format("woff");
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}

:root {
  /* True Tone — src/theme/originalTheme.ts */
  --bg:          #fff2e1;  /* categoryCardBackground — page ground, so the
                              app screenshots (on #efdfcc) stand off it */
  --card:        #efdfcc;  /* colors.background      — raised surfaces */
  --heading:     #2d2f78;  /* colors.heading         — navy */
  --subheading:  #2562d5;  /* colors.subheading      — brighter blue */
  --logo:        #6d1eb2;  /* colors.logo            — the mark's purple */
  --accent:      #fdd106;  /* goButtonCircle         — the gold */
  --muted:       #8b6639;  /* searchBarPlaceholder   — warm brown, small print */
  --mauve:       #726383;  /* categoryLabel          — secondary labels */
  --rule:        rgba(45, 47, 120, .14);

  --measure: 34rem;        /* ~70 characters — legal + FAQ body */
  --page:    72rem;
  --gutter:  clamp(1.25rem, 5vw, 4rem);

  --font-display: "Outfit", "Trebuchet MS", sans-serif;
  --font-body: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
               "Helvetica Neue", Arial, sans-serif;
}

*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--heading);
  font-family: var(--font-body);
  font-size: 1.0625rem;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}

/* Outfit 700 is for headings only — never body copy. */
h1, h2, h3 {
  font-family: var(--font-display);
  font-weight: 700;
  line-height: 1.05;
  letter-spacing: -0.02em;
  margin: 0;
}

a { color: var(--subheading); }
a:focus-visible,
button:focus-visible { outline: 3px solid var(--logo); outline-offset: 3px; border-radius: 4px; }

img, svg { max-width: 100%; height: auto; }

.wrap { max-width: var(--page); margin: 0 auto; padding-inline: var(--gutter); }

.skip-link {
  position: absolute; left: -9999px;
  background: var(--card); color: var(--heading);
  padding: .75rem 1rem; border-radius: 8px;
}
.skip-link:focus { left: var(--gutter); top: 1rem; z-index: 10; }

/* ---------- header ---------- */

.site-header { padding-block: 1.75rem 0; }
.site-header .wrap { display: flex; align-items: center; justify-content: space-between; gap: 1rem; }
.site-header .brand { display: inline-flex; align-items: center; gap: .6rem; text-decoration: none; }
.site-header .brand img { width: 44px; }
.site-header .brand span {
  font-family: var(--font-display); font-weight: 700;
  font-size: 1.1rem; color: var(--heading); letter-spacing: -0.01em;
}
.site-header nav { display: flex; gap: 1.25rem; font-size: .95rem; }
.site-header nav a { color: var(--mauve); text-decoration: none; }
.site-header nav a:hover { color: var(--heading); text-decoration: underline; }

/* ---------- hero ---------- */

.hero { padding-block: clamp(2.5rem, 7vw, 5.5rem) clamp(3rem, 8vw, 6rem); }
.hero .wrap {
  display: grid;
  grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
  gap: clamp(2rem, 6vw, 4.5rem);
  align-items: center;
}
.hero-logo { justify-self: center; width: min(100%, 19.8rem); }

/* "Hindsight is 20/20." is the widest line on the site and must never break
   mid-sentence. Measured in Outfit 700: it needs 827px per 100px of font size,
   so 529px at the 4rem cap — comfortably inside the 555px copy column at the
   72rem page width. The floor is set so it still holds one line at 375px. */
.hero h1 { font-size: clamp(2.35rem, 5vw, 4rem); color: var(--heading); }
.hero h1 .first,
.hero h1 .second { display: block; text-wrap: balance; }
.hero h1 .second { color: var(--logo); }

.lede { font-size: clamp(1.05rem, 1.9vw, 1.25rem); max-width: 32rem; margin: 1.5rem 0 0; }

.categories { margin: 1rem 0 0; font-size: .95rem; color: var(--muted); }

/* ---------- download row ---------- */

/* Two rows: badges on top, the QR beneath them on the left with its prompt
   alongside on the right. Explicit placement because the prompt comes before
   the QR in the markup (it reads better that way) but sits after it visually. */
.download {
  margin-top: clamp(2rem, 4vw, 2.75rem);
  display: grid;
  grid-template-columns: auto auto minmax(0, 1fr);
  gap: clamp(1.25rem, 3vw, 2rem) clamp(1rem, 2.2vw, 1.5rem);
  align-items: end;
  justify-items: start;
}
.download .badges   { grid-column: 1; grid-row: 1; }
.download .qr       { grid-column: 2; grid-row: 2; margin-left: 6rem; }
.download .qr-prompt{ grid-column: 2; grid-row: 1; }
.badges { display: flex; flex-direction: column; gap: .75rem; }

.badge {
  display: inline-flex; align-items: center; gap: .7rem;
  background: var(--heading); color: var(--bg);
  text-decoration: none;
  padding: .7rem 1.15rem; border-radius: 10px;
  min-width: 11.5rem;
  transition: transform .15s ease;
}
.badge:hover { transform: translateY(-1px); }
.badge svg { width: 22px; flex: none; fill: currentColor; }
.badge span { display: block; line-height: 1.15; }
.badge .small { font-size: .65rem; text-transform: uppercase; letter-spacing: .08em; opacity: .8; }
.badge .big { font-size: 1.02rem; font-weight: 600; }

/* Official store badges (Apple's own artwork). Apple: at least 40px tall, clear space of a
   quarter of the height, which the .75rem gap between badges provides. */
.store-badge { display: inline-block; line-height: 0; transition: transform .15s ease; }
.store-badge:hover { transform: translateY(-1px); }
.store-badge img { width: 11.5rem; height: auto; display: block; } /* same width as .badge (min-width 11.5rem) */

/* Until the store URLs exist the badges are inert — see site/README.md. */
.badge[aria-disabled="true"] { opacity: .45; pointer-events: none; }

.qr { margin: 0; position: relative; }
.qr img { width: 7.5rem; border-radius: 10px; display: block; }

/* Hooks from the prompt round to the QR. Same muted brown as the prompt. */
.download .arrow {
  position: absolute;
  left: 100%;
  top: -4.4rem;
  width: 7.5rem; height: auto;
  display: block;
  fill: none;
  stroke: var(--muted);
  stroke-width: 2.2;
  stroke-linecap: round;
  stroke-linejoin: round;
  opacity: .85;
}

/* Prompt sits beside the badges, above the QR. */
.qr-prompt { text-align: left; padding-bottom: .35rem; }
.qr-prompt p {
  margin: 0;
  font-size: .85rem; line-height: 1.35; color: var(--muted);
}
/* The QR is useless on the device it points to, so it is hidden by default and
   only shown to something that is actually a computer. Width alone would leak
   it onto tablets and large phones in landscape, so this also requires a fine
   pointer (mouse/trackpad) and real hover — touch devices report neither. */
.qr,
.qr-prompt,
.download .arrow { display: none; }

@media (min-width: 768px) and (pointer: fine) and (hover: hover) {
  .qr { display: block; }
  .qr-prompt { display: block; }
  .download .arrow { display: block; }
}

/* ---------- feature sections ---------- */

.feature { padding-block: clamp(2.5rem, 6vw, 4.5rem); }
.feature .wrap {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: clamp(2rem, 6vw, 5rem);
  align-items: center;
}
/* .shot is nested inside .screens now, so the flip has to target both — the
   grid item is whichever of the two is a direct child of .wrap. */
.feature.flip > .wrap > .shot,
.feature.flip > .wrap > .screens { order: 2; }
.feature h2 { font-size: clamp(1.6rem, 3.2vw, 2.2rem); }
.feature p { margin: .9rem 0 0; max-width: 30rem; }

/* Phone frame — 9:19.5, the app's own aspect. Swap the inner img, keep the frame. */
.shot {
  position: relative;   /* the click-to-advance overlay sizes against this;
                          without it the overlay covers the whole page */
  justify-self: center;
  width: min(100%, 17rem);
  aspect-ratio: 9 / 19.5;
  background: var(--card);
  border-radius: 28px;
  border: 1px solid var(--rule);
  box-shadow: 0 18px 40px rgba(171, 133, 46, .16);
  overflow: hidden;
  display: grid; place-items: center;

}
/* contain, not cover. The screenshots are 600x1301 and the frame is 9/19.5, so
   the two agree to within a rounding error and nothing is letterboxed in
   practice — but contain guarantees a screenshot is never silently cropped,
   which cover would do the moment someone swaps in an image at a different
   ratio. A frame that shows slightly less than the full width is a smaller
   problem than one that quietly eats the top of the screen. */
/* The image carries the frame's corners itself. Rounding the IMAGE rather than
   clipping it with an ancestor is what finally settles the iOS flash: there is
   nothing left to clip, so it does not matter whether Safari clips a composited
   layer to its parent's radius. A -webkit-mask on the stack was tried first and
   made it worse — a mask forces its own compositing layer, which is the thing
   causing the trouble in the first place. */
.shot img {
  width: 100%; height: 100%;
  object-fit: contain;
  border-radius: inherit;
}

/* ---------- slideshow inside a phone frame ---------- */

/* Nothing moves on its own — the reader steps through with the labels below.
   The checked radio decides which slide is opaque. */
/* position: relative is LOAD-BEARING, not tidiness. The hidden radios below are
   absolutely positioned; without a positioned ancestor they resolve against the
   initial containing block, i.e. the top of the page. Clicking a dot focuses one,
   the browser scrolls the focused element into view, and the page jumps to a
   seemingly arbitrary place. Anchoring them here keeps the focus target inside
   the section you are already looking at. */
.screens { position: relative; justify-self: center; width: min(100%, 17rem); }
.screen-radio {
  position: absolute; top: 0; left: 0;
  width: 1px; height: 1px;
  clip-path: inset(50%); overflow: hidden;
}
.screens .shot { width: 100%; }

/* Absolutely filling the frame rather than height:100% on a centred grid item.
   .shot uses place-items:center, which stops its child stretching, so height:100%
   resolves against a content-sized box — Chrome copes, Safari has been seen to
   collapse it and leave the screenshot floating in a part-empty frame. inset:0
   does not depend on how the parent chose to size its children. */
/* Safari does not clip a COMPOSITED child to an ancestor's border-radius. The
   slides fade via opacity, which promotes them to their own layer, so mid
   transition the layer escaped the rounded frame: square corners for an instant
   and an edge that read as a flash. overflow:hidden on the frame does not fix
   it. isolation forces a stacking context and the -webkit-mask is the
   long-standing incantation that makes Safari clip descendants to the radius.
   It lives HERE rather than on .shot deliberately: a mask clips the element's
   own box-shadow too, and .shot's shadow is what lifts the phone off the page.
   border-radius: inherit also has to be chained the whole way down, or .slide
   would inherit zero from an unrounded .slides. */
.slides {
  position: absolute; inset: 0;
  border-radius: inherit;
  overflow: hidden;
}
.slides .slide {
  position: absolute; inset: 0;
  display: grid; place-items: center;
  /* Belt and braces with the mask above: round the layer itself, so even if a
     browser fails to clip it to the frame it still has the frame's corners
     rather than square ones. */
  border-radius: inherit;
  overflow: hidden;
  opacity: 0;
  transition: opacity .35s ease;
}

/* Touch devices get an instant swap instead of the crossfade.
   The fade is what promotes a slide to its own compositing layer, and on iOS
   that layer is not clipped to the frame's rounded corners — the corner squared
   off for an instant and the edge read as a flash. Masking the stack was not
   enough on a real phone, so the honest fix is to remove the layer rather than
   keep trying to clip it. Desktop keeps the crossfade, where it looks right and
   the bug does not occur. */
@media (hover: none) {
  .slides .slide { transition: none; }
}

#sc1:checked ~ .shot .slides .slide:nth-child(1),
#sc2:checked ~ .shot .slides .slide:nth-child(2),
#sc3:checked ~ .shot .slides .slide:nth-child(3),
#sc4:checked ~ .shot .slides .slide:nth-child(4),
#sc5:checked ~ .shot .slides .slide:nth-child(5),
#en1:checked ~ .shot .slides .slide:nth-child(1),
#en2:checked ~ .shot .slides .slide:nth-child(2),
#th1:checked ~ .shot .slides .slide:nth-child(1),
#th2:checked ~ .shot .slides .slide:nth-child(2),
#th3:checked ~ .shot .slides .slide:nth-child(3),
#th4:checked ~ .shot .slides .slide:nth-child(4),
#th5:checked ~ .shot .slides .slide:nth-child(5),
#th6:checked ~ .shot .slides .slide:nth-child(6) { opacity: 1; }

/* Invisible click target over the screen — advances one step, last wraps to
   first. Sits above the slides but the dots still sit above it. */
.advance .adv {
  position: absolute; inset: 0; z-index: 2;
  display: none; cursor: pointer;

  /* THIS is the iOS "flash between slides", and it was never the slideshow.
     Safari paints a translucent grey rectangle over a tapped label's box. This
     label covers the whole screenshot, so the highlight is a full-frame,
     SQUARE-cornered grey layer for an instant — which is exactly what it looked
     like: a layer in between, and the corner going square. Android Chrome does
     not draw it, hence iOS only, and it survived removing lazy loading, masking
     the stack and disabling the crossfade because none of those were the cause.
     Found by building a stripped-down copy that did not flash and diffing. */
  -webkit-tap-highlight-color: transparent;
}
#sc1:checked ~ .shot .adv:nth-child(1),
#sc2:checked ~ .shot .adv:nth-child(2),
#sc3:checked ~ .shot .adv:nth-child(3),
#sc4:checked ~ .shot .adv:nth-child(4),
#sc5:checked ~ .shot .adv:nth-child(5),
#en1:checked ~ .shot .adv:nth-child(1),
#en2:checked ~ .shot .adv:nth-child(2),
#th1:checked ~ .shot .adv:nth-child(1),
#th2:checked ~ .shot .adv:nth-child(2),
#th3:checked ~ .shot .adv:nth-child(3),
#th4:checked ~ .shot .adv:nth-child(4),
#th5:checked ~ .shot .adv:nth-child(5),
#th6:checked ~ .shot .adv:nth-child(6) { display: block; }

/* ---------- the step labels ---------- */

.dots {
  display: flex; flex-wrap: wrap; justify-content: center;
  gap: .55rem; margin-top: 1.1rem; align-items: center;
}
/* Plain dots. The step names stay in the markup for screen readers. */
.dots label {
  cursor: pointer;
  /* Same reason as .adv above — a tapped dot would otherwise flash a grey square
     behind a 9px circle, which looks broken at that size. */
  -webkit-tap-highlight-color: transparent;
  width: 9px; height: 9px; border-radius: 50%;
  background: var(--rule);
  transition: background-color .2s ease, transform .2s ease;
}
.dots label:hover { background: var(--mauve); transform: scale(1.15); }
.dots label span {
  position: absolute; width: 1px; height: 1px;
  clip-path: inset(50%); overflow: hidden; white-space: nowrap;
}

#sc1:checked ~ .dots label:nth-child(1),
#sc2:checked ~ .dots label:nth-child(2),
#sc3:checked ~ .dots label:nth-child(3),
#sc4:checked ~ .dots label:nth-child(4),
#sc5:checked ~ .dots label:nth-child(5),
#en1:checked ~ .dots label:nth-child(1),
#en2:checked ~ .dots label:nth-child(2),
#th1:checked ~ .dots label:nth-child(1),
#th2:checked ~ .dots label:nth-child(2),
#th3:checked ~ .dots label:nth-child(3),
#th4:checked ~ .dots label:nth-child(4),
#th5:checked ~ .dots label:nth-child(5),
#th6:checked ~ .dots label:nth-child(6) { background: var(--heading); }

/* Keyboard users land on the radio, so show the focus ring on its label. */
.screen-radio:focus-visible + .screen-radio ~ .dots label,
.screen-radio:focus-visible ~ .dots label { outline: none; }
#sc1:focus-visible ~ .dots label:nth-child(1),
#sc2:focus-visible ~ .dots label:nth-child(2),
#sc3:focus-visible ~ .dots label:nth-child(3),
#sc4:focus-visible ~ .dots label:nth-child(4),
#en1:focus-visible ~ .dots label:nth-child(1),
#en2:focus-visible ~ .dots label:nth-child(2),
#th1:focus-visible ~ .dots label:nth-child(1),
#th2:focus-visible ~ .dots label:nth-child(2),
#th3:focus-visible ~ .dots label:nth-child(3),
#th4:focus-visible ~ .dots label:nth-child(4),
#th5:focus-visible ~ .dots label:nth-child(5),
#th6:focus-visible ~ .dots label:nth-child(6),
#sc5:focus-visible ~ .dots label:nth-child(5) {
  outline: 3px solid var(--logo); outline-offset: 2px;
}

.slides .slide img { width: 100%; height: 100%; object-fit: cover; }

/* Placeholder label — goes away with the real screenshots. */
.slides .slide span {
  font-family: var(--font-display); font-weight: 700;
  font-size: 2rem; color: var(--mauve);
}

/* With animation off, the first slide stays put rather than the frame going
   blank — every slide sits at opacity 0 until its keyframes run. */
.shot .placeholder {
  font-size: .8rem; color: var(--mauve); text-align: center;
  padding: 1.5rem; line-height: 1.5;
}

/* ---------- privacy ---------- */

/* A full-bleed band on the raised surface, which is what separates it from the feature
   sections above without needing a rule or a heavier heading. No phone frame here on purpose:
   the point is a claim about the app, not a picture of it. */
.privacy {
  background: var(--card);
  padding-block: clamp(3rem, 7vw, 4.5rem);
}
.privacy h2 { font-size: clamp(1.6rem, 3.2vw, 2.2rem); }
.privacy .lede {
  margin: .9rem 0 0;
  max-width: 34rem;
  font-size: 1.05rem;
}
.privacy .points {
  list-style: none;
  margin: clamp(1.75rem, 4vw, 2.5rem) 0 0;
  padding: 0;
  display: grid;
  /* Explicitly two columns rather than auto-fit: with four points, auto-fit finds room for
     three on a wide screen and leaves the fourth stranded on its own row. A fixed pair keeps
     it 2x2, which is the shape the content actually is. */
  grid-template-columns: 1fr;
  gap: clamp(1.25rem, 3vw, 2rem) clamp(2rem, 5vw, 4rem);
}
@media (min-width: 40rem) {
  .privacy .points { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
.privacy .points li { max-width: 26rem; }
.privacy .points strong { display: block; color: var(--heading); }
.privacy .points li { color: var(--muted); line-height: 1.55; }

/* ---------- closing ---------- */

.closing { padding-block: clamp(3rem, 7vw, 5rem); text-align: center; }
.closing .badges { flex-direction: row; justify-content: center; flex-wrap: wrap; }

/* ---------- prose (legal + support) ---------- */

.prose { padding-block: clamp(2.5rem, 6vw, 4rem) clamp(3rem, 7vw, 5rem); }
.prose .wrap { max-width: calc(var(--measure) + var(--gutter) * 2); }
.prose h1 { font-size: clamp(2rem, 5vw, 2.9rem); }
.prose h2 {
  font-size: 1.2rem; margin-top: 2.5rem;
  padding-top: 1.5rem; border-top: 1px solid var(--rule);
}
.prose ul { padding-left: 1.15rem; }
.prose li { margin-block: .4rem; }
.updated { color: var(--muted); font-size: .9rem; margin-top: .75rem; }

.button {
  display: inline-block;
  background: var(--heading); color: var(--bg);
  text-decoration: none;
  padding: .7rem 1.2rem; border-radius: 10px;
  font-weight: 600;
}
.button:hover { opacity: .9; }

/* A note we wrote ourselves, set apart from generated legal text. */
.callout {
  background: var(--card);
  border-left: 4px solid var(--logo);
  border-radius: 0 10px 10px 0;
  padding: 1.1rem 1.3rem;
  margin: 2rem 0;
}
.callout h2 { margin-top: 0; border-top: 0; padding-top: 0; font-size: 1.1rem; }
.callout p:first-of-type { margin-top: .6rem; }

/* ---------- legal pages ---------- */

/* Long documents: slightly smaller type and a numbered contents list. */
.legal p, .legal li { font-size: .95rem; }
.legal h3 { font-size: 1.02rem; margin-top: 1.75rem; }
.legal ol.toc { padding-left: 1.3rem; }
.legal ol.toc li { margin-block: .3rem; }

/* The US-categories table is wide — let it scroll rather than break the page. */
.table-scroll { overflow-x: auto; margin: 1.25rem 0; }
.legal table {
  border-collapse: collapse;
  width: 100%; min-width: 34rem;
  font-size: .85rem;
}
.legal th,
.legal td {
  border: 1px solid var(--rule);
  padding: .55rem .7rem;
  text-align: left;
  vertical-align: top;
}
.legal th { background: var(--card); font-weight: 600; }
.legal td:last-child { text-align: center; white-space: nowrap; }

/* Marks copy that has not been supplied yet. Delete the block with the text. */
.todo {
  background: var(--card);
  border-left: 4px solid var(--accent);
  padding: 1rem 1.15rem; border-radius: 0 10px 10px 0;
  color: var(--mauve); font-size: .95rem;
}
.todo strong { color: var(--heading); }

/* ---------- footer ---------- */

.site-footer {
  border-top: 1px solid var(--rule);
  padding-block: 2rem 3rem;
  font-size: .92rem; color: var(--mauve);
}
.site-footer .wrap {
  display: flex; justify-content: space-between; gap: 1rem 2rem; flex-wrap: wrap;
  /* When the two halves wrap onto separate lines on a phone, space-between stops
     doing anything and the copyright was left hanging on its own baseline away
     from the links. Aligning both to the start puts them on the same left edge. */
  align-items: baseline;
}
@media (max-width: 30rem) {
  .site-footer .wrap { justify-content: flex-start; }
}
.site-footer nav { display: flex; gap: 1.25rem; flex-wrap: wrap; }
.site-footer a { color: var(--mauve); text-decoration: none; }
.site-footer a:hover { color: var(--heading); text-decoration: underline; }

/* ---------- get.html ---------- */

.get { min-height: 70vh; display: grid; place-items: center; text-align: center; }
.get .badges { flex-direction: column; align-items: center; margin-top: 2rem; }

/* ---------- mobile ---------- */

@media (max-width: 860px) {
  .hero .wrap,
  .feature .wrap { grid-template-columns: minmax(0, 1fr); }
  /* stacked, the logo sits directly above the heading — give it room both
     above and below rather than letting it crowd the header. */
  .hero { padding-block-start: clamp(3.5rem, 16vw, 7rem); }
  .hero .wrap { row-gap: clamp(3.75rem, 16vw, 6.5rem); }

  /* side by side rather than stacked — two short badges fit a phone width */
  .download .badges { flex-direction: row; flex-wrap: wrap; gap: .6rem; }
  .download .badge { min-width: 0; flex: 1 1 0; padding-inline: .8rem; }
  .download .badge .big { font-size: .92rem; }
  .hero-logo { width: min(70%, 13.5rem); }
  .feature.flip > .wrap > .shot,
  .feature.flip > .wrap > .screens { order: 0; }
}

@media (prefers-reduced-motion: reduce) {
  * { transition: none !important; animation: none !important; }
}
