/* Bustan — MIORA's design system. Tokens and atoms, shared by every surface.
 *
 * **An atom used by two surfaces lives here.** `portal.css` is layouts and
 * instruments, never a card. The dining rail broke this rule and shipped every
 * diner page unstyled while a byte-budget test stayed green — bytes were never
 * what it measured.
 *
 * **Logical direction only.** No `left`, no `right`, in any token name,
 * component name, or property. `tools/design_lint.py` fails the build on one.
 * The reason is mechanical: the Ribbon is a horizontal pager with a 14px peek
 * and direction is its whole mechanism, Week-Dots carry a today-underline and a
 * reading order, and the Ticket sets numerals beside a state seal. Retrofitting
 * direction into those costs the design system rather than an afternoon.
 *
 * **The anti-coupon law is structural, not a guideline.** There is no badge
 * atom, no starburst, and no red that is not an error. In this segment visible
 * discounting reads as decline, so her rate is quiet fir text and nothing on
 * any surface shouts about it.
 *
 * **The strikethrough clause was lifted on 2026-08-30, deliberately.** It read
 * "no strikethrough" from the first draft, and the reasoning was sound for the
 * thing it was aimed at: a struck price is the grammar of a sale, and a sale
 * is what this product is not. The frozen rebuild strikes the salon's price
 * anyway, and looking at both pages side by side settles why. Two bare figures
 * on one line state no relation — a reader meeting `120  96` has to work out
 * which is which, and the quiet grey of the first is not an answer. The rule
 * through it says *this is the price, and it is not the one you pay* in a mark
 * every reader already knows. The rest of the law does the work the clause was
 * carrying: no badge announces it, no percentage is set larger than the price,
 * no colour changes, and the mark appears **once**, on the salon's own figure,
 * beside hers. Struck once and quietly is a statement of fact; struck under a
 * starburst is a coupon, and that is still banned.
 *
 * **And the salon page put the mark down again on 2026-09-14.** The founder's
 * redesign guide read the struck price on every line of a full menu as the
 * deals-page tell it had been argued not to be, and answered the *"120 96"*
 * problem another way: two aligned columns under two heads — *Salon*,
 * *Member* — so the relation is stated by the column rather than by a rule
 * through a figure. The clause stays lifted where the mark is one and quiet
 * (the collection's pills); on the list it is a rate card, not a sale.
 *
 * **A spent gift is struck too** (F222, the founder's C1 frames, 14 Oct
 * 2026): the figure on a used or ended gift card, on a grey card with no
 * figure beside it. It says *spent*, the way a used ticket is punched; it is
 * not a price and nothing reads as the new one.
 */

/* ============================================================ 1 · tokens */

:root {
  /* Native controls — the date picker, the select's own menu, a scrollbar —
     follow the page rather than the platform default. Without it a
     `datetime-local` on a dark salon page renders as a white slab with a black
     calendar glyph, which is what looking at the page found. Set beside the
     tokens rather than in the dark block, because it has to change with them. */
  color-scheme: light;
  /* Ground and paper. Ivory rather than white: white is a screen, ivory is a
     room. The card sits a half-step above the page, never on a shadow that
     reads as a popup. */
  /* **Paper, not white.** #FFFDF6 read as an unpainted default; the garden's
     ivory is warmer and reads as a page. `--raised` is the darkest ground any
     text is ever set on, which is why every ink below is measured against it
     rather than against the card. */
  --ground: #FBF8F1;
  /* **Not white.** Concierge's card is #FFFEFA — a hair off, and the hair is
     the point: a white card on ivory paper reads as a window cut in the page,
     and the whole system's first note says white is a screen and ivory is a
     room. Every ink measured on it is unmoved at this distance. */
  --card: #FFFEFA;
  --raised: #EFE4CC;
  /* The ground a price pill sits on: between the paper and the sand, so three
     of them in a row read as one object with three compartments rather than
     as three cards. */
  --pill: #F6F2E8;
  --line: #E6DFCE;
  --rule: #E6DEC8;
  /* The mist behind her column on a price list (the founder's v13, 15 Sep
     2026): a panel from the head to the last row, a shade off the ground
     and a shade under the line, so the column reads as one object. The app
     reads the same token. */
  --band: #ECEBE6;
  /* **F210 · the menu's band tints** (UX's tints.json, the founder's "Yes, the
     full set", 13 Oct 2026): one per canon category, `own` for the salon's own. */
  --tint-hair: #F4E4D8;
  --tint-nails: #E4EADF;
  --tint-skin: #F5EDDC;
  --tint-wax-threading: #EEE7DB;
  --tint-lashes-brows: #E9E6EE;
  --tint-massage: #E2E9E6;
  --tint-hammam: #E1E9EC;
  --tint-makeup: #F5E2DE;
  --tint-henna: #F2E5D4;
  --tint-bridal: #F6F0E8;
  --tint-kids: #F1ECD6;
  --tint-own: #ECECE5;

  /* Ink. Fir is the one action colour app-wide — a salon's own identity kit
     dresses its pane, but the Request button is fir everywhere, because an
     action that changes colour per salon is an action she has to re-learn. */
  --ink: #1F2822;
  /* **Titles and body are two inks now.** The handover separates them —
     `#1F2822` for a Cormorant title, `#2B342D` for the sentence under it — and
     the system had one `--ink` doing both, so a serif heading and the
     paragraph beneath it sat at exactly the same weight. Both clear the floor
     on every ground by a wide margin (12:1 and above); this is a distinction
     about hierarchy rather than about legibility. */
  --text: #2B342D;
  --fir: #2F4A38;
  --fir-deep: #24382B;
  --on-fir: #FBF8F1;
  /* Darkened from the mockups' #8C9383 and #A9A28C, deliberately.
     Those values measure 3.17:1 and 2.55:1 against white — the second fails
     even WCAG's 3:1 large-text floor, and both carry body-size text: 13px row
     labels, 12px captions, the 9px tracked section headers, and the empty
     state's reason line. Nothing here is decorative.
     These clear 4.5:1 against the darkest ground they are ever set on
     (--raised). The system loses a little of the mockups' airiness and gains
     a section header a woman can read in a bright salon, which is the trade
     the design law already names: money is serious, legibility first. */
  /* **The garden's greys, darkened until they hold.** The mockups set these
     at #7E8478 and its lighter kin — 3.09:1 on `--raised`, which is below the
     3:1 large-text floor and these carry 12.5px body. Darkened 21% until they
     clear 4.5:1 on the darkest ground they are set on. Same trade the greys
     already record: a little of the mockups' airiness, for a caption a woman
     can read in a bright salon. */
  --sub: #5E665F;
  /* **The posted price, set aside.** A token now because two surfaces and
     three components hold this figure and a literal in each is three chances
     to disagree.

     **At the floor, not under it** (the founder's AA ruling, 5 Oct 2026: no
     serious axe finding, AA contrast in both themes). It was #8E9187 — 3.17:1
     on the card, 3.93:1 in the dark — on the argument that a struck figure
     beside a 19px price need not be read. The ruling overrides that argument:
     a price is text, and it is read. It wears `--faint`'s values, so the
     strike and the quieter grey still set it under the figure she pays. */
  --struck: #6A665B;
  /* **Darkened 3% against a darker ground, not against a mockup.** Concierge
     moves `--raised` from #EFE6CE to #EFE4CC — two points of luminance — and
     `--faint` measured 4.28:1 on the new value, under the floor it cleared on
     the old one. A token that passes on the ground it was measured against and
     fails on the ground it is actually set on is the same fault as an
     eyeballed one. 4.54:1 on sand, 4.67:1 on blush.

     Concierge names a single secondary ink (`sub`), so this tier is a
     candidate for retirement when the type comes over — until then it is a
     real tier in a hundred templates and it has to hold. */
  --faint: #6A665B;

  /* Accents, and each has exactly one job.
     Rose is generosity — gifts and credits, never a warning.
     Peach is access — open windows and quiet hours.
     Brass is the Rate Seal and nothing else. */
  --rose: #AB4457;
  --rose-soft: #E491A0;
  --rose-wash: #F7E3E7;
  --rose-line: #F3CBD5;
  /* Peach carries one thing — the Pulse pane's 7.5px tracked kind label — and
     the mockup value measures **2.28:1**, which is not legible at any size and
     is a caption at that one. `--peach-wash` and `--peach-line` are grounds and
     keep the mockups' own values; this is the ink. */
  /* The composer's total card (frame 11-01): a sage wash and its line. */
  --sage-wash: #F7F9F5;
  --sage-line: #DFE7DA;
  /* **R9 A2** (the founder's pick, 18 Oct 2026): the ground of a fact the
     salon stated of its room, *Ladies only*, its words in fir. A fact, not
     an offer: no money, no rate, never red. */
  --sage-pill: #E4EDE2;
  --peach: #985533;
  --peach-wash: #FDF1E8;
  --peach-line: #F4DFCB;
  /* **Measured, not eyeballed — the same trade §1 records for the greys.**
     The mockups' brass and fir measure 3.94:1 and 4.31:1 against `--raised`,
     the darkest ground either is set on, and both carry body-size text: the
     seal, the paid tick, the today mark. Darkened until they clear 4.5:1.
     The dark twin's own values are re-measured in its block. */
  --brass: #7C6336;
  --brass-soft: #C98E43;

  /* States. `--amber` is waiting, not warning; `--alert` is the only red on
     any surface and never touches money. */
  --good: #456E4E;
  --amber: #93866F;
  --alert: #A6432F;

  /* Type. Each face with one job — see tools/fetch_fonts.py.

     **Instrument Sans replaced Karla, and the figures are the reason.** Karla
     sets proportional oldstyle by default, so a page of times and dates read
     `30` as `3O` and `31` as `3I` — on the one surface where every number is
     functional. Every figure that means something is now tabular lining, set
     once in `.num` rather than remembered per component.

     **DM Mono is struck from the member rail.** Money in a monospace read as
     code rather than as currency; her price is Cormorant, and the console
     keeps DM Mono where a column of figures must align.

     **Italic Cormorant is retired as a page-title style.** It was on every
     screen and read bridal; display is roman 600 now, and italic survives
     only as a deliberate accent. */
  /* **The garden's own inks.** Ornament is drawn from these and never from
     literals, so a theme change moves the flowers with the type. `--sage` is
     the growing green the week and the vine share; the two gold leaves are the
     crest and the bloom; `--ring` and `--petal` are the rosette's. */
  --sage: #5F7355;
  --sage-pale: #8CA07E;
  --gold-leaf: #C7AE68;
  --gold-leaf-2: #D9C48A;
  --ring: #D8C49E;
  --petal: #E3D0AE;
  /* F224 S3, the thin ring: its line, ivory fill and figure (the app's
     palette gate checks this light set). */
  --seal-line: #C7AE68;
  --seal-fill: #FFFDF7;
  --seal-ink: #7C6336;
  --petal-rose: #F3C3CE;
  /* The pane's paint. Warmer and more saturated than the line work, because
     paint is what it is — and named here so the one painted surface in the
     system still answers to the theme. */
  --pane-ground: #FFFBF0;
  --sage-leaf: #A7BC97;
  --bloom-rose: #EFA9B6;
  --bloom-rose-deep: #C9647A;
  --bloom-peach: #F6C8AE;
  --bloom-peach-deep: #DE9A73;
  --rose-deep: #DA9AA9;
  --display: 'Cormorant Garamond', 'Amiri', Georgia, serif;
  --ui: 'Instrument Sans', 'IBM Plex Sans Arabic', system-ui, -apple-system, sans-serif;
  /* **The member rail's figures are the UI face, set tabular and lining.**
     They were DM Mono, and money in a monospace reads as code rather than as
     currency — her price is the one number on the page that should feel like
     a price. The console keeps `--figure-mono`, where a dense column of
     amounts genuinely needs the glyphs to align. */
  --figure: 'Instrument Sans', system-ui, -apple-system, sans-serif;
  --figure-mono: 'DM Mono', ui-monospace, SFMono-Regular, monospace;
  --hero: 'Fraunces', 'Cormorant Garamond', Georgia, serif;
  --wordmark: 'Aref Ruqaa', 'Amiri', serif;
  --arabic: 'IBM Plex Sans Arabic', 'Amiri', 'Aref Ruqaa', sans-serif;
  /* **A display Arabic, for the one place Arabic is a name rather than text.**
     Plex Arabic is the reading face and is right for a price list; a salon's
     own name set in it is a label. Aref Ruqaa is a Ruqʿah display face and was
     already self-hosted and unused — an undefined `var()` here would have
     silently fallen back to the reading face and nobody could have told. */
  --arabic-display: 'Aref Ruqaa', 'Amiri', var(--arabic);

  /* **The scale, named once — and measured against the faces, not the em.**
     Five tiers on a phone: tag 11 · caption 13.5 · body 16 · section 26 ·
     title 38. The Concierge frames set body 14.5 / caption 12.5 / tags 9.5–10
     and section heads at Cormorant 19, and the first people to hold the app
     said the text was small and the headings could not be told from the
     details. Both were true, and the second had one cause: Cormorant
     Garamond's x-height is 0.386 em and Instrument Sans's is 0.510 em, so a
     Cormorant 19 heading (x-height 7.3px) sat *optically smaller* than the
     Instrument 14.5 row under it (7.4px) — only the serif said which was the
     heading.

     The rules, so nobody re-makes the mistake: a Cormorant size is an
     Instrument size × 1.32 for equal optical size; a heading must carry at
     least 1.25× the x-height of the line beneath it; nothing readable sits
     under 11px, and a control's text is never smaller than 15. The tiers
     below are the Latin ones; Arabic reads one step larger for the same
     legibility, so `[lang='ar']` takes 17 where Latin takes 16. */
  --t-caption: 13.5px;
  --t-body: 16px;
  --t-lede: 21px;
  --t-title: 26px;
  --t-display: 42px;

  --radius-card: 18px;
  --radius-sheet: 22px;
  --radius-btn: 12px;
  --radius-chip: 999px;

  --step: 4px;
  --gutter: 20px;

  /* The one place a physical direction is named, and it is named once.
     `linear-gradient()` has no reliable logical keyword — CSS Images 4 defines
     one and browsers do not agree on it — so the direction becomes a token that
     flips with the document, and every component reads the token. A component
     that spelled the side itself would be a component that stops mirroring. */
  --flow-end: to right;

  /* One shadow, used sparingly. A system with five shadows has none. */
  --lift: 0 12px 26px -16px rgb(51 64 47 / 0.22);

  /* **F219 · the circles on the salon's picture** (UX's hand-off, 14 Oct
     2026): near-white over the photograph, the circles' own shadow, and an
     icon that stays dark on them in either theme. */
  --float: rgb(255 254 250 / 0.94);
  --float-shadow: 0 2px 8px rgb(31 40 34 / 0.22);
  --on-float: #1F2822;
  /* F219: the app's soft shadow under the chips while they are stuck. */
  --stuck-shadow: 0 6px 10px rgb(31 40 34 / 0.18);
}

/* **C0, "a touch of cream"** (the founder's pick, 14 Oct 2026 ~12:25), with
   AFTER_APPLE on: `base.html` sets `.c0` on every member page; the desk, the
   console, meet and e-sign opt out. The page a touch lighter, the cards,
   chips, search and location box pure white, a softer line round each, and
   no shadow under a card. Light only: the dark twins below come later and
   keep their own values. */
:root.c0 {
  --ground: #FCFAF6;
  --card: #FFFFFF;
  --line: #ECE6D9;
  --lift: none;
  /* **U1, one face for money** (the founder's 1A, 18 Oct 2026): every
     price in the figure face, bold. Each price rule reads these two tokens
     and keeps its own face and weight while they are unset. */
  --price-face: var(--figure);
  --price-weight: 700;
}

/* The dark twin. Bustan at dusk rather than an inversion: the garden keeps its
   fir and its rose, and the ivory becomes the deep shade under a tree. */
:root:dir(rtl) {
  --flow-end: to left;
}

:root:not([data-theme='light']) {
  @media (prefers-color-scheme: dark) {
    color-scheme: dark;
    --ground: #16150F;
    --card: #1E1D16;
    --raised: #262419;
    --line: #33301F;
    --rule: #3B3726;
    --band: #23211A;
    --tint-hair: #281E13;
    --tint-nails: #1F2216;
    --tint-skin: #272112;
    --tint-wax-threading: #261F13;
    --tint-lashes-brows: #221F20;
    --tint-massage: #1D211C;
    --tint-hammam: #1D2120;
    --tint-makeup: #281D17;
    --tint-henna: #261F11;
    --tint-bridal: #272219;
    --tint-kids: #252112;
    --tint-own: #232119;
    --ink: #EDE7DA;
    /* The light block's twin. Without it `--text` keeps its light value and
       every sentence under a title goes #2B342D on a #16150F ground. */
    --text: #DDD6C7;
    --fir: #7C9E86;
    --fir-deep: #6B8D75;
    --on-fir: #12140F;
    --sub: #9AA58F;
    --faint: #8F8A7A;
    /* A pill at dusk is a compartment cut into the card, not a lamp. */
    --pill: #232116;
    --struck: #8F8A7A;
    /* The garden at night: the same plants, grown in less light. Every one is
       darkened rather than inverted — a bloom that gets brighter when the room
       does not is a light source, and none of these is one. */
    --sage: #7C9070;
    --sage-pale: #5E7053;
    --gold-leaf: #7C6A3E;
    --gold-leaf-2: #8E7A4A;
    --ring: #4B4230;
    --petal: #5A4E38;
    --seal-line: #7C6A3E;
    --seal-fill: #1E1D16;
    --seal-ink: #C9A96A;
    --petal-rose: #5C3A42;
    --pane-ground: #1B1A13;
    --sage-leaf: #536046;
    --bloom-rose: #6E4048;
    --bloom-rose-deep: #93555F;
    --bloom-peach: #6B4A38;
    --bloom-peach-deep: #96694A;
    --rose-deep: #7A4E58;
    --rose-wash: #2A1A1E;
    --rose-line: #47262D;
    --peach-wash: #2A2018;
    --peach-line: #45341F;
    /* **The accents, re-measured against this ground.** Every one of these was
       inherited from the light palette and never checked here — and three of
       them failed: rose measures 2.98:1 on `--raised` (below even the 3:1
       large-text floor) and carries the gift line; brass 3.44:1 and carries
       today's mark; fir-as-good 1.86:1, which is a tick nobody can see. Lifted
       to clear 4.5:1 on the darkest ground each is set on, the same trade §1
       documents for the mockup greys: a little of the palette's depth for a
       figure a woman can read in bed at eleven at night, which is when this
       product is used.
  
       Each keeps its one job: rose is generosity, peach is access, brass is the
       seal. */
    --rose: #E491A0;
      --peach: #E5AE8C;
    --sage-wash: #1C221B;
    --sage-line: #2E3A2D;
    --sage-pill: #263125;
    --brass: #C9A96A;
    --brass-soft: #DCB878;
    --good: #7C9E86;
    /* Dark's own red and amber (E2E-0185, UX 6 Oct 2026): light's read 2.78:1 on dark. */
    --alert: #D9765F;
    --amber: #A39680;
  }
}

:root[data-theme='dark'] {
  color-scheme: dark;
  --ground: #16150F;
  --card: #1E1D16;
  --raised: #262419;
  --line: #33301F;
  --rule: #3B3726;
  --band: #23211A;
  --tint-hair: #281E13;
  --tint-nails: #1F2216;
  --tint-skin: #272112;
  --tint-wax-threading: #261F13;
  --tint-lashes-brows: #221F20;
  --tint-massage: #1D211C;
  --tint-hammam: #1D2120;
  --tint-makeup: #281D17;
  --tint-henna: #261F11;
  --tint-bridal: #272219;
  --tint-kids: #252112;
  --tint-own: #232119;
  --ink: #EDE7DA;
  --text: #DDD6C7;
  --fir: #7C9E86;
  --fir-deep: #6B8D75;
  --on-fir: #12140F;
  --sub: #9AA58F;
  --faint: #8F8A7A;
  --pill: #232116;
  --struck: #8F8A7A;
  --sage: #7C9070;
  --sage-pale: #5E7053;
  --gold-leaf: #7C6A3E;
  --gold-leaf-2: #8E7A4A;
  --ring: #4B4230;
  --petal: #5A4E38;
  --seal-line: #7C6A3E;
  --seal-fill: #1E1D16;
  --seal-ink: #C9A96A;
  --petal-rose: #5C3A42;
  --pane-ground: #1B1A13;
  --sage-leaf: #536046;
  --bloom-rose: #6E4048;
  --bloom-rose-deep: #93555F;
  --bloom-peach: #6B4A38;
  --bloom-peach-deep: #96694A;
  --rose-deep: #7A4E58;
  --rose-wash: #2A1A1E;
  --rose-line: #47262D;
  --peach-wash: #2A2018;
  --peach-line: #45341F;

  /* **The accents, re-measured against this ground.** Every one of these was
     inherited from the light palette and never checked here — and three of
     them failed: rose measures 2.98:1 on `--raised` (below even the 3:1
     large-text floor) and carries the gift line; brass 3.44:1 and carries
     today's mark; fir-as-good 1.86:1, which is a tick nobody can see. Lifted
     to clear 4.5:1 on the darkest ground each is set on, the same trade §1
     documents for the mockup greys: a little of the palette's depth for a
     figure a woman can read in bed at eleven at night, which is when this
     product is used.

     Each keeps its one job: rose is generosity, peach is access, brass is the
     seal. */
  --rose: #E491A0;
  --peach: #E5AE8C;
  --sage-wash: #1C221B;
  --sage-line: #2E3A2D;
  --sage-pill: #263125;
  --brass: #C9A96A;
  --brass-soft: #DCB878;
  --good: #7C9E86;
  --alert: #D9765F;
  --amber: #A39680;
}

/* ============================================================ 2 · ground */

*,
*::before,
*::after {
  box-sizing: border-box;
}

/* **Hidden means hidden, everywhere** (UX audit F56, 25 Sep 2026). An atom's
   own `display` outranks the browser's `[hidden]`, so an element marked
   hidden was drawn anyway — an empty card under the salon's hours (G-402),
   the split bar's length after its finish arrived (F52), a ✓ beside every
   bill line the script had put away (F56). Fixed once, for every element. */
[hidden]:not([hidden="until-found" i]) {
  display: none !important;
}

body {
  margin: 0;
  background: var(--ground);
  position: relative;
  isolation: isolate;
  /* **The sentence ink, not the title ink.** Concierge separates them and the
     page inherits the one it is mostly made of; a Cormorant heading asks for
     `--ink` where it is set. Body copy at #1F2822 was every paragraph carrying
     a title's weight. */
  color: var(--text);
  font-family: var(--ui);
  /* **The rail was a phone layout at a desktop viewport**, and everything on
     it was one size too large for the room it was in. The scale is named in
     the token block; this is its base. */
  font-size: var(--t-body);
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
}

/* **Paper grain — ivory should read as paper, not as a screen.** The
   consolidated mockup multiplies a still SVG turbulence over the ground at
   half opacity; the same noise, fixed, painted *behind* the content — the
   mockup lets it touch the cards too, but a texture over 12.5px captions is
   a texture the contrast budget never agreed to. Deterministic pixels, so
   the look gate's goldens stay byte-stable.

   **45%, which the handover states and the frames render at 50%.** The token
   block wins over a frame where they disagree, and the paper is a shade
   lighter now — the same noise over #FBF8F1 reads heavier than it did over
   #FDFBF4, so the number moving down is the texture staying where it was. */
body::before {
  content: '';
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  opacity: 0.45;
  mix-blend-mode: multiply;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='160' height='160'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3'/><feColorMatrix type='saturate' values='0'/></filter><rect width='160' height='160' filter='url(%23n)' opacity='.22'/></svg>");
}

/* At dusk the same grain would only mud the shade — multiply over a near-black
   ground is invisible at best and a smear at worst, so the paper texture is a
   daylight fact. */
:root:not([data-theme='light']) {
  @media (prefers-color-scheme: dark) {
    body::before { content: none; }
  }
}

:root[data-theme='dark'] body::before { content: none; }

/* Arabic sets in Amiri and reads a size larger — the script's x-height is
   smaller at the same point size, and matching the Latin number would leave it
   looking timid beside it. */
:root[lang='ar'] body,
[lang='ar'] {
  font-family: var(--arabic);
  font-size: 17px;
  line-height: 1.75;
}

/* An Arabic block takes the width of its own words, never a sibling's.
 *
 * `dir="rtl"` sets where the run *starts*, and on a block that means the box's
 * end edge. The salon page stacks the Latin name, the Arabic name and the area
 * inside one shrink-wrapped column, so the box was sized by `Layali Al Reem`
 * and `ليالي الريم` hugged the far side of it — aligned with neither the name
 * above it nor the area below, floating in the middle of the page on the one
 * screen that is the salon's own.
 *
 * `fit-content` is the whole fix and it is safe on long text: it resolves to
 * the available width once the words no longer fit on a line, so a paragraph
 * still wraps. Not on `input`, which owns its box already.
 */
p[lang='ar'],
div[lang='ar'] {
  width: fit-content;
}

/* Every figure is tabular, and **every figure is a bidi island**.
 *
 * The tabular part is ordinary: a column of money that shifts as digits change
 * is a column nobody can scan.
 *
 * The isolation is not ordinary, and it was found by rendering the page in
 * Arabic and reading it. `−100.00` inside an RTL document renders visually as
 * `100.00−`: the minus is a neutral character, so the bidi algorithm reorders
 * it to the far end of the run. **The sign is the whole meaning of that line** —
 * it is what says the amount comes off her bill — and it was landing on the
 * wrong side of the number, on the bill stack, which is the one screen where
 * the brand is or is not what it claimed.
 *
 * A number in Arabic prose is written left to right regardless. `isolate` stops
 * it perturbing the sentence around it; `direction: ltr` keeps the sign welded
 * to its digits. Flex still places the box by the row's direction, so the
 * mirroring is untouched — only the run's internal order is pinned.
 *
 * The same treatment is what phone numbers, dates and identifiers need, and for
 * the same reason. */
.fig,
.money,
.dash,
.testmode,
input.fig,
.stand .code,
.prices .was,
.dc .dw,
.slot,
.plr .num,
.lr > .v,
.lr > dd,
.seal b,
.week span,
.ticket .when .meridiem,
.hero-num,
td.num,
code,
kbd {
  font-family: var(--figure);
  /* Lining as well as tabular: Cormorant and Karla both default to oldstyle,
     which is how `30` came to read as `3O` and `31` as `3I` on a page whose
     every number is a time, a date or an amount. */
  font-variant-numeric: tabular-nums lining-nums;
  font-feature-settings: 'tnum' 1, 'lnum' 1;
  unicode-bidi: isolate;
  direction: ltr;
}

/* **`.num` alone is the numerals, not the face.** The token block sets it as
   tabular lining and nothing else, so a Cormorant heading with an hour in it
   — *Morning · opens 10:00* — keeps its serif and loses the oldstyle `1O`.
   The list above is the figures face; this is the figures' shape. */
.num {
  font-variant-numeric: tabular-nums lining-nums;
  font-feature-settings: 'tnum' 1, 'lnum' 1;
}

/* ============================================================ 3 · marks */

.mark {
  display: inline-flex;
  flex-direction: column;
  line-height: 1;
}

.mark .ar {
  font-family: var(--wordmark);
  font-size: 22px;
  color: var(--fir);
}

/* The Latin half of the lockup. **8px tracked caps under a 22px wordmark** is
   a caption, and on the desk that slot carries the salon's own trading name —
   so a salon's identity was a caption beneath somebody else's mark. */
.mark .en {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.28em;
  color: var(--sub);
  margin-block-start: 2px;
}

/* --- The handoff --------------------------------------------------------- */
/* F-23. One line above the bill: the same state, one tap away. It is quiet on
   purpose — the web finished the whole job, and the app is an upgrade rather
   than a requirement. A banner that shouted would be the install wall this
   product exists without. */

.handoff {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 9px 12px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--raised);
  font-size: 13.5px;
  color: var(--sub);
  text-decoration: none;
}

.handoff b {
  color: var(--ink);
  font-weight: 500;
}

/* F224 S23: under Pay, the bill first. */
.handoff.handoff-under { margin-block-start: 14px; }

/* --- The code by the mirror -------------------------------------------- */
/* O-03. The salon's own address as a square, printed once and stuck up where
   she sits. It is inline SVG at scale 1, so the size is set here rather than in
   the generator — a poster and a phone screen want different squares and only
   the stylesheet knows which one it is on.

   `image-rendering: pixelated` is not needed and would be wrong: this is
   vector, and a printer should get the vector. */

.qr {
  margin-block: 12px;
  display: flex;
  justify-content: center;
}

.qr svg {
  inline-size: min(260px, 60vw);
  block-size: auto;
}

/* A printed poster is the whole point, so the print sheet drops everything the
   wall does not need and leaves the square and the address. */
@media print {
  .hd,
  .rail,
  .btn,
  nav {
    display: none;
  }

  .qr svg {
    inline-size: 70vw;
  }
}

/* --- Stand mode ------------------------------------------------------- */
/* O-03. The daily code, on a tablet propped by the mirror, read from a metre
   away. It is the same number the desk screen shows — one page, one query, one
   truth — set large enough to be read rather than leaned into.
 *
 * The rail and the header are hidden because a stand is not being operated: it
 * is being looked at, by somebody who is not staff. */

.stand {
  min-block-size: 100dvh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 18px;
  text-align: center;
  padding: var(--gutter);
  background: var(--ground);
}

.stand .code {
  font-size: clamp(56px, 18vw, 132px);
  letter-spacing: 0.12em;
  line-height: 1;
  color: var(--ink);
}

/* **The salon's own name, where a guest looks first** (the founder's 12A,
   26 Sep 2026): a strip across the top — the name at the start, the stand's
   label at the end — over *Check in*, the salon's QR, and today's code on
   one line with *Or enter*. The QR leads now; the code stays large enough to
   read from the chair. */
.stand {
  position: relative;
}
.stand-hd {
  position: absolute;
  inset-block-start: 20px;
  inset-inline: var(--gutter);
  display: flex;
  align-items: center;
  justify-content: space-between;
  text-align: start;
}
.stand-hd .mark .ar {
  display: block;
  font-family: var(--arabic);
  font-size: 22px;
  color: var(--ink);
}
.stand-hd .mark .en {
  font-size: 11px;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--sub);
}
.stand h1 {
  margin: 0;
  font-family: var(--display);
  font-weight: 500;
  font-size: clamp(36px, 6vmin, 60px);
}
.stand .qr {
  inline-size: min(44vmin, 340px);
  padding: 14px;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: 18px;
}
.stand .qr svg {
  display: block;
  inline-size: 100%;
  block-size: auto;
}
.stand .note .code {
  margin-inline-start: 10px;
  font-size: clamp(36px, 8vmin, 72px);
  vertical-align: middle;
}

@media print {
  /* Two things get printed: the stand, taped up when a tablet cannot be
     spared, and O-13's statement, which is what an accountant is given.
     Neither wants navigation on the page. */
  .stand { min-block-size: auto; }
  .hd,
  .rail,
  .today,
  .testmode,
  .btn { display: none; }

  .page,
  .work { padding: 0; }

  .card {
    box-shadow: none;
    break-inside: avoid;
  }
}

/* --- The picker ------------------------------------------------------- */
/* F-04a, ported from the mockup's own rules onto the tokens and onto logical
   directions — the mockup writes `left` and `bottom`, and this system is
   built direction-first so the Arabic rendering flips without touching a
   component.
 *
 * **The slots are the counts.** A slot inside an armed window wears its
 * `instant` tag because the salon has already said yes to that hour; the rest
 * are questions it will answer. That distinction is the whole of F-06 and it
 * was invisible while the rail served a `datetime-local`. */

/* **Two weeks, a week to a row** (F4 and UX's F146, 11 Oct 2026): fourteen
   chips in one flex row shrank to 34px and scrolled the page sideways at 375.
   Seven columns keep the approved one-week chip, about 41px on a phone. */
.daychips {
  display: grid;
  grid-template-columns: repeat(7, minmax(0, 1fr));
  gap: 8px;
  margin-block-start: 16px;
}

/* A day card, as frame 4-02 sets it: 11px of padding, a 12px radius, the
   1.2px hairline, the weekday as a 9px tag at three-quarters, the numeral at
   22/600 under it. The chosen one is fir with paper on it. */
.dc {
  flex: 1;
  border-radius: 12px;
  border: 1.2px solid var(--line);
  background: var(--card);
  padding-block: 11px;
  text-align: center;
  text-decoration: none;
  display: block;
}

.dc.on {
  border-color: var(--fir);
  background: var(--fir);
}

.dc.on .dw { color: var(--on-fir); opacity: 0.7; }

.dc.on .dn { color: var(--on-fir); }

/* F224 S32 (AFTER_APPLE's skin): at dusk the picked day's weekday is the
   numeral's own dark ink, not a faded one on the light fir. */
@media (prefers-color-scheme: dark) {
  :root.c0:not([data-theme='light']) .dc.on .dw { opacity: 1; }
}
:root.c0[data-theme='dark'] .dc.on .dw { opacity: 1; }

/* A day the salon does not trade is not offered. It stays visible so the week
   keeps its shape — five chips, one of them plainly shut. */
.dc.shut {
  opacity: 0.4;
  pointer-events: none;
}

.dc .dw {
  font-size: 11px;
  color: var(--ink);
  opacity: 0.75;
  margin: 0;
}

/* The greyed day's one word, *Closed* or *Full* (GT-007; the board, 10 Oct
   2026), under the numeral at the AA floor's eleven. */
.dc .dr {
  font-size: 11px;
  color: var(--sub);
  margin-block-start: 1px;
}

.dc .dn {
  /* The numeral is a figure, not a title — the markup wears `.num`, which is
     the one place the figure face is declared. Cormorant here read as
     ceremony over a Tuesday. */
  font-weight: 600;
  font-size: 24px;
  color: var(--ink);
  margin-block-start: 2px;
}

.slotgrid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 8px;
  margin-block: 0 0;
}

/* The part headings — a section head one step down, at 22, because they sit
   under the picker's own title and over 16px slots (frame 4-02 set them at
   16, which was the size of the slots they were meant to head). The first is
   20 under the day cards, the rest 16 under the grid before them. */
.picker .part-head {
  font-size: 22px;
  margin-block: 16px 10px;
}

.daychips + form .part-head:first-of-type { margin-block-start: 20px; }

/* The part of the day on request, under its heading (UX audit R4): moved
   here from the salon page, beside the times it is about. */
.picker .part-aside { margin-block: -4px 10px; color: var(--sub); }

.picker .greet { margin-block: 4px 0; }

/* **Who?** (F33–F35; the founder's board, #c1 A): one row per choice — the
   radio, the initial in its circle, the first name over what she does, and
   *Free this week* at the end. The chosen row is outlined in fir. Initials,
   never photos; the star is *Any stylist*. */
.wholist { display: flex; flex-direction: column; gap: 8px; margin-block: 16px 0; }

.whopick {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 14px;
  border: 1.2px solid var(--line);
  border-radius: 12px;
  background: var(--card);
  cursor: pointer;
}

.whopick:has(input:checked) { border-color: var(--fir); box-shadow: 0 0 0 1px var(--fir); }

.whopick input {
  appearance: none;
  flex: none;
  width: 18px;
  height: 18px;
  margin: 0;
  border-radius: 50%;
  border: 1.5px solid var(--struck);
}

.whopick input:checked { border: 5px solid var(--fir); }

.whopick input:focus-visible { outline: 2px solid var(--fir); outline-offset: 2px; }

.whoini {
  flex: none;
  width: 36px;
  height: 36px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  background: var(--sage-wash);
  border: 1px solid var(--sage-line);
  color: var(--fir);
  font-weight: 600;
}

.whoini.any { background: var(--pill); border-color: var(--line); color: var(--brass); }

.whoname { flex: 1; min-width: 0; display: flex; flex-direction: column; }

.whoname .s { color: var(--sub); font-size: 13.5px; }

.whofree { flex: none; color: var(--good); font-size: 12.5px; font-weight: 600; }

/* The time step's row (#time A): *With Mariam* and *Change*, above the days;
   and the way out under her times. */
/* **Who, as one control** (split visit D; UX audit F53): the names and
   *Change* inside one outlined box, so *Change* reads as changing them. */
.withrow {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 12px;
  margin-block: 10px 12px;
  padding: 10px 14px;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--card);
}

.withrow a, .moreany a { color: var(--fir); font-weight: 600; text-decoration: none; }

.withrow .withlines > span { display: block; }

.moreany { margin-block: 14px 0; color: var(--sub); }

/* Under each service on Check your booking and the sent screen (#review A). */
.ck-who { display: block; color: var(--sub); font-size: 13px; }

/* **Choose for each service** (#c3 A opened): a card per service, its name
   over the chips — *Any* and whoever does it — the chosen chip fir. */
.eachlist { display: flex; flex-direction: column; gap: 10px; margin-block: 16px 0; }

.eachrow { border: 1.2px solid var(--line); margin: 0; padding: 12px 14px; min-width: 0; }

.eachrow legend { float: inline-start; width: 100%; padding: 0; margin-block-end: 8px; }

.eachchips { display: flex; flex-wrap: wrap; gap: 6px; clear: both; }

.eachchip { cursor: pointer; }

.eachchip input { position: absolute; opacity: 0; width: 1px; height: 1px; }

.eachchip:has(input:checked) { background: var(--fir); border-color: var(--fir); color: var(--on-fir); }

.eachchip:has(input:focus-visible) { outline: 2px solid var(--fir); outline-offset: 2px; }

.eachhelp { margin-block: 12px 0; color: var(--sub); }

/* **Split visit D** (the founder, 25 Sep 2026): a wait is written on the time
   that has one, in the warm ink the hold's callout uses, never red. */
.slot-wait {
  display: block;
  font-size: 11px;
  font-weight: 700;
  color: var(--brass);
}

/* When nothing fits together: the day said plainly, then the ways out. */
.nofit { margin-block: 16px 0; }

.nofit .ways { display: flex; flex-direction: column; gap: 8px; margin-block-start: 10px; }

.nofit .ways a { color: var(--fir); font-weight: 600; text-decoration: none; }

/* A slot is the chip, a third wide, 11px of padding and a 12px radius. The
   selector outranks `.chip`, which is written later in this file. */
.slotgrid .chip.slot {
  display: flex;
  justify-content: center;
  padding-inline: 0;
  padding-block: 11px;
  border-radius: 12px;
  position: relative;
  cursor: pointer;
}

.slot:has(input:checked),
.slot.on {
  border-color: var(--fir);
  background: var(--fir);
  color: var(--on-fir);
}

/* **Her own time, when she is changing it** (the founder, 24 Sep 2026, A7). */
/* Hers, not unavailable (the UX board, 24 Sep 2026): an ink outline and the
   word in ink — the grey was reading as a slot somebody else had. */
.slot.mine {
  border-color: var(--ink);
  box-shadow: inset 0 0 0 0.5px var(--ink);
  color: var(--ink);
}

.slot-mine {
  display: block;
  font-size: 11px;
  font-weight: 700;
  color: var(--ink);
}

/* F224 S31 (AFTER_APPLE's skin): *Your time* under the time, inside the
   chip, as the app's slot has it, so a third of 320 still holds both. */
:root.c0 .slotgrid .chip.slot.mine { flex-direction: column; align-items: center; }

.slot input {
  position: absolute;
  opacity: 0;
  inset: 0;
  inline-size: 100%;
  block-size: 100%;
  margin: 0;
  cursor: pointer;
}

.slot:focus-within {
  outline: 2px solid var(--fir);
  outline-offset: 2px;
}

/* The picker's eyebrow, over the question: the tag face in gold. */
.pick-room {
  display: block;
  margin: 6px 0 0;
}

/* **A line for the salon.** Folded: the sentence with the verb in fir at
   600; open: the field under it. */
.noteask { margin-block-start: 16px; }

.noteask summary {
  cursor: pointer;
  list-style: none;
  margin: 0;
}

.noteask summary::-webkit-details-marker { display: none; }

.noteask summary b {
  color: var(--fir);
  font-weight: 600;
}

.noteask .notefield {
  margin-block-start: 10px;
  inline-size: 100%;
}

/* The picker's dock. The chosen line, its pair, the echoed time, one verb. */
.pickdock {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 2px 12px;
  margin-block-start: 14px;
}

.pickdock .dockline {
  flex: 1 1 auto;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 1px;
}

.pickdock .dockline .s { display: block; }

.pickdock .docktime {
  font-size: 16px;
  font-weight: 600;
  color: var(--ink);
}

.pickdock .docktime:empty { display: none; }

.pickdock .prices { margin: 0; }

.pickdock .prices .v {
  font-family: var(--price-face, var(--display));
  font-weight: var(--price-weight, 700);
  font-size: 26px;
  color: var(--fir);
}

.pickdock .was { font-size: 13.5px; color: var(--struck); }

.pickdock .btn {
  flex: 1 1 100%;
  margin-block-start: 8px;
}

@media (max-width: 999px) {
  .pickdock {
    position: fixed;
    inset-inline: 0;
    inset-block-end: 0;
    z-index: 80;
    margin: 0;
    border-block-start: 1px solid var(--rule);
    background: color-mix(in srgb, var(--raised) 45%, var(--ground));
    padding: 12px var(--gutter) 14px;
  }

  /* **The page keeps clear of the dock, footer included** (the founder's AA
     ruling, 5 Oct 2026). The room was the main's, so *Terms* and *Privacy*
     sat under the dock at the very bottom and took focus unseen. The body
     carries it now — 132px measured, with room for a line more — and the
     footer scrolls clear. */
  body:has(.pickdock) { padding-block-end: 150px; }
}

/* **Confirmed, as the art** (frame 6-01). Centred: the tag with its check,
   the day in the display face, the hour set large, the painting full-bleed,
   the sentence, the two quiet actions, the foot. */
.confirmed-art {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  padding-block-start: 22px;
}

.confirmed-art .confirmed-tag {
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  color: var(--ink);
  margin: 0;
}

.confirmed-art .confirmed-day {
  font-family: var(--display);
  font-weight: 500;
  font-size: 30px;
  line-height: 1.1;
  color: var(--ink);
  margin: 18px 0 0;
}

.confirmed-art .confirmed-time {
  display: flex;
  align-items: baseline;
  gap: 8px;
  margin: 6px 0 0;
}

.confirmed-art .confirmed-time b {
  font-family: var(--display);
  font-weight: 500;
  font-size: 64px;
  line-height: 1;
  letter-spacing: -0.02em;
  color: var(--ink);
}

.confirmed-art .confirmed-time .meridiem {
  font-size: 15px;
  font-weight: 500;
  color: var(--ink);
}

/* The flourish: the salon's painting at the page's width, the same plate the
   card wears, 200 tall. */
.confirmed-art .confirmed-plate {
  inline-size: calc(100% + 2 * var(--gutter));
  margin-inline: calc(-1 * var(--gutter));
  block-size: 200px;
  margin-block-start: 22px;
  overflow: hidden;
}

.confirmed-art .confirmed-plate svg {
  display: block;
  inline-size: 100%;
  block-size: 100%;
}

.confirmed-art .confirmed-line {
  font-size: 16px;
  margin: 22px 0 0;
  color: var(--text);
}

.confirmed-art .confirmed-line b { color: var(--ink); font-weight: 600; }

.confirmed-art .confirmed-about { margin: 6px 0 0; }

.confirmed-art .confirmed-hold,
.confirmed-art .confirmed-why {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 18px 0 0;
  text-align: start;
}

.confirmed-art .confirmed-acts {
  inline-size: 100%;
  margin-block-start: 22px;
}

.confirmed-art .confirmed-foot { margin: 18px 0 0; }

/* **Confirmed, facts first** (the founder's #9 A, 23 Sep 2026): the painting
   shrinks to a band, the facts read down the page from the start edge, the
   calendar is the one filled verb and the rest are links. Overrides the art
   above where the two differ, so the frame-6-01 rules stay legible. */
.confirmed-art:has(.confirmed-band) {
  align-items: stretch;
  text-align: start;
  padding-block-start: 6px;
}

.confirmed-art .confirmed-band {
  block-size: 64px;
  border-radius: 14px;
  overflow: hidden;
}

.confirmed-art .confirmed-band svg {
  display: block;
  inline-size: 100%;
  block-size: 100%;
}

.confirmed-art .confirmed-head {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 18px 0 0;
  font-size: 14.5px;
  font-weight: 600;
  color: var(--fir);
}

.confirmed-art:has(.confirmed-band) .confirmed-day {
  font-weight: 600;
  font-size: 40px;
  line-height: 1.1;
  margin: 10px 0 0;
}

.confirmed-art:has(.confirmed-band) .confirmed-time {
  display: block;
  font-family: var(--display);
  font-weight: 600;
  font-size: 28px;
  line-height: 1.15;
  color: var(--ink);
  margin: 0;
}

/* Who does each service, once confirmed (#review C): one per line under the
   hour, quieter than it. */
.confirmed-art .confirmed-with {
  font-size: 15px;
  line-height: 1.4;
  color: var(--text);
  margin: 2px 0 0;
}

.confirmed-art .confirmed-time + .confirmed-with { margin-block-start: 8px; }

/* Split visit D: when she finishes, beside the hour and quieter than it. */
.confirmed-art .confirmed-finish {
  font-family: var(--ui);
  font-size: 15px;
  font-weight: 500;
  color: var(--sub);
}

.confirmed-art:has(.confirmed-band) .confirmed-hold {
  font-size: 15px;
  color: var(--text);
  margin-block-start: 12px;
}

.confirmed-art .card.confirmed-where {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-block: 18px 20px;
  text-decoration: none;
  color: var(--ink);
}

.confirmed-art .confirmed-where b { display: block; font-weight: 600; }

.confirmed-art .confirmed-where .s { display: block; margin: 0; }

.confirmed-links {
  display: flex;
  justify-content: space-between;
  gap: 20px;
  margin: 14px 0 0;
}

.confirmed-links a {
  font-weight: 600;
  color: var(--fir);
  text-decoration: none;
}

.confirmed-links a.faint { color: var(--sub); }

.linkbtn {
  appearance: none;
  border: 0;
  background: none;
  padding: 4px 0;
  font: inherit;
  font-weight: 600;
  color: var(--fir);
  cursor: pointer;
}

/* **The screen after Send** (the founder's flow, frame 8, 23 Sep 2026): the
   four stops, the greeting, the salon, the day and what she asked for, the
   rail's sentence, and *Done*. */
.sent { display: flex; flex-direction: column; gap: 12px; }

.sent .greet { margin: 0; }

.vtrack {
  display: flex;
  list-style: none;
  margin: 0 0 4px;
  padding: 0;
}

.vtrack li {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  position: relative;
  font-size: 12px;
  color: var(--sub);
}

/* The rule between two stops, drawn from the stop before to this one. */
.vtrack li + li::before {
  content: "";
  position: absolute;
  inset-block-start: 10px;
  inset-inline-end: calc(50% + 15px);
  inline-size: calc(100% - 30px);
  block-size: 2px;
  background: var(--rule);
}

.vtrack li.on + li.on::before { background: var(--fir); }

.vtrack i {
  inline-size: 22px;
  block-size: 22px;
  border-radius: 50%;
  border: 1.5px solid var(--fir);
  background: var(--card);
  display: grid;
  place-items: center;
  font-style: normal;
  font-size: 11px;
  font-weight: 700;
  color: var(--fir);
}

.vtrack li.on { color: var(--ink); font-weight: 600; }

.vtrack li.on i { background: var(--fir); }

/* A stop the rail serves undrawn — after a cancellation — keeps its place. */
.vtrack li.undrawn { visibility: hidden; }

/* **Where a cancelled track ends** (the founder, 24 Sep 2026, A6): a grey
   dot, no tick and no number, and its word in the same grey. */
.vtrack li.ended { color: var(--faint); }

.vtrack li.ended i { border-color: var(--faint); background: var(--faint); }

/* **The line under the track** (Product, 24 Sep 2026): a counter-offer's
   under *Asked*, a cancellation's under the last stop reached — from the
   track's own start, as the screen's heading. */
.track-at {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.track-says {
  margin: 0;
  font-size: 17px;
  line-height: 1.35;
  font-weight: 600;
  color: var(--ink);
}

/* cx-A (UX, 19 Oct 2026): the salon's suggestion is the page's title, in
   the display face as *Your request is with…*, at the frame's 28. */
.sent.counter .track-says {
  font-family: var(--display);
  font-size: 28px;
  line-height: 1.1;
  letter-spacing: -0.012em;
}

.track-held { margin: 0; }

/* Her own time and what she asked for, beside the salon's suggestion (A4). */
.track-asked { margin: 0; }

.track-verbs { display: flex; gap: 10px; margin-block-start: 4px; }

.track-verbs > * { flex: 1; margin: 0; }

.track-verbs .btn { inline-size: 100%; }

/* **A new time's two answers** (O3's words, F224; AFTER_APPLE's skin): on
   a narrow phone *Accept* stacks above *Pick another time* at full width, as
   the app's invite buttons stack below 360, so no label touches its border.
   The line is 370, not 360: side by side, *Pick another time* keeps 12px
   inside its border only from 364 up (11.4 at 360), and 370 leaves room. */
@media (max-width: 369px) {
  :root.c0 .sent .track-verbs { flex-direction: column; }
  :root.c0 .sent .track-verbs > * { flex: none; }
}

/* **A new price at the chair, for her to accept before the work** (the price
   lines' one rule): the service, *Your price* with the salon's figure struck
   beside hers, and her two answers — on her phone and on the desk's tablet in
   her hands. */
.ask-sheet { display: grid; gap: 10px; margin-block-end: 18px; }
.ask-sheet .greet { margin: 0; }

/* Two classes, because `.card` sets `display: block` further down the file. */
.card.sent-salon { display: flex; align-items: center; gap: 12px; }

/* **The request ticket** (Round 2 A, `#r1`): one card — the salon, the hour,
   every line with both prices, *You pay*, and her saving in quiet fir. */
.sent-ticket { display: flex; flex-direction: column; gap: 8px; }

.sent-ticket .sent-salon { display: flex; align-items: center; gap: 12px; }

.sent-ticket hr { margin: 4px 0; }

.sent-when-line { margin: 0; font-size: 16px; }

.sent-pay { margin: 4px 0 0; font-size: 16px; color: var(--ink); }

.sent-ticket .ck-less { margin: 0; text-align: start; }

.sent-status {
  display: flex;
  gap: 8px;
  align-items: flex-start;
  color: var(--sub);
}

.sent-status svg { flex: none; margin-block-start: 4px; color: var(--brass); }

/* R7 (ans-A1/A2): *Sent 12:40 pm* under the heading, and the late card on
   the raised sand with its two rows (`.card.`: the later `.card` painted it
   white). */
.wait-sent { margin: -6px 0 0; }
.card.wait-late { background: var(--raised); }
.wait-late p { margin: 0; }
.wait-late .wait-late-head { color: var(--ink); }
:root.c0 .wait-late .confirmed-links.link-rows { border-block-start: 0; margin-block-start: 6px; }
:root.c0 .wait-late .confirmed-links.link-rows a { color: var(--ink); font-weight: 600; }
:root.c0 .wait-late .confirmed-links.link-rows a:last-child { border-block-end: 0; }

.sent-salon b { display: block; font-weight: 600; }

.sent-salon .s { display: block; margin: 0; }

.sent-plate {
  flex: none;
  inline-size: 44px;
  block-size: 44px;
  border-radius: 12px;
  overflow: hidden;
}

.sent-plate svg { display: block; inline-size: 100%; block-size: 100%; }

.sent-when p { margin: 0; }

.sent-when .s { margin-block-start: 4px; }

/* --- A visit someone else ended ---------------------------------------- */
/* The founder's missed B and salon-cancelled B (25 Sep 2026): the title,
   the visit on a small card, the money in one line, then her answers. */

.ended-card { display: flex; flex-direction: column; gap: 2px; }

.ended-card p { margin: 0; }

.ended-card .num { font-size: 16px; }

.ended-line { margin: 0; color: var(--ink); }
/* **Her money, its own row on the card** (salon-cancelled, pick B on UX board
   NnTpTJPXfafErNwSYhwsty; the founder's yes 22:55 15 Oct 2026). */
.ended-card .ended-money {
  margin-block-start: 10px;
  padding-block-start: 10px;
  border-block-start: 1px solid var(--line);
  gap: 12px;
}
.ended-card .ended-money .k { color: var(--ink); }
/* F230: the card's last row after an ending, a mark and a line (UX's frames
   04-app-design/f230-panel-fixes/, the founder's yes of 15 Oct 2026). */
.ended-row {
  display: flex; align-items: center; gap: 8px;
  margin: 14px 0 0; padding-top: 14px; border-top: 1px solid var(--line);
  font-weight: 600; color: var(--ink);
}
.ended-row svg { flex: none; color: var(--fir); }
/* Nothing owed is done: the good green (UX's check, 15 Oct 2026). */
.ended-row svg.check { color: var(--good); }

.ended-checking { margin: 0; align-self: center; text-align: center; }

.ended-sheet .confirmed-links { justify-content: center; margin: 0; }

/* The gift you can see (salon-cancelled B): a drawn edge and the amount in
   the display face — never a badge, and never red. */
.ended-gift {
  display: flex;
  align-items: center;
  gap: 12px;
  margin: 0;
  padding: 12px 14px;
  border: 1.5px dashed var(--brass-soft);
  border-radius: 12px;
  background: var(--pill);
  color: var(--ink);
}

.ended-gift b {
  font-family: var(--price-face, var(--display));
  font-weight: var(--price-weight, 600);
  font-size: 24px;
  line-height: 1;
  color: var(--brass);
}

/* The cancel screen's cost, as one figure (the founder's cancel B). */
.cancel-cost {
  font-family: var(--price-face, var(--display));
  font-weight: var(--price-weight, 600);
  font-size: 40px;
  line-height: 1;
  color: var(--fir);
  margin: 6px 0 0;
}

/* free-A: the word *Free* in the display face and ink, as the frame. */
.cancel-cost.free {
  font-family: var(--display);
  font-weight: 600;
  color: var(--ink);
}

.cancel-hold { margin: 0; }

/* free-A: *until Tue 20 Oct · 1:30 pm*, close under *Free*. */
.cancel-until { margin: 4px 0 0; color: var(--ink); }

.ended-sheet form .cancel-go { inline-size: 100%; }

.sent-note { margin: 0; }

.sent .next-steps { margin: 0; font-size: 13.5px; line-height: 1.5; color: var(--sub); }

.sent-links { justify-content: center; gap: 28px; margin: 0; }

/* The second quiet action, on the raised sand rather than outlined. */
.btn.sand {
  background: var(--raised);
  border-color: var(--raised);
  color: var(--ink);
}

.picker .cancel-instead { margin: 14px 0 0; text-align: center; }

/* ====================================================== Home (frame 7-01) */
/* The greeting, the one line about what is next, the ticket with its
   actions, the spreads, her rows, the foot. */
.home-greet { margin-block: 16px 0; }

.home-next {
  margin: 6px 0 0;
  font-size: 16px;
  color: var(--text);
}

/* **Her gift, under the greeting** (Beanz (b), 12 Oct 2026): a card-white
   pill, the gift drawn in rose, the figure beside it. A tap opens Gifts. */
.gift-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-block-start: 10px;
  padding: 5px 13px 5px 8px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--card);
  color: var(--ink);
  font-size: 14px;
  font-weight: 600;
  text-decoration: none;
}

.gift-chip svg { inline-size: 20px; block-size: 20px; color: var(--rose); flex: none; }

/* **Home's card, the founder's #7** (24 Sep 2026). The UX board's frame: the
   face and the name, the chip on its own line, the time in the display face,
   what she booked, the money as a pill with the amount at its end, one
   full-width button, and one quiet pair of links. The card opens the booking;
   the button and the links act. It replaces the L card, whose hour at 44 and
   two small buttons were a poster over a pair of doors. */
.ticket.vc { margin-block-start: 16px; padding: 18px; }

.vc .vc-open {
  display: flex;
  flex-direction: column;
  gap: 10px;
  color: inherit;
  text-decoration: none;
}

.vc .vc-head { display: flex; align-items: center; gap: 12px; }

/* The salon's face at 40 by 40, radius 10 — the tile *Book again* wears in
   the app, so one salon has one face on Home. */
.vc .vc-face {
  flex: none;
  inline-size: 40px;
  block-size: 40px;
  border-radius: 10px;
  border: 1px solid var(--line);
  background: var(--card);
  display: grid;
  place-items: center;
  overflow: hidden;
  font-family: var(--display);
  font-weight: 600;
  font-size: 18px;
  line-height: 1;
  color: var(--face-ink, var(--fir));
}

.vc .vc-face img { inline-size: 100%; block-size: 100%; object-fit: cover; }

/* The salon's own ink is a daylight colour: on the night card its letters all
   but vanished, so after dark the monogram takes the page's ink. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme='light']) .vc .vc-face { color: var(--ink); }
}

:root[data-theme='dark'] .vc .vc-face { color: var(--ink); }

.vc .vc-who { min-inline-size: 0; }

.vc .vc-name {
  margin: 0;
  font-size: 16px;
  font-weight: 600;
  line-height: 1.3;
  color: var(--ink);
}

.vc .vc-area {
  display: flex;
  align-items: center;
  gap: 4px;
  margin: 2px 0 0;
  font-size: 13.5px;
  color: var(--sub);
}

/* The chip on its own line, at the start: brass while it waits on somebody,
   fir once the salon has said yes. Tints of the tokens, so the dark theme
   follows them. */
.vc .vc-chip {
  align-self: flex-start;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  margin: 0;
  padding: 4px 10px;
  border-radius: 99px;
  font-size: 12.5px;
  font-weight: 600;
  color: var(--brass);
  background: color-mix(in srgb, var(--brass) 10%, var(--card));
  border: 1px solid color-mix(in srgb, var(--brass) 30%, var(--card));
}

.vc .vc-chip-settled {
  color: var(--fir);
  background: color-mix(in srgb, var(--fir) 9%, var(--card));
  border-color: color-mix(in srgb, var(--fir) 22%, var(--card));
}

/* An ending wears no mark: a tick beside *That time has gone* reads as done. */
.vc .vc-chip-ended {
  color: var(--sub);
  background: var(--raised);
  border-color: var(--line);
}

.vc .vc-time {
  margin: 2px 0 0;
  font-family: var(--display);
  font-weight: 600;
  font-size: 28px;
  line-height: 1.1;
  color: var(--ink);
}

.vc .vc-what { margin: 0; font-size: 14.5px; color: var(--sub); }

/* The money: a pill, the label at its start and the amount at its end. */
.vc .vc-money {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin: 2px 0 0;
  padding: 9px 12px;
  border-radius: 10px;
  background: var(--pill);
  font-size: 14px;
  color: var(--text);
}

.vc .vc-mlabel { display: inline-flex; align-items: center; gap: 6px; min-inline-size: 0; }

.vc .vc-money b { color: var(--ink); font-weight: 700; white-space: nowrap; }

.vc .vc-line {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 2px 0 0;
  font-size: 13.5px;
  color: var(--sub);
}

.vc .vc-note { margin: 0; }

.vc .vc-act { margin-block-start: 14px; }

.vc .vc-links {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  margin: 12px 0 0;
  font-size: 14px;
}

.vc .vc-links a { color: var(--fir); font-weight: 600; text-decoration: none; }

.vc .vc-links a.vc-quiet { color: var(--sub); font-weight: 500; }

/* **What happens next**, under a sent request: three numbered lines. */
.next-steps {
  margin: 14px 0 0;
  padding: 0;
  list-style: none;
  counter-reset: step;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.next-steps li {
  counter-increment: step;
  display: flex;
  gap: 10px;
  align-items: flex-start;
  font-size: 15px;
  line-height: 1.5;
  color: var(--text);
}

.next-steps li::before {
  content: counter(step);
  flex: none;
  inline-size: 22px;
  block-size: 22px;
  border-radius: 99px;
  border: 1px solid var(--line);
  color: var(--sub);
  font-size: 12px;
  font-weight: 600;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  margin-block-start: 1px;
}

/* The frame's small buttons: outlined fir at 1.4px, and the quiet one on the
   raised sand. */
.btn.quiet.sm { border-width: 1.4px; }

/* **The spreads** — the ribbon leading with pictures: 268 wide, the painting
   at 120, then the tag, the title in the serif at 22, one line, the verb. */
.spreads {
  display: flex;
  gap: 12px;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  margin-inline: calc(-1 * var(--gutter));
  padding-inline: var(--gutter);
  scrollbar-width: none;
}

.spreads::-webkit-scrollbar { display: none; }

.spread {
  flex: 0 0 268px;
  scroll-snap-align: start;
  display: block;
  border-radius: 18px;
  overflow: hidden;
  text-decoration: none;
  color: inherit;
  border: 1px solid var(--line);
  background: var(--card);
}

.spread .plate {
  display: block;
  block-size: 120px;
  position: relative;
  overflow: hidden;
}

.spread .plate svg {
  position: absolute;
  inset: 0;
  inline-size: 100%;
  block-size: 100%;
}

.spread .caption {
  display: block;
  padding: 12px 14px 14px;
}

.spread .caption > * { display: block; }

.spread .caption .tag { margin: 0; }

.spread .caption .tag.sage { color: var(--sage); }

.spread .caption .h2 {
  font-family: var(--display);
  font-weight: 600;
  font-size: 26px;
  line-height: 1.12;
  letter-spacing: -0.01em;
  color: var(--ink);
  margin-block-start: 3px;
}

.spread .caption .s { margin-block-start: 2px; }
/* R4 A (18 Oct 2026): on a service search, the salon's first time for it,
   in place of the open line, in fir. */
.caption .earliest { color: var(--fir); font-weight: 600; }

.spread .caption .btn {
  display: flex;
  margin-block-start: 10px;
  block-size: 38px;
  font-size: 15px;
}

/* **F222 · a gift card, C1 painted** (the founder's "C1 painted for the gift
   cards", 14 Oct 2026 ~13:55; UX's handoff, 04-app-design/f222-giftcards-
   handoff). The gift's painting is the card and the words sit over its
   start side. 268 × 164 at r18, 252 wide on a 320 screen.

   **The card's own colours, the same in both themes.** A gift card is a
   printed thing: it does not invert at night, so its inks are its own
   tokens and not `--brass` and `--ink`, which the dark theme moves. The
   grounds are the handoff's four; gold is only for gifts and no green is on
   one. The ribbon card's ground stays as drawn (brass on its darkest end is
   4.6:1). */
.gc {
  --gc-brass: #7C6336;
  --gc-ink: #1F2822;
  --gc-sub: #5E665F;
  --gc-ground: #F7EFDD;
  --gc-spent: #EEECE6;
  --gc-fig: var(--gc-brass);
  --gc-kick: var(--gc-brass);
  --gc-paid: var(--gc-brass);
  --gc-status: var(--gc-ink);
  --gc-date: var(--gc-sub);
  --gc-shift: 0px;
  position: relative;
  flex: 0 0 268px;
  block-size: 164px;
  scroll-snap-align: start;
  display: block;
  border-radius: 18px;
  overflow: hidden;
  background: var(--gc-ground);
  text-decoration: none;
  color: var(--gc-ink);
}

.gc-invite { --gc-ground: #FBEEE4; --gc-shift: 34px; }

.gc-thanks { --gc-ground: #FCF6E8; }

.gc-season {
  --gc-ground: #2A4233;
  --gc-spent: #3A3F3B;
  --gc-fig: #F3E5C4;
  --gc-kick: #D9C38A;
  --gc-paid: #D9C38A;
  --gc-status: #FBF8F1;
  --gc-date: rgb(251 248 241 / 0.82);
}

.gc-spent {
  background: var(--gc-spent);
  --gc-fig: var(--gc-sub);
  --gc-paid: var(--gc-sub);
}

.gc-season.gc-spent {
  --gc-fig: rgb(251 248 241 / 0.7);
  --gc-paid: rgb(251 248 241 / 0.7);
}

/* The painting: the plate at the card's height, its far side on the card's
   far edge, fading out under the words from 46% to 64% of the way across. */
.gc-art {
  position: absolute;
  inset: 0;
  -webkit-mask-image: linear-gradient(var(--flow-end), transparent 46%, #000 64%);
  mask-image: linear-gradient(var(--flow-end), transparent 46%, #000 64%);
}

.gc-art svg {
  position: absolute;
  inset-block: 0;
  inset-inline-end: calc(-1 * var(--gc-shift));
  inline-size: 372px;
  block-size: 164px;
}

.gc-thanks .gc-art,
.gc-season .gc-art {
  -webkit-mask-image: none;
  mask-image: none;
}

.gc-thanks .gc-art svg { inline-size: 100%; inset-inline-end: 0; }

/* The night card's wash keeps its light words clear over the palm. */
.gc-season .gc-art::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(var(--flow-end), rgb(36 56 43 / 0.94) 0%, rgb(36 56 43 / 0.72) 50%, rgb(36 56 43 / 0) 74%);
}

.gc-spent .gc-art svg { filter: grayscale(0.9); opacity: 0.45; }

.gc-words {
  position: absolute;
  inset: 15px 16px 14px;
  display: flex;
  flex-direction: column;
}

.gc-words > span { display: block; white-space: nowrap; }

.gc-kick {
  max-inline-size: 166px;
  overflow: hidden;
  text-overflow: ellipsis;
  font-family: var(--ui);
  font-weight: 700;
  font-size: 11px;
  line-height: 14px;
  letter-spacing: 1.4px;
  text-transform: uppercase;
  color: var(--gc-kick);
}

.gc-fig {
  align-self: flex-start;
  margin-block-start: 1px;
  font-family: var(--price-face, var(--display));
  font-weight: var(--price-weight, 600);
  font-size: 46px;
  line-height: 48px;
  color: var(--gc-fig);
}

/* **The third strikethrough** (the anti-coupon law's header names the
   others). A used or ended gift's figure is struck on a grey card: it says
   the gift is spent, not that a price was cut, and no figure stands beside
   it to be read as the new one. The founder's C1 frames draw it. */
.gc-spent .gc-fig {
  text-decoration: line-through;
  text-decoration-thickness: 1.5px;
}

.gc-sub,
.gc-paid,
.gc-status {
  font-family: var(--ui);
  font-weight: 600;
}

.gc-sub { font-size: 13px; line-height: 17px; color: var(--gc-status); }

.gc-sub + .gc-paid { margin-block-start: 2px; }

.gc-paid { font-size: 12px; line-height: 16px; color: var(--gc-paid); }

.gc-foot { margin-block-start: auto; }

.gc-foot > span { display: block; white-space: nowrap; }

.gc-status { font-size: 13.5px; line-height: 18px; color: var(--gc-status); }

.gc-date {
  font-family: var(--ui);
  font-size: 12.5px;
  line-height: 17px;
  color: var(--gc-date);
}

@media (max-width: 359px) {
  .gc { flex-basis: 252px; }
}

/* **F222 · the bill, one line**: the gift mark and *Gift · −Ð50*. */
.gift-line { display: flex; align-items: center; justify-content: center; gap: 8px; }

.gift-line svg {
  flex: none;
  stroke: var(--brass);
  stroke-width: 1.6;
  stroke-linejoin: round;
}

.gift-line .bow { fill: var(--gold-leaf); stroke-width: 1.3; }

/* **Her rows**: the painting small at 52 and r14, the name in the serif at
   19, one line under it, a hairline between rows. */
.rows { display: block; }

.row {
  display: flex;
  align-items: center;
  gap: 14px;
  padding-block: 14px;
  border-block-end: 1px solid var(--line);
  text-decoration: none;
  color: inherit;
}

.row .em {
  display: block;
  inline-size: 52px;
  block-size: 52px;
  border-radius: 14px;
  flex: none;
  position: relative;
  overflow: hidden;
}

.row .em svg {
  position: absolute;
  inset: 0;
  inline-size: 100%;
  block-size: 100%;
}

.row .rowin {
  display: block;
  flex: 1;
  min-inline-size: 0;
}

.row .rowin > * { display: block; }

.row .rowin .h2 {
  font-family: var(--display);
  font-weight: 600;
  font-size: 24px;
  line-height: 1.12;
  color: var(--ink);
}

.row .rowin .s { margin-block-start: 2px; }

/* **Visits, as the founder picked it** (Round 2 A, 24 Sep 2026 — the UX
   board's `#r2`). Two tabs; a row that reads at a glance — a date box, the
   room's square, the salon, the services on one line and one chip; the
   requests that ran out of time folded into one line. The old row set the
   state as brown text inside the service line and the hour in a right-hand
   column that wrapped every row to four lines. */
.visit-tabs {
  display: flex;
  gap: 2px;
  margin: 14px 0 6px;
  padding: 3px;
  border-radius: 12px;
  background: var(--raised);
}

.visit-tabs a {
  flex: 1;
  padding: 8px 0;
  border-radius: 9px;
  text-align: center;
  font-size: 14.5px;
  color: var(--sub);
  text-decoration: none;
}

.visit-tabs a.on {
  background: var(--card);
  color: var(--ink);
  font-weight: 600;
  box-shadow: 0 1px 2px rgb(0 0 0 / 8%);
}

.visit-row {
  position: relative;
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 0;
  border-bottom: 1px solid var(--line);
}

/* The date box: the day in brass capitals, the date large, the hour under. */
.visit-box {
  flex: none;
  inline-size: 50px;
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 5px 0;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--card);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.06em;
  line-height: 1.2;
  color: var(--brass);
}

.visit-box b {
  font-size: 19px;
  letter-spacing: 0;
  color: var(--ink);
}

.visit-box span:last-child {
  font-weight: 500;
  letter-spacing: 0;
  color: var(--sub);
  white-space: nowrap;
}

.visit-row .face-tile {
  inline-size: 36px;
  block-size: 36px;
  border-radius: 9px;
  font-size: 15px;
}

.visit-mid {
  flex: 1;
  min-inline-size: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
}

/* The salon's name is the way in, stretched over the whole row. **It wraps
   rather than clipping** (the founder's AA ruling, 5 Oct 2026): at 320px
   *Example …* was all of a name, and *Bedazzled Ladies Salon* lost its end
   at 390 — a name is the one thing on the row she reads to find her visit. */
.visit-go {
  font-size: 16px;
  font-weight: 600;
  color: var(--ink);
  text-decoration: none;
  overflow-wrap: break-word;
}

.visit-go::after {
  content: '';
  position: absolute;
  inset: 0;
}

.visit-what { margin: 0; }

/* One chip, drawn as Home's card draws it: brass with the clock while it
   waits on somebody, fir with the tick once settled, plain for an ending. */
.visit-chip {
  align-self: flex-start;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  margin-block-start: 3px;
  padding: 2px 8px;
  border-radius: 99px;
  font-size: 12px;
  font-weight: 600;
  color: var(--fir);
  background: color-mix(in srgb, var(--fir) 9%, var(--card));
  border: 1px solid color-mix(in srgb, var(--fir) 22%, var(--card));
}

.visit-waiting .visit-chip {
  color: var(--brass);
  background: color-mix(in srgb, var(--brass) 10%, var(--card));
  border-color: color-mix(in srgb, var(--brass) 30%, var(--card));
}

.visit-ended .visit-chip {
  color: var(--sub);
  background: var(--raised);
  border-color: var(--line);
}

.visit-end {
  flex: none;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 4px;
}

.visit-money s { color: var(--struck); }

.visit-money b { color: var(--fir); font-weight: 700; }

/* *Book again* sits above the stretched way in, as its own link. */
.visit-again {
  position: relative;
  z-index: 1;
  padding: 4px 0;
  font-size: 13.5px;
  font-weight: 600;
  color: var(--fir);
  text-decoration: none;
}

.visit-more {
  font-size: 20px;
  line-height: 1;
  color: var(--faint);
}

.visit-fold { margin: 14px 0 0; }

.visit-fold summary {
  list-style: none;
  text-align: center;
  cursor: pointer;
}

.visit-fold summary::-webkit-details-marker { display: none; }

.visit-fold-see {
  color: var(--fir);
  font-weight: 600;
}

.visits-foot {
  text-align: center;
  margin: 22px 0 0;
}

.visits-empty {
  text-align: center;
  padding-block: 64px 24px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
}

.visits-empty svg { margin-block-end: 24px; }

.visits-empty p { margin: 0; max-inline-size: 30ch; }

.visits-empty .visits-empty-yours { font-weight: 600; color: var(--ink); }

/* past-A: the empty Past tab — the mark, the line, an outline button. */
.past-empty { padding-block: 48px 0; }
.past-empty svg { margin-block-end: 16px; }
/* past-A: a centred button sized to its words, at least the frame's 200. */
.past-empty .past-empty-go {
  margin-block-start: 12px;
  inline-size: auto;
  min-inline-size: 200px;
  padding-inline: 24px;
  block-size: 44px;
  font-size: 15px;
  color: var(--ink);
  border-color: var(--ink);
}

/* **You** (frame 9-02): the name at 34, the standing under it at 13 with the
   rate in fir, then plain rows — a 15/600 title, a line, a chevron in fir —
   separated by hairlines rather than boxed. */
.you-head { margin-block-start: 18px; }

/* **You, as the founder picked it** (Round 2 A, `#r6`): her initial in a fir
   circle beside her name and her rate, then four groups under brass labels. */
.you-head-a {
  display: flex;
  align-items: center;
  gap: 14px;
}

.you-av {
  flex: none;
  inline-size: 52px;
  block-size: 52px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  background: var(--fir);
  color: var(--on-fir);
  font-family: var(--display);
  font-weight: 600;
  font-size: 26px;
  line-height: 1;
}

.you-grp {
  margin: 18px 0 -6px;
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--brass);
}

.you-head .greet { font-size: 38px; margin: 0; }

.you-head .you-standing {
  margin: 4px 0 0;
  font-size: 15px;
}

.you-head .you-standing b {
  color: var(--fir);
  font-weight: 600;
}

/* The foot: her gift in rose, the friend to bring in fir. */
/* **How the visit was** (A3, the founder, 23–24 Sep 2026). Three drawn faces
   as full-width rows, one tap each; *What did you love?* opens under *Loved it*
   alone; the chips are buttons she taps. The faces are the kit's line, never a
   platform's emoji, so they read the same on every phone. */
.fb .fb-head {
  margin: 0 0 12px;
  font-family: var(--display);
  font-weight: 600;
  font-size: 22px;
  line-height: 1.2;
  color: var(--ink);
}

.fb .fb-faces { display: flex; flex-direction: column; gap: 8px; }

.fb .fb-face {
  display: flex;
  align-items: center;
  gap: 12px;
  inline-size: 100%;
  padding: 10px 14px;
  border: 1.2px solid var(--line);
  border-radius: 12px;
  background: var(--card);
  color: var(--fir);
  font-family: var(--ui);
  font-size: 15px;
  font-weight: 600;
  text-align: start;
  cursor: pointer;
}

.fb .fb-face span { color: var(--ink); }

.fb .fb-face input { position: absolute; opacity: 0; pointer-events: none; }

.fb .fb-face:has(input:checked) {
  border-color: var(--fir);
  background: color-mix(in srgb, var(--fir) 7%, var(--card));
}

.fb .fb-face:has(input:focus-visible) { outline: 2px solid var(--fir); outline-offset: 2px; }

/* *Loved it* in the kit's rose; *Not quite* in brass, never red. */
.fb .fb-mark-loved { color: var(--rose); }
.fb .fb-mark-not_quite { color: var(--brass); }

.fb .fb-loved { display: none; margin-block-start: 14px; }

.fb .fb-form:has(input[value="LOVED"]:checked) .fb-loved { display: block; }

.fb .fb-prompt { margin: 0 0 8px; font-size: 14px; font-weight: 600; color: var(--text); }

.fb .fb-chips { display: flex; flex-wrap: wrap; gap: 8px; }

.fb .fb-chip {
  display: inline-flex;
  align-items: center;
  padding: 7px 12px;
  border: 1.2px solid var(--line);
  border-radius: var(--radius-chip);
  background: var(--card);
  color: var(--text);
  font-size: 13.5px;
  font-weight: 600;
  cursor: pointer;
  text-decoration: none;
}

.fb .fb-chip input { position: absolute; opacity: 0; pointer-events: none; }

.fb .fb-chip:has(input:checked) {
  border-color: var(--fir);
  background: var(--fir);
  color: var(--on-fir);
}

.fb .fb-chip:has(input:focus-visible) { outline: 2px solid var(--fir); outline-offset: 2px; }

/* *The bill* is a door, not a reason: it reads as a link to F-21. */
.fb .fb-door { color: var(--fir); border-style: dashed; }

.fb .fb-note { margin-block-start: 10px; inline-size: 100%; }

.fb .fb-owner { margin: 8px 0 0; }

.fb .fb-acts { display: flex; gap: 10px; margin-block-start: 14px; }

.fb .fb-acts > * { flex: 1; }

.fb .fb-acts form { margin: 0; }

.fb .fb-acts .btn { inline-size: 100%; }

.fb .fb-private {
  display: flex;
  align-items: center;
  gap: 6px;
  margin: 10px 0 14px;
  font-size: 13.5px;
  color: var(--sub);
}

.fb.fb-thanks p { margin: 0; font-size: 15px; color: var(--text); }

/* The next morning: the salon's face, *Yesterday at …*, a cross, then the
   three faces — one tap answers. */
.fb-morning .fb-mhead { display: flex; align-items: center; gap: 12px; margin-block-end: 12px; }

.fb-morning .fb-mhead form { margin: 0 0 0 auto; }

.fb-morning .fb-mwho { min-inline-size: 0; }

.fb-morning .fb-mtitle { margin: 0; font-size: 16px; font-weight: 600; color: var(--ink); }

.fb-morning .fb-mwho .s { margin: 1px 0 0; }

.fb-morning .fb-tile {
  flex: none;
  inline-size: 40px;
  block-size: 40px;
  border-radius: 10px;
  border: 1px solid var(--line);
  background: var(--card);
  display: grid;
  place-items: center;
  overflow: hidden;
  font-family: var(--display);
  font-weight: 600;
  font-size: 18px;
  line-height: 1;
  color: var(--face-ink, var(--fir));
}

.fb-morning .fb-tile img { inline-size: 100%; block-size: 100%; object-fit: cover; }

.fb-morning .fb-close {
  display: grid;
  place-items: center;
  inline-size: 32px;
  block-size: 32px;
  border: 0;
  border-radius: 99px;
  background: transparent;
  color: var(--sub);
  cursor: pointer;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme='light']) .fb-morning .fb-tile { color: var(--ink); }
}

:root[data-theme='dark'] .fb-morning .fb-tile { color: var(--ink); }

/* **The public line** on a salon's card and page: plain text and two quiet
   words — never a badge, never stars. */
.fb-public { display: block; margin-block-start: 6px; }

.fb-public .fb-pline {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 13.5px;
  color: var(--text);
}

.fb-public .fb-mark-loved { color: var(--rose); }

.fb-public .fb-pchips { display: flex; flex-wrap: wrap; gap: 6px; margin-block-start: 5px; }

.fb-public .fb-pchips span {
  padding: 2px 9px;
  border: 1px solid var(--line);
  border-radius: 99px;
  font-size: 12.5px;
  color: var(--sub);
}

/* **Her other live visits, as the same card, compact** (UX audit R13, the
   founder's yes, 24 Sep 2026): the face, the name, the chip and the time,
   smaller and closer than the card above, which stays the one to act on. */
.vc.vc-compact { margin-block-start: 10px; padding: 14px; }
.vc.vc-compact .vc-time { font-size: 20px; }
.vc.vc-compact .vc-line { color: var(--ink); margin-block-start: 4px; }

/* **The invitation card** (22 Sep 2026): *How it works* is a `<details>`
   that opens the three rules in place with no script — both amounts in the
   serif, the rule under it, two small verbs side by side. The link sits
   beside the disclosure rather than inside its summary (the founder's AA
   ruling, 5 Oct 2026), so the card wraps: the words and the rules take a
   whole line each, the two verbs share one, and the rules show while the
   disclosure is open. */
.card.invite {
  margin-block-start: 14px;
  display: flex;
  flex-wrap: wrap;
  column-gap: 8px;
}
.invite-say { flex: 0 0 100%; display: flex; flex-direction: column; gap: 6px; margin-block-end: 12px; }
.card.invite > .btn,
.invite-how { flex: 0 0 calc(50% - 4px); min-inline-size: 0; }
.invite-how > summary { list-style: none; }
.invite-how > summary::-webkit-details-marker { display: none; }
.invite-how:not([open]) ~ .invite-rules { display: none; }
.invite-rules { flex: 0 0 100%; margin: 12px 0 0; padding-inline-start: 20px; display: grid; gap: 6px; }
.invite-rules li { font-size: 14.5px; line-height: 21px; color: var(--text); }

/* **The composer** (frame 11-01; the founder's 6A since 26 Sep 2026): the
   head, the ledger with leaders, then the total and the verb — whose rows
   and the two panes are the desk's own, in `portal.css`. */
.composer-head h1 { font-size: 30px; }

.plr-ledger { margin-block-start: 16px; }

.plr {
  display: flex;
  align-items: baseline;
  gap: 8px;
  padding: 11px 6px;
  border-block-end: 1px solid var(--line);
  color: var(--ink);
  text-decoration: none;
}

.plr .nm { font-size: 15px; }

.plr .lead {
  flex: 1;
  border-block-end: 1px dotted var(--line);
  transform: translateY(-4px);
}

.plr .num {
  font-size: 16px;
  font-weight: 600;
}

/* A corrected bill's struck lines wear the one struck rule (`.struck .k` /
   `.struck .v`); the row only sets their colour. */
.plr.struck .k,
.plr.struck .v { color: var(--struck); }

.send-bill { margin-block-start: 14px; }

/* Review: the crest row over the stack, and the way back under the verb. */
.rv-head {
  display: flex;
  align-items: center;
  gap: 11px;
}

/* **A thumb is the plate, small.** 44 square at r12, the painting cropped
   to it — the review's head, and the row marks on Visits (frame 9). */
.thumb {
  display: inline-block;
  inline-size: 44px;
  block-size: 44px;
  border-radius: 12px;
  overflow: hidden;
  flex: none;
}

.thumb svg {
  display: block;
  inline-size: 100%;
  block-size: 100%;
}

/* **One moment — it's you** (frame 5-01). The tag over a number field with
   the country as a fixed prefix, the sentence, the one verb. */
.youstep { display: flex; flex-direction: column; gap: 12px; }

.youstep .tag { margin: 0; }

.phonerow {
  display: flex;
  align-items: center;
  gap: 12px;
}

.phonerow .cc {
  font-weight: 700;
  font-size: 16px;
  color: var(--ink);
}

.phonerow .phonefield {
  flex: 1;
  border: 0;
  border-block-end: 1px solid var(--line);
  border-radius: 0;
  background: transparent;
  padding-inline: 0;
  font-size: 17px;
}

.phonerow .phonefield:focus {
  outline: none;
  border-block-end-color: var(--fir);
}

.youstep .youstep-say { margin: 0; }

.youstep .youstep-say b { color: var(--ink); font-weight: 600; }

.rv-head p { margin: 0; }

/* **Where she is in the request** (#3 A): a back arrow and *Step 2 of 4*,
   then a bar of the steps with the ones taken in fir — the app's StepBar. */
.stepbar {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-block: 0 8px;
}

.stepbar-back {
  display: inline-flex;
  padding-block: 4px;
  padding-inline-end: 4px;
  color: var(--ink);
}

.stepbar .s { margin: 0; }

.stepsegs {
  display: flex;
  gap: 4px;
  list-style: none;
  margin: 0 0 14px;
  padding: 0;
}

.stepsegs li {
  flex: 1;
  block-size: 3px;
  border-radius: 2px;
  background: var(--line);
}

.stepsegs li.on { background: var(--fir); }

/* **Check your booking** (the founder's #1 B, revised, 23 Sep 2026): the
   day on its own line, every service a row with both prices, two totals side
   by side, the saving under them, and the hold as three dots. */
.ck-when { margin-block: 12px 0; }

/* Split visit D: when she will finish, and any wait, under the hour. */
.ck-finish { margin-block: 2px 0; color: var(--sub); }

.ck-list { display: flex; flex-direction: column; }

.ck-heads {
  display: flex;
  justify-content: space-between;
  margin: 0 0 4px;
}

.ck-row {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  padding-block: 8px;
  border-block-end: 1px solid var(--line);
}

.ck-row:last-child { border-block-end: 0; }

/* The line a correction struck is muted whole (G-416; UX measured the price
   at full ink beside a muted name): its figure as its name. */
.ck-row.struck .num { color: var(--faint); }

.ck-totals {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
  margin-block-start: 14px;
}

.ck-box {
  border: 1px solid var(--line);
  border-radius: 12px;
  padding: 10px 12px;
  text-align: center;
}

.ck-box .tag { margin: 0; }

.ck-box .ck-fig {
  margin: 4px 0 0;
  font-family: var(--price-face, var(--display));
  font-weight: var(--price-weight, 400);
  font-size: 26px;
  line-height: 1;
  color: var(--sub);
}

/* **Only buttons are filled** (Round 2 A, `#r3`): the *With MIORA* box read as
   a button, filled dark. A pale fir tint with a fir outline states her price
   and invites no tap. */
.ck-box.ours {
  background: color-mix(in srgb, var(--fir) 9%, var(--card));
  border: 1.5px solid var(--fir);
}

.ck-box.ours .tag,
.ck-box.ours .ck-fig { color: var(--fir); }

/* **The bar that does not move**: fixed to the bottom, the page's width, over
   everything the review scrolls — and the page leaves room under its end,
   **footer included**: the room was the main's, so the footer's *Terms*
   ("By requesting, you agree") sat under the bar (the founder's AA ruling,
   5 Oct 2026). The body carries the bar's height now. */
body:has(.ck-bar) { padding-block-end: calc(108px + env(safe-area-inset-bottom)); }

.ck-bar {
  position: fixed;
  inset-inline: 0;
  inset-block-end: 0;
  z-index: 5;
  padding: 10px var(--gutter) calc(12px + env(safe-area-inset-bottom));
  background: var(--card);
  border-block-start: 1px solid var(--line);
  box-shadow: 0 -6px 14px rgb(0 0 0 / 6%);
}

.ck-bar > * {
  max-inline-size: calc(44rem - 2 * var(--gutter));
  margin-inline: auto;
}

.ck-bar .btn { display: block; inline-size: 100%; }

.ck-bar-line {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  margin: 0 auto 8px;
  font-size: 13.5px;
  color: var(--sub);
}

.ck-bar-line b { color: var(--ink); font-size: 15px; }

/* **Her number, said under the verb** (card 4A): the faint centred line the
   app draws as zero_today, and the bar's room grows by its one line. */
.ck-bar .ck-bar-number {
  margin: 8px auto 0;
  text-align: center;
  font-size: 13.5px;
  line-height: 20px;
}

body:has(.ck-bar-number) { padding-block-end: calc(136px + env(safe-area-inset-bottom)); }

.ck-less {
  text-align: center;
  margin: 10px 0 0;
  font-weight: 600;
  color: var(--fir);
}

.ck-steps {
  list-style: none;
  margin: 16px 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.ck-step {
  position: relative;
  padding-inline-start: 22px;
}

.ck-step::before {
  content: "";
  position: absolute;
  inset-inline-start: 2px;
  inset-block-start: 5px;
  inline-size: 11px;
  block-size: 11px;
  border-radius: 50%;
  border: 1.5px solid var(--fir);
}

.ck-step.on::before { background: var(--fir); }

.rv-head .rv-item {
  font-weight: 600;
  font-size: 16px;
  color: var(--ink);
}

.backline {
  text-align: center;
  margin-block: 13px 0;
}

.linkback {
  font-size: 13.5px;
  font-weight: 500;
  color: var(--fir);
  text-decoration: underline;
  text-underline-offset: 3px;
}

/* The salon said yes to this hour in advance, so the request confirms itself.
   The tag sits below the numeral rather than inside it — a slot is a time, and
   a word crowding the time is a time that takes longer to read.
   **Centred both ways** (UX's F139, 11 Oct 2026): `inset-inline-start: 50%`
   with a leftward translate put it off the slot's edge in Arabic; both insets
   at zero and auto margins centre it in either direction. The word is the
   template's now, not `content:`. */
.slot .slot-inst {
  position: absolute;
  inset-block-end: -7px;
  inset-inline: 0;
  margin-inline: auto;
  inline-size: max-content;
  line-height: 1.3;
  font-family: var(--ui);
  font-size: 11px;
  letter-spacing: 0.12em;
  font-weight: 700;
  color: var(--fir);
  background: var(--ground);
  padding-inline: 5px;
  border-radius: 99px;
  border: 1px solid var(--line);
}

.slot.dis {
  opacity: 0.35;
  pointer-events: none;
}

/* **U2, readable when shut** (the founder's 1A, 18 Oct 2026): a closed day
   and a taken time keep their place on a plain fill, their words in `--sub`
   at about 5:1, not faded to a third. No reason on a time: it is simply not
   offered. AFTER_APPLE's skin. */
:root.c0 .dc.shut,
:root.c0 .slot.dis {
  opacity: 1;
  background: var(--band);
  border-color: var(--band);
  color: var(--sub);
}
/* **R11 A** (the founder's pick, 18 Oct 2026): the reason under a time she
   cannot ask for, *Full* or *Too soon*, on U2's plain fill. */
.slot-note {
  display: block;
  font-size: 11px;
  font-weight: 500;
  color: var(--sub);
}
/* Under the time, not beside it, so a third of 300 still holds both. */
:root.c0 .slotgrid .chip.slot:has(.slot-note) {
  flex-direction: column;
  align-items: center;
  padding-block: 7px;
}
:root.c0 .dc.shut .dw,
:root.c0 .dc.shut .dn,
:root.c0 .dc.shut .dr {
  opacity: 1;
  color: var(--sub);
}

/* --- Two quiet actions, side by side ---------------------------------- */
/* The ticket's second row: never the primary verb, always a pair. */

.qact {
  display: flex;
  gap: 10px;
  margin-block-start: 12px;
}

.qact > * {
  flex: 1;
  margin: 0;
}

/* --- Two prices on one line ------------------------------------------- */
/* F-12a: the salon's price and hers, side by side. The posted figure is
   quieter **and struck** — see the amendment in this file's header, which
   lifted the law's strikethrough clause on the evidence of the two pages set
   beside each other. The rule is what makes the pair legible as a pair: it is
   not a discount being advertised, it is what the salon charges beside what
   she pays, and without the mark those are two numbers in a row. */

.prices {
  display: inline-flex;
  align-items: baseline;
  gap: 10px;
  font-variant-numeric: tabular-nums lining-nums;
}
/* **S6** (F224, the founder's yes, 14 Oct 2026; AFTER_APPLE's skin): her
   price first, bold and green, then the struck salon price — on every pair. */
:root.c0 .prices b { font-weight: 700; color: var(--fir); }

.prices .was {
  font-size: var(--t-caption);
  /* Quieter than `--sub`: struck, this figure is being set aside, and at the
     body weight it competed with the one she pays. It was set at 3.1:1, under
     the floor, as text that need not be read; the founder's AA ruling (5 Oct
     2026) says a price is read, so `--struck` clears 4.5:1 now and the strike
     and the caption size carry the setting-aside. */
  color: var(--struck);
  text-decoration: line-through;
  text-decoration-thickness: 1px;
}

/* --- Explore: the search, and two rows of tags ------------------------- */
/* The title is the summary of a disclosure whose body is the search field, so
   the icon opens the field *in place of the title* (frame 2-02) with nothing
   loaded. Open, the title stands aside and the field takes its line. */
.explore .search { border: 0; padding: 0; margin: 0; }
.explore .search > summary {
  list-style: none;
  display: flex;
  align-items: center;
  justify-content: space-between;
  cursor: pointer;
}
.explore .search > summary::-webkit-details-marker { display: none; }
.explore .search > summary .greet { margin: 0; }
.explore .search-mark {
  inline-size: 40px;
  block-size: 40px;
  padding: 9px;
  border-radius: 99px;
  border: 1.2px solid var(--line);
  color: var(--fir);
  background: var(--card);
  flex: 0 0 auto;
}
.explore .search[open] > summary .greet { display: none; }
.explore .search[open] > summary { justify-content: flex-end; }
.explore .search-field {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-block-start: -40px;
  padding-inline-end: 52px;
  min-block-size: 40px;
}
.explore .search-field input {
  flex: 1;
  min-inline-size: 0;
  border: 0;
  background: transparent;
  font-family: var(--ui);
  font-size: 18px;
  color: var(--ink);
  padding: 0;
}
.explore .search-field input:focus { outline: none; }
.explore .search-clear {
  color: var(--sub);
  text-decoration: none;
  font-size: 22px;
  line-height: 1;
}
/* **M1 B** (F224, behind AFTER_APPLE): the field is a round pill with a fir
   ring, not the browser's blue box, and the five service chips sit under it
   while it is open. */
.explore .search-pill {
  flex: 1;
  min-inline-size: 0;
  display: flex;
  align-items: center;
  gap: 8px;
  min-block-size: 44px;
  padding-inline: 16px 12px;
  border: 1.5px solid var(--fir);
  border-radius: 99px;
  background: var(--card);
}
.explore .search-pill:focus-within { box-shadow: 0 0 0 1.5px var(--fir); }
.explore .search-pill input { font-size: 17px; }
.explore .search-chips { margin-block-start: 10px; }

/* Two rows, each scrolling sideways on a phone the way the frame's do — the
   fourth area chip is cut at the edge in 2-01, which is the affordance. */
.explore .tags {
  display: flex;
  gap: 8px;
  overflow-x: auto;
  scrollbar-width: none;
  margin-block-start: 12px;
  padding-block-end: 2px;
}
.explore .tags::-webkit-scrollbar { display: none; }
.explore .tags + .tags { margin-block-start: 10px; }
.explore .tags .chip { flex: 0 0 auto; }
/* **M1 at 320** (UX's walk, 14 Oct 2026; AFTER_APPLE's skin): `.cluster`
   wraps, so the five service chips stood in a column and no salon reached the
   first screen. Each group keeps one row that scrolls sideways, as the app's
   do; the row scrolls, never the page. */
:root.c0 .explore .tags { flex-wrap: nowrap; max-inline-size: 100%; }
:root.c0 .explore .tags .chip { white-space: nowrap; }
.explore .grove { margin-block-start: 6px; }

/* --- The salon page (frame 3-01) --------------------------------------- */
/* The plate, full-bleed, where the tinted band was: the page bleeds it past
   the gutters because a painting with a margin is a picture in a frame, and
   the frame runs it to the edge. 230px on a phone. */
.plate-head {
  position: relative;
  block-size: 230px;
  overflow: hidden;
  margin-inline: calc(-1 * var(--gutter));
  /* Flush under the header: the page's own 20px top padding was a band of
     paper between the chrome and the painting. */
  margin-block-start: -20px;
}

/* The leader was a printed list's device — service to price on a dotted rule
   — and the frame's rows have none: the pair sits at the end of the row and
   the hairline under it is the only line. */
.ledger .lr::after { content: none; }
/* `form.ledger` outranks the leader's own `.ledger .lr::after`, which is
   declared later and would otherwise win the strut back. */
form.ledger .lr::after { content: none; display: none; }

.plate-head svg,
.plate-head img {
  position: absolute;
  inset: 0;
  inline-size: 100%;
  block-size: 100%;
  object-fit: cover;
}

.salon-lock { margin-block-start: 22px; }

/* **The heart beside her salon's name** (favourites, 24 Sep 2026): outlined
   until the salon is one of her favourites, filled in rose once it is. */
.salon-title {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 12px;
}

.salon-heart { margin: 0; }

.salon-heart-btn {
  display: grid;
  place-items: center;
  inline-size: 44px;
  block-size: 44px;
  border: 1px solid var(--line);
  border-radius: 50%;
  background: var(--card);
  color: var(--sub);
  cursor: pointer;
}

.salon-heart-btn svg path { fill: none; }

.salon-heart-btn.on { color: var(--rose); border-color: var(--rose-line); }

.salon-heart-btn.on svg path { fill: currentColor; }

.salon-lock .nm {
  display: flex;
  align-items: baseline;
  gap: 10px;
}

.salon-lock .nm .n {
  font-family: var(--display);
  font-weight: 600;
  font-size: 38px;
  line-height: 1.05;
  letter-spacing: -0.014em;
  color: var(--ink);
  margin: 0;
}

.salon-lock .nm .arn {
  font-size: 20px;
  color: var(--brass);
}

.salon-lock .salon-line { margin: 0; }

/* **A fact and its mark.** The place with a pin, the hours with a clock —
   16px strokes in the caption ink, sitting on the first line's cap height,
   and the words unchanged beside them. */
.facts {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.salon-facts { margin-block-start: 10px; }

.fact {
  display: flex;
  align-items: flex-start;
  gap: 8px;
}

.fact .mark {
  flex: none;
  color: var(--sub);
  margin-block-start: 3px;
}

.fact p { margin: 0; }

/* The second sentence of the card step: when the money moves. */
.cardstep .card-held { margin-block-start: 6px; }

/* *Prices*, and beside it the six words that state the two columns — in the
   display italic, small, because it is a note on a title rather than a
   heading of its own. */
.prices-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 4px 12px;
  margin-block: 22px 8px;
}

.prices-head .sect { margin: 0; }

/* The note wraps. It was `nowrap` while it was six words; v13's sentence
   (*Prices when you book through MIORA…*) is fourteen, and one unbreakable
   line of it widened a 393px page to 631 with the figures off the edge. */
.prices-head .prices-note {
  font-family: var(--display);
  font-style: italic;
  font-size: 17px;
  line-height: 1.35;
  color: var(--sub);
  text-align: end;
  text-wrap: balance;
}

.prices-head .prices-note b,
.prices-head .prices-note .num { font-style: normal; }

/* **F220 · the gift line as a tag** (the founder's "the gift line i pick C",
   14 Oct 2026; UX's frames at 390 and 320): a cream tag on its own line at
   the left, the gift mark in brass with a gold-leaf bow, *Invited by Noora*
   at 600 and the rest at 400. No rose on it. The frame's 6 above comes on
   top of the head's own 8 (the two would collapse to 8), and the space under
   it is the frame's, down to the chips. */
.gift-tag {
  display: flex;
  inline-size: fit-content;
  max-inline-size: 100%;
  align-items: center;
  gap: 8px;
  margin: 14px 0 18px;
  padding: 7px 12px 7px 10px;
  border-radius: 10px;
  background: var(--raised);
  color: var(--ink);
  font-family: var(--ui);
  font-size: 13.5px;
  line-height: 19px;
}

.gift-tag svg {
  flex: none;
  stroke: var(--brass);
  stroke-width: 1.6;
  stroke-linejoin: round;
}

.gift-tag .bow {
  fill: var(--gold-leaf);
  stroke-width: 1.3;
}

.gift-tag b { font-weight: 600; }

/* **How it works, beside Prices** (Beanz pick 4, 12 Oct 2026): a fir link
   on the heading's right, and the sheet it opens. `:target` opens it, so it
   works with no script; the veil and *Got it* both go back to `#prices`. */
.prices-how {
  font-size: 14px;
  font-weight: 600;
  color: var(--fir);
  text-decoration: underline;
  text-underline-offset: 3px;
}

.how-miora { display: none; }
.how-miora:target {
  display: block;
  position: fixed;
  inset: 0;
  z-index: 95;
}

.how-miora-veil {
  position: absolute;
  inset: 0;
  background: color-mix(in srgb, var(--ink) 35%, transparent);
}

.how-miora > .sheet {
  position: absolute;
  inset-inline: 0;
  inset-block-end: 0;
  max-inline-size: 520px;
  margin-inline: auto;
  display: grid;
  gap: 14px;
  padding-block-end: calc(24px + env(safe-area-inset-bottom, 0px));
}

.how-miora-title {
  font-family: var(--display);
  font-size: 26px;
  font-weight: 600;
  line-height: 1.1;
  margin: 0;
}

.how-miora-steps {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 12px;
}

.how-miora-steps li {
  display: grid;
  grid-template-columns: 44px minmax(0, 1fr);
  gap: 12px;
  align-items: center;
  font-size: 16px;
  font-weight: 500;
  color: var(--ink);
}

.how-miora-steps svg { inline-size: 44px; block-size: 44px; }
.how-miora-steps svg .disc { fill: var(--band); stroke: none; }
.how-miora-steps svg rect,
.how-miora-steps svg path { fill: none; stroke: var(--fir); stroke-width: 1.6; }
.how-miora-steps svg .tick { stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.how-miora-steps svg text {
  font-family: var(--display);
  font-size: 13px;
  font-weight: 600;
  fill: var(--fir);
}

.how-miora .btn { justify-self: stretch; text-align: center; }

/* **Help's six questions** (Beanz (c), 12 Oct 2026): a row each, a tap to
   open, the chevron turning as `.how`'s does. */
.help-asked { padding-block: 4px; }
.help-q + .help-q { border-block-start: 1px solid var(--rule); }
.help-q > summary {
  list-style: none;
  display: flex;
  justify-content: space-between;
  gap: 12px;
  padding-block: 12px;
  font-size: 15.5px;
  font-weight: 600;
  color: var(--ink);
  cursor: pointer;
}
.help-q > summary::-webkit-details-marker { display: none; }
.help-q > summary::after { content: '›'; color: var(--faint); }
.help-q[open] > summary::after { content: '⌄'; }
.help-q > summary:focus-visible { outline: 2px solid var(--fir); outline-offset: 3px; }
.help-q > .note { margin: 0 0 12px; }

/* Help's *How it works* on You: the same three steps, numbered. */
.how-steps {
  margin-block: 8px 0;
  padding-inline-start: 20px;
  display: grid;
  gap: 4px;
}

/* **The chips over a list.** The list's own categories, in the salon's order,
   as a rail of chips that stays under the header while the rows scroll —
   a full menu is not one scroll, and the chip a thumb is on is the one thing
   that says where in it she is. The rail bleeds to the gutters and hides its
   scrollbar, like the ribbon; the chip is the chip atom; `.on` is the atom's
   own fir. Logical properties throughout, so Arabic mirrors it for free. */
.cats {
  position: sticky;
  inset-block-start: var(--stuck-top, 0px);
  z-index: 2;
  display: flex;
  gap: 8px;
  overflow-x: auto;
  /* **A scroller sizes to its box, not its chips.** As a grid item's child
     the rail's min-content — every chip side by side — widened the column to
     711px in a 393px viewport, and the whole page scrolled sideways with the
     prices running off the edge. Zero width with a minimum of the box is the
     one declaration that stops an overflowing child sizing its parent. */
  inline-size: 0;
  min-inline-size: calc(100% + var(--gutter) * 2);
  box-sizing: border-box;
  scroll-padding-inline: var(--gutter);
  padding-block: 10px;
  padding-inline: var(--gutter);
  margin-inline: calc(var(--gutter) * -1);
  margin-block-end: 4px;
  background: var(--ground);
  scrollbar-width: none;
}

.cats::-webkit-scrollbar {
  display: none;
}

/* At width the chips wrap (the founder's v5 mockup) rather than run off
   the column with a chip cut in half; on a phone the rail scrolls. */
@media (min-width: 1000px) {
  .cats {
    flex-wrap: wrap;
    overflow-x: visible;
  }
}

.cats .chip {
  flex: 0 0 auto;
}

/* **A hidden row is hidden.** The rows the chips filter carry their own
   `display` — the ledger's flex, the desk's grid — and an author `display`
   outranks the user agent's `[hidden]`, so a filtered row stayed on screen
   with the chip lit. Said once, for every row a chip can hide. */
[data-cat][hidden],
.cat-head[hidden] {
  display: none;
}

/* The small head where the category changes under *All*: the tag size, in
   `sub`, both scripts on one line. It is a printed menu's own rule, not a
   card, so it carries no frame. */
.cat-head {
  display: flex;
  align-items: baseline;
  gap: 10px;
  padding: 16px 14px 6px;
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--sub);
}

.cat-head [lang='ar'] {
  font-family: var(--arabic);
  font-size: 13px;
  letter-spacing: 0;
  text-transform: none;
  font-weight: 600;
}

/* Under the list: 11.5 in `sub`, as the frame sets it. */
.prices-foot {
  margin: 8px 0 0;
  font-size: 13.5px;
  line-height: 1.5;
  color: var(--sub);
}

/* **Where** (frame 3-01). The title is a section title; the line is body at
   14 with the one verb in fir; the hours beneath at 12.5 in `sub`, numerals
   lining. */
.where-head { margin-block: 26px 10px; }

.where-line {
  margin: 0;
  font-size: 16px;
  line-height: 1.55;
  color: var(--text);
}

.where-line .where-go {
  color: var(--fir);
  font-weight: 600;
  text-decoration: none;
}

.where-hours {
  margin: 0;
  font-size: 13.5px;
  line-height: 1.5;
  color: var(--sub);
  font-variant-numeric: tabular-nums lining-nums;
}

/* A price row, as the frame sets it: the name at 15/500, its Arabic under it
   at 11 in the reading face, the pair on the right — the salon's struck at
   10.5, hers in the display face at 22 in fir. */
.ledger .lr > .k {
  flex: 1 1 auto;
  font-size: 16px;
  font-weight: 500;
  color: var(--ink);
}

.ledger .lr .k .why {
  display: block;
  font-size: 13.5px;
  color: var(--sub);
  margin-block-start: 2px;
}

.ledger .lr .was {
  font-size: 13.5px;
  color: var(--struck);
}

.ledger .lr .prices .v {
  font-family: var(--price-face, var(--display));
  font-weight: var(--price-weight, 700);
  font-size: 26px;
  line-height: 1;
  color: var(--fir);
  font-variant-numeric: tabular-nums lining-nums;
}

/* The dock's line: the chosen price on the left, the two sentences on the
   right, and the verb across the bottom. */
.ask .dockline {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 14px;
  margin-block-start: 10px;
}

.ask .dockpick { display: flex; flex-direction: column; gap: 2px; }

.ask .dockpick .pn { font-size: 15px; color: var(--sub); }

.ask .dockpick .pp {
  display: flex;
  align-items: baseline;
  gap: 6px;
}

.ask .dockpick .pp s { font-size: 13.5px; color: var(--struck); }

.ask .dockpick .pp b {
  font-family: var(--price-face, var(--display));
  font-weight: var(--price-weight, 700);
  font-size: 26px;
  line-height: 1;
  color: var(--fir);
}

.ask .docksay {
  font-size: 13.5px;
  line-height: 1.45;
  color: var(--sub);
  text-align: end;
}

/* --- The salon card ---------------------------------------------------- */
/* **One card, four places.** Discovery, Explore, the salon page's head and
   Home all draw the same object, and the handover says so in as many words:
   *build the salon card once and reuse it.* The garden card it replaces put a
   26px sprig on a tinted wash and dissolved a price ledger under it; this puts
   172px of painted plate above a name and states three prices flat.

   The plate is illustration and the caption is information. Nothing in the
   caption sits on the painting — a 12.5px line over petals is a line the
   contrast budget never agreed to, which is the same note the paper grain
   carries. */

.sc {
  border-radius: 20px;
  overflow: hidden;
  background: var(--card);
  border: 1px solid var(--line);
  margin-block-start: 16px;
  position: relative;
  display: block;
  text-decoration: none;
  color: inherit;
}

.sc .plate {
  /* **A `<span>` is an inline box and ignores a height.** The card is an `<a>`,
     so every part of it is phrasing content — the plate collapsed to 18px, the
     line-height of its own empty line, and the painting rendered into a sliver
     nobody would have called a bug from the markup. */
  display: block;
  block-size: 172px;
  position: relative;
  overflow: hidden;
}

.sc .caption,
.sc .nm,
.sc .pills,
.sc .btn { display: flex; }

.sc .caption { display: block; }

.sc .plate svg,
.sc .plate img {
  position: absolute;
  inset: 0;
  inline-size: 100%;
  block-size: 100%;
  object-fit: cover;
}

.sc .caption { padding: 14px 18px 16px; }

/* The empty circle's card: the painting and caption open the room; the foot
   is the ring-filling verb and the quiet way past it. */
.sc.sc-join .sc-open {
  display: block;
  color: inherit;
  text-decoration: none;
}

.sc.sc-join .sc-foot {
  padding-block-start: 0;
  text-align: center;
}

.sc.sc-join .sc-foot .btn { inline-size: 100%; }

.sc.sc-join .sc-foot .linkback {
  display: inline-block;
  margin-block-start: 12px;
}

/* **The card's three services, one to a row** (#2 A): the whole name on the
   start side, the salon's figure struck beside hers on the end side. */
.sc .glines {
  display: flex;
  flex-direction: column;
  margin-block-start: 10px;
}

.sc .gline {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 12px;
  padding-block: 7px;
  border-block-end: 1px solid var(--line);
  font-size: 14.5px;
  color: var(--ink);
}

.sc .gline:last-child { border-block-end: 0; }

.sc .gline .gp { flex: none; display: inline-flex; gap: 6px; align-items: baseline; }

.sc .gline .gp s { font-size: 13px; color: var(--struck); }

.sc .gline .gp b { font-weight: 700; color: var(--fir); }

.sc .nm .n,
.sc .nm .arn { display: inline-block; }

/* The salon's own name, and its Arabic beside it on the same baseline. */
.sc .nm {
  display: flex;
  align-items: baseline;
  gap: 9px;
}

.sc .nm .n {
  font-family: var(--display);
  font-weight: 600;
  font-size: 30px;
  line-height: 1.08;
  letter-spacing: -0.012em;
  color: var(--ink);
}

/* **Gold, not the room's tint.** Concierge sets every Arabic name in one gold
   — the brass the rail already measured, since #8F723E reads 4.04:1 on a pill.
   A name that changed colour per salon was the tint doing a typeface's job. */
.sc .nm .arn {
  font-family: var(--arabic-display);
  font-size: 17px;
  color: var(--brass);
}

/* An event, and whether it is already hers. Both ride the plate, so both carry
   their own ground: a tracked cap over a painting is unreadable otherwise. */
.sc .ev,
.sc .yours {
  position: absolute;
  inset-block-start: 14px;
  border-radius: 99px;
  background: rgb(255 254 250 / 0.92);
  padding: 6px 11px;
  font-weight: 700;
  color: var(--fir);
}

.sc .ev {
  inset-inline-start: 14px;
  font-size: 11px;
  display: flex;
  align-items: center;
  gap: 6px;
}

.sc .ev i {
  inline-size: 6px;
  block-size: 6px;
  border-radius: 99px;
  background: var(--fir);
  font-style: normal;
}

.sc .yours {
  inset-inline-end: 14px;
  font-size: 11px;
}

/* **The heart for her favourite** (F212, the founder's "Yes, all", 14 Oct
   2026): with AFTER_APPLE on the word *yours* becomes the same heart the salon
   page saves her with, filled in fir on the plate's own ground. */
.sc .yours.heart {
  display: grid;
  place-items: center;
  padding: 6px;
  line-height: 0;
}

.sc .yours.heart svg path { fill: currentColor; }

/* Three prices, flat. **The fading ledger is retired**: a row that dissolves
   says *there is more* by making the last thing she reads unreadable, and the
   handover's own law is that the fade ends on a row. Three pills end on a row
   because there are three. */
.pills {
  display: flex;
  gap: 8px;
  margin-block-start: 12px;
}

.pill {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 1px;
  padding: 8px 10px;
  border-radius: 12px;
  background: var(--pill);
  min-inline-size: 0;
}

.pill .pn {
  font-size: 13.5px;
  color: var(--sub);
  font-weight: 600;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.pill .pp {
  display: flex;
  align-items: baseline;
  gap: 5px;
}

.pill .pp s {
  font-size: 13.5px;
  color: var(--struck);
}

.pill .pp b {
  font-family: var(--price-face, var(--display));
  font-size: 24px;
  font-weight: var(--price-weight, 700);
  line-height: 1;
  color: var(--fir);
  font-variant-numeric: tabular-nums lining-nums;
}

.sc .btn { margin-block-start: 12px; }

/* --- The garden: band, lockup, vine, pane, leaf ----------------------- */
/* **The page has a temperature.** Same information, same scale, same lining
   figures as the build it replaces — and a room rather than a template. Every
   piece here is drawn from the token set rather than from an image, so a theme
   change moves the flowers with the type and nothing is fetched to render a
   mood. The kit is `_garden.html`; this is where it sits on the page. */

/* The wash behind the name. It bleeds to the viewport edge because a tint that
   stops at the text column reads as a card, and a card is a component — this
   is supposed to be the room the page is in. */
.page:has(.band) {
  padding-block-start: 0;
}

.band {
  position: relative;
  overflow: hidden;
  margin-inline: calc(50% - 50vw);
  padding-block: 26px 22px;
  border-block-end: 1px solid var(--line);
  margin-block-end: 26px;
}

.band > .bandin {
  position: relative;
  z-index: 2;
  max-inline-size: 66rem;
  margin-inline: auto;
  padding-inline: var(--gutter);
  display: flex;
  align-items: flex-end;
  gap: 18px;
}

/* Six washes, one per salon, chosen by its name. Each fades to nothing before
   the right edge so the band lightens under the hours rather than boxing them. */
.tint-sand { background: linear-gradient(168deg, #FAF3E2 0%, #F6EAD0 62%, rgba(246, 234, 208, 0) 100%); }
.tint-rose { background: linear-gradient(168deg, #FCF1F2 0%, #F9E7EA 60%, rgba(249, 231, 234, 0) 100%); }
.tint-sage { background: linear-gradient(168deg, #F1F5EC 0%, #E6EEDF 60%, rgba(230, 238, 223, 0) 100%); }
.tint-brass { background: linear-gradient(168deg, #FAF2E0 0%, #F2E6C9 60%, rgba(242, 230, 201, 0) 100%); }
.tint-shell { background: linear-gradient(168deg, #FBF2EC 0%, #F6E7DB 60%, rgba(246, 231, 219, 0) 100%); }
.tint-olive { background: linear-gradient(168deg, #F5F4E6 0%, #ECEBD5 60%, rgba(236, 235, 213, 0) 100%); }

/* The crest tile in its salon's own wash — the mockup's c-* crests. Two full
   stops rather than the band's fade: a 34px tile with a transparent corner
   reads as a misprint. The dark block's single tile rule outranks these. */
.sigil.tint-sand { background: linear-gradient(160deg, #F7EFDA, #EFE1BE); }
.sigil.tint-rose { background: linear-gradient(160deg, #FBEBEE, #F6DCE1); }
.sigil.tint-sage { background: linear-gradient(160deg, #EAF0E6, #DCE6D5); }
.sigil.tint-brass { background: linear-gradient(160deg, #FAF2E0, #F0E3C4); }
.sigil.tint-shell { background: linear-gradient(160deg, #FBEDE3, #F5DCCB); }
.sigil.tint-olive { background: linear-gradient(160deg, #F5F4E6, #EAE9D2); }

/* **The washes at dusk — found by looking at the dark twin.** The six tints
   were light literals with no night values, so a band's name set light ink on
   a light blush and vanished: the exact look-found class, on both the salon
   band and the member's. The same plants grown in less light — each wash
   darkened toward the ground rather than inverted, fading the same way. The
   sage ink lifts like every other accent measured against the dark ground. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme='light']) .tint-sand { background: linear-gradient(168deg, #2b2718 0%, #262213 62%, rgba(38, 34, 19, 0) 100%); }
  :root:not([data-theme='light']) .tint-rose { background: linear-gradient(168deg, #2e1c21 0%, #29181c 60%, rgba(41, 24, 28, 0) 100%); }
  :root:not([data-theme='light']) .tint-sage { background: linear-gradient(168deg, #20261a 0%, #1b2115 60%, rgba(27, 33, 21, 0) 100%); }
  :root:not([data-theme='light']) .tint-brass { background: linear-gradient(168deg, #2b2515 0%, #262011 60%, rgba(38, 32, 17, 0) 100%); }
  :root:not([data-theme='light']) .tint-shell { background: linear-gradient(168deg, #2b211a 0%, #261c15 60%, rgba(38, 28, 21, 0) 100%); }
  :root:not([data-theme='light']) .tint-olive { background: linear-gradient(168deg, #262614 0%, #212110 60%, rgba(33, 33, 16, 0) 100%); }
  :root:not([data-theme='light']) .tint-sage,
  :root:not([data-theme='light']) .tint-olive { --tint-ink: #9DB48F; }
  :root:not([data-theme='light']) .sigil { background: linear-gradient(160deg, #2e2a1c 0%, #262114 100%); }
}

:root[data-theme='dark'] .tint-sand { background: linear-gradient(168deg, #2b2718 0%, #262213 62%, rgba(38, 34, 19, 0) 100%); }
:root[data-theme='dark'] .tint-rose { background: linear-gradient(168deg, #2e1c21 0%, #29181c 60%, rgba(41, 24, 28, 0) 100%); }
:root[data-theme='dark'] .tint-sage { background: linear-gradient(168deg, #20261a 0%, #1b2115 60%, rgba(27, 33, 21, 0) 100%); }
:root[data-theme='dark'] .tint-brass { background: linear-gradient(168deg, #2b2515 0%, #262011 60%, rgba(38, 32, 17, 0) 100%); }
:root[data-theme='dark'] .tint-shell { background: linear-gradient(168deg, #2b211a 0%, #261c15 60%, rgba(38, 28, 21, 0) 100%); }
:root[data-theme='dark'] .tint-olive { background: linear-gradient(168deg, #262614 0%, #212110 60%, rgba(33, 33, 16, 0) 100%); }
:root[data-theme='dark'] .tint-sage,
:root[data-theme='dark'] .tint-olive { --tint-ink: #9DB48F; }
:root[data-theme='dark'] .sigil { background: linear-gradient(160deg, #2e2a1c 0%, #262114 100%); }

/* Each wash carries its own ink — the eyebrow and the Arabic half of a lockup
   set on a tint take the tint's family, darkened until a 9.5px tracked cap
   still clears its ground. The mockups' own values (#B0714A, #61795A) sit
   near 3.5:1 and these are the same trade §1 records: a little of the
   airiness for a label a woman can read. */
.tint-sand,
.tint-brass { --tint-ink: var(--brass); }
.tint-rose { --tint-ink: var(--rose); }
.tint-shell { --tint-ink: var(--peach); }
.tint-sage,
.tint-olive { --tint-ink: #52654A; }

/* ------------------------------------------------- the door's grove ---- */
/* The guest door's collection, one garden card per admitted salon. The card
   is the salon's whole argument — who, where, when she can come, one verb —
   and its tint, botanical and ink derive from its own name, the same three
   strides the salon page walks, so a room keeps one face from the door in. */
.grove {
  display: flex;
  flex-direction: column;
  gap: 14px;
}

.gcard {
  position: relative;
  display: block;
  overflow: hidden;
  border-radius: var(--radius-card);
  padding: 16px 16px 14px;
  text-decoration: none;
  color: var(--ink);
}

.gcard .tag,
.gcard .arn { color: var(--tint-ink); }

/* The spill wears the tint's family too — ornament may stay lighter than the
   ink because it carries no fact. */
.tint-rose .spill { --gold-leaf: var(--bloom-rose); --gold-leaf-2: var(--petal-rose); --brass: var(--bloom-rose-deep); }
.tint-shell .spill { --gold-leaf: var(--bloom-peach); --gold-leaf-2: var(--bloom-peach); --brass: var(--bloom-peach-deep); }
.tint-sage .spill,
.tint-olive .spill { --gold-leaf: var(--sage-leaf); --gold-leaf-2: var(--sage-leaf); --brass: var(--sage); }
.tint-rose .sigil svg { --gold-leaf: var(--bloom-rose); --gold-leaf-2: var(--petal-rose); --brass: var(--bloom-rose-deep); }
.tint-shell .sigil svg { --gold-leaf: var(--bloom-peach); --gold-leaf-2: var(--bloom-peach); --brass: var(--bloom-peach-deep); }
.tint-sage .sigil svg,
.tint-olive .sigil svg { --gold-leaf: var(--sage-leaf); --gold-leaf-2: var(--sage-leaf); --brass: var(--sage); }

.gcard .spill {
  position: absolute;
  pointer-events: none;
  inset-block-start: -26px;
  inset-inline-end: -14px;
  inline-size: 160px;
  block-size: 140px;
  z-index: 0;
}

.gcard .gc-head {
  position: relative;
  z-index: 1;
  display: flex;
  align-items: flex-end;
  gap: 12px;
}

.gcard .sigil {
  inline-size: 44px;
  block-size: 44px;
  border-radius: 13px;
}

.gcard .lock .en {
  font-size: 30px;
  margin-block-start: 4px;
}

.gcard .lock .tag { font-size: 11px; }

.gcard .lock .arn {
  font-size: 15px;
  margin-block-start: 4px;
}

.gcard .gc-when {
  position: relative;
  z-index: 1;
  display: flex;
  align-items: center;
  gap: 12px;
  margin-block-start: 12px;
}

.gcard .gc-when .when {
  font-size: 13.5px;
  color: var(--sub);
}

.gcard .gc-when .wk {
  display: inline-flex;
  margin-inline-start: auto;
}

.gcard .btn {
  position: relative;
  z-index: 1;
  margin-block-start: 12px;
}

/* **The fading ledger** — the card's glimpse of the page it opens. Three
   lines at most, dissolving into the verb: the fade is the sentence "there
   is more", said without a word. The pair inside wears `.prices .was`/`.v`,
   so the one struck-price rule in the system is the one that strikes it. */
.gcard .glimpse {
  position: relative;
  z-index: 1;
  display: block;
  margin-block-start: 12px;
  padding-block-start: 6px;
  border-block-start: 1px dotted var(--line);
  -webkit-mask-image: linear-gradient(180deg, #000 30%, rgb(0 0 0 / 0.42) 68%, transparent 100%);
  mask-image: linear-gradient(180deg, #000 30%, rgb(0 0 0 / 0.42) 68%, transparent 100%);
}

.gcard .gl-row {
  display: flex;
  align-items: baseline;
  gap: 8px;
  padding-block: 5.5px;
}

.gcard .gl-name {
  flex: 0 1 auto;
  font-size: 15px;
  font-weight: 500;
  color: var(--ink);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.gcard .gl-lead {
  flex: 1;
  min-inline-size: 14px;
  border-block-end: 1px dotted var(--line);
  transform: translateY(-4px);
}

.gcard .glimpse .prices {
  display: inline-flex;
  align-items: baseline;
  gap: 8px;
  flex: 0 0 auto;
}

.gcard .glimpse .was { font-size: 13.5px; }

.gcard .glimpse .v {
  font-family: var(--price-face, var(--display));
  font-weight: var(--price-weight, 600);
  font-size: 22px;
  line-height: 1;
  color: var(--fir);
  min-inline-size: 34px;
  text-align: end;
}

/* The same collection as a roster, where the page is wide enough to read a
   list — the desktop frame's shape. One of the two is always display: none. */
.roster { display: none; }

.rrow {
  display: flex;
  align-items: center;
  gap: 14px;
  padding-block: 13px;
  border-block-end: 1px solid var(--line);
  text-decoration: none;
  color: var(--ink);
}

.rrow .sigil {
  inline-size: 40px;
  block-size: 40px;
  border-radius: 12px;
}

.rrow .rr-say {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-inline-size: 0;
}

.rrow .rr-name {
  font-family: var(--display);
  font-weight: 600;
  font-size: 24px;
  line-height: 1.1;
}

.rrow .rr-name .arn {
  font-family: var(--arabic-display);
  font-size: 14px;
  color: var(--brass);
  margin-inline-start: 6px;
}

.rrow .wk {
  display: inline-flex;
  gap: 6px;
  margin-inline-start: auto;
}

/* The member's own band. The blush is hers the way a salon's tint is the
   salon's; the day is the eyebrow and the greeting is the lockup. */
.band.hers { margin-block-end: 20px; }

.band.hers .tag { color: var(--rose); }

.band.hers .greet-band {
  font-family: var(--display);
  font-weight: 600;
  font-size: 32px;
  line-height: 1.1;
  letter-spacing: -0.02em;
  color: var(--ink);
  margin: 4px 0 0;
}

/* Her circle keeps its garden cards at every width — the roster swap below
   is the guest door's, not hers; the :not() carries that exception. */

/* The member's compact roster row: a 34px crest and the sentence, no week. */
.rrow.sm { padding-block: 12px; gap: 12px; }

.rrow.sm .sigil {
  inline-size: 34px;
  block-size: 34px;
  border-radius: 10px;
}

.rrow.sm .rr-name { font-size: 19px; }

/* The frame's small rows carry the Latin name alone — the Arabic half stays
   on the card, the roster and the salon's own page, where there is room for
   a name to be whole. */
.rrow.sm .rr-name .arn { display: none; }

/* The visits ledger row: dot, serif salon, service · state — the when at the
   end with its money under it. */
/* You: the gifts strip — rose, hers, and only when it is true. */
.card.giftstrip {
  display: flex;
  align-items: center;
  gap: 12px;
  background: var(--rose-wash);
  border-color: var(--rose-line);
  text-decoration: none;
  color: var(--ink);
}

.giftstrip .lbl.rosey,
.doorside .lbl.rosey {
  display: block;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--rose);
}

.giftstrip .note { display: block; margin-block-start: 2px; }

.giftstrip .gift-fig {
  margin-inline-start: auto;
  display: flex;
  align-items: baseline;
  gap: 5px;
}

.giftstrip .gift-fig b {
  font-family: var(--price-face, var(--display));
  font-weight: var(--price-weight, 600);
  font-size: 30px;
  line-height: 1;
  color: var(--rose);
}

/* You: the quiet rows. A fact and a door on one line. */
.card.row-card {
  padding: 15px 0;
  border: 0;
  border-radius: 0;
  border-block-end: 1px solid var(--line);
  background: transparent;
  box-shadow: none;
  margin: 0;
}

a.card.row-card { display: flex; }

.rowline {
  display: flex;
  align-items: center;
  gap: 12px;
  text-decoration: none;
  color: var(--ink);
  cursor: pointer;
  list-style: none;
}

.rowline::-webkit-details-marker { display: none; }

.rowline > span:first-child {
  display: flex;
  flex-direction: column;
  gap: 3px;
  min-inline-size: 0;
  flex: 1 1 auto;
}

.row-say {
  font-weight: 600;
  font-size: 16px;
  line-height: 1.55;
  color: var(--ink);
}

/* A row's value beside its title (*Invite a friend · AED 50 each*), quieter
   than the title — R6: one line per row, no line under it. */
.row-val {
  font-size: 15px;
  font-weight: 400;
  color: var(--sub);
}

.row-go {
  margin-inline-start: auto;
  flex: 0 0 auto;
  font-size: 16px;
  font-weight: 400;
  color: var(--fir);
}

.rowline > span:first-child { gap: 0; }

details.row-card[open] .rowline { margin-block-end: 8px; }

/* The ghosted goodbye, centred. */
.signout-line { text-align: center; margin-block-start: 4px; }

.signout-line .btn.plain {
  inline-size: auto;
  block-size: auto;
  padding: 4px 8px;
  font-size: 13.5px;
  font-weight: 400;
  color: var(--faint);
}

/* The hold strip — B's fact, drawn once here so B has only to say the line. */
.hold {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 11px 13px;
  border-radius: 12px;
  background: var(--raised);
  margin-block-start: 14px;
}

.hold .hi { flex: 0 0 auto; }

.hold .note { margin: 0; }

/* The bill page's answer is a size up from the review's — the frame sets
   'Your bill · 320' at 34 where 'You'll pay about' sits at 26. */
.billcard .stack .pays .v { font-size: 38px; }

/* The receipt's leading fact. */
.paidhead .state {
  display: flex;
  align-items: center;
  gap: 7px;
  margin: 0;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--fir);
}

.paidhead .paidfig {
  font-family: var(--price-face, var(--display));
  font-weight: var(--price-weight, 600);
  font-size: 44px;
  line-height: 1;
  letter-spacing: -0.02em;
  color: var(--ink);
  margin: 10px 0 0;
}

/* **The bill** (frame 8-01). The tag over the title; the reveal centred —
   the salon's figure struck at 30 over what she pays at 72 in fir; the tip
   title centred at 17; the chips a quarter wide at 11/12; the sentence, the
   hold in one line, the verb, and the quiet alternative. */
.bill-tag { margin-block-start: 16px; }

.bill-h1 { margin-block: 4px 0; }

.reveal {
  text-align: center;
  margin-block-start: 22px;
}

.reveal p { margin: 0; }

/* The salon's figure, struck under the one struck-price rule (`.prices
   .was`) — this sets only its size. */
.reveal .reveal-was {
  display: block;
  font-family: var(--price-face, var(--display));
  font-weight: var(--price-weight, 400);
  font-size: 34px;
  line-height: 1.1;
  color: var(--struck);
  margin-block-start: 2px;
}

.reveal .prices { margin: 0; }

.reveal .reveal-you { margin-block-start: 8px; }

.reveal .reveal-hers {
  font-family: var(--price-face, var(--display));
  font-weight: var(--price-weight, 700);
  font-size: 72px;
  line-height: 1;
  letter-spacing: -0.02em;
  color: var(--fir);
}

/* **F224 R5 · one line** (AFTER_APPLE's skin): her figure at 60, the salon's
   struck at 30 beside it on one baseline, as the app's bill has them. */
:root.c0 .reveal .reveal-one {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: baseline;
  column-gap: 12px;
}
:root.c0 .reveal .reveal-one .reveal-hers { font-size: 60px; line-height: 64px; letter-spacing: -1.2px; }
:root.c0 .reveal .reveal-one .reveal-was { display: inline; font-size: 30px; line-height: 34px; margin: 0; }

.sect.tip-head {
  text-align: center;
  font-size: 22px;
}

.tips {
  display: flex;
  gap: 8px;
}

.tips .chip.tipchip {
  flex: 1;
  display: flex;
  justify-content: center;
  padding-inline: 0;
  padding-block: 11px;
  border-radius: 12px;
}

.tipwhy {
  margin-block: 8px 0;
  text-align: center;
}

.hold.hold-line {
  justify-content: center;
  background: transparent;
  padding: 0;
  margin-block-start: 16px;
  gap: 8px;
}

.hold.hold-line .note {
  font-size: 13.5px;
  color: var(--sub);
}

.paycard { margin-block-start: 16px; }

.settles {
  text-align: center;
  margin: 10px 0 0;
}

.paidhead .paidwith { margin: 6px 0 0; }
/* M4 A (F224): the salon and the visit's time, under the figure. */
.paidhead .paidvisit { margin: 6px 0 0; color: var(--ink); }

/* Prima speaks in sentences, at reading rhythm. */
.primaline {
  margin: 0 0 8px;
  font-size: 15px;
  line-height: 1.7;
}

/* The signed-in page at width: the ticket spreads, the aside carries her
   pane and the whisper-card. The band is full-bleed above both columns. */
.herside-aside .pane-gift {
  display: flex;
  align-items: baseline;
  gap: 5px;
  margin-block: 4px 2px;
}

.herside-aside .pane-gift b {
  font-family: var(--price-face, var(--display));
  font-weight: var(--price-weight, 600);
  font-size: 34px;
  line-height: 1;
  color: var(--rose);
}

.herside-aside .m0 { margin: 8px 0 0; }

@media (min-width: 1000px) {
  /* The ticket at width: the verb sits at the end, vertically centred. */
  .herside .ticket {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: center;
    column-gap: 20px;
  }

  .herside .ticket > * { grid-column: 1; }

  .herside .ticket .btn {
    grid-column: 2;
    grid-row: 1 / span 3;
    inline-size: auto;
    /* The floor holds a short verb; the padding holds a long one. Without it
       *Tell them you are here* would sit against both edges. */
    min-inline-size: 132px;
    padding-inline: 18px;
    margin-block-start: 0;
  }
}

/* Her circle as a shelf on a phone: the cards ride a snap row with a peek of
   the next, which is the frame's carousel with no script at all. */
@media (max-width: 999px) {
  .grove-stay {
    flex-direction: row;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    scrollbar-width: none;
    margin-inline: calc(-1 * var(--gutter));
    padding-inline: var(--gutter);
  }

  .grove-stay::-webkit-scrollbar { display: none; }

  .grove-stay .gcard {
    flex: 0 0 88%;
    scroll-snap-align: center;
  }

  /* One card needs no shelf. */
  .grove-stay .gcard:only-child { flex-basis: 100%; }
}

/* The rose New at a row's end — a fact, not a badge: text in the tag's own
   cut, no ground, no border, and it retires with the sixty days. */
.rrow .newtag {
  margin-inline-start: auto;
  flex: 0 0 auto;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--rose);
}

.rrow .newtag + .wk { margin-inline-start: 14px; }

/* The shelf's typed panes — frame 3-01. An event is a fact with a verb in
   its salon's own ink; the gift wears rose because it is hers. They ride the
   same snap shelf as her cards, narrower, so the cards stay the headline. */
/* The ground sits in :where() at zero specificity, so a salon's wash class
   wins it without a duplicate gradient — the pane in the garden's colour is
   one class, not six more rules. */
:where(.ribpane) {
  border: 1px solid var(--line);
  background: var(--card);
}

.ribpane {
  position: relative;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  border-radius: var(--radius-card);
  padding: 14px 15px;
  text-decoration: none;
  color: var(--ink);
}

.ribpane .spill {
  position: absolute;
  pointer-events: none;
  inset-block-start: -24px;
  inset-inline-end: -12px;
  inline-size: 140px;
  block-size: 122px;
  z-index: 0;
}

.ribpane > :not(.spill) { position: relative; z-index: 1; }

.ribpane .pe {
  font-size: 11px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  font-weight: 700;
  color: var(--tint-ink, var(--sub));
}

.ribpane .psay {
  font-size: 15px;
  font-weight: 500;
  line-height: 1.45;
  margin-block-start: 6px;
}

.btn.sm {
  /* Concierge's second button size — the one a card carries. The rail had this
     only inside a ribbon pane, so a `.btn.sm` anywhere else silently took the
     full 46. */
  block-size: 42px;
  font-size: 15px;
}

.ribpane .btn.sm {
  block-size: 36px;
  font-size: 13.5px;
  margin-block-start: auto;
  padding-block-start: 10px;
}

.ribpane .btn { margin-block-start: auto; }

.ribpane.rp-gift {
  background: var(--rose-wash);
  border-color: var(--rose-line);
}

.ribpane.rp-gift .pe { color: var(--rose); }

.ribpane .giftfig {
  display: flex;
  align-items: baseline;
  gap: 6px;
  margin-block-start: 8px;
}

.ribpane .giftfig i {
  font-style: normal;
  font-size: 13.5px;
  color: var(--sub);
}

.ribpane .giftfig b {
  font-family: var(--price-face, var(--display));
  font-weight: var(--price-weight, 600);
  font-size: 34px;
  line-height: 1;
  color: var(--rose);
}

/* One label, two truths — and each shape keeps to its width. */
.at-desk { display: none; }

@media (min-width: 1000px) {
  .at-hand { display: none; }

  .at-desk { display: inline; }

  /* At width the pulse lists above and the gift paints in the aside; the
     shelf keeps only her cards. */
  .grove-stay .ribpane { display: none; }
}

@media (max-width: 999px) {
  /* On a phone the shelf is the pulse, so the list above yields to it. */
  .pulse-list { display: none; }

  .grove-stay .ribpane {
    flex: 0 0 246px;
    scroll-snap-align: center;
  }
}

/* The join card's own two verbs sit above the wash like everything else. */
.gcard .gc-act {
  position: relative;
  z-index: 1;
  margin-block-start: 12px;
}

.gcard .backline {
  position: relative;
  z-index: 1;
  margin-block: 10px 0;
}

/* The Circle's salon rows — variant B of the board. One room per row in its
   own wash (the tint class carries it), the crest, both names, the sentence,
   the week — badges trailing, where facts live. */
.srows {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.srow {
  display: flex;
  align-items: center;
  gap: 12px;
  border-radius: var(--radius-card);
  padding: 12px 14px;
  text-decoration: none;
  color: var(--ink);
  overflow: hidden;
}

.srow .sigil {
  inline-size: 44px;
  block-size: 44px;
  border-radius: 13px;
}

.srow .sr-say {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-inline-size: 0;
  flex: 1;
}

.srow .sr-name {
  font-family: var(--display);
  font-weight: 600;
  font-size: 24px;
  line-height: 1.1;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.srow .sr-name .arn {
  font-family: var(--arabic-display);
  font-size: 14px;
  color: var(--tint-ink, var(--brass));
  margin-inline-start: 5px;
}

.srow .sr-sub {
  font-size: 13.5px;
  color: var(--sub);
}

.srow .sr-end {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 5px;
  flex: 0 0 auto;
}

.srow .wk { display: inline-flex; gap: 3px; }

.srow .newtag {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--rose);
}

/* The switcher — the chip atom, worn as two links. */
.switch {
  display: flex;
  gap: 8px;
  margin-block: 0 10px;
}

.switch .chip { text-decoration: none; }

/* Her usual, as the shelf's first pane. */
.ribpane.usual .pe { font-size: 11px; }

.ribpane.usual .up-when {
  font-family: var(--display);
  font-weight: 600;
  font-size: 24px;
  line-height: 1.15;
  margin-block-start: 6px;
}

.ribpane.usual .up-sub {
  font-size: 13.5px;
  color: var(--sub);
  margin-block-start: 2px;
}

.ribpane.usual .btn { margin-block-start: auto; }

/* The pager's dots: grey until chosen, then the pane's own ink. */
.gdots {
  display: flex;
  gap: 7px;
  justify-content: center;
  align-items: center;
  margin-block-start: 10px;
}

.gd {
  inline-size: 7px;
  block-size: 7px;
  border-radius: 999px;
  background: var(--rule);
  cursor: pointer;
  transition: all 0.25s;
}

.gd.on {
  inline-size: 16px;
  background: var(--dot, var(--fir));
}

@media (min-width: 1000px) {
  /* The old shelf's dots were the phone's shape; the spreads (frame 7-01)
     ride at every width, so the rule keeps only the dots. */
  .sect-shelf,
  .gdots { display: none; }
}

/* The planner card in the ticket's seat: the gcard, one size calmer. */
.nextcard { margin-block-start: 4px; }

.nextcard .lock .en { font-size: 28px; }

.grove-note {
  text-align: center;
  margin-block: 18px 6px;
  font-size: 13.5px;
}

/* **One salon, one card — including at width.** `_grove.html`'s own opening
   line says the door's grove and the Circle's list draw the same object, *so a
   room keeps one face wherever she meets it*, and this rule was the thing
   breaking that promise: it hid the garden card above 1000px and swapped in a
   row carrying no price, no verb, no wash and — for any room inside its first
   sixty days, which in a pilot is all of them — no hours either.
   
   So the desk door made MIORA's whole claim in the seal strip and then showed
   nothing that demonstrated it, on the page a referral spends AED 50 a side to
   land her on. And `/explore` has only a grove, so above 1000px it rendered an
   empty page with a heading over it.
   
   The cards lay out as a grid instead. `auto-fit` with a floor rather than a
   fixed count, because the door has four salons today and the collection grows
   by at most two a month — a hardcoded three would be wrong in April. */
@media (min-width: 1000px) {
  .grove:not(.grove-stay) {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
    align-items: start;
  }

  /* The roster is gone from the door. The macro stays for `salon_srow`'s
     neighbour — a member's own circle is a list on purpose, because her eye is
     on the rooms she already has. */
  .roster { display: none; }
}

/* --------------------------------------------- the door's own pieces ---- */
/* `.greet.door-h1` — the base .greet is defined later in the sheet and its
   26 was quietly winning at equal specificity. 31 and 1.08 are frame 1-01's
   own numbers; the second line is fir because it is the sentence she came for,
   and it is the one place fir is a title colour rather than an action's. */
.greet.door-h1 {
  margin-block: 18px 0;
  font-size: 36px;
  line-height: 1.08;
  letter-spacing: -0.012em;
  /* "Book Abu Dhabi's chosen salons." left *salons.* alone on a phone's
     line; balanced, the two halves read as one sentence. */
  text-wrap: balance;
}

.door-h1 .door-rate { color: var(--fir); }

/* The paragraph under it: 13.5 in the sentence ink, and the question at the
   end in fir at 600 — a link, set as the frame sets it. */
.door-say {
  margin-block: 10px 0;
  font-size: 16px;
  line-height: 1.55;
  color: var(--text);
}

/* **The promise strip** (the founder's #8 A, 23 Sep 2026): three ticks under
   the headline, then the salon — Product's words, the tick drawn in fir. */
.promise {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 8px;
  list-style: none;
  margin: 14px 0 0;
  padding: 0;
}

.promise li {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  border: 1px solid var(--line);
  background: var(--card);
  border-radius: 99px;
  padding: 5px 12px;
  font-size: 14px;
  color: var(--ink);
}

.promise li::before {
  content: "✓";
  font-weight: 700;
  color: var(--fir);
}

/* The question, set as the frame sets it: fir, 600, the paragraph's own size,
   and no marker — a disclosure whose control reads as a sentence. */
/* `.how.door-how`, because the base `.how` is declared again later in the
   sheet and its rule was winning the border back at equal specificity. */
.how.door-how {
  margin-block-start: 2px;
  border-block-start: 0;
  padding-block-start: 0;
}

.door-how > summary.how-link {
  list-style: none;
  cursor: pointer;
  font-size: 15px;
  line-height: 1.55;
  font-weight: 600;
  color: var(--fir);
}

.door-how > summary.how-link::-webkit-details-marker { display: none; }
.door-how > summary.how-link::marker { content: ''; }
/* The base `.how` summary appends a chevron; the frame sets a sentence. */
.door-how > summary.how-link::after { content: none; }
.door-how > .note { margin-block: 8px 0; }

/* The header's pill: the chip atom in fir, so a stranger meets the action ink
   before she meets a card. */
.hd .signin-pill {
  border-color: var(--fir);
  color: var(--fir);
  font-size: 15px;
  block-size: 34px;
  padding-inline: 14px;
}

/* The seal strip: the rosette wearing the base rate, beside the claim.
   `.card.sealstrip` because `.card` declares display later in the sheet. */
.card.sealstrip {
  display: flex;
  align-items: center;
  gap: 14px;
  margin-block-start: 18px;
  background: var(--ground);
  border-color: var(--petal);
}

.sealfig {
  position: relative;
  inline-size: 64px;
  block-size: 64px;
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.sealfig .rr {
  position: absolute;
  inset: 0;
}

.sealfig b {
  font-size: 16px;
  font-weight: 700;
  line-height: 1;
  color: var(--fir);
}

.sealstrip .rateline {
  margin: 0;
  font-size: 15px;
  font-weight: 600;
  line-height: 1.45;
}

.sealstrip .note { margin-block: 4px 0; }

.sealstrip .note b { color: var(--ink); }

.sealstrip .how { margin-block-start: 6px; }

/* SEAL · seal-A (18 Oct 2026): the page the seal opens — the seal, the
   head, the line, one bordered example row, and the terms. */
.ratesheet-top { display: flex; align-items: center; gap: 14px; }
.ratesheet-top .greet { margin: 0; }
/* `.card.` because `.card` sets display later in the sheet: the two ends sat
   side by side with no space between ("Ð120You pay"). */
.card.ratesheet-ex { display: flex; flex-wrap: wrap; justify-content: space-between; gap: 8px; }
/* The frame's seal in the sheet: a 52 ring round a 15 figure, not the
   header's 34 round 11. */
:root.c0 .ratesheet .sealfig { inline-size: 52px; block-size: 52px; }
:root.c0 .ratesheet .sealfig::before { inset: 0; }
:root.c0 .ratesheet .sealfig b { font-size: 15px; }
/* The same sheet over the page she is on (seal-A, `rate-sheet.js`): /rate's
   own <main> in a <dialog>, from the foot, under a handle that closes it. */
.ratesheet-dlg { inset-block: auto 0; inset-inline: 0; margin-inline: auto; margin-block-end: 0; inline-size: min(100%, 480px); max-inline-size: 100%; padding: 0; border: 0; border-radius: var(--radius-sheet) var(--radius-sheet) 0 0; background: var(--card); color: var(--ink); }
.ratesheet-dlg::backdrop { background: rgb(0 0 0 / 0.35); }
.ratesheet-dlg .ratesheet { display: grid; gap: 14px; padding: 0 20px 26px; }
.ratesheet-dlg .ratesheet > * { margin: 0; }
.ratesheet-handle { display: block; margin: 0 auto 4px; inline-size: 44px; block-size: 28px; padding: 0; border: 0; background: none; cursor: pointer; }
.ratesheet-handle::before { content: ""; display: block; margin: 12px auto 0; inline-size: 36px; block-size: 4px; border-radius: 2px; background: var(--line); }

/* RECEIPTS · rec-A (18 Oct 2026): what she paid, in ink, before the ›. */
.rcpt-amt { color: var(--ink); font-weight: 700; }

/* **The leaf-closed label is gone with the label.** `.ldiv` survives as the
   garden's own divider — two rules meeting at a leaf, an ornament between
   blocks — but a section *title* no longer wears one. The two templates that
   drew it are unwrapped rather than left with a stray glyph. */

/* The aside is the desktop's half of the door. */
.doorside { display: none; }

@media (min-width: 1000px) {
  .doorside {
    display: flex;
    flex-direction: column;
    gap: 16px;
  }

  /* The mechanism stands open in the aside there, so the strip's folded copy
     of it would be the same words twice on one screen. */
  .sealstrip .how { display: none; }

  /* **E2E-0251, 1A**: the newest room's list copy steps aside only here,
     where the pane paints it. Below this width the pane is not drawn and
     the card is her way in. */
  .door:has(.doorside .pane) .door-spotlit { display: none; }

  .greet.door-h1 { font-size: var(--t-display); }
}

.doorside .pane {
  display: flex;
  text-decoration: none;
  color: var(--ink);
}

.doorside .pane-name {
  display: block;
  font-family: var(--display);
  font-weight: 600;
  font-size: 28px;
  line-height: 1.1;
  margin-block: 6px 2px;
}

.doorside .lbl.rosey { color: var(--rose); }

.how-card .lbl {
  display: block;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--faint);
  margin-block-end: 8px;
}

.how-card .how-said {
  margin: 0;
  font-size: 15px;
  line-height: 1.62;
  color: var(--sub);
}

.how-card .how-said b { color: var(--ink); }

/* The band's eyebrow and the Arabic half of the lockup wear the tint's own
   ink — the mockup colours them by the room (terracotta on the peach wash,
   rose on the blush), darkened here to the --tint-ink values §1's trade
   already covers. Brass remains the fallback for a band with no tint. */
.band .lock .tag,
.band .lock .arn {
  color: var(--tint-ink, var(--brass));
}

/* The bloom spilling past the top edge. Anchored to the band's own right edge,
   which is the viewport's — anchored to the text column instead it landed on
   top of the hours, which is the one thing at that end of the band. */
.band .spill {
  position: absolute;
  pointer-events: none;
  inset-block-start: -72px;
  inset-inline-end: -34px;
  z-index: 1;
}

/* **The band's tile, and it is not the gallery's Crest atom.** That one is a
   card with a name under it and a lift beneath; reusing the class here bought
   its padding, its shadow and its white ground, and the sand tile vanished. */
.sigil.shot {
  overflow: hidden;
  background: var(--raised);
}

.sigil img {
  inline-size: 100%;
  block-size: 100%;
  object-fit: cover;
}

.sigil {
  inline-size: 58px;
  block-size: 58px;
  border-radius: 16px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  background: linear-gradient(160deg, #F7EFDA, #EFE1BE);
}

/* Hours at the band's end: a caption, not body copy. */
.whenwk .when {
  font-size: var(--t-caption);
  line-height: 1.5;
  color: var(--sub);
}

/* **The bilingual lockup.** دار الورد under Dar Al Ward is the salon as it is
   actually called. Set as half of the name, not as a note about it: the Arabic
   is a display face at 19px in brass, not body copy at 14 in grey. */
.lock {
  line-height: 1;
  min-inline-size: 0;
}

.lock .tag {
  display: block;
  letter-spacing: 0.16em;
}

.lock .en {
  display: block;
  font-family: var(--display);
  font-style: normal;
  font-weight: 600;
  font-size: 42px;
  letter-spacing: -0.02em;
  color: var(--ink);
  margin: 6px 0 0;
  line-height: 1.02;
}

.lock .arn {
  display: block;
  font-family: var(--arabic-display);
  font-size: 21px;
  line-height: 1.15;
  color: var(--brass);
  margin-block-start: 5px;
  /* Shrink-wrapped, or the RTL run aligns to the far end of a stretched
     lockup — بيت نورة floated to the band's other side the moment the phone
     band let .lock take the row. Same rule §2 states for Arabic paragraphs. */
  inline-size: fit-content;
}

/* Hours and the week, at the band's far end. */
.whenwk {
  margin-inline-start: auto;
  text-align: end;
  flex: 0 0 auto;
}

.whenwk p {
  margin: 0;
}

/* The week is seven glyphs wide, not as wide as the sentence above it: as a
   stretched flex child its `justify-content` moved the leaves without moving
   the row, so the box reported the sentence's width and the today marker had
   nothing to sit under. */
.whenwk .wk {
  display: inline-flex;
  margin-block-start: 9px;
}

/* **The band at phone width.** The garden's mobile frame sets the name at
   30px, drops the eyebrow to 9.5, shrinks the bloom, and puts the hours and
   the week on their own line under the lockup — at 420px the 42px name wrapped
   across two lines and the bloom landed on top of the hours.
 *
 * One departure, deliberate: the garden's phone band carries no crest at all,
 * and this keeps it at 44px. G-10 is a law with a test behind it — a salon has
 * a face on every surface — and the surface where most members meet a room is
 * the one place that law should not be quietly dropped for space. */
@media (max-width: 559px) {
  .band {
    padding-block: 16px;
  }

  /* The phone frame's week is dots alone — at eleven pixels the letters were
     halving the leaf, and the sentence beside the dots already says the week
     out loud (and `aria-label` says it precisely). Desktop keeps the letters. */
  .band .wkd em { display: none; }

  .band > .bandin {
    flex-wrap: wrap;
    align-items: center;
    gap: 12px;
  }

  .sigil {
    inline-size: 44px;
    block-size: 44px;
    border-radius: 13px;
  }

  .sigil svg {
    inline-size: 26px;
    block-size: 26px;
  }

  .lock .tag {
    font-size: 11px;
  }

  .lock .en {
    font-size: 32px;
  }

  .lock .arn {
    font-size: 16px;
  }

  /* Its own line, reading from the start edge like everything else on a
     phone — right-aligned under a left-aligned name is a column of two. */
  .whenwk {
    inline-size: 100%;
    margin-inline-start: 0;
    text-align: start;
    display: flex;
    align-items: center;
    gap: 14px;
  }

  .whenwk .said {
    min-inline-size: 0;
  }

  .whenwk .wk {
    margin-block-start: 0;
    margin-inline-start: auto;
  }

  .band .spill {
    inline-size: 150px;
    block-size: 130px;
    inset-block-start: -24px;
    inset-inline-end: -12px;
  }
}

/* **The vine lives in the margin or it does not appear at all.** Placed 30px
   outside the text column it ran straight down the price list, over Bridal,
   over Hair spa and over the link at the foot — an ornament crossing the one
   column the page exists to be read in. It needs 96px of clear margin, so it
   is drawn only on windows wide enough to have that, and it sits behind the
   content in any case rather than trusting the geometry. */
.withaside-main {
  position: relative;
}

.vine {
  display: none;
  position: absolute;
  pointer-events: none;
  z-index: 0;
  inset-inline-start: -104px;
  inset-block-start: 250px;
}

@media (min-width: 1272px) {
  .vine {
    display: block;
  }
}

/* The list draws above it, so a narrow window or a long name can never put a
   leaf through a price. */
.ledger,
.saidby,
.lede.said {
  position: relative;
  z-index: 1;
}

/* The leaf that ends a list. Two rules fading from nothing, one leaf between. */
.ldiv {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-block: 22px 12px;
}

/* The two closing statements on one line: what this is, and who said it. */
.saidby {
  display: flex;
  align-items: center;
  gap: 18px;
  flex-wrap: wrap;
}

.saidby > * {
  margin: 0;
  flex: 0 0 auto;
}

/* Inside the closing row the disclosure drops the rule and the space it wears
   when it stands alone — the leaf divider above is already the break, and a
   second hairline eighteen pixels under it read as a mistake. */
.saidby .how {
  min-inline-size: 0;
  margin-block-start: 0;
  border-block-start: 0;
  padding-block-start: 0;
}

.saidby .how[open] {
  flex: 1 1 100%;
}

.saidby .note.faint {
  font-size: var(--t-caption);
}

.ldiv .r {
  flex: 1;
  block-size: 1px;
  background: linear-gradient(90deg, transparent, var(--line) 18%, var(--line) 82%, transparent);
}

/* **The one surface licensed for paint.** Everything else in the kit is drawn
   in the grammar layer; the pane is where a picture may go, and what it holds
   is hers — the credit waiting on her first bill, in the rose this system
   keeps for her own money. */
.pane {
  position: relative;
  border-radius: 18px;
  overflow: hidden;
  border: 1px solid var(--line);
  background: var(--card);
  min-block-size: 196px;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  padding: 16px;
  margin-block-start: 14px;
}

.pane .pa {
  position: absolute;
  inset: 0;
}

/* **Paint does not get to make a sentence hard to read.** The gouache is
   cropped to fill, so where a bloom lands is a function of the box — on a
   narrow column a petal sat straight under the line naming her credit. The
   ground fades back in beneath the text, which keeps the painting whole and
   the words legible whatever the crop does. */
.pane::after {
  content: '';
  position: absolute;
  inset-inline: 0;
  inset-block-end: 0;
  block-size: 96px;
  background: linear-gradient(to bottom, transparent, var(--pane-ground) 62%);
}

.pane > *:not(.pa) {
  position: relative;
  z-index: 1;
}

.pane .lbl {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--rose);
  margin: 0 0 6px;
}

.pane p {
  margin: 0;
  font-size: 15px;
  color: var(--ink);
}

/* --- The salon page: nameplate, hours, and the list as the picker ----- */
/* Measured against the frozen rebuild, this page put 224px of furniture above
   the thing it exists to sell — the first price began 486px down where the
   design puts it at 262, five lines above the fold instead of seven. What
   follows is the composition that closes that gap. */

.nameplate {
  display: flex;
  align-items: center;
  gap: 16px;
}

/* Upright and in ink here, not the italic fir of a greeting: this is a proper
   noun on a document, not MIORA speaking to her. */
.nameplate .greet {
  font-style: normal;
  font-size: 38px;
  color: var(--ink);
  letter-spacing: -0.015em;
}

.nameplate .face {
  margin-block-end: 0;
}

/* The eyebrow: where the room is, and that MIORA chose it. */
/* **The tag survives the section label's retirement, and is not it.** The
   handover bans tracked caps as a *section* label and keeps them for what they
   are good at — a tiny fact clipped to an object: `yours`, `new`, an event on a
   plate. Concierge sets it at 10/.16em/700; this was 10.5/.14em/600. */
.tag {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--brass);
  margin: 0 0 2px;
}

/* Hours as a sentence with the week beside it — the card this replaces was
   215px of white between the name and the prices. */
.hours {
  display: flex;
  align-items: center;
  gap: 26px;
  margin-block: 18px 24px;
}

.hours > div:first-child > p {
  margin: 0;
}

.hours .wk {
  margin-inline-start: auto;
}

.wk {
  display: flex;
  gap: 9px;
  align-items: flex-end;
  flex: 0 0 auto;
}

.wkd {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 5px;
}

/* Shut: drawn in outline. Open: filled. The week reads as a row of leaves
   with gaps in it, which is the one fact seven dots have to carry. */
.wkd svg {
  fill: none;
  stroke: var(--line);
  stroke-width: 1.2;
  display: block;
}

.wkd svg.open {
  fill: var(--sage-pale);
  stroke: none;
}

/* Today is the one leaf in the action ink, so the week reads at a glance
   without the letter having to be marked as well. */
.wkd.today svg.open {
  fill: var(--fir);
}

.wkd em {
  font-style: normal;
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.06em;
  color: var(--sub);
}

/* Today is marked under its letter, so the mark does not change the dot's box
   — seven dots that grow on Tuesdays is a row that jitters through the week. */
.wkd.today em {
  color: var(--ink);
}

/* The sentence over the list: whose prices these are. */
.lede.said {
  color: var(--ink);
  font-weight: 500;
  font-size: var(--t-body);
  max-inline-size: none;
  margin-block-end: 12px;
}

/* **The list is the picker**, so every line that can be asked for is a button.
   Unboxing it was the other half: inside a bordered card the row rules had a
   second frame around them, and the ledger's whole idiom is a printed list on
   paper rather than a widget on a surface. */
.ledger {
  border-block-start: 1px solid var(--line);
}

.ledger .lr {
  inline-size: 100%;
  box-sizing: border-box;
  padding: 13px 12px 13px 14px;
  border: 0;
  border-block-end: 1px solid var(--line);
  border-radius: 0;
  background: none;
  font: inherit;
  color: inherit;
  text-align: start;
  position: relative;
}

button.lr {
  cursor: pointer;
}

button.lr:hover {
  background: color-mix(in srgb, var(--raised) 34%, transparent);
}

/* The line she is asking for. The fill is the identity sand at low strength
   and the rule is the one action ink — the same pair the seal uses, so a
   selected row reads as *chosen* rather than as highlighted. */
.ledger .lr[aria-current] {
  background: color-mix(in srgb, var(--raised) 42%, var(--card));
}

.ledger .lr[aria-current]::before {
  content: '';
  position: absolute;
  inset-block: 0;
  inset-inline-start: 0;
  inline-size: 3px;
  background: var(--fir);
}

/* The request panel echoes the chosen line. */
.ask h3 {
  font-family: var(--display);
  font-weight: 600;
  font-size: 28px;
  line-height: 1.15;
  color: var(--ink);
  margin: 10px 0 0;
}

.ask .prices {
  margin-block: 8px 0;
}

.ask .btn {
  margin-block-start: 14px;
}

/* The chosen line's pair in the panel: hers in the display face, in fir —
   the same answer the review's stack gives, at panel size. */
.ask .prices .v.big {
  font-family: var(--price-face, var(--display));
  font-weight: var(--price-weight, 600);
  font-size: 30px;
  color: var(--fir);
}

.ask .was { font-size: 13.5px; }

/* **The bar** (the founder's v16, 16 Sep 2026). Below the aside's width the
   card sits in flow under the list, and a bar rides the bottom edge with
   the count, the total and the one verb — shown only with something in the
   basket. It replaced the dock, which folded the whole card to the foot. */
.bar { display: none; }

@media (max-width: 999px) {
  .bar {
    position: fixed;
    inset-inline: 0;
    inset-block-end: 0;
    z-index: 80;
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 12px;
    padding: 10px var(--gutter);
    background: var(--card);
    border-block-start: 1px solid var(--line);
    font-size: 14px;
    font-weight: 500;
    color: var(--ink);
  }

  .bar .btn {
    inline-size: auto;
    padding: 10px 16px;
    font-size: 14px;
    margin: 0;
  }

  /* The page keeps clear of its own bar, footer included (5 Oct 2026). */
  body:has(.bar) { padding-block-end: 72px; }

  /* An unpaid bill is said once on a phone — by the bar (UX, 5 Oct 2026). */
  .ask.owes { display: none; }

  /* **F-multi / E2E-0256** (the founder's 1A, 18 Oct 2026): her figure bold,
     the salon's struck, a chevron that opens the list; while a count is
     missing, its question in brass; and the list keeps the bar's measured
     height clear under it (UX's ruling), large text included. */
  body:has(.bar.multi) { padding-block-end: max(72px, calc(var(--bar-h, 72px) + 16px)); }
  .bar.multi .bar-sum { display: inline-flex; flex-wrap: wrap; align-items: center; gap: 4px; min-inline-size: 0; color: var(--ink); text-decoration: none; }
  .bar.multi .bar-sum b { font-weight: 700; }
  .bar.multi .bar-sum .was { color: var(--sub); font-weight: 400; }
  .bar.multi .bar-asks { color: var(--brass); font-weight: 600; }
  .bar.multi .bar-up { flex: none; }
  .bar.multi .btn { flex: none; text-decoration: none; }
}

/* The label sits inside the panel, where the mockup puts it: outside, the
   `.sect` rule ran a hairline across the column and read as a divider between
   the prices and the panel rather than as this card's own name. */
.ask .lbl {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--sub);
  margin: 0;
}

.ask .rule {
  block-size: 1px;
  background: var(--line);
  margin-block: 14px;
}

.ask .change {
  text-align: center;
  font-size: 13.5px;
  margin-block: 12px 0;
}

.ask .change a {
  font-weight: 600;
  color: var(--fir);
}

.prices .v.big {
  font-size: 32px;
}

/* --- Composition: the page with an aside ------------------------------ */
/* **The web gets its own composition rather than a widened phone.** Below the
   fold of a laptop the rail was a single 44rem column with the request panel
   stacked under a long price list — a phone layout at a desktop viewport.
   Above 1000px the list keeps the left and the request panel sits beside it,
   sticky, so the thing she is deciding and the thing she decides with are on
   screen together.
 *
 * Below that width the grid collapses and the source order rules: prices
 * first, request after. That order is the ruling, not the layout's
 * convenience — the list with her rate on every line is what sells the room. */
.withaside {
  display: grid;
  /* **One column the width of the page, not of its widest row.** An implicit
     track sizes to its content's min-content, and the price list's rows ask
     for 309px — so in a 320px window the column grew past the gutter, the
     chips bled 20px further, and the page scrolled sideways (the founder's AA
     ruling, 5 Oct 2026). The rows wrap at 280 with nothing cut. */
  grid-template-columns: minmax(0, 1fr);
  gap: 0 38px;
  align-items: start;
}

@media (min-width: 1000px) {
  .page:has(.withaside) {
    max-inline-size: 66rem;
  }

  .withaside {
    grid-template-columns: minmax(0, 1fr) 20.125rem;
  }

  /* **An empty aside takes its column with it.** The door reserves 322px for
     one painted pane, and that pane is conditional — a guest sees it only
     while a salon is inside its first sixty days. Outside that window the
     column stood empty and the reading measure shrank anyway, so crossing
     1000px made the collection *narrower* than it was at 999. */
  .withaside:not(:has(.withaside-side > *)) {
    grid-template-columns: minmax(0, 1fr);
  }

  .page:has(.withaside:not(:has(.withaside-side > *))) {
    max-inline-size: 44rem;
  }

  .withaside-side {
    position: sticky;
    inset-block-start: calc(var(--stuck-top, 0px) + 20px);
  }
}

/* --- The price ledger ------------------------------------------------- */
/* **The signature, and it is borrowed rather than invented.** A salon's own
   printed list runs the service to its price on a dotted leader, and reading
   one is a thing every woman in this market has done a hundred times. The
   rail set the two prices as a flush pair, which reads as a table of data;
   the leader reads as a menu.
 *
 * Her price is Cormorant and the largest thing in the row, because it is the
 * number the page exists to state. The salon's price sits before it, quiet and
 * struck — the founder ruled on 2026-08-30 to match the rebuild, and the law
 * at the top of this file records what that clause was holding shut and why
 * lifting it here does not reopen it.
 *
 * The leader is a border on a flexible spacer rather than a row of periods:
 * dots typed into the markup are read aloud by a screen reader, one per dot. */
.ledger .lr,
dl.stack.ledger .lr {
  align-items: baseline;
  gap: 0;
}

.ledger .lr > .k {
  flex: 0 1 auto;
  padding-inline-end: 8px;
  /* A shade heavier than body, and in ink: the service name is what she is
     scanning for, and the generic key grey put the one word she reads below
     the leader it belongs to. The mockup sets every service name in ink. */
  font-size: var(--t-body);
  font-weight: 500;
  color: var(--ink);
}

/* Its Arabic half stays quiet under it. */
.ledger .lr > .k .why { color: var(--sub); }

/* The spacer. It carries no text, so it is invisible to assistive tech and
   audible to nobody. */
.ledger .lr::after {
  /* A zero-width space, not an empty string. An empty pseudo-element has no
     baseline, so `align-self: baseline` had nothing to sit on and the leader
     fell to the bottom of the row — under the Arabic name rather than beside
     the price it belongs to. The strut gives it a first line to align with,
     and carries no text for a screen reader to announce. */
  content: "\200b";
  order: 1;
  flex: 1 1 auto;
  align-self: baseline;
  margin-inline: 6px;
  border-block-end: 1px dotted var(--line);
  min-inline-size: 18px;
}

/* **The prices are the far column, and the leader runs to them.** `.prices`
   is a `<span>` now rather than a `<dd>`, because every bookable line is a
   button and a button may not hold a description list. Without it in this
   selector the pair kept source order, the leader took `order: 1` behind
   them, and the dotted rule ran off the right-hand edge into nothing while
   the name and the figures huddled at the left. */
.ledger .lr > .v,
.ledger .lr > .prices,
.ledger .lr > dd {
  order: 2;
  flex: 0 0 auto;
  padding-inline-start: 8px;
}

/* Two columns of fixed width, so the figures stack down the list rather than
   ragging with the length of each service's name. */
.ledger .prices {
  gap: 9px;
}

.ledger .prices .was {
  min-inline-size: 52px;
  text-align: end;
}

/* The salon's own word for the service, under its name rather than beside it. */
/* **The row is 62px, and it was 74.** The Arabic under each service name was
   inheriting `.why`'s own block spacing on top of the row's padding, so every
   line paid twelve pixels and the list lost one service off the fold for every
   six it showed. */
.ledger .lr > .k .why {
  display: block;
  margin-block: 1px 0;
  font-size: 13.5px;
  line-height: 1.25;
}

.ledger .lr {
  padding-block: 10px;
}




.ledger .prices .v {
  font-family: var(--price-face, var(--display));
  font-weight: var(--price-weight, 600);
  font-size: 26px;
  line-height: 1.1;
  color: var(--fir);
  /* The far column, fixed, so her figures stack down the list rather than
     ragging with the length of each service's name. */
  min-inline-size: 64px;
  text-align: end;
}

/* The phone frame's ledger: a step down on both figures and a hair less air
   at the row's ends, so five services hold the fold the mockup holds. After
   the base rules, or the cascade hands the size straight back. */
@media (max-width: 559px) {
  .ledger .lr {
    padding-block: 11px;
    padding-inline: 8px;
  }

  .ledger .prices .v {
    font-size: 24px;
  }

  .ledger .prices .was {
    font-size: 13.5px;
    min-inline-size: 40px;
  }
}


/* --- The header ------------------------------------------------------- */
/* Every mockup frame wears one: the wordmark on one side, her Rate Seal on the
   other. The rail shipped without it, so every page was an island — once she
   opened a booking there was no way back but the browser's own button, and no
   page ever told her what her rate was except the two that happened to.
 *
 * The mockups' three **browser** frames carry no tab bar, and that distinction
 * is deliberate: a phone app gets tabs, a web page gets a header. This is the
 * header. */

/* **The header aligns with the page under it, and its rule spans the window.**
   It was pinned to 44rem while the salon page runs to 66, so the wordmark and
   the nav sat inboard of the band below them — two columns on one screen, and
   the eye reads the narrower one as an inset panel. The row follows whichever
   column the page is using; the hairline underneath ignores both and runs to
   the edges, which is what makes the band beneath it read as the next storey
   of the same building rather than as a card. */
.hd {
  position: relative;
  max-inline-size: 44rem;
  margin-inline: auto;
  padding: 0 var(--gutter);
  block-size: 58px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
}

body:has(.withaside) .hd {
  max-inline-size: 66rem;
}

.hd::after {
  content: '';
  position: absolute;
  inset-inline: calc(50% - 50vw);
  inset-block-end: 0;
  block-size: 1px;
  background: var(--line);
}

.hd .mark { text-decoration: none; }

/* The member rail's lockup: the Arabic mark at 27 over 9.5px caps tracked
   wide — a third up from the mockup's 20 over 7.5, which read too small on
   the live page (the founder, 16 Sep 2026); it still sits inside the 58px
   bar. Scoped to the rail's header because the desk reuses `.mark .en` for
   the salon's own trading name, and 9.5px is a size only a logotype may be. */
.hd .mark .ar {
  font-size: 27px;
  font-weight: 400;
}

.hd a.mark .en {
  font-size: 9.5px;
  letter-spacing: 0.42em;
  margin-block-start: 2px;
}

.hd nav {
  display: flex;
  align-items: center;
  gap: 16px;
}

.hd nav a {
  font-size: 15px;
  font-weight: 500;
  color: var(--sub);
  text-decoration: none;
  padding-block: 4px;
  border-block-end: 1.5px solid transparent;
}

.hd nav a:hover {
  color: var(--ink);
}

/* The page she is on, said in ink over a fir rule — the mockup's underline is
   the action colour because the underline is where she is, not a border. */
.hd nav a[aria-current='page'] {
  color: var(--ink);
  font-weight: 600;
  border-block-end-color: var(--fir);
}

/* The header's seal is a link to what it means, and carries no ring shadow of
   its own — it sits against the page rather than on a card. */
.hd .seal { margin-block: 0; }

/* **Nothing scrolls sideways at 320** (the founder's AA ruling, 5 Oct 2026).
   Signed in, the wordmark, four tabs and the seal measured 356px in a 320px
   window — and 200% zoom on a 640px screen is the same box — so the whole
   page slid 36px. Under 360 the tabs sit closer and a half-step smaller;
   nothing is dropped and nothing wraps. */
@media (max-width: 360px) {
  .hd { gap: 10px; }
  .hd nav { gap: 10px; }
  .hd nav a { font-size: 14px; }
}
/* **And the seal keeps the gutter** (UX's look nit, 5 Oct 2026): under 340
   it sat 3px from the right edge against 20px on the left, so the tabs sit
   7px apart and the wordmark 6px from them — both edges at 20px. */
@media (max-width: 340px) {
  .hd { gap: 6px; }
  .hd nav { gap: 7px; }
}

.greet {
  font-family: var(--display);
  /* **Upright and in ink, everywhere.** The italic fir greeting predates the
     consolidated mockup, which sets every page title roman 600 in ink — the
     italic read bridal as a title, and fir is the action colour, not the
     title's. Italic survives only as a deliberate accent inside a line. */
  font-style: normal;
  font-weight: 600;
  /* The token block's `.h1`: 30/1.08 at −.012em, on every page title. */
  font-size: 38px;
  line-height: 1.08;
  letter-spacing: -0.012em;
  color: var(--ink);
  margin: 0;
}

/* **The tracked label is retired.** The handover's own law: *no tracked-caps
   section labels; serif titles instead* — and the frames draw it plainly, the
   word alone. *Coming*, *Past*, *Your salons*: Cormorant 19 in title ink, with
   no rule beside it, no leaf closing it and no tracking.

   The 9.5/600/.22em below it was measured twice and correct both times; what
   changed is not the measurement but what a section header is. A tracked
   micro-caps label is a filing tab — it names a drawer. A serif title is the
   page speaking, and this product's pages speak.

   Sentence case comes free: every template already writes these as sentences
   and the old rule shouted them. Nothing to re-word. */
.sect {
  font-family: var(--display);
  font-size: 26px;
  font-weight: 600;
  letter-spacing: normal;
  text-transform: none;
  color: var(--ink);
  margin-block: 26px 10px;
}

/* The fading rule went with the tracking: a serif title needs no ruled line to
   be a heading, and the two together read as a letterhead. */
.sect::after {
  content: none;
}

/* ====================================================== 4 · layout primitives */
/* Three, and no more. A system with a utility for every gap is a system with
   no layout at all — these exist because every surface needs vertical rhythm,
   a wrapping row, and a two-up, and re-inventing those per screen is how the
   dining rail's twenty-eight templates stopped adding up to a portal. */

.flow > * + * {
  margin-block-start: var(--flow-gap, 12px);
}

.cluster {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--cluster-gap, 8px);
}

/* A button is full-width by default, because most of the time it is the one
   thing on the screen to do. **In a cluster it is one of several**, so it
   sizes to its own words — otherwise the first exit takes the whole row and
   the other two wrap beneath it at three different widths, which is what
   O-04's three exits looked like. */
.cluster > form {
  flex: 0 0 auto;
  margin: 0;
}

.cluster .btn {
  inline-size: auto;
  padding-inline: 18px;
}

.pair {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(220px, 100%), 1fr));
  gap: 11px;
}

/* ============================================================ 5 · atoms */

.card {
  /* **An atom looks the same whichever element carries it.** A card is a
     `<div>` on most screens and an `<a>` wherever it is tappable, and an
     anchor is inline by default — so the border fragmented around its own line
     boxes and drew an empty rounded rectangle beside the content instead of
     around it. The same law already had to be written for `.chip`. */
  display: block;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius-card);
  box-shadow: var(--lift);
  padding: 15px 18px;
}

/* Label at the reading start, value at the reading end. The whole reason this
   is one atom: two surfaces rendering "label … value" differently is how a
   salon's number and MIORA's number start to look like different numbers. */
.lr {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  padding-block: 7px;
}

.lr + .lr {
  border-block-start: 1px solid var(--line);
}

.lr > dt,
.lr > .k {
  color: var(--sub);
  font-size: 16px;
}

.lr > dd,
.lr > .v {
  margin: 0;
  font-variant-numeric: tabular-nums;
  font-size: 16px;
  color: var(--ink);
}

/* An atom looks the same whichever element carries it. A chip rendered as a
   link picked up the browser's underline, which is the anti-coupon law losing
   to a user-agent default — and it would have shipped, because it only shows
   on the surfaces that make chips clickable. */
.chip,
.btn {
  text-decoration: none;
}

/* **The token block's two reading sizes.** `.p` is body — 14.5 on 1.55 in
   the sentence ink; `.s` is the small line — 12.5 on 1.5 in `sub`. Named
   here so a template says which it is rather than restating the numbers. */
.p {
  font-size: 16px;
  line-height: 1.55;
  color: var(--text);
}

.s {
  font-size: 13.5px;
  line-height: 1.5;
  color: var(--sub);
}

/* **Concierge's chip** — padding 8/13, a 1.2px hairline, 12.5 at 600 — where
   the garden's was a 26px sliver at 10.5. A tag row a thumb reads is a row of
   things a thumb can hit; the frame sets them at 36px tall and so does this. */
.chip {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 5px;
  /* **A button element inherits no font.** The chip atom never declared one,
     so every <button class="chip"> — the tip row, first among them — set its
     figures in the browser's Arial. Found by the verification harness reading
     computed styles; invisible to every eye that passed over it. */
  font-family: var(--ui);
  padding: 8px 13px;
  border-radius: var(--radius-chip);
  border: 1.2px solid var(--line);
  background: var(--card);
  color: var(--text);
  font-size: 13.5px;
  font-weight: 600;
  line-height: 1.25;
  white-space: nowrap;
}

.chip.on {
  background: var(--fir);
  border-color: var(--fir);
  color: var(--on-fir);
}

.chip.waiting {
  color: var(--amber);
  border-color: var(--rule);
}

.chip.open {
  color: var(--good);
}

.chip.gift {
  background: var(--rose-wash);
  border-color: var(--rose-line);
  color: var(--rose);
}

/* The one big number on a screen. One, deliberately — a screen with three hero
   numbers has told her nothing about which matters. */
.hero-num {
  font-family: var(--price-face, var(--hero));
  font-weight: var(--price-weight, 900);
  font-variant-numeric: tabular-nums;
  font-size: clamp(38px, 9vw, 56px);
  line-height: 0.95;
  color: var(--ink);
  margin: 0;
}

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  inline-size: 100%;
  /* 48 × r12, weight 600 at 14.5 — the Concierge token block's one button. */
  block-size: 48px;
  border: 1px solid transparent;
  border-radius: var(--radius-btn);
  background: var(--fir);
  color: var(--on-fir);
  font-family: var(--ui);
  font-size: 16px;
  font-weight: 600;
  cursor: pointer;
}

.btn:hover {
  background: var(--fir-deep);
}

.btn:focus-visible {
  outline: 2px solid var(--fir);
  outline-offset: 2px;
}

.btn.quiet {
  background: transparent;
  border-color: var(--fir);
  color: var(--fir);
}

/* **The card step, 1-06.** One line — *Card number* — inside the same card as
   the sentence that says what saving it means. The field is Stripe's iframe and
   it arrives unstyled, so the frame is ours: the same border, radius and focus
   the rest of the product's inputs wear, or the most trust-bearing moment on
   the rail is the one place the brand stops. */
.cardstep {
  margin-block-end: 16px;
}

.cardstep .card {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

/* The bill's field joined this rule the day it stopped being a Payment Element
   (G-362): the Payment Element drew its own frame, the Card Element does not,
   and an unframed iframe on the signature screen is the brand stopping at the
   moment it matters most. */
#card-element,
#element {
  border: 1px solid var(--line);
  border-radius: var(--radius-btn);
  padding: 13px 14px;
  background: var(--card);
}

#card-element.StripeElement--focus,
#element.StripeElement--focus {
  border-color: var(--fir);
}

/* **The card she already gave, named on the bill.** G-361: this screen mounted
   an element over a card already on file, so a visit asked for the same digits
   twice. The line is a statement, not a field — it sits at body weight above
   the button that says what it will take, and it carries **no mark at all**:
   the anti-coupon law's *no badge atom* holds here too, a Visa lozenge on the
   signature screen would be the first logo the rail has ever worn, and a drawn
   card glyph — tried, and looked at — read as a minus sign in a box. The rail
   has no icons anywhere else and the sentence does not need one. */
/* Two words that may not be parted by a line ending. Replaces a pair of
   `&nbsp;` entities in the door's headline — the words now come from one
   constant the app also renders, and a constant a client renders may not
   carry markup. */
.nowrap {
  white-space: nowrap;
}

.saidcard {
  margin: 0 0 4px;
  color: var(--ink);
}

/* **or pay by card** — the rule between a wallet and the fields it replaces.
   Hidden until a wallet actually mounts, because a divider with nothing above
   it says a choice was withheld. Not a heading: she is not choosing between
   two products, she is being told the shorter way exists. */
.orcard {
  display: flex;
  align-items: center;
  gap: 12px;
  margin: 16px 0;
  font-size: 13.5px;
  letter-spacing: 0.02em;
  color: var(--sub);
}

.orcard::before,
.orcard::after {
  content: "";
  flex: 1;
  block-size: 1px;
  background: var(--line);
}

/* **Who is taking her money**, under the footer's three links. Quieter than
   they are and on its own line: it is a fact she is entitled to and not a
   thing to read twice, and a processor verifying this business needs to find
   it on the front door rather than three pages in. */
.pagefoot .whois {
  flex-basis: 100%;
  margin: 10px 0 0;
  font-size: 12.5px;
  letter-spacing: 0.02em;
  color: var(--sub);
  text-align: center;
  /* On a phone this wraps, and left to itself it dropped `· Abu Dhabi` alone
     onto a second line — a two-word orphan under a full one. Balanced, the two
     lines are even and it reads as a sentence that happens to wrap. */
  text-wrap: balance;
}

/* The full words, one tap away and never further. Part A permits a summary to
   lead; the hash is always of the whole, which is why the whole is in the
   document rather than behind a request. */
.mandate summary {
  font-family: var(--ui);
  font-size: 15px;
  color: var(--sub);
  cursor: pointer;
}

.mandate-said {
  margin-block-start: 10px;
  max-block-size: 300px;
  overflow-y: auto;
  font-size: 13.5px;
  line-height: 1.55;
  color: var(--sub);
  white-space: pre-line;
}

/* The two lines under a page's name that say what it is. One size down from
   the heading and one up from a note — a lede is neither. */
.lede {
  font-family: var(--ui);
  font-size: 17px;
  line-height: 1.5;
  color: var(--sub);
  margin: 0 0 4px;
  max-inline-size: 34ch;
}

/* The invitation, where the prices are. Rose is this system's credit colour
   — the chip, the pane and the stack's credit line all wear it — so a gift
   reads as a gift here without a word saying so. */
.note.gift {
  color: var(--rose);
  margin-block-start: 10px;
}

/* "How is this real?" — the mechanism, one tap in.
   A `<details>` rather than a modal: no script to load, no state to manage, and
   with JavaScript off it degrades to an open block rather than to nothing. */
.how {
  margin-block-start: 14px;
  border-block-start: 1px solid var(--rule);
  padding-block-start: 12px;
}

.how > summary {
  font-family: var(--ui);
  font-size: 15px;
  font-weight: 600;
  color: var(--fir);
  cursor: pointer;
  /* The default triangle is a browser's idea of an affordance, not ours. */
  list-style: none;
}

.how > summary::-webkit-details-marker {
  display: none;
}

.how > summary::after {
  content: ' ›';
  color: var(--faint);
}

.how[open] > summary::after {
  content: ' ⌄';
}

.how > summary:focus-visible {
  outline: 2px solid var(--fir);
  outline-offset: 3px;
}

.how p {
  margin-block: 8px 0;
}

/* **A control that is off must look off.** There was no `:disabled` rule
   anywhere in this system, and five templates ship disabled controls — so
   every one of them rendered solid fir and fully live.

   Two of those are the release queue's dual approval, the only pair of
   controls in the product that moves money: disabled until a tranche is ready,
   and indistinguishable from ready. Somebody clicks Release, nothing happens,
   and they conclude the console is broken rather than that the tranche is not
   yet approved — which is the same failure as the button that was `type=button`
   with no form, arrived at from the other direction.

   Placed on the atom rather than on the pages, because the next disabled
   control should not have to remember. */
.btn:disabled,
.btn[aria-disabled='true'] {
  background: var(--line);
  border-color: var(--line);
  color: var(--faint);
  cursor: not-allowed;
}

/* Hover must not undo it — a control that lights up under the pointer is a
   control that says it can be pressed. */
.btn:disabled:hover,
.btn[aria-disabled='true']:hover {
  background: var(--line);
}

.btn.quiet:disabled,
.btn.plain:disabled {
  background: transparent;
  border-color: var(--line);
  color: var(--faint);
}

.btn.plain {
  background: transparent;
  border-color: transparent;
  color: var(--sub);
  font-weight: 600;
}

.sheet {
  background: var(--card);
  border: 1px solid var(--line);
  border-start-start-radius: var(--radius-sheet);
  border-start-end-radius: var(--radius-sheet);
  padding: 18px var(--gutter) 24px;
  box-shadow: 0 -18px 40px -24px rgb(51 64 47 / 0.3);
}

/* Waiting, degraded, wrong. `.banner.alert` is the only red on any surface and
   never appears beside money. */
.banner {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 10px 14px;
  border-radius: 12px;
  background: var(--peach-wash);
  border: 1px solid var(--peach-line);
  color: var(--ink);
  font-size: 13.5px;
}

.banner.alert {
  background: color-mix(in srgb, var(--alert) 8%, var(--ground));
  border-color: color-mix(in srgb, var(--alert) 26%, var(--ground));
}

/* **Every panel has one.** A blank space is a screen that failed silently; an
   empty state says why it is empty, in one warm line. A job that never ran
   reads `never run`, never a zero. */
.empty {
  padding: 22px 18px;
  text-align: center;
  color: var(--sub);
  font-size: 16px;
  border: 1px dashed var(--rule);
  border-radius: var(--radius-card);
}

.empty .why {
  display: block;
  margin-block-start: 4px;
  font-size: 13.5px;
  color: var(--faint);
}

/* A figure the surface could not fetch reads as a dash and says so. Content
   caches; numbers do not (UI spec law 8). */
.dash {
  color: var(--faint);
}

/* **Sticky things stick under the strip** (UX, 14 Oct 2026): where the strip
   is drawn (never on production), it is itself stuck at the top, 23px high
   (14 of line, 4 + 4 of padding, 1 of rule), and a member page's sticky
   chips and blocks stop below it rather than sliding under it. */
:root:has(.testmode) {
  --stuck-top: 23px;
}

/* Sandbox. Loud on purpose — the one place this system shouts. */
.testmode {
  position: sticky;
  inset-block-start: 0;
  z-index: 90;
  padding: 4px var(--gutter);
  /* **It was the loudest thing on the page and it is the least important.**
     Saturated brass at 30px pulled the eye before the salon's name did. The
     rebuild sets it as a hairline register in the identity fill: still
     unmissable if you are looking for it, invisible if you are not. */
  background: var(--raised);
  color: var(--brass);
  border-block-end: 1px solid var(--line);
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  text-align: center;
  line-height: 14px;
}

/* ============================================== 6 · the five inventions */

/* --- Rate Seal -------------------------------------------------------- */
/* Her standing rate, worn rather than announced. A medallion, not a badge:
   no starburst, no percentage that isn't hers, nothing that varies. */

/* **A rosette: her rate stamped inside a ring of petals.** Three shapes were
   tried in the open — a 46px medallion that stacked the figure over a 6.5px
   tier line nobody could read, a pill that said YOUR RATE beside it, and this,
   which the garden study settles on. The words went to the `aria-label`, which
   is where a screen reader was getting them anyway and where they are a
   sentence rather than tracked capitals. What is left is the figure, ringed.
 *
 * It is a seal and not a badge because it never varies, never states a
 * number that is not hers, and never moves to catch the eye: the one time it
 * moves is on the receipt she has just paid, once, opening round what she
 * paid (F182 A, the founder's yes, 13 Oct 2026). */
.seal {
  position: relative;
  inline-size: 56px;
  block-size: 56px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  text-decoration: none;
}

.seal .rr {
  position: absolute;
  inset: 0;
}

.seal b {
  position: relative;
  font-variant-numeric: tabular-nums lining-nums;
  font-size: 15px;
  font-weight: 600;
  color: var(--fir);
}

/* Prima's ring is drawn in brass rather than the base tone — the one visible
   difference a subscriber is paying for, and it is a material, not a badge. */
.seal:not(.free) .rr {
  --ring: var(--brass);
  --petal: var(--gold-leaf);
}

/* On a phone the rosette shrinks rather than losing anything: the ring scales
   with the box, so there is nothing to drop. */
@media (max-width: 559px) {
  .seal {
    inline-size: 44px;
    block-size: 44px;
  }

  .seal b {
    font-size: 13.5px;
  }
}



/* --- Ticket ----------------------------------------------------------- */
/* A visit as one large time, one state seal, one verb. The dominant object on
   Home whenever a visit exists, and silent when none does. */

.ticket {
  display: block;
  position: relative;
}

.ticket .state {
  display: flex;
  align-items: center;
  gap: 7px;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--fir);
}

.ticket .when {
  display: flex;
  align-items: baseline;
  gap: 10px;
  margin-block-start: 8px;
}

.ticket .when b {
  font-family: var(--display);
  font-weight: 600;
  font-size: 46px;
  line-height: 1;
  letter-spacing: -0.02em;
  color: var(--ink);
  /* Lining, or `11:00` reads as `II:OO` in Cormorant's oldstyle. */
  font-variant-numeric: tabular-nums lining-nums;
  font-feature-settings: 'tnum' 1, 'lnum' 1;
}

.ticket .when .meridiem {
  font-size: 13.5px;
  color: var(--sub);
  /* *pm · Sat 12*, as written: one clock for members, and it is never *PM*
     (Product, 24 Sep 2026). This set the frame's *PM · SAT 12* in capitals. */
}

/* The hour at 38 on a phone — the frame steps the 46 down where the card
   is the screen's width. The booking page's own ticket keeps 42: the page
   about the visit gets the bigger hour (frames 2-01/2-03 vs 2-04). */
@media (max-width: 559px) {
  .ticket .when b { font-size: 38px; }

  .tkpage .ticket .when b { font-size: 42px; }
}

/* F224 S14: the bill's amount as the card's big line — *Ð96 to pay* — and
   the words in its place when a gift or a package paid it all, which wrap. */
.ticket .when.tkfig b { line-height: 1.1; }
/* F224 fix 1: words in the figure's place take Home's sentence size, so
   *Your gift paid this bill* sits on one line at 390. */
.ticket .when.tkfig.tkwords b { font-size: 28px; letter-spacing: 0; }
.ticket .note.payby { color: var(--ink); }

/* A waiting state wears the asking gold, not the action fir — the frame
   colours the chip by what the visit is doing (2-01), and amber-as-waiting
   is this palette's own law. The bud is the awaiting leaf. */
.ticket:has(.leaf.bud) .state { color: var(--brass); }

/* The name card asks in the label register — tracked caps, the asking gold. */
/* The token block's tag: 10 at 700, tracked .16em, in the asking gold. */
.asklbl {
  display: block;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--brass);
  margin-block-end: 8px;
}

.ticket .who {
  font-size: 13.5px;
  color: var(--sub);
  margin-block-start: 5px;
}

.ticket .who b {
  color: var(--ink);
  font-weight: 700;
}

.ticket .btn {
  margin-block-start: 12px;
}

/* Leaf grammar: bud awaiting, leaf in the chair, petal paid. Three states of
   one growing thing rather than three unrelated icons — the visit is the same
   object throughout, and the vocabulary says so. */
.leaf {
  inline-size: 16px;
  block-size: 16px;
  border-radius: 999px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 11px;
  background: var(--fir);
  color: var(--on-fir);
  flex: 0 0 auto;
}

.leaf.bud {
  background: var(--raised);
  color: var(--fir);
}

.leaf.petal {
  background: var(--rose-wash);
  color: var(--rose);
}

/* --- Week-Dots -------------------------------------------------------- */
/* Seven days at a glance, with almost no words. Filled = open, hollow =
   closed, underline = today.
 *
 * **Availability points forward and never merchandises scarcity.** These say
 * when she can come; they never say how little remains. A count lives only
 * inside the slot picker, as the slots themselves. */

.week {
  display: flex;
  align-items: center;
  gap: 6px;
}

.week i {
  inline-size: 7px;
  block-size: 7px;
  border-radius: 999px;
  border: 1.4px solid var(--sub);
  opacity: 0.45;
  flex: 0 0 auto;
}

.week i.open {
  background: var(--good);
  border-color: var(--good);
  opacity: 1;
}

/* Today. `box-shadow` rather than `border-block-end` so the mark sits below
   the dot without changing its box — seven dots that grow on Tuesdays is a row
   that jitters through the week. */
.week i.today {
  box-shadow: 0 3px 0 -1px var(--brass);
}

.week span {
  font-size: 11px;
  letter-spacing: 0.06em;
  color: var(--sub);
  margin-inline-start: 4px;
}

/* --- Crest Tiles ------------------------------------------------------ */
/* A salon's identity, invented rather than photographed. Photography of
   interiors and clients is culturally constrained in this segment, so every
   image on screen is created — and a salon still has to be recognisable at a
   glance in a circle of five. */

.crest {
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius-card);
  box-shadow: var(--lift);
  padding: 13px 12px 12px;
  text-align: center;
  position: relative;
  overflow: visible;
}

.crest .glyph {
  inline-size: 34px;
  block-size: 34px;
  margin-inline: auto;
  color: var(--fir);
}

.crest h4 {
  font-family: var(--display);
  font-weight: 600;
  font-size: 22px;
  margin: 6px 0 0;
  color: var(--ink);
}

/* **§2's own law, broken by §2's own atom.** The rule above says Arabic sets
   in Amiri and reads *a size larger* — the script's x-height is smaller at the
   same point size — and the crest then set a salon's Arabic name at 9.5px
   against a 17px Latin: 56%, in a low-x-height Naskh, exactly where the
   comment warns small Arabic "looks timid". A large share of members in this
   segment read the Arabic name first, and at 9.5px it was decoration on the
   atom whose stated purpose is that a salon is recognisable at a glance. */
.crest .ar {
  font-family: var(--arabic);
  font-size: 15px;
  color: var(--ink);
  margin-block-start: 1px;
}

.crest .area {
  font-size: 11px;
  color: var(--faint);
}

/* "Something new here", and nothing more. Not a count of unread things and not
   a red dot — a quiet mark that resolves when she looks. */
.crest .new {
  position: absolute;
  inset-block-start: 10px;
  inset-inline-end: 10px;
  inline-size: 7px;
  block-size: 7px;
  border-radius: 999px;
  background: var(--rose-soft);
}

/* The salon's own wash, for its pane and its page header. A salon dresses its
   own surfaces; the actions on them stay fir. */
.crest.kit,
.kit {
  background: linear-gradient(165deg, var(--kit-wash, var(--card)), var(--card));
  border-color: var(--kit-line, var(--line));
}

/* --- Ribbon ----------------------------------------------------------- */
/* A horizontal pager. Pane one is always her usual; panes two to five carry
   live Pulse events and expire with them.
 *
 * **Never autoplays.** The peek is the only invitation to swipe — 14px of the
 * next pane's ground, widening to ~96px when that pane is a featured
 * invitation carrying its own colour. With no news there is one pane and no
 * dots at all: an empty week collapses silently, and filler is banned.
 *
 * Direction comes from the document. `scroll-snap` and logical padding do the
 * mirroring for free; nothing here names a side. */

.ribbon {
  display: flex;
  gap: 10px;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scroll-padding-inline: var(--gutter);
  padding-inline: var(--gutter);
  margin-inline: calc(var(--gutter) * -1);
  scrollbar-width: none;
}

.ribbon::-webkit-scrollbar {
  display: none;
}

.ribbon > .pane {
  flex: 0 0 min(300px, 82%);
  scroll-snap-align: center;
  border-radius: var(--radius-sheet);
  background: var(--card);
  border: 1px solid var(--line);
  padding: 14px 16px;
  min-block-size: 200px;
  display: flex;
  flex-direction: column;
}

/* The 14px sliver. It is a peek and not a card: it carries the next pane's
   ground so she knows there is something, and no content she could try to
   read. */
.ribbon > .pane.peek {
  flex-basis: 14px;
  min-block-size: 0;
  padding: 0;
  background: var(--peach-wash);
  border-color: var(--peach-line);
}

/* A featured invitation widens its peek to carry its own type-signature
   ground: package deep fir, access peach, arrival blush, gift rose. */
.ribbon > .pane.peek.featured {
  flex-basis: 96px;
}

.pane .kind {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--peach);
}

.pane h3 {
  font-family: var(--display);
  font-weight: 600;
  font-size: 26px;
  margin: 4px 0 0;
  color: var(--ink);
}

.pane .btn {
  margin-block-start: auto;
}

.pane.gift {
  background: var(--rose-wash);
  border-color: var(--rose-line);
}

.pane.gift .kind {
  color: var(--rose);
}

.pane.access {
  background: var(--peach-wash);
  border-color: var(--peach-line);
}

/* Page dots. Absent when there is one pane, because a single dot is a control
   that tells her nothing. */
.dots {
  display: flex;
  gap: 5px;
  justify-content: center;
  margin-block-start: 9px;
}

.dots i {
  inline-size: 5.5px;
  block-size: 5.5px;
  border-radius: 999px;
  background: var(--rule);
  transition: inline-size 160ms ease;
}

.dots i.on {
  inline-size: 15px;
  background: var(--fir);
}

/* ================================================ 7 · the bill stack */
/* posted -> her rate -> credit -> she pays. One component, four surfaces.
 *
 * A price never renders without her rate beside it, and the posted amount
 * stays visible to the end — the stack is the moment the brand is or is not
 * what it claimed. */

.stack {
  margin: 0;
}

.stack .rate .v {
  color: var(--fir);
}

.stack .credit .v {
  color: var(--rose);
}
/* F222 (UX's walk, 14 Oct 2026): a gift's state, *Ended · 11 Oct*, stays on
   one line at 320; the name beside it takes the wrap. */
:root.c0 .stack .credit .v,
:root.c0 .stack .spent .v { white-space: nowrap; }
/* A used or ended gift's row (`kind` *spent*): done, so quiet. */
.stack .spent .v { color: var(--sub); }

.stack .pays {
  border-block-start: 1.5px solid var(--ink);
  margin-block-start: 4px;
  padding-block-start: 10px;
}

/* The stack's own colours, per the frame: the posted line is quiet, the
   rate line is hers — fir — and the pays row asks in ink at 13.5/600. */
.stack .lr > .k { font-size: 15px; }

.stack .lr.posted .v { color: var(--sub); }

.stack .lr.rate .v { color: var(--fir); }

/* **The VAT inside what she paid** (the founder's pick 2B, 27 Sep 2026): one
   quiet row under the total, only once VAT is on. */
.stack .lr.vat > .k, .stack .lr.vat > .v { font-size: var(--t-caption); color: var(--sub); }

.stack .pays .k {
  color: var(--ink);
  font-weight: 600;
  font-size: 16px;
}

/* The figure she agrees to answers in her price's own face — the same
   Cormorant the ledger's column ends in, in fir, per the frame. */
.stack .pays .v {
  font-family: var(--price-face, var(--display));
  font-weight: var(--price-weight, 600);
  font-size: 30px;
  line-height: 1;
  color: var(--fir);
}

/* **Paid and received never share a container** (UI spec law 5). This is a
   separate object, always, on every surface — MIORA's part never touches her
   bill, and a shared border would say it did. */
.received {
  margin-block-start: 14px;
  background: var(--raised);
  border: 1px solid var(--line);
  border-radius: var(--radius-card);
  padding: 13px 16px;
}

.received h5 {
  margin: 0 0 6px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--sub);
}

.received .foot {
  margin-block-start: 6px;
  font-size: 13.5px;
  color: var(--faint);
}

/* ============================================================ 8 · a11y */

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

.visually-hidden {
  position: absolute;
  inline-size: 1px;
  block-size: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* ============================================================ 9 · asking her

   Forms. **The first surface with one arrived in Phase B**, and until then
   `core.css` styled none of these — so a sign-in page rendered a system-default
   white input on an ivory ground, in the browser's font, with the label jammed
   against it. Found by looking at the page.

   These are element selectors rather than classes on purpose. A form is markup
   somebody writes quickly at the end of a template, and an atom that has to be
   remembered is an atom that will not be. */

/* A full page on a phone, and a column on anything wider.
 *
 * **Not `.sheet`** — that is a bottom sheet: rounded top corners, a shadow cast
 * upward, made to sit against the bottom edge of a screen with content behind
 * it. Using it as a page container drew a box that ended two thirds of the way
 * down an empty page, which is what looking at the sign-in page found. */
.page {
  max-inline-size: 44rem;
  margin-inline: auto;
  padding: 20px var(--gutter) 40px;
  display: flex;
  flex-direction: column;
  gap: 14px;
}

.page > h1 {
  margin: 0;
}

.field {
  display: flex;
  flex-direction: column;
  gap: 5px;
  margin-block: 12px;
}

.field > label,
label.k {
  font-size: 13.5px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--sub);
}

input[type='text'],
input[type='tel'],
input[type='number'],
input[type='password'],
input[type='search'],
.pricesheet input[type='date'],
select,
textarea {
  inline-size: 100%;
  box-sizing: border-box;
  min-block-size: 46px;
  padding: 11px 13px;
  font: inherit;
  font-size: 16px;
  color: var(--ink);
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius-btn);
  /* 16px or larger, or iOS zooms the page on focus and she loses the form. */
}

textarea {
  min-block-size: 96px;
  resize: vertical;
}

/* Figures she types are figures: a phone number, a PIN, a six-digit code.
   `input.fig` is in **the one rule** that sets the figure face, up in §2 — a
   second declaration is exactly the shape of the bug that law exists to catch,
   and it carries the isolation with it. A code typed into an Arabic page must
   not reorder as she types it.

   Only the tracking is here, because that is about a keypad rather than a
   typeface. */
input.fig {
  letter-spacing: 0.08em;
}

/* **A tick is MIORA's green, not the phone's blue** (F115, version 3; UX, 5
   Oct 2026): with no accent-color, every checked box drew the system's blue
   in both themes. Fir is the green of the verb beside it, and has a dark
   twin. */
input[type='checkbox'] {
  accent-color: var(--fir);
}

input:focus-visible,
select:focus-visible,
textarea:focus-visible {
  outline: 2px solid var(--fir);
  outline-offset: 1px;
  border-color: var(--fir);
}

input::placeholder,
textarea::placeholder {
  color: var(--faint);
}

/* Links. Unstyled until Phase B, because until then no template had one — and
   the first one rendered as browser-default blue and underlined on an ivory
   ground, three inches under a bill set in Cormorant. Found by looking.

   Fir rather than blue, and the underline stays: an underline is how a link is
   recognisable to somebody who cannot rely on the colour. */
a {
  color: var(--fir);
  text-decoration-thickness: 1px;
  text-underline-offset: 2px;
}

a:hover {
  color: var(--fir-deep);
}

/* **A card that is a link is not underlined.** The underline is how an inline
   link is recognisable without relying on colour; drawn under every line of a
   whole card it is just noise, and it was — the collection rendered with a rule
   under the salon's name, its area and its availability sentence alike. */
a.card,
a.chip {
  color: inherit;
  text-decoration: none;
}

/* `a.btn` is deliberately absent. `.chip, .btn` already unsets the underline,
   and a type-and-class selector here would outrank `.btn` — which is exactly
   how folding buttons into the rule above once made every link-shaped primary
   button dark-on-dark. "Keep it" on the cancel sheet was legible only by
   knowing it was there. */

a.card:hover {
  border-color: var(--rule);
}

a:focus-visible {
  outline: 2px solid var(--fir);
  outline-offset: 2px;
  border-radius: 3px;
}

/* A quiet aside. **Not `.dash`** — that is the figure face, for an em dash and
   a number a surface could not fetch. Using it for prose set every sentence on
   the sign-in page in DM Mono, which is what looking at the page found. */
.note {
  color: var(--sub);
  font-size: 13.5px;
  line-height: 1.5;
  margin-block: 8px;
}

.note.faint {
  color: var(--faint);
  font-size: 13.5px;
}

/* **And why it did not.** The reason a form would not save, beside the form
   rather than on a screen of its own — which is where it used to go, taking
   what she had typed with it. Warm rather than red: this is almost always a
   typo on line three, and a page that alarms about a typo is a page that
   alarms about everything. */
.card.problem {
  border-color: var(--peach-line);
  background: var(--peach-wash);
  margin-block-end: 16px;
}

/* **It worked.** One line above the work, for the one page after the thing
   happened. Quiet on purpose: this is a receipt, not an alarm — the only place
   this system raises its voice is the sandbox ribbon, and a green banner for
   every saved form would teach people to stop reading the ones that matter. */
.note.said {
  color: var(--ink);
  background: var(--raised);
  border-radius: 10px;
  padding: 9px 12px;
  margin-block-end: 16px;
}

/* The same line on the member's rail, which cannot put it inside `<main>`.
 * Every page there opens its own, so `base.html` renders the flash just above
 * them and it has to take the column by itself — the column and no more, since
 * `.page`'s own block padding would open a gap above a page that said nothing
 * a moment ago. */
.note.said.adrift {
  max-inline-size: 44rem;
  margin-inline: auto;
  margin-block: 16px 0;
  inline-size: calc(100% - 2 * var(--gutter));
}

/* A struck line stays readable. O-10: a corrected bill shows what was struck on
   both screens, because a line that vanished is a line she cannot ask about. */
.struck .k,
.struck .v {
  text-decoration: line-through;
  color: var(--faint);
}

/* A "why" is a sub-line, wherever it sits.
   Only `.empty .why` was ever styled, so every other use of the class rendered
   inline and ran into the label above it: "Pause It stops taking new bookings",
   "Colour course · 6 sessions 260 a session on its own", "Hamdan sedr_admin ·
   +971501110001 · since 26 Aug". Found by reading four screens in a row and
   seeing the same sentence collapse each time. */
.why {
  display: block;
  margin-block-start: 4px;
  font-size: 13.5px;
  color: var(--faint);
  font-weight: 400;
  letter-spacing: 0;
  text-transform: none;
}

/* G-10 · a salon's face.
   A collection of at most two salons a month rendered as a name and an area is
   typographically a directory, and the scarcity is the product. A photograph
   when the salon has given one; its own monogram, in its own ink, when it has
   not — never a grey square apologising for a missing image. */
.face {
  display: inline-grid;
  place-items: center;
  flex: none;
  overflow: hidden;
  color: #fff;
  /* **`--font-en` was never defined.** An undefined `var()` is invalid at
     computed-value time, so every monogram silently inherited Karla from
     `body` and the intended face was unknowable from the code — the system's
     one unresolvable variable, in a file whose own comments hunt exactly this
     drift. A monogram is a display letterform: `--display`. */
  font-family: var(--display);
  font-weight: 500;
  letter-spacing: 0.02em;
  line-height: 1;
  /* The bidi isolate matters: an Arabic monogram beside a Latin name must not
     drag the name's punctuation to the other end of the line. */
  unicode-bidi: isolate;
}

.face img {
  inline-size: 100%;
  block-size: 100%;
  object-fit: cover;
}

.face-card {
  inline-size: 30px;
  block-size: 30px;
  border-radius: 9px;
  font-size: 13.5px;
  margin-inline-end: 2px;
  vertical-align: -8px;
}

/* **The page tile in the identity fill, not in slate.** The monogram takes a
   colour derived from the salon's own name, which is right in a circle of five
   where the point is telling rooms apart at a glance — and wrong at 52px
   beside the name it spells, where it was the only object on the page in a
   colour the token set does not contain. Here it wears sand and brass, and the
   salon's own derived ink stays where it does its work: the collection. */
.face-page {
  inline-size: 52px;
  block-size: 52px;
  border-radius: 15px;
  font-size: 22px;
  margin-block-end: 0;
  background: var(--raised);
  color: var(--brass);
  border: 1px solid var(--line);
}

/* The desk offline banner. Defined here too because the venue templates load
   core.css, and a rule that exists in one stylesheet is a banner that renders
   unstyled on half the screens that raise it. */
.offline {
  position: sticky;
  inset-block-start: 0;
  z-index: 40;
  margin: 0;
  padding: 10px 16px;
  background: #5A3C2F;
  color: #fff;
  font-size: 13.5px;
  line-height: 1.45;
  text-align: center;
}

/* The same rule on the member rail, for the same reason: her salon's own name
   and its own words for a service must render in an Arabic face whatever
   component they happen to sit in. */
[lang='ar'],
[lang='ar'] * {
  font-family: var(--arabic) !important;
  letter-spacing: 0 !important;
}

/* **Except a name.** `--arabic-display` exists for "the one place Arabic is a
   name rather than text" — and the blanket above was quietly defeating it
   with its !important, so بيت نورة under a lockup rendered in the reading
   face on every surface and nobody could tell (the fallback chain ends in
   the same glyphs at a different cut). Found by reading computed styles
   against the mockup, which is what the mockup round is for.

   **`.arn`, not a list of the components that have one.** This named two, and
   by then four components carried an Arabic name: `.gcard .arn` and `.srow
   .sr-name .arn` had been rendering in the reading face since they were
   written, and the salon card would have joined them — the same bug, found
   the same way, a second time. `.arn` means *Arabic name* everywhere in this
   file and nothing else ever wears it, so the exception is stated where the
   meaning is rather than once per component that remembers to ask. */
.arn {
  font-family: var(--arabic-display) !important;
}

/* The door, on every page. Quiet on purpose — it is furniture until the
   moment it is the only thing on the screen that helps, and a loud support
   link on a booking page is a product apologising in advance. */
.pagefoot {
  display: flex;
  flex-wrap: wrap;
  gap: 0 0.6rem;
  justify-content: center;
  align-items: center;
  margin-block: 3rem 1.5rem;
  padding-inline: 1rem;
}

/* One quiet line — the mockup sets the three doors with middots between. */
.pagefoot a + a::before {
  content: '·';
  margin-inline-end: 0.6rem;
  color: var(--faint);
}
.pagefoot a {
  color: var(--sub);
  font-family: var(--ui);
  font-size: 13.5px;
  letter-spacing: 0.04em;
  text-decoration: none;
}
.pagefoot a:hover,
.pagefoot a:focus-visible { color: var(--fir); text-decoration: underline; }

/* The day letters above Week-Dots. Seven dots said a salon opens on some days
   without saying which — the availability glance decorating rather than
   informing. Tracked to the dots' own rhythm so the two rows read as one. */
.week b.wd {
  display: inline-block;
  width: 7px;
  font-family: var(--ui);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0;
  text-align: center;
  color: var(--sub);
}
.week b.wd.today { color: var(--brass); }

/* =====================================================================
   The salon page, redrawn to the founder's redesign guide (14 Sep 2026):
   a slim band, the name over its Arabic, the afternoons as a pill, a rate
   card of two aligned columns with no strikethrough, a check on the row,
   the duration beside the name, variants as a picker inside one row, and a
   request card that is empty until she chooses. Tokens only; the atoms
   below are this page's and nobody else's.
   ===================================================================== */

/* The band, a third of what it was. */
.plate-head.slim {
  block-size: 120px;
  border-radius: 0;
}

.plate-head.slim svg,
.plate-head.slim img {
  inline-size: 100%;
  block-size: 100%;
  object-fit: cover;
  object-position: 100% 50%;
}

@media (max-width: 999px) {
  .plate-head.slim { block-size: 100px; }
}

/* The name, then its Arabic on its own line in the text face — the same
   ink family as the English, not a gold tag beside it. */
.salon-lock .n {
  font-family: var(--display);
  font-weight: 500;
  font-size: 42px;
  line-height: 1.05;
  letter-spacing: -0.01em;
  color: var(--ink);
  margin: 0;
}

/* **P2's sizes on a phone** (F213; the founder's frames at 390 and 320; UX,
   14 Oct 2026, AFTER_APPLE only, by `.n-fit`): under 600px the name is the
   app's 34/37; wider, it keeps 42. */
@media (max-width: 599px) {
  .salon-lock .n.n-fit {
    font-size: 34px;
    line-height: 37px;
    letter-spacing: -0.01em;
  }
}

/* **P2: a long name in two lines, not three**: where the name measures three
   lines or more at its own size, it steps down to 27/31, as the app's does.
   Nothing else moves. After the phone size, so it wins there too. */
.salon-lock .n.n-fit.n-long {
  font-size: 27px;
  line-height: 31px;
  letter-spacing: -0.01em;
}

/* **S9. One Arabic face for a salon's name** (the founder's ruling on the
   wow review, 5 Oct 2026): the cards' gold Aref Ruqaa on the salon page too.
   Her own name in Home's greeting is not a salon's and keeps its face. */
.salon-lock .arn-line {
  font-family: var(--arabic-display);
  font-size: 24px;
  line-height: 1.5;
  color: var(--brass);
  margin: 4px 0 0;
  text-align: start;
}

/* Where, when, and the product as a pill. */
.salon-lock .meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px 22px;
  margin-block-start: 10px;
  color: var(--sub);
  font-size: 14px;
}

.salon-lock .meta .fact {
  display: inline-flex;
  align-items: center;
  gap: 8px;
}

.salon-lock .meta .fact .mark { margin: 0; }

.pill.window {
  display: inline-flex;
  align-items: center;
  padding: 3px 11px;
  border-radius: 999px;
  border: 1px solid color-mix(in srgb, var(--fir) 32%, var(--line));
  background: color-mix(in srgb, var(--fir) 10%, var(--card));
  color: var(--fir);
  font-size: 13px;
  font-weight: 500;
  flex: none;
}

/* **The chips and the two heads are one sticky block** (v13). The rail
   keeps its own scroller on a phone; here it is not the sticky thing, the
   block is. */
.sticky {
  position: sticky;
  inset-block-start: var(--stuck-top, 0px);
  z-index: 2;
  background: var(--ground);
  border-block-end: 1px solid var(--line);
}

.sticky .cats {
  position: static;
  margin-block-end: 0;
}

/* Two heads over two columns: 14px semibold in `faint`, each with its own
   mark — the storefront for the salon's price, the flower for hers — and
   hers on a mist tab that joins the panel under it.

   **The column is as wide as its head needs.** v13 set 108px for *With
   Miora*; *With MIORA* is ten pixels wider, and at 108 the flower stood
   four pixels outside its tab (the founder, 16 Sep 2026). 120 seats the
   mark, the gap and the word inside the tab's own padding. */
.cols,
.ledger { --rate-col: 120px; }

/* **The tint, the panel and the tab share one right edge.** The rows
   carried 12px of padding on both sides while the heads and the panel
   stopped 12px short of the column, so a chosen row's tint ran past the
   panel on the right (the founder, 16 Sep 2026). Nothing is inset on the
   right now: her cell is the last 120px of the row, the panel is the last
   120px of the list, the tab the last 120px of the heads. */
.cols {
  display: flex;
  justify-content: flex-end;
  align-items: flex-end;
  gap: 0;
  padding: 8px 0 0 12px;
  font-size: 14px;
  font-weight: 600;
  color: var(--faint);
}

.cols span {
  display: inline-flex;
  justify-content: flex-end;
  align-items: center;
  gap: 7px;
  inline-size: var(--rate-col);
  box-sizing: border-box;
  padding: 7px 14px 7px 0;
  white-space: nowrap;
}

/* The currency, once, just before the heads (Product, 25 Sep 2026) — inside
   the salon's head, so it moves with it. */
.cols .h-unit { font-size: inherit; font-weight: 600; margin-inline-end: 3px; }

.cols svg { inline-size: 15px; block-size: 15px; flex: none; }
.cols .eye { fill: var(--band); }

.cols .h-you {
  position: relative;
  z-index: 1;
  color: var(--ink);
  background: var(--band);
  border-radius: 8px 8px 0 0;
  padding: 7px 8px 8px;
  margin-block-end: -1px;
}

/* The mist panel: one continuous ground behind every row's second column,
   from the head's tab to the last row, confined to the column's box. The
   rows sit above it. */
.ledger { position: relative; }

.ledger .mist {
  position: absolute;
  inset-block: 0;
  inset-inline-end: 0;
  inline-size: var(--rate-col);
  background: var(--band);
  border-radius: 0 0 8px 8px;
  z-index: 0;
}

/* The row: a radio, the name with its duration, two figures in two columns.
   Hers is the loud one — 18px semibold in ink on the mist — the salon's
   quiet at 14; no strikethrough anywhere. */
.ledger .lr.svc {
  position: relative;
  z-index: 1;
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 14px 0 14px 12px;
  border-radius: 10px;
  border-block-end: 1px solid var(--line);
  cursor: pointer;
}

.ledger .lr.svc:hover { background: color-mix(in srgb, var(--ink) 3.5%, transparent); }

/* **A hidden row is hidden — again.** The rule above is more specific than
   `[data-cat][hidden]` and later in the file, so every row a chip had
   hidden came back the moment the row was restyled: the short list and all
   seven categories on one page, with *Featured* lit. Seen on the dev rail,
   15 Sep 2026. Said here, after the rule that outranked it. */
.ledger .lr.svc[hidden],
.ledger .svc-group[hidden],
.ledger .cat-head[hidden] {
  display: none;
}

/* The one selection tint, fir at a tenth over whatever is under it. */
.ledger .lr.svc.on,
.ledger .lr.svc[aria-pressed="true"] {
  background: color-mix(in srgb, var(--fir) 10%, transparent);
  border-block-end-color: transparent;
}

/* Two chosen lines in a row keep a sliver of ground between their tints
   (the founder, 16 Sep 2026) — otherwise they read as one block. */
.ledger .lr.svc.on + .lr.svc.on,
.ledger .lr.svc.on + .svc-group > summary.on,
.ledger .svc-group:has(> summary.on) + .lr.svc.on {
  margin-block-start: 4px;
}

.ledger .lr.svc[aria-pressed="true"]::before { content: none; }

/* The control slot: a radio on a line she can choose, a caret on a parent
   that opens. */
.ledger .ctl {
  flex: none;
  inline-size: 20px;
  block-size: 20px;
  display: grid;
  place-items: center;
}

.ledger .ctl.radio {
  border-radius: 50%;
  border: 1.5px solid var(--faint);
  background: var(--card);
  box-sizing: border-box;
}

.ledger .ctl.radio i {
  display: none;
  inline-size: 10px;
  block-size: 10px;
  border-radius: 50%;
  background: var(--fir);
}

.ledger .lr.svc.on .ctl.radio,
.ledger .lr.svc[aria-pressed="true"] .ctl.radio { border-color: var(--fir); }

.ledger .lr.svc.on .ctl.radio i,
.ledger .lr.svc[aria-pressed="true"] .ctl.radio i { display: block; }

/* A service is a checkbox (v16): a 5px box, a check when chosen. */
.ledger .ctl.box {
  border-radius: 5px;
  border: 1.5px solid var(--faint);
  background: var(--card);
  color: var(--on-fir);
  box-sizing: border-box;
}

.ledger .ctl.box svg {
  display: none;
  inline-size: 11px;
  block-size: 11px;
}

.ledger .lr.svc.on .ctl.box,
.ledger .lr.svc[aria-pressed="true"] .ctl.box {
  background: var(--fir);
  border-color: var(--fir);
}

.ledger .lr.svc.on .ctl.box svg,
.ledger .lr.svc[aria-pressed="true"] .ctl.box svg { display: block; }

.ledger .lr.svc > .k {
  flex: 1 1 auto;
  min-inline-size: 0;
  font-size: 16px;
  font-weight: 500;
  color: var(--ink);
}

.ledger .lr.svc .dur {
  font-size: 13px;
  font-weight: 400;
  color: var(--faint);
  margin-inline-start: 10px;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

/* Under the name: the prompt while a parent is open, the chosen variant
   and its minutes once it is closed on a choice. */
.ledger .lr.svc .sub {
  display: block;
  font-size: 13px;
  font-weight: 400;
  color: var(--sub);
  margin-block-start: 2px;
}

.ledger .lr.svc .prices {
  display: flex;
  align-items: baseline;
  flex: none;
  gap: 0;
  padding: 0;
  white-space: nowrap;
  font-variant-numeric: tabular-nums lining-nums;
}

.ledger .lr.svc .prices .salon {
  inline-size: var(--rate-col);
  box-sizing: border-box;
  padding-inline-end: 14px;
  text-align: end;
  font-family: var(--ui);
  font-size: 14px;
  font-weight: 400;
  color: var(--faint);
}

.ledger .lr.svc .prices .v {
  inline-size: var(--rate-col);
  min-inline-size: 0;
  box-sizing: border-box;
  padding-inline: 8px;
  text-align: end;
  font-family: var(--ui);
  font-size: 18px;
  font-weight: 600;
  line-height: 1.2;
  color: var(--ink);
}

.ledger .lr.svc .prices .note { font-size: 13px; }

/* **How many? in the row she ticked** (the price lines' pick 2A; UX's check
   against the frames, 27 Sep 2026): a line by the unit, once chosen, is the
   row's own drop — its box, name and figures, as any chosen row — and
   − n + under the name, the whole of it under the one tint. The drop keeps
   the row's measures, so the pill starts where the name does. */
.ledger .counted {
  position: relative;
  z-index: 1;
  border-radius: 10px;
  background: color-mix(in srgb, var(--fir) 10%, transparent);
  padding-block-end: 12px;
}

.ledger .counted[hidden] { display: none; }

.ledger .counted > .lr.svc.on {
  inline-size: 100%;
  background: none;
  padding-block-end: 8px;
}

/* No hover band of its own: on a phone a tap leaves :hover behind, and half
   the row a shade darker reads as two rows. */
.ledger .counted > .lr.svc.on:hover { background: none; }

.ledger .lr.svc.on + .counted,
.ledger .counted + .lr.svc.on,
.ledger .counted + .counted {
  margin-block-start: 4px;
}

.ledger .counted .stp,
.menu-counted .stp {
  display: inline-flex;
  align-items: center;
  margin-inline-start: 44px;
  border: 1px solid var(--fir);
  border-radius: 999px;
  overflow: hidden;
  background: var(--card);
}

.ledger .counted .stp button,
.menu-counted .stp button {
  inline-size: 44px;
  block-size: 34px;
  padding-inline: 0;
  padding-block: 0;
  border: 0;
  background: none;
  color: var(--fir);
  font-family: var(--ui);
  font-size: 19px;
  font-weight: 600;
  line-height: 1;
  cursor: pointer;
}

.ledger .counted .stp button:disabled,
.menu-counted .stp button:disabled {
  color: var(--faint);
  cursor: default;
}

.ledger .counted .stp button:focus-visible,
.menu-counted .stp button:focus-visible {
  outline: 2px solid var(--fir);
  outline-offset: -2px;
}

.ledger .counted .stp b,
.menu-counted .stp b {
  min-inline-size: 2.2ch;
  text-align: center;
  font-family: var(--ui);
  font-size: 16px;
  font-weight: 700;
  color: var(--ink);
  font-variant-numeric: tabular-nums lining-nums;
}

/* Service is the unit (v13, v16): a parent row that opens and closes, its
   variants as child rows beneath in the same two columns, each with its
   own radio. A `details`, so it works with no script. Open, the group is a
   framed sheet — the line drawn outside the box so nothing inside shifts,
   white at 55% over the page, 8px above and below. */
.svc-group { border-block-end: 1px solid var(--line); }
.svc-group > summary { list-style: none; }
.svc-group > summary::-webkit-details-marker { display: none; }
.svc-group > summary.lr.svc { border-block-end: 0; }

.ledger .svc-group[open] {
  margin-block: 8px;
  border-block-end: 0;
  border-radius: 10px;
  box-shadow: 0 0 0 1px var(--line);
  background: color-mix(in srgb, var(--card) 55%, transparent);
}

.ledger .svc-group[open] > summary.lr.svc { border-radius: 10px 10px 0 0; }

/* Three looks. Closed with nothing chosen: an empty box, the spans, the
   options count. Open: the box hidden, the prompt in green under the name,
   the figures aside for the children's. Closed on a choice: checked and
   tinted, the variant's name and its minutes, the chosen figures. */
/* (`summary.lr.svc` throughout: the row's own `.sub` and `.dur` rules
   carry four classes, and a parent's states have to outrank them.) */
.ledger .svc-group > summary.lr.svc .sub,
.ledger .svc-group > summary.lr.svc .dur.pick,
.ledger .svc-group > summary.lr.svc .picked { display: none; }

/* Open, the parent is not the chosen thing — the variant is — so it drops
   the tint it wears when closed on a choice. */
.ledger .svc-group[open] > summary.lr.svc.on,
.ledger .svc-group[open] > summary.lr.svc[aria-pressed="true"] { background: transparent; }
.ledger .svc-group[open] > summary.lr.svc:hover { background: color-mix(in srgb, var(--ink) 3.5%, transparent); }
.ledger .svc-group[open] > summary.lr.svc .ctl.box { visibility: hidden; }
.ledger .svc-group[open] > summary.lr.svc .sub.prompt {
  display: block;
  color: var(--fir);
  font-weight: 500;
}
.ledger .svc-group[open] > summary.lr.svc .prices { visibility: hidden; }

.ledger .svc-group:not([open]) > summary.lr.svc.has-pick .sub.pick { display: block; }
.ledger .svc-group:not([open]) > summary.lr.svc.has-pick .dur.pick { display: block; }
.ledger .svc-group:not([open]) > summary.lr.svc.has-pick .dur.span,
.ledger .svc-group:not([open]) > summary.lr.svc.has-pick .spans { display: none; }
.ledger .svc-group:not([open]) > summary.lr.svc.has-pick .picked { display: contents; }

.ledger .svc-group .spans { display: contents; }

.svc-group .kids .lr.svc.child {
  padding-inline-start: 44px;
  border-radius: 0;
  border-block-start: 1px solid var(--line);
  border-block-end: 0;
}

.svc-group .kids .lr.svc.child:last-child { border-radius: 0 0 10px 10px; }

/* On a phone the two columns share 180px unevenly — hers 104, the salon's
   76 — so *With MIORA* and its flower sit on one line inside the tab at
   12px; the salon's head is right-aligned and may reach past its own cell
   to the left, where there is nothing. The app splits the same way. */
@media (max-width: 999px) {
  .ledger,
  .cols { --rate-col: 104px; --salon-col: 76px; }
  .ledger .lr.svc { gap: 10px; padding-inline: 8px 0; }
  .cols { padding-inline: 8px 0; font-size: 12px; }
  .cols span { padding-inline-end: 6px; }
  .cols .h-salon,
  .ledger .lr.svc .prices .salon { inline-size: var(--salon-col); }
  .ledger .lr.svc > .k { font-size: 15px; }
  .ledger .lr.svc .prices .salon { padding-inline-end: 8px; font-size: 13px; }
  .ledger .lr.svc .prices .v,
  .cols .h-you { padding-inline: 5px; }
  .ledger .lr.svc .prices .v { font-size: 16px; }
  /* At 76px a span with places — `150.00–220.00` — ran into the next
     column. A span may take two lines, breaking after its dash. */
  .ledger .lr.svc .prices .salon,
  .ledger .svc-group .spans .v { white-space: normal; line-height: 1.25; }
  .svc-group .kids .lr.svc.child { padding-inline-start: 38px; }
}

/* The category head: the guide's 15px medium, the Arabic beside it. */
.cat-head {
  padding: 22px 12px 4px;
  font-size: 15px;
  font-weight: 500;
  letter-spacing: 0;
  text-transform: none;
  color: var(--ink);
}

.cat-head [lang='ar'] {
  font-size: 15px;
  font-weight: 400;
  color: var(--faint);
}

/* The request card, in its two states. */
.ask .lbl { margin: 0 0 8px; }

.ask .card-empty {
  color: var(--sub);
  font-size: 14px;
  line-height: 1.5;
  margin: 0 0 18px;
}

.ask .svc-name {
  font-size: 16px;
  font-weight: 500;
  line-height: 1.35;
  margin: 0;
  color: var(--ink);
}

.ask .svc-sub {
  color: var(--sub);
  font-size: 14px;
  margin: 3px 0 0;
}

.ask .prices2 {
  margin: 14px 0 18px;
  font-variant-numeric: tabular-nums;
}

.ask .prices2 div {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  padding: 8px 0;
  border-block-start: 1px solid var(--line);
  color: var(--sub);
  font-size: 14px;
}

.ask .prices2 dt,
.ask .prices2 dd { margin: 0; }

.ask .prices2 .you { color: var(--ink); font-weight: 500; font-size: 15px; }
.ask .prices2 .you dd { font-size: 22px; }
.ask .prices2 .less { color: var(--fir); font-size: 13px; border-block-start: 0; padding-block-start: 0; }

.ask .btn:disabled,
.ask .btn:disabled:hover {
  background: color-mix(in srgb, var(--raised) 60%, var(--card));
  border-color: transparent;
  color: var(--faint);
  cursor: default;
}

.ask .after {
  color: var(--faint);
  font-size: 13px;
  margin: 12px 0 0;
  text-align: center;
}

/* The basket: one line per service, the name over the variant and its
   minutes, hers with the salon's small under it, an × to take it out. */
.ask .basket {
  list-style: none;
  margin: 4px 0 0;
  padding: 0;
}

.ask .basket .item {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 9px 0;
  border-block-start: 1px solid var(--line);
}

.ask .basket .item:first-child { border-block-start: 0; }
.ask .basket .t { flex: 1 1 auto; min-inline-size: 0; }
.ask .basket .n { display: block; font-size: 14px; font-weight: 500; line-height: 1.3; }
.ask .basket .d { display: block; font-size: 12px; color: var(--sub); }

.ask .basket .p {
  font-size: 14px;
  font-weight: 600;
  white-space: nowrap;
  text-align: end;
  font-variant-numeric: tabular-nums;
}

.ask .basket .p small {
  display: block;
  font-weight: 400;
  color: var(--faint);
  font-size: 12px;
}

/* A line by the unit before she counts: what the verb waits for. */
.ask .basket .p.asks {
  font-weight: 500;
  color: var(--fir);
}

.ask .basket .x {
  font: inherit;
  font-size: 18px;
  line-height: 1;
  color: var(--faint);
  background: none;
  border: 0;
  padding: 0 2px;
  margin-block-start: -2px;
  cursor: pointer;
}

.ask .basket .x:hover { color: var(--ink); }

/* The totals' last line: how long on the left, the difference on the right. */
.ask .prices2 .less dt { color: var(--faint); font-weight: 400; }


/* **What deleting costs her, first** (Product, 24 Sep 2026): the forfeit lines
   lead the card in the page's ink, one to a line, before the paragraph. */
.card p.del-warn { margin: 0 0 8px; font-size: 15.5px; font-weight: 600; color: var(--ink); }
.card p.del-warn + p:not(.del-warn) { margin-block-start: 12px; }

/* **The public gate** (the founder, 24 Sep 2026: "gate yes"): the mark and one
   line, in the middle of the column, and the two documents under them. */
.page.cs-wrap { min-block-size: 78vh; align-items: center; justify-content: center; text-align: center; gap: 22px; }
.cs-wrap .mark { transform: scale(1.6); transform-origin: center; }
.cs-line { margin: 18px 0 0; max-inline-size: 22ch; font-family: var(--display); font-weight: 600; font-size: clamp(28px, 6vw, 40px); line-height: 1.12; color: var(--ink); text-wrap: balance; }
.cs-line .cs-when { display: block; }
.pagefoot.cs-foot { margin-block: 2.5rem 0; }


/* **Section P** (the founder's pick, 24 Sep 2026): the room leads, and a salon
   without a photograph wears its identity — never flowers on a card. */

/* The small square, wherever the salon is named small: the room, or the letter
   tile Home's visit card already wears (the same rule, lifted). */
.face-tile {
  flex: none;
  inline-size: 40px;
  block-size: 40px;
  border-radius: 10px;
  border: 1px solid var(--line);
  background: var(--card);
  display: grid;
  place-items: center;
  overflow: hidden;
  font-family: var(--display);
  font-weight: 600;
  font-size: 18px;
  line-height: 1;
  color: var(--face-ink, var(--fir));
}
.face-tile img { inline-size: 100%; block-size: 100%; object-fit: cover; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme='light']) .face-tile { color: var(--ink); }
}
:root[data-theme='dark'] .face-tile { color: var(--ink); }

/* The seal: two letters on the paper tint inside a drawn ring. */
.face-seal {
  flex: none;
  inline-size: 54px;
  block-size: 54px;
  border-radius: 50%;
  border: 1.5px dashed var(--amber);
  background: var(--pill);
  display: grid;
  place-items: center;
  font-family: var(--display);
  font-weight: 600;
  font-size: 22px;
  line-height: 1;
  color: var(--fir);
}
.face-seal.seal-lg { inline-size: 64px; block-size: 64px; font-size: 26px; }

/* The room, swiped. The strip scrolls by itself; `photos.js` lights the dot. */
.shots { display: block; position: relative; overflow: hidden; }
.shots .shots-strip {
  display: flex;
  inline-size: 100%;
  block-size: 100%;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
}
.shots .shots-strip::-webkit-scrollbar { display: none; }
/* **Inside a card the strip does not scroll by itself** (the founder's AA
   ruling, 5 Oct 2026): a scroller must be focusable, and inside the card's
   link a focusable strip is a control inside a control. So it is clipped,
   and `photos.js` moves it under her finger and settles it on a photograph
   — the same swipe, the same dots; the card's link is the keyboard's way to
   every photograph, on the salon's page. */
.shots .shots-strip[data-swipe] {
  overflow-x: hidden;
  scroll-snap-type: none;
  touch-action: pan-y;
}
/* On the salon's page the strip is a stop of its own; the ring sits inside
   it, because the band clips anything drawn outside. */
.shots .shots-strip:focus-visible { outline: 2px solid var(--fir); outline-offset: -4px; }
.shots .shots-strip > img {
  position: static;
  flex: 0 0 100%;
  inline-size: 100%;
  block-size: 100%;
  object-fit: cover;
  scroll-snap-align: start;
}
/* **On their own dark pill** (the founder's yes, 27 Sep 2026; UX with Codex):
   white dots on a white basin vanished, so they sit on the room's ink,
   see-through, and read on any photograph — the app draws the same. */
.shots-dots {
  position: absolute;
  inset-block-end: 10px;
  inset-inline-end: 10px;
  display: flex;
  gap: 5px;
  padding-block: 5px;
  padding-inline: 7px;
  border-radius: 999px;
  background: rgb(31 40 34 / 0.45);
  pointer-events: none;
}
.shots-dots i { inline-size: 6px; block-size: 6px; border-radius: 50%; background: rgb(255 255 255 / 0.55); }
.shots-dots i.on { background: #fff; }

/* The Explore card: the room fills its top, about 16:10. */
.sc .plate.sc-room { block-size: auto; aspect-ratio: 16 / 10; }
.sc .plate.sc-room .shots { position: absolute; inset: 0; }
/* Without one: the seal beside both names, and the card is shorter. */
.sc .sc-head { display: flex; align-items: center; gap: 12px; }
.sc .sc-head .nm { flex-direction: column; align-items: flex-start; gap: 2px; }
.sc .sc-says { display: flex; flex-wrap: wrap; gap: 8px; margin-block-start: 10px; }
.sc .sc-says .ev,
.sc .sc-says .yours { position: static; border: 1px solid var(--line); }

/* The salon page: a full-width band of the room, or a short paper band with the seal. */
.plate-head.band-room { block-size: auto; aspect-ratio: 16 / 10; max-block-size: 300px; }
.plate-head.band-room .shots { position: absolute; inset: 0; }
.plate-head.band-seal {
  block-size: 96px;
  background: var(--pill);
  display: flex;
  align-items: center;
  padding-inline: var(--gutter);
}

/* The small surfaces' own boxes carry the tile now, at their old sizes. */
.row .face-tile { inline-size: 52px; block-size: 52px; border-radius: 14px; font-size: 21px; }
.sent-salon .face-tile,
.rv-head .face-tile { inline-size: 44px; block-size: 44px; border-radius: 12px; }

/* The bill's own lines before she pays (24 Sep 2026): Check your booking's rows,
   with the salon's additions named under their line. */
.bill-lines .bill-added,
.stack .bill-added { display: block; margin-block-start: 2px; font-size: 12.5px; color: var(--brass); }

/* **One statement of the hold** (the founder's Round 2, #3 A): a padlock
   callout on the paper tint, the sentence first and the rest quiet. */
.hold-callout { display: flex; gap: 10px; align-items: flex-start; margin-block: 14px 4px; padding: 12px 14px; border: 1px solid var(--line); border-radius: 12px; background: var(--pill); }
.hold-callout .hi { flex: none; margin-block-start: 2px; }
.hold-callout p { margin: 0; line-height: 1.45; }
.hold-callout .note { display: block; margin-block-start: 2px; }

/* **F-fees** (Product P-8 #7; the founder's 1A, 18 Oct 2026): the hold, then
   this visit's fees, one line each with its mark in a round tint, hairlines
   between, as frame card-A draws them. */
.fee-lines { margin-block: 14px 4px; padding: 4px 14px; border: 1px solid var(--line); border-radius: 12px; background: var(--card); }
.fee-line { display: flex; gap: 12px; align-items: flex-start; padding-block: 10px; border-block-end: 1px solid var(--line); }
.fee-line:last-child { border-block-end: 0; }
.fee-line p { margin: 0; line-height: 1.45; overflow-wrap: anywhere; }
.fee-mark { flex: none; display: grid; place-items: center; inline-size: 30px; block-size: 30px; border-radius: 50%; background: var(--pill); color: var(--fir); }
.agreeing { margin-block: 10px 0; }
.agreeing summary { text-decoration: underline; color: var(--fir); }

/* U4: the total under two services or more — *You pay*, both figures. */
.ck-row.ck-total { border-block-start: 1px solid var(--line); margin-block-start: 4px; padding-block-start: 12px; }

/* R3: Legal's sentence under *Add your card*. */
.card-terms { margin-block: 0 10px; }
.card-terms a { color: var(--fir); }

/* **E2E-0246** (the founder's 1A): the card form was stopped. A tinted box
   with a brass edge, its sentence and *Try again*. */
.card-blocked { margin-block: 4px 12px; padding: 12px 14px; border: 1px solid var(--brass); border-radius: var(--radius-btn); background: var(--pill); }
.card-blocked p { margin: 0 0 4px; }
.card-blocked .btn { margin-block-start: 8px; inline-size: 100%; }

/* **The code, as six boxes** (#5 A; UX audit R11, 24 Sep 2026). With script,
   the one field lies over the boxes, transparent — taps and the phone's
   autofill reach it — and six digits submit; without script it is the plain
   field and its button. */
.otp { display: none; }
.otp-on .otp-wrap { position: relative; }
.otp-on .otp { display: flex; justify-content: center; gap: 8px; }
.otp-on .otp-box {
  inline-size: 46px;
  block-size: 56px;
  display: grid;
  place-items: center;
  border: 1.2px solid var(--line);
  border-radius: 12px;
  background: var(--card);
  font-size: 24px;
  font-weight: 600;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}
.otp-on .otp-box.cur { border: 2px solid var(--fir); }
.otp-on .otp-field {
  position: absolute;
  inset: 0;
  inline-size: 100%;
  opacity: 0;
}
.otp-on .otp-go { display: none; }
.otp-wait { text-align: center; color: var(--sub); }


/* **Her tax document, whole and in both languages** (the founder's pick 3A on
   UX's VAT board, 27 Sep 2026): English on the left, Arabic on the right, the
   figures between, in the stack's two places. Printed as it reads. */
.taxdoc { max-inline-size: 720px; }
/* Plex Arabic sits larger than Instrument at one size: a tenth off, so the
   two languages read at one weight across the line. */
.taxdoc [lang="ar"] { font-family: var(--arabic); font-size: 0.9em; }
.taxdoc-head h1 { display: flex; justify-content: space-between; align-items: baseline; gap: 16px; flex-wrap: wrap; }
/* Its own inline end is the left, so wrapped under the English it still
   keeps to the right. */
.taxdoc-head h1 [lang="ar"] { font-size: 0.7em; font-weight: 600; margin-inline-end: auto; }
.taxdoc-test {
  display: inline-block;
  margin-block: 8px 0;
  padding-block: 2px;
  padding-inline: 8px;
  border-radius: 6px;
  background: var(--peach-wash);
  color: var(--peach);
  font-size: var(--t-caption);
  font-weight: 600;
}
.taxdoc-issuer { margin-block: 12px 0; text-align: center; color: var(--sub); font-size: var(--t-caption); }
.taxdoc-issuer span { display: block; }
.taxdoc-rows { margin-block-start: 16px; }
.taxdoc-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
  align-items: baseline;
  gap: 12px;
  padding-block: 7px;
  border-block-end: 1px solid var(--line);
  font-size: 14.5px;
}
.taxdoc-row .en { color: var(--sub); }
.taxdoc-row .num { text-align: center; color: var(--ink); font-variant-numeric: tabular-nums lining-nums; }
/* `start` in Arabic is the right edge: the Arabic keeps to the page's far
   side, as the frame draws it, whatever the page's own direction. */
.taxdoc-row .ar { color: var(--sub); text-align: start; }
.taxdoc-row.taxdoc-strong .en, .taxdoc-row.taxdoc-strong .num, .taxdoc-row.taxdoc-strong .ar { color: var(--ink); font-weight: 600; }
.taxdoc-value-ar { display: block; text-align: start; }
.taxdoc-row.taxdoc-unit { padding-block: 4px; font-size: 12.5px; }
.taxdoc-row.taxdoc-unit .num { color: var(--sub); }
/* Words between the labels don't fit a phone's middle: the labels keep their
   line, and the words take the next one. */
@media (max-width: 600px) {
  .taxdoc-row.taxdoc-wide { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); row-gap: 2px; }
  .taxdoc-wide .en { grid-column: 1; grid-row: 1; }
  .taxdoc-wide .ar { grid-column: 2; grid-row: 1; }
  .taxdoc-wide .num { grid-column: 1 / -1; grid-row: 2; text-align: start; }
}
.taxdoc-lines { inline-size: 100%; border-collapse: collapse; margin-block-start: 16px; font-size: 14px; }
.taxdoc-lines th { font-weight: 500; color: var(--sub); font-size: 12.5px; text-align: start; padding-block: 6px; padding-inline: 4px; border-block-end: 1px solid var(--line); }
.taxdoc-lines td { padding-block: 8px; padding-inline: 4px; border-block-end: 1px solid var(--line); vertical-align: top; }
.taxdoc-lines .num { text-align: end; white-space: nowrap; font-variant-numeric: tabular-nums lining-nums; }
.taxdoc-lines .ar { text-align: start; }
.taxdoc-collected { display: flex; justify-content: space-between; gap: 12px; flex-wrap: wrap; color: var(--sub); font-size: var(--t-caption); margin-block-start: 16px; }
/* **Her tax document as a PDF** (the founder's yes to the download, 27 Sep
   2026): WeasyPrint lays out the page's own partial from this stylesheet, for
   print. The four faces the document uses, each file once and whole: the site's
   fonts.css splits every face by script with unicode-range, which the PDF
   renderer mismatched (a middle dot or a 5 drawn as an Arabic mark) and spent
   four seconds loading. Figures inside the Arabic come from Plex Arabic's own
   Latin file, then its Arabic. A browser fetches these only when printing. */
@font-face { font-family: 'Doc Sans'; src: url(/static/fonts/instrument-sans-normal-latin.v2.woff2); font-weight: 400 700; }
@font-face { font-family: 'Doc Serif'; src: url(/static/fonts/cormorant-garamond-normal-latin.v2.woff2); font-weight: 400 700; }
@font-face { font-family: 'Doc Arabic Figures'; src: url(/static/fonts/ibm-plex-sans-arabic-normal-latin.woff2); font-weight: 400 700; }
@font-face { font-family: 'Doc Arabic'; src: url(/static/fonts/ibm-plex-sans-arabic-normal-arabic.woff2); font-weight: 400 700; }
@media print {
  :root {
    --ui: 'Doc Sans', sans-serif;
    --figure: 'Doc Sans', sans-serif;
    --display: 'Doc Serif', serif;
    --arabic: 'Doc Arabic Figures', 'Doc Arabic', sans-serif;
  }
  @page { size: A4; margin: 16mm 14mm; }
  html, body { background: transparent; }
  .taxdoc { display: block; max-inline-size: none; margin: 0; padding: 0; }
  .taxdoc-head h1 span { white-space: nowrap; }
}

/* Her receipt's doors, one row: the tax document's, then hers. */
.paid-doors { display: flex; justify-content: space-between; gap: 8px 16px; flex-wrap: wrap; }

/* **Nearest, beside the Explore title** (the founder's pick A on UX's Nearest
   board, 27 Sep 2026): a quiet pill, fir when on. The arrow is a symbol, not a
   direction, so a right-to-left page does not flip it. */
.explore-head { display: flex; align-items: center; gap: 12px; }
.explore-head > .search { flex: 1 1 auto; min-inline-size: 0; }
.near {
  flex: none;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding-block: 7px;
  padding-inline: 13px;
  border: 1px solid var(--line);
  border-radius: var(--radius-chip);
  background: var(--card);
  color: var(--fir);
  font-family: var(--ui);
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
}
.near[aria-pressed="true"] { background: var(--fir); border-color: var(--fir); color: var(--on-fir); }
.near[aria-busy="true"] { opacity: 0.7; }
.near:focus-visible { outline: 2px solid var(--fir); outline-offset: 2px; }
.near-mark { font-size: 11px; direction: ltr; unicode-bidi: isolate; }
.near-none { margin-block: 0; }

/* ── Her one screen, a walk-in's choice on the desk's tablet ──────────────
   UX's walk-in board (27 Sep 2026), re-checked 29 Sep: the code beside
   "Pay with MIORA · 20% less" with the total large, and "or / Pay the salon"
   in the same view on a landscape tablet (1180×820), never below the fold. */
.walkin-choice { inline-size: 100%; max-inline-size: 880px; margin-inline: auto; }
.walkin-choosing { inline-size: 100%; }
/* After her choice, the whole screen: a round tick, the heading, the way back —
   centred, no card, the same width in every state (UX's check, 29 Sep 2026). */
.walkin-after {
  display: grid;
  justify-items: center;
  gap: 24px;
  text-align: center;
}
/* **One group, centred on the screen** (UX's re-check): the tick, the heading
   and "Hand the tablet back" stack together, 18px apart, never a heading in
   the middle and a button far below it. */
.walkin-choice:has(.walkin-after:not([hidden])) {
  min-block-size: 72vh;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 18px;
}
.walkin-after[hidden], .walkin-back[hidden] { display: none; }
.walkin-after .greet { margin: 0; }
.walkin-tick {
  inline-size: 88px;
  block-size: 88px;
  border-radius: 50%;
  background: var(--fir);
  color: var(--on-fir);
  display: grid;
  place-items: center;
  font-size: 44px;
  line-height: 1;
}
.walkin-back { display: flex; justify-content: center; }
.walkin-choice .walkin-back .btn { inline-size: auto; min-inline-size: 280px; padding-inline: 28px; }
.walkin-miora {
  display: grid;
  grid-template-columns: minmax(180px, 240px) 1fr;
  align-items: center;
  gap: 28px;
  padding: 22px;
}
.walkin-qr svg { display: block; width: 100%; height: auto; }
.walkin-miora .k { margin: 0; font-size: 20px; font-weight: 600; color: var(--ink); }
.walkin-total {
  margin: 6px 0 8px;
  font-family: var(--price-face, var(--display));
  font-weight: var(--price-weight, 400);
  font-size: 56px;
  line-height: 1;
  color: var(--ink);
}
.walkin-miora .note { margin: 4px 0 0; }
.walkin-or { text-align: center; margin: 4px 0; }
.walkin-choosing form .btn { inline-size: 100%; }
@media (max-width: 640px) {
  .walkin-miora { grid-template-columns: 1fr; justify-items: center; text-align: center; }
  .walkin-qr { max-width: 220px; }
}

/* **New terms** (§6 revised; the founder's frame FeeaeHqYm6jRpybQff99Ck):
   two ink links on one line, each opening its words in place below it. */
.terms-links{display:flex;gap:10px;align-items:baseline;font-size:15.5px;margin:6px 4px 10px}
.terms-links a{color:var(--ink);text-decoration:underline;text-underline-offset:3px}
.terms-links .dot{color:var(--sub)}
.words{display:none}
.words:target,.words.open{display:block}

/* --- The wow review (the founder's rulings, 5 Oct 2026) ------------------ */

/* **T1 A. A picture leads every salon.** Home's *Book again* opens on her
   salon's room — or its painted plate, when no photograph passed — run to
   the card's edges, as the Explore card's room is. */
.card.again { overflow: hidden; }
.card.again .again-room {
  position: relative;
  display: block;
  block-size: 172px;
  margin: -15px -18px 14px;
  overflow: hidden;
}
.card.again .again-room img,
.card.again .again-room svg {
  position: absolute;
  inset: 0;
  inline-size: 100%;
  block-size: 100%;
  object-fit: cover;
}

/* **T3. The seal beside the receipt's total**: her rate in the header's
   rosette, a little smaller, on the figure's line. */
.paidhead .paidrow { display: flex; align-items: center; gap: 14px; margin-block-start: 10px; }
.paidhead .paidrow .paidfig { margin-block-start: 0; }
.sealfig.paidseal { inline-size: 56px; block-size: 56px; }
.sealfig.paidseal b { font-size: 14px; }
/* R4 (F224; AFTER_APPLE's receipt): the seal beside the rate line, the
   line it explains — not beside a total that holds the tip. */
.stack .rate .k:has(.rateseal) { display: inline-flex; align-items: center; gap: 8px; }
.sealfig.rateseal { inline-size: 40px; block-size: 40px; }
.sealfig.rateseal b { font-size: 11px; }

/* --- Held for Apple's answer: F177, F181, F182 ------------------------ */
/* The founder's yes to UX's board, 13 Oct 2026. Drawn only while
   AFTER_APPLE is on; the classes below appear on no other page. */

/* F177 · Talk to MIORA, wherever money is: one row in the card's own link
   style, 44 px tall, the WhatsApp glyph beside the words. */
.talkrow { margin-block-start: 2px; }
.paycard .talkrow, .paid-doors + .talkrow { margin-block-end: -10px; }
.talk-wa {
  display: inline-flex; align-items: center; gap: 7px;
  min-block-size: 44px; font-weight: 600; color: var(--fir); text-decoration: none;
}
.talk-wa .wa { inline-size: 18px; block-size: 18px; flex: 0 0 auto; }
.talk-under { text-align: center; margin-block: 2px 14px; }

/* F181 · An empty search carries one leaf of our garden, then the same
   words — the empty ledger's pattern (frame 10-02), no dashed box. */
.empty-new { display: flex; flex-direction: column; align-items: center; gap: 8px; padding: 14px 6px 4px; text-align: center; }
.empty-new .mk {
  display: block; margin-block-end: 6px;
  --brass: var(--sage); --gold-leaf: var(--sage-leaf); --gold-leaf-2: var(--sage-pale);
}
.empty-new .l, .empty-new .w { text-wrap: balance; }
.empty-new .l { margin: 0; max-inline-size: 300px; color: var(--text); font-size: 16px; line-height: 25px; }
.empty-new .w { margin: 0; max-inline-size: 300px; color: var(--faint); font-size: 13.5px; line-height: 1.45; }
.empty-new .w a { color: var(--fir); font-weight: 600; display: inline-block; padding-block: 12px; margin-block: -10px; }
.grove .empty-new { padding-block: 36px 12px; }

/* F182 A · The seal opens round what she paid as the tick draws: 680 ms,
   once, on the receipt she has just paid. Still under Reduce Motion. */
.leaf.drawn .mtick { inline-size: 11px; block-size: 11px; }
.leaf.drawn .mtick path { fill: none; stroke: currentColor; stroke-width: 2.2; stroke-linecap: round; stroke-linejoin: round; stroke-dasharray: 1; stroke-dashoffset: 0; }
.rr ellipse[style] { transform: rotate(var(--r, 0deg)); }
@media (prefers-reduced-motion: no-preference) {
  .moment-a .paidseal, .moment-a ~ .stack .rateseal { animation: paid-land 520ms cubic-bezier(.2, .8, .2, 1) both; }
  .moment-a .paidseal .rr ellipse, .moment-a ~ .stack .rateseal .rr ellipse { animation: paid-petal 420ms cubic-bezier(.2, .8, .2, 1) calc(var(--i, 0) * 22ms) both; }
  .moment-a .paidseal .rr circle, .moment-a ~ .stack .rateseal .rr circle { animation: paid-fade 360ms ease-out both; }
  .moment-a .paidfig { animation: paid-rise 380ms cubic-bezier(.2, .8, .2, 1) 120ms both; }
  .moment-a .paidseal b, .moment-a ~ .stack .rateseal b { animation: paid-fade 300ms ease-out 260ms both; }
  .moment-a .leaf.drawn .mtick path { animation: paid-draw 300ms ease-out 80ms both; }
}
@keyframes paid-land { from { transform: scale(1.14); } to { transform: none; } }
@keyframes paid-petal { from { transform: rotate(calc(var(--r, 0deg) - 40deg)) scale(.25); opacity: 0; } to { transform: rotate(var(--r, 0deg)) scale(1); opacity: 1; } }
@keyframes paid-fade { from { opacity: 0; } to { opacity: 1; } }
@keyframes paid-rise { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }
@keyframes paid-draw { from { stroke-dashoffset: 1; } to { stroke-dashoffset: 0; } }

/* **T4. Something happened.** A closed bud on *Asked* while she waits; on
   Confirmed the plate is taller and opens from the tick while the tick
   draws, in 300 ms. No words, and no motion where she asked for less. */
.vtrack li.on i.bud { background: var(--card); }
.vtrack i.bud svg { display: block; }
.confirmed-art .confirmed-band { block-size: 156px; }
@media (prefers-reduced-motion: no-preference) {
  .confirmed-art .confirmed-band { animation: band-opens 300ms ease-out both; }
  .confirmed-art .confirmed-head svg path {
    stroke-dasharray: 1;
    stroke-dashoffset: 1;
    animation: tick-draws 300ms ease-out forwards;
  }
}
@keyframes band-opens {
  from { clip-path: circle(4% at 18px 100%); }
  to { clip-path: circle(154% at 18px 100%); }
}
@keyframes tick-draws { to { stroke-dashoffset: 0; } }

/* **T5. Tidy price rows.** A service's minutes on their own grey line under
   its name, and a grouped row's span and count on one — *45–75 min · 4
   options*; names break between words, never at a hyphen. v13's columns
   are untouched. */
.ledger .lr.svc .dur.line2 {
  display: block;
  margin-inline-start: 0;
  margin-block-start: 2px;
  white-space: normal;
}

/* **S1. Sign-in** (the wow review, 5 Oct 2026): no word alone on the
   heading's last line, and the footer anchored to the foot of the screen. */
.signin-page .greet { text-wrap: balance; }
body:has(> main.signin-page) { min-block-size: 100dvh; display: flex; flex-direction: column; }
body:has(> main.signin-page) > * { inline-size: 100%; }
body:has(> main.signin-page) > main { flex: 1 0 auto; }

/* **S3. Who?** Each stylist's letter inside the ornament kit's ring of
   petals, in the display face — no photographs. */
.whoini.mono { position: relative; inline-size: 40px; block-size: 40px; background: none; border: 0; }
.whoini.mono .rr { position: absolute; inset: 0; inline-size: 100%; block-size: 100%; }
.whoini.mono b { position: relative; font-family: var(--display); font-weight: 600; font-size: 19px; line-height: 1; color: var(--fir); }

/* **S8. Gifts** (the wow review, 5 Oct 2026): what is left in the bill's own
   serif figure. */
.hero-num.gifts-fig {
  font-family: var(--price-face, var(--display));
  font-weight: var(--price-weight, 700);
  font-size: 72px;
  line-height: 1;
  letter-spacing: -0.02em;
  color: var(--fir);
}

/* ── Tap targets: 44px to the finger, the same look to the eye ────────────
   The founder's AA ruling, 5 Oct 2026 (UX's audit, should-fix): each small
   control the audit measured gets an invisible hit area out towards 44px — a
   `::after` with negative insets on a positioned control — so nothing moves
   and nothing is redrawn. Where neighbours sit close the area stops at half
   the gap, so a tap still lands on the control it was aimed at. A control
   whose `::after` is already spoken for is not listed here; a Visits row's
   name already stretches over the whole row. */
.hd nav a:not(.seal),
.cats .chip,
.near,
.stepbar-back,
.tips .chip.tipchip,
.confirmed-links a,
.noteask summary,
.linkback,
a[href$='/not-mine'] {
  position: relative;
}

.hd nav a:not(.seal)::after,
.cats .chip::after,
.near::after,
.stepbar-back::after,
.tips .chip.tipchip::after,
.visit-again::after,
.confirmed-links a::after,
.noteask summary::after,
.linkback::after,
a[href$='/not-mine']::after {
  content: '';
  position: absolute;
}

/* Insets are measured from inside a control's border, so a bordered chip
   reaches a little further than its number says. */
/* The header's tabs: 31–33px tall in a 58px bar; across, half the gap —
   16px wide, 10 under 360px, 7 under 340 (`.hd` above). */
.hd nav a:not(.seal)::after { inset: -8px -8px; }
@media (max-width: 360px) { .hd nav a:not(.seal)::after { inset-inline: -5px; } }
@media (max-width: 340px) { .hd nav a:not(.seal)::after { inset-inline: -3px; } }
/* Chips in a row, 34–35px; the rail has 10px of its own above and below. */
.cats .chip::after,
.near::after { inset: -6px 0; }
.tips .chip.tipchip::after { inset: -3px 0; }
/* The step bar's back arrow, 26 × 30. */
.stepbar-back::after { inset: -8px -9px; }
/* *Pay* and *Book again* on a Visits row sit above the row's own link. */
.visit-again::after { inset: -8px -11px; }
/* Text links on a line of their own. */
.confirmed-links a::after { inset: -10px 0; }
.noteask summary::after { inset: -12px 0; }
/* 13px under the button before it, so it stops a pixel short of it. */
.linkback::after { inset: -12px 0 -14px; }
a[href$='/not-mine']::after { inset: -14px 0; }

/* **Round two** (UX's re-check, 5 Oct 2026). */
.pagefoot a,
.visit-tabs a,
.card.invite > .btn,
.invite-how > summary,
.sc.sc-join .sc-foot .btn,
label.lr,
details.row-card > summary.rowline,
.signout-line .btn.plain {
  position: relative;
}
.pagefoot a::after,
.visit-tabs a::after,
.card.invite > .btn::after,
.invite-how > summary::after,
.sc.sc-join .sc-foot .btn::after,
label.lr::after,
details.row-card > summary.rowline::after,
.signout-line .btn.plain::after {
  content: '';
  position: absolute;
}
/* The footer's three doors, 22px in one row: up and down only, so the
   middot (each link's own `::before`) still divides them. */
.pagefoot a::after { inset: -12px 0; }
/* Upcoming and Past, 40px inside their 3px tray. */
.visit-tabs a::after { inset: -4px 0; }
/* The 42px small buttons. */
.card.invite > .btn::after,
.invite-how > summary::after { inset: -2px 0; }
.sc.sc-join .sc-foot .btn::after { inset: -3px 0; }
.sc.sc-join .sc-foot .linkback::after { inset-block-start: -9px; }
/* A notification row, 39px: 3px each way, so two rows meet and never cross. */
label.lr::after { inset: -3px 0; }
/* You's folding rows: the words were the 26px target and the row's own 15px
   above and below were not. Up to the row's edge; down only as far as the
   8px an opened row leaves before what it holds. */
details.row-card > summary.rowline::after { inset: -15px 0 -8px; }
/* *Sign out*, 26px, with the last row's edge 4px above it. */
.signout-line .btn.plain::after { inset: -11px 0; }

/* **F224 S27 · 44 tall to the eye as well** (the founder's yes to UX's
   member audit, 14 Oct 2026; AFTER_APPLE's skin). The app made every tap at
   least 44 tall; the web does the same where the control itself was shorter,
   and the visit's quiet verbs become full-width rows under a rule, as the
   app's LinkRows draw them. Off, nothing here applies. */
:root.c0 .btn.sm { block-size: 44px; }
:root.c0 .ribpane .btn.sm { block-size: 36px; }
:root.c0 a.chip,
:root.c0 button.chip,
:root.c0 label.chip,
:root.c0 .near,
:root.c0 .fb .fb-chip,
:root.c0 .handoff { min-block-size: 44px; }
:root.c0 .tips .chip.tipchip { padding-block: 0; }
:root.c0 .tips .chip.tipchip::after { inset: 0; }
:root.c0 .explore .search > summary { min-block-size: 44px; }
/* Text links with no box of their own reach 44 the old way, with a hit area:
   the lockup in its 58px bar, the invite link on its own line, and a link in
   a small note (*Get the app*, the privacy line, *Delete my account*). */
:root.c0 .hd .mark,
:root.c0 #invite-link,
:root.c0 p.note a:not(.btn, .linkback) { position: relative; }
:root.c0 .hd .mark::after,
:root.c0 #invite-link::after,
:root.c0 p.note a:not(.btn, .linkback)::after { content: ''; position: absolute; }
:root.c0 .hd .mark::after { inset: -3px 0; }
/* The salon page keeps the app's sizes — the 40 circles on the picture, the
   38 chips (their hit area above) — and reaches 44 with hit areas, as the
   app's hitSlop does; *Cancel the visit instead* reaches down, not up into
   the button above it. */
:root.c0 .plate-head .pic-btn::after,
:root.c0 .plate-head .pic-heart-btn::after,
:root.c0 .prices-how::after,
:root.c0 .where-c0 .where-go::after { content: ''; position: absolute; }
:root.c0 .prices-how,
:root.c0 .where-c0 .where-go { position: relative; }
:root.c0 .plate-head .pic-btn::after,
:root.c0 .plate-head .pic-heart-btn::after { inset: -2px; }
:root.c0 .prices-how::after { inset: -12px 0; }
:root.c0 .where-c0 .where-go::after { inset: -13px 0; }
:root.c0 .cancel-instead .linkback::after { inset-block-end: -16px; }
/* **UX's walk of 85661f4** (14 Oct 2026), measured as she taps — the height
   along a control's centre line that a tap there reaches it, a neighbour's
   hit area counting against it: the slim bar's two 36 circles, the feedback
   card's 32 close, Visits' folded line, a quiet way out under a button
   (12 up and 14 down was 43), and the pay card's two text links, whose hit
   areas met at 28 apart — each is its own 44 line now, with no hit area. */
:root.c0 .slim-bar .slim-back,
:root.c0 .slim-bar .slim-heart-btn,
:root.c0 .fb-morning .fb-close,
:root.c0 .visit-fold summary { position: relative; }
:root.c0 .slim-bar .slim-back::after,
:root.c0 .slim-bar .slim-heart-btn::after,
:root.c0 .fb-morning .fb-close::after,
:root.c0 .visit-fold summary::after { content: ''; position: absolute; }
:root.c0 .slim-bar .slim-back::after,
:root.c0 .slim-bar .slim-heart-btn::after { inset: -4px; }
:root.c0 .fb-morning .fb-close::after { inset: -6px; }
:root.c0 .visit-fold summary::after { inset: -12px 0; }
:root.c0 .linkback::after { inset-block-end: -15px; }
:root.c0 .paycard p.note a {
  display: flex;
  align-items: center;
  inline-size: fit-content;
  min-block-size: 44px;
}
:root.c0 .paycard p.note a::after { content: none; }
:root.c0 #invite-link::after { inset: -12px 0; }
:root.c0 p.note a:not(.btn, .linkback)::after { inset: -14px 0; }

/* The visit's rows: each verb on a 48px row with a hairline under it and a
   chevron at its end, the first under a hairline of its own. The chevron is
   the link's `::before` (its `::after` is the hit area above, which the row
   no longer needs), moved to the end. */
:root.c0 .confirmed-links.link-rows {
  display: block;
  margin-block-start: 14px;
  border-block-start: 1px solid var(--line);
}
:root.c0 .confirmed-links.link-rows a {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  min-block-size: 48px;
  border-block-end: 1px solid var(--line);
  font-size: 15px;
}
:root.c0 .confirmed-links.link-rows a::before {
  content: '\203A';
  order: 1;
  font-size: 20px;
  line-height: 22px;
  font-weight: 400;
  color: var(--faint);
}
:root.c0 .confirmed-links.link-rows a::after { content: none; }
/* **U6** (the founder's 1A, 18 Oct 2026): *Change time* and *Cancel visit*
   are rows like the others, in the rows' own colour, not the faint one. */
:root.c0 .confirmed-links.link-rows a.faint { color: var(--fir); }
/* **cx-A** (E2E-0351, the founder's pick, 18 Oct 2026): the rows in their
   own card, dark, the first without a rule above, the last without one under. */
:root.c0 .link-card { padding-block: 0; }
:root.c0 .link-card .confirmed-links.link-rows { margin-block-start: 0; border-block-start: 0; }
:root.c0 .link-card .confirmed-links.link-rows a {
  min-block-size: 56px;
  color: var(--ink);
  font-weight: 600;
}
:root.c0 .link-card .confirmed-links.link-rows a:last-child { border-block-end: 0; }
/* A lone quiet verb is 44 tall, centred as it was. */
:root.c0 .confirmed-links:not(.link-rows) a {
  display: inline-flex;
  align-items: center;
  min-block-size: 44px;
}
:root.c0 .confirmed-links:not(.link-rows) a::after { inset: 0; }

/* ------------------------------------------------------------------------
   **F210 · the salon menu** (the founder's "Yes, the full set", 13 Oct 2026;
   04-app-design/f210-menu-handoff/). With AFTER_APPLE on, /s/{slug} draws
   the app's menu in place of the rate card: the search pill from 40
   services, the chips with the lit one centred, a band per category, the
   key once under it, a card per service. Every class here is `menu-*`, so
   nothing reaches the rate card the page shows with the flag off.
   ------------------------------------------------------------------------ */
.menu {
  /* **One left edge** (the founder's pass, 14 Oct 2026 ~01:10: F210's
     MENU_INSET 40 -> 20): the search, chips, bands and cards start on the
     page's own gutter, with the name, *Prices* and the gift tag. The menu
     is drawn only with AFTER_APPLE on. */
  padding-inline: 0;
  /* The drawings' white at 45%, over a band or a tile. */
  --menu-soft: color-mix(in srgb, var(--card) 45%, transparent);
}

/* **The tints plug in here, and only here.** Every band and tile reads
   `--menu-tint`, set per canon key below from the `--tint-*` tokens (light
   and dark, UX's tints.json), with `own` for a category of the salon's own. */
.menu-band,
.menu-tile {
  background: var(--menu-tint, var(--band));
}

.menu [data-tint="hair"],
.cat-plate[data-tint="hair"] {
  --menu-tint: var(--tint-hair);
}
.menu [data-tint="nails"],
.cat-plate[data-tint="nails"] {
  --menu-tint: var(--tint-nails);
}
.menu [data-tint="skin"],
.cat-plate[data-tint="skin"] {
  --menu-tint: var(--tint-skin);
}
.menu [data-tint="wax-threading"],
.cat-plate[data-tint="wax-threading"] {
  --menu-tint: var(--tint-wax-threading);
}
.menu [data-tint="lashes-brows"],
.cat-plate[data-tint="lashes-brows"] {
  --menu-tint: var(--tint-lashes-brows);
}
.menu [data-tint="massage"],
.cat-plate[data-tint="massage"] {
  --menu-tint: var(--tint-massage);
}
.menu [data-tint="hammam"],
.cat-plate[data-tint="hammam"] {
  --menu-tint: var(--tint-hammam);
}
.menu [data-tint="makeup"],
.cat-plate[data-tint="makeup"] {
  --menu-tint: var(--tint-makeup);
}
.menu [data-tint="henna"],
.cat-plate[data-tint="henna"] {
  --menu-tint: var(--tint-henna);
}
.menu [data-tint="bridal"],
.cat-plate[data-tint="bridal"] {
  --menu-tint: var(--tint-bridal);
}
.menu [data-tint="kids"],
.cat-plate[data-tint="kids"] {
  --menu-tint: var(--tint-kids);
}
.menu [data-tint="own"],
.cat-plate[data-tint="own"] {
  --menu-tint: var(--tint-own);
}

/* The search: a pill, 46 high, a fir line while it holds her words. The
   field keeps 16px, or iOS zooms the page on focus. */
.menu-search {
  display: flex;
  align-items: center;
  gap: 10px;
  min-block-size: 46px;
  box-sizing: border-box;
  margin-block: 2px 12px;
  padding-inline: 16px 6px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--card);
  color: var(--sub);
}

.menu-search.on {
  border: 1.5px solid var(--fir);
}

.menu-search .menu-lens { flex: none; }

.menu-search input.menu-q {
  flex: 1;
  min-inline-size: 0;
  min-block-size: 44px;
  padding: 0;
  border: 0;
  border-radius: 0;
  background: none;
  font-family: var(--ui);
  font-size: 16px;
  color: var(--ink);
  outline: none;
  -webkit-appearance: none;
  appearance: none;
}

.menu-search input.menu-q::placeholder { color: var(--sub); }
.menu-search input.menu-q::-webkit-search-cancel-button { display: none; }
.menu-search:focus-within { border-color: var(--fir); }

.menu-clear {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
  inline-size: 24px;
  block-size: 24px;
  margin-inline-end: 10px;
  border-radius: 999px;
  background: var(--band);
  color: var(--ink);
}

/* A 24px mark, a 44px tap. */
.menu-clear::after {
  content: '';
  position: absolute;
  inset: -10px;
}

/* The chips: 38 high, 15 at 500, the rail clipped at the menu's edges
   rather than bled to the page's. */
.menu .cats.menu-chips {
  inline-size: auto;
  min-inline-size: 0;
  margin-inline: 0;
  padding-inline: 0;
  padding-block: 4px 10px;
  margin-block-end: 0;
  scroll-padding-inline: 0;
  /* **No band behind the chips** (UX, 14 Oct 2026: match the app). The
     strip wears the page's own paper — the ground, and the body's grain at
     the body's strength (0.22 x 0.45), fixed to the viewport as the body's
     is — so at rest there is nothing to see, and stuck it still covers the
     cards, which are exactly its width. */
  box-shadow: none;
  clip-path: none;
  background-color: var(--ground);
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='160' height='160'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3'/><feColorMatrix type='saturate' values='0'/></filter><rect width='160' height='160' filter='url(%23n)' opacity='.099'/></svg>");
  background-attachment: fixed;
  background-blend-mode: multiply;
}

/* At dusk the body has no grain, so neither does the strip. */
:root:not([data-theme='light']) {
  @media (prefers-color-scheme: dark) {
    .menu .cats.menu-chips { background-image: none; }
  }
}

:root[data-theme='dark'] .menu .cats.menu-chips { background-image: none; }

.menu .cats.menu-chips .chip {
  min-block-size: 38px;
  box-sizing: border-box;
  padding: 0 15px;
  font-size: 15px;
  font-weight: 500;
}

/* **One band per category**: radius 18, the name in the display face at
   27/30, *{Arabic} · {n} services* under it in sub, the drawing at 62. */
.menu-band {
  display: flex;
  align-items: center;
  gap: 12px;
  /* The app's 22 above a band follows another category's cards; here a
     chip shows one category, so its band is always the first thing. */
  margin-block: 6px 12px;
  padding: 12px 14px 12px 18px;
  border-radius: var(--radius-card);
}

.menu-band-text {
  flex: 1;
  min-inline-size: 0;
  display: flex;
  flex-direction: column;
}

.menu-band-name {
  font-family: var(--display);
  font-size: 27px;
  line-height: 30px;
  color: var(--ink);
}

.menu-band-sub {
  margin-block-start: 2px;
  font-size: 13px;
  line-height: 18px;
  color: var(--sub);
  font-variant-numeric: tabular-nums lining-nums;
}

.menu-band-sub bdi {
  font-family: var(--arabic);
  font-size: 13.5px;
}

.menu-pic { flex: none; }

/* **The key**, once under the band: the salon's figure struck and *At the
   salon*; hers bold and *You pay*. */
.menu-key {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  column-gap: 16px;
  margin: 0 0 9px;
  font-size: 13px;
  line-height: 18px;
  color: var(--sub);
  font-variant-numeric: tabular-nums lining-nums;
}

.menu-key:empty { display: none; }
.menu-key b { font-weight: 700; color: var(--ink); }

/* **One service, one card**: the name at 16/21, the price pair under it,
   only the button on the end. Chosen, a pale fir wash inside a fir line. */
.menu-card,
.menu-group {
  margin-block-end: 10px;
}

.menu-card {
  display: flex;
  align-items: center;
  gap: 12px;
  inline-size: 100%;
  box-sizing: border-box;
  padding: 14px 14px 14px 16px;
  border: 1px solid var(--line);
  border-radius: 14px;
  background: var(--card);
  font: inherit;
  font-family: var(--ui);
  color: var(--ink);
  text-align: start;
}

button.menu-card,
summary.menu-card { cursor: pointer; }

.menu-card.on {
  border-color: var(--fir);
  background: color-mix(in srgb, var(--fir) 6%, var(--card));
}

.menu-text {
  flex: 1;
  min-inline-size: 0;
  display: flex;
  flex-direction: column;
}

.menu-name {
  font-size: 16px;
  line-height: 21px;
  font-weight: 500;
  color: var(--ink);
}

.menu-variant { color: var(--fir); }

.menu-pair {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  column-gap: 7px;
  margin-block-start: 3px;
  font-variant-numeric: tabular-nums lining-nums;
}

.menu-pair b {
  font-size: 16px;
  line-height: 20px;
  font-weight: 700;
  color: var(--ink);
}

.menu-pair s,
.menu-min {
  font-size: 13.5px;
  line-height: 18px;
  color: var(--sub);
}

.menu-min {
  margin-inline-start: -3px;
  white-space: nowrap;
}

.menu-pair > .menu-min:first-child { margin-inline-start: 0; }

.menu-note {
  margin-block-start: 2px;
  font-size: 13.5px;
  line-height: 19px;
  color: var(--sub);
}

.menu-quote {
  margin-block-start: 3px;
  font-size: 14px;
  line-height: 20px;
  color: var(--fir);
}

/* The card's one button: + in a fir ring, ✓ filled once chosen. */
.menu-add {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
  inline-size: 36px;
  block-size: 36px;
  box-sizing: border-box;
  border: 1px solid var(--fir);
  border-radius: 999px;
  color: var(--fir);
}

.menu-add.menu-sm {
  inline-size: 30px;
  block-size: 30px;
}

.menu-add svg { inline-size: 16px; block-size: 16px; }
.menu-add.menu-sm svg { inline-size: 14px; block-size: 14px; }
.menu-add .menu-tick { inline-size: 20px; block-size: 20px; }
.menu-add.menu-sm .menu-tick { inline-size: 17px; block-size: 17px; }
.menu-add .menu-tick { display: none; }

.on > .menu-add {
  background: var(--fir);
  color: var(--on-fir);
}

.on > .menu-add .menu-plus { display: none; }
.on > .menu-add .menu-tick { display: block; }

.menu-chev {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
  inline-size: 36px;
  block-size: 36px;
  box-sizing: border-box;
  border: 1px solid var(--line);
  border-radius: 999px;
  color: var(--ink);
}

/* **A service with options.** Folded: both ranges and the chevron; on her
   pick, a chosen card with the option in fir. Open: a 1.5 fir line, the
   head with *Choose an option*, then one row per option. */
.menu-group > summary {
  list-style: none;
  margin-block-end: 0;
}

.menu-group > summary::-webkit-details-marker { display: none; }
.menu-group .menu-head { display: none; }

.menu-group[open] {
  border: 1.5px solid var(--fir);
  border-radius: 14px;
  background: var(--card);
  overflow: hidden;
}

.menu-group[open] > summary {
  padding: 14px 14px 10px 16px;
  border: 0;
  border-radius: 0;
  background: none;
  gap: 14px;
}

.menu-group[open] .menu-shut,
.menu-group[open] > summary > .menu-add { display: none; }
.menu-group[open] .menu-head { display: flex; }
.menu-group[open] .menu-chev svg { transform: rotate(180deg); }

.menu-hint {
  margin-block-start: 2px;
  font-size: 13px;
  line-height: 18px;
  font-weight: 500;
  color: var(--fir);
}

.menu-opt {
  display: flex;
  align-items: center;
  gap: 14px;
  inline-size: 100%;
  box-sizing: border-box;
  padding: 11px 14px 11px 16px;
  border: 0;
  border-block-start: 1px solid var(--line);
  border-radius: 0;
  background: none;
  font: inherit;
  font-family: var(--ui);
  color: var(--ink);
  text-align: start;
}

button.menu-opt { cursor: pointer; }

.menu-opt.on {
  background: color-mix(in srgb, var(--fir) 6%, var(--card));
}

.menu-oname {
  font-size: 15px;
  line-height: 20px;
  font-weight: 500;
  color: var(--ink);
}

.menu-opt .menu-pair { margin-block-start: 2px; }

/* **How many?** in the card she ticked: − n + under its figures, inside
   the same fir line. The stepper is the rate card's own. */
.menu-counted {
  margin-block-end: 10px;
  padding-block-end: 12px;
  border: 1px solid var(--fir);
  border-radius: 14px;
  background: color-mix(in srgb, var(--fir) 6%, var(--card));
}

.menu-counted > .menu-card,
.menu-counted > .menu-opt {
  margin: 0;
  border: 0;
  background: none;
  padding-block-end: 8px;
}

.menu-counted.menu-in-group {
  margin: 0;
  border: 0;
  border-block-start: 1px solid var(--line);
  border-radius: 0;
}

.menu-counted .stp { margin-inline-start: 16px; }

/* Search results: *n found*, each category's small head on its tile. */
.menu-found {
  margin: 4px 0 10px;
  font-size: 13.5px;
  line-height: 18px;
  color: var(--sub);
}

.menu-found-head {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-block: 4px 10px;
  font-family: var(--display);
  font-size: 23px;
  line-height: 26px;
  color: var(--ink);
}

.menu-found-head .menu-tile {
  flex: none;
  inline-size: 34px;
  block-size: 34px;
  box-sizing: border-box;
  padding: 5px;
  border-radius: 10px;
}

/* **A search with no match**: the sprig on its tile, the sentence, and one
   way back to every service. */
.menu-none {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
  padding-block: 28px 12px;
  text-align: center;
}

.menu-none .menu-tile {
  inline-size: 64px;
  block-size: 64px;
  box-sizing: border-box;
  padding: 10px;
  border-radius: 16px;
}

.menu-none p {
  margin: 0;
  font-size: 16px;
  line-height: 22px;
  font-weight: 500;
  color: var(--ink);
}

.menu-all {
  display: inline-flex;
  align-items: center;
  min-block-size: 44px;
  box-sizing: border-box;
  padding-inline: 20px;
  border: 1px solid var(--fir);
  border-radius: 999px;
  color: var(--fir);
  font-size: 16px;
  font-weight: 500;
  text-decoration: none;
}

/* F209 on the page's bar: the total stays on one line at 320. */
body:has(.menu) .bar .bar-sum { white-space: nowrap; }

/* ================================================ F219 · the salon page */
/* With AFTER_APPLE on (the founder's picks, 14 Oct 2026; UX's hand-off in
   04-app-design/salon-page-handoff/). Every class here is drawn only then. */

/* 1 · Back and the heart on the picture: 40 circles, 16 from the edges. */
.plate-head .pic-btn,
.plate-head .pic-heart-btn {
  position: absolute;
  z-index: 6;
  inset-block-start: 16px;
  display: grid;
  place-items: center;
  inline-size: 40px;
  block-size: 40px;
  margin: 0;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: var(--float, rgb(255 254 250 / 0.94));
  box-shadow: var(--float-shadow, 0 2px 8px rgb(31 40 34 / 0.22));
  color: var(--on-float, #1F2822);
  cursor: pointer;
}

.plate-head .pic-back { inset-inline-start: 16px; }
.plate-head a.pic-heart-btn { inset-inline-end: 16px; }

.plate-head form.pic-heart {
  position: absolute;
  z-index: 6;
  inset-block-start: 16px;
  inset-inline-end: 16px;
  margin: 0;
}

.plate-head form.pic-heart .pic-heart-btn { position: static; }

/* The picture's own rule sizes every svg in it to the band; not these. */
.plate-head .pic-btn svg,
.plate-head .pic-heart-btn svg {
  position: static;
  inline-size: 20px;
  block-size: 20px;
}

.pic-heart-btn svg path,
.slim-heart-btn svg path { fill: none; }

.pic-heart-btn.on,
.slim-heart-btn.on { color: var(--fir); }

.pic-heart-btn.on svg path,
.slim-heart-btn.on svg path { fill: currentColor; }

/* 3 · Where she is: D. The hours as they stand, then the area in a box. */
.salon-lock .where-now {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin-block-start: 14px;
}

.where-now .now {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  margin: 0;
  font-family: var(--ui);
  font-size: 15px;
  line-height: 21px;
  color: var(--sub);
}

.where-now .now.open { color: var(--good); }

/* **R9 A2** (the founder's pick, 18 Oct 2026): what the salon stated of its
   room, as sage pills — 15px with a mark on the page, 13px words alone on an
   Explore card. A stated fact, not an offer: no money, no rate, never red. */
.room-facts {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 0;
}

.room-fact {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 7px 13px;
  border-radius: 99px;
  background: var(--sage-pill);
  color: var(--fir);
  font-family: var(--ui);
  font-size: 15px;
  font-weight: 600;
  line-height: 20px;
}

.where-now .room-fact .mark { color: var(--fir); }

/* On a card, one row: a pill that cannot fit wraps out of sight. */
.sc-facts {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-block-start: 8px;
  font-size: 13px;
  max-block-size: calc(1.4em + 8px);
  overflow: hidden;
}

.sc-facts .room-fact {
  padding: 4px 10px;
  font-size: 1em;
  line-height: 1.4;
}

.where-now .mark,
.where-c0 .mark {
  flex: none;
  inline-size: 18px;
  block-size: 18px;
  margin: 0;
  color: var(--sub);
}

.where-now .area-box {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 12px 14px;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--card);
  color: var(--ink);
  font-family: var(--ui);
  font-size: 15px;
  line-height: 21px;
  text-decoration: none;
}

.where-now .area-box .mark { color: var(--ink); }

.where-now .area-box span {
  flex: 1;
  min-inline-size: 0;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}

.where-now .area-chev { flex: none; color: var(--sub); }

/* 4 · "Services" and "Where" at 22/26. */
.prices-head .sect.services-head,
.sect.where-head#where {
  font-size: 22px;
  line-height: 26px;
}

/* 6 · The map under "Where": the column's width, 164 high, radius 16. */
.where-c0 {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin-block: 12px 8px;
}

.where-map {
  position: relative;
  display: block;
  block-size: 164px;
  box-sizing: border-box;
  overflow: hidden;
  border: 1px solid var(--line);
  border-radius: 16px;
  background: var(--raised);
}

.where-map picture,
.where-map img {
  display: block;
  inline-size: 100%;
  block-size: 100%;
  object-fit: cover;
}

.where-map .where-dir {
  position: absolute;
  inset-inline-end: 10px;
  inset-block-end: 10px;
  display: flex;
  align-items: center;
  gap: 6px;
  block-size: 36px;
  padding: 0 14px;
  border-radius: 18px;
  background: var(--card);
  box-shadow: var(--float-shadow, 0 2px 8px rgb(31 40 34 / 0.22));
  color: var(--fir);
  font-family: var(--ui);
  font-size: 15px;
  font-weight: 600;
}

.where-c0 .where-at {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  margin: 0;
  font-family: var(--ui);
  font-size: 15px;
  line-height: 21px;
  color: var(--ink);
}

.where-c0 .where-at .mark { margin-block-start: 1.5px; }

.where-c0 .where-week {
  color: var(--text);
  font-variant-numeric: tabular-nums lining-nums;
}

.where-c0 .where-go {
  color: var(--fir);
  font-weight: 600;
  text-decoration: none;
}

/* 7 · As she scrolls: the slim bar, in the page colour, under the strip. */
.slim-bar {
  position: fixed;
  inset-inline: 0;
  inset-block-start: var(--stuck-top, 0px);
  z-index: 30;
  block-size: 56px;
  box-sizing: border-box;
  border-block-end: 1px solid var(--line);
  background: var(--ground);
  visibility: hidden;
  opacity: 0;
  transition: opacity 0.15s, visibility 0.15s;
}

.slim-bar.on {
  visibility: visible;
  opacity: 1;
}

.slim-bar .slim-in {
  display: flex;
  align-items: center;
  gap: 10px;
  block-size: 100%;
  max-inline-size: 66rem;
  margin-inline: auto;
  padding-inline: 14px;
  box-sizing: border-box;
}

.slim-bar .slim-back,
.slim-bar .slim-heart-btn {
  flex: none;
  display: grid;
  place-items: center;
  inline-size: 36px;
  block-size: 36px;
  margin: 0;
  padding: 0;
  border: 0;
  background: none;
  color: var(--ink);
  cursor: pointer;
}

.slim-bar form.slim-heart { flex: none; margin: 0; }

.slim-bar .slim-name {
  flex: 1;
  min-inline-size: 0;
  margin: 0;
  overflow: hidden;
  font-family: var(--display);
  font-size: 21px;
  font-weight: 600;
  line-height: 26px;
  color: var(--ink);
  white-space: nowrap;
  text-overflow: ellipsis;
}

/* The chips stick under the bar, and a jump lands below it. */
:root.slim-on .menu .cats.menu-chips {
  inset-block-start: calc(var(--stuck-top, 0px) + 56px);
}

.page:has(.slim-bar) #where,
.page:has(.slim-bar) #prices {
  scroll-margin-block-start: calc(var(--stuck-top, 0px) + 64px);
}

@media (min-width: 1000px) {
  :root.slim-on .withaside-side {
    inset-block-start: calc(var(--stuck-top, 0px) + 76px);
  }
}

.menu .cats.menu-chips.stuck {
  box-shadow: var(--stuck-shadow, 0 6px 10px rgb(31 40 34 / 0.18));
}

/* The Arabic name in sub, as the frames and the app set it. */
.page:has(.slim-bar) .salon-lock .arn-line { color: var(--sub); }

/* **A salon with no photograph** (S3 B, as the app draws it): its main
   category's drawing on that category's tint, in the room's place. */
.plate-head .cat-plate {
  position: absolute;
  inset: 0;
  background: var(--menu-tint, var(--band));
  display: grid;
  place-items: center;
}

.plate-head .cat-plate svg {
  position: static;
  inline-size: auto;
  block-size: min(160px, 55%);
  aspect-ratio: 1;
}

/* C0: every white thing she can tap wears the one 1px line. */
:root.c0 .menu .cats.menu-chips .chip { border-width: 1px; }

@media (max-width: 359px) {
  .plate-head .pic-btn,
  .plate-head .pic-heart-btn,
  .plate-head form.pic-heart { inset-block-start: 12px; }
  .plate-head .pic-back { inset-inline-start: 12px; }
  .plate-head a.pic-heart-btn,
  .plate-head form.pic-heart { inset-inline-end: 12px; }
  .where-map { block-size: 140px; }
  .slim-bar .slim-in { padding-inline: 10px; }
}

/* **C0's Visits track** (the app's 6967c41, 14 Oct 2026): the line colour
   (#ECE6D9 under C0) behind the two tabs, the chosen one on the card's
   white. Light only: at dusk the track keeps `--raised`. */
:root.c0 .visit-tabs { background: var(--line); }

:root.c0:not([data-theme='light']) {
  @media (prefers-color-scheme: dark) {
    .visit-tabs { background: var(--raised); }
  }
}

:root.c0[data-theme='dark'] .visit-tabs { background: var(--raised); }
/* R5 (UX's walk of bd25e9d): the pay-by rule over the card, in the app's
   words' place — centred, quiet, before *Card •••• 4242* and Pay. */
:root.c0 .settles.settles-first { margin: 16px 0 0; }
:root.c0 .dial-saved:last-child { margin-block-end: 0; }

/* **F224 S3, the thin ring** (the founder's "T4 with S3", 14 Oct 2026 23:32,
   board G6qgDZ5C6cpK3JNnz2vXNS). With AFTER_APPLE on, the seal loses its
   rosette: a 1.6px gold line round an ivory fill, the figure in brass. In the
   header it is a 34px circle inside the 44px tap box, so her initial (T4,
   later) stays the thing to tap; on the receipt's rate line it keeps R4's 40px
   and the same line and figure. The seal beside the total (no rate line) keeps
   its rosette, the web twin of the app's PaidMoment (UX, 14 Oct). */
:root.c0 .seal::before,
:root.c0 .sealfig.rateseal::before {
  content: "";
  position: absolute;
  inset: 0;
  box-sizing: border-box;
  border: 1.6px solid var(--seal-line);
  border-radius: 50%;
  background: var(--seal-fill);
}
:root.c0 .seal::before { inset: calc(50% - 17px); }
:root.c0 .seal b,
:root.c0 .sealfig.rateseal b {
  position: relative;
  font-size: 11px; /* the AA floor: 10.5 was under it (CI, 15 Oct 2026) */
  font-weight: 700;
  color: var(--seal-ink);
}

/* **F224 E, the chip on its own line** (the founder's "Yes, E", 14 Oct 2026
   23:36). With AFTER_APPLE on, a Visits row's chip leaves the text column and
   sits on a line of its own under the row, its start edge on the date box's,
   at its own width and on one line at 320. The line is inside the row, so the
   name's stretched link still answers a tap anywhere on it (S27). Home's card
   chip is not this one. */
:root.c0 .visit-row { flex-wrap: wrap; row-gap: 10px; }
:root.c0 .visit-chipline { flex: 0 0 100%; display: flex; }
:root.c0 .visit-chipline .visit-chip { margin-block-start: 0; white-space: nowrap; }

/* **R5 · mv-A** (the founder's pick, 18 Oct 2026): a change in flight on the
   visit that stays — the time asked, that the visit stays hers, and the undo
   as a dark verb above the row's stretched link. The card is the visit
   page's form of the same lines. */
:root.c0 .visit-moveline { flex: 0 0 100%; display: flex; flex-direction: column; gap: 2px; }
:root.c0 .visit-moveline form,
:root.c0 .move-card form { position: relative; z-index: 1; }
:root.c0 .move-undo { color: var(--ink); text-align: start; }
:root.c0 .move-card { display: flex; flex-direction: column; gap: 4px; }
:root.c0 .move-card p { margin: 0; }
:root.c0 .move-chip {
  color: var(--brass);
  background: color-mix(in srgb, var(--brass) 10%, var(--card));
  border-color: color-mix(in srgb, var(--brass) 30%, var(--card));
}

/* **F228 · W1, the web header** (the founder's "w1", 15 Oct 2026 00:43; UX's
   frames 04-app-design/f228-web-header). Signed in with AFTER_APPLE on: the
   mark, then the seal and her initial 1px apart (the app's T4 corner), and on
   a phone the four tabs on a second row, the open one's 2px fir rule on the
   header's own line; the bar grows from 58 to about 104. From 720px it is one
   row: the mark, the tabs, the corner. */
.hd.hd-w1 {
  block-size: auto;
  flex-wrap: wrap;
  row-gap: 2px;
  padding-block-start: 8px;
}
.hd.hd-w1 .w1-corner {
  order: 2;
  margin-inline-start: auto;
  display: flex;
  align-items: center;
  gap: 1px;
  flex: none;
}
.hd.hd-w1 .seal { margin: 5px; }
.hd.hd-w1 nav {
  order: 3;
  flex-basis: 100%;
  gap: 28px;
}
.hd.hd-w1 nav a {
  font-size: 15px;
  padding-block: 6px 9px;
  border-block-end-width: 2px;
}
/* Her initial: a 36 fir circle, the letter in the serif, in a 44 tap box.
   The box is the link itself: 4px of padding the fir does not paint
   (content-box clip), never a margin, which a tap does not reach (E2E-0215:
   it caught 36x36 only). */
.w1-ini {
  box-sizing: border-box;
  inline-size: 44px;
  block-size: 44px;
  padding: 4px;
  border-radius: 50%;
  background: var(--fir);
  background-clip: content-box;
  color: var(--on-fir);
  font-family: var(--display);
  font-size: 21px;
  line-height: 1;
  display: grid;
  place-items: center;
  text-decoration: none;
}
.w1-ini svg { inline-size: 18px; block-size: 18px; }
/* The brass dot on *Gifts* while a gift is unseen (the app's rule). */
.w1-dot {
  position: absolute;
  inset-block-start: 2px;
  inset-inline-end: -9px;
  inline-size: 7px;
  block-size: 7px;
  border-radius: 50%;
  background: var(--brass);
}
@media (max-width: 360px) {
  .hd.hd-w1 nav { gap: 22px; }
  .hd.hd-w1 nav a::after { inset-inline: -10px; }
}
@media (min-width: 720px) {
  .hd.hd-w1 {
    block-size: 58px;
    flex-wrap: nowrap;
    padding-block-start: 0;
  }
  .hd.hd-w1 nav {
    order: 2;
    flex-basis: auto;
    margin-inline-start: auto;
    gap: 18px;
  }
  .hd.hd-w1 nav a { padding-block: 4px; border-block-end-width: 1.5px; }
  .hd.hd-w1 .w1-corner { order: 3; margin-inline-start: 0; }
}

/* **F228 · My MIORA and Gifts on the web** (AFTER_APPLE): the app's B3 page
   and launch Gifts tab, built from the rows /you already draws. Groups are
   brass small capitals; rows hairlined, a group's last without one. */
.mm .mm-title { font-size: 34px; line-height: 38px; font-weight: 400; margin-block-end: 0; }
.mm .you-grp { margin: 26px 0 2px; }
.mm-grp > .row-card:last-child { border-block-end: 0; }
.mm .row-card { padding-block: 0; }
.mm .rowline { min-block-size: 54px; padding-block: 8px; }
.mm details.row-card[open] { padding-block-end: 15px; }
.mm details.row-card[open] .rowline { margin-block-end: 0; }
.mm .row-card > .lr,
.mm .row-card > .k { margin-block-start: 12px; }
.mm .row-card > .note:last-child { margin-block-end: 12px; }
/* Sign out does a thing; it goes nowhere, so no chevron. */
.mm-act button.rowline {
  inline-size: 100%;
  border: 0;
  background: none;
  font: inherit;
  text-align: start;
  padding-inline: 0;
}

/* Her member card: ivory over the card, a brass hairline inset 7px, the seal
   at 1.45 and her name in the serif; below a brass rule, what MIORA took off. */
.mm-card {
  position: relative;
  margin-block-start: 14px;
  padding: 18px 20px 16px;
  border-radius: 20px;
  background: linear-gradient(160deg, var(--card), color-mix(in srgb, var(--pill) 70%, var(--card)));
  box-shadow: 0 1px 2px color-mix(in srgb, var(--ink) 6%, transparent), 0 10px 26px color-mix(in srgb, var(--ink) 7%, transparent);
}
.mm-card::before {
  content: "";
  position: absolute;
  inset: 7px;
  border: 1px solid color-mix(in srgb, var(--gold-leaf) 55%, transparent);
  border-radius: 14px;
  pointer-events: none;
}
.mm-top { display: flex; align-items: flex-start; justify-content: space-between; }
.mm-lock { display: flex; flex-direction: column; }
.mm-lock .ar { font-family: var(--wordmark); font-weight: 400; font-size: 22px; line-height: 26px; color: var(--fir); }
.mm-lock .en { font-size: 9.5px; font-weight: 700; letter-spacing: 2.2px; color: var(--sub); margin-block-start: 1px; }
.mm-seal { inline-size: 64px; block-size: 64px; }
:root.c0 .mm-seal::before { inset: calc(50% - 24.5px); }
:root.c0 .mm-seal b { font-size: 15px; }
.mm-name { font-family: var(--display); font-size: 38px; line-height: 40px; color: var(--ink); margin: 6px 0 0; }
.mm-since { font-size: 13.5px; line-height: 18px; color: var(--sub); margin: 2px 0 0; }
.mm-less {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  min-block-size: 28px;
  margin-block-start: 14px;
  padding-block-start: 10px;
  border-block-start: 1px solid color-mix(in srgb, var(--gold-leaf) 45%, transparent);
  font-size: 15px;
  line-height: 21px;
  color: var(--ink);
  text-decoration: none;
}
.mm-less b { font-size: 17px; font-weight: 700; color: var(--fir); }
.mm-less::after { content: ""; position: absolute; inset: -8px 0; }

/* Gifts: each card at the column's width, 164 high as drawn. */
.mm-gcs { display: flex; flex-direction: column; gap: 12px; margin-block-start: 8px; }
.mm-gcs .gc { flex: none; inline-size: 100%; }
.mm-invite {
  display: flex;
  align-items: center;
  gap: 12px;
  min-block-size: 64px;
  margin-block-start: 8px;
  padding: 12px 16px;
  border: 1px solid var(--line);
  border-radius: 16px;
  background: var(--card);
  text-decoration: none;
  color: var(--ink);
}
.mm-gm { flex: none; inline-size: 34px; display: grid; place-items: center; }
.mm-gm svg { inline-size: 28px; block-size: 28px; }
.mm-invite-words { flex: 1 1 auto; min-inline-size: 0; display: flex; flex-direction: column; }
.mm-invite .row-say { line-height: 21px; }
.mm-invite-line { font-size: 13.5px; line-height: 18px; color: var(--sub); }
.mm-invite .row-go { font-weight: 600; }
.mm-empty { display: flex; flex-direction: column; align-items: center; text-align: center; padding: 64px 12px 40px; }
.mm-empty-mark { inline-size: 96px; block-size: 96px; border-radius: 50%; background: var(--raised); display: grid; place-items: center; }
.mm-empty-mark svg { inline-size: 52px; block-size: 52px; }
.mm-empty-line { font-family: var(--display); font-size: 28px; line-height: 32px; color: var(--ink); margin: 18px 0 0; }
.mm-empty-why { font-size: 15px; line-height: 21px; color: var(--sub); margin: 6px 0 0; }
.mm-empty-go { margin-block-start: 20px; min-block-size: 50px; padding-inline: 28px; border-radius: 25px; inline-size: auto; }
.mm-gifts .mm-past { margin-block-start: 14px; border-block-end: 0; }
.mm-gifts .mm-past .row-say { font-weight: 400; color: var(--sub); }

/* **F230** (the founder's "B, yes, yes, yes", 15 Oct 2026 ~22:24). The gift
   kept for her visit, said above what she pays, and P2's *What is held?* —
   a quiet link under the hold line that opens a bottom sheet, no script. */
.gift-kept { margin: 8px 0 0; font-size: 15px; color: var(--fir); }
.held-link { display: inline-block; margin-block-start: 4px; padding: 0; border: 0; background: none; font: inherit; font-size: 13px; color: var(--fir); text-decoration: underline; text-underline-offset: 2px; cursor: pointer; }
.held-sheet { inset-block: auto 0; inset-inline: 0; margin-inline: auto; inline-size: min(100%, 440px); padding: 20px 18px 24px; border: 0; border-radius: 16px 16px 0 0; background: var(--card); color: var(--ink); }
.held-sheet::backdrop { background: rgb(0 0 0 / 0.35); }
.held-sheet p { margin: 0 0 8px; font-size: 15px; line-height: 1.45; }
.held-sheet .held-title { margin-block-end: 12px; font-weight: 600; font-size: 17px; }
.held-sheet .btn { margin-block-start: 8px; inline-size: 100%; }
