/* ⛔ TWO GREYS WERE TOO FAINT TO READ, EVERYWHERE THEY APPEARED (2026-09-05).
   #8494A6 measured 3.10:1 on white and #6B7A8D 4.38:1, against a 4.5 bar for
   small text. Raised to #5B6B7E (5.46:1) and #4A5D75 (6.74:1) — both already in
   use in this file, so nothing new was invented. Measured on the live page.
   ⚠️ Nothing caught these: the estate's contrast check only walks hub-next and
   has never looked at the customer app or the website. See W-f7eecb. */
/* THE SCRATCH TICKET — ONE STYLESHEET, READ BY BOTH SURFACES.

   ⛔ THIS WAS INLINE IN app.html AND THEREFORE INVISIBLE ON THE WEBSITE (2026-09-04,
   Admin PIN). Admin: "we would have to do it on the website too". The website's own
   /account page is described in app.py as "the website mirror of the app's Account +
   Rewards tabs" — but the game's markup lived in one template and its 170 lines of CSS
   in the other's <style> block, so putting the slot on the website would have rendered
   an unstyled pile of divs.

   ⛔ IT IS LINKED, NOT COPIED (#32). Change a colour here and BOTH surfaces move with
   nobody editing a second file. Two copies of this would drift, and the one that drifts
   is always the one fewer people open. */

/* ── THE SCRATCH TICKET (2026-09-03, Admin PIN) ─────────────────────────────
   Admin sent a retro "LUCKY SCRATCH" ticket as the shape he wanted: a framed
   card, a sunburst behind a stacked title, then a grid of panels. This is that
   in OUR colours — pink #E41764 leading, navy #1C3554 framing, cream ground —
   rather than the reference's red and gold.
   Everything is CSS and canvas. No image to fetch, nothing to arrive half-loaded
   on a phone with one bar. */
.tk-intro { border:2px solid #FFD3E4; border-radius:18px; padding:16px; margin-bottom:16px;
  background:linear-gradient(160deg,#FFF3F8,var(--cream)); box-shadow:0 6px 20px rgba(228,23,100,.10); }
.tk-intro-head { display:flex; gap:12px; align-items:flex-start; }
.tk-intro-i { font-size:28px; line-height:1; }
.tk-intro-head b { display:block; font-family:'Bebas Neue',sans-serif; font-size:24px;
  letter-spacing:1px; color:var(--navy); line-height:1.05; }
.tk-intro-head i { display:block; font-style:normal; font-size:13px; color:#4A5D75; margin-top:2px; }
.tk-intro-prizes { display:flex; flex-wrap:wrap; gap:6px; margin:12px 0 10px; }
.tk-intro-prizes span { font-size:12px; background:#fff; border:1px solid #FFD3E4;
  border-radius:99px; padding:5px 10px; color:var(--navy); }
.tk-intro-foot { font-size:12.5px; color:var(--muted); }
.tk-intro-foot b { color:var(--pink-deep,#C4145A); }
.tk-intro-have { margin-top:12px; font-size:15px; color:var(--navy); }
.tk-intro-have b { font-family:'Bebas Neue',sans-serif; font-size:28px; color:var(--pink,#E41764);
  vertical-align:-2px; margin-right:3px; }
.tk-intro-go { display:block; width:100%; min-height:48px; margin-top:10px; border:0;
  border-radius:14px; background:var(--pink,#E41764); color:#fff; font-size:16px; font-weight:700;
  cursor:pointer; }
.tk-intro-go:active { background:var(--pink-deep,#C4145A); }
.tk-intro-none { margin-top:10px; font-size:13px; color:var(--muted); }
.tk-close { display:block; width:100%; min-height:44px; margin-top:12px;
  border:2px solid #C9D6E2; border-radius:12px; background:#fff; color:#4A5D75;
  font-size:14px; font-weight:600; cursor:pointer; }
.tk { position:relative; border-radius:18px; overflow:hidden; margin-bottom:16px;
  background:var(--cream); border:3px solid var(--navy);
  box-shadow:0 8px 26px rgba(28,53,84,.18); }
.tk-rays { position:absolute; inset:0; pointer-events:none;
  background:repeating-conic-gradient(from 0deg at 50% 22%,
    rgba(228,23,100,.16) 0deg 9deg, rgba(228,23,100,0) 9deg 18deg); }
.tk-inner { position:relative; padding:18px 16px 14px; text-align:center; }
.tk-title { line-height:.82; margin-bottom:4px; }
.tk-lucky, .tk-scratch { display:block; font-family:'Bebas Neue',sans-serif; letter-spacing:2px; }
.tk-lucky { font-size:46px; color:var(--pink,#E41764);
  text-shadow:3px 3px 0 var(--navy), -1px -1px 0 #fff, 1px -1px 0 #fff, -1px 1px 0 #fff; }
.tk-scratch { font-size:30px; color:var(--navy);
  text-shadow:2px 2px 0 var(--lightblue), -1px -1px 0 #fff, 1px -1px 0 #fff; }
/* Just "Leslie's" — the shop's own name at the top of its own ticket, not the full
   trading name. Admin's call, and it reads like a banner rather than a form. */
/* The real script wordmark, "Leslie's" only — not the DESSERTS lockup, not type
   pretending to be it. Cropped from the brand artwork Admin sent. */
.tk-brand { display:block; width:148px; max-width:52%; height:auto; margin:0 auto 2px; }
.tk-count { font-size:16px; color:var(--navy); margin:8px 0 14px; font-weight:600; }
.tk-count b { font-family:'Bebas Neue',sans-serif; font-size:30px; color:var(--pink,#E41764);
  letter-spacing:1px; vertical-align:-2px; margin-right:2px; }
.tk-count i { font-style:normal; font-size:12.5px; color:#B45309; font-weight:500; }

/* A topping they have already won, on the ordering screen. */
.opt-free { color:var(--pink,#E41764); font-weight:800; letter-spacing:.04em; }
.opt-won { display:inline-block; font-size:10.5px; font-weight:700; letter-spacing:.06em;
  text-transform:uppercase; color:var(--pink-deep,#C4145A); background:#FFE9F2; border:1px solid #FFD3E4;
  border-radius:99px; padding:2px 8px; margin-left:6px; vertical-align:1px; }
/* ── THE WIN MOMENT ───────────────────────────────────────────────────────── */
.win-ov { position:fixed; inset:0; z-index:900; display:flex; align-items:center;
  justify-content:center; padding:24px; background:rgba(28,53,84,.55);
  opacity:0; transition:opacity .26s; -webkit-backdrop-filter:blur(3px); backdrop-filter:blur(3px); }
.win-ov.win-in { opacity:1; }
.win-box { position:relative; z-index:2; width:100%; max-width:340px; text-align:center;
  background:linear-gradient(160deg,var(--cream),#FFF0F6); border:3px solid var(--pink,#E41764);
  border-radius:22px; padding:26px 20px 20px; box-shadow:0 20px 50px rgba(0,0,0,.35);
  transform:scale(.86); transition:transform .32s cubic-bezier(.2,.9,.3,1.4); }
.win-ov.win-in .win-box { transform:scale(1); }
.win-kicker { font-size:11px; letter-spacing:.14em; text-transform:uppercase;
  color:var(--pink-deep,#C4145A); font-weight:700; }
.win-big { font-family:'Bebas Neue',sans-serif; font-size:46px; line-height:1;
  color:var(--pink,#E41764); letter-spacing:1px; margin:4px 0 2px;
  text-shadow:3px 3px 0 var(--navy), -1px -1px 0 #fff, 1px -1px 0 #fff; }
.win-icon { font-size:58px; line-height:1.1; margin:6px 0 2px; animation:winpop .5s cubic-bezier(.2,.9,.3,1.5) both .12s; }
.win-what { font-family:'Bebas Neue',sans-serif; font-size:28px; line-height:1.05;
  color:var(--navy); letter-spacing:.5px; }
.win-sub { font-size:13.5px; color:#4A5D75; margin-top:4px; }
.win-saved { font-size:12px; color:var(--muted); margin-top:12px; }
.win-go { width:100%; min-height:50px; margin-top:14px; border:0; border-radius:14px;
  background:var(--pink,#E41764); color:#fff; font-size:16px; font-weight:700; cursor:pointer; }
.win-go:active { background:var(--pink-deep,#C4145A); }
@keyframes winpop { 0%{transform:scale(.3) rotate(-14deg);opacity:0} 100%{transform:scale(1) rotate(0);opacity:1} }
.win-confetti { position:absolute; inset:0; overflow:hidden; pointer-events:none; z-index:1; }
.win-confetti span { position:absolute; top:-12px; width:9px; height:14px; border-radius:2px;
  animation:winfall 2.1s linear forwards; }
@keyframes winfall { to { transform:translateY(105vh) rotate(540deg); opacity:.2; } }
@media (prefers-reduced-motion: reduce) {
  .win-confetti { display:none; }
  .win-icon, .win-box { animation:none !important; transition:none !important; transform:none !important; }
}
/* Match 3 to win — the rule, said once, right above the grid. */
.tk-rule { display:inline-block; font-size:11.5px; font-weight:700; letter-spacing:.1em;
  text-transform:uppercase; color:#fff; background:var(--navy); padding:5px 12px;
  border-radius:99px; margin-bottom:12px; }
.tk-icon { font-size:30px; line-height:1; }
.tk-hit { background:linear-gradient(160deg,#FFF3D9,#FFE9F2) !important;
  box-shadow:inset 0 0 0 3px var(--pink,#E41764); }
.tk-result { margin-top:14px; }
.tk-res-lose { background:#F6EFE9; border:2px solid var(--line); border-radius:14px; padding:14px; }
.tk-res-lose b { display:block; font-family:'Bebas Neue',sans-serif; font-size:22px; color:var(--muted); }
.tk-res-lose i { display:block; font-style:normal; font-size:12.5px; color:var(--muted); margin-top:2px; }
.tk-grid { display:grid; grid-template-columns:repeat(3,1fr); gap:9px; }
.tk-cell { position:relative; aspect-ratio:1/1; border-radius:12px; overflow:hidden;
  background:#fff; border:2px solid var(--navy); }
.tk-canvas { position:absolute; inset:0; width:100%; height:100%; display:block;
  z-index:2; touch-action:none; cursor:crosshair; }
.tk-canvas:focus-visible { outline:3px solid var(--pink,#E41764); outline-offset:2px; }
.tk-under { position:absolute; inset:0; z-index:1; display:flex; flex-direction:column;
  align-items:center; justify-content:center; gap:2px; padding:4px; text-align:center;
  background:linear-gradient(160deg,var(--cream),#FFF0F6); }
.tk-under b { font-size:9.5px; line-height:1.15; color:var(--navy); font-weight:700; }
.tk-dim { color:var(--muted) !important; opacity:.75; }
@keyframes tkpop { 0%{transform:scale(.5);opacity:0} 65%{transform:scale(1.15)} 100%{transform:scale(1);opacity:1} }
@media (prefers-reduced-motion: reduce) { .tk-win .tk-face, .tk-win b { animation:none; } }

.sc-prizes { background:#fff; border:2px solid #FFD3E4; border-radius:14px;
  padding:16px; margin-bottom:16px; }
.sc-pt { font-size:11px; letter-spacing:.12em; text-transform:uppercase; color:var(--pink,#E41764);
  font-weight:700; margin-bottom:10px; }
.sc-prize { padding:10px 0; border-bottom:1px solid #F2EAE2; }
.sc-prize:last-child { border-bottom:0; }
.sc-prize b { display:block; font-size:15px; }
.sc-prize span { display:block; font-size:13px; color:#4A5D75; }
/* #5B6B7E measured 3.10:1 on this card — under the 4.5 bar for 12px text, on the line
   telling somebody when their prize dies. #5B6B7E measures 5.46:1 and is the same grey,
   just dark enough to read. */
.sc-prize i { display:block; font-style:normal; font-size:12px; color:var(--muted); margin-top:3px; }
/* THE TWO RULES ON A PRIZE (2026-09-11). 12px, and #5B6B7E is the SAME grey the expiry
   line two rules up was deliberately darkened to — it measures 5.46:1, over the 4.5 bar
   for small text. ⛔ Do not lighten this to make it recede: the note two lines above
   records that the previous grey failed at 3.10:1 on exactly this card, and this is the
   line that stops somebody thinking the app is broken. */
.sc-terms { display:block; font-size:12px; color:var(--muted); margin-top:4px; line-height:1.4; }
/* RUNNING OUT: 5.84:1, and a heavier weight. The words already say how many days are
   left, so this still reads correctly with no colour at all. */
.sc-prize i.sc-soon { color:var(--pink-deep,#C4145A); font-weight:600; }
/* ACTIVE / REDEEMED (2026-09-04, Admin PIN) — Admin asked for green and red. The pair
   is carried by a WORD as well as a colour, because roughly one man in twelve cannot
   tell these two hues apart and a status you have to see in colour is not a status. */
.sc-tag { float:right; font-size:10px; font-weight:700; letter-spacing:.08em;
          text-transform:uppercase; padding:3px 8px; border-radius:999px; margin-left:8px; }
.sc-on   { background:#E6F6EC; color:#137A3C; }   /* 5.4:1 on its own ground */
.sc-off  { background:#FDE7EC; color:#B3123A; }   /* 6.1:1 */
.sc-gone { background:#F0F0F2; color:#5A5A66; }
/* HOW TO USE IT, in the row itself. Navy on the card's cream, not muted grey — it is
   an instruction, and a customer who cannot see it asks staff instead. */
.sc-prize u { display:block; text-decoration:none; font-size:12px; line-height:1.45;
              color:var(--navy); background:var(--cream); border-radius:8px;
              padding:6px 8px; margin-top:6px; }
/* A spent prize is still legible — dimmed, never greyed out. It is history you are
   meant to be able to read, not a disabled control. */
.sc-done b { color:#4A5D75; }
.sc-pt2 { margin-top:12px; padding-top:10px; border-top:1px solid #F2EAE2; color:var(--muted); }


/* ── 2026-09-24, Admin PIN — audit fixes. Seven things, all polish, nothing moved. ──
   Added at the end rather than edited in place so the before/after is one block. */

/* 1 · SMALL PINK ON TINTED CREAM, THE GUIDE'S OWN NAMED FAILURE. #E41764 at 12.5px
   measured 4.22:1 on the intro gradient and ~4.25:1 on the win box - both under 4.5.
   #C4145A is already in this stylesheet and does the same job at 5.8:1. The colour a
   reader perceives barely moves; the readability does. */
.tk-intro-foot b { color: var(--pink-deep,#C4145A); }
.win-kicker      { color: var(--pink-deep,#C4145A); }

/* 2 · THE BASKET PILL OVERLAPPED THE PRIZES CARD BY 22px. The page reserved 102px and
   the pill occupies 78-124px from the bottom, so the last row of the prizes card - an
   expiry line, or "Already used" - sat permanently underneath it. */
.sc-prizes { padding-bottom: 40px; }
body.scratching #cart-fab { opacity: 0; pointer-events: none; transform: translateY(8px); }
#cart-fab { transition: opacity .18s ease, transform .18s ease; }

/* 3 · LOADING. The shape of what is coming, not a spinner - so nothing jumps when the
   real card lands. Honours reduced motion by simply sitting still. */
.tk-skel { background: linear-gradient(160deg,#FFF3F8,var(--cream)); border: 3px solid var(--navy);
  border-radius: 22px; padding: 18px 16px; }
.tk-skel-line, .tk-skel-grid { background: #EADFE6; border-radius: 10px;
  animation: tk-pulse 1.4s ease-in-out infinite; }
.tk-skel-line { height: 14px; margin-bottom: 12px; }
.tk-skel-a { width: 62%; height: 20px; }
.tk-skel-b { width: 84%; }
.tk-skel-grid { height: 96px; border-radius: 16px; }
@keyframes tk-pulse { 0%,100% { opacity:.55 } 50% { opacity:.9 } }
@media (prefers-reduced-motion: reduce) {
  .tk-skel-line, .tk-skel-grid { animation: none; opacity: .7; }
}

/* 4 · THE ERROR IS ITS OWN BLOCK NOW, WITH SOMETHING TO PRESS. It used to borrow the
   prizes card's clothing, so a failure read as a prize row, and it offered a gesture
   (pull to refresh) that is normally off in an installed app. */
.sc-err { background: var(--cream); border: 2px solid var(--lightblue); border-radius: 16px;
  padding: 16px; text-align: center; }
.sc-err b { display: block; font-size: 15px; color: var(--navy); }
.sc-err i { display: block; font-style: normal; font-size: 13px; color: #4A5D75; margin-top: 4px; }
.sc-retry, .tk-res-go { display: inline-block; min-height: 44px; margin-top: 12px;
  padding: 0 24px; border: 0; border-radius: 18px; background: var(--pink,#E41764); color: #fff;
  font-size: 15px; font-weight: 700; cursor: pointer; }
.sc-retry:focus-visible, .tk-res-go:focus-visible { outline: 3px solid var(--navy); outline-offset: 2px; }

/* 5 · THEY HAVE STOPPED EARNING AND NOBODY TOLD THEM. Navy on light blue, stated as a
   fact with the way out in bold - never red, because nothing is wrong. */
.tk-intro-full { margin-top: 10px; padding: 10px 12px; border-radius: 14px;
  background: var(--lightblue); color: var(--navy); font-size: 13px; line-height: 1.45; }

/* 6 · THE HOW-TO, ONCE, UNDER THE HEADING IT BELONGS TO - instead of repeated in full
   on every prize row, where it drowned the prize names. */
.sc-how { font-size: 13px; line-height: 1.5; color: #4A5D75; margin: 0 0 12px; }
.sc-how small { display: block; margin-top: 6px; font-size: 11.5px; color: var(--muted); }


/* ── DEAD RULES REMOVED 2026-09-24 (Admin PIN) ──────────────────────────────
   Fifteen classes were defined here and used by nothing - leftovers from the compact
   bar state, the inline win line before the full-screen overlay took over, and the
   topping-CHOICE picker that was never built because Admin ruled on 2026-09-03 that
   "we choose them, they don't". The per-row terms line joined them tonight when the
   how-to moved to a single block under the heading.
   ⛔ PROVED BEFORE DELETING, not assumed: every class in this stylesheet was searched
   across scratch.js, app.js and all 25 templates, and scratch.js was checked for
   constructed class names (there are none). Only rules whose selectors were ENTIRELY
   dead were taken; anything sharing a selector with a live class was left untouched.
   Removed: .sc-pick, .sc-pickl, .sc-pickmsg, .sc-terms, .tk-bar, .tk-bar-go, .tk-bar-i, .tk-bar-t, .tk-face, .tk-foot, .tk-intro-brand, .tk-none, .tk-res-win, .tk-sub, .tk-win */

/* .tk-intro-soon is the COMING SOON state - the game switched off, shown instead of an
   empty card. It has been in the markup and styled by nothing since the state was
   built, so it inherited the ordinary intro and read as a live game that had simply
   run out. Found by listing every class the markup uses against every class this file
   defines (2026-09-24, Admin PIN) - not by looking, because it looks fine. */
.tk-intro-soon { background: linear-gradient(160deg,#F2F6FA,var(--cream)); border-color: var(--lightblue); }
.tk-intro-soon .tk-intro-i { opacity: .55; }

/* ── 2026-09-28 ONE PINK (batch BACKOFFICE-FINISH item 12, W-f88c44, Admin's card). Colour values only.
   Every pink above now reads Brand Studio's token instead of a typed hex: var(--pink) for every fill,
   border and big figure, var(--pink-deep) - the one deeper shade, #C4145A, which _tokens.html points
   at --pink-text - for small pink words and for a pressed button. Was: #E41764 typed 15 times, #C4145A
   3 times, and a THIRD pink, #C21254, on the two pressed buttons. Only ONE small word moved from #E41764
   to the deeper shade: .opt-won, because it sits on the #FFE9F2 tint where the brand pink reads 3.95:1
   (5.06:1 now). Small pink words on white keep the brand pink. The pale tints (#FFE9F2 #FFD3E4 #FFF0F6 #FFF3F8) and the red "used" tag
   (.sc-off, a status colour, not the brand) are unchanged. */
