/* ═══════════════════════════════════════════════════════════
   Feed: the home page's top-stories slider and the list of rows
   (home, category, tag and search pages).
   ═══════════════════════════════════════════════════════════ */

/* ── Feed list: one panel of rows instead of a grid of cards — a single line to scan.
   The rules between rows belong to the component; sections still part by space.
   A row is a read-also card laid sideways: the picture (tag and bookmark on it) at the
   end, the title, the excerpt and the meta line beside it — the meta on the picture's
   bottom line. On a phone it stands up into a card. ── */
.feed-list {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  overflow: hidden;
}
.feed-row {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1fr) 224px;
  grid-template-areas: "body media";
  gap: var(--sp-6);
  padding: var(--sp-5) var(--sp-6);
  transition: background var(--dur-1) var(--ease);
}
.feed-row + .feed-row { border-top: 1px solid var(--border); }
/* Two title lines, two excerpt lines and the meta come to the picture's 126px: the text
   fills its height, the meta sits on its bottom line. A longer title just runs past it. */
.feed-row__body { grid-area: body; display: flex; flex-direction: column; gap: var(--sp-2); min-width: 0; }
.feed-row__meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-1) var(--sp-4);
  margin-top: auto;
  font-size: var(--text-xs);
  line-height: var(--lh-16);
  color: var(--text-tertiary);
}
.feed-row__date, .feed-row__time { display: inline-flex; align-items: center; gap: var(--sp-1); }
:is(.feed-row__date, .feed-row__time) .icon { width: 16px; height: 16px; }
.feed-row__title {
  font-size: var(--text-xl);
  line-height: var(--lh-28);
  letter-spacing: -0.025em;
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
/* The whole row is the link; the tag and the bookmark stay clickable on top (z-index 2). */
.feed-row__link::after { content: ""; position: absolute; inset: 0; }
/* The panel clips an outer outline, so the focus ring is drawn inside the row. */
.feed-row__link:focus-visible { outline: none; }
.feed-row:has(.feed-row__link:focus-visible) { outline: 2px solid var(--accent); outline-offset: -2px; }
.feed-row__excerpt {
  font-size: var(--text-sm);
  line-height: var(--lh-20);
  color: var(--text-secondary);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.feed-row__media {
  grid-area: media;
  align-self: start;
  position: relative;
  aspect-ratio: 16 / 9;
  overflow: hidden;
  border-radius: var(--r-lg);
  background: var(--surface-raised);
}
/* The tag stops 8px short of the bookmark: 12 in from each side, the bookmark's 24, a gap of 8. */
.feed-row__media .tag--on-media { max-width: calc(100% - var(--sp-3) - 32px - var(--sp-3)); }
.feed-row__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform var(--dur-3) var(--ease);
}
/* A row unsaved on the «Избранное» page folds away. */
.feed-row.is-leaving { opacity: 0; transform: translateX(-12px); transition: opacity var(--dur-2) var(--ease-exit), transform var(--dur-2) var(--ease-exit); }
@media (hover: hover) {
  .feed-row:hover { background: var(--overlay-hover); }
  .feed-row:hover .feed-row__media img { transform: scale(1.03); }
}
/* A phone: the row stands up into a card — the picture across, then the text; the meta
   at the ends of its line, as on a card. */
@media (max-width: 640px) {
  .feed-row {
    grid-template-columns: minmax(0, 1fr);
    grid-template-areas: "media" "body";
    gap: var(--sp-4);
    padding: var(--sp-4);
  }
  .feed-row__title { font-size: var(--text-lg); line-height: var(--lh-24); }
  .feed-row__excerpt { -webkit-line-clamp: 3; }
  .feed-row__meta { justify-content: space-between; }
}

/* ── Hero slider: one story at a time, nothing of its neighbours showing. Without JS
   it is a native scroll-snap strip of full-width slides (swipe and trackpad work on
   their own). Once hero_controller runs (.is-ready) the slides lie in a stack inside
   one panel and change by a crossfade — below; it adds autoplay, the progress bars,
   the arrows and its own swipe. ── */
.hero { margin-top: var(--sp-8); }
.hero__viewport {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: 100%;
  gap: var(--sp-4);
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
}
.hero__viewport::-webkit-scrollbar { display: none; }

/* A bento panel round the cover: the cover is a picture (20), 12px in, so the panel's
   corner is 20 + 12 = 32. */
.hero__slide {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 3fr) minmax(0, 2fr);
  gap: var(--sp-6);
  padding: var(--sp-3);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-3xl);
  scroll-snap-align: start;
  transition: border-color var(--dur-2) var(--ease);
}

/* The stack. The panel moves from each slide to the viewport — the same box, so nothing
   jumps when the controller starts — and the slides themselves turn transparent: the
   incoming cover then fades in over the outgoing one, which stays opaque underneath
   (two half-transparent panels would dip to the page background halfway). The text
   cannot be laid over text, so the outgoing one leaves first and the new one follows.
   All slides share one grid cell: the panel is as tall as the tallest story and keeps
   its height from slide to slide. touch-action leaves the vertical scroll to the
   browser and the horizontal swipe to the controller. */
.hero.is-ready .hero__viewport {
  grid-auto-flow: row;
  grid-template-columns: minmax(0, 1fr);
  gap: 0;
  overflow: visible;
  scroll-snap-type: none;
  touch-action: pan-y;
  padding: var(--sp-3);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-3xl);
  transition: border-color var(--dur-2) var(--ease);
}
.hero.is-ready .hero__slide {
  grid-area: 1 / 1;
  padding: 0;
  background: none;
  border: 0;
  border-radius: 0;
  visibility: hidden;
  pointer-events: none;
}
.hero.is-ready .hero__slide.is-current { z-index: 2; visibility: visible; pointer-events: auto; }
.hero.is-ready .hero__slide.is-leaving { z-index: 1; visibility: visible; }
/* A hidden slide waits faded out, its cover slightly enlarged and its text lowered;
   none of this is animated on the way back (the slide is hidden by then). */
.hero.is-ready .hero__media,
.hero.is-ready .hero__body { opacity: 0; }
.hero.is-ready .hero__media > * { scale: 1.06; }
.hero.is-ready .hero__body { translate: 0 12px; }
/* In: the cover fades in and settles, the text rises once the old one has gone — 500ms,
   the design system's longest step (a screen's change), easing out as an entrance. */
.hero.is-ready .hero__slide.is-current .hero__media {
  opacity: 1;
  transition: opacity var(--dur-4) var(--ease);
}
.hero.is-ready .hero__slide:is(.is-current, .is-leaving) .hero__media > * {
  scale: 1;
  transition: scale var(--dur-4) var(--ease), transform var(--dur-3) var(--ease);
}
.hero.is-ready .hero__slide.is-current .hero__body {
  opacity: 1;
  translate: 0;
  transition: opacity var(--dur-4) var(--ease) var(--dur-2), translate var(--dur-4) var(--ease) var(--dur-2);
}
/* Out: the cover stays under the incoming one, the text fades — an exit, faster and easing in. */
.hero.is-ready .hero__slide.is-leaving .hero__media { opacity: 1; }
.hero.is-ready .hero__slide.is-leaving .hero__body {
  opacity: 0;
  translate: 0;
  transition: opacity var(--dur-2) var(--ease-exit);
}
/* base.css shortens the durations there, not the delay: the text would be missing for
   a moment. */
@media (prefers-reduced-motion: reduce) {
  .hero.is-ready .hero__slide.is-current .hero__body { transition-delay: 0s; }
}
.hero__media {
  position: relative;
  display: block;
  aspect-ratio: 16 / 9;
  overflow: hidden;
  border-radius: var(--r-lg);
  background: var(--surface-raised);
}
.hero__cover { display: block; width: 100%; height: 100%; }
.hero__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform var(--dur-3) var(--ease);
}
/* Positioned: the title link's stretched area below is measured from this column, always.
   It used to be meant for the whole slide, but the text's rise (translate) made the column
   its containing block anyway, and the cover was left dead under its own zoom. The
   cover is a link of its own now (_hero). */
.hero__body {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: var(--sp-4);
  min-width: 0;
  padding-block: var(--sp-5);
  padding-inline: 0 var(--sp-5);
}
/* In steps, not fluid: a clamp() size cannot keep its line on the grid. */
.hero__title {
  font-size: 30px;
  line-height: var(--lh-36);
  letter-spacing: -0.02em;
  display: -webkit-box;
  -webkit-line-clamp: 4;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
/* The text column and the panel round it: the 12px of padding outside the slide (or of the
   slide, without JS) and the 24px gap to the cover, so nothing between the two links is dead. */
.hero__link::after {
  content: "";
  position: absolute;
  inset: calc(-1 * var(--sp-3));
  inset-inline-start: calc(-1 * var(--sp-6));
}
.hero__link:focus-visible { outline: none; }
.hero__slide:has(.hero__link:focus-visible) { outline: 2px solid var(--accent); outline-offset: 2px; }
/* In the stack the focus ring goes round the panel. */
.hero.is-ready .hero__slide:has(.hero__link:focus-visible) { outline: none; }
.hero.is-ready .hero__viewport:has(.hero__link:focus-visible) { outline: 2px solid var(--accent); outline-offset: 2px; }
.hero__excerpt {
  font-size: var(--text-base);
  line-height: var(--lh-24);
  color: var(--text-secondary);
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.hero__meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-1) var(--sp-3);
  margin-top: auto;
  font-size: var(--text-xs);
  line-height: var(--lh-16);
  color: var(--text-tertiary);
}
.hero__date, .hero__time { display: inline-flex; align-items: center; gap: var(--sp-1); }
:is(.hero__date, .hero__time) .icon { width: 16px; height: 16px; }
@media (hover: hover) {
  .hero__slide:hover,
  .hero.is-ready .hero__viewport:hover { border-color: var(--border-hover); }
  .hero__slide:hover .hero__media img { transform: scale(1.03); }
}

/* Progress bars (one per story, each a button) and the arrows. Hidden until the
   controller runs: without it they would do nothing. */
.hero__controls { display: none; }
.hero.is-ready .hero__controls {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-4);
  margin-top: var(--sp-4);
}
.hero__steps { display: flex; gap: var(--sp-2); }
.hero__step {
  display: flex;
  align-items: center;
  width: 48px;
  height: 24px;
  padding: 0;
  background: none;
  border: 0;
  border-radius: var(--r-xs);
  cursor: pointer;
}
.hero__step:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.hero__step-track {
  position: relative;
  display: block;
  width: 100%;
  height: 2px;
  overflow: hidden;
  background: var(--border-strong);
  transition: background var(--dur-1) var(--ease);
}
@media (hover: hover) {
  .hero__step:hover .hero__step-track { background: var(--text-tertiary); }
}
.hero__step-fill {
  position: absolute;
  inset: 0;
  background: var(--text-tertiary);
  transform: scaleX(0);
  transform-origin: 0 50%;
}
.hero__step.is-done .hero__step-fill { transform: scaleX(1); }
.hero__step.is-active .hero__step-fill { transform: scaleX(1); background: var(--accent); }
/* The current bar fills while its story is on screen; the controller moves on at the
   animation's end. Never under reduced motion — base.css shortens every animation to
   0.01ms there, which would flip through the stories as fast as frames allow. */
@keyframes hero-progress { from { transform: scaleX(0); } to { transform: scaleX(1); } }
@media (prefers-reduced-motion: no-preference) {
  .hero.is-playing .hero__step.is-active .hero__step-fill { animation: hero-progress var(--hero-interval, 6s) linear both; }
  .hero.is-playing.is-paused .hero__step.is-active .hero__step-fill { animation-play-state: paused; }
}
.hero__arrows { display: flex; gap: var(--sp-2); }

@media (max-width: 1200px) {
  .hero__title { font-size: var(--text-2xl); line-height: var(--lh-32); }
}
@media (max-width: 900px) {
  .hero__slide { grid-template-columns: minmax(0, 1fr); gap: var(--sp-4); }
  .hero__body { padding: 0 var(--sp-2) var(--sp-2); }
  /* The cover is above the text here: the 16px gap is upward. */
  .hero__link::after { inset: calc(-1 * var(--sp-3)); top: calc(-1 * var(--sp-4)); }
  /* A phone: at most three lines of title and three of description. */
  .hero__title { -webkit-line-clamp: 3; }
  .hero__excerpt { -webkit-line-clamp: 3; }
}
@media (max-width: 640px) {
  .hero__title { font-size: 20px; line-height: var(--lh-28); }
  .hero__step { width: 32px; }
}

/* ── Bottom bar: the categories and the filter button in one light glass pill (theme-day:
   dark on the dark page, the bar went unnoticed), sticky at the bottom of the feed's
   container, with a haze under it. Only the pill takes clicks — the bar's empty sides
   must not block the rows under them. ── */
.feed-bar {
  position: sticky;
  bottom: var(--sp-6);
  z-index: 980;
  display: flex;
  justify-content: center;
  margin-top: var(--sp-8);
  pointer-events: none;
}
/* Keyboard focus never lands under the bar. */
html:has(.feed-bar) { scroll-padding-bottom: 96px; }
.feed-bar__pill {
  position: relative;
  z-index: 1;
  pointer-events: auto;
  display: flex;
  gap: var(--sp-1);
  max-width: 100%;
  padding: var(--sp-1);
  /* Nearly opaque: the dark page showing through greyed it to the thumb's own tone. The
     design system's thick blur (32), and no outer shadow on a material (ADR-0009). */
  background: rgba(245, 245, 247, 0.94);
  backdrop-filter: blur(32px);
  -webkit-backdrop-filter: blur(32px);
  border: 1px solid var(--border);
  border-radius: var(--r-md); /* 16 = the segments' 12 + the 4px padding */
}
.feed-bar__segments { flex: 0 1 auto; border-radius: var(--r-control-l); }
.feed-bar__btn {
  position: relative;
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 48px;
  height: 48px;
  padding: 0;
  color: var(--text-secondary);
  background: transparent;
  border: 0;
  border-radius: var(--r-control-l);
  cursor: pointer;
  transition: color var(--dur-1) var(--ease), background var(--dur-1) var(--ease);
}
@media (hover: hover) {
  .feed-bar__btn:hover { color: var(--text); background: var(--surface); }
}
/* Inside: an outer ring would cross the pill's edge and the next segment. */
.feed-bar__btn:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.feed-bar__btn .icon { width: 20px; height: 20px; }
/* The dialog's footer takes the bar's place while it is open. */
/* Hidden only once the dialog over it is opaque (100ms) — no gap between the two. */
.feed-bar:has(.feed-filters:popover-open) .feed-bar__pill { visibility: hidden; transition: visibility 0s var(--dur-1); }

/* On the day surfaces (tokens.css, .theme-day) a chosen option keeps dark text — the day
   green on its light tint reads at about 2.7:1; the green border and tint mark the choice. */
.theme-day .choice:has(:checked) > span { color: var(--text); }
/* The grey badge vanishes on the light pill: a dark one. */
.theme-day .count-badge--neutral { color: var(--bg); background: var(--text); }

/* Haze: content under the bar blurs, more toward the screen's edge, in an arc — the
   Hark scroll-edge recipe (DOCS/ДИЗАЙН-СИСТЕМА/20, §5.1): six backdrop-filter layers,
   the blur doubling from one to the next, each seen in its own overlapping band, the
   strongest at the bottom edge. The strength goes by height alone, so at the pill's
   level the feed blurs alike across every column; a first version banded it by the
   distance from the bottom centre, and the text beside the pill stayed sharp. The arc
   is a second mask on every layer, intersected with its band: an ellipse wider than the
   block, so the bottom corners lie well inside it and the top edge curves down toward
   the sides, softly.
   Down to the screen's edge while the bar is stuck, and only then (feed_bar_controller
   sets is-stuck): parked above the subscribe card, the bar has the pagination right
   above it. The layers fade, not the block — an ancestor with opacity < 1 is a backdrop
   root, and the layers would blur nothing while it faded. */
.feed-bar__haze {
  --haze-shape: radial-gradient(ellipse 100% 100% at 50% 100%, #000 70%, #0000 100%);
  position: absolute;
  z-index: 0;
  bottom: calc(-1 * var(--sp-6));
  left: 0;
  width: 100%; /* the bar's padding box: the feed with its gutters */
  height: 200px;
}
.feed-bar__haze > i {
  position: absolute;
  inset: 0;
  opacity: 0;
  -webkit-backdrop-filter: blur(var(--haze-blur));
  backdrop-filter: blur(var(--haze-blur));
  -webkit-mask-image: linear-gradient(to bottom, var(--haze-band)), var(--haze-shape);
  mask-image: linear-gradient(to bottom, var(--haze-band)), var(--haze-shape);
  -webkit-mask-composite: source-in;
  mask-composite: intersect;
  transition: opacity var(--dur-3) var(--ease-morph);
}
.feed-bar.is-stuck .feed-bar__haze > i { opacity: 1; }
.feed-bar__haze > i:nth-child(1) { --haze-blur: 0.15px; --haze-band: #0000 0%, #000 0% 16.7%, #0000 33.3%; }
.feed-bar__haze > i:nth-child(2) { --haze-blur: 0.3px; --haze-band: #0000 0%, #000 16.7% 33.3%, #0000 50%; }
.feed-bar__haze > i:nth-child(3) { --haze-blur: 0.6px; --haze-band: #0000 16.7%, #000 33.3% 50%, #0000 66.7%; }
.feed-bar__haze > i:nth-child(4) { --haze-blur: 1.2px; --haze-band: #0000 33.3%, #000 50% 66.7%, #0000 83.3%; }
.feed-bar__haze > i:nth-child(5) { --haze-blur: 2.4px; --haze-band: #0000 50%, #000 66.7% 83.3%, #0000 100%; }
.feed-bar__haze > i:nth-child(6) { --haze-blur: 4.8px; --haze-band: #0000 66.7%, #000 83.3% 100%; }
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .feed-bar__haze { display: none; }
}
@media (prefers-reduced-transparency: reduce) {
  .feed-bar__haze { display: none; }
}

@media (max-width: 640px) {
  .feed-bar { bottom: var(--sp-3); }
  .feed-bar__haze { bottom: calc(-1 * var(--sp-3)); height: 140px; }
  .feed-bar__pill { width: 100%; border-radius: var(--r-sm); } /* 12 = 8 + 4 */
  .feed-bar__segments { flex: 1 1 auto; border-radius: var(--r-control); }
  .feed-bar .segmented__item { height: 40px; padding: 0 var(--sp-3); border-radius: var(--r-control); }
  .feed-bar .segmented__thumb { border-radius: var(--r-control); }
  .feed-bar__btn { width: 40px; height: 40px; border-radius: var(--r-control); }
  .feed-bar__btn .count-badge { top: 2px; inset-inline-end: 2px; }
}

/* ── Filter dialog: a native popover laid over the bar. It grows out of the bar's own
   rectangle (feed_bar_controller hands over --fb-bottom, --fb-width, --fb-height), so the
   bar seems to turn into the dialog, its [Apply | Reset] footer where the bar was. On a
   phone it is a bottom sheet. Everything in it — the title row, the options, the two
   buttons — stands in one 20px column (the design system's ADR-0018 §3); the options
   scroll between the title and the buttons with fading edges (ADR-0020). The closed state is the UA's display: none — set display
   only for the open one, or it would never close. ── */
.feed-filters {
  /* It sits inside .feed-bar, whose pointer-events: none is inherited — the top layer
     does not reset it. Without this every click went through the dialog (and its
     backdrop) to the feed row underneath: «Применить» opened an article. */
  pointer-events: auto;
  position: fixed;
  inset: auto 0 var(--fb-bottom, var(--sp-6));
  width: min(max(var(--fb-width, 560px), 520px), calc(100vw - 2 * var(--gutter)));
  max-height: min(680px, calc(100dvh - var(--header-height) - var(--sp-10)));
  margin: 0 auto;
  padding: 0;
  overflow: hidden;
  color: var(--text);
  /* theme-day: the pill's own light, so the bar turns into the dialog without a change
     of colour on the way. */
  background: var(--bg);
  border: 1px solid var(--border-strong);
  border-radius: var(--r-md); /* the pill's 16: its 48px buttons' 12 + the 4px around them */
  box-shadow: var(--sh-card-hover);
}
.feed-filters:popover-open { display: flex; flex-direction: column; }
.feed-filters::backdrop { background: rgba(15, 16, 17, 0.4); }
.feed-filters__form { display: flex; flex: 1; flex-direction: column; min-height: 0; }
.feed-filters__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-4);
  padding: var(--sp-4) var(--sp-5) var(--sp-2);
}
.feed-filters__title { font-size: var(--text-lg); line-height: var(--lh-24); }
.feed-filters__body {
  display: grid;
  gap: var(--sp-5);
  padding: var(--sp-2) var(--sp-5) var(--sp-5);
  overflow-y: auto;
  overscroll-behavior: contain;
}
.feed-filters__group { min-width: 0; margin: 0; padding: 0; border: 0; }
.feed-filters__legend {
  margin-bottom: var(--sp-3);
  padding: 0;
  font-size: var(--text-sm);
  line-height: var(--lh-20);
  color: var(--text-tertiary);
}
/* The buttons stand on the options' column, 8px apart like the chips. Until 19.10.2026 the
   row copied the bar — 4px round two buttons — and stuck out past the column on each side. */
.feed-filters__foot {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--sp-2);
  padding: var(--sp-3) var(--sp-5) var(--sp-5);
}
/* No line above the footer and no outline on «Сбросить»: an outlined button against a
   divider was a box against a line. Their fill is what sets them apart from the options. */
.feed-filters__foot .btn--secondary { border-color: transparent; }
/* Open and close are one gesture each way, with nothing switched in a single frame. The
   dialog grows out of the bar's rectangle (300ms, a system move) and turns opaque within
   the first 100ms. The pill under it stays visible until then (the :has rule above), so
   there is never a gap. Closing is an exit — faster, easing in: it shrinks back into that
   rectangle in 200ms and dissolves over the last 100 into the pill showing under it.
   Without that its [Apply | Reset] row turned into the categories in one frame. The dim
   fades in and out with it. Each direction takes the transition of the state it goes to. */
@supports selector(:popover-open) {
  .feed-filters {
    --fb-closed: inset(calc(100% - var(--fb-height, 58px)) max(0px, calc((100% - var(--fb-width, 100%)) / 2)) 0 round var(--r-md));
    clip-path: inset(0 round var(--r-md));
  }
  .feed-filters:popover-open {
    opacity: 1;
    transition: clip-path var(--dur-3) var(--ease-morph), opacity var(--dur-1) var(--ease),
                overlay var(--dur-3) allow-discrete, display var(--dur-3) allow-discrete;
  }
  .feed-filters:not(:popover-open) {
    clip-path: var(--fb-closed);
    opacity: 0;
    transition: clip-path var(--dur-2) var(--ease-exit), opacity var(--dur-1) var(--ease-exit) var(--dur-1),
                overlay var(--dur-2) allow-discrete, display var(--dur-2) allow-discrete;
  }
  @starting-style {
    .feed-filters:popover-open { clip-path: var(--fb-closed); opacity: 0; }
  }
  .feed-filters::backdrop {
    background: rgba(15, 16, 17, 0);
    transition: background var(--dur-2) var(--ease-exit),
                overlay var(--dur-2) allow-discrete, display var(--dur-2) allow-discrete;
  }
  .feed-filters:popover-open::backdrop {
    background: rgba(15, 16, 17, 0.4);
    transition: background var(--dur-3) var(--ease-morph),
                overlay var(--dur-3) allow-discrete, display var(--dur-3) allow-discrete;
  }
  @starting-style {
    .feed-filters:popover-open::backdrop { background: rgba(15, 16, 17, 0); }
  }
}
/* On a phone the dialog is a bottom sheet. It slides up and down, opaque all the way,
   and the dim fades with it. */
@media (max-width: 640px) {
  .feed-filters {
    inset: auto 0 0;
    width: 100%;
    max-height: 85dvh;
    border-bottom: 0;
    border-radius: 40px 40px 0 0; /* the design system's sheet top */
  }
  @supports selector(:popover-open) {
    .feed-filters { clip-path: none; }
    .feed-filters:popover-open {
      transform: translateY(0);
      transition: transform var(--dur-3) var(--ease-morph),
                  overlay var(--dur-3) allow-discrete, display var(--dur-3) allow-discrete;
    }
    .feed-filters:not(:popover-open) {
      clip-path: none;
      opacity: 1;
      transform: translateY(100%);
      transition: transform var(--dur-2) var(--ease-exit),
                  overlay var(--dur-2) allow-discrete, display var(--dur-2) allow-discrete;
    }
    @starting-style {
      .feed-filters:popover-open { clip-path: none; opacity: 1; transform: translateY(100%); }
    }
    .feed-filters:popover-open::backdrop { background: rgba(0, 0, 0, 0.5); }
  }
}
