/**
 * MyPeptideApp — Promo modal
 *
 * The "Where to buy" sheet. Layered ON TOP of the existing Modal component
 * (public/css/components.css) rather than replacing it: the overlay, the
 * mobile bottom-sheet behaviour, the drag handle, drag-to-dismiss, the close
 * button and the Escape handling all come from there and are not repeated
 * here. What this file adds is the content inside .modal-body.
 *
 * ── EVERY CLASS IS PREFIXED ────────────────────────────────────────────────
 * The mockup called its button `.btn` and its headline `.headline`. Both
 * names are already taken app-wide, and `.btn` in particular is on every
 * primary action in the product. So everything here is `promo-` prefixed.
 * Nothing in this file may style a bare element or a shared class.
 *
 * ── THE TINT ──────────────────────────────────────────────────────────────
 * The mockup used an absolutely positioned ::before. That does not survive
 * being dropped into this Modal, because .modal is itself the scrolling box:
 * an absolute child would scroll away with the content on a short screen.
 *
 * A background-image on .modal does the same job and cannot scroll, because
 * background-attachment defaults to `scroll`, which paints against the
 * element's own border box rather than its content. Same look, one
 * declaration, no z-index stacking to maintain.
 *
 * THE TWO THEMES DO NOT SHARE A COLOUR. Dark mode keeps the vendor's own
 * tint, which arrives as an inline custom property from
 * promo_vendors.tint_hex, so a second shop can look different without
 * touching CSS. Light mode uses the app's violet instead: a saturated green
 * over white reads as a success message rather than as a surface, and this
 * sheet is neither a confirmation nor a warning. The vendor colour is not
 * thrown away there, it is only unset: hand in --promo-tint-light the same
 * way --promo-tint is handed in and a shop gets its own light tint too.
 *
 * color-mix is not universal; where it is missing the whole declaration is
 * dropped and the sheet renders in the app's normal elevated background,
 * which is the pre-tint design and perfectly fine.
 *
 * ── THE VERTICAL RHYTHM ───────────────────────────────────────────────────
 * On a phone this sheet is short. Seven small blocks, none of which can be
 * made taller without writing more copy, and left to its content it stopped
 * a little past half the screen: next to the app's other sheets that reads
 * as a dialog that failed to load rather than as a sheet.
 *
 * So the mobile sheet has a min-height, and the slack that creates is handed
 * to AUTO MARGINS rather than to padding, because free space in a flex column
 * goes to the auto margins and nowhere else.
 *
 * ── AND IT IS SPLIT FOUR WAYS, NOT TWO ───────────────────────────────────
 * The first version of this put the slack in two gaps, above the code label
 * and above the body copy. On a large phone that measured 68px, 57px and
 * then 27px down to the button: the code block was pushed away from the
 * headline it belongs to, and the body copy ended up marooned high and
 * pressed against the button underneath. It read like small print, which is
 * the one thing that paragraph must not read like, because it carries the
 * actual argument.
 *
 * Four zones now, and deliberately not the same four:
 *
 *   above the headline    the sheet's top margin, air rather than a gap
 *   above the body copy   \  the two real breaks in this sheet, and they
 *   above the button      /  are kept equal so nothing looks marooned
 *   below the fine print  the sheet's bottom margin
 *
 * The gap between the subline and the code label is NOT one of them. Those
 * four blocks are one thought (here is the offer, here is the code for it)
 * and they stay at the same 24px they have on desktop.
 *
 * Two properties of splitting it this way are worth keeping: no single gap
 * can run away, because everything is divided by four rather than by two,
 * and half of the growth lands as padding at the two edges of the sheet,
 * where extra space reads as generosity instead of as distance.
 *
 * The MINIMUM of each of those four zones is the margin or padding on the
 * side that does NOT carry the auto, because an auto margin computes to zero
 * when there is nothing left to distribute. That is why .modal-body's own
 * padding, .promo-code and .promo-why carry numbers while .promo-headline,
 * .promo-why, .promo-cta and .promo-fine carry the autos. Move a number onto
 * the auto side and the layout collapses on the one screen it matters on,
 * the small one, where there is no slack at all and every gap is its
 * minimum.
 *
 * The consequence worth knowing before editing copy: shortening the body
 * text no longer shortens the sheet. It widens those four zones instead.
 */

/* ── The sheet ───────────────────────────────────────────────────────── */

.modal--promo {
    /* Light mode. The literal hex rather than --chart-2, which is this
       violet in the light palette and a lighter one in the dark palette;
       this value has to mean the same thing in both. */
    --promo-tint-active: var(--promo-tint-light, #7C3AED);
    --promo-tint-strength: 14%;

    background-image: linear-gradient(
        to bottom,
        color-mix(in srgb, var(--promo-tint-active, transparent) var(--promo-tint-strength, 12%), transparent),
        transparent
    );
    background-repeat: no-repeat;
    background-size: 100% 240px;

    /* The query container for the headline below, and deliberately the SHEET
       rather than .promo. Container query units resolve against the
       container's CONTENT box, so with the container sitting inside
       .modal-body the headline was being sized against the body width and
       shrank a little every time that padding grew. On the sheet, 5.7cqw
       means what it meant in the mockup the number was tuned in.

       Inline-size containment only: the height still comes from the content,
       so nothing about the sheet's own sizing changes. */
    container-type: inline-size;
}

[data-theme="dark"] .modal--promo {
    --promo-tint-active: var(--promo-tint, transparent);
    --promo-tint-strength: 12%;
}

/* The header carries no title, only the way out. Hiding the empty <h3>
   recovers the space it would otherwise hold open. */
.modal--promo .modal-title {
    display: none;
}

/* ── AND THAT IS WHY THE CLOSE BUTTON NEEDS A LINE OF ITS OWN ──
   .modal-header is `justify-content: space-between`, which is correct while
   there are two children. Hide the title and the button is the only child
   left, and a lone child under space-between sits at the START of the row.
   So this one sheet had its X on the left while every other dialog in the
   app has it on the right. */
.modal--promo .modal-header {
    justify-content: flex-end;
}

.modal--promo .modal-body {
    padding: var(--space-2) var(--space-5) var(--space-6);
    text-align: center;
}

/* One column, so the mobile block at the bottom of this file has auto
   margins to hand its slack to.

   On desktop this changes nothing at all: every gap in this sheet is a
   margin on ONE side only, so the collapsed block margins and the summed
   flex margins come to the same number. Worth keeping it that way, because
   the moment two adjacent elements both carry a margin, the two layouts
   drift. */
.promo {
    display: flex;
    flex-direction: column;
}

/* ── Headline ────────────────────────────────────────────────────────── */

.promo-headline {
    font-size: var(--text-lg);
    font-weight: var(--weight-bold);
    letter-spacing: -0.03em;
    line-height: 1.3;
    margin: var(--space-1) 0 var(--space-3);
    color: var(--color-text-primary);
    text-wrap: balance;
}

/* Scales with the sheet, so the same headline takes the same share of the
   width on a 320px phone and in the 400px desktop dialog. The plain size
   above is the fallback for browsers without container query units.

   IT IS ALLOWED TO WRAP. An earlier version pinned it to one line with
   white-space: nowrap, which is only safe for a headline of about this
   length: the mobile sheet clips its overflow, so a longer one from a second
   creative would have been cut off mid-word rather than set on two lines.
   The current copy still fits on one line at every width; balance is there
   for the day it does not. */
@supports (font-size: 1cqw) {
    .promo-headline {
        font-size: clamp(1.0625rem, 5.7cqw, 1.4rem);
    }
}

.promo-subline {
    font-size: var(--text-base);
    color: var(--color-text-secondary);
    line-height: 1.55;
    margin: 0 auto var(--space-6);
    max-width: 32ch;
    text-wrap: balance;
}

/* ── The code ────────────────────────────────────────────────────────── */

.promo-codelabel {
    font-size: 10.5px;
    font-family: var(--font-mono);
    letter-spacing: 0.13em;
    text-transform: uppercase;
    color: var(--color-text-tertiary);
    margin-bottom: var(--space-2);
    text-align: left;
}

.promo-code {
    display: flex;
    align-items: stretch;
    border: 1.5px dashed var(--color-border-strong);
    border-radius: var(--radius-lg);
    background: var(--color-bg-secondary);
    overflow: hidden;
}

.promo-code-val {
    flex: 1;
    min-width: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 16px var(--space-2);
    font-family: var(--font-mono);
    font-weight: var(--weight-bold);
    font-size: var(--text-md);
    letter-spacing: 0.04em;
    color: var(--color-text-primary);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    /* Selectable on purpose. If both clipboard paths fail, the user can
       still get the code out by hand, and this is the one string in the
       sheet that has to survive that. */
    user-select: all;
    -webkit-user-select: all;
}

.promo-code-copy {
    border: 0;
    border-left: 1.5px dashed var(--color-border-strong);
    background: transparent;
    cursor: pointer;
    padding: 0 15px;
    display: flex;
    align-items: center;
    gap: var(--space-2);
    font: inherit;
    font-size: var(--text-sm);
    font-weight: var(--weight-semibold);
    color: var(--color-text-secondary);
    flex-shrink: 0;
    transition: color var(--duration-fast) var(--ease-out);
}

@media (hover: hover) {
    .promo-code-copy:hover { color: var(--color-text-primary); }
}

.promo-code-copy.is-done {
    color: var(--color-success);
}

/* ── Body copy and actions ───────────────────────────────────────────── */

.promo-why {
    font-size: var(--text-sm);
    color: var(--color-text-secondary);
    line-height: 1.65;
    margin: var(--space-6) auto;
    max-width: 38ch;
    text-wrap: pretty;
}

.promo-cta {
    width: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
    border: 0;
    border-radius: var(--radius-md);
    cursor: pointer;
    font: inherit;
    font-size: var(--text-base);
    font-weight: var(--weight-semibold);
    min-height: 48px;
    background: var(--color-primary);
    color: var(--color-text-inverse);
    transition: transform 0.12s var(--ease-out), background var(--duration-fast) var(--ease-out);
}

@media (hover: hover) {
    .promo-cta:hover { background: var(--color-primary-hover); }
}

.promo-cta:active {
    transform: scale(0.985);
}

/* base.css turns the focus ring off on every button in the app. Both
   controls in here put it back for keyboard users only, in the shape
   .label-action already uses, because a sheet with exactly two actions and
   no visible focus is unusable without a mouse. */
.promo-cta:focus-visible,
.promo-code-copy:focus-visible {
    outline: 2px solid var(--color-primary);
    outline-offset: 2px;
}

/* Never optional, and never smaller than this. It is the affiliate
   disclosure, not a footnote about it. */
.promo-fine {
    font-size: 11px;
    line-height: 1.55;
    color: var(--color-text-tertiary);
    margin: var(--space-4) auto 0;
    max-width: 40ch;
}

/* ── The phone ───────────────────────────────────────────────────────── */

@media (max-width: 768px) {
    /* The floor the sheet is held at. Two limits, because they answer two
       different failure modes: the percentage keeps it in proportion on a
       phone, and the pixel cap stops a tablet in portrait (768px is inside
       this query) from opening a 740px sheet with a quarter of it empty.

       The vh line is the fallback for browsers without dvh, the same pair
       .modal uses for its max-height. Not a token, because that pair cannot
       be one: a var() holding a dvh value computes to invalid on a browser
       that does not know the unit and takes the fallback down with it. */
    .modal--promo {
        min-height: min(72vh, 640px);
        min-height: min(72dvh, 640px);
    }

    .modal--promo .modal-body {
        display: flex;
        flex-direction: column;
        padding: var(--space-3) var(--space-6) var(--space-6);
    }

    .modal--promo .promo {
        /* Fills the taller sheet, and never shrinks below its content: long
           copy on a small screen still scrolls the body rather than being
           squeezed into it. */
        flex: 1 0 auto;
    }

    /* The four zones the slack is divided between, and the two numbers that
       are the minimum of the middle two. Read THE VERTICAL RHYTHM at the top
       before moving any of these six lines, and in particular before adding
       a fifth auto: every one of them takes a quarter of the growth away
       from the other three. */
    .modal--promo .promo-headline { margin-top: auto; }
    .modal--promo .promo-code     { margin-bottom: var(--space-6); }
    .modal--promo .promo-why      { margin-top: auto; }
    .modal--promo .promo-cta      { margin-top: auto; }
    .modal--promo .promo-fine     { margin-bottom: auto; }

    /* One step up, to the size the subline is already set in.
       This paragraph is the only argument in the sheet: it is the sentence
       that says the discount is not the point and that ordering here is what
       keeps the app free. At 13px, centred, grey and five lines long it
       looked like the leaflet in a medicine box, which is a shape people
       have learned to skip. It does not go bigger than the subline, because
       the subline is the more important of the two and the order has to
       stay readable. */
    .modal--promo .promo-why {
        font-size: var(--text-base);
    }

    /* A little more of the two things a thumb has to hit. */
    .modal--promo .promo-code-val {
        padding-top: 18px;
        padding-bottom: 18px;
    }

    .modal--promo .promo-cta {
        min-height: 52px;
    }
}
