/*
 * Telegram Mini App chrome. Everything here hangs off `[data-app='tg']`, written on <html> by
 * tg.js, so the file is inert on the website. `[data-os]` picks the conventions: iOS follows the
 * HIG (centred title, chevron-and-label back control, translucent bar, large title on a root
 * screen), Android follows Material 3 (leading title, back arrow, tonal surface on scroll,
 * a pill behind the active tab icon).
 *
 * Loads last, so it wins over the site rules it replaces without needing !important for anything
 * that is not already !important itself.
 */

/* ---------- the site's own chrome steps aside ---------- */

/* Telegram draws its own header above the webview, and a marketing footer inside a mini app is
   just weight. The site's bottom nav is replaced by .apptabs, which has its own item set. */
[data-app='tg'] .header,
[data-app='tg'] .footer,
[data-app='tg'] .tabbar,
[data-app='tg'] .to-top { display: none; }

/* One height for the tab bar, read by the body's clearance, the buy bar and the tabs
   themselves — three places that used to hold three different numbers. */
[data-app='tg'] { --tabbar-h: 56px; }
[data-app='tg'][data-os='ios'] { --tabbar-h: 49px; }
[data-app='tg'][data-os='android'] { --tabbar-h: 64px; }

[data-app='tg'] body {
  /* the bar's own height, the safe area under it, and 16px so content never ends against it */
  padding-bottom: calc(var(--tabbar-h) + 16px + max(var(--tg-bottom, 0px), env(safe-area-inset-bottom)));
}

/* A mini app is a phone-width surface whatever the client's window is doing. */
[data-app='tg'] .page,
[data-app='tg'] .narrow,
[data-app='tg'] .wide,
[data-app='tg'] .checkout { max-width: 560px; }

/* ---------- app bar ---------- */

/* Sticky, not fixed: the large title then scrolls out of the bar on its own and the row pins,
   which is the iOS behaviour, and no page has to be padded to clear a floating header. */
.appbar {
  position: sticky;
  top: 0;
  z-index: 60;
  padding-top: max(var(--tg-top, 0px), env(safe-area-inset-top));
  background: var(--fx-surface);
  transition: box-shadow var(--fx-base) ease, background-color var(--fx-base) ease;
}

/* One height on every screen and on both platforms: a bar that changed size as you moved
   between screens read as a different bar each time. */
.appbar-row {
  display: grid;
  align-items: center;
  gap: 4px;
  height: 56px;
  padding: 0 6px;
  transition: height var(--fx-base) ease;
}

.appbar-title {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-family: var(--fx-display);
  color: var(--fx-ink);
}

/* A chevron and nothing else. A caption beside it pushed a long screen title off centre on
   iOS and has no place in Material at all. */
.appbar-back {
  position: relative;
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  background: transparent;
  color: var(--fx-cyanink);
  cursor: pointer;
}

/* 40px drawn, 44px touched — the same top-up the site's small controls use. */
.appbar-back::after { content: ''; position: absolute; inset: -2px; }
.appbar-back i { font-size: 26px; }

.appbar-large {
  margin: 0;
  /* No bottom padding: the 24px at the top of .tg-page is the whole gap, on every screen. */
  padding: 2px 16px 0;
  font-family: var(--fx-display);
  color: var(--fx-ink);
  letter-spacing: -.03em;
  transform-origin: left center;
  transition: opacity var(--fx-base) ease, transform var(--fx-base) ease,
              max-height var(--fx-base) ease, padding var(--fx-base) ease;
  max-height: 60px;
}

/* Scrolled: the large title folds away and the row keeps the name. */
.appbar.condensed .appbar-large {
  opacity: 0;
  max-height: 0;
  padding-top: 0;
  padding-bottom: 0;
  transform: scale(.86);
}

/* On a root screen the row's title only appears once the large one has gone. */
.appbar.root .appbar-title { opacity: 0; transition: opacity var(--fx-base) ease; }
.appbar.root.condensed .appbar-title { opacity: 1; }

/* A root screen other than home opens as its title and nothing else — an empty row above a
   large title is 56px of surface saying nothing. It comes back on scroll, once the large title
   has folded away and something has to say where you are. Home keeps its row at all times: the
   logo and the bell live in it, and it has no large title of its own. */
.appbar.root:not(.home) .appbar-row { height: 0; overflow: hidden; }
.appbar.root:not(.home).condensed .appbar-row { height: 56px; overflow: visible; }
.appbar.root:not(.home) .appbar-large { padding-top: 14px; }
.appbar.root:not(.home).condensed .appbar-large { padding-top: 0; }

.appbar-lead,
.appbar-trail { display: flex; align-items: center; min-width: 0; }
.appbar-trail { justify-content: flex-end; }

/* Home gives the whole free column to the logo and keeps none for a centre title. */
.appbar.home .appbar-row { grid-template-columns: minmax(0, 1fr) 0 auto; }

/* The lock-up sits at the row's leading edge, lined up with the large title below it and with
   the 16px page gutter — the row's own padding is 6px, so the rest is made up here. */
.appbar-brand { padding-left: 10px; }
.appbar-brand img { height: 24px; }

.appbar-action {
  position: relative;
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
  flex-shrink: 0;
  border-radius: 50%;
  color: var(--fx-ink);
}

/* 40px drawn, 44px touched — the same trick the site's small controls use. */
.appbar-action::after { content: ''; position: absolute; inset: -2px; }
.appbar-action i { font-size: 21px; }
[data-os='ios'] .appbar-action { color: var(--fx-cyanink); }
[data-os='android'] .appbar-action { width: 48px; height: 48px; }
[data-os='android'] .appbar-action:active { background: var(--fx-bg); }

.appbar-dot {
  position: absolute;
  top: 5px;
  right: 5px;
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--fx-err);
  border: 2px solid var(--fx-surface);
}

/* ---------- app bar: iOS ---------- */

/* 1fr auto 1fr keeps the title on the centre of the screen whatever the back label is. */
[data-os='ios'] .appbar-row { grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr); }
[data-os='ios'] .appbar-title { justify-self: center; font-size: 17px; font-weight: 600; letter-spacing: -.01em; }
[data-os='ios'] .appbar-large { font-size: 34px; font-weight: 700; }
[data-os='ios'] .appbar.condensed { box-shadow: 0 .5px 0 var(--fx-border); }

@supports (backdrop-filter: blur(1px)) and (background: color-mix(in srgb, red 50%, transparent)) {
  [data-os='ios'] .appbar {
    background: color-mix(in srgb, var(--fx-surface) 78%, transparent);
    backdrop-filter: saturate(180%) blur(20px);
    -webkit-backdrop-filter: saturate(180%) blur(20px);
  }
}

/* ---------- app bar: Android ---------- */

/* Material's small top app bar: 64dp, leading title, no divider — depth arrives with the scroll. */
[data-os='android'] .appbar-row { grid-template-columns: auto minmax(0, 1fr) auto; padding: 0 4px; }
[data-os='android'] .appbar-title { justify-self: start; padding-left: 8px; font-size: 22px; font-weight: 500; }
[data-os='android'] .appbar-large { font-size: 28px; font-weight: 600; padding-left: 12px; }
[data-os='android'] .appbar.condensed { background: var(--fx-raise); box-shadow: var(--fx-shadow-sm); }

/* Material sizes its icon buttons at 48dp and tints them with ink, not with the accent. */
[data-os='android'] .appbar-back { width: 48px; height: 48px; color: var(--fx-ink); }
[data-os='android'] .appbar-back:active { background: var(--fx-bg); }

/* ---------- screen transitions ---------- */

/* iOS pushes laterally, Material fades through with a short rise. Both are skipped wholesale by
   the reduced-motion rule in base.css, which zeroes every animation on the page. */
[data-app='tg'] #app { animation-fill-mode: both; }

[data-os='ios'][data-app='tg'] #app[data-nav='push'] { animation: navPush var(--fx-slow) var(--fx-ease-out); }
[data-os='ios'][data-app='tg'] #app[data-nav='pop'] { animation: navPop var(--fx-slow) var(--fx-ease-out); }
[data-os='android'][data-app='tg'] #app[data-nav='push'],
[data-os='android'][data-app='tg'] #app[data-nav='pop'] { animation: navFade var(--fx-base) var(--fx-ease-out); }

@keyframes navPush { from { opacity: 0; transform: translateX(22px); } }
@keyframes navPop { from { opacity: 0; transform: translateX(-22px); } }
@keyframes navFade { from { opacity: 0; transform: translateY(10px); } }

/* ---------- tab bar ---------- */

.apptabs {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 60;
  display: flex;
  background: var(--fx-surface);
  border-top: 1px solid var(--fx-border);
  padding-bottom: max(var(--tg-bottom, 0px), env(safe-area-inset-bottom));
}

.tab {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  height: var(--tabbar-h);
  background: transparent;
  border: 0;
  font-family: var(--fx-text);
  color: var(--fx-ink2);
  cursor: pointer;
}

.tab span {
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.tab i { font-size: 22px; transition: background-color var(--fx-fast) ease, color var(--fx-fast) ease; }
.tab[aria-current='true'] { color: var(--fx-cyanink); }

[data-os='ios'] .tab { gap: 3px; font-size: 10px; font-weight: 500; }
[data-os='ios'] .tab i { font-size: 24px; }

/* Material marks the active destination with a pill behind the icon, not with colour alone. */
[data-os='android'] .tab { gap: 4px; font-size: 12px; font-weight: 500; }
[data-os='android'] .tab i { padding: 4px 18px; border-radius: 999px; }
[data-os='android'] .tab[aria-current='true'] i { background: var(--fx-cyansoft); color: var(--fx-cyanink); }

/* ---------- mini app screens ---------- */

/* 24px of air under the bar on every screen. The rhythm below it is set at the end of this
   file — see "screen rhythm". */
.tg-page { padding: 24px 16px 32px; }

.tg-h2 {
  margin: 0;
  font-family: var(--fx-display);
  font-size: 18px;
  font-weight: 600;
  letter-spacing: -.02em;
  color: var(--fx-ink);
}

/* The home screen's field is a button that opens the store; the store's is a real input. */
.tg-search { width: 100%; height: 44px; text-align: left; cursor: pointer; }
.tg-search-ghost { color: var(--fx-ink2); font-size: 15px; }
[data-os='ios'] .tg-search { border-radius: 10px; }
[data-os='android'] .tg-search { border-radius: 999px; height: 48px; padding: 0 18px; }

/* ---------- destination tiles ---------- */

.tg-tiles { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }

.tg-tile {
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: 60px;
  padding: 10px 12px;
  background: var(--fx-surface);
  border: 1px solid var(--fx-border);
  border-radius: var(--fx-r-card);
  color: inherit;
}

.tg-tile:active { border-color: var(--fx-cyan); }
.tg-tile-name { display: block; font-size: 14px; font-weight: 600; line-height: 1.25; }
.tg-tile-sub { display: block; margin-top: 2px; font-size: 12px; color: var(--fx-ink2); }

/* ---------- rows and links ---------- */

.tg-list { display: grid; }

.tg-row {
  display: flex;
  align-items: center;
  gap: 12px;
  min-height: 62px;
  padding: 10px 4px;
  color: inherit;
}

/* A list, so the rows are separated by a rule rather than each floated on its own card. */
.tg-row + .tg-row { border-top: 1px solid var(--fx-border); }
.tg-row:active { background: var(--fx-bg); }
.tg-row > i { color: var(--fx-ink2); font-size: 20px; flex-shrink: 0; }
.tg-row-name { display: block; font-size: 16px; font-weight: 500; }
.tg-row-sub {
  display: block;
  margin-top: 2px;
  font-size: 13px;
  color: var(--fx-ink2);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.tg-row-meta { flex-shrink: 0; font-size: 13px; font-weight: 500; color: var(--fx-cyanink); }

.tg-links { display: grid; gap: 8px; }

.tg-linkrow {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  min-height: 56px;
  padding: 10px 12px;
  background: var(--fx-surface);
  border: 1px solid var(--fx-border);
  border-radius: var(--fx-r-card);
  font-family: var(--fx-text);
  font-size: 15px;
  font-weight: 500;
  color: var(--fx-ink);
  text-align: left;
  cursor: pointer;
}

.tg-linkrow:active { background: var(--fx-bg); }
.tg-linkrow > i { color: var(--fx-ink2); font-size: 20px; flex-shrink: 0; }

.tg-linkrow-mark {
  display: grid;
  place-items: center;
  width: 34px;
  height: 34px;
  flex-shrink: 0;
  border-radius: 10px;
  background: var(--fx-cyansoft);
}

.tg-linkrow-mark i { font-size: 18px; color: var(--fx-cyanink); }

/* ---------- plan cards ---------- */

.tg-plans { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }

.tg-plan {
  display: grid;
  align-content: start;
  gap: 2px;
  padding: 14px;
  background: var(--fx-surface);
  border: 1px solid var(--fx-border);
  border-radius: var(--fx-r-feature);
  color: inherit;
}

.tg-plan-mark {
  display: grid;
  place-items: center;
  width: 34px;
  height: 34px;
  margin-bottom: 10px;
  border-radius: 10px;
  background: var(--fx-cyansoft);
}

.tg-plan-mark i { font-size: 18px; color: var(--fx-cyanink); }
.tg-plan-gb { font-family: var(--fx-display); font-size: 20px; font-weight: 600; letter-spacing: -.02em; }
.tg-plan-meta { font-size: 12px; color: var(--fx-ink2); }
.tg-plan-price { margin-top: 8px; font-size: 15px; font-weight: 600; color: var(--fx-cyanink); }

/* ---------- the "how it works" rail ---------- */

/* Scrolls sideways under the thumb. Full-bleed, so a card can sit against the screen edge and
   the gutter comes back as padding — the same idiom the site's step rail uses. */
.tg-rail {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: 76%;
  gap: 10px;
  overflow: auto hidden;
  overscroll-behavior-x: contain;
  scroll-snap-type: x proximity;
  margin-inline: -16px;
  padding-inline: 16px;
  scroll-padding-inline: 16px;
  scrollbar-width: none;
}

.tg-rail::-webkit-scrollbar { display: none; }

.tg-step {
  scroll-snap-align: start;
  padding: 16px;
  background: var(--fx-surface);
  border: 1px solid var(--fx-border);
  border-radius: var(--fx-r-feature);
}

.tg-step-n {
  display: grid;
  place-items: center;
  width: 26px;
  height: 26px;
  margin-bottom: 10px;
  border-radius: 50%;
  background: var(--fx-cyansoft);
  color: var(--fx-cyanink);
  font-size: 13px;
  font-weight: 600;
}

.tg-step-t { margin: 0 0 6px; font-family: var(--fx-display); font-size: 16px; letter-spacing: -.01em; }
.tg-step-d { margin: 0; font-size: 13px; line-height: 1.5; color: var(--fx-ink2); }

/* ---------- promo and support ---------- */

.tg-promo,
.tg-support {
  display: grid;
  justify-items: center;
  text-align: center;
  gap: 4px;
  padding: 24px 18px;
  border-radius: var(--fx-r-hero);
  color: inherit;
}

.tg-promo { background: var(--fx-cyansoft); }
.tg-support { background: var(--fx-raise); border: 1px solid var(--fx-border); }
.tg-promo > i, .tg-support > i { font-size: 32px; color: var(--fx-cyanink); margin-bottom: 8px; }
.tg-promo-t, .tg-support-t { font-family: var(--fx-display); font-size: 19px; font-weight: 600; letter-spacing: -.02em; }
.tg-promo-d, .tg-support-d { font-size: 14px; line-height: 1.5; color: var(--fx-ink2); }
.tg-promo-cta, .tg-support-cta { margin-top: 14px; }

/* ---------- store ---------- */

.tg-seg { margin: 0; }

/* ---------- my eSIMs ---------- */

.tg-esims { display: grid; gap: 12px; }
.tg-esim { display: grid; gap: 12px; color: inherit; }
.tg-esim-head { display: flex; align-items: center; gap: 11px; }
.tg-esim-bar { height: 6px; }
.tg-esim-foot { display: flex; justify-content: space-between; gap: 10px; }

.tg-blank {
  display: grid;
  justify-items: center;
  text-align: center;
  padding: 28px 20px;
  background: var(--fx-surface);
  border: 1px solid var(--fx-border);
  border-radius: var(--fx-r-hero);
}

.tg-blank-mark {
  display: grid;
  place-items: center;
  width: 52px;
  height: 52px;
  margin-bottom: 14px;
  border-radius: 16px;
  background: var(--fx-cyansoft);
}

.tg-blank-mark i { font-size: 24px; color: var(--fx-cyanink); }
.tg-blank-t { margin: 0 0 6px; font-family: var(--fx-display); font-size: 19px; letter-spacing: -.02em; }
.tg-blank-d { margin: 0 0 18px; font-size: 14px; line-height: 1.55; color: var(--fx-ink2); max-width: 30em; }

/* ---------- profile ---------- */

.tg-me {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 16px;
  background: var(--fx-surface);
  border: 1px solid var(--fx-border);
  border-radius: var(--fx-r-feature);
}

/* Matches .avatar.big, which is what stands in when Telegram gives no photo. */
.tg-me-photo { width: 46px; height: 46px; border-radius: 50%; object-fit: cover; flex-shrink: 0; }
.tg-me-name { display: block; font-family: var(--fx-display); font-size: 18px; font-weight: 600; letter-spacing: -.02em; }
.tg-me-sub { display: block; margin-top: 3px; font-size: 13px; color: var(--fx-ink2); }

.tg-empty { padding: 40px 8px; text-align: center; color: var(--fx-ink2); font-size: 15px; }

/* ---------- pages the mini app borrows from the site ---------- */

/* The buy bar has to clear .apptabs, which is a different height from the site's bottom nav it
   was measured against. */
[data-app='tg'] .sticky-cta {
  bottom: calc(var(--tabbar-h) + max(var(--tg-bottom, 0px), env(safe-area-inset-bottom)));
}

/* A mini app is a phone surface even when the client is a desktop window, so the structural
   swaps the site makes at 1024 have to stay on their mobile side. Each is named: `.mob-only`
   holds no display value of its own for `revert` to find. */
@media (min-width: 1024px) {
  [data-app='tg'] .desk-only { display: none !important; }
  [data-app='tg'] .plan-foot { display: flex !important; }
  [data-app='tg'] .sticky-cta { display: block !important; }
  [data-app='tg'] .dash-rail { display: flex !important; }
  [data-app='tg'] .dash { grid-template-columns: 1fr; gap: 0; }
}

/* The site sizes this block for a full page; inside the mini app the screen's own rhythm owns
   the spacing around it. */
[data-app='tg'] .faq-section { max-width: none; padding: 0; }

/* ---------- notifications ---------- */

.tg-notes { display: grid; gap: 10px; }

.tg-note {
  display: flex;
  gap: 12px;
  padding: 14px;
  background: var(--fx-surface);
  border: 1px solid var(--fx-border);
  border-radius: var(--fx-r-card);
  color: inherit;
}

/* Unread is carried by the surface and the edge, not by a coloured left rule. */
.tg-note.unread { background: var(--fx-raise); border-color: var(--fx-cyan); }
.tg-note:active { background: var(--fx-bg); }

.tg-note-mark {
  display: grid;
  place-items: center;
  width: 38px;
  height: 38px;
  flex-shrink: 0;
  border-radius: 12px;
}

.tg-note-mark i { font-size: 19px; }
.tg-note-mark.tone-cyan { background: var(--fx-cyansoft); color: var(--fx-cyanink); }
.tg-note-mark.tone-warn { background: var(--fx-warnsoft); color: var(--fx-warn); }
.tg-note-mark.tone-ok { background: var(--fx-oksoft); color: var(--fx-ok); }

.tg-note-t { display: block; font-size: 15px; font-weight: 600; }
.tg-note-d { display: block; margin-top: 3px; font-size: 13px; line-height: 1.5; color: var(--fx-ink2); }
.tg-note-at { display: block; margin-top: 6px; font-size: 12px; color: var(--fx-ink2); }

/* ---------- screen rhythm ---------- */

/* Last in the file on purpose. A media query adds no specificity and neither does a `+`, so
   these tie with every `.tg-*` component rule above and win only by position. Written any
   earlier, `.tg-h2 { margin: 0 }` would take the gap straight back off the headings — which is
   exactly what it did.
 *
 * 16px between blocks, and a heading kept closer to the block it introduces than to the
 * section it follows. */
.tg-page > * + * { margin-top: 16px; }
.tg-h2 + * { margin-top: 10px; }

/* ---------- home stories ----------
   The rail of round covers, and the full-screen viewer behind it. Structure only — the ring
   colours come from the tone tokens, so both skins get a rail that matches themselves. */

/*
 * The rail scrolls freely, the way a story rail does — no snapping. Snap points belong to things
 * the width of the screen, like the banner below; on a row of 64px circles they only tug the end
 * of a drag onto the nearest circle, which is a gesture nobody asked for.
 */
.stories {
  display: flex;
  gap: 12px;
  /* the rail runs to both page edges while the screen keeps its 16px gutter */
  margin: 0 -16px;
  padding: 0 16px 2px;
  overflow-x: auto;
  /* the drag stops at the ends of the rail instead of turning into Telegram's swipe-back */
  overscroll-behavior-x: contain;
  scrollbar-width: none;
}

.stories::-webkit-scrollbar { display: none; }

.story {
  flex-shrink: 0;
  display: grid;
  justify-items: center;
  gap: 6px;
  width: 72px;
  padding: 0;
  background: none;
  border: 0;
  cursor: pointer;
}

/* The ring is the padding of a filled disc: a 2px gap between it and the cover is what makes it
   read as a ring rather than a border. */
.story-ring {
  display: grid;
  place-items: center;
  width: 64px;
  height: 64px;
  border-radius: 50%;
  background: var(--tone, var(--fx-cyan));
  transition: transform var(--fx-fast) var(--fx-ease);
}

.story:active .story-ring { transform: scale(.94); }

/* Opened already — the ring steps back and stops competing with the unseen ones. The tone rules
   below only set a variable, so this wins on specificity wherever it sits. */
.story-ring.seen { background: var(--fx-border); }

/* The tone is set once, here, and the ring and the viewer both read it — so a skin only has to
   answer the five --fx-tone-* tokens to get a rail in its own colours. */
.story-ring.tone-promo,
.story-view[data-tone='promo'] { --tone: var(--fx-tone-promo); }
.story-ring.tone-info,
.story-view[data-tone='info'] { --tone: var(--fx-tone-info); }
.story-ring.tone-product,
.story-view[data-tone='product'] { --tone: var(--fx-tone-product); }
.story-ring.tone-bonus,
.story-view[data-tone='bonus'] { --tone: var(--fx-tone-bonus); }
.story-ring.tone-news,
.story-view[data-tone='news'] { --tone: var(--fx-tone-news); }

.story-cover {
  display: grid;
  place-items: center;
  width: 58px;
  height: 58px;
  border-radius: 50%;
  /* the page ground, not the card one: the gap has to read as a hole in the ring */
  background: var(--fx-bg);
  color: var(--fx-ink);
  font-size: 24px;
}

.story-flag { font-size: 28px; line-height: 1; }

.story-label {
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 12px;
  font-weight: 500;
  color: var(--fx-ink2);
}

/* ---------- the viewer ---------- */

/* The page behind must not scroll while a story is open, and on iOS that needs the position
   lock rather than overflow alone. */
html.story-open, html.story-open body { overflow: hidden; }

.story-view {
  position: fixed;
  inset: 0;
  z-index: 200;
  display: grid;
  grid-template-rows: auto 1fr;
  background: var(--fx-deep);
  animation: storyIn var(--fx-base) var(--fx-ease-out);
}

.story-view.out { animation: storyOut var(--fx-fast) var(--fx-ease) forwards; }

@keyframes storyIn { from { opacity: 0; transform: scale(.96); } }
@keyframes storyOut { to { opacity: 0; } }

.story-head {
  position: relative;
  z-index: 2;
  padding: max(var(--tg-top, 0px), env(safe-area-inset-top)) 12px 0;
}

.story-bars { display: flex; gap: 4px; padding-top: 10px; }

.story-bar {
  flex: 1;
  height: 3px;
  border-radius: 999px;
  background: var(--fx-white-16);
  overflow: hidden;
}

.story-bar i {
  display: block;
  width: 0;
  height: 100%;
  border-radius: 999px;
  background: #fff;
}

/* Width is what grows, so the fill reads left to right. The active bar's width and transition
   are set from JS, which is what lets a hold freeze it and a resume finish the remaining time. */
.story-bar i.done { width: 100%; }

.story-top {
  display: flex;
  align-items: center;
  gap: 10px;
  height: 48px;
}

.story-top-name {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-family: var(--fx-display);
  font-size: 15px;
  font-weight: 600;
  color: var(--fx-deepink);
}

.story-x {
  display: grid;
  place-items: center;
  width: 36px;
  height: 36px;
  border: 0;
  border-radius: 50%;
  background: transparent;
  color: var(--fx-deepink);
  font-size: 22px;
  cursor: pointer;
}

/* The slide sits low, the way a story that is mostly artwork does — centred, it read as adrift
   in the middle of an empty frame. */
.story-body {
  display: grid;
  align-items: end;
  padding: 0 24px calc(40px + max(var(--tg-bottom, 0px), env(safe-area-inset-bottom)));
}

.story-slide {
  display: grid;
  justify-items: start;
  gap: 14px;
  max-width: 22em;
  animation: storySlide var(--fx-slow) var(--fx-ease-out);
}

@keyframes storySlide { from { opacity: 0; transform: translateY(10px); } }

.story-mark {
  display: grid;
  place-items: center;
  width: 64px;
  height: 64px;
  margin-bottom: 4px;
  border-radius: 20px;
  background: var(--fx-white-12);
  color: var(--fx-deepink);
  font-size: 30px;
}

.story-h {
  margin: 0;
  font-family: var(--fx-display);
  font-size: 30px;
  font-weight: 700;
  line-height: 1.1;
  letter-spacing: -.02em;
  color: var(--fx-deepink);
}

.story-p {
  margin: 0;
  font-size: 16px;
  line-height: 1.5;
  color: var(--fx-deepink2);
}

.story-cta { margin-top: 6px; }

/* The two tap halves sit under the content but over the ground, so the CTA still takes its own
   clicks while anywhere else advances. */
.story-half {
  position: absolute;
  top: 0;
  bottom: 0;
  width: 38%;
  z-index: 1;
  padding: 0;
  border: 0;
  background: transparent;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

.story-back { left: 0; }
.story-fwd { right: 0; width: 62%; }

/* A story's own colour washes the ground it is told on — mixed down into the deep ink rather
   than listed as five more hand-picked darks, so it follows whatever the skin's tone is. */
@supports (background: color-mix(in srgb, red 50%, white)) {
  .story-view {
    background: linear-gradient(160deg, color-mix(in srgb, var(--tone) 30%, var(--fx-deep)), var(--fx-deep) 62%);
  }
}

/* ---------- home banners ----------
   The promo carousel under the stories. Tones come from the same --fx-tone-* tokens the rail
   uses, so a banner wears whichever palette the skin is in. */

.banners { display: grid; gap: 10px; }

.banner-rail {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: 100%;
  gap: 12px;
  /* the rail runs to both page edges while the screen keeps its 16px gutter */
  margin: 0 -16px;
  padding: 0 16px;
  overflow-x: auto;
  scrollbar-width: none;
  scroll-snap-type: x mandatory;
}

.banner-rail::-webkit-scrollbar { display: none; }

.banner {
  position: relative;
  display: block;
  min-height: 132px;
  padding: 18px;
  border-radius: var(--fx-r-feature);
  background: var(--tone, var(--fx-cyan));
  color: var(--fx-deepink);
  overflow: hidden;
  scroll-snap-align: center;
}

/* The banner is a link, so base.css's `a:not(.btn):hover` would recolour every line on it —
   white copy over a photograph turning brand-coloured, which is both ugly and unreadable. The
   card holds its ink; the pill takes the hover instead, being the part that looks pressable.
   Same specificity as the base rule, and tg.css loads after it. */
a.banner:hover,
a.banner:active { color: var(--fx-deepink); }

.banner-art {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 62% 40%;
}

/* The scrim is what makes white copy legible over a photograph whose brightness we do not
   control, so it is the deep ink rather than the banner's tone — a light tone washed over a
   light photo left the second line barely readable. The tone still owns the card underneath and
   shows on a banner that carries no art. */
.banner-art + .banner-copy::before {
  content: '';
  position: absolute;
  inset: 0;
  background: var(--fx-deep);
  opacity: .68;
}

@supports (background: color-mix(in srgb, red 50%, transparent)) {
  .banner-art + .banner-copy::before {
    opacity: 1;
    background: linear-gradient(96deg,
      color-mix(in srgb, var(--fx-deep) 88%, transparent) 0%,
      color-mix(in srgb, var(--fx-deep) 64%, transparent) 54%,
      color-mix(in srgb, var(--fx-deep) 22%, transparent) 100%);
  }
}

/* Deliberately not positioned: that lets the scrim below span the whole card instead of stopping
   at the edge of the copy. The children take the positioning instead, which is what lifts them
   over both the art and the scrim. */
.banner-copy {
  display: grid;
  justify-items: start;
  gap: 6px;
  max-width: 19em;
}

.banner-copy > * { position: relative; }

.banner-title {
  font-family: var(--fx-display);
  font-size: 19px;
  font-weight: 700;
  line-height: 1.2;
  letter-spacing: -.02em;
}

.banner-text { font-size: 13px; line-height: 1.45; opacity: .92; }

.banner-cta {
  margin-top: 6px;
  padding: 8px 14px;
  border-radius: var(--fx-r-pill);
  background: var(--fx-white-16);
  font-size: 13px;
  font-weight: 600;
  transition: background-color var(--fx-fast) var(--fx-ease), color var(--fx-fast) var(--fx-ease);
}

/* Translucent at rest, solid on hover — the one thing on the card that changes. */
.banner:hover .banner-cta,
.banner:active .banner-cta {
  background: var(--fx-deepink);
  color: var(--fx-deep);
}

/* ---------- dots ---------- */

.banner-dots { display: flex; justify-content: center; gap: 6px; }

.banner-dot {
  position: relative;
  width: 6px;
  height: 6px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: var(--fx-border);
  cursor: pointer;
  transition: width var(--fx-base) var(--fx-ease), background-color var(--fx-base) var(--fx-ease);
}

/* 6px drawn, 44px touched — the same top-up the site's small controls use. */
.banner-dot::after { content: ''; position: absolute; inset: -19px -8px; }
.banner-dot[aria-current='true'] { width: 18px; border-radius: 999px; background: var(--fx-ink2); }

/* ---------- region grid ----------
   Two columns of cards instead of one column of rows: a region's name runs long ("Yaqin Sharq va
   Shimoliy Afrika") and a row gave it one cramped line beside a price, while a card gives it two
   and still has room for the count and the from-price underneath. */

.tg-rgrid { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }

.tg-rcard {
  display: grid;
  align-content: start;
  gap: 2px;
  min-height: 150px;
  padding: 14px;
  background: var(--fx-surface);
  border: 1px solid var(--fx-border);
  border-radius: var(--fx-r-card);
  color: inherit;
}

.tg-rcard:active { border-color: var(--fx-cyan); }
.tg-rcard img { margin-bottom: 10px; }

.tg-rcard-name {
  font-size: 14px;
  font-weight: 600;
  line-height: 1.25;
  /* Always two lines tall, clamped at two: a one-line name would otherwise pull its count and
     price up while the card beside it kept them low, and the prices stopped lining up. */
  min-height: 2.5em;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.tg-rcard-count { font-size: 12px; color: var(--fx-ink2); }

.tg-rcard-price {
  padding-top: 8px;
  font-size: 14px;
  font-weight: 600;
  color: var(--fx-cyanink);
}

/* The rest of the grid is one tap away rather than a scroll: eight cards is a screenful. */
.tg-more {
  width: 100%;
  min-height: 44px;
  margin-top: 10px;
  padding: 0 16px;
  background: var(--fx-cyansoft);
  border: 0;
  border-radius: var(--fx-r-btn);
  font-family: var(--fx-text);
  font-size: 14px;
  font-weight: 600;
  color: var(--fx-cyanink);
  cursor: pointer;
}
