/* Generated by tools/build-embed.mjs — do not edit. Source: assets/css/app.css */
/* ---------------------------------------------------------------------------
   AudioSlim Web — visual system
   ---------------------------------------------------------------------------
   Three sources, and where each one wins:

   - **kebekinteractive.com** owns the chrome. This page has to sit beside its
     neighbours without looking imported, so the background, the accent values
     and the type come from the site's own `styles.css`.
   - **The Android app** owns the identity: the real app icon, the real pill
     artwork, and the light-mode palette from `lib/theme/app_colors.dart`.
   - Everything else is this page's own.

   The site is dark-only. The app is not, so light mode is kept here — dark is
   the default and the one that matches the site exactly.
--------------------------------------------------------------------------- */

/* ---------------------------------------------------------------------------
   Type
   ---------------------------------------------------------------------------
   The site's stylesheet asks for Inter and ships no font file, so every visitor
   without Inter installed silently gets system-ui instead. That is most of them,
   and it is the actual reason this page's lettering did not match: both ends
   were falling back, to different things.

   Self-hosted here, variable weight, three subsets — latin, latin-ext and
   vietnamese, which is exactly the site's locale set (en/fr/es/vi). No external
   request, so it costs nothing in privacy or in blocking time.
--------------------------------------------------------------------------- */

@font-face {
  font-family: "InterVariable";
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("/tool/vendor/fonts/inter-latin-wght-normal.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+2000-206F, U+2192,
    U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "InterVariable";
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("/tool/vendor/fonts/inter-latin-ext-wght-normal.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+0304, U+0308, U+0329, U+1E00-1E9F,
    U+1EF2-1EFF, U+2020, U+20A0-20AB, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "InterVariable";
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("/tool/vendor/fonts/inter-vietnamese-wght-normal.woff2") format("woff2");
  unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1,
    U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9,
    U+20AB;
}

/* ---------------------------------------------------------------------------
   Tokens
--------------------------------------------------------------------------- */

.aslim {
  /* From the site's styles.css, verbatim, so the two cannot drift apart. */
  --bg: #05070c;
  --panel: #0d1320;
  --panel-2: #101827;
  --text: #f7fbff;
  --muted: #aeb8c8;
  --cyan: #1bdcff;
  --violet: #8b55ff;
  --amber: #f5b84b;
  --line: rgba(255, 255, 255, 0.14);
  --shadow: 0 24px 80px rgba(0, 0, 0, 0.42);

  /* This page's own, derived from the app's palette. */
  --surface-alt: #0e1e36;
  --text-2: #d3dae8;
  --hairline: rgba(255, 255, 255, 0.075);
  --glass: rgba(255, 255, 255, 0.055);
  --inset-tray: rgba(5, 11, 24, 0.58);

  --ok: #3ddc97;
  --warn: var(--amber);
  --danger: #ff6b6b;

  --radius: 16px;
  --radius-sm: 10px;
  --radius-pill: 999px;
  --maxw: 1080px;

  --font: "InterVariable", Inter, ui-sans-serif, system-ui, -apple-system,
    BlinkMacSystemFont, "Segoe UI", sans-serif;

  color-scheme: dark;
}

/* Light mode is **opt-in only**, and deliberately not wired to
   `prefers-color-scheme`.

   The app follows the system setting. The website does not — `styles.css` pins
   `color-scheme: dark` and ships no light palette at all. This page lives on the
   website, so following the system here would make it the one page that turns
   white while every page around it stayed dark, on any visitor whose OS is set
   to light. Matching the neighbours wins over matching the app.

   The values below are the app's own light palette, so the toggle still lands
   somewhere real rather than on an invented third look. */

/* ---------------------------------------------------------------------------
   Base
--------------------------------------------------------------------------- */

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

.aslim {
  -webkit-text-size-adjust: 100%;
  overflow-x: clip;
  scroll-behavior: smooth;
}

.aslim {
  margin: 0;
  overflow-x: clip;
  /* The site's two-lamp backdrop: cyan top-left, violet upper-right. This is
     the single strongest cue that a page belongs to kebekinteractive.com. */
  background:
    radial-gradient(circle at 15% 10%, rgba(27, 220, 255, 0.16), transparent 28rem),
    radial-gradient(circle at 85% 25%, rgba(139, 85, 255, 0.18), transparent 30rem),
    var(--bg);
  background-attachment: fixed;
  color: var(--text);
  font-family: var(--font);
  font-size: 16px;
  line-height: 1.6;
  min-height: 100vh;
}

/* The lamps are far too strong over a light page — same hues, a fifth of the
   strength. */

/* The site runs its headings at 800-850. Matching that is most of why the
   lettering reads as the same family of pages. */
.aslim h1,
.aslim h2,
.aslim h3 {
  line-height: 1.15;
  margin: 0 0 0.5em;
  letter-spacing: -0.03em;
  font-weight: 800;
}
.aslim h1 {
  font-size: clamp(2rem, 5vw, 3.1rem);
  font-weight: 850;
}
.aslim h2 {
  font-size: clamp(1.4rem, 3vw, 1.9rem);
}
.aslim h3 {
  font-size: 1.05rem;
  font-weight: 700;
}

.aslim p {
  margin: 0 0 1em;
  color: var(--muted);
}

.aslim a {
  color: var(--cyan);
}

.aslim small,
.aslim .small {
  font-size: 0.85rem;
  color: var(--muted);
}

.aslim .wrap {
  max-width: var(--maxw);
  margin: 0 auto;
  padding: 0 20px;
}

.aslim .stack > * + * {
  margin-top: 14px;
}

.aslim .hidden {
  display: none !important;
}

.aslim :focus-visible {
  outline: 2px solid var(--cyan);
  outline-offset: 4px;
}

/* ---------------------------------------------------------------------------
   The 3D pill kit
   ---------------------------------------------------------------------------
   Straight from the app's `assets/images/buttons/`, and it has to be sliced or
   it distorts. The rule the app learned the hard way: **artwork that stretches
   carries no fixed-aspect content.** A pill scaled with `background-size: 100%
   100%` squashes its round caps into ovals the moment the button is wider than
   the source — which is always, and is exactly what "Apply to project" looked
   like before it was fixed.

   `border-image` is the web's own answer to that, and it maps onto the app's
   three-slice widget exactly:

   - The source caps are 100px of a 200px-tall pill — precisely half the height,
     a true round cap. Re-encoded to 128px tall, that is a 64px slice.
   - `border-image-width` is then set to **half the rendered control height**, so
     the cap scales by the same factor horizontally and vertically and cannot
     distort. 44px control → 22px cap. That pairing is load-bearing; changing one
     without the other reintroduces the oval.
   - `round` on the repeat tiles the 48px middle strip instead of stretching it.
     Stretched, its speckled texture smears into streaks.
--------------------------------------------------------------------------- */

/* The rules themselves live after the button styles — see the note there. */

/* ---------------------------------------------------------------------------
   Header
--------------------------------------------------------------------------- */

.aslim .site-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 18px 0;
}

.aslim .brand {
  display: flex;
  align-items: center;
  gap: 11px;
  font-weight: 800;
  font-size: 1.12rem;
  letter-spacing: -0.02em;
  color: var(--text);
  text-decoration: none;
}

/* The real app icon, not a glyph standing in for it. */
.aslim .brand-mark {
  width: 34px;
  height: auto;
  display: block;
  filter: drop-shadow(0 4px 12px rgba(27, 220, 255, 0.28));
}

/* Smaller pill, so the caps shrink with it — 38px tall means a 19px cap, or the
   round end goes oval. See the pill kit. */
.aslim .theme-toggle {
  min-height: 38px;
  padding: 0 6px;
  color: var(--text-2);
  border-radius: var(--radius-pill);
  font: inherit;
  font-size: 0.85rem;
  font-weight: 700;
  cursor: pointer;
  text-shadow: 0 1px 3px rgba(0, 0, 0, 0.5);
  background: transparent;
  border-style: solid;
  border-color: transparent;
  border-width: 0 19px;
  border-image-source: url("/tool/img/pill-blue-dim.webp");
  border-image-slice: 0 64 fill;
  border-image-width: 0 19px;
  border-image-repeat: round;
}
.aslim .theme-toggle:hover {
  border-image-source: url("/tool/img/pill-blue.webp");
  color: #fff;
}

/* ---------------------------------------------------------------------------
   Hero
--------------------------------------------------------------------------- */

.aslim .hero {
  text-align: center;
  padding: 30px 0 8px;
}

.aslim .hero h1 .accent {
  background: linear-gradient(100deg, var(--cyan), var(--violet));
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

.aslim .hero p.lede {
  font-size: 1.1rem;
  color: var(--muted);
  max-width: 60ch;
  margin-inline: auto;
}

.aslim .badges {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  justify-content: center;
  margin: 20px 0 0;
  padding: 0;
  list-style: none;
}

.aslim .badge {
  border: 1px solid var(--line);
  background: var(--glass);
  color: var(--muted);
  border-radius: var(--radius-pill);
  padding: 7px 14px;
  font-size: 0.82rem;
  font-weight: 600;
}

/* ---------------------------------------------------------------------------
   Tool panel
--------------------------------------------------------------------------- */

.aslim .tool {
  margin: 28px 0 40px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: linear-gradient(180deg, var(--panel), var(--panel-2));
  box-shadow: var(--shadow);
  overflow: hidden;
}

.aslim .tool-inner {
  padding: 22px;
}

@media (max-width: 620px) {
  .aslim .tool-inner {
    padding: 16px;
  }
}

.aslim .dropzone {
  border: 2px dashed var(--line);
  border-radius: var(--radius);
  padding: 42px 20px;
  text-align: center;
  background: var(--glass);
  transition:
    border-color 0.15s,
    background 0.15s;
  cursor: pointer;
}
.aslim .dropzone:hover,
.aslim .dropzone.is-over {
  border-color: var(--violet);
  background: color-mix(in srgb, var(--violet) 9%, transparent);
}
.aslim .dropzone h2 {
  margin-bottom: 6px;
}
.aslim .dropzone .small {
  display: block;
  margin-top: 8px;
}

/* App artwork, at its real aspect. */
.aslim .dz-icon {
  width: 62px;
  height: 62px;
  margin: 0 auto 15px;
  display: block;
  filter: drop-shadow(0 8px 20px rgba(139, 85, 255, 0.32));
}

/* ---------------------------------------------------------------------------
   Buttons
--------------------------------------------------------------------------- */

.aslim .btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 9px;
  border-radius: var(--radius-pill);
  border: 1px solid transparent;
  padding: 12px 24px;
  font: inherit;
  font-weight: 700;
  color: var(--text);
  cursor: pointer;
  text-decoration: none;
  transition:
    filter 0.15s,
    transform 0.05s;
}
.aslim .btn:active {
  transform: translateY(1px);
}
.aslim .btn:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

/* Artwork buttons: the pill supplies the whole surface. Padding is horizontal
   only — the caps already provide the inset, and adding more would push the
   label off-centre between them.

   Note there is no `border` here. That is deliberate: see the pill kit below. */
.aslim .btn-primary,
.aslim .btn-accent {
  padding: 10px 6px;
  color: #fff;
  text-shadow: 0 1px 3px rgba(0, 0, 0, 0.45);
}
.aslim .btn-primary:hover:not(:disabled),
.aslim .btn-accent:hover:not(:disabled) {
  filter: brightness(1.1);
}

/* Secondary buttons wear the same artwork, pre-dimmed. Nothing on this page is
   a flat rectangle any more — the difference between a primary and a secondary
   action is how lit it is, not whether it is three-dimensional. */
.aslim .btn-ghost {
  min-height: 44px;
  padding: 0 8px;
  color: var(--text);
  font-weight: 700;
  text-shadow: 0 1px 3px rgba(0, 0, 0, 0.5);
  background: transparent;
  border-style: solid;
  border-color: transparent;
  border-width: 0 22px;
  border-image-source: url("/tool/img/pill-blue-dim.webp");
  border-image-slice: 0 64 fill;
  border-image-width: 0 22px;
  border-image-repeat: round;
}
/* Hover lights the same pill rather than changing its colour, so the control
   reads as the one object throughout. */
.aslim .btn-ghost:hover:not(:disabled) {
  border-image-source: url("/tool/img/pill-blue.webp");
  color: #fff;
}

.aslim .btn-icon {
  width: 20px;
  height: 20px;
  flex: none;
}

.aslim .btn-row {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  align-items: center;
}

/* ---------------------------------------------------------------------------
   The 3D pill kit
   ---------------------------------------------------------------------------
   Straight from the app's `assets/images/buttons/`, and it has to be sliced or
   it distorts. The rule the app learned the hard way: **artwork that stretches
   carries no fixed-aspect content.** A pill scaled with `background-size: 100%
   100%` squashes its round caps into ovals the moment the button is wider than
   the source — which is always, and is exactly what "Apply to project" looked
   like before it was fixed.

   `border-image` is the web's own answer, and it maps onto the app's
   three-slice widget exactly:

   - The source caps are 100px of a 200px-tall pill — precisely half the height,
     a true round cap. Re-encoded to 128px tall, that is a 64px slice.
   - `border-image-width` is set to **half the rendered control height**, so the
     cap scales by the same factor horizontally and vertically and cannot
     distort. 44px control → 22px cap. That pairing is load-bearing; changing
     one without the other brings the oval straight back.
   - `round` tiles the 48px middle strip rather than stretching it. Stretched,
     its speckled texture smears into streaks.

   **This block must stay after the `.btn` rules.** The `border` shorthand
   resets `border-image` to `none`, so a `border: 1px solid transparent` further
   down the file silently erases every pill on the page — which is exactly what
   happened the first time this was written.
--------------------------------------------------------------------------- */

.aslim .pill {
  border-style: solid;
  border-color: transparent;
  border-image-slice: 0 64 fill;
  border-image-repeat: round;
  background: transparent;
}

/* **A pill must never wrap its label**, and this is not a typographic
   preference — it is the cap geometry again.
   `border-image-width` is a fixed pixel value chosen as half the control's
   height. The moment a label wraps to a second line the element grows taller
   while the cap stays the size it was, the two stop being half-and-half, and the
   round end flattens into an oval. Found on the French feature list at 375px,
   where one string wrapped and its pill went from 38px to 44px against a cap
   still set at 19.
   Widening is free — the middle tiles — so a long label makes a longer pill
   instead. If something genuinely will not fit, shorten the string; do not let
   it wrap. */
.aslim .pill,
.aslim .chip,
.aslim .btn-ghost,
.aslim .theme-toggle,
.aslim .upsell .feature-pills li {
  white-space: nowrap;
}

/* Height and cap width move together — see above. */
.aslim .pill-38 {
  min-height: 38px;
  border-width: 0 19px;
  border-image-width: 0 19px;
}
.aslim .pill-44 {
  min-height: 44px;
  border-width: 0 22px;
  border-image-width: 0 22px;
}
.aslim .pill-52 {
  min-height: 52px;
  border-width: 0 26px;
  border-image-width: 0 26px;
}

.aslim .pill-violet {
  border-image-source: url("/tool/img/pill-violet.webp");
}
.aslim .pill-blue {
  border-image-source: url("/tool/img/pill-blue.webp");
}
/* The app also ships a magenta pill. Add the class and the build-script entry
   together on the day something draws it, not before. */

/* The artwork is drawn for a dark page. On a light one it keeps its hue and
   loses contrast — the same trap `AppColors.onLightSurface` exists to solve in
   the app. Darkened rather than re-drawn, so it stays recognisably itself.
   Everything wearing a pill is listed, not just `.pill`, because the chips and
   the secondary buttons carry their border-image from their own rules. */

/* Light mode inverts where the depth cues come from: a white highlight on a
   near-white tile is invisible, so the lit edge becomes a *darker* rim and the
   cast shadow softens to something that does not read as a smudge. Same mistake
   the app's `hairline` and `glassFill` were built to avoid. */

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

.aslim .file-head {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  padding-bottom: 16px;
  margin-bottom: 16px;
  border-bottom: 1px solid var(--hairline);
}

.aslim .file-name {
  font-weight: 700;
  word-break: break-all;
  flex: 1;
  min-width: 200px;
}

/* ---------------------------------------------------------------------------
   Waveform
--------------------------------------------------------------------------- */

.aslim .wave-shell {
  position: relative;
  border-radius: var(--radius-sm);
  background: var(--inset-tray);
  border: 1px solid var(--hairline);
  overflow: hidden;
  touch-action: none;
}

.aslim #waveform {
  display: block;
  width: 100%;
  height: 150px;
}

.aslim .trim-handle {
  position: absolute;
  top: 0;
  bottom: 0;
  width: 14px;
  cursor: ew-resize;
  border-radius: 4px;
  background: linear-gradient(180deg, var(--cyan), color-mix(in srgb, var(--cyan) 55%, var(--violet)));
  box-shadow:
    0 0 0 1px rgba(0, 0, 0, 0.35),
    0 4px 14px rgba(27, 220, 255, 0.4);
  touch-action: none;
}
.aslim .trim-handle::after {
  content: "";
  position: absolute;
  inset: 50% 4px auto;
  height: 18px;
  transform: translateY(-50%);
  border-left: 2px solid rgba(255, 255, 255, 0.8);
  border-right: 2px solid rgba(255, 255, 255, 0.8);
}

/* A 14px target is comfortable with a mouse and far too small for a thumb.
   Widened on touch only, because on desktop a wide handle hides the waveform it
   is pointing at. The JS reads the rendered width, so this is the only place the
   number lives. */
@media (pointer: coarse) {
  .aslim .trim-handle {
    width: 30px;
  }
  .aslim .trim-handle::after {
    inset: 50% 11px auto;
    height: 26px;
  }
}

.aslim .trim-shade {
  position: absolute;
  top: 0;
  bottom: 0;
  background: color-mix(in srgb, var(--bg) 70%, transparent);
  pointer-events: none;
}

.aslim .playhead {
  position: absolute;
  top: 0;
  bottom: 0;
  width: 2px;
  background: var(--amber);
  box-shadow: 0 0 10px var(--amber);
  pointer-events: none;
  display: none;
}

/* ---------------------------------------------------------------------------
   Form controls
--------------------------------------------------------------------------- */

.aslim .field {
  display: block;
  margin-bottom: 16px;
}

.aslim .field > label,
.aslim .field-label {
  display: block;
  font-size: 0.78rem;
  font-weight: 700;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  margin-bottom: 8px;
}

.aslim select,
.aslim input[type="number"],
.aslim input[type="text"] {
  width: 100%;
  background: var(--surface-alt);
  color: var(--text);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  padding: 11px 12px;
  font: inherit;
  font-weight: 600;
}

.aslim .grid-2 {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  gap: 16px;
}

/* ---------------------------------------------------------------------------
   Format chips — the 3D tabs
--------------------------------------------------------------------------- */

.aslim .chips {
  display: flex;
  flex-wrap: wrap;
  gap: 9px;
}

/* Every chip is three-dimensional. Selection is carried by how *lit* the pill
   is, not by whether it has artwork at all — an unselected format is still a
   real button and should look like one.
   Padding is small because the caps already supply ~22px of inset each side. */
.aslim .chip {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  min-height: 44px;
  padding: 0 6px;
  border-radius: var(--radius-pill);
  color: var(--text-2);
  font: inherit;
  font-size: 0.94rem;
  font-weight: 700;
  cursor: pointer;
  text-decoration: none;
  text-shadow: 0 1px 3px rgba(0, 0, 0, 0.5);
  background: transparent;
  border-style: solid;
  border-color: transparent;
  border-width: 0 22px;
  border-image-source: url("/tool/img/pill-blue-dim.webp");
  border-image-slice: 0 64 fill;
  border-image-width: 0 22px;
  border-image-repeat: round;
  transition: color 0.15s;
}

.aslim .chip:hover:not([aria-pressed="true"]) {
  border-image-source: url("/tool/img/pill-blue.webp");
  color: #fff;
}

/* The selected format: the same pill at full strength. */
.aslim .chip[aria-pressed="true"] {
  border-image-source: url("/tool/img/pill-blue.webp");
  color: #fff;
}

/* Locked formats stay dimmed even on hover — they are not choices here, they
   are a link to the app. The padlock says so; the lighting agrees with it. */
.aslim .chip-locked {
  color: var(--muted);
}
.aslim .chip-locked:hover {
  border-image-source: url("/tool/img/pill-blue-dim.webp");
  color: var(--text-2);
}
.aslim .chip .lock {
  font-size: 0.85em;
  opacity: 0.9;
}

/* ---------------------------------------------------------------------------
   Estimate
--------------------------------------------------------------------------- */

/* Four raised tiles rather than one flat tray.
   The depth is built from four cues stacked in one box-shadow, and it only
   reads as a solid object when all four agree on where the light is — top-left,
   the same as the page's cyan lamp:
     1. a lit top edge (inset highlight)
     2. a dark bottom edge (inset shadow), so the tile has thickness
     3. a cast shadow below it, to lift it off the panel
     4. a hairline ring, to stop it dissolving into the background
   The gradient runs light-to-dark top-to-bottom for the same reason. */
.aslim .estimate {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(132px, 1fr));
  gap: 11px;
  margin: 20px 0;
  padding: 0;
  background: none;
  border: 0;
}

.aslim .stat {
  position: relative;
  text-align: center;
  padding: 15px 10px 14px;
  border-radius: 15px;
  border: 1px solid var(--line);
  background:
    linear-gradient(
      180deg,
      rgba(255, 255, 255, 0.11) 0%,
      rgba(255, 255, 255, 0.03) 42%,
      rgba(0, 0, 0, 0.16) 100%
    ),
    linear-gradient(180deg, var(--panel-2), var(--panel));
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.3),
    inset 0 -1px 0 rgba(0, 0, 0, 0.42),
    inset 1px 0 0 rgba(255, 255, 255, 0.06),
    0 7px 18px rgba(0, 0, 0, 0.42);
  overflow: hidden;
}

/* A soft gloss across the top third — the highlight a curved surface would
   actually catch. Kept subtle; at full strength it reads as a glass button from
   2008. */
.aslim .stat::before {
  content: "";
  position: absolute;
  inset: 0 0 auto;
  height: 46%;
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.09), transparent);
  pointer-events: none;
}

/* The estimate is the number people came for, so its tile is the lit one. */
.aslim .stat.is-primary {
  border-color: color-mix(in srgb, var(--cyan) 38%, var(--line));
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.34),
    inset 0 -1px 0 rgba(0, 0, 0, 0.42),
    0 7px 20px rgba(0, 0, 0, 0.45),
    0 0 22px color-mix(in srgb, var(--cyan) 22%, transparent);
}

.aslim .stat .k {
  display: block;
  position: relative;
  font-size: 0.71rem;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  font-weight: 700;
  color: var(--muted);
  margin-bottom: 5px;
}
.aslim .stat .v {
  display: block;
  position: relative;
  font-size: 1.34rem;
  font-weight: 800;
  letter-spacing: -0.02em;
  color: var(--text);
  text-shadow: 0 1px 3px rgba(0, 0, 0, 0.45);
}
.aslim .stat .v.good {
  color: var(--ok);
}
.aslim .stat .v.accent {
  background: linear-gradient(100deg, var(--cyan), var(--violet));
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

/* ---------------------------------------------------------------------------
   Progress + notices
--------------------------------------------------------------------------- */

.aslim .progress {
  height: 8px;
  border-radius: var(--radius-pill);
  background: var(--inset-tray);
  overflow: hidden;
  border: 1px solid var(--hairline);
}
.aslim .progress > i {
  display: block;
  height: 100%;
  width: 0%;
  background: linear-gradient(90deg, var(--cyan), var(--violet));
  transition: width 0.2s;
}

.aslim .notice {
  border-radius: var(--radius-sm);
  padding: 12px 14px;
  font-size: 0.9rem;
  border: 1px solid var(--line);
  background: var(--glass);
  color: var(--muted);
}
.aslim .notice.warn {
  border-color: color-mix(in srgb, var(--warn) 45%, var(--line));
  background: color-mix(in srgb, var(--warn) 10%, transparent);
}
.aslim .notice.error {
  border-color: color-mix(in srgb, var(--danger) 45%, var(--line));
  background: color-mix(in srgb, var(--danger) 10%, transparent);
}
.aslim .notice.ok {
  border-color: color-mix(in srgb, var(--ok) 45%, var(--line));
  background: color-mix(in srgb, var(--ok) 10%, transparent);
}

/* ---------------------------------------------------------------------------
   Upsell
--------------------------------------------------------------------------- */

.aslim .upsell {
  margin: 36px 0;
  padding: 30px 26px;
  border-radius: var(--radius);
  border: 1px solid var(--line);
  background:
    radial-gradient(circle at 20% 0%, rgba(27, 220, 255, 0.12), transparent 20rem),
    radial-gradient(circle at 80% 100%, rgba(139, 85, 255, 0.14), transparent 22rem),
    linear-gradient(180deg, var(--panel), var(--panel-2));
  box-shadow: var(--shadow);
  text-align: center;
}

/* Narrow phones get less side padding: pills cannot wrap, so every pixel of
   inner width is one less chance of a label running past the card edge.
   Must stay after `.upsell` — same specificity, so order decides. */
@media (max-width: 480px) {
  .aslim .upsell {
    padding-inline: 14px;
  }
}

.aslim .upsell-icon {
  width: 76px;
  height: auto;
  display: block;
  margin: 0 auto 14px;
  filter: drop-shadow(0 10px 26px rgba(27, 220, 255, 0.3));
}

/* Scoped to `.feature-pills`, not to every `ul` in the section — the carousel
   below is also a list, and would otherwise inherit all of this. */
.aslim .upsell .feature-pills {
  list-style: none;
  padding: 0;
  margin: 18px auto;
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  justify-content: center;
  max-width: 640px;
}
/* The feature list wears the pill artwork too, dimmed — these are the things
   you do not get here, so "present but unlit" is exactly the right reading.
   38px tall means a 19px cap; see the pill kit for why those two numbers are
   tied together.

   Deliberately *not* interactive: no hover lift, no pointer cursor. The app hit
   the same question with its `source_file` badge and answered it the same way —
   a display badge gets the pill background without being given a button's
   behaviour. Making these light up on hover would promise a click that does not
   exist. */
.aslim .upsell .feature-pills li {
  display: inline-flex;
  align-items: center;
  min-height: 38px;
  padding: 0 6px;
  border-radius: var(--radius-pill);
  font-size: 0.86rem;
  font-weight: 700;
  color: var(--text-2);
  text-shadow: 0 1px 3px rgba(0, 0, 0, 0.5);
  background: transparent;
  border-style: solid;
  border-color: transparent;
  border-width: 0 19px;
  border-image-source: url("/tool/img/pill-blue-dim.webp");
  border-image-slice: 0 64 fill;
  border-image-width: 0 19px;
  border-image-repeat: round;
}

/* ---------------------------------------------------------------------------
   Session savings panel
   ---------------------------------------------------------------------------
   Appears only after the first successful export. Built from parts that already
   exist -- the raised-panel treatment used by the stat tiles, the blue pill
   artwork, and `icon-waveform.webp` -- so it reads as part of the tool rather
   than as something bolted on afterwards. No new image was drawn for it.

   **The total wears a real pill, so it must never wrap**, for the cap-geometry
   reason spelled out above the `.pill` rules: `border-image-width` is a fixed
   half-height value, and a second line flattens the round ends into ovals. It
   holds a formatted byte count and nothing else, so it cannot -- but do not put
   a label inside it. The words live outside the pill precisely so that French
   and Vietnamese, both markedly longer than English here, are free to wrap
   without touching the artwork.

   This block sits after the `.pill` rules on purpose. The `border` shorthand
   silently resets `border-image`, so nothing here may set `border` on the pill.
--------------------------------------------------------------------------- */

.aslim .savings {
  display: grid;
  grid-template-columns: auto 1fr;
  align-items: center;
  gap: 4px 16px;
  margin-top: 18px;
  padding: 16px 18px;
  border-radius: var(--radius);
  background: linear-gradient(180deg, var(--panel-2), var(--panel));
  /* Same four agreeing depth cues as the stat tiles: lit top edge, cast shadow,
     hairline rim, top-to-bottom gradient. */
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.16),
    0 10px 26px rgba(0, 0, 0, 0.45);
  outline: 1px solid var(--line);
  outline-offset: -1px;
}

.aslim .savings-icon {
  width: 52px;
  height: 52px;
  display: block;
  filter: drop-shadow(0 6px 14px rgba(27, 220, 255, 0.35));
}

.aslim .savings-body {
  min-width: 0;
}

.aslim .savings-heading {
  margin: 0 0 8px;
  font-size: 0.86rem;
  font-weight: 700;
  color: var(--muted);
}

.aslim .savings-total {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  margin: 0;
  padding: 0;
  min-width: 0;
  font-size: 1.45rem;
  font-weight: 850;
  color: var(--text);
  text-shadow: 0 1px 4px rgba(0, 0, 0, 0.55);
}

.aslim .savings-files {
  margin: 8px 0 0;
  color: var(--muted);
}

/* Full width under both columns: it is a footnote about the whole panel, and on
   a phone there is no room for it beside the icon. */
.aslim .savings-note {
  grid-column: 1 / -1;
  margin: 12px 0 0;
  padding-top: 12px;
  border-top: 1px solid var(--hairline);
  color: var(--muted);
}

/* At 320px the icon and the figure together are wider than the column, so the
   icon steps aside rather than squeezing the number it is decorating. */
@media (max-width: 380px) {
  .aslim .savings {
    grid-template-columns: 1fr;
    gap: 10px;
  }
  .aslim .savings-icon {
    width: 40px;
    height: 40px;
  }
  .aslim .savings-total {
    font-size: 1.25rem;
  }
}

/* ---------------------------------------------------------------------------
   Screenshot carousel
   ---------------------------------------------------------------------------
   Built on CSS scroll-snap rather than on a JavaScript slider. The track is a
   real overflow-x container, so it already drags on touch, flicks with momentum,
   scrolls with a trackpad and works with the keyboard — before a line of our JS
   runs. The script only adds the arrows and the dots, and if it never loads the
   carousel still works, which is the whole argument for doing it this way.

   The track is the one element on the page allowed to scroll horizontally. The
   overflow audit treats `overflow-x: auto` as intentional for exactly this
   reason.
--------------------------------------------------------------------------- */

.aslim .carousel {
  position: relative;
  margin: 22px 0 8px;
}

.aslim .carousel-track {
  display: flex;
  gap: 14px;
  list-style: none;
  margin: 0;
  padding: 4px 2px 10px;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scroll-behavior: smooth;
  scrollbar-width: none;
  /* Vertical panning must stay with the page, or a thumb dragging down the
     screen gets swallowed by the carousel. */
  touch-action: pan-x pan-y;
}
.aslim .carousel-track::-webkit-scrollbar {
  display: none;
}
.aslim .carousel-track:focus-visible {
  outline: 2px solid var(--cyan);
  outline-offset: 4px;
  border-radius: var(--radius);
}

.aslim .slide {
  flex: 0 0 auto;
  scroll-snap-align: center;
  width: 232px;
}

.aslim .slide figure {
  margin: 0;
  text-align: center;
}

.aslim .slide img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 14px;
  border: 1px solid var(--line);
  /* Phone screenshots want to look like a device sitting on the page, so they
     get the same lit-edge-and-cast-shadow treatment as the stat tiles. */
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.16),
    0 10px 26px rgba(0, 0, 0, 0.5);
  background: var(--panel);
}

.aslim .slide figcaption {
  margin-top: 10px;
  font-size: 0.82rem;
  font-weight: 600;
  line-height: 1.4;
  color: var(--muted);
}

/* Arrows sit outside the track on wide screens and are hidden on touch, where
   dragging is the natural gesture and a tap target over the image just gets in
   the way. */
.aslim .carousel-nav {
  position: absolute;
  top: 40%;
  z-index: 2;
  width: 42px;
  height: 42px;
  padding: 0;
  border-radius: 50%;
  border: 1px solid var(--line);
  background: linear-gradient(180deg, var(--panel-2), var(--panel));
  color: var(--text);
  font-size: 1.5rem;
  line-height: 1;
  cursor: pointer;
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.22),
    0 6px 16px rgba(0, 0, 0, 0.5);
  transition: transform 0.12s, border-color 0.15s;
}
.aslim .carousel-nav:hover {
  border-color: var(--cyan);
  transform: scale(1.06);
}
.aslim .carousel-nav:disabled {
  opacity: 0.3;
  cursor: default;
  transform: none;
}
/* Flush with the track, not hanging outside it. Overhanging by a few pixels
   looked better in isolation but pushed `.carousel` wider than its own box,
   which is the first step toward a page that scrolls sideways on a phone. */
.aslim #shotsPrev {
  left: 0;
}
.aslim #shotsNext {
  right: 0;
}

@media (pointer: coarse) {
  .aslim .carousel-nav {
    display: none;
  }
}

.aslim .carousel-dots {
  display: flex;
  justify-content: center;
  gap: 7px;
  margin-top: 6px;
}

.aslim .carousel-dots button {
  width: 8px;
  height: 8px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: var(--line);
  cursor: pointer;
  transition: background 0.2s, width 0.2s;
}
.aslim .carousel-dots button[aria-current="true"] {
  width: 22px;
  border-radius: 999px;
  background: linear-gradient(90deg, var(--cyan), var(--violet));
}

/* ---------------------------------------------------------------------------
   Lightbox
   ---------------------------------------------------------------------------
   Fixed to the viewport, so it escapes the `.aslim` box it lives in — which is
   what makes it work on a host page whose sections it knows nothing about. The
   z-index is deliberately far above anything on the site; a viewer that opens
   *behind* the page header is worse than no viewer.
--------------------------------------------------------------------------- */

.aslim .slide img.is-zoomable {
  cursor: zoom-in;
  transition: transform 0.15s, border-color 0.15s;
}
.aslim .slide img.is-zoomable:hover {
  transform: translateY(-3px);
  border-color: var(--cyan);
}

.aslim .lightbox {
  position: fixed;
  inset: 0;
  z-index: 99999;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  padding: 20px;
  background: rgba(3, 5, 12, 0.93);
  backdrop-filter: blur(6px);
  cursor: zoom-out;
}

.aslim .lb-figure {
  margin: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  max-height: 100%;
  cursor: default;
}

.aslim .lb-img {
  display: block;
  max-width: min(92vw, 460px);
  /* Room reserved for the caption and counter under it, or a tall phone
     screenshot pushes them off the bottom of the viewport. */
  max-height: calc(100vh - 150px);
  width: auto;
  height: auto;
  object-fit: contain;
  border-radius: 16px;
  border: 1px solid var(--line);
  box-shadow: 0 24px 70px rgba(0, 0, 0, 0.7);
}

.aslim .lb-caption {
  margin: 0;
  text-align: center;
  font-weight: 700;
  color: #fff;
  max-width: 42ch;
}

.aslim .lb-count {
  margin: 0;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}

.aslim .lb-close,
.aslim .lb-nav {
  flex: none;
  width: 46px;
  height: 46px;
  border-radius: 50%;
  border: 1px solid var(--line);
  background: linear-gradient(180deg, var(--panel-2), var(--panel));
  color: var(--text);
  font-size: 1.6rem;
  line-height: 1;
  cursor: pointer;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 6px 18px rgba(0, 0, 0, 0.6);
}
.aslim .lb-close:hover,
.aslim .lb-nav:hover {
  border-color: var(--cyan);
}

.aslim .lb-close {
  position: absolute;
  top: 18px;
  right: 18px;
  font-size: 1.9rem;
}

/* On a phone the arrows would sit on top of a nearly full-width image, so they
   drop to the bottom corners where a thumb reaches them anyway. */
@media (max-width: 620px) {
  .aslim .lightbox {
    padding: 12px;
  }
  .aslim .lb-nav {
    position: absolute;
    bottom: 18px;
  }
  .aslim .lb-prev {
    left: 22px;
  }
  .aslim .lb-next {
    right: 22px;
  }
  .aslim .lb-img {
    max-height: calc(100vh - 190px);
  }
}

/* Google's badge, placed to their brand guidelines: never restyled, never
   given a background or a border of ours, and carrying clear space of at least
   a quarter of its own height on every side. The only thing we control is how
   big it is. */
.aslim .store-badge {
  display: inline-block;
  margin: 8px 0;
  padding: 0;
  border: 0;
  background: none;
  line-height: 0;
  transition: transform 0.12s;
}
.aslim .store-badge:hover {
  transform: translateY(-2px);
}
.aslim .store-badge:active {
  transform: translateY(0);
}
.aslim .store-badge img {
  display: block;
  width: 208px;
  height: auto;
}

/* ---------------------------------------------------------------------------
   Content
--------------------------------------------------------------------------- */

.aslim .prose {
  max-width: 72ch;
  margin: 0 auto 40px;
}

.aslim .faq details {
  border-bottom: 1px solid var(--hairline);
  padding: 14px 0;
}
.aslim .faq summary {
  cursor: pointer;
  font-weight: 700;
  color: var(--text);
}
.aslim .faq details p {
  margin: 10px 0 0;
}

.aslim .site-footer {
  border-top: 1px solid var(--hairline);
  padding: 26px 0 40px;
  text-align: center;
}

@media (prefers-reduced-motion: reduce) {
  .aslim * {
    animation: none !important;
    transition: none !important;
    scroll-behavior: auto !important;
  }
}
