.referral-banner {
  position: relative;
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: clamp(12px, 1.5vw, 22px);
  width: 100%;
  padding: clamp(13px, 1.35vw, 19px) clamp(16px, 1.8vw, 26px);
  overflow: hidden;
  text-align: left;
  background:
    radial-gradient(circle at 8% 10%, rgba(238, 198, 91, 0.2), transparent 30%),
    linear-gradient(110deg, rgba(38, 21, 55, 0.97), rgba(13, 11, 25, 0.96));
  border: 1px solid rgba(235, 208, 126, 0.42);
  border-radius: clamp(12px, 1.2vw, 18px);
  box-shadow: 0 15px 36px rgba(0, 0, 0, 0.3), inset 0 1px rgba(255, 255, 255, 0.07);
}

/* A layout-neutral host on compact/mobile/tablet viewports lets the phone
   implementation continue to own the banner independently. */
.lobby-utility-rail {
  display: contents;
}

.referral-banner::after {
  content: '';
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: linear-gradient(105deg, transparent 28%, rgba(255, 255, 255, 0.055) 47%, transparent 66%);
}

.referral-banner-mark {
  display: grid;
  width: clamp(40px, 4vw, 58px);
  aspect-ratio: 1;
  place-items: center;
  color: #ffe39b;
  font-size: clamp(22px, 2.2vw, 34px);
  background: radial-gradient(circle, rgba(150, 102, 211, 0.5), rgba(42, 26, 62, 0.92));
  border: 1px solid rgba(255, 225, 147, 0.55);
  border-radius: 50%;
  box-shadow: 0 0 22px rgba(188, 131, 238, 0.36);
}

.referral-banner-content {
  min-width: 0;
}

.referral-banner h2 {
  margin: 0 0 3px;
  color: #fff2cb;
  /* Georgia falls back to taller platform CJK faces. A Latin-tight line box
     clipped their ascenders by 1–2px in Chrome/Firefox (and twice that on a
     wrapped Korean title), so the shared title box must budget for its real
     fallback glyph metrics instead of a single-language font. */
  font: 700 clamp(16px, 1.45vw, 22px)/1.4 Georgia, serif;
  letter-spacing: 0.025em;
  overflow-wrap: anywhere;
  /* WebKit still uses the unbroken word for scrollWidth in a narrow grid
     track unless its legacy break policy is explicit. Keep every localized
     title inside the invitation rail rather than clipping the final glyphs. */
  word-break: break-word;
}

.referral-banner p {
  margin: 0;
}

#referral-banner-copy {
  color: #e6dded;
  font-size: clamp(12px, 1.05vw, 15px);
}

.referral-banner-status {
  margin-top: 4px !important;
  color: #bcaacf;
  font-size: clamp(11px, 0.9vw, 13px);
}

.referral-banner-open,
.referral-copy,
.referral-share {
  position: relative;
  z-index: 1;
  min-height: 44px;
  padding: 10px 18px;
  color: #1b1023;
  font-size: clamp(14px, 1vw, 16px);
  font-weight: 800;
  white-space: nowrap;
  background: linear-gradient(180deg, #ffe49c, #d7a948);
  border: 1px solid rgba(255, 239, 184, 0.86);
  border-radius: 10px;
  box-shadow: 0 7px 17px rgba(0, 0, 0, 0.28);
}

.referral-banner-open:hover,
.referral-copy:hover,
.referral-share:hover {
  filter: brightness(1.08);
  transform: translateY(-1px);
}

/* THE PRESS IS ACKNOWLEDGED. The dialog now opens only once its ticket has
   decoded (referrals.js), so on a cold cache a press is followed by up to a
   few seconds of nothing -- and a press that does nothing reads as a dead
   button. The shared click guard holds the control busy for exactly that
   window. Its `.btn-pending` visual is drawn for the dark buttons (lavender
   ink, a vmin-sized spinner at the right edge); on this gold pill the ink
   stays dark and the spinner shrinks into the padding so the label -- "Invite"
   on a phone, where the pill hugs its text -- is never overdrawn. The box does
   not change size: a control that grows while working moves its neighbours. */
.referral-banner-open.btn-pending {
  color: rgba(27, 16, 35, 0.78) !important;
  filter: saturate(0.6) brightness(0.94);
  transform: none;
}

/* The shared rule halves every child; on gold that leaves the label hard to
   read. Working is shown by the spinner and the drained gradient, not by
   fading the words. */
.referral-banner-open.btn-pending > * {
  opacity: 0.85;
}

/* ON THE PHONE PILL THE STAR IS THE INDICATOR. The bar's pill carries its
   glyph (`✦ Invite`, and at the narrowest page box the glyph alone in a 44px
   round), so a ring in the right-hand padding lands on top of the star —
   measured at 667x275: the two overlapped into one smudged mark. The glyph
   already sits where the eye is; it turns while the open is in flight, at
   the shared spinner's own rate, and the ring is dropped. A `transform` needs
   a box, hence `inline-block`, which changes nothing about the inline
   glyph's size or place. */
.user-controls > .referral-banner > .referral-banner-open.btn-pending::after {
  display: none;
}

.user-controls > .referral-banner > .referral-banner-open.btn-pending .referral-open-icon {
  display: inline-block;
  opacity: 1;
  animation: mf-pending-spin 0.9s linear infinite;
}

@media (prefers-reduced-motion: reduce) {
  .user-controls > .referral-banner > .referral-banner-open.btn-pending .referral-open-icon {
    animation-duration: 2.5s;
  }
}

.referral-banner-open.btn-pending::after {
  right: 5px;
  width: 10px;
  height: 10px;
  margin-top: -5px;
  border-width: 2px;
  border-color: rgba(27, 16, 35, 0.22);
  border-top-color: rgba(27, 16, 35, 0.85);
}

.referral-open-icon,
.referral-open-compact-label {
  display: none;
}

.referral-dialog {
  position: fixed;
  z-index: 10020;
  inset: 0;
  display: grid;
  padding:
    max(18px, var(--mf-safe-top, 0px))
    max(18px, var(--mf-safe-right, 0px))
    max(18px, var(--mf-safe-bottom, 0px))
    max(18px, var(--mf-safe-left, 0px));
  place-items: center;
  overflow: auto;
  background: rgba(4, 2, 9, 0.82);
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
  animation: referral-fade-in 180ms ease-out both;
}

.referral-dialog-card {
  position: relative;
  width: min(620px, 100%);
  max-height: 100%;
  overflow: auto;
  padding: clamp(24px, 4vw, 42px);
  color: #f5eff9;
  text-align: left;
  background:
    radial-gradient(circle at 85% 0, rgba(174, 117, 230, 0.25), transparent 38%),
    linear-gradient(150deg, #25162f, #0d0a16 70%);
  border: 1px solid rgba(236, 209, 134, 0.5);
  border-radius: 22px;
  box-shadow: 0 28px 80px rgba(0, 0, 0, 0.6), inset 0 1px rgba(255, 255, 255, 0.09);
  animation: referral-card-in 300ms cubic-bezier(0.2, 0.9, 0.28, 1.08) both;
}

.referral-dialog-summary,
.referral-dialog-invite {
  display: contents;
}

.referral-dialog-close {
  position: absolute;
  top: 12px;
  right: 14px;
  display: grid;
  width: 42px;
  height: 42px;
  padding: 0;
  place-items: center;
  color: #e7dbef;
  font-size: 30px;
  line-height: 1;
  background: transparent;
  border: 0;
  border-radius: 50%;
}

.referral-dialog-close:hover {
  color: #fff;
  background: rgba(255, 255, 255, 0.09);
}

.referral-dialog-eyebrow {
  margin: 0 0 7px;
  color: #e4bd5f;
  font-size: 12px;
  font-weight: 800;
  letter-spacing: 0.18em;
}

.referral-dialog-card h2 {
  margin: 0 50px 10px 0;
  color: #fff2ca;
  font: 700 clamp(25px, 4vw, 38px)/1.08 Georgia, serif;
}

.referral-dialog-footnote {
  margin: 14px 0 0;
  color: #a99cb6;
  font-size: 11.5px;
  line-height: 1.5;
  text-wrap: pretty;
}

/* ===========================================================================
   THE TICKET, and the counter.

   This screen was five stacked paragraphs, a labelled read-only input holding a
   URL nobody reads, and two prose "status" lines -- above the one button the
   player actually came to press. What is being sent is an OBJECT, so the object
   is what the screen shows; the link leaves through the button.
   ======================================================================== */
.referral-dialog-object {
  display: grid;
  place-items: center;
  margin: 0 0 clamp(12px, 2.4vmin, 22px);
  /* The arrival screen's `.invite-ticket-stage` supplies this; the dialog has
     no stage, so without it the tilt rotates a flat plane and reads as a
     shear rather than an object turning. */
  perspective: 1100px;
}

/* ===========================================================================
   The object is built by ui/invite-ticket-object.js and carries the arrival
   screen's own `.invite-ticket` class, so its face, stamps and glare come for
   free. Three things from that stylesheet do NOT belong here, and all three
   were reported at once -- "ticket doesnt rotate by mouse, text is added at
   wrong locations and it background has a weird ticket ghost".

   HEIGHT. `.invite-ticket` sizes itself `min(58svh, 520px)` because the
   arrival screen gives it the whole viewport. The dialog gives it a column, so
   the width is what is known and the height has to follow the artwork. Leaving
   the viewport height in charge stretched the box off its own aspect ratio,
   and the face is laid out in `cqw` against a `container-type: size` box -- so
   the printing moved with it.

   ANIMATION. `invite-ticket-arrive` runs with `fill-mode: both`, which means
   it KEEPS owning `transform` at its final keyframe forever and beats the
   inline transform CardTilt writes: the ticket registered fine and simply
   could not move. The arrival screen already knew this and clears the
   animation at `animationend`; the dialog has its own entrance and does not
   want a second one at all. The same filled transform, offset from where the
   drop-shadow is cast, is the "ghost".
   ======================================================================== */
.referral-dialog-object .invite-ticket {
  width: clamp(150px, 21vmin, 232px);
  height: auto;
  animation: none;
  /* CONSUME THE TILT VARIABLES. CardTilt does not write a transform -- it
     writes `--card-tilt-rotate-x/y` and expects a rule to apply them, which
     `.card` has and this ticket does not. On the arrival screen that rule
     lives on `--settled`, added at `animationend`; the dialog runs no arrival
     animation, so that event never fires and the class never lands. Registering
     therefore "worked" while the ticket sat perfectly still: reported as
     "ticket doesnt rotate by mouse". */
  transform:
    rotateX(var(--card-tilt-rotate-x, 0deg))
    rotateY(var(--card-tilt-rotate-y, 0deg));
  transition: transform 90ms ease-out;
}

.referral-dialog-stats {
  display: flex;
  flex-wrap: wrap;
  gap: clamp(10px, 2vw, 20px);
  margin: clamp(12px, 2.2vmin, 20px) 0 0;
}

.referral-stat {
  display: grid;
  flex: 1 1 auto;
  min-width: 108px;
  padding: 10px 14px;
  gap: 2px;
  background: rgba(221, 173, 72, 0.1);
  border: 1px solid rgba(226, 185, 94, 0.24);
  border-radius: 11px;
}

.referral-stat-value {
  color: #ffe8a7;
  font: 700 clamp(22px, 3.4vw, 30px)/1 Georgia, serif;
  font-variant-numeric: tabular-nums;
}

.referral-stat-label {
  color: #cbbcd6;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

/* WIDE: the ticket stands beside its offer rather than above it. */
@media (min-width: 760px) and (min-height: 460px) {
  /* The right-hand column is ONE flow, not two centred rows. Centring each row
     against a ticket that spans both pushed the offer to the top and the
     actions to the bottom with a dead band between them. */
  .referral-dialog-card {
    display: flex;
    align-items: center;
    gap: clamp(30px, 4vw, 56px);
    width: min(880px, 100%);
    padding: clamp(30px, 4.4vw, 52px);
  }

  .referral-dialog-object { margin: 0; flex: 0 0 auto; }
  .referral-dialog-object .invite-ticket { width: clamp(186px, 24vmin, 286px); }

  .referral-dialog-body { flex: 1 1 auto; min-width: 0; }
  .referral-dialog-summary,
  .referral-dialog-invite { display: block; }
}

.referral-dialog-actions {
  display: flex;
  gap: 10px;
  margin-top: 12px;
}

.referral-copy {
  color: #f3eaf8;
  background: linear-gradient(180deg, #604178, #412d53);
  border-color: rgba(207, 172, 225, 0.42);
}

.referral-toast {
  position: fixed;
  z-index: 10030;
  bottom: max(24px, calc(var(--mf-safe-bottom, 0px) + 14px));
  left: 50%;
  padding: 11px 19px;
  color: #fff7dd;
  font-size: 14px;
  background: rgba(24, 14, 32, 0.97);
  border: 1px solid rgba(235, 205, 121, 0.52);
  border-radius: 999px;
  box-shadow: 0 10px 32px rgba(0, 0, 0, 0.5);
  transform: translateX(-50%);
  transition: opacity 220ms ease, transform 220ms ease;
}

.referral-toast--exit {
  opacity: 0;
  transform: translate(-50%, 8px);
}

.referral-copy-fallback {
  position: fixed;
  left: -10000px;
}

@keyframes referral-fade-in {
  from { opacity: 0; }
}

@keyframes referral-card-in {
  from { opacity: 0; transform: scale(0.98); }
}

@media (max-width: 680px) {
  .referral-banner {
    grid-template-columns: auto minmax(0, 1fr);
  }

  .referral-banner-open {
    grid-column: 1 / -1;
    width: 100%;
  }

  .referral-dialog-actions {
    flex-direction: column;
  }

  .referral-dialog-actions button {
    width: 100%;
  }
}

@media (max-height: 560px) and (orientation: landscape) {
  .referral-banner {
    padding-block: 10px;
  }

  .referral-banner-status {
    display: none;
  }

  .referral-dialog {
    box-sizing: border-box;
    padding:
      max(4px, var(--mf-safe-top, 0px))
      max(8px, var(--mf-safe-right, 0px))
      max(4px, var(--mf-safe-bottom, 0px))
      max(8px, var(--mf-safe-left, 0px));
    place-items: center;
    overflow: hidden;
  }

  /* THREE columns, and the object is placed EXPLICITLY. This grid names a
     position for every child; the ticket was added later and, unplaced,
     auto-flowed into a third column of its own on the right with the card
     stretched around it. */
  /*
   * THE SAME COMPOSITION AS DESKTOP, SMALLER. NOT A DIFFERENT ONE.
   *
   * This split the COPY into two columns -- the offer in one, the buttons and
   * fine print in another -- to "use the width". It read as two unrelated
   * blocks of text side by side, which is not a layout, it is a spill. The
   * desktop arrangement is the design: the object on the left, and one column
   * beside it reading eyebrow, offer, counters, action, terms. The width goes
   * to the measure, never to a second column of prose.
   *
   * Within that column the counters and the buttons DO share a line, because a
   * landscape phone page box is wide and short and neither of them is prose --
   * see the grid on `.referral-dialog-body` below.
   */
  /*
   * THE CARD IS THE SIZE OF WHAT IT HOLDS.
   *
   * It was `width: min(760px, 100%)` with `height: 100%`, so a ~200px stack of
   * content sat in a 292px box with a 59px dead band beneath it, and 128px of
   * the width lay unused to the right of a column that had stopped growing at
   * its measure. Both read as an unfinished screen. `fit-content` resolves
   * against the column's own definite width below, so the card ends where the
   * fine print ends and is centred by the overlay's `place-items`.
   */
  .referral-dialog-card {
    box-sizing: border-box;
    display: flex;
    align-items: center;
    gap: clamp(14px, 2.6vw, 26px);
    width: fit-content;
    /*
     * THE CAP IS IN VIEWPORT UNITS, NOT A PERCENTAGE.
     *
     * `max-width: min(760px, 100%)` does not clamp a `fit-content` grid item in
     * WebKit -- measured on an iPhone 13 in landscape (664x390): the card stayed
     * 685.5px and hung 29.5px off the page box, and `max-width: 100%` on its own
     * behaved identically while the viewport form snapped it to 648px. The two
     * terms below are the overlay's own horizontal padding, so this is the same
     * number the percentage was meant to be.
     */
    max-width: min(
      760px,
      calc(100vw - max(8px, var(--mf-safe-left, 0px)) - max(8px, var(--mf-safe-right, 0px)))
    );
    height: auto;
    max-height: 100%;
    padding: 12px 52px 12px 16px;
    overflow: hidden;
    border-radius: 14px;
  }

  .referral-dialog-object {
    flex: 0 0 auto;
    margin: 0;
  }

  /*
   * 84px was a thumbnail beside its own description. The ticket is the subject
   * of this screen and a hugging card has the height to give it, so its width
   * is solved from the height the page box actually has: the artwork is
   * 533x1100, and 56px covers the card's padding plus a margin off both edges
   * of the strip. A plain `svh` fraction cannot do this -- 26svh of a 300px
   * page box is 78px, under the floor, so every landscape phone got the same
   * minimum whatever room it had.
   */
  .referral-dialog-object .invite-ticket {
    width: clamp(96px, calc((100svh - 56px) * 0.4845), 150px);
  }

  /*
   * ONE COLUMN OF PROSE, AND ONE ROW OF CONTROLS.
   *
   * The measure is a WIDTH, not a cap: `.referral-dialog-card` above is
   * `fit-content`, and a percentage or a bare `max-width` resolves to `auto`
   * during its intrinsic sizing pass, so the card measured the paragraph's
   * max-content and kept 175px of void to the right of a column that had
   * already stopped growing.
   *
   * Inside it the counters and the buttons share a line. Stacked, a lone
   * counter had to span the whole 448px column to keep the right edge
   * straight, which made it an empty ribbon, and the row beneath held one
   * two-word button and 250px of nothing. A landscape phone page box is wide
   * and short: width is the resource, height is not.
   *
   * It wraps rather than being a grid, because a two-track grid cannot give
   * up. On a 664px iPhone 13 in landscape, WebKit's wider buttons put that
   * row's min-content at 696px and the card overflowed the page box by
   * 29.5px. Wrapping degrades on its own -- the buttons drop to their own
   * line, still right-aligned -- so no breakpoint has to guess where labels
   * stop fitting in eight languages.
   */
  .referral-dialog-body {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 7px 12px;
    flex: 0 1 auto;
    width: 62ch;
    max-width: 100%;
    min-width: 0;
  }

  /* The two wrappers exist so the desktop column can be one block; here they
     step aside so the five rows lay themselves out. */
  .referral-dialog-summary,
  .referral-dialog-invite {
    display: contents;
  }

  /* Prose takes the whole line; the two controls share what is left. */
  .referral-dialog-eyebrow,
  .referral-dialog-card h2,
  .referral-dialog-footnote {
    flex: 0 0 100%;
  }

  /* `1 1 0`, so the counters and the buttons always FORM one line: flex decides
     the wrap from hypothetical main sizes, and at `auto` two counters measured
     215px which, with a two-button row, exceeded the 448px measure and pushed
     the buttons onto a row of their own. At zero basis the line is made first
     and the space divided after. The counters inside still take their own
     width and wrap among themselves if the labels ever need it. */
  .referral-dialog-stats {
    flex: 1 1 0;
    min-width: 0;
    flex-wrap: wrap;
    gap: 8px;
  }

  /* `margin-left: auto` pins it to the far edge, so the row ends where the fine
     print ends whether the two share a line or not -- and it does that WITHOUT
     growing. As `1 1 auto` it took half the free space away from the counters,
     which then wrapped into a tower beside it. */
  .referral-dialog-actions {
    flex: 0 1 auto;
    min-width: 0;
    margin-left: auto;
  }

  .referral-dialog-close {
    top: 3px;
    right: 5px;
    width: 44px;
    height: 44px;
  }

  .referral-dialog-eyebrow,
  .referral-dialog-card h2,
  .referral-dialog-stats,
  .referral-dialog-actions,
  .referral-dialog-footnote {
    margin: 0;
    overflow-wrap: anywhere;
  }

  .referral-dialog-eyebrow {
    font-size: 10px;
    line-height: 1.1;
  }

  .referral-dialog-card h2 {
    margin-right: 0;
    font-size: clamp(22px, 5vh, 30px);
    line-height: 1;
  }

  /*
   * A ZERO-ish BASIS so two counters form one line before anything is sized --
   * at `auto` they measured 112 + 95 and the second wrapped beneath the first,
   * a tower beside a half-empty button row. 78px is the narrowest a two-digit
   * ratio over its label reads at.
   */
  .referral-stat {
    flex: 1 1 78px;
    min-width: 78px;
    padding: 5px 8px;
  }

  /* A LONE counter is not stretched. Growing into a track wider than its own
     text is what turned it into an empty bar with the words hugging the left. */
  .referral-stat:only-child {
    flex: 0 1 auto;
  }

  .referral-stat-value {
    font-size: clamp(15px, 3vh, 20px);
  }

  .referral-stat-label {
    font-size: clamp(8px, 1.8vh, 10px);
  }

  /* `2vh` of a 300px page box is 6px, so this clamped to its 9px floor on every
     landscape phone -- the smallest type on the screen, in the lowest-contrast
     colour on it. The page box is the wrong basis for a font size; the floor
     is now the size. */
  .referral-dialog-footnote {
    font-size: clamp(10.5px, 2.6vh, 12px);
    line-height: 1.35;
  }

  /* Natural widths, as on desktop. `width: 100%` on each button stretched a
     two-word label across half the card, which is the same "use the width"
     instinct that produced the two text columns. */
  .referral-dialog-actions {
    flex-direction: row;
    gap: 8px;
  }

  .referral-dialog-actions button {
    min-height: 44px;
    width: auto;
    padding: 6px 16px;
  }
}

/* Desktop keeps a generous empty rail beside the command canvas. Put the
   invitation there instead of lengthening the lobby column: translated room
   states and the 960x600 tablet canvas must retain their no-scroll contract. */
@media (orientation: landscape) and (min-height: 561px) {
  .referral-banner {
    position: fixed;
    right: clamp(20px, 2.4vw, 36px);
    bottom: calc(var(--legal-footer-h, 40px) + 10px);
    z-index: 14;
    width: min(360px, calc(100vw - 40px));
    padding: 11px 14px;
    gap: 10px;
  }

  .referral-banner-mark {
    width: 42px;
  }

  .referral-banner h2 {
    font-size: 17px;
  }

  #referral-banner-copy {
    display: -webkit-box;
    overflow: hidden;
    font-size: 12px;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
  }

  .referral-banner-status {
    display: none;
  }

  .referral-banner-open {
    min-height: 44px;
    padding-inline: 14px;
  }
}

/* Wide desktop keeps the invitation in a deliberate bottom-right rail while
   Feedback joins Language in the top-right cluster. The separated controls
   cannot cover one another and translated referral copy remains readable. */
@media (orientation: landscape) and (min-width: 1367px) and (min-height: 561px) {
  .lobby-utility-rail {
    position: fixed;
    right: clamp(20px, 2.4vw, 36px);
    bottom: calc(var(--legal-footer-h, 40px) + 10px);
    z-index: 1002;
    width: min(380px, calc(100vw - 40px));
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 10px;
    pointer-events: none;
  }

  .lobby-utility-rail > * {
    pointer-events: auto;
  }

  .lobby-utility-rail .referral-banner {
    position: static;
    /* A translated title and reward sentence need the complete text lane.
       Keep the seal beside them, then give the CTA its own full-width row. */
    grid-template-columns: auto minmax(0, 1fr);
    width: 100%;
    max-width: none;
  }

  .lobby-utility-rail .referral-banner-mark {
    grid-row: 1 / span 2;
  }

  .lobby-utility-rail .referral-banner-open {
    grid-column: 2;
    width: 100%;
  }

  .lobby-utility-rail #referral-banner-copy {
    display: block;
    overflow: visible;
    -webkit-line-clamp: unset;
  }
}

/* Landscape tablets use the full-width command canvas, so their remaining
   safe region is the strip above the legal footer rather than a side rail. */
@media (orientation: landscape)
  and (min-width: 960px)
  and (min-height: 561px)
  and (max-width: 1560px)
  and (max-aspect-ratio: 17/10) {
  .referral-banner {
    right: clamp(24px, 2.5vw, 34px);
    left: clamp(24px, 2.5vw, 34px);
    width: auto;
  }

  #referral-banner-copy {
    -webkit-line-clamp: 1;
  }
}

@media (prefers-reduced-motion: reduce) {
  .referral-dialog,
  .referral-dialog-card {
    animation: none;
  }

  .referral-banner-open,
  .referral-copy,
  .referral-share {
    transition: none;
  }
}
