/**
 * File: css/changelog-mobile.css
 *
 * Mobile Updates feed (< 992px). The desktop #changelog section and its
 * paginator are hidden below the breakpoint and this block takes over, the
 * same way css/creators-pages.css swaps .creators-mobile in for #our-models.
 *
 * Everything except the one `.cl-mobile { display: none }` line below lives
 * inside @media (max-width: 991.98px), so desktop cannot be reached from here.
 */

.cl-mobile { display: none; }

@media (max-width: 991.98px) {
  /* The desktop tree steps aside. !important is required on the paginator, not
     defensive: js/changelog-pagination.js writes an inline style.display on
     this root, and an inline `display:""` beats a plain stylesheet rule — the
     pager would reappear here on every load, since 17 cards over 4 per page
     always means more than one page. */
  body.changelog-page #changelog,
  body.changelog-page .page-pagination,
  body.changelog-page .page-pagination + hr.divider { display: none !important; }

  .cl-mobile {
    display: block;
    /* Exactly the mobile header's height, so the hero opens flush under it. */
    padding-top: 80px;
    padding-bottom: clamp(56px, 15vw, 76px);
    background: var(--cl-bg);
    color: var(--cl-ink);

    --cl-bg: #FCFBFD;
    --cl-ink: #0C0B2B;
    --cl-ink-2: #45445F;
    --cl-ink-3: #75748C;
    --cl-coral: #FF3B61;
    --cl-violet: #7357F6;
    --cl-line: rgba(12, 11, 43, .08);
    --cl-line-2: rgba(12, 11, 43, .06);
    --cl-radius: 22px;
    --cl-air: 18px;
    /* Flipped to -1 under html.lang-ar so the segmented pill travels the other
       way; transform is physical, direction is not. */
    --cl-dir: 1;
  }

  /* The reference's side gutter is 7.85% of the viewport — 28px at 360, 31px
     at 390, 34px at 430. Wider than the rest of the site on purpose: the whole
     point of this page is air. */
  .cl-mobile__inner {
    width: 100%;
    max-width: 470px;
    margin: 0 auto;
    padding-inline: clamp(24px, 7.85vw, 34px);
  }

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

  .cl-hero { padding-top: clamp(22px, 6.5vw, 30px); }

  .cl-hero__eyebrow {
    margin: 0 0 clamp(10px, 2.8vw, 14px);
    color: var(--cl-coral);
    font-size: 10.5px;
    font-weight: 800;
    letter-spacing: .13em;
    line-height: 1;
    text-transform: uppercase;
  }

  /* Set from the reference: cap height is 0.76 of the side gutter, which lands
     the display size at ~8.4vw. Uppercase, one weight above the card titles,
     tracking pulled in hard so "WHAT'S NEW." holds one line at 360. */
  .cl-hero__title {
    margin: 0;
    color: var(--cl-ink);
    font-size: clamp(30px, 8.4vw, 38px);
    font-weight: 800;
    letter-spacing: -.03em;
    line-height: .96;
    text-transform: uppercase;
    text-wrap: balance;
  }

  .cl-hero__dot { color: var(--cl-coral); }

  .cl-hero__lede {
    /* Measure in em so the two lines survive a language change instead of
       spilling to three. */
    max-width: 23em;
    margin: clamp(13px, 3.6vw, 17px) 0 0;
    color: var(--cl-ink-2);
    font-size: clamp(13.5px, 3.6vw, 15px);
    line-height: 1.5;
  }

  /* No reserved height here on purpose: this line grows to two lines in ru /
     th / vi and changes on every filter tap, but withAnchor() restores the
     reader's position from the anchor card's own viewport offset, which absorbs
     any height change above the feed. Reserving two lines would only leave a
     hole under a one-line row. */
  .cl-hero__latest {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 7px 10px;
    margin: clamp(18px, 5vw, 24px) 0 0;
  }

  .cl-hero__latest-tag,
  .cl-hero__latest-platform {
    padding: 5px 12px 6px;
    border-radius: 999px;
    font-size: 12.5px;
    font-weight: 700;
    line-height: 1.15;
  }

  .cl-hero__latest-tag { background: rgba(255, 59, 97, .1); color: var(--cl-coral); }

  .cl-hero__latest-platform {
    background: rgba(12, 11, 43, .06);
    color: var(--cl-ink);
  }

  .cl-hero__latest-version {
    color: var(--cl-coral);
    font-size: clamp(20px, 5.6vw, 25px);
    font-weight: 800;
    letter-spacing: -.02em;
    line-height: 1;
    font-variant-numeric: tabular-nums;
  }

  .cl-hero__latest-date {
    color: var(--cl-ink-3);
    font-size: 13.5px;
    line-height: 1.2;
  }

  /* --- segmented control ------------------------------------------------- */

  /* Three equal columns, so the pill has one constant width and only ever
     translates. Nothing is measured, which means nothing can desync when a
     Thai label is three times the width of "All", and RTL needs only the
     --cl-dir flip. */
  .cl-mobile__filter {
    position: relative;
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    margin-top: clamp(20px, 5.5vw, 26px);
    padding: 5px;
    border: 1px solid var(--cl-line);
    border-radius: 999px;
    background: #fff;
    box-shadow: 0 2px 10px rgba(12, 11, 43, .04);
    isolation: isolate;
  }

  .cl-mobile__filter__pill {
    position: absolute;
    top: 5px;
    inset-inline-start: 5px;
    z-index: 0;
    width: calc((100% - 10px) / 3);
    height: calc(100% - 10px);
    border-radius: 999px;
    background: linear-gradient(135deg, #FF4E70 0%, #FF3B61 55%, #F92C58 100%);
    box-shadow: 0 6px 16px rgba(255, 59, 97, .3);
    transform: translate3d(0, 0, 0);
    pointer-events: none;
  }

  /* 100% of the pill's own width is exactly one segment, because the segments
     are thirds of the same track. */
  .cl-mobile__filter[data-filter="ios"] .cl-mobile__filter__pill {
    transform: translate3d(calc(100% * var(--cl-dir)), 0, 0);
  }

  .cl-mobile__filter[data-filter="android"] .cl-mobile__filter__pill {
    transform: translate3d(calc(200% * var(--cl-dir)), 0, 0);
  }

  /* The transition is gated behind is-ready, added two frames after mount, so
     arriving at ?platform=android paints the pill already in place instead of
     sliding it in from the first segment. */
  .cl-mobile__filter.is-ready .cl-mobile__filter__pill {
    transition: transform 280ms cubic-bezier(.22, .61, .36, 1);
  }

  .cl-mobile__filter__btn {
    position: relative;
    z-index: 1;
    min-height: clamp(42px, 11.5vw, 48px);
    padding: 0 6px;
    border: 0;
    border-radius: 999px;
    background: none;
    color: var(--cl-ink);
    font-family: inherit;
    font-size: clamp(13px, 3.5vw, 14.5px);
    font-weight: 700;
    letter-spacing: -.005em;
    white-space: nowrap;
    cursor: pointer;
    -webkit-appearance: none;
    appearance: none;
    /* Cross-fades while the pill travels, so it never arrives under dark text
       or leaves white text behind on the plain track. */
    transition: color 220ms cubic-bezier(.22, .61, .36, 1);
  }

  .cl-mobile__filter__btn[aria-selected="true"] { color: #fff; }

  .cl-mobile__filter__btn:focus-visible {
    outline: 2px solid var(--cl-coral);
    outline-offset: 3px;
  }

  /* --- the feed ---------------------------------------------------------- */

  .cl-mobile__feed {
    margin-top: clamp(22px, 6vw, 28px);
    /* The anchor helper in the module is the mechanism that keeps the page
       still across a filter tap; the browser's own anchoring is the net. */
    overflow-anchor: auto;
  }

  .cl-mobile__list {
    display: grid;
    gap: clamp(16px, 4.4vw, 20px);
  }

  /* Filtering is display, not height. The `hidden` attribute alone would not
     be enough — an author `display` on .cl-card beats the UA sheet's [hidden]
     rule — so it is spelled out. */
  .cl-mobile__list .cl-card[hidden] { display: none !important; }

  .cl-card {
    position: relative;
    overflow: hidden;
    border: 1px solid var(--cl-line);
    border-radius: var(--cl-radius);
    background: #fff;
    box-shadow: 0 1px 2px rgba(12, 11, 43, .03), 0 10px 26px -14px rgba(12, 11, 43, .14);
    isolation: isolate;
  }

  .cl-card[data-platform="ios"] {
    --cl-accent: #FF3B61;
    --cl-accent-soft: rgba(255, 59, 97, .1);
  }

  .cl-card[data-platform="android"] {
    --cl-accent: #7357F6;
    --cl-accent-soft: rgba(115, 87, 246, .1);
  }

  /* --- the head, which is also the disclosure trigger ---------------------- */

  /* A real <button>, so Enter and Space come for free and aria-expanded has an
     owner. Everything inside it is phrasing content, which is the one thing a
     button's content model allows, so the former block elements are spans and
     are given their display back here. */
  .cl-card__head {
    display: block;
    width: 100%;
    margin: 0;
    padding: 0;
    border: 0;
    background: none;
    color: inherit;
    font: inherit;
    text-align: start;
    cursor: pointer;
    -webkit-appearance: none;
    appearance: none;
  }

  .cl-card__head:focus-visible {
    outline: 2px solid var(--cl-accent);
    outline-offset: -3px;
    border-radius: var(--cl-radius);
  }

  .cl-card__copy,
  .cl-card__title,
  .cl-card__summary { display: block; }

  .cl-card__idline { display: flex; }

  /* The upper block: copy on the left, the colour panel in the slot the phone
     mockup used to hold — the right 38% of the card, as in the reference. */
  .cl-card__main {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 38%;
    align-items: stretch;
  }

  .cl-card__copy {
    padding: clamp(15px, 4.1vw, 18px);
    padding-inline-end: clamp(10px, 3vw, 13px);
  }

  .cl-card__date {
    display: block;
    color: var(--cl-ink-3);
    font-size: 11px;
    font-weight: 700;
    letter-spacing: .07em;
    line-height: 1;
    text-transform: uppercase;
  }

  .cl-card__idline {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px 9px;
    margin-top: clamp(8px, 2.4vw, 11px);
  }

  .cl-card__version {
    color: var(--cl-ink);
    font-size: clamp(21px, 5.9vw, 26px);
    font-weight: 800;
    letter-spacing: -.03em;
    line-height: 1;
    font-variant-numeric: tabular-nums;
  }

  .cl-card__pill {
    padding: 4px 10px 5px;
    border-radius: 999px;
    background: var(--cl-accent-soft);
    color: var(--cl-accent);
    font-size: 11px;
    font-weight: 700;
    line-height: 1.15;
  }

  .cl-card__type {
    display: flex;
    align-items: center;
    gap: 7px;
    margin-top: clamp(11px, 3.2vw, 14px);
    color: var(--cl-accent);
    font-size: 10.5px;
    font-weight: 800;
    letter-spacing: .08em;
    line-height: 1;
    text-transform: uppercase;
  }

  .cl-card__type-badge {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 19px;
    height: 19px;
    border-radius: 50%;
    background: var(--cl-accent-soft);
  }

  .cl-card__type-badge svg { display: block; width: 11px; height: 11px; }

  .cl-card__title {
    margin: clamp(10px, 3vw, 13px) 0 0;
    color: var(--cl-ink);
    font-size: clamp(17px, 4.6vw, 20px);
    font-weight: 800;
    letter-spacing: -.028em;
    line-height: 1.13;
    text-wrap: balance;
  }

  .cl-card__summary {
    margin: clamp(7px, 2.2vw, 10px) 0 0;
    color: var(--cl-ink-2);
    font-size: clamp(12.5px, 3.3vw, 13.5px);
    line-height: 1.46;
  }

  /* --- the colour panel -------------------------------------------------- */

  /* No image, no mockup: a tinted field, two soft circles and a very large
     translucent numeral. The circles are gradients on pseudo-elements, so the
     page adds no asset of any kind. Static art — nothing here animates. */
  .cl-card__panel {
    display: block;
    position: relative;
    overflow: hidden;
    container-type: inline-size;
    background: linear-gradient(150deg, #FBFAFC 0%, #F3F1F7 100%);
  }

  .cl-card__panel::before,
  .cl-card__panel::after {
    content: "";
    position: absolute;
    border-radius: 50%;
    pointer-events: none;
  }

  .cl-card__panel::before {
    top: -18%;
    inset-inline-end: -26%;
    width: 78%;
    padding-bottom: 78%;
  }

  .cl-card__panel::after {
    bottom: -30%;
    inset-inline-start: -20%;
    width: 56%;
    padding-bottom: 56%;
  }

  /* The wash is for the drawn panel only. A release that carries a poster
     paints its own band colour instead, and that rule is one class against
     this one's four, so it has to be kept out of the match rather than
     out-weighed. */
  .cl-card[data-platform="ios"][data-tone="platform"] .cl-card__panel:not(.cl-card__panel--shot) {
    background: linear-gradient(150deg, #FFF2F5 0%, #FFE5EC 52%, #FFDBE6 100%);
  }

  .cl-card[data-platform="ios"][data-tone="platform"] .cl-card__panel::before {
    background: radial-gradient(circle, rgba(255, 255, 255, .95), rgba(255, 255, 255, .35) 58%, rgba(255, 255, 255, 0) 74%);
  }

  .cl-card[data-platform="ios"][data-tone="platform"] .cl-card__panel::after {
    background: radial-gradient(circle, rgba(255, 59, 97, .3), rgba(255, 59, 97, .08) 58%, rgba(255, 59, 97, 0) 76%);
  }

  .cl-card[data-platform="android"][data-tone="platform"] .cl-card__panel:not(.cl-card__panel--shot) {
    background: linear-gradient(150deg, #6247E8 0%, #7357F6 48%, #8C6DFF 100%);
  }

  .cl-card[data-platform="android"][data-tone="platform"] .cl-card__panel::before {
    background: radial-gradient(circle, rgba(206, 193, 255, .6), rgba(206, 193, 255, .16) 58%, rgba(206, 193, 255, 0) 76%);
  }

  .cl-card[data-platform="android"][data-tone="platform"] .cl-card__panel::after {
    background: radial-gradient(circle, rgba(255, 255, 255, .28), rgba(255, 255, 255, .06) 58%, rgba(255, 255, 255, 0) 76%);
  }

  /* Store-metadata releases — the two entries where nothing shipped to a
     device — keep the milky ground and a hairline arc instead of a wash. */
  .cl-card[data-tone="neutral"] .cl-card__panel::before {
    top: -14%;
    inset-inline-end: -22%;
    width: 70%;
    padding-bottom: 70%;
    border: 1px solid rgba(12, 11, 43, .07);
  }

  .cl-card[data-tone="neutral"] .cl-card__panel::after {
    bottom: -24%;
    inset-inline-start: -16%;
    width: 48%;
    padding-bottom: 48%;
    border: 1px solid rgba(12, 11, 43, .05);
  }

  .cl-card__bignum {
    position: absolute;
    inset-inline-end: 7%;
    bottom: 6%;
    max-width: 86%;
    color: rgba(12, 11, 43, .13);
    /* The fallback, for engines without container queries. */
    font-size: clamp(24px, 7.5vw, 32px);
    /* The panel is the container, so the numeral scales with the panel rather
       than with the viewport and "08.20" cannot outgrow the box the way a vw
       size did. */
    font-size: 31cqw;
    font-weight: 800;
    letter-spacing: -.06em;
    line-height: .82;
    font-variant-numeric: tabular-nums;
    /* The numeral is a graphic, not a data field — it must never be read out
       after the version that already sits in the copy column. */
    user-select: none;
  }

  .cl-card[data-platform="ios"][data-tone="platform"] .cl-card__bignum {
    color: rgba(255, 59, 97, .28);
  }

  .cl-card[data-platform="android"][data-tone="platform"] .cl-card__bignum {
    color: rgba(255, 255, 255, .34);
  }

  /* --- the improvements list --------------------------------------------- */

  .cl-card__items {
    margin: 0;
    /* The hairline that separates the head from the detail zone. It lives on
       the list, inside the clip, so it appears with the content instead of
       sitting under a closed card as a stray rule. */
    padding: clamp(13px, 3.6vw, 16px) clamp(15px, 4.1vw, 18px) clamp(15px, 4.1vw, 18px);
    border-top: 1px solid var(--cl-line-2);
    list-style: none;
    display: grid;
    gap: clamp(7px, 2.1vw, 9px);
  }

  .cl-card__items > li {
    position: relative;
    padding-inline-start: 26px;
    color: var(--cl-ink-2);
    font-size: clamp(12px, 3.2vw, 13px);
    line-height: 1.4;
  }

  /* The marker is one inline SVG in its own span rather than a ::marker or a
     CSS-drawn glyph: ::marker can only animate colour, and the beam has to be
     able to swell the whole mark as it passes. */
  .cl-card__mark {
    position: absolute;
    top: .06em;
    inset-inline-start: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 17px;
    height: 17px;
    border-radius: 50%;
    background: var(--cl-accent-soft);
    color: var(--cl-accent);
  }

  .cl-card__mark svg { display: block; width: 10px; height: 10px; }

  /* --- release artwork ---------------------------------------------------- */

  /* The picture takes the visual square that otherwise holds the big numeral.
     Same box, same clip, same radius as before — the card neither grows nor
     changes shape; only what is inside the square changes. The drawn circles
     go with the numeral, because the poster is the visual now.

     That square is far more portrait than the file — 0.38 against
     941/1672 = 0.563 at 390 — so `cover` sizes the poster to the panel's
     height and throws a third of its width away, logo and headline with it.
     `contain` keeps all 941px, and the band it leaves under the picture is
     painted in the poster's own bottom edge colour, which the manifest
     carries, so the file reads as running out rather than as a letterbox —
     the same answer the desktop panel gives at css/changelog-desktop.css:695.
     The picture is anchored to the top because only the bottom edge of these
     posters is a flat colour; centring it would open a second seam above,
     where the artwork is not. */
  .cl-card__panel--shot { background: var(--cl-shot-b, #0F1020); }

  .cl-card__panel--shot::before,
  .cl-card__panel--shot::after { content: none; }

  .cl-card__shot {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: contain;
    object-position: 50% 0;
  }

  /* --- poster cards: the poster is a picture, not the column ---------------- */

  /* The poster keeps the card's right column, beside the copy and not over it,
     but it stops being the column: it is given the file's own 941x1672 ratio
     and start alignment, so it is exactly as tall as the picture and no taller.
     That is what removes the red tail. The old rule let the panel stretch to
     whatever height the copy set, fitted the portrait into the top of it and
     painted the leftover in the file's bottom-edge colour — a band that grew
     with every longer translation, and Russian is the longest.

     With the height coming from the picture there is no leftover to paint, so
     the panel carries no background of its own and the card's own white is
     what shows under the poster. --cl-shot-b, which js/changelog-mobile.js
     still writes inline, has nothing left to colour here.

     Only these cards change. A release with no poster keeps the drawn colour
     panel exactly as it was — that panel is a gradient and a numeral, and it
     is meant to fill whatever height it is given. */
  .cl-card--shot .cl-card__panel {
    align-self: start;
    aspect-ratio: 941 / 1672;
    background: none;
  }

  /* contain, and the box is already the picture's ratio, so the fit is exact:
     nothing is cropped, and any sub-pixel slack falls on the card's white
     rather than on a colour of its own. */
  .cl-card--shot .cl-card__shot {
    object-fit: contain;
    object-position: 50% 0;
  }

  /* --- chevron ------------------------------------------------------------ */

  .cl-card__chevron {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 26px;
    height: 26px;
    margin-top: clamp(11px, 3.2vw, 14px);
    margin-inline-start: -5px;
    border-radius: 50%;
    color: var(--cl-ink-3);
    transition: transform 340ms cubic-bezier(.22, .61, .36, 1), color 200ms ease;
  }

  .cl-card__chevron svg { display: block; width: 16px; height: 16px; }

  .cl-card.is-open .cl-card__chevron {
    transform: rotate(180deg);
    color: var(--cl-accent);
  }

  /* --- the detail drop ---------------------------------------------------- */

  /* Height on grid-template-rows 0fr -> 1fr with the clip supplying the
     overflow: the list keeps its own sizes and nothing is scaled into place.
     Collapsed it is visibility:hidden, which takes the points out of the tab
     order; that switch is delayed by the length of the collapse so the content
     stays on screen while the height runs out.

     The card grows below its own head, so the head never moves under the
     finger and a plain click cannot shift the page. */
  .cl-card__drop {
    display: grid;
    grid-template-rows: 0fr;
    visibility: hidden;
    /* closing */
    transition:
      grid-template-rows 240ms cubic-bezier(.22, .61, .36, 1),
      visibility 0s linear 240ms;
  }

  .cl-card__drop-clip { min-height: 0; overflow: hidden; }

  .cl-card__drop .cl-card__items {
    opacity: 0;
    transform: translate3d(0, -6px, 0);
    transition:
      opacity 180ms cubic-bezier(.22, .61, .36, 1),
      transform 180ms cubic-bezier(.22, .61, .36, 1);
  }

  .cl-card.is-open .cl-card__drop {
    grid-template-rows: 1fr;
    visibility: visible;
    /* opening */
    transition:
      grid-template-rows 340ms cubic-bezier(.22, .61, .36, 1),
      visibility 0s;
  }

  /* The points settle just behind the height, so they land in a space already
     made for them rather than being seen through the clip. */
  .cl-card.is-open .cl-card__drop .cl-card__items {
    opacity: 1;
    transform: none;
    transition:
      opacity 260ms cubic-bezier(.22, .61, .36, 1) 90ms,
      transform 260ms cubic-bezier(.22, .61, .36, 1) 90ms;
  }

  /* --- show more --------------------------------------------------------- */

  /* The same height mechanism as css/creators-pages.css: grid-template-rows
     0fr -> 1fr on the wrapper with the clip supplying the overflow, so the
     cards keep their own sizes and gap and nothing is scaled into place.
     Collapsed it is visibility:hidden, which takes its content out of the tab
     order; the visibility transition is delayed by the length of the collapse
     so the cards stay on screen while the height runs out. */
  /* Two things move, on purpose. The wrapper owns the height and the tab
     order; the list inside owns the fade and the short settle. Splitting them
     is what makes it read as a system disclosure rather than a box growing:
     the panel opens, and its content arrives into the opened space.

     Height still travels on grid-template-rows 0fr -> 1fr with the clip
     supplying the overflow, so the cards keep their own sizes and gap and
     nothing is scaled. Collapsed it is visibility:hidden, which takes the
     content out of the tab order; that switch is delayed by the length of the
     collapse so the cards stay on screen while the height runs out. */
  .cl-mobile__extra {
    display: grid;
    grid-template-rows: 0fr;
    visibility: hidden;
    /* closing */
    transition:
      grid-template-rows 240ms cubic-bezier(.22, .61, .36, 1),
      visibility 0s linear 240ms;
  }

  .cl-mobile__extra-clip { min-height: 0; overflow: hidden; }

  /* The gap above the extra cards sits inside the clip, so it collapses too. */
  .cl-mobile__extra .cl-mobile__list { padding-top: clamp(16px, 4.4vw, 20px); }

  .cl-mobile__extra .cl-mobile__list {
    opacity: 0;
    transform: translate3d(0, -6px, 0);
    transition:
      opacity 180ms cubic-bezier(.22, .61, .36, 1),
      transform 180ms cubic-bezier(.22, .61, .36, 1);
  }

  .cl-mobile__feed.is-expanded .cl-mobile__extra {
    grid-template-rows: 1fr;
    visibility: visible;
    /* opening */
    transition:
      grid-template-rows 340ms cubic-bezier(.22, .61, .36, 1),
      visibility 0s;
  }

  /* The content settles slightly behind the height, so it lands in a space
     that has already been made for it and nothing is seen through the clip. */
  .cl-mobile__feed.is-expanded .cl-mobile__extra .cl-mobile__list {
    opacity: 1;
    transform: none;
    transition:
      opacity 260ms cubic-bezier(.22, .61, .36, 1) 90ms,
      transform 260ms cubic-bezier(.22, .61, .36, 1) 90ms;
  }

  .cl-mobile__toggle {
    display: flex;
    align-items: center;
    justify-content: space-between;
    width: 100%;
    min-height: clamp(50px, 13.5vw, 56px);
    margin-top: clamp(18px, 5vw, 22px);
    padding: 0 20px;
    border: 1.5px solid var(--cl-ink);
    border-radius: 999px;
    background: #fff;
    color: var(--cl-ink);
    font-family: inherit;
    font-size: clamp(13px, 3.4vw, 14px);
    font-weight: 800;
    letter-spacing: -.005em;
    text-align: start;
    cursor: pointer;
    -webkit-appearance: none;
    appearance: none;
  }

  .cl-mobile__toggle:focus-visible {
    outline: 2px solid var(--cl-coral);
    outline-offset: 3px;
  }

  .cl-mobile__toggle[hidden] { display: none !important; }

  .cl-mobile__toggle-chevron {
    flex: 0 0 auto;
    width: 9px;
    height: 9px;
    margin: -4px 3px 0 12px;
    border-right: 1.6px solid currentColor;
    border-bottom: 1.6px solid currentColor;
    transform: rotate(45deg);
    transition: transform 340ms cubic-bezier(.22, .61, .36, 1);
  }

  .cl-mobile__feed.is-expanded .cl-mobile__toggle-chevron {
    margin-top: 4px;
    transform: rotate(225deg);
  }

  .cl-mobile__empty {
    margin: clamp(24px, 7vw, 32px) 0 0;
    color: var(--cl-ink-3);
    font-size: 14px;
  }

  .cl-mobile__empty[hidden] { display: none !important; }

  /* --- stagger reveal ---------------------------------------------------- */

  /* The hidden state sits behind cl-reveal, which only the script adds. With
     JS off, without IntersectionObserver, or with motion turned down the class
     never appears and the cards are simply there. */
  .cl-mobile__list.cl-reveal > .cl-card {
    opacity: 0;
    transform: translate3d(0, 12px, 0);
    will-change: opacity, transform;
  }

  .cl-mobile__list.cl-reveal > .cl-card.is-in {
    opacity: 1;
    transform: none;
    will-change: auto;
    transition:
      opacity 420ms cubic-bezier(.22, .61, .36, 1),
      transform 420ms cubic-bezier(.22, .61, .36, 1);
    transition-delay: var(--cl-seq, 0ms);
  }

  /* Cards inside the show-more clip opt out: that toggle already has a motion
     of its own, and two motions for one tap is one too many. */
  .cl-mobile__extra .cl-mobile__list.cl-reveal > .cl-card,
  .cl-mobile__extra .cl-mobile__list.cl-reveal > .cl-card.is-in {
    opacity: 1;
    transform: none;
    transition: none;
    will-change: auto;
  }

  /* Long feeds: skip layout for cards well below the fold. Kept off the first
     four on purpose — a skipped subtree has no layout, and the beam measures
     positions inside the first card. */
  .cl-mobile__list > .cl-card:nth-child(n + 5) {
    content-visibility: auto;
    contain-intrinsic-size: auto 420px;
  }

  /* --- the release beam -------------------------------------------------- */

  /* One injected element, a direct child of the card, clipped by the card's
     own overflow and radius. It is inset:0, so its own 100% *is* the card
     height: the travel needs no measurement and stays right even if a
     dictionary or font swap changes that height while it is in flight. */
  .cl-card__beam {
    position: absolute;
    inset: 0;
    z-index: 4;
    transform: translate3d(0, 0, 0);
    will-change: transform;
    pointer-events: none;
    animation: cl-beam-travel var(--cl-beam-ms, 800ms) linear var(--cl-beam-lead, 260ms) 1 both;
  }

  /* The line itself. bottom:100% parks it directly above the card, so the rail
     can start at translate 0 with nothing on screen. It overhangs 12% each
     side, so the gradient's transparent tips are clipped away and the visible
     line reaches both card edges at strength instead of stopping dead.
     No blend mode: this card is a coloured panel at the top and white at the
     bottom, and screen/plus-lighter would make the beam vanish over the white. */
  .cl-card__beam::before {
    content: "";
    position: absolute;
    inset-inline: -12%;
    bottom: 100%;
    height: var(--cl-beam-h, 92px);
    background:
      linear-gradient(90deg,
        rgba(255, 59, 97, 0) 0%, #FF3B61 18%, #A874F7 52%, #7357F6 82%,
        rgba(115, 87, 246, 0) 100%) 50% 50% / 100% 1.5px no-repeat,
      radial-gradient(120% 46px at 50% 50%,
        rgba(168, 116, 247, .2), rgba(255, 59, 97, .1) 46%, rgba(255, 59, 97, 0) 72%);
    opacity: 0;
    animation: cl-beam-life var(--cl-beam-ms, 800ms) linear var(--cl-beam-lead, 260ms) 1 both;
  }

  /* Position, and only position. Linear on purpose: it keeps the highlight
     delays below a closed form instead of something that has to be inverted
     numerically per element. */
  @keyframes cl-beam-travel {
    from { transform: translate3d(0, 0, 0); }
    to   { transform: translate3d(0, calc(100% + var(--cl-beam-h, 92px)), 0); }
  }

  /* It strikes in, holds, and is gone before the bottom edge, so the card is
     never left with a line sitting on its border. */
  @keyframes cl-beam-life {
    0%   { opacity: 0; transform: scaleX(.82); }
    12%  { opacity: 1; transform: scaleX(1); }
    82%  { opacity: 1; transform: scaleX(1); }
    100% { opacity: 0; transform: scaleX(.94); }
  }

  /* What the beam lights on its way. Both highlights are additions that return
     to their own resting values, so there is nothing for the reduced-motion
     block to undo and nothing left behind if one is cancelled halfway. */
  .cl-card--latest.is-beaming .cl-card__bignum {
    animation: cl-lit-num 420ms cubic-bezier(.22, .61, .36, 1)
      calc(var(--cl-beam-lead, 260ms) + var(--cl-lit-delay, 0ms)) 1;
  }

  @keyframes cl-lit-num {
    0%   { filter: none; }
    22%  { filter: brightness(1.5) saturate(1.3); }
    100% { filter: none; }
  }

  .cl-card--latest.is-beaming .cl-card__mark {
    animation: cl-lit-dot 320ms cubic-bezier(.22, .61, .36, 1)
      calc(var(--cl-beam-lead, 260ms) + var(--cl-lit-delay, 0ms)) 1;
  }

  @keyframes cl-lit-dot {
    0%   { transform: scale(1); }
    30%  { transform: scale(1.55); }
    100% { transform: scale(1); }
  }

  .cl-card__items > li::after {
    content: "";
    position: absolute;
    inset-inline: 26px 0;
    bottom: -3px;
    height: 1.5px;
    border-radius: 2px;
    background: linear-gradient(90deg, var(--cl-coral), var(--cl-violet));
    /* The resting state: not drawn at all. */
    opacity: 0;
    transform: scaleX(0);
    transform-origin: left center;
    pointer-events: none;
  }

  .cl-card--latest.is-beaming .cl-card__items > li::after {
    animation: cl-lit-rule 340ms cubic-bezier(.22, .61, .36, 1)
      calc(var(--cl-beam-lead, 260ms) + var(--cl-lit-delay, 0ms)) 1;
  }

  @keyframes cl-lit-rule {
    0%   { opacity: 0;   transform: scaleX(0); }
    35%  { opacity: .8; }
    60%  { opacity: .8;  transform: scaleX(1); }
    100% { opacity: 0;   transform: scaleX(1); }
  }

  /* --- narrow phones ----------------------------------------------------- */

  /* At 360 the panel would squeeze the title to three lines. Give the copy
     column more room and let the numeral come down a step. */
  @media (max-width: 374.98px) {
    .cl-card__main { grid-template-columns: minmax(0, 1fr) 35%; }
  }
}

/* Arabic is the only RTL locale here, and the site switches direction in CSS —
   there is no dir attribute anywhere. Mirrors the pattern at
   css/our-models.css:571. --cl-dir flips the segmented pill's travel, because
   transform stays physical while direction does not. */
@media (max-width: 991.98px) {
  html.lang-ar body.changelog-page .cl-mobile {
    direction: rtl;
    text-align: right;
    --cl-dir: -1;
  }

  html.lang-ar body.changelog-page .cl-card__items > li::after {
    transform-origin: right center;
  }
}

@media (max-width: 991.98px) and (prefers-reduced-motion: reduce) {
  /* The module already declines to add cl-reveal and never injects the beam
     under this preference. This block is what catches the preference being
     switched on after load — and it is deliberately the third guarantee about
     the beam, after "never built" and "removed when it ends". */
  .cl-mobile__list.cl-reveal > .cl-card,
  .cl-mobile__list.cl-reveal > .cl-card.is-in {
    opacity: 1;
    transform: none;
    transition: none;
    will-change: auto;
  }

  /* display:none, not opacity:0 — so it can never be parked mid-card as a
     stray line, and never holds a compositing layer. */
  .cl-card__beam { display: none; }

  /* The highlights only ever add to a finished resting state, so cancelling
     them is the whole fix: the numeral keeps its designed translucency and
     each bullet keeps its marker and its undrawn hairline. */
  .cl-card--latest.is-beaming .cl-card__bignum,
  .cl-card--latest.is-beaming .cl-card__mark,
  .cl-card--latest.is-beaming .cl-card__items > li::after { animation: none; }

  /* The pill still moves between segments — it arrives instead of travelling,
     which is the whole point of the control. */
  .cl-mobile__filter.is-ready .cl-mobile__filter__pill,
  .cl-mobile__filter__btn { transition: none; }

  /* Release cards still open and close; they just arrive. Both halves are
     cancelled and the list is pinned to its resting pose, so a collapsed card
     can never leave its points faded out. */
  .cl-card__drop,
  .cl-card.is-open .cl-card__drop { transition: visibility 0s; }

  .cl-card__drop .cl-card__items,
  .cl-card.is-open .cl-card__drop .cl-card__items {
    opacity: 1;
    transform: none;
    transition: none;
  }

  .cl-card__chevron { transition: none; }

  /* The show more still opens and closes; it just arrives. Both halves are
     cancelled, and the list is pinned to its resting pose so a collapsed panel
     can never leave it faded out. */
  .cl-mobile__extra,
  .cl-mobile__feed.is-expanded .cl-mobile__extra { transition: visibility 0s; }

  .cl-mobile__extra .cl-mobile__list,
  .cl-mobile__feed.is-expanded .cl-mobile__extra .cl-mobile__list {
    opacity: 1;
    transform: none;
    transition: none;
  }

  .cl-mobile__toggle-chevron { transition: none; }
}
