/* The install / add-to-home-screen card.
 *
 * Moved out of utyk/templates/_utyk_install.html on 2026-08-31. It was inline in the
 * HTML, so no browser could cache a byte of it and it was re-sent on
 * every request. url_for('static', ...) stamps this URL with the
 * file's own CONTENT hash and serves it immutable for a year, so it
 * re-downloads when these rules change and never otherwise.
 *
 * Byte-for-byte the block that was there; only its address moved.
 */

  .uki[hidden], .uki-ios[hidden] { display:none; }
  /* Secondary to "Start free" everywhere it appears, so it never takes the
     accent as a fill. The accent only shows up on hover, as a border. */
  .uki-btn { display:inline-flex; align-items:center; gap:12px;
             padding:13px 20px; border-radius:14px; cursor:pointer;
             min-height:48px;
             border:1px solid var(--uk-line); text-align:left;
             background:var(--uk-raised); color:var(--uk-text);
             font-family:inherit; backdrop-filter:blur(6px); }
  .uki-btn:hover { border-color:var(--uk-accent);
                   background:var(--utyk-accent-wash); }
  .uki-ic { font-size:22px; line-height:1; flex:none; }
  .uki-btn b { display:block; font:800 14.5px Inter,sans-serif; }
  .uki-btn small { display:block; font-size:12px; color:var(--uk-dim);
                   margin-top:2px; }
  .uki-ios-card { background:var(--uk-panel); border:1px solid var(--uk-line);
                  border-radius:16px;
                  padding:18px 20px; max-width:420px; }
  .uki-ios-card b { font:800 15px Inter,sans-serif; }
  .uki-ios-card p { font-size:13px; color:var(--uk-dim); line-height:1.5;
                    margin:5px 0 10px; }
  .uki-ios-card ol { margin:0; padding-left:19px; color:var(--uk-text);
                     font-size:13px; line-height:1.65; }
  .uki-ios-card ol li + li { margin-top:3px; }
  .uki-share { width:15px; height:15px; display:inline-block;
               vertical-align:-3px; color:var(--uk-accent); }
  /* THE SIGNED-IN SHELL renders this as a bottom sheet rather than inline,
     because there it is included at the END of the body (so its <script>
     cannot land above the page content) and an inline card there would sit
     under everything. Offset by --uk-tabh, the same token the FAB uses, so
     it clears the phone tab bar instead of covering it. */
  .uki-ios-fixed { position:fixed; left:12px; right:12px; z-index:60;
                   bottom:12px; }
  /* Clear the phone tab bar. THE BREAKPOINT HERE MUST MATCH THE ONE THAT
     RENDERS THE TAB BAR, which is 1000px in utyk_base.html, not 720. It said
     720 and the tab bar's own boundary moved to 1000 on 2026-08-06 without
     this following it, and the result was not cosmetic: the tab bar is
     z-index 70 and this card is 60, so between 721 and 1000 the card's own
     "Not now" sat UNDERNEATH the tab bar. document.elementFromPoint over the
     dismiss link returned `uk-tab active`, so the card could not be put away
     AT ALL, on every iPad in portrait except the 13 inch, while still covering
     the foot of every page. Verified unreachable at 744, 820 and 999, and
     reachable again at 390 and at 1001. A nag with no dismiss is worse than
     the overlap it was added to prevent, so if these two numbers ever
     disagree again, this is the failure. */
  @media (max-width:1000px) {
    .uki-ios-fixed { bottom:calc(var(--uk-tabh, 0px) + 12px); }
  }
  /* ABOVE 1000px there is no tab bar, but there IS a composer pinned to the
     foot of the thread column, and the shell is a split view there so the
     thread is always on screen. Full width plus bottom:12px put this card
     exactly on top of it: the plus, the input, the mic and SEND all reported
     the card as the topmost element, in both orientations, so an iPad could
     not send a message while it was up.
     Constrained to the list column instead of offset upward, because the
     column is where the conversations are and this card is about them. The
     thread column keeps its composer clear, and the list column's own footer
     is already handled by the reservation rule below. --uk-nav-w is the rail,
     400px is the list column from the .ukc grid, so 12px of inset either
     side leaves 376. */
  @media (min-width:1001px) {
    .uki-ios-fixed { left:calc(var(--uk-nav-w, 232px) + 12px); right:auto;
                     width:376px; }
  }
  /* RESERVE ITS HEIGHT IN WHATEVER SCROLLS, because `position:fixed` takes no
     space at all: every scroll region in the shell ends underneath this card,
     and the content in that band cannot be brought out from under it by
     scrolling, because there is nothing below it to scroll to. Measured on an
     iPhone Air (420x912) with the sheet up, before this rule existed:

       Chats      1 of 6 conversations fully visible, and the LAST one could
                  not be reached at all: .ukc-rows scrolled to its end with
                  two rows still behind the card, plus both swipe actions.
       Shop       the entire request form, both selects and the textarea.
     Shop menu  the last product of the last category, and (once it had one)
                the Ask the bar and Your receipts rows under it. Added
                2026-08-12: `.uks` and `.ukx` are the Shop's own scroll
                regions and postdate this list, which is a literal, so the
                test below could not notice them. `ukcx` above is the ASK
                form, which is what /shop used to be.
       Account    four settings rows (Alerts, When you arrive, How your Thai
                  reads, Password), and the trial card sliced in half.
       Discover   the last lady card with its Open chat and its star.
       Thread     the foot of the message history.

     PADDING INSIDE EACH SCROLLER WAS THE WRONG PLACE, and it is worth being
     precise about what it did and did not buy, because it looked right for
     two months. It let the LAST row be scrolled out from under the card. It
     did nothing whatever about the card sitting on top of the middle of the
     page, because a scroller's bottom padding is at the far end of its
     content, not at the bottom of its viewport. Measured at 390x844 on first
     paint with all seven of those rules in force:

       Shop       the card covered a product card and its Add button. 72 of
                  the probe points inside the card's rect landed on real
                  content, chiefly .uks-grid and .uks-link.
       Account    56 points, over a.uv-grow and its label, 100% hidden.

     So a man's first sight of the Shop had a nag over the button that adds
     the thing he came for, and no amount of scroll room below fixed that.

     RESERVE IT ON THE THING THAT SIZES THE SCROLLERS INSTEAD. `.uk-body` is
     `flex:1; display:flex; min-height:0`, and every scroll region in the
     signed-in shell is a flex child of it, so padding there shortens their
     VIEWPORTS and the card comes to rest over reserved background rather than
     over content. Verified by shrinking .uk-body 200px in the live page and
     re-measuring each one: .ukc-list, .ukd, .uka, .uks and .ukx all followed
     it exactly, on /chat, /discover, /account, /shop and the checkout. Same
     probe after the rule: 0 covered points on all four pages, nothing
     clipped, nothing overflowing.

     This is also the shell's OWN pattern rather than a new idea. The tab bar
     is `position:fixed` too, and the reason it does not cover anything is the
     line `.uk-body { padding-bottom: var(--uk-tabh) }` a few hundred lines up
     in utyk_base.html. This is that line, extended by the card.

     Both numbers come from the same two variables the card's own `bottom`
     uses, so the reservation and the card cannot disagree about where the
     card is: --uk-tabh + 12px is its offset, --uki-sheeth its measured
     height. That matters on the pages that suppress the tab bar
     (`uk-lady-mode`, `uk-detail-mode`), where the card still floats at the
     tab bar's offset: because both expressions carry --uk-tabh, the space
     reserved is exactly the space taken, with or without a bar under it.
     --uki-sheeth is published by the script below from the card's real
     height, so re-worded copy cannot leave it stale.

     ONE RULE ALSO ENDS THE LIST-ROT. The old form named seven classes by
     hand and its own test confessed the weakness: `.uks` and `.ukx` shipped
     with the Shop and sat unlisted for weeks until somebody found the last
     product of the menu permanently under the card on a real iPhone. A page
     added next month brings a new scroller and this needs no edit, because
     it does not name any of them. */
  @media (max-width:1000px) {
    body.uk-install-open .uk-body {
      padding-bottom: calc(var(--uk-tabh, 0px) + var(--uki-sheeth, 196px)
                           + 24px);
    }
  }
  /* ABOVE 1000px ONLY THE LIST COLUMN PAYS, because that is the only thing
     the card is over: the rule further up constrains it to --uk-nav-w + 12px
     and 376px wide, which is the conversation list. Shrinking the whole shell
     here would lift the THREAD column's composer off the foot of its column
     and leave a gap under it, to clear a card that is nowhere near it.
     This is also why the inbox column is the right target rather than the
     rows inside it: "Clear all conversations" lives in .ukc-listfoot, which
     is `margin-top:auto; flex:none` and therefore pinned to the foot of the
     column OUTSIDE the scroller, where no amount of padding within .ukc-rows
     can reach it. Shrinking the column lifts the scroller and the pinned
     footer together.
     Shrinking is only safe because the sheet waits for the reply-address card
     to go: with that card up there is not enough column left and .ukc-rows
     would hit its 200px min-height floor and overflow a column that clips. */
  @media (min-width:1001px) {
    body.uk-install-open .ukc-list {
      padding-bottom: calc(var(--uki-sheeth, 196px) + 36px);
    }
  }
  /* NOTHING FOR THE THREAD, deliberately. `.tp-body` was in the old list, and
     it is the one entry that never needed to be: it lives inside
     `.tp-overlay`, which is `position:fixed; inset:0; z-index:9600`, so it is
     a separate stacking context nine and a half thousand levels above this
     card and the card cannot be in front of it. Its padding was therefore
     never reserving space against anything, and it was not free either: it
     pushed the newest message 232px up off the composer, which is the
     "dead space between the last message and the composer" this file has
     already been bitten by once. The thread also autofocuses its composer,
     which hides the card outright through the :has(:focus) rule below. */
  /* NOT ON A SHORT SCREEN, because 196px of fixed card stops being a strip
     along the bottom and becomes half the viewport.
     Measured at 390x500 the card lands at y229 and the reply-address form's
     Save button is at y227, so the card is on top of it and eats the tap:
     document.elementFromPoint over Save returns .uki-ios-card. A man types
     the address this very card asked him for, presses Save, and nothing
     happens, with no way to tell why.
     Two triggers, and the second is the one that bites in portrait:
       max-height   landscape (390px tall) and small phones with browser
                    chrome. 600px keeps the ordinary 844px phone untouched.
       :has(:focus) the keyboard. It is up for exactly as long as he is
                    filling in a field, which is exactly when a card pinned
                    to the bottom is in the way, and it takes the visual
                    viewport to roughly 380px on a standard iPhone. Ignored
                    wholesale by a browser without :has, which is no worse
                    than today. */
  @media (max-height:600px) {
    .uki-ios-fixed { display:none; }
  }
  body:has(input:focus, textarea:focus) .uki-ios-fixed { display:none; }
  /* NEVER OVER THE CONTROL THAT TAKES MONEY.
     The Shop's basket bar and the checkout's Pay bar are `position:fixed` at
     `bottom: var(--uk-tabh)` with z-index 60. This card is z-index 60 at
     `--uk-tabh + 12px` and is included at the END of the body, so it wins the
     tie and paints straight over the Pay button. Found on an iPhone 16e,
     2026-08-12: a first-time visitor with something in his basket could not
     see the button, let alone press it.
     Same rule as the reply-address deference below, for a stronger reason.
     That one is one setup prompt deferring to another; this is a nag getting
     out of the way of a purchase. It is live rather than checked once on
     load, because the basket bar appears the moment something goes in and
     nothing re-runs the script at that point.
     `.uks-basket` carries `.uks-hide` while the basket is empty, so an empty
     Shop still gets the card. */
  body:has(.uks-basket:not(.uks-hide)) .uki-ios-fixed,
  body:has(.ukx-bar) .uki-ios-fixed,
  /* AND THE ROUND-OF-DRINKS BAR, which is the same case as the basket bar
     above and not a new one. `.uksd-bar` carries the running count and the
     primary control on the round-of-drinks page, and it is fixed at
     `--uk-tabh` on a phone, which is within twelve pixels of where this card
     sits.

     (Its label is deliberately not written out here, and neither is the
     route. `uk_shop.html` carries the same note for the same reason: a
     stylesheet comment ships with the page, and two tests scan the served
     body for the words of a buy control. They are right and the comment is
     what has to move. This one was caught doing it.)
     Reported 2026-08-22 on an iPhone 16e, where the card was covering the
     second row of girls; the page was ALSO about to have the card land
     directly on top of that control, because the bar had just moved from
     sticky to fixed to clear the tab bar.
     Unconditional, unlike the basket's, because this bar is the only action
     on the page: it is drawn whether or not anything has been chosen, since
     it is also where the running total lives. A page whose whole purpose is
     one button does not get a nag over it. */
  body:has(.uksd-bar) .uki-ios-fixed,
  /* AND THE FULL-SCREEN PAGER, for the same reason one step further on.
     New today is a photograph and one button, and `uk_detail` takes the tab
     bar away, so `--uk-tabh` is 0 and this card drops to `bottom:12px`:
     straight onto `.ukf-meta`, which is `bottom:0` and carries her name, the
     favourite star and Open chat. Seen on an iPhone Air, 2026-08-16, eating
     roughly the bottom third of the picture.
     It also cannot win a stacking argument it should not be having:
     `.ukf-wrap` is `z-index:60` and so is this, so the winner is whichever
     the body happens to include last. That is not a thing to tune, it is a
     thing to stop entering.
     He still meets this on Inbox, Discover, Shop and Account, which is four
     surfaces more than enough for a nag. */
  body:has(.ukf-wrap) .uki-ios-fixed { display:none; }
  /* The FAB sits at exactly that offset too, so stand it down while the
     sheet is up rather than shuffling the sheet above it and leaving a gap:
     the sheet is dismissable and the button comes straight back.

     BOTH CLASS NAMES, and that is the whole of this rule's history. It was
     written against `.uk-fab` when that was the FAB. The redesign renamed it
     to `.r-fab` (utyk-rd.css) and `utyk_base.html` has rendered `.r-fab`
     ever since, so from that day this rule matched nothing and the outcome
     was the opposite of the one it describes: `.uki-ios-fixed` is z-index 60
     at `--uk-tabh + 12px` and `.r-fab` is z-index 30 at `--uk-tabh + 3px`,
     nine pixels below and thirty levels under, so the card painted straight
     over "Start a chat" and ate the tap. Measured at 375x812:
     document.elementFromPoint over the FAB's centre returned .uki-ios-card.
     Reached on the Inbox, where the FAB is the only way to start a NEW
     conversation once a returning customer has threads and the empty state's
     "Browse the ladies" is gone.
     `.uk-fab` is still DEFINED in utyk_base.html and nothing renders it;
     it is kept here so a page that goes back to it is not broken again. */
  body.uk-install-open .uk-fab,
  body.uk-install-open .r-fab { display:none; }
  .uki-ios-fixed .uki-ios-card { max-width:none; padding:14px 16px 12px;
                                 box-shadow:0 18px 48px -18px rgba(0,0,0,.75); }
  .uki-ios-fixed .uki-dismiss { margin-top:8px; }
  /* "Not now" was 15px tall, and it is the ONLY way to put this card away.
     The card is fixed over the foot of every signed-in screen, so a thumb
     that keeps missing leaves it covering the bottom of the app for good.
     Expanded past the paint rather than by inflating the paint, the same
     trick the Discover and Favourites stars use: the underline stays where
     the design put it and the target reaches the 44px floor. `position` is
     what makes the inset resolve against the button. */
  .uki-dismiss { margin-top:12px; border:0; background:none; padding:0;
                 color:var(--uk-muted); font:600 12.5px Inter,sans-serif;
                 text-decoration:underline; cursor:pointer;
                 position:relative; }
  .uki-dismiss::before { content:''; position:absolute;
                         left:-24px; right:-24px; top:-15px; bottom:-15px; }
