/* ASTROLOGY MABEL — the vertical's own stylesheet, loaded only on /astrology and its supporting pages.
 *
 * WHY THIS FILE EXISTS AT ALL. The flavor mechanism re-colours the shared marketing components by
 * overriding `:root` tokens, and that carries most of a theme for free. It cannot carry this one, for a
 * reason worth writing down: marketing.css uses a single token for "ink" (--maroon) in two different
 * jobs — text on the page's own surface, and text inside the white cards sitting on it. The reminder
 * palette is light-on-light, so one value serves both. This page is dark with LIGHT cards, and the two
 * jobs need opposite values. A token can't be both, and forcing it produces an invisible heading
 * somewhere every time.
 *
 * So: tokens do the surfaces and the accent (see landing.ts), and this file explicitly restyles the
 * places where shared ink lands on the dark surface. That is nearly all of it. The one exception is
 * `.as-sky`, the falling glyphs — the only markup this vertical invents, in the `.as-*` namespace that
 * exists so deleting the vertical stays a delete. (The twelve-signs section was `.as-signs` and went
 * that way on 2026-08-14: one block of rules, gone with the HTML that needed them.)
 *
 * It lives in public/ rather than the flavor's folder because that is where static assets are served
 * from — the same forced exception as migrations and tests. Deleting this vertical means deleting
 * src/flavors/astrology, this file, and public/mabel-astro-fullbody.webp.
 *
 * The shared sheet is NOT edited. The reminder palette does not move, and no rule here can reach a page
 * that does not load this file.
 */

/* THE PALETTE IS TWO COLOURS AND A SURFACE, and which does which is the whole design.
 *
 * LILAC decorates: eyebrows, hairlines, trust-bar icons, the qualifier, links on the dark surface. It
 * is everywhere, so it can never be the thing you click.
 * BLUSH acts: the CTA, and nothing else on the page. One blush object per screen, and it is always the
 * next step. (It is declared in landing.ts, because it is a shared token — `--salmon` — and the shared
 * button rule already reaches for it.)
 * VIOLET is the ground both sit on.
 *
 * The version this replaced had one colour, gold, doing both jobs on a neutral off-black. That is why
 * it read as a whiskey advertisement: with no hue in the surface, the only hue on the page becomes its
 * personality, and gold's personality is expensive-and-forty. The audience is 18-24 and female.
 */
:root {
  /* Ink on the dark surface — the half --maroon cannot do here. */
  --as-ink-hi: #F6F2FF;      /* headings */
  --as-ink-wordmark: #F6F2FF;
  --as-ink-body: #C3BADF;    /* hero sub */
  --as-ink-muted: #B6ACD4;   /* nav, trust labels, inactive tab */
  --as-ink-quiet: #948BB4;   /* captions, fine print */
  --as-accent: #C6B2FF;      /* lilac: decorates */
  --as-accent-hover: #DED2FF;
  --as-blush: #FF8FB4;       /* acts — same value as the --salmon token, for the rare glow on dark */
  --as-hairline: rgba(190,170,255,.22);
  --as-glass: rgba(190,170,255,.065);   /* the lift a card needs to read as an object on violet */
  --as-glass-hi: rgba(190,170,255,.11);
}

/* ---- header ---------------------------------------------------------------------------------- */

/* `flex-wrap` here is a LAST RESORT, not the layout. The qualifier costs ~73px of a header that had
   about 30px spare on a phone; without a wrap the compliance pill hung off the right edge and gave the
   whole page a horizontal scrollbar (measured at 390px: the document came out 418px wide). But wrapping
   the pill onto its own row is a bad answer too — it doubles the header's height and reads as a second
   nav. The real fix is the brand lockup below, which takes the qualifier out of the row; this stays as
   the graceful failure below ~330px, where even the reminder header overflows. */
/* NO RULE UNDER THE HEADER (2026-08-15, owner). The shared sheet draws one from 900px up in #e0d2c2 —
   correct on parchment — and this file used to re-colour it to lilac instead of removing it, which put a
   bright line straight across the top of a dark page. It is `border-bottom: 0` rather than a deleted
   declaration because the shared rule lives inside a media query: drop the override and the line comes
   back on desktop only, which is the worst of the three states. The header now ends where the surface
   changes, which on a page that is one continuous violet means it does not appear to end at all — the
   same change of mind as the flat background below, made in the same sitting: the chrome should sit on
   the page rather than be boxed off from it. */
.mk-header { border-bottom: 0; flex-wrap: wrap; gap: 10px 14px; }
.mk-wordmark { color: var(--as-ink-wordmark); }

/* THE AVATAR IS A DIFFERENT MABEL. The shared layout stamps an inline SVG of the reminder mascot into
   the header and the phone's thread bar; on this page that is the wrong character wearing the wrong
   palette, and it appears in the two places a visitor looks to decide who they are talking to. Swapped
   in CSS rather than by parameterising the markup: it is one image in two circles, and a `MABEL_DEFS`
   the flavor could override would be a second way to draw an avatar for every page to keep in step.
   The crop centres her face — the art is full-body, and the head occupies the top ~45% of it. */
.mk-ava, .mk-ava.on-white, .mk-ava.on-nude, .mk-brand .mk-ava {
  background: #2C2455 url(/static/mabel-astro-fullbody.webp) no-repeat 50% 46%;
  background-size: 210% auto;
}
.mk-ava svg { display: none; }

/* The qualifier beside the wordmark. Emitted by the shared layout whenever a flavor sets `qualifier`,
   and styled here because the shared sheet must not grow rules for markup only a vertical renders. */
.mk-qualifier {
  font: 700 9.5px var(--sans); letter-spacing: .1em; text-transform: uppercase;
  color: var(--as-accent); margin-left: 5px; align-self: center; white-space: nowrap;
}
@media (min-width: 900px) {
  .mk-qualifier {
    font-size: 11px; letter-spacing: .16em;
    border-left: 1px solid rgba(190,170,255,.42); padding-left: 10px; margin-left: 2px;
  }
}
/* THE MOBILE LOCKUP. Inline, the brand measures 193px against a 180px pill in 346px of usable width —
   13px short, so the pill wrapped onto its own row, which doubles the header's height and reads as a
   second nav. Stacking the qualifier under the wordmark (indented to the "T" by the avatar's 28px plus
   the brand's 8px gap) brings the brand to ~124px, and the row fits with room to spare at 360px.
   Must stay BELOW the rules above: same specificity, so source order is what decides the margin. */
@media (max-width: 899px) {
  .mk-brand {
    display: grid; grid-template-columns: auto auto; justify-content: start;
    column-gap: 8px; row-gap: 0; align-items: center;
  }
  .mk-brand .mk-ava { grid-row: 1 / span 2; }
  .mk-wordmark, .mk-qualifier { grid-column: 2; justify-self: start; }
  .mk-qualifier { margin: -4px 0 0 0; }
}

.mk-nav-desktop { color: var(--as-ink-muted); }
.mk-nav-desktop a:hover { color: var(--as-accent-hover); }
/* The compliance pill is white and stays white. On a page that is otherwise entirely dark it is the
   only bright chip in the chrome, which is the point: it is the one link in the header that a visitor
   deciding whether to hand over a phone number is looking for. The shared rule fills it with --white,
   which is the faintly-pink card colour here, so it is set explicitly rather than left to the token —
   a badge of accreditation should be the one thing on the page wearing no palette at all. */
.mk-navlink, .mk-nav-compliance {
  background: #FFFFFF; border-color: #FFFFFF; color: #1E1D1C;
}
.mk-navlink:hover, .mk-nav-compliance:hover { background: #F1ECE3; border-color: #F1ECE3; color: #1E1D1C; }
/* The last 20px. With the brand stacked, a 360px phone has 316px of usable header and wants 318 — two
   pixels short, which is the whole difference between one row and two. The pill sheds them: a slightly
   smaller seal, a slightly tighter font, less inner padding. Reads identically and now fits every
   handset width down to 360. Below ~330 the header wraps, and so does the reminder one. */
@media (max-width: 480px) {
  .mk-navlink { gap: 6px; padding: 4px 7px 4px 12px; font-size: 11.5px; }
  .mk-navlink .mk-nav-badge { width: 30px; height: 30px; }
}

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

/* THE SURFACE IS ONE FLAT COLOUR (2026-08-15, owner: deep purple solid, not the gradient).
 *
 * What was here until today: two wide radial glows and seven one-pixel "stars", painted on <body> at
 * 100% x 1100px so that the header and the hero sat on one continuous sky. It is deleted rather than
 * dimmed — a gradient turned far enough down to stop being noticed is still a gradient, still banding
 * on cheap panels, and still the thing every future colour decision has to be checked against.
 *
 * There is no rule left in this file, because the shared sheet's `body { background: var(--nude) }`
 * already IS the solid: --nude is #17122F, the deep plum-violet from landing.ts, and every section
 * below the hero paints the same token. So the page is now one uninterrupted purple from the top of the
 * header to the footer, and the seam this block was written to solve cannot exist — there is nothing
 * left to be out of step with. THE COLOUR MOVES AS ONE TOKEN: if this purple is ever wrong, change
 * `nude` in landing.ts and the whole page follows. Do not put a second value here.
 *
 * The falling glyphs below are now the only thing on the surface, which is why the sky effect stopped
 * being decoration on top of a picture and became the picture. Its opacity ceiling was tuned against the
 * old gradient; on a flat ground each glyph reads slightly cleaner, which is the direction we want. */

.mk-h1 { color: var(--as-ink-hi); }
/* The shared rule sets `white-space:nowrap` on each headline line so the designed breaks hold exactly.
   That is safe for "Stop texting yourself." and is a trap for anything longer: at 390px this headline
   overflowed the viewport and gave the whole page a horizontal scrollbar. Allowing a wrap keeps the
   authored breaks wherever they fit and degrades to an extra line where they don't, which is the right
   failure. Any flavor writing a longer headline than the reminder one needs this. */
.mk-h1 span { white-space: normal; text-wrap: balance; }
/* THE TABLET BAND, 900-1279px. Above 900 the shared hero grid becomes `1fr 540px`, so the phone mock
   takes a fixed 540 and the headline gets whatever is left: 234px at 900, 294px at 960. The shared
   type scale (4.6vw, floor 42px) is sized for the 614px column a 1280 window gives, and in a 234px one
   it puts roughly one word per line — measured at 6 lines for this headline, and 6 for the reminder
   page's too; it is simply less visible there because "Stop texting yourself." is three short words.
   This headline is now the whole pitch, so it gets a gentler ramp in that band only: 5 lines at 900,
   4 at 960, 3 from 1024 up, which is what the shared rule already produces by 1280 — where it takes
   back over. Flavor-only, so the reminder hero is untouched. */
@media (min-width: 900px) and (max-width: 1279px) {
  .mk-h1 { font-size: clamp(30px, 3.6vw, 46px); }
}
.mk-sub { color: var(--as-ink-body); }
.mk-caption { color: var(--as-ink-quiet); }

/* This artwork is 1024x1536 where the reminder one is 560x720, and it carries a soft glow of its own
   transparent margin. At the shared widths she lands noticeably smaller than the phone she is supposed
   to be leaning on, so both breakpoints get a size of their own — and a deeper overlap, since the
   transparent margin is what was holding her off the bezel. */
/* Phone width is the constraint, not taste: the bezel is a fixed 246px, so the figure plus its overlap
   has to fit the rest of a 360px screen. 126 - 22 + 246 = 350. Going wider overflowed. */
.mk-mabel { width: 126px; margin-right: -22px; }
@media (min-width: 900px) { .mk-mabel { width: 250px; margin-right: -30px; } }

/* ---- the falling sky ---------------------------------------------------------------------------- */

/* SNOW, IF SNOW WERE ZODIAC GLYPHS. Thirty-six signs, planets, nodes and aspect marks drifting down the
 * whole viewport, slowly and very faintly. The markup is `.as-sky` from landing.ts (glyphs only, no
 * inline styles); everything about how it moves is here.
 *
 * IT IS FIXED AND IT IS IN FRONT. Both are choices with a cost, so:
 *
 * Fixed, because the sky is not a section — the page is one flat surface from the header to the footer
 * (see the note above), and snow that scrolled away with the hero would be a hero decoration that
 * quits at the signup band. Fixed also means a fixed thirty-six elements exist for the life of the page
 * rather than however many a scrolling field would need, and each one is a composited transform: `translate`
 * falls, `transform` sways, `opacity` fades in and out at the edges so nothing pops in at 0vh or
 * vanishes at 100. Three animations on three separate properties, which is why they can have different
 * durations without fighting over one `transform`.
 *
 * In FRONT (z-index 1) rather than behind, because behind is not available: the sections below the hero
 * paint opaque backgrounds, so a layer under them would show through the hero and then stop. The cost is
 * that glyphs cross the light cards — the signup card, the price card — and THAT is what the opacity
 * ceiling is defending. Peak alpha runs .13-.26 of lilac: a clear glyph on #17122F, and on the near-white
 * cards a lavender speck you have to look for. If it ever reads as dirt on the card asking for a phone
 * number, this is the knob — lower the `--o` column, do not start scoping rules per section.
 *
 * EXCEPT BEHIND THE PHONE (2026-08-15, owner). Snow falling across the hero mock was the one place the
 * effect broke its own fiction: that component's entire value is being indistinguishable from a real
 * screenshot of Messages, and no screenshot has weather on it — a glyph drifting over the bubbles reads
 * as a smudge on the glass, or worse, as something the app is drawing. So the two hero objects are
 * lifted above the field instead of the field being scoped away from them. It is done by raising THEM
 * rather than lowering the sky because `z-index: 0` on a fixed layer still paints over every unpositioned
 * background and every line of text on the page, so the sky would keep crossing the signup card while
 * ducking whichever later sections happen to be positioned — layering that depends on document order is
 * layering nobody can reason about. Two explicit values, one stacking context, no surprises. */
.mk-phone { z-index: 2; }   /* was 1 (shared): now above .as-sky */
.mk-mabel { z-index: 3; }   /* was 2 (shared): keeps her in front of the bezel she leans on */

/* Back to the field itself.
 *
 * `pointer-events: none` is load-bearing: this layer sits over the signup field and the CTA.
 *
 * It does not run for anyone who asked motion to stop (bottom of the block), and the back half of the
 * field is dropped on phones — eighteen lanes across 390px is weather, not texture, and it is the
 * smallest screen paying for the compositing.
 */
.as-sky {
  position: fixed; inset: 0; overflow: hidden; pointer-events: none; z-index: 1;
  contain: layout paint;
}
.as-sky i {
  position: absolute; top: 0; left: var(--x);
  font-style: normal; line-height: 1;
  /* A symbol stack, because none of the page's own faces have these codepoints — left to --sans this
     falls back to whatever the browser picks per glyph, which is how you get eight of them in one
     weight and ten in another. Ends in `serif` rather than `sans-serif` deliberately: where a system
     has to substitute, the serif symbol fonts are the ones with the classical astrological forms. */
  font-family: "Apple Symbols", "Segoe UI Symbol", "Noto Sans Symbols 2", "Noto Sans Symbols2", "Noto Sans Symbols", "DejaVu Sans", serif;
  font-size: var(--s); color: var(--as-accent);
  translate: 0 -12vh; opacity: 0;
  animation:
    as-sky-fall var(--t) linear var(--d) infinite,
    as-sky-fade var(--t) linear var(--d) infinite,
    as-sky-sway calc(var(--t) / 4) ease-in-out var(--d) infinite alternate;
}
@keyframes as-sky-fall { to { translate: 0 112vh; } }
/* The delays are NEGATIVE, so the field is already mid-fall on the first paint. Without that, a visitor
   arrives at an empty sky and watches it fill for half a minute — the animation would be at its most
   noticeable exactly when the headline is being read. */
@keyframes as-sky-fade { 0%, 100% { opacity: 0; } 14%, 86% { opacity: var(--o); } }
@keyframes as-sky-sway { from { transform: translateX(calc(var(--sw) * -1)); } to { transform: translateX(var(--sw)); } }

/* THE THIRTY-SIX LANES. One line each: horizontal position, size, fall time, head start, peak opacity,
   sway. Nothing here is random at runtime — the GLYPHS are shuffled per request (landing.ts) and the
   choreography is fixed, which is the split that lets this be tuned by eye instead of re-rolled.
   Size, speed and opacity move together on purpose: a bigger glyph is a nearer one, so it falls faster,
   swings wider and sits brighter. Five sizes at four speeds is enough parallax to stop the field
   reading as one flat sheet coming down.

   THE SIZES DOUBLED ON 2026-08-14 (owner), 10-22px to 20-44px. Worth knowing what that did rather than
   just that it happened: a glyph twice as wide covers FOUR times the area, so at an unchanged --o the
   field puts four times the lilac on the page — the ceiling below is now doing four times the work it
   was tuned for, and the light cards are where you will see it first. The sways were left alone; they
   were sized against the lanes, not against the glyphs.

   IT WAS EIGHTEEN UNTIL 2026-08-14 (owner: about twice as much). The second eighteen are lanes 19-36
   below, and they are NOT appended in order: 1-15 march left to right, so continuing that would put the
   whole second half of the field down the left edge of a phone, where only the first twenty lanes
   render. They are interleaved into the gaps of the first eighteen and dealt out of order, which is
   also what keeps the mobile subset spanning the full width. */
.as-sky i:nth-child(1)  { --x:  4%; --s: 32px; --t: 34s; --d:  -3s; --o: .19; --sw: 14px; }
.as-sky i:nth-child(2)  { --x: 11%; --s: 22px; --t: 52s; --d: -22s; --o: .13; --sw:  8px; }
.as-sky i:nth-child(3)  { --x: 18%; --s: 40px; --t: 28s; --d: -14s; --o: .24; --sw: 18px; }
.as-sky i:nth-child(4)  { --x: 26%; --s: 26px; --t: 44s; --d: -37s; --o: .15; --sw: 10px; }
.as-sky i:nth-child(5)  { --x: 33%; --s: 34px; --t: 31s; --d:  -8s; --o: .20; --sw: 15px; }
.as-sky i:nth-child(6)  { --x: 39%; --s: 20px; --t: 57s; --d: -46s; --o: .13; --sw:  7px; }
.as-sky i:nth-child(7)  { --x: 46%; --s: 44px; --t: 26s; --d: -19s; --o: .26; --sw: 20px; }
.as-sky i:nth-child(8)  { --x: 52%; --s: 24px; --t: 48s; --d: -31s; --o: .14; --sw:  9px; }
.as-sky i:nth-child(9)  { --x: 58%; --s: 36px; --t: 33s; --d:  -5s; --o: .21; --sw: 16px; }
.as-sky i:nth-child(10) { --x: 64%; --s: 22px; --t: 55s; --d: -41s; --o: .13; --sw:  8px; }
.as-sky i:nth-child(11) { --x: 71%; --s: 30px; --t: 37s; --d: -26s; --o: .18; --sw: 12px; }
.as-sky i:nth-child(12) { --x: 77%; --s: 42px; --t: 29s; --d: -11s; --o: .25; --sw: 19px; }
.as-sky i:nth-child(13) { --x: 84%; --s: 24px; --t: 50s; --d: -34s; --o: .14; --sw:  9px; }
.as-sky i:nth-child(14) { --x: 90%; --s: 32px; --t: 35s; --d: -17s; --o: .19; --sw: 13px; }
.as-sky i:nth-child(15) { --x: 95%; --s: 20px; --t: 60s; --d: -50s; --o: .13; --sw:  7px; }
/* The last three break the left-to-right march, so the eye stops finding the row. */
.as-sky i:nth-child(16) { --x:  8%; --s: 38px; --t: 30s; --d: -24s; --o: .23; --sw: 17px; }
.as-sky i:nth-child(17) { --x: 30%; --s: 24px; --t: 46s; --d: -12s; --o: .14; --sw:  9px; }
.as-sky i:nth-child(18) { --x: 61%; --s: 28px; --t: 40s; --d: -29s; --o: .17; --sw: 11px; }
.as-sky i:nth-child(19) { --x: 42%; --s: 26px; --t: 43s; --d: -16s; --o: .15; --sw: 10px; }
.as-sky i:nth-child(20) { --x:  6%; --s: 36px; --t: 32s; --d: -28s; --o: .21; --sw: 16px; }
.as-sky i:nth-child(21) { --x: 74%; --s: 22px; --t: 54s; --d:  -9s; --o: .13; --sw:  8px; }
.as-sky i:nth-child(22) { --x: 21%; --s: 32px; --t: 36s; --d: -33s; --o: .19; --sw: 13px; }
.as-sky i:nth-child(23) { --x: 92%; --s: 24px; --t: 47s; --d: -21s; --o: .14; --sw:  9px; }
.as-sky i:nth-child(24) { --x: 36%; --s: 40px; --t: 27s; --d: -13s; --o: .24; --sw: 18px; }
.as-sky i:nth-child(25) { --x: 55%; --s: 20px; --t: 58s; --d: -44s; --o: .13; --sw:  7px; }
.as-sky i:nth-child(26) { --x:  2%; --s: 30px; --t: 38s; --d: -25s; --o: .18; --sw: 12px; }
.as-sky i:nth-child(27) { --x: 87%; --s: 42px; --t: 30s; --d:  -6s; --o: .25; --sw: 19px; }
.as-sky i:nth-child(28) { --x: 29%; --s: 22px; --t: 53s; --d: -39s; --o: .13; --sw:  8px; }
.as-sky i:nth-child(29) { --x: 67%; --s: 34px; --t: 33s; --d: -18s; --o: .20; --sw: 15px; }
.as-sky i:nth-child(30) { --x: 14%; --s: 24px; --t: 49s; --d: -30s; --o: .14; --sw:  9px; }
.as-sky i:nth-child(31) { --x: 97%; --s: 28px; --t: 41s; --d: -10s; --o: .17; --sw: 11px; }
.as-sky i:nth-child(32) { --x: 49%; --s: 38px; --t: 29s; --d: -35s; --o: .23; --sw: 17px; }
.as-sky i:nth-child(33) { --x: 24%; --s: 20px; --t: 59s; --d: -48s; --o: .13; --sw:  7px; }
.as-sky i:nth-child(34) { --x: 80%; --s: 32px; --t: 35s; --d: -23s; --o: .19; --sw: 13px; }
.as-sky i:nth-child(35) { --x: 44%; --s: 24px; --t: 51s; --d: -42s; --o: .14; --sw:  9px; }
.as-sky i:nth-child(36) { --x: 68%; --s: 26px; --t: 45s; --d: -15s; --o: .16; --sw: 10px; }

/* Twenty lanes on a phone, not thirty-six — the same fraction of the field it was thinned to at
   eighteen. A phone is a third of a laptop's width, so the full set on it is not the same weather at a
   smaller size, it is a blizzard; and the smallest screen is also the one paying most for compositing.
   Lanes 1-20 span the full width by construction (see the note on the table above), so what this drops
   is density, never a side of the page. */
@media (max-width: 700px) {
  .as-sky i:nth-child(n+21) { display: none; }
}

/* Motion that nobody asked for and nobody can pause: the one case where "off entirely" is the honest
   answer. Not slowed, not faded — a page-wide drift is exactly what this preference is about, and a
   decoration has nothing to degrade to. */
@media (prefers-reduced-motion: reduce) {
  .as-sky { display: none; }
}

/* ---- the phone: Messages in dark mode ----------------------------------------------------------- */

/* The hero mock is a SCREENSHOT, and its job is to be believable — which is why every value below is
   Apple's rather than ours. A white Messages thread was the single brightest object on a night page and
   the one thing that still looked like the old palette; it also, at a glance, looked like a light-mode
   phone photographed on a dark website. Dark mode is both prettier here and truer: the person this page
   is for has had their phone in dark mode since they got it.
 *
 * NOT recoloured to the brand. A lilac bubble would stop reading as iOS instantly, and the whole value
 * of this component is that it is indistinguishable from a real thread. The one thing that IS ours is
 * the avatar, which astrology.css already swaps everywhere.
 *
 * The green stays #34C759. It is the SMS green — the reason this thread is green and not blue is that
 * Mabel is a phone number, not an iPhone, which is the entire product — and white-on-green is a
 * documented contrast exception this page inherits from the shared component, scoring identically on
 * the reminder homepage. Apple ships it; changing it would fix a number and break the illusion. */
.mk-screen-thread { background: #000; }
.fk-thread .cap-demo-view { background: #000; }
.fk-thread-bar { background: #1C1C1E; border-bottom-color: #38383A; }
.fk-thread-id .mk-ava { border-color: #38383A; }
.fk-thread-name { color: #FFFFFF; }
.fk-thread-name span { color: #8E8E93; }
.fk-thread .md-ts { color: #8E8E93; }
.fk-thread .md-ts b { color: #D1D1D6; }
.fk-thread .md-bubble--in { background: #26252A; color: #FFFFFF; }
.fk-thread .md-typing { background: #26252A; }

/* THE SCREEN IS SHORTER THAN THE SHARED ONE, because this conversation is shorter. The 468px desktop
   height is tuned to the reminder homepage's twenty-message script, which is long enough that the frame
   is always overfull. This thread is seven messages, and the four it lands on measure 285px — so at 468
   the visitor arrives at a phone that is 39% empty sky, which reads as a conversation that has not
   started rather than one already going. 400 leaves the ~100px a real thread has above its first bubble
   and keeps the bezel tall enough to read as a phone; below 380 it starts to read as a widget, which is
   what the shared comment on this rule warns about. Measured, at both the seeded state and the finished
   one. Mobile is untouched — the 330px screen already overflows, and messages scrolling off the top is
   what a real thread does. */
@media (min-width: 900px) { .fk-thread .mk-hero-thread-view { height: 400px; } }

/* ---- signup band ------------------------------------------------------------------------------ */

/* The card itself is untouched — same markup, same warm surface, same click-wrap paragraph. Only the
   copy AROUND it, which sits on the dark surface, needs different ink. */
.mk-signup-sub { color: var(--as-ink-quiet); }
.mk-tb-item span { color: var(--as-ink-muted); }
.mk-tb-icon { stroke: var(--as-accent); }

/* ---- section headings ------------------------------------------------------------------------- */

/* .mk-calls-h is the serif heading every section opens with, and it is --maroon: correct on parchment,
   invisible on #17122F. Every section on this page is on that surface, so it simply flips. Same for
   .mk-calls-sub, and for the eyebrow below. */
.mk-calls-h { color: var(--as-ink-hi); }
.mk-calls-sub { color: var(--as-ink-body); }
.mk-eyebrow { color: var(--as-accent); }

/* ---- rotating examples ------------------------------------------------------------------------ */

/* THE STRIP WEARS THE SIGNUP CARD'S SURFACE. It sits directly under that card and these lines are the
   answer to the question its empty field provokes — what do I even say to her — so they belong to it
   rather than to the dark page they cross. It was a slightly-lifted violet for a day, which read as a
   divider closing the signup section off instead of as its second half.
   No hairline: at #FFFAFD on a #17122F page the band separates itself, and the rule that was doing that
   job is now the thing drawing a line through the middle of one idea. Ink is --maroon, the plum this
   flavor uses INSIDE its light cards — the same ink the signup card's own label is set in, which is the
   whole point of borrowing the surface. */
.mk-ex-band { background: var(--white); border-block: 0; }
.mk-ex-line span { color: var(--maroon); }

/* ---- section rhythm ---------------------------------------------------------------------------- */

/* With no surface change left to mark them, each new subject opens on a hairline. Without this the
   page below the hero is one unbroken slab and the eye stops finding the beats. (It used to list
   `.as-signs` first; that section was deleted 2026-08-14 and the `.as-*` rules went with it — the
   whole point of a flavor's markup living in its own namespace is that deleting it is this easy.) */
#why, #pricing { border-top: 1px solid var(--as-hairline); }

/* ---- pricing ----------------------------------------------------------------------------------- */

/* The tab rail on the dark surface: the shared rule fills it with --cream, which is parchment here and
   would float a light bar with no card under it. */
.mk-pp-tabs { background: var(--as-glass); border-color: rgba(190,170,255,.25); }
.mk-pp-tab { color: var(--as-ink-muted); }
.mk-pp-tab:hover { color: var(--as-ink-hi); }
.mk-pp-r:nth-of-type(1):focus-visible ~ .mk-pp-tabs .mk-pp-tab:nth-child(1),
.mk-pp-r:nth-of-type(2):focus-visible ~ .mk-pp-tabs .mk-pp-tab:nth-child(2),
.mk-pp-r:nth-of-type(3):focus-visible ~ .mk-pp-tabs .mk-pp-tab:nth-child(3) { outline-color: var(--as-accent); }
.mk-price-note { text-align: center; font-size: 12.5px; color: var(--as-ink-quiet); margin: 16px 0 0; }

/* ---- the signed-in pages: /welcome, /account, /checkout ----------------------------------------- */

/*
 * THE FUNNEL DOES NOT CHANGE COLOUR HALFWAY THROUGH. These are the screens a visitor sees after the
 * landing page — the consent gate that asks to text them, the account page, the plan picker the cap
 * message links to — and a product that is violet up to the phone field and salmon immediately after
 * it reads as two companies, or as one that has been spoofed. That is a trust problem, not a taste one,
 * and it lands at the exact moment we are asking for a phone number.
 *
 * Most of it comes free: the tokens are injected into this layout now, so cards, buttons, ink inside
 * cards and the CTA are already right. What is left is the same two-jobs problem as the landing page —
 * shared ink that lands on the PAGE surface rather than inside a card — plus the app shell's own fill.
 */
/* The shell paints --cream, which on this palette is a LIGHT lavender: correct as a card surface,
   wrong as the ground everything sits on. */
body.mk-app { background: var(--nude); }

/* ONLY WHAT SITS ON THE PAGE ITSELF. Everything else on these screens lives inside a .mk-form-card,
   which the tokens already made a light card with plum ink — and the first cut of this block got that
   wrong, lightening `.mk-acc-note` into 1.78:1 white-on-white inside the card that explains why we
   cannot text you yet. The two-jobs problem from the top of this file, met again three hundred lines
   later: the fix is a scope, not a colour. If you add a rule here, check first whether the element is
   inside a card. */
.mk-app-header .mk-wordmark { color: var(--as-ink-wordmark); }
.mk-back { color: var(--as-ink-muted); }
.mk-back:hover { color: var(--as-ink-hi); }
.mk-acc-h { color: var(--as-ink-hi); }
.mk-acc-sub, .mk-trial-lead { color: var(--as-ink-body); }
/* The welcome gate's two emphasised lines — "Your phone's about to buzz." and Mabel's number — are
   --deep, which is a CARD ink: 1.08:1 here, i.e. invisible. They are the two most important strings on
   the page a user reads immediately before consenting to be texted. */
.wg-hero .mk-acc-sub strong, .wg-hero .mk-acc-sub b { color: var(--as-ink-hi); }
.mk-foot-note { color: var(--as-ink-muted); }
.mk-acc-actions .mk-textbtn { color: var(--as-ink-muted); }
.mk-acc-actions .mk-textbtn:hover { color: var(--as-ink-hi); }
/* The consent chips are white on --salmon, and blush is much lighter than the reminder salmon they
   were picked against: 2.13:1. Same swap the CTA already makes — the dark ink that belongs on blush. */
.mk-consent-tag { color: var(--on-salmon); }
/* The A2P pill in the app header is the same white chip as the marketing one, for the same reason:
   a credential wears no palette. `.mk-pill` is filled from --cream here, which is nearly white on this
   palette but not white, so it is set outright. */
.mk-app-pill, .mk-pill { background: #FFFFFF; border-color: #FFFFFF; color: #1E1D1C; }

/* ---- legal + footer ---------------------------------------------------------------------------- */

.mk-legal { color: #8B83A8; }
.mk-legal strong { color: #C3BADF; }
.mk-legal a { color: var(--as-accent); }
.mk-footer .mk-wordmark { color: #9990B6; }

/* ---- the button --------------------------------------------------------------------------------- */

/* There is one blush object per screen and this is it, so it gets the only glow on the page — a soft
   halo in its own colour, which is what separates a button that was chosen from a rectangle that was
   filled. Both buttons that matter (Send code, Sign up) sit inside a near-white card, so the halo has
   somewhere to land; on the dark surface it would disappear. */
.mk-btn-primary {
  box-shadow: 0 8px 22px rgba(255,143,180,.34);
  transition: background .16s ease, box-shadow .16s ease, transform .16s ease;
}
.mk-btn-primary:hover { background: #FF7AA6; box-shadow: 0 10px 26px rgba(255,143,180,.44); }
.mk-btn-primary:active { transform: translateY(1px); box-shadow: 0 5px 14px rgba(255,143,180,.30); }
.mk-btn-primary[aria-busy="true"] { box-shadow: none; }
@media (prefers-reduced-motion: reduce) { .mk-btn-primary { transition: none; } .mk-btn-primary:active { transform: none; } }

/* ---- links, focus ------------------------------------------------------------------------------ */

/* The content pages (this vertical's compliance disclosure) run the shared prose styles, and every one
   of them is a CARD ink landing on the page's own surface: body copy came out at 2.2:1 and <strong> at
   --deep was invisible outright — which on a compliance page hides exactly the sentences that were
   bolded because they matter most ("Replying STOP stops everything from this number"). Found by
   computing WCAG ratios against the real rendered background, not by looking at it: at 2.2:1 this copy
   still reads as "a bit dim" to someone with good eyesight on a good monitor. The ink tokens have since
   moved from brown to plum and these overrides are still what saves this page — the tokens changed, the
   two-jobs problem did not. */
/* THE CONTAINER, not only the elements listed inside it. The line below was written when every content
   page was paragraphs and list items. The chart, share and compare pages then arrived with TABLES and a
   text INPUT, which match none of those selectors, inherit from `body` — i.e. --body, the ink for the
   LIGHT cards — and landed on the violet surface at 2.3:1, with the chart's house column, dimmed to
   .65, at 1.6:1. That is the placements table: the actual content of the page Mabel texts you.
   Setting the INHERITED colour means the next element someone adds to one of these pages is legible
   because of where it is, not because a selector list was remembered. */
.mk-page-body { color: var(--as-ink-body); }
.mk-page-body p, .mk-page-body li, .mk-page-body em, .mk-page-body address { color: var(--as-ink-body); }
.mk-page-body strong { color: var(--as-ink-hi); }
.mk-page-body .muted { color: var(--as-ink-quiet); }
.mk-page-body a { color: var(--as-accent); }
.mk-page-body a:hover { color: var(--as-accent-hover); }
.mk-page-body h1, .mk-page-body h2, .mk-page-title { color: var(--as-ink-hi); }
.mk-page-body .mk-eyebrow { color: var(--as-accent); }
/* A BUTTON IS AN <a>, AND THE LINE ABOVE WAS BEATING IT.
   `.mk-page-body a` is (0,1,1); `.mk-btn-primary`, which sets `color: var(--on-salmon)` against its own
   salmon background, is (0,1,0). So every primary button on a content page had its label repainted the
   LINK colour and came out lilac #C6B2FF on blush #FF8FB4: 1.14:1, which is not "a bit dim", it is a
   button with no legible text on it. The chart page is where it showed, because that page is now two
   buttons and almost nothing else.
   Restated at the same specificity as the rule that broke it, and both variants, so this cannot be half
   fixed: on-salmon lands at 7.58:1 and the secondary's cream at 12.7:1. :hover too — the hover rule is
   (0,2,1) and would otherwise put the lilac straight back the moment a mouse touched it. */
.mk-page-body .mk-btn-primary, .mk-page-body .mk-btn-primary:hover { color: var(--on-salmon); }
.mk-page-body .mk-btn-secondary, .mk-page-body .mk-btn-secondary:hover { color: #F6E9DF; }
/* The shared focus ring is maroon, which disappears against #17122F. Buttons and inputs that sit inside
   the light cards keep it; anything on the dark surface gets the accent. */
.mk-btn:focus-visible, .mk-navlink:focus-visible, .mk-nav-compliance:focus-visible,
.mk-nav-desktop a:focus-visible, .mk-footer-login:focus-visible { outline-color: var(--as-accent); }

/* ---- measured contrast corrections --------------------------------------------------------------
 *
 * Four values that a designer's eye passes and a contrast meter does not, all of them caused by this
 * page's surfaces being a shade different from the ones the shared tokens were picked against. The
 * price card is #F8F4EC where the reminder card is pure white, which is enough to drop "/ month" from
 * just-passing to just-failing. This is the class of defect nobody notices until somebody with poor
 * vision cannot read the price, so it was measured rather than judged.
 *
 * TWO remain below 4.5:1 on this page and both are deliberate: the outgoing SMS bubble (white on
 * #34C759) and the "+1" field prefix. Both are shared components and score identically on the reminder
 * homepage. The green is Apple's, in a mock whose entire value is being indistinguishable from a real
 * thread — and it is GREEN rather than blue because Mabel is a phone number and not an iPhone, which is
 * the product. Fixing that number would break the illusion it exists to sell.
 *
 * It used to be four. Putting the phone in dark mode fixed the other two for free — the timestamp and
 * the back chevron were mid-greys chosen against white, and they clear the threshold comfortably on
 * black. Worth noting because it is the direction these things usually go: a change made for looks that
 * happens to take two items off the list.
 */
.mk-price-amt .per { color: var(--body2); }
