/* Flit app shell + client file. Tokens taken from deliverables/product/Flit.dc.html. */
:root {
  --ink:#4a3f3a; --serif:#6d5147; --muted:#9a8a82; --faint:#b7a89f; --soft:#a89890;
  --line:#f0e8e3; --field:#eadfd8; --bar:#8a5a3f; --brown:#8a5a3f; --deep:#3f342f;
  --rose:#a86e6e; --rose-2:#c08f8f; --terra:#c08f5f; --header-txt:#6d5147;
  --tablehead:#b98d90; --card:#fff; --wash:#faf6f3; --wash-2:#f4ede9;
  --shadow:0 10px 26px rgba(120,90,80,.10);
  --navh:112px;   /* bottom nav height, used to run the client file under it */
  /* The wordmark keeps the serif: a logotype is a drawing, and it is what makes Flit recognisable.
     Everything else is set in the sans, which reads faster on a tablet held at arm's length and
     keeps the interface out of the way of the work. */
  --logo-font:'Playfair Display', Georgia, serif;
  --sans:'Poppins', -apple-system, 'Segoe UI', Helvetica, Arial, sans-serif;
  --serif-font:var(--sans);
}
* { box-sizing:border-box; }
html, body { margin:0; height:100%; }
body {
  font-family:var(--sans); font-weight:400; color:var(--ink);
  background:linear-gradient(165deg, #ffffff, #fefcfb 55%, #fffefe);
  background-attachment:fixed;
  -webkit-user-select:none; user-select:none;
}
h1,h2,h3 { font-family:var(--sans); color:var(--serif); font-weight:600; letter-spacing:-.015em; margin:0; }
.hidden { display:none !important; }
input, textarea, button { font-family:inherit; }

/* App frame, like the mockup: a fixed-height column. The header and the bottom nav never move,
   and the content scrolls in the band between them. It does not slide under the nav.
   Sized with 100lvh, the LARGE viewport: on an installed iPhone that is the whole screen, edge to
   edge, home-indicator strip included, so the white nav reaches the very bottom with no beige gap
   below it. It was measured to be the one stable height on the device (852px, never moved), unlike
   100dvh which iOS mis-measures on the first paint; position:fixed;inset:0 was stable too but iOS
   would not extend it under the home indicator, leaving that strip showing the page background.
   The vh line is the fallback for engines without lvh. */
.app { position:relative; margin-inline:auto; max-width:1024px;
       height:100vh; height:100lvh;
       display:flex; flex-direction:column; overflow:hidden; }

/* ---- header ---- */
.header {
  /* Installed full screen, the gradient runs up behind the status bar (safe-area top), and the
     logo and name stay centred in the 96px band below it. */
  flex:none; height:calc(96px + env(safe-area-inset-top));
  padding:env(safe-area-inset-top) 28px 0;
  display:flex; align-items:center; justify-content:space-between;
  background:linear-gradient(105deg, #6f4f4d, #8a6660 32%, #b48f77 68%, #caa588);
  border-radius:0 0 28px 28px; box-shadow:0 14px 30px rgba(120,86,74,.22);
  z-index:40;
}
.logo { display:flex; align-items:center; gap:12px; }
.logo .word { font-family:var(--logo-font); font-size:36px; color:#fff; letter-spacing:.02em; }
/* The page name in the header, shown only on a laptop (see the min-width:1025 block). */
.pagetitle { display:none; }
.who { display:flex; align-items:center; gap:16px; }
.who .name { font-size:20px; font-weight:600; color:#fff; }
.avatar { width:56px; height:56px; border-radius:50%; border:3px solid rgba(255,255,255,.85);
          background:#efe3dd; color:#8a5a3f; display:flex; align-items:center; justify-content:center;
          font-weight:600; font-size:20px; cursor:pointer; }

/* ---- content: the scrolling band between header and nav ---- */
/* The band runs to the bottom of the frame and the nav floats over it, so a page scrolls *under*
   the menu instead of stopping at its edge. The nav plate is transparent above its curve: with the
   content stopping short, that strip showed the page background as a beige band across the screen. */
.content { flex:1; min-height:0; display:flex; flex-direction:column;
  overflow-y:auto; overflow-x:hidden;
  padding:22px calc(26px + env(safe-area-inset-right)) calc(var(--navh) + env(safe-area-inset-bottom) + 26px) calc(26px + env(safe-area-inset-left)); }

/* ---- bottom nav ---- */
.nav { position:absolute; left:0; right:0; bottom:0; height:var(--navh); pointer-events:none; z-index:45; }
/* The floating pill is the menu everywhere now, phone, tablet and desktop: the swoop is retired. A
   light translucent rounded bar of the four icons, centred, with the Flit action button as a
   separate circle just to its right. The phone block below anchors the same two pieces to the left
   and the far right instead of centring them. Centring math: group = pill 460 + gap 14 + circle 68 =
   542, so the pill starts at 50% - 271 and the circle at 50% + 203 (= 271 - 68). */
.nav .plate, .plate-soft, .plate-tight { display:none; }
.nav .items { position:absolute; left:calc(50% - 271px); right:auto; bottom:calc(env(safe-area-inset-bottom) + 28px);
              width:460px; height:66px; display:flex; align-items:center; justify-content:space-between;
              padding:0 40px; pointer-events:auto;
              background:rgba(252,249,247,.66); -webkit-backdrop-filter:blur(14px); backdrop-filter:blur(14px);
              border:1px solid rgba(255,255,255,.55); border-radius:33px; box-shadow:0 12px 28px rgba(120,90,80,.18); }
.nav .items > button { background:none; border:0; cursor:pointer; padding:8px; line-height:0; }
.nav .spacer { display:none; }
.nav .feather { position:absolute; left:calc(50% + 203px); right:auto; top:auto; transform:none; cursor:pointer;
                bottom:calc(env(safe-area-inset-bottom) + 28px);
                pointer-events:auto; width:68px; height:68px; border-radius:50%;
                background:linear-gradient(115deg, #6d4a49 0%, #8a604f 46%, #c39c7b 100%);
                display:flex; align-items:center; justify-content:center;
                box-shadow:0 12px 24px rgba(110,69,53,.34); }
/* The Flit wordmark in the round button, white on the brand gradient, filling most of it. */
.feather-logo { width:54px; height:54px; object-fit:contain; }

/* Portrait tablet: the fixed 460px group centred leaves wide side margins and reads as a small
   island. Stretch it across the width (left-anchored, feather to the far right) so it feels like a
   bar, not a cluster. Landscape keeps the centred group (the base rule) untouched. */
@media (min-width: 641px) and (max-width: 1024px) and (orientation: portrait) {
  .nav .items { left:64px; right:150px; width:auto; }
  .nav .feather { left:auto; right:64px; }
}

/* Both bars were drawn for the tablet mockup: a 96px header, a 104px button in a 112px bar. Held at
   arm's length on an iPad those are right; on a 390px phone the same absolute sizes swallow the
   screen, and the round button covers the text above it. On a phone the whole chrome scales down,
   which is also what lifts the content up. */
@media (max-width: 640px) {
  .header { height:calc(58px + env(safe-area-inset-top)); padding:env(safe-area-inset-top) 16px 0;
            border-radius:0 0 20px 20px; box-shadow:0 10px 22px rgba(120,86,74,.18); }
  .logo .word { font-size:24px; }
  .who { gap:9px; }
  .who .name { font-size:15px; }
  .avatar { width:36px; height:36px; font-size:14px; border-width:2px; }
  :root { --navh:96px; }   /* room the content reserves at the bottom for the floating bar */
  /* Floating pill nav (from Choumous's mockup), replacing the swoop on the phone: a light translucent
     rounded bar holding the four icons, with the Flit action button as a separate circle on its right.
     A plain rectangle floating above the home indicator is far more predictable than the stretched
     swoop: the icons space evenly inside it, none can fall into a curve, and the whole safe-area
     question is one bottom-margin rule. The swoop stays on tablet and desktop (the base rules). */
  .nav .plate { display:none; }        /* no swoop on the phone */
  .nav .spacer { display:none; }        /* the centre gap only existed for the old centred button */
  .nav .items {
    left:16px; right:88px; width:auto;  /* wide, left-anchored; the Flit circle takes the room on the right */
    bottom:calc(env(safe-area-inset-bottom) + 18px);
    height:60px; padding:0 24px;
    background:rgba(252,249,247,.66);
    -webkit-backdrop-filter:blur(14px); backdrop-filter:blur(14px);
    border:1px solid rgba(255,255,255,.55);
    border-radius:30px;
    box-shadow:0 12px 28px rgba(120,90,80,.18);
    justify-content:space-between;
  }
  .nav .items > button { padding:6px; }
  .nav .items > button svg { width:26px; height:26px; }
  .nav .feather {
    left:auto; right:16px; top:auto;
    bottom:calc(env(safe-area-inset-bottom) + 18px);
    width:64px; height:64px; transform:none;
    box-shadow:0 12px 24px rgba(110,69,53,.34);
  }
  .feather-logo { width:52px; height:52px; }
}

/* ============================ RESPONSIVE FOUNDATION ============================
   One set of breakpoints for the whole app, so every screen bends at the same widths:
     phone   : up to 640px    (a lash artist working mobile, try-on like a filter)
     tablet  : 641 to 1024px  (the studio device, the design target, the default)
     desktop : 1025px and up   (finances and admin, where the extra width earns its keep)
   The tablet layout is the base every other rule sits on; phone and desktop only add to it. */
@media (min-width: 1025px) {
  /* Laptop layout: a full-width header carrying the page name, a vertical rail of icons down the
     left with the larger try-on button at its foot, and the content sitting to the right of the
     rail. Phone (<640) and tablet (640-1024) are untouched: they keep the floating bottom pill. */
  .app { max-width:none; --navh:0; }   /* full width; no bottom bar to clear anywhere */

  /* Header: page name (uppercased) on the left, who she is on the right. The Flit wordmark leaves
     the header and lives in the try-on button at the foot of the rail. Indented to line up over the
     content, past the rail. */
  .header { border-radius:0; padding-left:134px; padding-right:44px; }
  .logo .word { display:none; }
  .pagetitle { display:block; font-size:28px; font-weight:400; color:#fff;
    text-transform:uppercase; letter-spacing:.03em; line-height:1; }
  .who .name { font-size:20px; }

  /* The rail: the icon pill, then the try-on circle just below it, both centred on the same axis.
     A flex column so the circle rides right under the pill, detached but close, rather than pinned
     to the bottom of the screen. Kept modest so it sits in scale with the content. */
  /* Top follows the header down when a device adds a safe-area inset (an installed iPad in landscape),
     so the rail never ends up glued under a taller header. On a Mac the inset is 0, so it is unchanged. */
  .nav { top:calc(120px + env(safe-area-inset-top)); right:auto; left:0;
    bottom:calc(28px + env(safe-area-inset-bottom)); width:116px; height:auto;
    display:flex; flex-direction:column; align-items:center; gap:18px; }
  .nav .items { position:static; flex:1 1 auto; flex-direction:column; justify-content:space-evenly;
    align-items:center; width:64px; padding:22px 0; border-radius:34px; }
  .nav .items > button { padding:8px; }
  .nav .items > button svg { width:24px; height:24px; }
  .nav .feather { position:static; flex:none; width:76px; height:76px; }
  .feather-logo { width:56px; height:56px; }

  /* Content clears the rail on the left; there is no bottom bar to clear. */
  .content { padding:24px 44px 32px 134px; }

  /* The header already names the page, so drop the in-content page title (inside .listhead) to
     avoid saying it twice. Sub-section headers inside a screen (Medical Info, Lash Mapping…) stay,
     since they are not the page title. */
  .listhead .section { display:none; }

  /* Settings has its own gear in the rail on a laptop, so it leaves the profile panel here. */
  .pitem[data-p="settings"] { display:none; }
  /* Note: the Home breakdown/tray row layout lives in its own min-width block further down, after the
     Home base styles, so it is not overridden by them (this block sits above them in the file). */
}

/* The rail's Settings gear is a laptop-only affordance: on phone and tablet Settings stays in the
   profile panel, and the floating pill keeps its four icons. */
@media (max-width: 1024px) {
  .nav .items > .nav-settings { display:none; }
}

/* ---- clients list ---- */
.listhead { display:flex; align-items:baseline; gap:14px; margin:0 4px 14px; flex-wrap:wrap; }
.listhead .back { margin-left:auto; align-self:center; }
.listhead .section { margin:0; }
.listhead .count { color:var(--muted); font-size:17px; }
.searchbar { display:flex; align-items:center; gap:16px; }
.search { flex:1; display:flex; align-items:center; gap:12px; background:var(--card);
          border-radius:40px; padding:14px 24px; box-shadow:0 8px 20px rgba(120,90,80,.08); }
.search input { flex:1; border:0; outline:0; background:transparent; font:inherit; font-size:18px; color:var(--ink); }
.sortwrap { flex:none; display:flex; align-items:center; gap:10px; background:var(--card); border-radius:40px;
            padding:0 18px 0 22px; height:60px; box-shadow:0 8px 20px rgba(120,90,80,.08); }
.sortwrap label { color:var(--muted); font-size:16px; white-space:nowrap; }
.sortsel { border:0; outline:0; background:transparent; font:inherit; font-size:17px; color:var(--ink); cursor:pointer; }
.add { width:60px; height:60px; flex:none; border-radius:50%; border:0; cursor:pointer; color:#fff; font-size:30px;
       background:linear-gradient(115deg, #6d4a49 0%, #8a604f 46%, #c39c7b 100%); box-shadow:0 8px 20px rgba(120,74,73,.32);
       display:flex; align-items:center; justify-content:center; }
.table { margin-top:20px; background:var(--card); border-radius:20px; overflow:hidden; box-shadow:var(--shadow); }
.thead, .trow { display:grid; grid-template-columns:1.35fr 1.05fr .85fr 1.05fr .9fr; align-items:center; }
.thead { background:linear-gradient(115deg, #6d4a49 0%, #8a604f 46%, #c39c7b 100%); color:#fff; font-size:17px; font-weight:500; }
.thead > div { padding:15px 16px; }
.thead .c { text-align:center; }
.trow { border-top:1px solid var(--line); cursor:pointer; }
.trow:hover { background:var(--wash); }
.trow > div { padding:18px 16px; font-size:19px; }
/* Sortable column titles: click to sort, click again to flip. The chevron marks which is active. */
.thead [data-sort] { cursor:pointer; -webkit-user-select:none; user-select:none; }
.thead [data-sort]:hover { color:#ffe9e4; }
.sarr { display:inline-block; margin-left:5px; font-size:13px; opacity:.5; vertical-align:middle; }
.th-sm { display:none; }
.thead [data-sort].sorted .sarr { opacity:1; }
/* The delete affordance rides in its own column, hidden until the phone layout turns it on. */
.trashcell, .thtrash { display:none; }
.trash { display:inline-flex; align-items:center; justify-content:center; width:34px; height:34px; padding:0;
  border:0; background:none; color:#c48f8a; cursor:pointer; border-radius:9px; }
.trash:hover, .trash:active { background:rgba(179,84,63,.12); color:#b3543f; }
/* Archived clients read dimmer, and a link under the list switches between active and archived. */
.trow.archived { opacity:.6; }
.trow.archived .name { font-style:italic; }
.clients-arch { display:block; margin:16px auto 0; padding:8px 14px; background:none; border:0; cursor:pointer;
  color:var(--terra); font:inherit; font-size:16px; font-weight:600; }
.clients-arch.hidden { display:none; }
.trow .name { padding-left:24px; }
/* The last-visit line under the name is a phone-only affordance; the tablet has its own Last-seen column. */
.trow .name-when { display:none; }
.trow .phone { font-size:17px; color:#6d5f57; white-space:nowrap; }
.trow .c { text-align:center; color:#6d5f57; font-size:17px; }
/* Money still owed reads at a glance, and says how many visits it spans: sitting right next to the
   last service, a bare amount would be read as that service's price rather than the whole file. */
.thead .money em { display:block; font-style:normal; font-size:12px; font-weight:400; opacity:.75; margin-top:2px; }
.trow .money { border-left:1px solid var(--line); }
.owed { color:#b3543f; font-weight:600; }
.owed + .over { display:block; font-style:normal; font-size:12px; color:var(--soft); margin-top:2px; }
.settled { color:var(--faint); }
/* A service is named in four places; it wears the same colour in all of them. */
.pill { display:inline-block; padding:5px 14px; border-radius:999px; font-size:15px;
        background:var(--c, var(--wash-2)); color:var(--ink, var(--bar)); font-weight:500; }
/* The last-seen date, tucked under the service pill on a phone only (see the phone list rules). On a
   wider screen Last seen has its own column, so this copy stays hidden. */
.svc-when { display:none; }
.pdf { width:44px; height:44px; border-radius:50%; background:var(--wash-2); display:inline-flex;
       align-items:center; justify-content:center; cursor:pointer; }
.empty { padding:70px 20px; text-align:center; color:var(--muted); font-size:18px; }

/* On a phone the client list stays a table, one line per client, but a narrow one: only Name, Last
   service and Total owed fit legibly here. Phone and Last seen leave the list (both are one tap away
   in the record). The column header stays, so the row reads without a legend. Search and the add
   button share one row above it. */
@media (max-width: 640px) {
  .searchbar { gap:12px; }
  .sortwrap { display:none; }
  /* min-width:0 is the whole fix: a flex item holding an <input> will not shrink below the input's
     own text width unless told it may, so on a real phone the search bar ran off the right edge and
     shoved the + button off-screen. Now it shrinks and the + stays put. Compacter too: 16px text and
     tighter padding read better at this size. */
  .search { flex:1 1 auto; min-width:0; padding:12px 20px; }
  .search input { min-width:0; font-size:16px; }
  .add { width:54px; height:54px; font-size:27px; }
  /* Four columns: the name, the last visit as its own dated column (tap the header to sort by it), what
     they owe, and the X. The phone and last-service columns are dropped, since the file carries them.
     Hidden cells: Phone (2) and Last service (4); Last visit (3) is now a column of its own. */
  /* Each row is its own grid, so the last-visit and owed columns are fixed widths, not `auto`: with
     `auto` an empty owed cell let the date slide right and the rows stopped lining up. Fixed widths
     hold every date and amount in the same place down the whole list. */
  .thead, .trow { grid-template-columns:minmax(0,1fr) 86px 74px 28px; }
  .thead > :nth-child(2), .thead > :nth-child(4),
  .trow  > :nth-child(2), .trow  > :nth-child(4) { display:none; }
  .trow .c:nth-child(3) { font-size:13px; color:var(--soft); white-space:nowrap; text-align:center; }
  .th-lg { display:none; }
  .th-sm { display:inline; }
  .thead > div, .trow > div { padding-left:9px; padding-right:9px; white-space:nowrap; }
  .trashcell { display:flex; justify-content:center; padding:0; }
  .thtrash { display:block; }
  .thead { font-size:12.5px; }
  .thead > div { padding:11px 14px; }
  .thead .money, .trow .money { text-align:right; }
  .thead .money em { display:none; }
  .trow > div { padding:14px 14px; }
  /* The last visit has its own column now, so the name is a single line again, no date beneath it. */
  .trow .name { display:flex; align-items:center; padding-left:16px; }
  .trow .name .nm { max-width:100%; font-size:15px; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
  .trow .name-when { display:none; }
  .trow .money { font-size:15px; border-left:0; }
  .trow .money .over { display:none; }
  /* Nothing owed shows nothing, not "All settled": only a real balance earns a line here. */
  .trow .money .settled { display:none; }
}

/* ---- record ----
   The client file is a fixed frame, not a page that grows. The card fills the band under the header
   and runs to the bottom of the screen, behind the nav; only its body scrolls. Two consequences we
   want: the side tabs keep the exact same size on every tab, short or long, and scrolling a long
   page (Lash info, Consent) never moves the frame around it. */
.content:has(#view-record:not(.hidden)) { overflow:visible; padding-bottom:0; }
#view-record { position:relative; flex:1; min-height:0; }
.record { position:absolute; left:0; right:0; top:0; bottom:0;
          background:var(--card); border-radius:26px 26px 0 0; box-shadow:var(--shadow); overflow:hidden;
          display:flex; }
/* the spine and the tabs stay inside the visible band, never under the nav */
.spine { width:58px; flex:none; border-right:1px solid var(--line); display:flex; align-items:center;
         justify-content:center; padding-bottom:var(--navh); }
.spine span { writing-mode:vertical-rl; transform:rotate(180deg); font-family:var(--serif-font);
              font-size:30px; letter-spacing:.18em; color:#7d5a45; white-space:nowrap; }
.rbody { flex:1; min-width:0; overflow-y:auto; overflow-x:hidden; padding:22px 30px calc(var(--navh) + 24px); }
.recbar { display:flex; align-items:center; justify-content:space-between; margin-bottom:4px; }
.back { display:inline-flex; align-items:center; gap:6px; color:var(--terra); cursor:pointer;
        font:inherit; font-size:18px; background:none; border:0; }
.saved { font-size:14px; color:#8aa88f; opacity:0; transition:opacity .3s; }
.saved.on { opacity:1; }
.round-btn { width:52px; height:52px; border-radius:50%; border:0; cursor:pointer; color:#fff; font-size:26px;
             background:linear-gradient(115deg, #6d4a49 0%, #8a604f 46%, #c39c7b 100%); display:flex; align-items:center; justify-content:center; }

.rail { width:56px; flex:none; display:flex; flex-direction:column; padding-bottom:var(--navh); }
.rail .tab { flex:1; display:flex; align-items:center; justify-content:center; cursor:pointer; color:#fff;
             margin-left:10px; border-radius:14px 0 0 14px; opacity:.9; transition:margin .15s, opacity .15s; }
.rail .tab.active { margin-left:0; opacity:1; border-radius:16px 0 0 16px; box-shadow:-4px 0 12px rgba(90,60,40,.2); }
.rail .tab span { writing-mode:vertical-rl; transform:rotate(180deg); font-size:14px; font-weight:600;
                  letter-spacing:.14em; white-space:nowrap; }
/* Laptop: give each record tab room to breathe rather than dividing the height six ways. The rail
   scrolls if the taller tabs run past the bottom -- she asked for that over cramped labels. */
@media (min-width: 1025px) {
  /* Taller tabs so the vertical label is not cramped, and the rail scrolls past the bottom -- but no
     gap between them: they stay a continuous strip, just taller. */
  .rail { overflow-y:auto; overflow-x:visible; }
  .rail .tab { flex:0 0 auto; min-height:168px; }
  /* The record's + sits inline beside its search bar (as on the phone), not floating in a corner or
     lost in the top bar. Show the inline one and drop the recbar + entirely on a laptop. */
  .trecbar .trec-add { display:flex; width:44px; height:44px; font-size:24px; flex:none; }
  #rec-action { display:none; }
}

/* On a phone the client file reclaims the ~58px the decorative left spine took: the open tab is
   already named on the right rail, so the title on the edge is redundant here. The rail narrows a
   little too, leaving the form the width it needs. */
@media (max-width: 640px) {
  .spine { display:none; }
  .rbody { padding:18px 18px calc(var(--navh) + 24px); }
  .rail { width:46px; }
  .rail .tab span { font-size:12px; letter-spacing:.1em; }
  /* The phone treatment table is set further down, after the ≤720 rule, so its five-column grid wins
     over that rule's nine columns at this width. */
}

h2.section { font-size:34px; margin-top:6px; font-weight:600; }
h3.sub { font-size:30px; margin-top:26px; }
.accent { border-left:3px solid var(--bar); padding-left:22px; margin-top:14px; }
.medtray-h { margin-top:32px; }
.maptray-h { margin-top:36px; }
.grid2 { display:grid; grid-template-columns:1fr 1fr; gap:14px 40px; }
.f { display:flex; flex-direction:column; gap:3px; }
.f label { color:var(--muted); font-size:15px; }
.f .val { font-size:22px; color:var(--ink); min-height:30px; }
.f .val .k { color:var(--muted); }
.f input, .cell input, textarea.note-body, textarea.big {
  border:0; border-bottom:1.5px solid var(--field); background:transparent; outline:0;
  font:inherit; font-size:21px; color:var(--ink); padding:4px 0; transition:border-color .15s;
}
.f input:focus { border-color:var(--rose-2); }
.f.wide { grid-column:1 / -1; }

/* medical Q&A */
/* allergies: a full field, not a thin line, so it carries the weight of the Medical Info section
   and holds more than one condition */
.allergy { max-width:640px; margin-bottom:20px; background:#faf4f1; border:1.5px solid var(--field);
           border-radius:14px; padding:14px 18px; }
.allergy label { display:block; font-size:19px; color:var(--bar); font-weight:600; margin-bottom:6px; }
.allergy textarea { width:100%; border:0; outline:0; background:transparent; resize:none; font:inherit;
                    font-size:20px; color:var(--ink); line-height:1.4; }
.medq { max-width:640px; }
.medq .row { display:flex; align-items:center; justify-content:space-between; padding:9px 0; font-size:21px; }
.medq .opts { display:flex; gap:26px; }
.medq .opt { display:flex; align-items:center; gap:8px; cursor:pointer; font-size:19px; }
.box { width:26px; height:26px; border:2px solid var(--bar); border-radius:5px; background:#fff; }
.box.on { background:var(--bar); }
.medbox { max-width:640px; margin-top:8px; background:#faf4f1; border:1.5px solid var(--field);
          border-radius:14px; padding:14px 18px; }
.medbox label { font-size:16px; color:var(--bar); font-weight:600; }
.medbox textarea { width:100%; border:0; outline:0; background:transparent; resize:none; font:inherit;
                   font-size:18px; color:var(--ink); line-height:1.5; margin-top:4px; }

/* chip fields (lash info), shown as compact dropdowns, laid out two per row */
.cfgrid { display:grid; grid-template-columns:1fr 1fr; gap:12px 22px; }
.cfgrid .cf { margin-bottom:0; }
.cf { margin-bottom:12px; position:relative; }
.dd { display:flex; align-items:center; gap:16px; width:100%; text-align:left;
  border:1.5px solid var(--field); border-radius:12px; background:#fff; padding:13px 18px;
  font:inherit; cursor:pointer; transition:border-color .12s; }
.dd:hover { border-color:var(--rose-2); }
.dd.open { border-color:var(--bar); }
.dd-label { color:var(--muted); font-size:18px; min-width:118px; flex:none; }
.dd-val { flex:1; font-size:21px; color:var(--ink); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.dd-val.novalue { color:var(--faint); }
.dd-caret { color:var(--muted); font-size:14px; transition:transform .15s; }
.dd.open .dd-caret { transform:rotate(180deg); }
/* Floats over the fields below like a real menu, so opening one never pushes the layout. */
.dd-panel { position:absolute; top:100%; left:0; right:0; z-index:30; margin-top:6px; padding:14px 16px;
  border:1.5px solid var(--field); border-radius:12px; background:#fff; box-shadow:0 14px 30px rgba(120,90,80,.18); }
.dd-panel.hidden { display:none; }
.pan-head { display:flex; justify-content:flex-end; margin:-4px 0 8px; }
/* a free-text field wearing the dropdown's clothes, so it lines up beside them */
.dd.dd-text { cursor:text; }
.dd.dd-text:focus-within { border-color:var(--bar); }
.dd-input { flex:1; min-width:0; border:0; outline:0; background:transparent; font:inherit; font-size:21px; color:var(--ink); }
.cfgrid .tf { margin-top:0; }
.chips { display:flex; flex-wrap:wrap; gap:8px; }

/* boxed text field (Product), so it reads as an input, not a separator line */
.tf { margin-top:12px; }
.tf label { display:block; color:var(--muted); font-size:18px; margin-bottom:6px; }
.tf-in { width:100%; border:1.5px solid var(--field); border-radius:12px; background:#fff;
  padding:13px 18px; font:inherit; font-size:21px; color:var(--ink); outline:0; transition:border-color .12s; }
.tf-in:focus { border-color:var(--bar); }
.chip { font:inherit; font-size:18px; padding:8px 16px; border-radius:999px; cursor:pointer;
  border:1.5px solid var(--field); background:#fff; color:var(--ink); transition:all .12s; }
.chip:hover { border-color:var(--rose-2); }
.chip.on { background:var(--bar); border-color:var(--bar); color:#fff; }
.chip.other { border-style:dashed; color:var(--muted); }
.chip.other.on { border-style:solid; }
.chip-in { display:block; margin-top:10px; max-width:360px; width:100%; border:0; border-bottom:1.5px solid var(--field);
  background:transparent; outline:0; font:inherit; font-size:20px; color:var(--ink); padding:4px 0; }
.chip-in.hidden { display:none; }

/* tidy-up mode: every chip gets a x, and the values she retired come back greyed so she can undo */
.lnk { float:right; font:inherit; font-size:16px; border:0; background:none; cursor:pointer;
  color:var(--bar); text-decoration:underline; padding:0; }
.chips.editing .chip { padding-right:10px; }
.chip .x { display:inline-block; margin-left:8px; width:22px; height:22px; line-height:20px; text-align:center;
  border-radius:999px; background:rgba(0,0,0,.08); color:var(--muted); font-size:16px; vertical-align:middle; }
.chip.on .x { background:rgba(255,255,255,.25); color:#fff; }
.chip .x:hover { background:#c0392b; color:#fff; }
.chip.gone { border-style:dashed; color:var(--muted); opacity:.65; }

/* lash mapping: draw on an eye template, with the artist's library + reference maps */
.maphint { color:var(--muted); font-size:16px; margin:6px 0 0; }
.mapcard { position:relative; margin-top:14px; max-width:720px; border:1.5px solid var(--field);
  border-radius:18px; overflow:hidden; background:#fff; cursor:pointer; }
.mapcard .mapimg, .mapcard .maptpl { display:block; width:100%; height:auto; }
.mapcard-tools { position:absolute; right:14px; bottom:14px; display:flex; align-items:center; gap:10px; }
.mapcard-tools .btn.ghost { background:rgba(255,255,255,.92); }
.mapcard-edit { border:0; border-radius:999px; cursor:pointer;
  background:var(--bar); color:#fff; font:inherit; font-size:17px; padding:9px 18px; box-shadow:0 6px 16px rgba(120,90,80,.25); }

/* map editor modal, opened large so drawing is comfortable */
.modal.mapmodal { width:min(1180px, 96vw); max-width:none; }
.mapedit { margin-top:12px; border:1.5px solid var(--field); border-radius:14px; overflow:hidden; background:#fff; position:relative; }
/* The canvas is taller than the eye guide on purpose: the guide sits centred (object-fit: contain)
   with room above and below, so there is somewhere to draw once the view is pinched in close. */
.mapzoom { position:relative; display:block; transform-origin:0 0; }
.mapbg { position:absolute; inset:0; width:100%; height:100%; object-fit:contain; }
.mapcanvas { position:relative; z-index:1; display:block; width:100%; height:auto; touch-action:none; cursor:crosshair; }
.saverow { margin-top:14px; display:flex; gap:12px; align-items:center; }
.mapname { flex:1; min-width:0; box-sizing:border-box; border:1.5px solid var(--field); border-radius:12px; background:#fff;
  padding:12px 16px; font:inherit; font-size:18px; color:var(--ink); outline:0; }
.mapname:focus { border-color:var(--bar); }
.mapname.need { border-color:var(--rose); background:#fdf3f1; }
.saverow .btn { flex:none; }
.pens { display:flex; align-items:center; gap:12px; margin-top:14px; flex-wrap:wrap; }
/* Erase and Clear share the colour row, pushed to its right end. */
.pentools { margin-left:auto; display:flex; align-items:center; gap:8px; }
/* Colours are shown as bare swatches now: no labels, since she already knows what each stands for. */
.pen { display:inline-flex; align-items:center; justify-content:center; width:38px; height:38px; padding:0;
  border:1.5px solid var(--field); background:#fff; border-radius:50%; cursor:pointer; }
.pen span { width:22px; height:22px; border-radius:50%; display:inline-block; }
.pen.on { border-color:var(--bar); box-shadow:0 0 0 3px rgba(125,90,69,.25); }
/* The eraser is a tool, not a colour: it lights up when active. */
.btn.ghost.tool.on { background:var(--bar); border-color:var(--bar); color:#fff; }
/* Undo one mark: a small round button beside the colours. */
.undo { display:inline-flex; align-items:center; justify-content:center; width:34px; height:34px; padding:0;
  border:1.5px solid var(--field); background:#fff; border-radius:50%; color:var(--bar); cursor:pointer; }
.undo:active { background:var(--wash); }
/* Three families of button in the map modal, so they read apart at a glance: the drawing tools stay
   rose (Erase, Clear), the library actions are brown, Cancel is a quiet grey, and the primary Save
   for this client keeps its filled rose. */
.modal.mapmodal .btn.ghost[data-act="library"],
.modal.mapmodal .btn.ghost[data-act="savelib"] { background:#ecd7c5; border-color:#ecd7c5; color:#8a5a3f; }
.modal.mapmodal .btn.ghost[data-act="cancel"] { background:#ece6e2; border-color:#ece6e2; color:#7a6f67; }
/* On a phone the drawing modal keeps its controls small and in scale with the sheet. */
@media (max-width: 640px) {
  /* Give the drawing as much room as a portrait screen allows: full width, thin padding, and the
     surrounding chrome kept tight so the frame is the biggest thing on screen. */
  .modal.mapmodal { width:100vw; max-width:100vw; border-radius:20px 20px 0 0; padding:12px 8px; }
  .modal.mapmodal h3 { font-size:20px; }
  .modal.mapmodal .muted { font-size:11.5px; margin:3px 0 6px; }
  .mapmodal .mapedit { margin-top:8px; }
  .mapmodal .pens { gap:10px; margin-top:10px; }
  .mapmodal .pen { width:32px; height:32px; }
  .mapmodal .pen span { width:19px; height:19px; }
  .mapmodal .undo { width:32px; height:32px; }
  .mapmodal .pentools { gap:7px; }
  .mapmodal .saverow { gap:7px; margin-top:10px; }
  .mapmodal .mapname { font-size:12.5px; padding:9px 11px; }
  .modal.mapmodal .actions { gap:8px; margin-top:10px; }
  .mapmodal .btn { padding:7px 11px; font-size:12.5px; }
}

/* map library modal */
.libmodal { max-width:760px; }
.libgroups { margin-top:12px; max-height:60vh; overflow-y:auto; }
.libsec { margin-bottom:18px; }
.libtitle { font-size:15px; letter-spacing:.06em; text-transform:uppercase; color:var(--faint); margin-bottom:10px; }
.libgrid { display:grid; grid-template-columns:repeat(3, 1fr); gap:12px; }
.libcell { position:relative; border:1.5px solid var(--field); border-radius:12px; overflow:hidden;
  background:#fdfaf8; cursor:pointer; transition:border-color .12s; }
.libcell:hover { border-color:var(--bar); }
.libcell img { display:block; width:100%; height:auto; }
.libname { padding:6px 10px; font-size:15px; color:var(--ink); }
.libdel { position:absolute; top:6px; right:6px; width:28px; height:28px; border-radius:50%; border:0;
  background:rgba(63,52,47,.72); color:#fff; font-size:18px; line-height:1; cursor:pointer; }

/* consent */
.consent-bar { display:flex; align-items:center; justify-content:space-between; gap:12px; margin-top:4px; }
.locked-note { display:inline-flex; align-items:center; gap:6px; font-size:15px; color:var(--soft);
  background:var(--wash); border:1px solid var(--field); border-radius:10px; padding:8px 14px; }
.consent-text { font-size:19px; line-height:1.7; color:var(--ink); margin-top:10px; }
.consent-text p { margin:0 0 14px; }
.consent-text ul { background:#f7ede7; border-radius:12px; padding:16px 22px 16px 42px; margin:16px 0; line-height:1.7; }
.consent-edit { width:100%; box-sizing:border-box; margin-top:12px; min-height:52vh; resize:vertical;
  border:1.5px solid var(--field); border-radius:14px; background:#fff; padding:18px 20px;
  font:inherit; font-size:18px; line-height:1.7; color:var(--ink); outline:0; }
.consent-edit:focus { border-color:var(--bar); }
/* Laptop: the consent reads like a document, so a touch smaller and justified rather than a big
   ragged-right block. */
@media (min-width: 1025px) {
  .consent-text { font-size:16px; line-height:1.65; }
  .consent-text p { text-align:justify; hyphens:auto; -webkit-hyphens:auto; }
}
.signame { color:#4a3f3a; font-size:16px; margin-top:6px; }
.scope { display:flex; flex-direction:column; gap:12px; margin:6px 0 4px; }
.scope-opt { text-align:left; border:1.5px solid var(--field); border-radius:14px; background:#fff; cursor:pointer;
  padding:14px 18px; font:inherit; display:flex; flex-direction:column; gap:3px; transition:border-color .12s; }
.scope-opt:hover { border-color:var(--bar); background:var(--wash); }
.scope-opt b { font-size:19px; color:var(--ink); font-weight:600; }
.scope-opt span { font-size:15px; color:var(--muted); }
/* On a phone the scope-choice modal (Apply these changes to…) reads a size down. */
@media (max-width: 640px) {
  .modal.scopemodal h3 { font-size:21px; }
  .modal.scopemodal .muted { font-size:13px; margin:4px 0 10px; }
  .scope { gap:10px; }
  .scope-opt { padding:11px 14px; }
  .scope-opt b { font-size:15px; }
  .scope-opt span { font-size:12.5px; }
}
.scope-opt.danger-opt:hover { border-color:#c0564a; background:#fdf3f1; }
.scope-opt.danger-opt b { color:#c0564a; }
/* the recommended path stands out: solid green, white text */
.scope-opt.good-opt { background:#4a8a50; border-color:#4a8a50; }
.scope-opt.good-opt:hover { background:#417a47; border-color:#417a47; }
.scope-opt.good-opt b { color:#fff; }
.scope-opt.good-opt span { color:rgba(255,255,255,.9); }
/* the three permissions: separate from the wording, and answered one by one */
.perms { margin:26px 0 4px; background:var(--wash); border:1.5px solid var(--field);
         border-radius:16px; padding:6px 20px 14px; }
.perms-head { display:flex; align-items:baseline; justify-content:space-between; gap:14px;
              padding-top:12px; }
.perms-head h3 { margin:0; font-size:17px; color:var(--bar); font-weight:600;
                 letter-spacing:.04em; text-transform:uppercase; }
.perms-open { font-size:15px; color:var(--rose-2); }
.prow { display:flex; align-items:center; justify-content:space-between; gap:24px;
        padding:14px 0; border-top:1px solid var(--field); margin-top:12px; }
.prow:first-of-type { border-top:0; }
.pinfo { flex:1; min-width:0; }
.plabel { font-size:19px; color:var(--ink); line-height:1.35; }
.pwhy { font-size:15px; color:var(--muted); margin-top:3px; line-height:1.4; }
.prow .opts { display:flex; gap:26px; flex-shrink:0; }
.prow .opt { display:flex; align-items:center; gap:8px; cursor:pointer; font-size:19px; color:var(--ink); }
/* a minor's file says what the document is missing, and blocks nothing */
.minor-note { margin:18px 0 4px; background:#fdf3f1; border:1.5px solid #e8bdb4; border-radius:14px;
              padding:14px 18px; font-size:17px; line-height:1.5; color:#8d3b2f; }
.minor-note.soft { background:var(--wash); border-color:var(--field); color:var(--muted); }
/* The link is part of the sentence, not a floated button hanging off the corner: it reads inline
   after "sign too", wrapping to the next line naturally instead of detaching to the right edge. */
.minor-note .lnk { font-size:17px; float:none; display:inline; margin-left:4px; }
.guardian-in { display:block; width:100%; box-sizing:border-box; margin-top:6px; border:0; outline:0;
               background:transparent; font:inherit; font-size:16px; color:#4a3f3a; padding:0; }

.siglines { display:flex; gap:40px; margin-top:36px; }
.sigline { flex:1; border-top:1.5px solid var(--ink); padding-top:8px; font-size:15px; color:var(--muted);
           min-height:96px; }
.sigline.tap { cursor:pointer; }
.sigline.date { flex:.5; }
/* Signature sits on its own line under the label, never on top of it. */
.sigline img { display:block; margin-top:10px; height:52px; max-width:100%; object-fit:contain; }
.sigline .hint { display:block; margin-top:14px; font-size:14px; color:var(--rose-2); }

/* treatment record */
/* narrowing the visits: a search over the written fields, and a status filter on the Payment header */
.trecbar { display:flex; align-items:center; gap:14px; margin-top:14px; }
/* min-width:0 so the search field can shrink and leave room for the + beside it: without it, Safari
   keeps the input at its content width and pushes the + off the right edge of the screen. */
.tsearch { flex:1; min-width:0; display:flex; align-items:center; gap:10px; background:var(--card); border:1.5px solid var(--field);
           border-radius:40px; padding:10px 18px; max-width:480px; }
.tsearch input { flex:1; min-width:0; border:0; outline:0; background:transparent; font:inherit; font-size:17px; color:var(--ink); }
/* The visit + sits on the search row on every format now, beside the search, so it is where the eye
   already is instead of floating in the header. The old header + is retired (hidden below). */
.trec-add { display:flex; flex:none; width:46px; height:46px; font-size:24px; }
#rec-action { display:none; }
.tclear { border:0; background:none; font:inherit; font-size:20px; color:var(--muted); cursor:pointer; padding:0 2px; }
.thidden { color:var(--muted); font-size:16px; }
.thidden .lnk { margin-left:6px; float:none; }
.payhead { position:relative; white-space:nowrap; }
.colfilt { border:0; background:none; font:inherit; font-size:inherit; color:#fff; cursor:pointer; padding:0; white-space:nowrap; }
.colfilt.on { font-weight:600; text-decoration:underline; }
.colmenu { position:absolute; top:calc(100% + 8px); right:0; z-index:30; background:var(--card); border:1px solid var(--field);
           border-radius:14px; box-shadow:var(--shadow); padding:6px; min-width:180px; }
.colmenu button { display:block; width:100%; text-align:left; border:0; background:none; font:inherit; font-size:17px;
                  color:var(--ink); padding:11px 14px; border-radius:10px; cursor:pointer; }
.colmenu button:hover { background:var(--wash); }
.colmenu button.on { background:var(--wash-2); font-weight:600; color:var(--bar); }
.trec { margin-top:12px; border:1px solid var(--field); border-radius:14px; overflow:hidden; }
.trec .head, .trec .line { display:grid; grid-template-columns:1.1fr 1.1fr 1.05fr .52fr .62fr .62fr .68fr .82fr 44px; }
/* Income and Expenses reuse the .trec shell but carry their own columns, not the record's nine, so
   they fill the width with no empty track left on the right. */
.trec.pay-table .head, .trec.pay-table .line { grid-template-columns:.8fr 1fr 1.05fr .95fr .85fr .7fr .9fr; }
.trec.exp-table .head, .trec.exp-table .line { grid-template-columns:1fr 1.4fr 1fr .7fr 1.05fr 44px; }
.trec.exp-table.novat .head, .trec.exp-table.novat .line { grid-template-columns:1.1fr 1.7fr 1.1fr 44px; }
.trec .head { background:var(--tablehead); color:#fff; font-size:17px; }
.trec .head > div { padding:12px 11px; }
.trec .line { border-top:1px solid var(--line); }
.trec .line[data-row] { cursor:pointer; transition:background .12s; }
.trec .line[data-row]:hover { background:var(--wash); }
.trec .cell { display:flex; align-items:center; font-size:17px; padding:15px 11px; color:var(--ink); min-height:54px;
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.trec .cell + .cell { border-left:1px solid var(--wash-2); }
/* a long service or style name shortens with an ellipsis instead of being cut mid-letter */
.trec .cell .v { overflow:hidden; text-overflow:ellipsis; white-space:nowrap; min-width:0; }
.trec .cell.price { font-weight:600; color:var(--serif); }
.trec .datecell { flex-direction:column; align-items:flex-start; justify-content:center; gap:5px; }
.locpill { display:inline-block; background:#e2eff8; color:#3f7fa1; font-size:12px; font-weight:600;
           border-radius:999px; padding:3px 11px; white-space:nowrap; }
.trec .dash { color:var(--faint); }
.trec .paycell { display:flex; align-items:center; justify-content:center; padding:8px; border-left:1px solid var(--wash-2); }
.paypill { border:0; cursor:pointer; font:inherit; font-size:15px; font-weight:600; border-radius:999px;
           padding:6px 14px; white-space:nowrap; transition:background .12s; }
.paypill.paid { cursor:default; }   /* paid can only be undone in the editor */
.paypill.paid { background:#e3f0e2; color:#3f7a43; }
.paypill.unpaid { background:#f4e5e2; color:#b25c4c; }
.paypill.partial { background:#f6ecd8; color:#a9822f; }
.paypill.noshow { cursor:default; background:#efe1cd; color:#8a6a3a; }   /* a label, not a payment state */
.paypill.deposit { background:#e7e0f2; color:#6a4fa0; }   /* deposit held, tap to complete the visit */
.paypill.refunded { cursor:default; background:#e4e7ea; color:#5f6b74; }   /* deposit given back, counts as nothing */
.trec .del { display:flex; align-items:center; justify-content:center; cursor:pointer; color:#c07a6a;
             font-size:24px; border-left:1px solid var(--wash-2); }

/* treatment form popup */
.modal.trecmodal { width:min(720px, 94vw); }
.tform { display:grid; grid-template-columns:1fr 1fr; gap:16px 22px; margin-top:8px; }
.tform .tf { margin-top:0; }
.tform .tf.full { grid-column:1 / -1; }
/* A group that is shown or hidden as one block, but whose fields still belong to the form's grid.
   Left as a plain div it took a single cell, so its fields stacked in the left column and left a
   hole down the right one. `display:contents` makes the wrapper exist for JS and not for layout;
   `.hidden` still wins over it, so toggling the group keeps working. */
.tform .fieldgroup { display:contents; }

/* ---- payment, inside a treatment ----
   Its own bordered block rather than loose fields in the form's two columns, where the first
   installment's method landed beside the second installment's amount and read as belonging to it.
   An amount and the way it was paid now sit on one row and cannot be misread as anything else. */
.payblock { border:1px solid var(--field); border-radius:16px; padding:16px 18px 14px; background:var(--wash); }
.payblock > label { margin-bottom:10px; }
.payrow { display:flex; gap:20px; align-items:flex-start; margin-bottom:12px; flex-wrap:wrap; }
.paycol { display:flex; flex-direction:column; gap:6px; }
.paycol.grow { flex:1; min-width:230px; }
.paycol .amount { width:150px; background:var(--card); }
.paycol .chips { margin-top:0; }
.paylab { font-size:14px; color:var(--muted); }
.payfoot { display:flex; align-items:center; justify-content:space-between; gap:16px; flex-wrap:wrap;
           padding-top:4px; border-top:1px solid var(--field); margin-top:2px; }
.payfoot .paytotal { margin:0; }
.paystatus { display:flex; align-items:center; gap:12px; flex-wrap:wrap; margin-top:12px;
             padding-top:12px; border-top:1px solid var(--field); }
.paystatus .chips { margin-top:0; }
.paystatus .sset-hint { margin:0; font-size:13px; flex-basis:100%; }
/* Partial is a result, so it is shown and not offered. */
.chip.readonly { cursor:default; }
.chip.readonly:not(.on) { opacity:.5; }
.payblock .fieldnote { color:#b3543f; margin:8px 0 0; }
select.svc { cursor:pointer; appearance:none; -webkit-appearance:none;
  background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%239a8a82' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'><polyline points='6 9 12 15 18 9'/></svg>");
  background-repeat:no-repeat; background-position:right 16px center; padding-right:40px; }
.tform .chips { margin-top:2px; }
.amount { display:flex; align-items:center; border:1.5px solid var(--field); border-radius:12px; background:#fff; padding-left:16px; transition:border-color .12s; }
.amount:focus-within { border-color:var(--bar); }
.amount .cur { color:var(--muted); font-size:20px; }
.amount .tf-in { border:0; padding-left:8px; }
.paytotal { font-size:17px; color:var(--serif); font-weight:600; padding-top:2px; }

/* archived treatments */
.arch-toggle { margin-top:14px; border:0; background:none; cursor:pointer; font:inherit; font-size:16px;
  color:var(--terra); font-weight:600; padding:6px 0; }
.archived-list { margin-top:8px; display:flex; flex-direction:column; gap:8px; }
.arch-row { display:flex; align-items:center; justify-content:space-between; gap:14px; padding:12px 16px;
  border:1px solid var(--field); border-radius:12px; background:var(--wash); color:var(--soft); }
.arch-row .arch-info { font-size:16px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.arch-row .arch-info b { color:var(--serif); }
.arch-row .paypill { margin-left:8px; font-size:13px; padding:4px 10px; }
.arch-acts { display:flex; align-items:center; gap:8px; flex:none; }
.arch-acts .btn.ghost { padding:7px 14px; font-size:14px; }
.arch-acts .del { border:0; background:none; cursor:pointer; color:#c0564a; font-size:22px; padding:0 6px; line-height:1; }

/* pictures & notes */
/* what a permission removed from this screen, and where to change it */
.perm-bar { display:flex; align-items:center; justify-content:space-between; gap:16px; flex-wrap:wrap;
  margin-top:18px; background:#fdf3f1; border:1.5px solid #e8bdb4; border-radius:14px;
  padding:13px 18px; font-size:17px; line-height:1.45; color:#8d3b2f; }
.perm-bar .lnk { font-size:17px; color:#8d3b2f; text-decoration:underline; flex:none; }

.gallery { display:grid; grid-template-columns:repeat(3, 1fr); gap:16px; margin-top:22px; }
.gcell { position:relative; aspect-ratio:1; border-radius:14px; overflow:hidden; background:#efe3dd;
         box-shadow:0 6px 16px rgba(120,90,80,.12); cursor:pointer; }
.gcell img { width:100%; height:100%; object-fit:cover; }
.gcell .cap { position:absolute; left:0; right:0; bottom:0; padding:14px 10px 8px; color:#fff; font-size:13px;
              font-weight:600; background:linear-gradient(to top, rgba(40,25,20,.72), transparent); }
/* Share the picture out, or delete it. On a tablet there is no hover, so the tools are always there. */
.gtools { position:absolute; top:8px; right:8px; display:flex; gap:6px; z-index:2; }
.gt { width:32px; height:32px; border-radius:50%; border:0; cursor:pointer; padding:0;
      display:inline-flex; align-items:center; justify-content:center;
      background:rgba(255,255,255,.94); color:var(--serif); font:400 17px/32px var(--sans);
      box-shadow:0 3px 8px rgba(80,55,45,.24); }
.gt svg { display:block; }
.gt.del { color:var(--rose); font-size:20px; }
.gt:active { background:var(--deep); color:#fff; }

.gadd { display:flex; align-items:center; justify-content:center; border:2px dashed var(--field);
        color:var(--muted); font-size:15px; background:var(--wash); }
.notes-wrap { display:flex; margin-top:18px; border:1px solid var(--field); border-radius:16px; overflow:hidden; min-height:420px; }
.notes-list { width:250px; flex:none; background:var(--wash); border-right:1px solid var(--field); display:flex; flex-direction:column; }
.notes-list .lh { display:flex; align-items:center; justify-content:space-between; gap:8px; padding:12px 12px; border-bottom:1px solid var(--field); }
.notes-list .lh span { font-weight:600; font-size:16px; color:var(--serif); }
/* The notes list header carries a compact search and its + on one line. */
.notes-list .lh .tsearch { flex:1; min-width:0; padding:8px 12px; border-radius:12px; }
.notes-list .lh .tsearch input { font-size:15px; }
.notes-list .lh .round-btn.nadd { flex:none; width:38px; height:38px; font-size:22px;
  box-shadow:0 6px 14px rgba(160,110,110,.3); }
.notes-none { padding:22px 16px; color:#9a8a82; font-size:14px; }
.notes-list .item { padding:14px 16px; border-bottom:1px solid var(--line); cursor:pointer; }
.notes-list .item.on { background:#f0e2da; }
.notes-list .item .t { font-weight:600; font-size:16px; color:var(--ink); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.notes-list .item .d { font-size:13px; color:var(--soft); margin-top:3px; }
.note-editor { flex:1; padding:20px 24px; display:flex; flex-direction:column; }
.note-editor .d { font-size:14px; color:var(--soft); }
.note-editor input.title { border:0; outline:0; background:transparent; font-family:var(--serif-font);
                           font-size:28px; color:var(--serif); margin:4px 0 12px; }
.note-editor textarea { flex:1; border:0; outline:0; background:transparent; resize:none; font:inherit;
                        font-size:19px; line-height:1.7; color:var(--ink); min-height:240px; }

/* The full-screen note editor a phone card opens into. Title, body, delete, saving as it is typed. */
.modal.notemodal { display:flex; flex-direction:column; width:min(720px, 94vw); height:min(80vh, 760px); overflow:hidden; }
.notemodal-h { flex:none; display:flex; align-items:center; justify-content:space-between; gap:12px; }
.nm-date { font-size:14px; color:var(--soft); }
.nm-title { border:0; outline:0; background:transparent; font-family:var(--serif-font); font-size:24px;
            color:var(--serif); padding:10px 0 6px; }
.nm-body { flex:1; min-height:0; border:0; outline:0; background:transparent; resize:none; font:inherit;
           font-size:16px; line-height:1.6; color:var(--ink); }
.notemodal-f { flex:none; display:flex; justify-content:flex-start; padding-top:12px; margin-top:6px; border-top:1px solid var(--line); }
.notemodal .nm-del { border-color:#e6c4bd; color:#c07a6a; }

/* Notes on a phone: a single column of cards on a beige band, grouped by day, like the mockup. The
   two-pane list-and-editor is desktop only. */
@media (max-width: 640px) {
  /* The tab's + moves off the file header (where it looked like it acted on the whole file) onto the
     tab itself: the search row for Record, the top of the beige card for Notes. */
  #rec-action { display:none; }
  .trec-add { display:flex; width:46px; height:46px; font-size:24px; flex:none; }

  .notes-empty { color:var(--muted); font-size:16px; padding:20px 4px 30px; }
  .rbody:has(.notetray) { padding-bottom:0; }
  .notetray { background:#efe4db; box-sizing:border-box;
              margin:16px calc(-26px - env(safe-area-inset-right)) 0 calc(-26px - env(safe-area-inset-left));
              padding:4px calc(26px + env(safe-area-inset-right)) calc(var(--navh) + env(safe-area-inset-bottom) + 24px) calc(26px + env(safe-area-inset-left));
              border-radius:26px 26px 0 0;
              /* Reach the bottom of the screen even with one note: the beige runs under the nav like
                 Home and Finances, instead of stopping short on white. */
              min-height:calc(100dvh - 120px); }
  .notetray-top { display:flex; align-items:center; gap:10px; padding-top:12px; }
  .notetray-top .notesearch { flex:1; min-width:0; }
  .notetray-top .round-btn { flex:none; width:46px; height:46px; font-size:24px; }
  .notegroup { margin-top:16px; }
  .notegroup-h { font-size:15px; font-weight:600; color:var(--soft); margin:0 2px 10px; }
  .notecard { display:flex; align-items:center; gap:12px; background:#fff; border-radius:16px;
              box-shadow:0 4px 14px rgba(120,90,80,.10); padding:14px; margin-bottom:10px; cursor:pointer; }
  .notecard:active { background:#fbf7f4; }
  .notecard-txt { flex:1; min-width:0; }
  .notecard .nt { font-size:16px; font-weight:600; color:var(--ink); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
  .notecard .nb { font-size:13.5px; color:var(--soft); margin-top:3px; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
  .noteopen { flex:none; width:38px; height:38px; border-radius:50%; background:var(--bar); color:#fff;
              display:inline-flex; align-items:center; justify-content:center; pointer-events:none; }
  .noteopen svg { width:17px; height:17px; }
  /* A framed, centred editor, not a full screen: shorter, with room to breathe around it. */
  .modal.notemodal { width:92vw; height:min(66vh, 540px); max-width:none; border-radius:22px; }
}

/* buttons */
.btn { border:0; cursor:pointer; font:inherit; border-radius:12px; padding:10px 18px; font-size:16px; }
.btn.ghost { background:none; border:1.5px solid var(--rose-2); color:var(--rose); font-weight:600;
             display:inline-flex; align-items:center; gap:8px; }
.btn.solid { background:linear-gradient(135deg, var(--rose-2), var(--rose)); color:#fff; font-weight:600;
             display:inline-flex; align-items:center; gap:8px; }
.btn.danger { background:#c0564a; color:#fff; font-weight:600; display:inline-flex; align-items:center; gap:8px; }

/* signature modal */
/* A dialog taller than the screen used to overflow equally above and below, with nothing to
   scroll: the title and the buttons were simply unreachable. Two things fix it. The backdrop
   scrolls and aligns to the top (centring a taller-than-viewport flex child clips its top and makes
   it impossible to scroll back to), and `margin:auto` keeps it centred while it still fits. */
.modal-bg { position:fixed; inset:0; background:rgba(60,40,35,.34); z-index:60; display:flex;
            align-items:flex-start; justify-content:center; overflow-y:auto; padding:20px; }
.modal { width:min(560px, 92vw); background:#fff; border-radius:24px; padding:28px 30px;
         box-shadow:0 24px 60px rgba(90,60,50,.3); margin:auto; max-height:calc(100dvh - 40px);
         overflow-y:auto; }
/* The long forms do better with their own scroller: the heading and the buttons stay in place, so
   Save is always one tap away instead of being at the end of a long scroll. */
.modal.trecmodal, .modal.mapmodal { display:flex; flex-direction:column; overflow:hidden; }
.modal.trecmodal .tform { flex:1; min-height:0; overflow-y:auto; padding-right:6px; }
.modal.trecmodal h3, .modal.trecmodal .actions, .modal.mapmodal h3, .modal.mapmodal .actions { flex:none; }
.modal h3 { font-size:30px; }
.modal .muted { color:var(--soft); font-size:16px; margin:6px 0 16px; }

/* The visit editor is built at tablet sizes; on a phone it reads at the same scale as the rest of
   the file (Intake, Lash), so more than three fields fit at once and nothing shouts. Scoped to the
   modal, so tablet and desktop keep their sizes. */
@media (max-width: 640px) {
  .modal.trecmodal { padding:22px 20px; }
  .modal.trecmodal h3 { font-size:22px; }
  .modal.trecmodal .tform { gap:12px; margin-top:4px; }
  .modal.trecmodal .tf label { font-size:13px; margin-bottom:4px; }
  .modal.trecmodal .req { font-size:10.5px; }
  .modal.trecmodal .tf-in,
  .modal.trecmodal .tform input,
  .modal.trecmodal .tform select { font-size:16px; padding:11px 14px; }
  .modal.trecmodal .chip { font-size:14px; padding:6px 13px; }
  .modal.trecmodal .chip .x { width:18px; height:18px; line-height:16px; margin-left:6px; }
  .modal.trecmodal .chip-in { font-size:15px; }
  .modal.trecmodal .lnk { font-size:13px; }
  .modal.trecmodal .payblock { padding:12px 14px 10px; }
  .modal.trecmodal .paylab, .modal.trecmodal .paystatus .sset-hint { font-size:12px; }
  .modal.trecmodal .actions .btn { font-size:15px; padding:9px 16px; }
}
/* The period picker (Pick a period) is built at tablet sizes too; on a phone it reads at the same
   calm scale as the visit editor, so its title and fields stop shouting. Scoped, like trecmodal. */
@media (max-width: 640px) {
  .modal.ppmodal { padding:22px 20px; }
  .modal.ppmodal h3 { font-size:22px; }
  .modal.ppmodal .tform { gap:12px; margin-top:4px; }
  .modal.ppmodal .tf label { font-size:13px; margin-bottom:4px; }
  .modal.ppmodal .tf-in,
  .modal.ppmodal .tform input,
  .modal.ppmodal .tform select { font-size:16px; padding:11px 14px; }
  .modal.ppmodal .tf-note { font-size:12px; }
  .modal.ppmodal .paytotal { font-size:14px; }
  .modal.ppmodal .actions .btn { font-size:15px; padding:9px 16px; }
}
/* photo opened large, with save / share. Darker backdrop so the photo carries the screen. */
.modal-bg.lightbox { background:rgba(28,20,18,.86); }
.lightbox .lb { display:flex; flex-direction:column; gap:14px; align-items:center; max-width:94vw; }
.lightbox .lb img { max-width:94vw; max-height:74vh; border-radius:16px; box-shadow:0 24px 60px rgba(0,0,0,.45); display:block; }
.lb-bar { display:flex; align-items:center; justify-content:space-between; gap:20px; width:100%; flex-wrap:wrap; }
.lb-cap { color:#fff; font-size:16px; text-shadow:0 1px 6px rgba(0,0,0,.5); }
.lb-note { opacity:.85; font-size:14px; }
.lb-acts { display:flex; gap:10px; margin-left:auto; }
.lightbox .btn.ghost { background:rgba(255,255,255,.94); }

.modal.sigmodal { width:min(720px, 94vw); }
.pad { width:100%; height:260px; border:1.5px solid var(--field); border-radius:14px; background:#fdfaf8; touch-action:none; display:block; cursor:crosshair; }
.modal .actions { display:flex; justify-content:flex-end; gap:12px; margin-top:16px; }
/* On a phone a modal can carry four buttons (Delete, Cancel appointment, Close, Save). Without a wrap
   they overflow a 390px screen and the left ones are clipped off the edge. Let them fall to a second
   row, still right-aligned, so every button stays reachable. */
@media (max-width: 640px) {
  .modal .actions { flex-wrap:wrap; gap:10px; }
}

/* Portrait tablets narrower than a 12.9" iPad (which is 1024 wide, matching the mockup):
   let the two-column grids stack so nothing is clipped by the tab rail. */
@media (max-width: 960px) {
  .grid2 { grid-template-columns:1fr; gap:14px 0; }
  .cfgrid { grid-template-columns:1fr; gap:12px; }
  .medq { max-width:none; }
  .rbody { padding:20px 22px; }
  h2.section { font-size:30px; }
  h3.sub { font-size:26px; }
}
@media (max-width: 720px) {
  .libgrid { grid-template-columns:repeat(2, 1fr); }
  .medq .row { flex-wrap:wrap; gap:4px 0; }
  .trec .head, .trec .line { grid-template-columns:1.05fr 1.05fr 1fr .5fr .6fr .6fr .64fr .78fr 38px; }
  .trec .cell { font-size:16px; padding:12px 8px; }
  .paypill { font-size:13px; padding:6px 10px; }
  .tform { grid-template-columns:1fr; }
  .siglines { flex-direction:column; gap:20px; }
}

/* The treatment table on a phone: the five columns that matter (Date, Service, Style, Price, Payment)
   fit the screen instead of scrolling sideways. Volume, Length and Curl live in the visit editor, a
   tap away. This sits after the ≤720 rule on purpose, so its grid wins over that rule's nine columns
   at this width. Phone only; tablet and desktop keep every column. */
@media (max-width: 640px) {
  /* Reclaim a little of the body's reading gutter so five columns have room to read fully, the way
     the mockup does: the search bar and the table both bleed a touch wider and stay aligned. */
  .trecbar { margin-left:-13px; margin-right:-13px; }
  .trec { overflow-x:visible; margin-left:-13px; margin-right:-13px; }
  .trec .head, .trec .line { min-width:0; grid-template-columns:72px minmax(0,1fr) 56px 46px 56px 20px; }
  /* Volume, Length, Curl are the 4th, 5th and 6th cell of every row and header. */
  .trec .head > *:nth-child(4), .trec .head > *:nth-child(5), .trec .head > *:nth-child(6),
  .trec .line > *:nth-child(4), .trec .line > *:nth-child(5), .trec .line > *:nth-child(6) { display:none; }
  /* Income on the phone: Date, Client, Amount, Status. Service, Method and Left step aside; the amount
     (the point of the table) is brought back, and the four columns fill the width with no gap. */
  .trec.pay-table .head, .trec.pay-table .line { grid-template-columns:56px minmax(0,1fr) 78px 62px; }
  .trec.pay-table .head > *:nth-child(3), .trec.pay-table .line > *:nth-child(3) { display:none; }
  .trec.pay-table .head > *:nth-child(4) { display:block; }
  .trec.pay-table .line > *:nth-child(4) { display:flex; }
  /* Expenses on the phone: Date, Category, Amount. VAT, reclaimable and the × are on the wider screen.
     The .novat variant is spelled out too, or its more specific desktop grid would win here. */
  .trec.exp-table .head, .trec.exp-table .line,
  .trec.exp-table.novat .head, .trec.exp-table.novat .line { grid-template-columns:58px minmax(0,1fr) 92px; }
  .trec .head { font-size:12px; }
  .trec .head > div { padding:11px 5px; }
  /* Nothing spills into its neighbour: each cell clips, and the service pill ellipsises rather than
     overflowing the column when a name is long. */
  .trec .cell { font-size:13px; padding:12px 5px; min-height:50px; overflow:hidden; }
  .trec .datecell { font-size:11px; gap:3px; white-space:nowrap; }
  /* Style repeats the style word (Volume, Hybrid): a size down so it reads in full in a narrow column. */
  .trec .head > *:nth-child(3), .trec .line > *:nth-child(3) { font-size:11.5px; }
  .trec .cell.price { font-size:13.5px; }
  .trec .pill { font-size:11px; padding:4px 8px; max-width:100%; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  .trec .locpill { font-size:8.5px; padding:2px 5px; max-width:100%; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  .trec .paycell { padding:6px 2px; }
  .trec .paypill { font-size:11.5px; padding:5px 8px; }
  .trec .del { font-size:16px; }
  .colfilt { font-size:12px; }
}

/* The client file on a phone: the tab rail becomes a horizontal row of pills at the top of the body
   (moved there in the DOM by placeRail), the form pairs into two columns the way the mockup asks, and
   the decorative left rule is dropped. This block sits after the ≤960 rules on purpose, so its
   two-column grid wins over their single-column stack. Phone only; tablet and desktop are untouched. */
@media (max-width: 640px) {
  /* No white card around the file on a phone: with the tabs swiped rather than pinned to a rail, the
     card was just a frame. The record breaks out of the content's 26px side padding to span the whole
     screen, so the beige band and the tab strip can bleed to the very edges like Home and Finances. */
  .record { background:transparent; border-radius:0; box-shadow:none;
            left:calc(-26px - env(safe-area-inset-left)); right:calc(-26px - env(safe-area-inset-right)); }
  /* The form keeps a 26px reading gutter (same as Home/Finances content), added back on the body. */
  .rbody { padding-top:18px;
           padding-left:calc(26px + env(safe-area-inset-left)); padding-right:calc(26px + env(safe-area-inset-right)); }
  /* The tab strip bleeds full-width and scrolls edge to edge; the first pill still lines up on the gutter. */
  .rail { width:auto; flex-direction:row; gap:5px; padding-bottom:0;
          margin:2px calc(-26px - env(safe-area-inset-right)) 18px calc(-26px - env(safe-area-inset-left));
          padding-left:calc(26px + env(safe-area-inset-left)); padding-right:calc(26px + env(safe-area-inset-right));
          overflow-x:auto; -webkit-overflow-scrolling:touch; scrollbar-width:none; }
  .rail::-webkit-scrollbar { display:none; }
  .rail .tab { flex:0 0 auto; margin-left:0; opacity:.92; border-radius:999px; padding:7px 12px; }
  .rail .tab.active { margin-left:0; border-radius:999px; opacity:1; box-shadow:0 6px 14px rgba(90,60,40,.22); }
  .rail .tab span { writing-mode:horizontal-tb; transform:none; font-size:11px; letter-spacing:.05em; }

  .accent { border-left:0; padding-left:0; margin-top:10px; }
  .accent .grid2 { grid-template-columns:minmax(0,1fr) minmax(0,1fr); gap:15px 16px; }
  .grid2 .f { min-width:0; }
  .f input { font-size:16px; min-width:0; }
  .f label { font-size:13px; }
  .f-name { order:1; } .f-phone { order:2; }
  .f-dob { order:3; } .f-email { order:4; }
  .f-address { grid-column:1 / -1; order:5; }
  .f-referral { order:6; } .f-started { order:7; }
  .f-emergencyName { order:8; } .f-emergencyPhone { order:9; }

  /* Lash Info: the dropdown boxes go two-up, with a compact label and value so both fit in a narrow
     box. Product is a free-text field dressed as the same inline box, half-width on the left. */
  .cfgrid { grid-template-columns:minmax(0,1fr) minmax(0,1fr); gap:11px; }
  .cfgrid .cf { min-width:0; }
  .dd { gap:6px; padding:10px 11px; }
  .dd-label { min-width:0; font-size:11.5px; }
  .dd-val, .dd-input { font-size:14.5px; min-width:0; }
  .dd-caret { font-size:15px; flex:none; }
  /* The options panel: smaller chips, in scale with the compact page. */
  .dd-panel { padding:11px; }
  .dd-panel .chips { gap:6px; }
  .dd-panel .chip { font-size:12px; padding:5px 11px; }
  .dd-panel .chip .x { width:17px; height:17px; line-height:15px; margin-left:6px; }
  .dd-panel .chip-in { font-size:13px; }
  .accent .tf { display:flex; align-items:center; gap:6px; margin-top:11px; max-width:calc(50% - 6px);
                border:1.5px solid var(--field); border-radius:12px; background:#fff; padding:10px 11px; }
  .accent .tf label { margin:0; flex:none; white-space:nowrap; font-size:11.5px; }
  .accent .tf-in { flex:1 1 auto; min-width:0; border:0; border-radius:0; background:transparent; padding:0; font-size:14.5px; }
  .maptray .maptray-h { margin-top:22px; }
  .maptray .maphint { margin-top:8px; font-size:14.5px; }
  .maptray .mapcard { background:#fff; margin-top:14px; }
  /* The Library / Draw buttons sit below the drawing, not over it, so they never hide the map. */
  .maptray .mapcard-tools { position:static; right:auto; bottom:auto; justify-content:flex-end;
                            gap:10px; padding:12px; }

  /* Consent on a phone: Edit and Download shrink to icon buttons in the top-right corner, the text
     reads a size smaller, and the paragraphs are justified with a first-line indent, like a book. */
  .consent-bar { justify-content:flex-end; gap:8px; margin-top:0; }
  .consent-bar .locked-note { margin-right:auto; }   /* signed: note keeps the left, icon stays right */
  .cbtn { padding:0; width:40px; height:40px; flex:none; display:inline-flex; align-items:center;
          justify-content:center; border-radius:12px; }
  .cbtn .btxt { display:none; }
  .cbtn svg { width:20px; height:20px; }
  .consent-text { font-size:15px; line-height:1.65; margin-top:8px; }
  .consent-text p { text-align:justify; hyphens:auto; -webkit-hyphens:auto; text-indent:1.3em; margin:0 0 9px; }
  .consent-text p:first-child { text-indent:0; }
  /* The permissions block reads a size down too. */
  .perms { padding:4px 14px 12px; margin:18px 0 4px; }
  .perms-head h3 { font-size:13.5px; }
  .perms-open { font-size:12.5px; }
  .prow { padding:10px 0; gap:14px; margin-top:10px; }
  .plabel { font-size:14.5px; line-height:1.3; }
  .pwhy { font-size:12px; margin-top:2px; }
  .prow .opts { gap:14px; }
  .prow .opt { font-size:13.5px; gap:6px; }
  .prow .opt .box { width:20px; height:20px; }
  /* Editing mode: the "Editing…" note takes its own line so it reads, and the buttons shrink and wrap
     instead of crowding off the left edge. The textarea drops a size too. */
  .consent-bar { flex-wrap:wrap; }
  .consent-bar .muted { flex:1 1 100%; margin-bottom:8px; font-size:13px; }
  .consent-bar > div { flex-wrap:wrap; }
  .consent-bar .btn:not(.cbtn) { font-size:12.5px; padding:8px 12px; }
  .consent-edit { font-size:15px; line-height:1.6; padding:14px 16px; margin-top:10px; }

  /* Medical Info rides a full-width beige band to the bottom, like Home and Finances. The band cancels
     the body's 18px side padding to reach the edges, and the body's bottom padding is zeroed so the
     beige runs under the nav instead of stopping short on white. */
  .rbody:has(.medtray), .rbody:has(.maptray) { padding-bottom:0; }
  .medtray, .maptray { background:#efe4db;
             margin:22px calc(-26px - env(safe-area-inset-right)) 0 calc(-26px - env(safe-area-inset-left));
             padding:2px calc(26px + env(safe-area-inset-right)) calc(var(--navh) + env(safe-area-inset-bottom) + 24px) calc(26px + env(safe-area-inset-left));
             border-radius:26px 26px 0 0; }
  .medtray .medtray-h { margin-top:22px; }
  .medtray .accent { margin-top:12px; }
  /* The allergies label sits on the beige, the answer in a white box under it. */
  .medtray .allergy { background:transparent; border:0; padding:0; margin-bottom:22px; max-width:none; }
  .medtray .allergy label { font-size:16px; margin-bottom:8px; }
  .medtray .allergy textarea { background:#fff; border:1px solid rgba(120,90,80,.16); border-radius:14px;
                               padding:12px 14px; font-size:16px; }
  /* Yes/No become filled pills: the square is hidden and the option itself carries the state. */
  .medtray .medq .row { flex-wrap:nowrap; gap:12px; align-items:center; font-size:15px;
                        padding:12px 0; border-bottom:1px solid rgba(120,90,80,.12); }
  .medtray .medq .row:last-child { border-bottom:0; }
  .medtray .medq .row > div:first-child { min-width:0; }
  .medtray .opts { gap:8px; flex:none; }
  .medtray .opt { gap:0; padding:6px 15px; border-radius:999px; background:#fff;
                  border:1px solid rgba(120,90,80,.22); color:var(--muted); font-size:13px; font-weight:600; }
  .medtray .opt .box { display:none; }
  .medtray .opt.on { background:var(--bar); border-color:var(--bar); color:#fff; }
  /* The medications follow-up box matches the allergies box: white on the beige. */
  .medtray .medbox { background:#fff; border:1px solid rgba(120,90,80,.16); border-radius:14px; max-width:none; }

  /* Pictures on a phone: two photos to a row (three left each one too small to read a lash line),
     and the "sharing is off" notice reads a size down so it sits as a quiet note, not a banner. */
  .gallery { grid-template-columns:repeat(2, 1fr); gap:12px; margin-top:18px; }
  .perm-bar { margin-top:14px; padding:11px 15px; gap:10px; font-size:14px; line-height:1.4; }
  .perm-bar .lnk { font-size:14px; }
}

/* placeholder screens */
.placeholder { background:var(--card); border-radius:26px; box-shadow:var(--shadow); padding:60px 40px;
               text-align:center; margin-top:10px; }
.placeholder h2 { font-size:38px; }
.placeholder p { color:var(--muted); font-size:18px; margin-top:10px; line-height:1.6; }


/* ---- settings ----
   One card per subject, each editing data the client file already reads. Rows are inputs that save
   as they are typed: there is no Save button because there is nothing to commit, only her own
   settings being kept. */
.sset { background:var(--card); border-radius:20px; box-shadow:var(--shadow); padding:22px 26px 24px; margin-bottom:18px; }
.sset-h { font-size:22px; }
.sset-hint { color:var(--muted); font-size:16px; margin:6px 0 16px; max-width:760px; }
.sset-empty { color:var(--muted); font-size:17px; margin:4px 0 0; }
.sgrid { display:grid; grid-template-columns:1fr 1fr; gap:6px 26px; }
.tf-note { margin:8px 0 0; font-size:14px; line-height:1.5; color:var(--muted); }
.tf-note b { color:var(--ink); font-weight:600; }
.tf-read { border:1.5px solid var(--line); border-radius:12px; background:var(--wash); padding:13px 18px;
           font-size:19px; color:var(--muted); }
.srow { display:flex; align-items:center; gap:12px; margin-bottom:10px; }
.srow .tf-in { flex:1; }
/* A studio is a small stack: its name (with the remove button) on top, then its address and map link
   underneath, lighter, so the block reads as one place. */
.ststack { margin-bottom:16px; }
.ststack .srow { margin-bottom:8px; }
.ststack .st-sub { display:block; width:100%; margin-top:8px; font-size:15px; padding:10px 14px; background:#faf7f4; }
/* A service and its booking-page category: the row on top, the category select on a quiet line below,
   indented under the name so the block reads as one service. */
.svcstack { margin-bottom:16px; }
.svcstack .srow.svc { margin-bottom:6px; }
.svc-cat { display:flex; align-items:center; gap:10px; padding-left:56px; }
.svc-cat label { flex:none; font-size:13px; color:var(--muted); }
.svc-cat select { flex:1; max-width:280px; font-size:15px; padding:9px 12px; background:#faf7f4; }
@media (max-width: 640px) { .svc-cat { padding-left:0; } .svc-cat select { max-width:none; } }
.catrow .movebtn { flex:none; }
/* The read-only category tag shown beside a service in My booking page (edited in Settings). */
.bsvc-cat { display:inline-block; margin-left:8px; font-size:12px; color:var(--muted);
  background:var(--wash-2); padding:2px 9px; border-radius:999px; }
.srow.svc { display:grid; grid-template-columns:44px 1fr 155px 175px 44px; }
/* The colour a service wears on the calendar, right where its name and price are edited. */
/* Both halves of the colour are shown, tint and ink, laid out like an appointment on the calendar:
   what she picks here is exactly what she will see there. Showing only the tint made every swatch
   look like an empty grey box. */
.swatch { width:36px; height:36px; border-radius:11px; border:0; border-left:5px solid var(--ink, #57667F);
          cursor:pointer; box-shadow:0 0 0 1.5px var(--field), 0 3px 7px rgba(120,90,80,.16); }
.palette { display:grid; grid-template-columns:repeat(6, 1fr); gap:12px; margin:18px 0 4px; }
.pswatch { height:52px; border-radius:14px; border:0; border-left:6px solid var(--ink, #57667F);
           cursor:pointer; position:relative; box-shadow:0 0 0 1.5px var(--field); }
.pswatch.on { box-shadow:0 0 0 3px var(--bar); }
.pswatch .dup { position:absolute; right:7px; top:2px; color:var(--ink, #57667F); font-size:22px; line-height:1; }
/* the row is dense: a slightly smaller type, and the unit kept off the edge of its box */
.srow .tf-in { font-size:18px; padding:12px 16px; }
.srow .amount { padding-right:14px; }
.srow .amount .tf-in { padding-right:6px; }
.srow.exp { display:grid; grid-template-columns:1fr 265px 44px; }
.srow .del { width:40px; height:40px; flex:none; border:0; font:inherit; border-radius:10px; background:#faf1ee; color:#c07a6a;
             display:flex; align-items:center; justify-content:center; font-size:22px; cursor:pointer; }
.srow .del:hover { background:#f6e4df; }
.srow .amount .cur.suff { order:2; margin:0 0 0 6px; white-space:nowrap; font-size:15px; color:var(--muted); }
.addrow { margin-top:6px; }

/* On a phone the settings drop to one column. A service still holds its whole line: colour, name,
   price, duration and remove, all shrunk to fit rather than wrapping onto a second row. An expense
   keeps its name and remove on the first line, the reclaim rate below. */
@media (max-width: 640px) {
  .sgrid { grid-template-columns:1fr; }
  /* A description-and-picker row stacks: the label on top, the menu full width below, so a long
     option like a time zone is no longer cut off the right edge. */
  .setline { flex-wrap:wrap; }
  .setline > div { flex:1 1 100%; }
  .setline .setpick, .setline .setpick.wide { width:100%; max-width:none; }
  .srow.svc { display:grid; align-items:center; gap:6px;
    grid-template-columns:22px minmax(0,1fr) 58px 68px 34px;
    grid-template-areas:"swatch name price dur del"; }
  .srow.svc > :nth-child(1) { grid-area:swatch; }
  .srow.svc > :nth-child(2) { grid-area:name; min-width:0; }
  .srow.svc > :nth-child(3) { grid-area:price; min-width:0; }
  .srow.svc > :nth-child(4) { grid-area:dur; min-width:0; }
  .srow.svc > :nth-child(5) { grid-area:del; }
  .srow.svc .swatch { width:22px; height:22px; }
  .srow.svc .amount { padding-left:5px; border-radius:9px; border-width:1px; min-width:0; }
  .srow.svc .amount .cur { font-size:12.5px; }
  .srow.svc .amount .cur.suff { font-size:10px; margin-left:1px; }
  .srow.svc .amount .tf-in { padding:7px 1px; font-size:13px; min-width:0; flex:1; text-align:center; }
  .srow.exp { display:grid; align-items:center; gap:8px 10px;
    grid-template-columns:1fr auto; grid-template-areas:"name del" "tax tax"; }
  .srow.exp > .tf-in { grid-area:name; min-width:0; }
  .srow.exp > .amount { grid-area:tax; min-width:0; }
  .srow.exp > .del { grid-area:del; }
}
/* the week, taken from the mockup: a switch decides the day, a closed day shows only the word */
.wrow { display:flex; align-items:center; gap:18px; padding:14px 0; border-bottom:1px solid var(--line); }
.wrow:last-of-type { border-bottom:0; }
.wday { width:130px; flex:none; font-size:19px; font-weight:600; color:var(--ink); }
.wday .d-sm { display:none; }   /* the 3-letter form is a phone-only fallback (see the week media query) */
.wtimes { display:flex; align-items:center; gap:12px; }
.wrow.solo .wtimes { flex:1; }   /* nothing to pick after them: the hours take the line */
.wrow.solo .wtime { flex:1; width:auto; }
.wdash { color:var(--soft); }
.wtime { width:130px; padding:10px 14px; font-size:17px; }
.wloc { display:flex; align-items:center; gap:8px; flex:1; }   /* the studio runs to the end of the row */
.wstudio { padding:10px 12px; font-size:16px; flex:1; min-width:0; }
.wclosed { color:#bcaea6; font-size:17px; font-style:italic; }
/* On a phone the whole day fits on one line: switch, the day in its 3-letter form, the two times,
   then the studio running to the edge. Everything shrinks to make the room rather than wrapping onto
   three lines. A closed day is just switch, day, and the word pushed to the end. */
@media (max-width: 640px) {
  .wrow { flex-wrap:nowrap; gap:7px; padding:11px 0; }
  .wday { width:auto; flex:none; font-size:14px; }
  .wday .d-lg { display:none; }
  .wday .d-sm { display:inline; }
  .wtimes { flex:none; gap:4px; }
  .wtime { width:62px; flex:none; font-size:12px; padding:7px 5px; text-align:center; }
  .wrow.solo .wtimes { flex:1; }
  .wrow.solo .wtime { flex:1; width:auto; }
  .wloc { flex:1 1 auto; min-width:0; gap:4px; }
  .wloc svg { display:none; }   /* the pin costs width the studio name needs more */
  .wstudio { flex:1 1 auto; min-width:0; font-size:12px; padding:7px 8px; }
  .wclosed { font-size:13px; margin-left:auto; }
}
.switch { width:56px; height:30px; flex:none; border:0; border-radius:20px; padding:3px; cursor:pointer;
          display:flex; align-items:center; background:#d8ccc4; justify-content:flex-start; transition:all .2s; }
.switch.on { background:#4d9a6a; justify-content:flex-end; }
.switch span { width:24px; height:24px; border-radius:50%; background:#fff; box-shadow:0 2px 5px rgba(0,0,0,.25); }
/* one setting on its own line: what it does on the left, the choice on the right */
.setline.first { margin-top:0; padding-top:0; border-top:0; }
.setline { display:flex; align-items:center; justify-content:space-between; gap:16px;
           margin-top:20px; padding-top:20px; border-top:1px solid var(--line); }
.setline b { display:block; font-size:18px; font-weight:600; color:var(--ink); }
.setline span { font-size:14px; color:var(--muted); }
.setpick { width:auto; padding:12px 16px; font-size:16px; cursor:pointer; }
.setpick.wide { max-width:340px; }
.setrow-acts { margin-top:12px; display:flex; align-items:center; gap:10px; flex-wrap:wrap; }
.dirty { color:#b3543f; font-size:15px; }
.btn.solid[disabled], .btn.ghost[disabled] { opacity:.45; cursor:default; }
.maplib-grid { display:grid; grid-template-columns:repeat(3, 1fr); gap:16px; }
.mapcard-s { border:1px solid var(--field); border-radius:16px; padding:12px; display:flex; flex-direction:column; gap:10px; }
.mapcard-s img { width:100%; border-radius:10px; background:var(--wash); }
.mapcard-s .del { align-self:flex-end; }
.btn.ghost[disabled] { opacity:.55; cursor:default; }
.soon { display:flex; flex-direction:column; gap:2px; padding:12px 0; border-top:1px solid var(--line); }
.soon:first-of-type { border-top:0; }
.soon b { font-size:19px; color:var(--serif); font-weight:600; }
.soon span { color:var(--muted); font-size:16px; }

/* ---- profile panel: who is signed in, and the three places that belong to her ---- */
#profile-bg { position:absolute; inset:0; z-index:60; }
.profilepanel { position:absolute; top:84px; right:20px; width:min(384px, calc(100% - 40px)); max-height:calc(100% - 120px); overflow-y:auto; background:var(--card);
                border-radius:24px; padding:22px 24px; box-shadow:0 24px 60px rgba(90,60,50,.28); }
.phead { display:flex; align-items:center; justify-content:space-between; gap:16px; }
.pname { font-size:22px; font-weight:600; color:var(--deep); }
.pmail { color:var(--muted); font-size:15px; margin-top:4px; word-break:break-all; }
.pavatar { width:56px; height:56px; flex:none; border-radius:50%; overflow:hidden; background:#efe3dd; color:var(--bar);
           display:flex; align-items:center; justify-content:center; font-weight:600; font-size:19px; border:2px solid #e7dcd4; }
.pavatar img { width:100%; height:100%; object-fit:cover; }
.pavatar.big { width:64px; height:64px; font-size:20px; color:var(--faint); }
.pplan { margin:15px 0 16px; font-size:16px; color:var(--muted); }
.pplan b { color:var(--bar); font-weight:600; }
/* icon and label as one centred group, with room to breathe between them */
.pitem { display:flex; align-items:center; justify-content:center; gap:11px; width:100%; border:0;
         border-radius:13px; background:#f4ebe6; color:var(--header-txt);
         font:inherit; font-size:16.5px; font-weight:600; padding:12px 15px; margin-top:9px; cursor:pointer; }
.pitem svg { flex:none; display:block; width:20px; height:20px; }
.pitem > span { display:inline-flex; align-items:center; gap:8px; }
.pitem:hover { background:#eddfd7; }
.pitem em { font-style:normal; font-weight:500; font-size:14px; color:var(--faint); margin-left:0;
            border:1px solid var(--field); border-radius:999px; padding:2px 9px; }
.pitem.logout { background:none; color:#c5604c; }
#avatar img { width:100%; height:100%; object-fit:cover; border-radius:50%; }

/* The profile panel is built at tablet sizes; on a phone it reads at the app's own scale so it does
   not fill the screen with a giant name and oversized rows. */
@media (max-width: 640px) {
  .profilepanel { top:70px; right:16px; padding:20px; border-radius:22px; }
  .pname { font-size:20px; }
  .pmail { font-size:14px; margin-top:3px; }
  .pavatar { width:52px; height:52px; font-size:18px; }
  .pavatar.big { width:58px; height:58px; font-size:19px; }
  .pplan { font-size:14.5px; margin:14px 0 14px; }
  .pitem { font-size:15.5px; padding:12px 14px; margin-top:9px; gap:10px; border-radius:12px; }
  .pitem em { font-size:12px; padding:2px 8px; }
  .pitem svg { width:19px; height:19px; }
}

/* Manage account, Settings & availability, and My booking page are built at tablet sizes; on a phone
   they read at the app's own scale (title ~24, labels ~13, fields ~16) so more than a few rows fit and
   nothing shouts. The .settingsview prefix keeps this off every other screen that shares these classes
   (Finance cards, the visit editor). A first pass; each page is then fine-tuned on its own. */
@media (max-width: 640px) {
  .settingsview h2.section { font-size:24px; }
  /* The back control is a bare chevron: on a screen you reached in one tap, the arrow says "back"
     without a line of text cluttering the top. */
  .settingsview .back { font-size:0; gap:0; padding:2px 4px; }
  .settingsview .back::before { content:"\2039"; font-size:30px; line-height:1; color:var(--terra); }
  /* A back link belongs top-left, the title just under it (not off on the right). Stack the header
     and lift the back above the title; the "Saved" flash sits out of the flow in the top corner. */
  .settingsview .listhead { flex-direction:column; align-items:flex-start; gap:4px; position:relative; }
  .settingsview .listhead .back { order:-1; margin:0; align-self:flex-start; }
  .settingsview .listhead .saved { position:absolute; top:2px; right:0; }
  .settingsview .sset { padding:18px 18px 20px; margin-bottom:14px; border-radius:18px; }
  .settingsview .sset-h { font-size:16.5px; }
  .settingsview .sset-hint { font-size:13px; }
  .settingsview .sset-empty { font-size:13.5px; }
  .settingsview .tf label { font-size:12.5px; margin-bottom:4px; }
  .settingsview .tf-in { font-size:15px; padding:9px 12px; }
  .settingsview .tf-read { font-size:15px; padding:9px 12px; }
  .settingsview .tf-note { font-size:11.5px; }
  .settingsview .setline b { font-size:15px; }
  .settingsview .setline span { font-size:12.5px; }
  .settingsview .switch { width:44px; height:24px; }
  .settingsview .switch span { width:18px; height:18px; }
  .settingsview .srow .del { width:34px; height:34px; font-size:18px; }
  .settingsview .wday { font-size:14px; }
  .settingsview .wtime { font-size:12px; padding:7px 5px; }
  .settingsview .wstudio { font-size:12px; padding:7px 8px; }
  .settingsview .palette .pswatch { height:44px; }
  .settingsview .bkname { font-size:22px; }
  .settingsview .bsvc-n, .settingsview .bsvc-d { font-size:13.5px; }
  .settingsview .bkspec { font-size:11.5px; }
}
#avatar { overflow:hidden; padding:0; }
.photorow { display:flex; align-items:center; gap:12px; }
.newcat { grid-column:1 / -1; }
.newcat-row { display:grid; grid-template-columns:1fr 230px; gap:12px; }
.newcat .sset-hint { margin:8px 0 0; font-size:15px; }

/* ---- finance ----
   Nothing here is a figure of its own: every number is read from the client files and the expense
   table below. The layout follows that, headline first, then where the money came from. */
/* the periods sit in their own white pill, as in the mockup */
.periodwrap { margin:0 0 18px; }
/* Same control as the calendar's Month/Week/Day toggle: a beige track, the selected pill white. */
.periodbar { display:inline-flex; background:var(--wash-2); border-radius:40px; padding:5px; gap:2px;
             max-width:100%; flex-wrap:wrap; }
.pchip { border:0; background:none; font:inherit; font-size:18px; color:#8c7d74; padding:11px 22px;
         border-radius:30px; cursor:pointer; white-space:nowrap; }
.pchip.on { background:var(--card); color:var(--ink); font-weight:600; box-shadow:0 3px 8px rgba(120,90,80,.13); }
.kpis { display:grid; grid-template-columns:repeat(3, 1fr); gap:18px; margin-bottom:18px; }
/* On a phone the row is cut to the three figures a business is actually run on: what came in, what
   it cost, and what is left. Still owed steps aside because the dashboard already carries it, in
   red, on the screen she opens first; Visits is derived from the two beside it; the tax estimate is
   a calculator, not a figure, and it needs room to be read. All three remain on a wider screen.
   Their order in the markup is Net income, Collected, Still owed, Expenses, Visits, tax. */
@media (max-width: 640px) {
  /* Two figures per row, so four cards read as a tidy 2×2 instead of three-and-a-lonely-one. Still two
     rows either way, so this costs no height. */
  .kpis { grid-template-columns:repeat(2, 1fr); gap:8px; margin-bottom:14px; }
  /* Phone keeps the figures that matter at a glance (Net, Collected, Expenses, and No-shows when there
     are any); Still owed, Visits and the tax estimate live on the wider screen so the row stays light. */
  .kpis .kpi.hide-phone { display:none; }
  .kpis .kpi { padding:11px 11px 13px; border-radius:16px; gap:3px; }
  .kpis .k-lab { font-size:12px; line-height:1.25; }
  .kpis .k-val { font-size:20px; }
  .kpis .k-sub { font-size:10px; line-height:1.3; }
  /* The beige detail tray, the same idea as the Home dashboard: from Income down the white cards sit
     on a full-width beige band that reads as the background of the detail half of the page. */
  .ftray {
    background:#efe4db;
    margin-left:calc(-26px - env(safe-area-inset-left)); margin-right:calc(-26px - env(safe-area-inset-right));
    border-radius:26px 26px 0 0;
    padding:18px 26px 48px;
  }
  .ftray .sset:last-child { margin-bottom:0; }
  /* Where you work and How you are paid both leave the phone: three columns of service / location /
     method are a lot on a small screen, and only Top services matters there. Both stay on the tablet. */
  .fgrid3 .sset:nth-child(2), .fgrid3 .sset:nth-child(3) { display:none; }
  /* One title size on the phone, the smaller "Income by service" size: the full-width headings
     (Revenue & visits, Income, Expenses) read too big otherwise. */
  .sset-h { font-size:18px; }
  /* The legal note is one column on a phone: two columns of small print on a 390px screen is
     unreadable. Scoped under .legal to outrank the base .legal-cols rule that sits lower in the file. */
  .legal .legal-cols { column-count:1; }
}
.kpi { background:var(--card); border-radius:22px; padding:20px 22px; box-shadow:var(--shadow);
       display:flex; flex-direction:column; gap:5px; min-width:0; }
/* Six identical white cards said six different things in the same voice. A thin band of colour on
   top names what each one is about, kept in the brand's nude range: brown is money in, red is money
   still out, taupe is money spent, warm tan is the count of visits. No greens or yellows. */
.kpi { position:relative; overflow:hidden; }
/* The little accent bar on top of each card is gone in the new design; the cards carry their meaning
   through their own colour now, not a stripe. Kept as a no-op rather than deleted so .kpi.good/.bad
   etc. still parse. */
.kpi::before { content:none; }
.kpi.good { --accent:#9c7147; }
.kpi.bad { --accent:#C0564A; }
.kpi.spend { --accent:#8C7D74; }
.kpi.count { --accent:#c79a6e; }
.kpi.tax { --accent:#6244C4; }
.kpi.good .k-val { color:#8a5a3f; }
.kpi.bad .k-val { color:#b3543f; }
.kpi.bad .k-sub { color:#b3543f; }
.kpi.hero { background:linear-gradient(135deg, #9c7147, #6f4a2a); box-shadow:0 12px 26px rgba(120,80,45,.28); }
.k-lab { color:var(--muted); font-size:15px; }
.k-val { font-size:30px; font-weight:600; color:var(--ink); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.k-sub { color:var(--muted); font-size:14px; }
.kpi.hero .k-lab { color:rgba(255,255,255,.85); }
.kpi.hero .k-val { color:#fff; }
.kpi.hero .k-sub { color:rgba(255,255,255,.82); }
.fgrid { display:grid; grid-template-columns:1fr 1fr; gap:18px; }
/* the three breakdowns side by side: same question asked three ways, so they read as one row */
/* Flex, not a fixed 3-track grid, so the row fills evenly whether it holds two breakdowns or three
   (Where you work drops out when there is only one location). */
.fgrid3 { display:flex; gap:18px; margin-bottom:18px; }
.fgrid3 > .sset { flex:1 1 0; min-width:0; }
.fgrid3 .sset { padding:20px 20px 22px; margin-bottom:0; }
.fgrid3 .sset-h { font-size:19px; }
.fgrid3 .b-head { font-size:15px; }
.fgrid3 .b-head b { font-size:16px; }
/* On a phone the three breakdowns stack, each full width, instead of three columns too narrow to read. */
@media (max-width: 640px) { .fgrid3 { grid-template-columns:1fr; gap:14px; } }
.fgrid .sset { margin-bottom:18px; }
/* the list scrolls inside its card, so ten services do not stretch the row */
/* three lines and no more: the card stays short, the rest is one scroll away */
.bars { display:flex; flex-direction:column; gap:13px; margin-top:4px; max-height:149px; overflow-y:auto;   /* exactly three lines: 3 x 41 + 2 x 13 */
        padding-right:4px; }
.bars-more { font-size:13px; color:var(--faint); margin-top:10px; }
/* The way out of "Not recorded": it names how many are waiting rather than nagging about them. */
.fixmethods { display:block; margin-top:12px; font-size:14px; text-align:left; }
.fixlist { display:block; }
.fixrow { display:grid; grid-template-columns:1fr 1.3fr 1.4fr auto; gap:12px; align-items:center;
          width:100%; text-align:left; font:inherit; cursor:pointer; padding:13px 14px;
          border:1px solid var(--field); border-radius:12px; background:var(--card); margin-bottom:8px; }
.fixrow:hover { background:var(--wash); }
.fixrow .fx-when { color:var(--muted); font-size:15px; }
.fixrow .fx-who { font-weight:600; color:var(--ink); }
.fixrow .fx-what { color:var(--muted); font-size:15px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.fixrow .fx-amt { font-weight:600; color:var(--serif); white-space:nowrap; }
.b-head { display:flex; justify-content:space-between; gap:12px; font-size:17px; margin-bottom:6px; }
.b-head span { overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.b-head b { color:var(--serif); white-space:nowrap; }
.b-track { height:10px; border-radius:999px; background:var(--wash-2); overflow:hidden; }
/* The bar wears the colour of what it counts, the same one it wears on the calendar. Flat, for the
   same reason as the chart: the value does not change along the bar. */
.b-fill { height:100%; border-radius:999px; background:var(--ink, #8a5a3f); }
/* A dot repeats that colour beside the name, so the link to the calendar is readable even on the
   short bars where there is almost no fill to see. */
.b-head .dot { display:inline-block; width:9px; height:9px; border-radius:3px; flex:none;
               background:var(--ink, #8a5a3f); margin-right:8px; vertical-align:middle;
               position:relative; top:-1px; }
/* the tax card carries its own rate, editable in place, as in the mockup */
.taxrow { display:flex; align-items:center; justify-content:space-between; gap:10px; }
.taxpick { display:flex; align-items:center; gap:4px; color:var(--muted); font-size:15px; }
.taxin { width:56px; text-align:right; border:1.5px solid var(--field); border-radius:8px;
         padding:4px 6px; font:inherit; font-size:15px; color:var(--ink); outline:0; background:#fff; }
.taxin:focus { border-color:var(--bar); }
/* recent payments: what came in, in how many goes, how, and what is still out */
.exp-table.novat .head, .exp-table.novat .line { grid-template-columns:1.1fr 2fr 1.2fr 44px; }
.srow.exp.novat { grid-template-columns:1fr 44px; }
.newcat-row.solo { grid-template-columns:1fr; }
/* six rows, then the table scrolls inside its own card: the page keeps its length whatever the
   month held, and the header stays put above the rows */
.trec .tbody { max-height:330px; overflow-y:auto; }
.pay-table { margin-top:14px; }
.pay-table .head, .pay-table .line { grid-template-columns:1fr 1.25fr 1.35fr 1.15fr .85fr .8fr .95fr; }
.pay-table .line { cursor:pointer; }
.pay-table .inst .v { display:flex; flex-direction:column; gap:2px; }
.pay-table .inst b { color:var(--serif); font-weight:600; }
.pay-table .inst em { font-style:normal; font-size:13px; color:var(--muted); }
/* an archived visit still earns money, so it stays in Finance; the badge says why it is missing
   from the client's own list, before she goes looking for it */
.archpill { display:inline-block; margin-left:8px; background:#efe6e0; color:#8a7166; font-size:12px;
            border-radius:999px; padding:2px 9px; vertical-align:middle; }
.archnote { background:#faf4f1; border:1px solid var(--field); border-radius:12px; padding:12px 14px;
            font-size:15px; line-height:1.5; color:var(--muted); }
.mpill { display:inline-block; background:var(--wash-2); color:var(--bar); font-size:14px;
         margin:1px 3px 1px 0;
         border-radius:999px; padding:4px 12px; white-space:nowrap; }
.exp-table .head, .exp-table .line { grid-template-columns:1.1fr 1.5fr 1fr .7fr 1fr 44px; }
.exp-line { cursor:pointer; }
.exp-tot { text-align:right; font-size:19px; font-weight:600; color:var(--serif); margin-top:12px; }

/* revenue & visits: bars for how many, a line for how much */
.chart-head { display:flex; align-items:baseline; justify-content:space-between; gap:16px; flex-wrap:wrap; }
.legend { display:flex; gap:18px; font-size:15px; color:var(--muted); }
.legend span { display:flex; align-items:center; gap:6px; }
.legend .sq { width:12px; height:12px; border-radius:3px; background:#E7CFAD; display:inline-block; }
.legend .ln { width:16px; height:3px; border-radius:2px; background:#8a5a3f; display:inline-block; }
.chart { position:relative; height:240px; margin-top:16px; }
/* The line stops where the bars stop. A column reserves 14px for its label plus a 6px gap, so the
   bars stand on a baseline 20px off the bottom; the line used to run to the very bottom, which put
   it on a different zero from the bars it is read against, and on a short chart it crossed the day
   labels outright. Same floor for both, and the labels get their strip back. */
/* The height is stated, not left to stretch: an <svg> is a replaced element, so top+bottom alone
   make it fall back to its intrinsic ratio and it runs straight out of the card. */
.chart-line { position:absolute; top:0; left:0; width:100%; height:calc(100% - 20px); z-index:2; pointer-events:none; }
.chart-bars { position:absolute; inset:0; display:flex; align-items:flex-end; justify-content:space-between; gap:5px; z-index:1; }
/* The bubble lives inside this group, and a child never escapes its parent's stacking context: at
   z-index 1 the whole group sat under the revenue line, so the line was drawn straight across the
   figures the bubble exists to show. Pointing at a column lifts the group above the line, and the
   line goes back on top the moment it leaves. On a touch screen there is no leaving: a tap kept the
   button focused, so `:focus-within` held the group up for good and the curve stayed buried behind
   the bars. So the tap lift is a `.lift` class the script drops on a timer instead (see bindChartCols):
   the bar rises just long enough to read its bubble, then settles back and the curve returns. */
.chart-bars:hover, .chart-bars.lift { z-index:3; }
/* Every column ends at the same baseline. The label lives inside the column, so a column without
   one used to be shorter and its bar sat lower than its neighbours: the axis looked as though it
   wobbled. The label's line is reserved whether it holds text or not. */
.cb { flex:1; min-width:0; display:flex; flex-direction:column; align-items:center; gap:6px;
      height:100%; justify-content:flex-end; position:relative; cursor:pointer;
      border:0; background:none; padding:0; font:inherit; }
.cb-lab { font-size:11px; color:var(--faint); white-space:nowrap; min-height:14px; line-height:14px; }
/* The chart carries the colour on the money screens, all in the lavender family: visits are soft
   pastel-lavender bars, revenue a deeper lavender curve grading across them, with a faint lavender
   wash beneath. Light bars, deep line: they read apart while staying one palette. */
/* A gentle top-to-bottom sheen gives the bar a little depth without pretending the value changes
   along its height; the shift is light enough to read as a surface, not as data. */
.cb-fill { width:min(100%, 34px);
  background:linear-gradient(180deg, rgba(240,232,222,0.45) 0%, rgba(240,232,222,0.8) 50%, rgba(240,232,222,1) 100%);
  border-radius:8px 8px 4px 4px; min-height:2px; transform-origin:bottom; }
/* The intro (bars rise staggered, curve draws itself in, wash fades up) plays only when she arrives
   on Home or Finance: the .animate class is put on .chart at the arrival sites in app.js. Without it
   the chart is drawn at rest, so touching a period pill or any button on the page repaints it still,
   not as a fresh show. Returning to the page later animates again, which she likes. */
.chart.animate .cb-fill { animation:barRise .55s cubic-bezier(.22,1,.36,1) backwards;
  animation-delay:calc(var(--i, 0) * 45ms); }
@keyframes barRise { from { transform:scaleY(0); opacity:.5; } to { transform:scaleY(1); opacity:1; } }
/* Rosé cream, everywhere: CSS overrides the shared SVG gradients (attributes lose to properties). */
.chart-curve { stroke:#d6a89c; stroke-dasharray:1; }
.chart.animate .chart-curve { animation:curveDraw 1.1s ease-out .15s backwards; }
@keyframes curveDraw { from { stroke-dashoffset:1; } to { stroke-dashoffset:0; } }
.chart-area { fill:none; }
.chart.animate .chart-area { animation:areaFade .8s ease-out .5s backwards; }
@keyframes areaFade { from { opacity:0; } to { opacity:1; } }
@media (prefers-reduced-motion: reduce) {
  .chart.animate .cb-fill, .chart.animate .chart-curve, .chart.animate .chart-area { animation:none; }
}
/* The count sits on top of its own bar. Reading it off the axis was guesswork, and the labels
   underneath are thinned out on long periods, which made the chart look as though it were
   forgetting some columns. */
/* The count belongs in a bubble on demand, not stamped over the chart: a number above every bar
   turns a graph into a table. It answers a hover on a laptop and a tap on a tablet. */
/* The bubble sits just above its own bar, not at the top of the column: `--h` is the bar's height,
   so a short bar keeps its bubble low instead of floating over the chart's title. */
/* Never above the top of the chart. The bubble sits over its own bar, but the tallest bar reaches
   the ceiling, and there it was pushed out of the card and sliced in half by the edge. Past that
   point it stops climbing and rides just inside the top instead. */
.cb-tip { position:absolute; bottom:min(calc(var(--h, 0%) + 34px), calc(100% - 52px)); left:50%; transform:translateX(-50%) translateY(4px);
          background:var(--deep); color:#fff; border-radius:10px; padding:7px 11px; font-size:12px;
          font-weight:600; white-space:nowrap; opacity:0; pointer-events:none; z-index:6;
          transition:opacity .12s ease, transform .12s ease; box-shadow:0 6px 16px rgba(60,40,35,.28); }
.cb-tip em { display:block; font-style:normal; font-weight:400; opacity:.8; margin-top:1px; }
.cb:hover .cb-tip, .cb.on .cb-tip { opacity:1; transform:translateX(-50%) translateY(0); }
.cb:hover .cb-fill, .cb.on .cb-fill { filter:brightness(1.06); }

.chart-caption { font-size:15px; color:var(--muted); margin-top:14px; }

/* the notice sits at the foot of the money screen: visible, readable, and not shouting */
.ast { border:0; background:none; cursor:pointer; font:inherit; font-size:17px; font-weight:700;
       color:var(--terra); padding:0 0 0 3px; line-height:1; vertical-align:super; }
.ast:hover { color:var(--bar); }
.ast-mark { color:var(--terra); font-weight:700; }
@keyframes legalFlash { 0%, 100% { box-shadow:0 0 0 0 rgba(192,143,95,0); }
                        30% { box-shadow:0 0 0 5px rgba(192,143,95,.45); } }
.legal.flash { animation:legalFlash 1.4s ease; }
.legal { background:var(--wash); border:1px solid var(--field); border-radius:18px; scroll-margin:24px;
         padding:20px 24px 22px; margin-bottom:18px; }
.legal h4 { margin:0 0 8px; font-family:var(--sans); font-size:16px; font-weight:600;
            color:var(--serif); letter-spacing:.02em; }
/* two columns rather than one narrow strip with a wide empty margin beside it */
.legal-cols { column-count:2; column-gap:36px; }
/* justified, with hyphenation on: in a narrow column, justifying without it opens rivers of white */
.legal p { margin:0 0 10px; font-size:14px; line-height:1.6; color:var(--muted); break-inside:avoid;
           text-align:justify; text-wrap:pretty; hyphens:auto; -webkit-hyphens:auto; }
.legal p:last-child { margin-bottom:0; }
.legal b { color:var(--ink); }
.k-sub.muted-sub { color:var(--muted); }

/* ---- calendar ----
   The calendar is the one screen that fills its band instead of growing with its content: a day
   runs from her opening hour to her closing one whatever happens in it, and the page behind must
   not scroll while she drags through the hours. So the band stops scrolling here, the card takes
   the full height, and only the grid inside it moves. */
.content:has(#view-calendar:not(.hidden)) { overflow:hidden; padding-bottom:calc(var(--navh) + 6px); }
#view-calendar { flex:1; min-height:0; display:flex; }
.calcard { flex:1; min-width:0; min-height:0; background:var(--card); border-radius:24px; box-shadow:var(--shadow);
           padding:20px 24px 18px; display:flex; flex-direction:column; }
/* One line, and almost no chrome. Five grey pills on two rows read as a toolbar bolted on top of
   the calendar; here only the two things she actually chooses carry a background (the view, and
   adding an appointment). Moving through time is a pair of thin chevrons around the date, which is
   where the eye already is. */
.calbar { display:flex; align-items:center; justify-content:space-between; gap:20px; flex:none;
          padding:2px 2px 6px; }
.calwhen { display:flex; align-items:center; gap:6px; min-width:0; }
.calwhen h2 { font-size:26px; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; padding:0 4px; }
.calwhen .arrow { border:0; background:none; font:inherit; font-size:30px; line-height:1; cursor:pointer;
                  color:var(--faint); padding:2px 8px; border-radius:10px; }
.calwhen .arrow:hover { color:var(--bar); background:var(--wash-2); }
.todaylnk { border:0; background:none; font:inherit; font-size:15px; font-weight:600; cursor:pointer;
            color:var(--rose); padding:6px 10px; border-radius:20px; margin-left:4px; white-space:nowrap; }
.todaylnk:hover { background:#fbf0ee; }
.calviews { display:inline-flex; background:var(--wash-2); border-radius:30px; padding:5px; gap:2px; flex:none; }
.calviews button { border:0; background:none; font:inherit; font-size:16px; color:#8c7d74;
                   padding:9px 20px; border-radius:24px; cursor:pointer; }
.calviews button.on { background:var(--card); color:var(--ink); font-weight:600;
                      box-shadow:0 3px 8px rgba(120,90,80,.13); }
.calacts { display:flex; align-items:center; gap:10px; flex:none; }
.icobtn { width:44px; height:44px; border-radius:50%; border:0; background:none; cursor:pointer;
          display:flex; align-items:center; justify-content:center; }
.icobtn:hover { background:var(--wash-2); }
.newbtn { width:46px; height:46px; border-radius:50%; border:0; cursor:pointer; color:#fff;
          font-size:28px; line-height:1;
          display:flex; align-items:center; justify-content:center;
          background:linear-gradient(115deg, #6d4a49 0%, #8a604f 46%, #c39c7b 100%);
          box-shadow:0 6px 16px rgba(120,74,73,.3); }
/* On a phone the toolbar wraps: the date and its arrows take the first row, the view switch and the
   two actions share the second, instead of the three groups spilling off the right edge. */
@media (max-width: 640px) {
  /* The card is double-padded on a phone (the content gutter, then its own 24px): trimmed here so the
     grid columns and the toolbar get the width back. */
  .calcard { padding:16px 12px 14px; }
  /* Title centred on its own row; the Month/Week/Day toggle and the +/settings share the next row,
     the buttons pushed to the right. */
  .calbar { flex-wrap:wrap; gap:10px 12px; padding:2px 0 6px; }
  .calwhen { flex:1 1 100%; justify-content:center; }
  .calwhen h2 { font-size:22px; }
  .calviews { flex:0 1 auto; }
  .calviews button { padding:7px 13px; font-size:14px; }
  .calacts { margin-left:auto; gap:8px; }
  .icobtn { width:40px; height:40px; }
  .newbtn { width:42px; height:42px; font-size:24px; }
  /* Closed-day note: smaller so it holds on one line on a phone. Raised specificity so it beats the
     base .calclosed further down the file (equal specificity, later source would otherwise win). */
  .calcard .calclosed { font-size:12px; white-space:nowrap; }
}

/* the timed grid, shared by the day and week views */
/* One minute is `--pxm` pixels, so an appointment can be placed by its real start and length. The
   hour is stretched after the grid is drawn to fill the card when the day is short, rather than
   leaving a wide empty band under the last hour. */
.calgrid { flex:1; min-height:0; overflow-y:auto; margin-top:10px; position:relative; --pxm:1px; }
.calgrid .inner { display:grid; gap:0; padding-top:9px; }   /* room for the first hour's label */
.calgrid .gutter div { height:calc(var(--pxm) * 60); font-size:13px; color:var(--faint); text-align:right;
                       padding-right:8px; transform:translateY(-9px); white-space:nowrap; }
.caldaycol { position:relative; border-left:1px solid var(--line); }
/* White means free and tapping it books. Outside her hours is a flat, quiet wash: the old hatching
   shouted louder than the appointments themselves, so the eye read the closed hours first. */
.caldaycol .slot { height:calc(var(--pxm) * 60); border-bottom:1px solid #f8f3ef; cursor:pointer; }
.caldaycol .slot.off { background:#f7f2ee; cursor:pointer; }
.caldaycol .slot:hover { background:rgba(192,143,95,.10); }
.caldaycol .slot.off:hover { background:#f0e9e4; }
.calhead { display:grid; gap:0; flex:none; margin-top:14px; }
/* The week's head and grid scroll together (vertically). Transparent to layout on tablet and desktop. */
.weekscroll { display:contents; }
@media (max-width: 640px) {
  /* The whole week fits the screen, the way a phone calendar shows it: seven narrow columns instead
     of a 736px strip that scrolled sideways three days at a time. An event is a small block, tapped
     for its details; a day header opens the day view. Only the vertical scroll (the hours) remains. */
  /* A slim time gutter (compact hours like "8a") so the seven day columns get the width instead. */
  .weekscroll { display:flex; flex-direction:column; flex:1; min-height:0; margin-top:14px; --calgut:40px; }
  .weekscroll .calhead { margin-top:0; }
  .weekscroll .calgrid { margin-top:8px; }
  .weekscroll .calhead .dh { padding:5px 1px; }
  .weekscroll .calhead .dh .n { font-size:10px; letter-spacing:0; }
  .weekscroll .calhead .dh .d { font-size:16px; }
  .weekscroll .calgrid .gutter div { font-size:11px; padding-right:4px; }
  /* Events shrink to the narrow columns: a name that no longer fits ellipsises, the tick is dropped. */
  .weekscroll .ev { left:1.5px; right:1.5px; padding:3px 4px; border-radius:7px; }
  .weekscroll .ev b { font-size:10px; gap:2px; }
  .weekscroll .ev.short { padding:2px 4px; }
  .weekscroll .ev.short b { font-size:9.5px; }
  .weekscroll .ev em { font-size:9px; margin-top:1px; }
  .weekscroll .ev b .evtick { display:none; }
}
.calhead .dh { text-align:center; padding:6px 4px; border-radius:12px; cursor:pointer;
               border:0; background:none; font:inherit; }
.calhead .dh .n { display:block; font-size:13px; letter-spacing:.5px; color:var(--muted); }
.calhead .dh .d { display:block; font-size:23px; font-weight:700; color:var(--ink); line-height:1.15; }
.calhead .dh.today { background:var(--wash-2); }
.calhead .dh.today .d { color:var(--bar); }
.calhead .dh.closed .d, .calhead .dh.closed .n { color:var(--faint); }

/* An appointment, drawn where it actually sits in the day. `--c` is the colour of the service
   booked, set inline; the status is said by a mark, not by the colour, which now belongs to the
   service. */
.ev { position:absolute; left:4px; right:4px; border-radius:11px; padding:7px 10px; cursor:pointer;
      background:var(--c, #E5E9F1); color:var(--ink, #57667F); overflow:hidden;
      border:0; border-left:3px solid var(--ink, #57667F); text-align:left; font:inherit;
      box-shadow:0 2px 6px rgba(90,70,60,.07); }
.ev b { display:flex; align-items:center; gap:5px; font-size:14px; font-weight:600; line-height:1.2;
        white-space:nowrap; overflow:hidden; }
.ev b span { overflow:hidden; text-overflow:ellipsis; min-width:0; }
/* Under an hour there is only room for one line, so it holds the time and the name together. */
.ev.short { padding:4px 9px; display:flex; align-items:center; }
.ev.short b { font-size:12.5px; font-weight:600; width:100%; }
.ev b .evtick { flex:none; margin-left:auto; stroke:var(--ink, #57667F); }
/* One line each. In a week column barely a hundred pixels wide, "1:00 PM · Refill (2 wk)" wrapped
   onto three lines and pushed the name out of a short appointment. Cut, it still says who and when,
   and the rest is one tap away. */
.ev em { font-style:normal; font-size:12px; opacity:.85; display:block; margin-top:2px;
         white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
/* Recorded keeps its service colour and wears a tick. Cancelled goes pale and struck through: the
   slot was held, and it is worth nothing. */
.ev.done { opacity:.72; }
.ev.cancelled { background:#f4eee9; color:#a2938b; text-decoration:line-through;
                border-left:3px dashed #cfc0b7; box-shadow:none; }
.ev.clash { box-shadow:0 0 0 2px #c0564a; }
/* A folded overlap on the phone's week: a count, not one appointment. It reads as a small stack (a
   second card peeking behind), opens the day rather than dragging, and lets the grid scroll under it. */
.ev.fold { cursor:pointer; touch-action:auto; background:#fbeeeb; color:#8a3b32;
  border-left:3px solid #c0564a;
  background-image:repeating-linear-gradient(135deg, rgba(192,86,74,.09) 0 5px, transparent 5px 11px);
  box-shadow:0 0 0 2px #c0564a, 4px 4px 0 -1px #fbeeeb, 5px 5px 0 0 rgba(192,86,74,.35); }
.ev.fold b { color:#8a3b32; }
.ev.fold em { color:#a4564c; opacity:1; }
/* Lifted off the grid while it is being moved, so it is clearly the thing under her finger. */
.ev.dragging { z-index:5; cursor:grabbing; opacity:.94; transform:scale(1.015);
               box-shadow:0 10px 22px rgba(90,60,50,.28); }
/* Only the block itself opts out of touch scrolling: the grid must still scroll under a finger
   dragged anywhere else, or she could no longer reach the end of her day. */
.ev { touch-action:none; cursor:grab; }
.ev.done { cursor:pointer; }   /* it opens, it does not move: the visit already happened */
/* A frozen field still reads clearly: it is there to be consulted, not to look broken. */
.tform input:disabled, .tform select:disabled { background:var(--wash); color:var(--soft); cursor:default; }
.tform .chip:disabled { cursor:default; opacity:.6; }
.tform .chip.on:disabled { opacity:.85; }
/* The buffer is the tail of its appointment and is genuinely unavailable, so it is striped in its
   own ink rather than left white. */
.evbuf { position:absolute; left:4px; right:4px; border-radius:0 0 11px 11px; pointer-events:none;
         background:repeating-linear-gradient(135deg,
           color-mix(in srgb, var(--ink, #57667F) 17%, transparent) 0 5px,
           color-mix(in srgb, var(--ink, #57667F) 5%, transparent) 5px 10px); }

/* month view */
.calmonth { flex:1; min-height:0; display:flex; flex-direction:column; margin-top:14px; }
.calmonth .wk { display:grid; grid-template-columns:repeat(7, 1fr); gap:6px; flex:none; }
.calmonth .wk div { text-align:center; font-size:13px; letter-spacing:.5px; color:var(--muted); font-weight:600; }
.calmonth .cells { display:grid; grid-template-columns:repeat(7, 1fr); grid-auto-rows:1fr; gap:6px;
                   margin-top:6px; flex:1; min-height:0; }
.mcell { background:var(--wash); border-radius:14px; padding:6px 7px; cursor:pointer; overflow:hidden;
         display:flex; flex-direction:column; gap:3px; border:1.5px solid transparent; text-align:left; font:inherit; }
.mcell.out { opacity:.4; }
.mcell.closed { background:#f6f1ee; }
.mcell.today { border-color:var(--rose-2); }
.mcell .num { font-size:15px; font-weight:600; color:var(--ink); flex:none; }
.mcell.today .num { color:var(--rose); }
/* `width:100%` and `min-width:0`, or a long name simply runs out of its day: a nowrap child in a
   flex column is sized by its text, so the ellipsis never gets a width to cut against. */
.mcell .me { background:var(--c, #E5E9F1); color:var(--ink, #57667F); border-radius:6px;
             padding:3px 7px; font-size:11px; font-weight:500;
             white-space:nowrap; overflow:hidden; text-overflow:ellipsis; flex:none;
             width:100%; min-width:0; }
.mcell .me.cancelled { background:#f0e9e4; color:#a2938b; text-decoration:line-through; }
.mcell .more { font-size:11px; color:var(--faint); padding-left:3px; }

.calempty { color:var(--muted); font-size:17px; padding:10px 2px 0; flex:none; }
.calclosed { font-size:15px; color:var(--faint); margin-top:2px; }
.apptwhen { display:flex; gap:12px; }
.apptwhen .tf { flex:1; }
.evnote { background:var(--wash); border:1px solid var(--field); border-radius:12px; padding:11px 14px;
          font-size:15px; color:var(--muted); line-height:1.5; grid-column:1 / -1; }
/* A quiet aside, not a boxed announcement. It states a consequence in one line and gets out of the way. */
.fieldnote { display:block; font-size:14px; color:var(--muted); margin-top:-4px; }
.tf .fieldnote { margin-top:6px; font-size:13px; }
.req { font-style:normal; font-size:12px; font-weight:600; letter-spacing:.04em; text-transform:uppercase;
       color:var(--rose); margin-left:6px; }
/* Sits with the buttons, because it exists to answer "why can I not save this?" */
.missing { margin-right:auto; font-size:14px; color:#b3543f; text-align:left; line-height:1.4; }


/* Scrolling inside a card must stay inside it. Without `overscroll-behavior: contain`, the moment
   an inner list reaches its top or bottom the gesture carries on into the page behind, which is why
   scrolling a table moved the whole screen about every other try. Applied to every inner scroller.
   `-webkit-overflow-scrolling` restores iOS momentum inside those same boxes. */
.trec .tbody, .bars, .modal, .modal.trecmodal .tform, .rbody, .dd-panel, .notes-list > div,
.colmenu, .profilepanel, #profile-bg, .modal-bg, .calgrid, .hevs, .tlist {
  overscroll-behavior:contain;
  -webkit-overflow-scrolling:touch;
}

/* ============================ DASHBOARD ============================ */
/* Her morning, not a second Finance page. The three cards are read-only doors into Finance, so they
   look like cards and behave like links: no period lives here, only this month. */
.hgreet { display:flex; align-items:baseline; gap:14px; flex-wrap:wrap; margin:0 0 18px; }
.hgreet h2 { font-size:30px; font-weight:600; color:var(--serif); margin:0; letter-spacing:-.015em; }
.hgreet span { color:var(--muted); font-size:17px; }
/* The window continues the sentence rather than sitting beside it: "Good evening, Elena. July so
   far", the second half lighter. A label floating on its own line read as an orphan. */
.hgreet .hsince { font-weight:400; color:var(--muted); font-size:17px; letter-spacing:0; }
/* The hello never breaks inside itself. "Good afternoon" is longer than "Good evening", so on a
   narrow screen the line has to give somewhere: it gives after the full stop, and the window
   continues on the next line, rather than stranding the first name at the start of a line. */
.hgreet .hhello, .hgreet .hsince { white-space:nowrap; }
/* Her name and avatar, phone only: with the header bar gone, this is the way into the profile. */
.hwho { display:none; align-items:center; gap:9px; border:0; background:none; padding:0; cursor:pointer; font:inherit; }
.hwho-n { font-size:13px; font-weight:600; color:var(--serif); white-space:nowrap; }
.hwho-a { width:46px; height:46px; flex:none; border-radius:50%; overflow:hidden;
          border:2px solid rgba(255,255,255,.9); background:#efe3dd; color:#8a5a3f;
          display:flex; align-items:center; justify-content:center; font-size:17px; font-weight:600;
          box-shadow:0 4px 12px rgba(120,90,80,.18); }
.hwho-a img { width:100%; height:100%; object-fit:cover; }

/* The wordmark bar that replaces the header on a phone. Hidden everywhere else. */
.phonebar { display:none; flex:none; justify-content:center; }
.phonebar .plate { display:inline-flex; align-items:center; border-radius:999px; padding:5px 20px;
  background:linear-gradient(115deg, #6d4a49 0%, #8a604f 46%, #c39c7b 100%);
  box-shadow:0 6px 16px rgba(80,55,45,.26); }
.phonebar img { display:block; height:19px; width:auto; object-fit:contain; }
/* The period, twice over: the chip row where there is room, this compact dropdown on a phone. Both
   drive the same `homePeriod`, so they can never disagree. */
/* Outlined pill, no fill: a soft pastel-orange border and a light-brown label, so it reads as a quiet
   control on the pale dashboard rather than a coloured block. */
.hperiod-sel { display:none; flex:none; font:inherit; font-size:16px; font-weight:600; color:var(--muted);
  background:transparent; border:1.5px solid #eec5a3; border-radius:16px; padding:9px 14px;
  cursor:pointer; }

.hkpis { display:grid; grid-template-columns:repeat(3, 1fr); gap:18px; margin-bottom:18px; }
.hkpi { border:0; font:inherit; text-align:left; cursor:pointer; transition:transform .12s, box-shadow .12s; }
.hkpi:hover { transform:translateY(-2px); box-shadow:0 14px 30px rgba(120,90,80,.16); }
.hkpi .k-sub { color:var(--muted); }
/* On the dashboard the money still owed wears a warm tan band rather than a red one: this is her
   calm morning screen, and the figure itself is already red. Finance keeps the red band, because
   that is the screen she opens to act on it. */
.hkpi.bad { --accent:#c79a6e; }
/* The dashboard KPI cards carry their colour, like the mockup: Collected filled in the brand gradient
   with white figures, Still owed a soft warm tint. Home only (.hkpi), so the Finance table keeps its
   plain white cards. */
.hkpi.good { background:linear-gradient(140deg, #8a6660, #a97e63 55%, #c49a78);
             box-shadow:0 12px 26px rgba(120,80,55,.24); }
.hkpi.good .k-lab { color:rgba(255,255,255,.86); }
.hkpi.good .k-val { color:#fff; }
.hkpi.good .k-sub { color:rgba(255,255,255,.82); }

/* The chart is the same component Finance draws, so it needs no styling of its own beyond the room
   to breathe: bars for the visits, a line for the money, the count in a bubble on hover. */
/* Shorter here than in Finance on purpose. The dashboard answers "how is it going" at a glance and
   then gets out of the way; a full-height chart pushes today's appointments off the screen, which
   is the one thing this page exists to show. */
.hchart { margin-bottom:18px; }
.hchart .chart { height:170px; margin-top:4px; }
.hchart .chart-caption { margin-top:10px; font-size:14px; }

.hgrid { display:flex; flex-direction:column; gap:18px; }
.htray { display:flex; flex-direction:column; gap:18px; }
/* The breakdown wrapper is invisible until a laptop turns it into a three-card row; below that it is
   transparent, so Top services behaves exactly as it did. The two extra cards are laptop-only. */
.hbreak { display:contents; }
.deskonly { display:none; }
/* Home, laptop: the three breakdowns share a row, and Today + To do share the row below. This block
   sits after the Home base styles on purpose, so it wins the cascade over them at equal specificity. */
@media (min-width: 1025px) {
  /* Flex, not a fixed 3-track grid, so the row fills evenly whether it holds two cards or three
     (the Where-you-work card drops out when there is only one location). */
  .hbreak { display:flex; gap:18px; align-items:flex-start; }
  .hbreak > .hcard { flex:1 1 0; min-width:0; }
  .hbreak > .deskonly { display:block; }
  .htray { display:grid; grid-template-columns:1.4fr 1fr; gap:18px; align-items:start; }
}
.hcard { background:var(--card); border-radius:22px; padding:20px 22px; box-shadow:var(--shadow); min-width:0; }
.hcard h3 { font-size:19px; font-weight:600; color:var(--serif); margin:0 0 14px; letter-spacing:-.01em; }
.hempty { color:var(--muted); font-size:16px; margin:4px 0 0; }

.hhead { display:flex; align-items:baseline; justify-content:space-between; gap:12px; margin-bottom:14px; }
.hhead h3 { margin:0; }
.hlink { border:0; background:none; font:inherit; font-size:15px; color:var(--terra); cursor:pointer; padding:4px 0; }
.hlink:hover { text-decoration:underline; }

/* Seven days forward from today, never a calendar week: at 8 a.m. on a Friday, Monday is spent. */
.hstrip { display:flex; gap:8px; margin-bottom:18px; }
.hday { flex:1; min-width:0; border:1px solid var(--line); background:var(--card); border-radius:14px;
        padding:10px 4px 8px; cursor:pointer; font:inherit; display:flex; flex-direction:column;
        align-items:center; gap:2px; }
.hday:hover { background:var(--wash); }
.hday.on { background:#f0e8de; border-color:#e6d8ca; }
.hday .hd-w { font-size:12px; letter-spacing:.06em; text-transform:uppercase; color:var(--muted); }
.hday .hd-n { font-size:21px; font-weight:600; color:var(--serif); line-height:1.1; }
.hday.on .hd-w, .hday.on .hd-n { color:#6d4f3f; }
/* One dot per appointment, up to four: she reads how full a day is before tapping it. */
.hday .pips { font-size:9px; line-height:8px; height:8px; letter-spacing:1px; color:var(--terra); }

.hevs { display:flex; flex-direction:column; gap:10px; max-height:328px; overflow-y:auto; padding-right:4px; }
.hev { display:flex; gap:14px; align-items:stretch; width:100%; text-align:left; font:inherit;
       border:0; background:none; padding:0; cursor:pointer; }
.hev-at { flex:none; width:64px; font-size:15px; color:var(--muted); padding-top:12px; }
.hev-body { flex:1; min-width:0; background:var(--c, var(--wash-2)); border-left:4px solid var(--ink, var(--bar));
            border-radius:12px; padding:11px 15px; display:flex; flex-direction:column; gap:3px; }
.hev:hover .hev-body { filter:brightness(.97); }
.hev-body b { font-size:16px; font-weight:600; color:var(--ink, var(--serif)); overflow:hidden;
              text-overflow:ellipsis; white-space:nowrap; }
.hev-body em { font-style:normal; font-size:14px; color:var(--ink, var(--muted)); opacity:.78;
               overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }

/* A ticked task sinks and fades, it does not vanish: seeing it done is the point of ticking it. */
.tlist { display:flex; flex-direction:column; gap:12px; max-height:236px; overflow-y:auto; padding-right:4px; }
.htodo { display:flex; align-items:center; gap:13px; }
.tick { width:24px; height:24px; flex:none; border-radius:50%; border:2px solid var(--field);
        background:var(--card); cursor:pointer; padding:0; }
.tick:hover { border-color:var(--terra); }
/* Filled in the brand's caramel once done, not a green: the palette stays nude and pastel throughout,
   and a lone green tick jarred against it. The white check still reads as clearly "settled". */
.htodo.done .tick { background:#c08f5f; border-color:#c08f5f;
  background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='3.4' stroke-linecap='round' stroke-linejoin='round'><path d='M5 13l4 4L19 7'/></svg>");
  background-size:15px; background-repeat:no-repeat; background-position:center; }
.ttext { flex:1; min-width:0; font-size:17px; color:var(--ink); cursor:text; word-break:break-word;
         border-bottom:1px solid transparent; }
.ttext:hover { border-bottom-color:var(--field); }
/* The field lands exactly where the words were, so the line does not jump under her finger. */
.ttext-edit { flex:1; min-width:0; font:inherit; font-size:17px; color:var(--ink); background:transparent;
              border:0; border-bottom:1px solid var(--terra); outline:none; padding:0; }
.htodo.done .ttext { color:var(--faint); text-decoration:line-through; }
/* The red the app already uses for danger and for deleting, not the softer rose: removing a task is
   the one move on this card that cannot be undone. */
.tdel { width:26px; height:26px; flex:none; border:0; background:none; color:#C0564A; font-size:21px;
        line-height:1; cursor:pointer; border-radius:50%; padding:0; }
.tdel:hover { background:var(--wash-2); }
.tadd { display:flex; align-items:center; gap:13px; margin-bottom:14px; padding-bottom:14px; border-bottom:1px solid var(--line); }
.tplus { width:26px; height:26px; flex:none; border:0; border-radius:50%; background:#c79a6a; color:#fff;
         font-size:19px; line-height:1; cursor:pointer; padding:0; }
.tadd input { flex:1; min-width:0; border:0; outline:none; background:transparent; font:inherit;
              font-size:17px; color:var(--ink); padding:2px 0; }

/* Portrait, or any narrow tablet: the agenda goes full width and the side column falls under it. */
@media (max-width: 1023px) {
  /* The three cards stay on one row: two and a half leaves a hole where the third should be, and
     the row reads as one answer in three parts, not as two plus an orphan. */
  .hkpis { gap:14px; }
  .hkpi { padding:18px 16px; }
  .hkpi .k-val { font-size:26px; }
  .hgrid { grid-template-columns:1fr; }
}
/* The phone dashboard, from Choumous's mockup. Three moves, all about seeing the useful part without
   scrolling: the six-chip period grid becomes one compact dropdown next to "July so far" (about
   200px back), the figures go two across and Average visit steps aside, and Top services rises above
   Today. The rhythm tightens throughout. */
@media (max-width: 640px) {
  /* The compact phone header (sized just above, at 58px) comes back, on every screen (the try-on is a
     separate page and has none): the wordmark on the left, the notification bell and her profile on
     the right. Her name steps aside to keep the row to the bell and the avatar. */
  .header { display:flex; }
  .who { gap:6px; }
  .who .name { display:none; }
  /* The status-band wordmark and the dashboard's own name/avatar are now in the header; drop both. */
  .phonebar { display:none; }
  .hgreet { display:none; }
  /* Content sits just under the header, which already accounts for the safe area in its own height. */
  .content { padding-top:14px; }

  /* Phone shows the full chip bar (her choice), not the dropdown, on both screens: the window is
     one tap not two, and it sits above the figures it drives. Chips shrink to wrap cleanly. */
  .periodwrap { display:block; }
  .hperiod-sel { display:none; }
  .pchip { font-size:14px; padding:8px 14px; }
  /* One line that swipes horizontally: six chips never fit across a phone at a readable size,
     so the bar scrolls rather than wraps. Scrollbar hidden, momentum on. */
  .periodbar { display:flex; width:100%; flex-wrap:nowrap; overflow-x:auto;
               -webkit-overflow-scrolling:touch; scrollbar-width:none; padding:6px; gap:4px; }
  .periodbar::-webkit-scrollbar { display:none; }
  /* Phone drops the 30-day window: This month covers the near term, the longer spans the rest. */
  .pchip[data-period="30d"], .pchip[data-hperiod="30d"] { display:none; }
  #finance-head { align-items:center; }

  /* The window on the left, who she is on the right. The greeting steps aside: it said hello
     twice a day and cost a whole line. */
  .hgreet { gap:10px; margin:0 0 14px; flex-wrap:nowrap; align-items:center; justify-content:flex-end; }
  .hgreet h2 { display:none; }
  .hwho { display:flex; }
  /* Period picker far left, then who she is on the far right: name first, round photo last. */
  .hgreet .hperiod-sel { order:0; }
  .hgreet .hwho { order:1; }
  .hperiod-sel { padding:8px 12px; font-size:14px; border-radius:12px; }
  .hkpis { grid-template-columns:repeat(2, 1fr); gap:12px; margin-bottom:14px; }
  /* Average visit is the one figure she can do without on a small screen: it is derived from the
     two beside it, and Finance still carries it. */
  .hkpis .hkpi:nth-child(3) { display:none; }
  .hkpi { padding:14px 15px 16px; }
  .hkpi .k-val { font-size:28px; }
  /* One line, so the two cards keep the same height side by side. */
  .hkpi .k-sub { font-size:13px; }
  .hcard { padding:16px 16px 18px; border-radius:18px; }
  /* Top services leaves the phone dashboard: it now lives on Finances (renamed there from "Income by
     service"), so a second copy here is clutter. */
  .hgrid .htop { display:none; }
  /* The beige tray: a full-width band bleeding to both screen edges, so it reads as the background of
     the lower section, not a card. Today and the to-do list stay WHITE cards, sitting on it. Negative
     margins cancel the content's side padding to reach the edges; the 26px inner padding lines the
     white cards up with the cards above. Rounded only at the top, where the band rises out of the
     page. The bottom padding runs the beige all the way down behind the floating menu, and the
     content's own bottom padding is dropped on Home (below) so no light strip shows under the band. */
  .htray {
    background:#efe4db; gap:14px;
    margin-left:calc(-26px - env(safe-area-inset-left)); margin-right:calc(-26px - env(safe-area-inset-right));
    border-radius:26px 26px 0 0;
    padding:20px 26px calc(var(--navh) + env(safe-area-inset-bottom) + 24px);
  }
  .content:has(#view-home:not(.hidden)) { padding-bottom:0; }
}

/* ====================== MY BOOKING PAGE (editor) ====================== */
/* The editor shows the page rather than describing it: she edits the thing itself, so there is no
   gap between what she sets and what her clients get. */
.bkhead { display:flex; align-items:center; justify-content:space-between; gap:16px; flex-wrap:wrap; margin-bottom:6px; }
.bkhead h2 { font-family:var(--logo-font); font-size:30px; font-weight:500; color:var(--serif); margin:0; }
.bkhint { color:var(--muted); font-size:16px; margin:0 0 18px; }

.bkcard { position:relative; background:var(--card); border-radius:24px; box-shadow:var(--shadow); margin-bottom:18px; }
.bkbanner { position:relative; display:block; width:100%; aspect-ratio:3 / 1; border:0; padding:0; cursor:pointer;
            overflow:hidden; border-radius:24px 24px 0 0; background:linear-gradient(135deg, #e6d3c6, #cbb2a2); }
.bkbanner img { width:100%; height:100%; display:block; }
.bkbanner.empty > span:first-child { position:absolute; inset:0; display:flex; align-items:center;
  justify-content:center; color:#fff; font:inherit; font-size:16px; font-weight:500; text-shadow:0 1px 6px rgba(80,55,45,.4); }
.bkbanner:hover { filter:brightness(.97); }
/* A presentation photo, matching the page: large and round, hanging below the banner. */
.bkavatar { position:absolute; left:30px; top:-72px; width:144px; height:144px; aspect-ratio:1/1; padding:0;
            border-radius:50%; border:6px solid #fff; overflow:hidden; background:#efe3dd; z-index:2;
            box-shadow:0 10px 24px rgba(80,55,45,.24);
            display:flex; align-items:center; justify-content:center; cursor:pointer;
            font-family:var(--logo-font); font-size:46px; color:var(--brown); }
.bkavatar img { position:absolute; inset:0; width:100%; height:100%; object-fit:cover; }
.bkavatar:hover { filter:brightness(.96); }
.bkwho { position:relative; padding:88px 26px 24px; }
/* The little "Adjust" pill on any editable image. */
.bkadjust { position:absolute; right:12px; bottom:12px; background:rgba(40,25,20,.82); color:#fff;
  font-size:13px; font-weight:600; padding:6px 12px; border-radius:20px; cursor:pointer; z-index:2; }
.bkadjust.round { right:50%; bottom:8px; transform:translateX(50%); padding:4px 10px; font-size:11px; }
.bkadjust:hover { background:rgba(40,25,20,.95); }
/* Transparent until touched: the page is what it looks like, not a form laid over it. */
.bkname, .bkbio { width:100%; font:inherit; color:var(--ink); background:transparent;
  border:1.5px solid transparent; border-radius:12px; padding:6px 12px; margin-left:-12px; outline:none; }
.bkname { font-family:var(--logo-font); font-size:30px; color:var(--serif); }
.bkbio { font-size:17px; line-height:1.55; color:#6d5f57; resize:none; margin-top:4px; }
.bkname:hover, .bkbio:hover { background:var(--wash); }
.bkname:focus, .bkbio:focus { background:var(--wash); border-color:var(--field); }

.bsvc { display:flex; align-items:center; gap:14px; padding:11px 0; border-bottom:1px solid var(--line); }
.bsvc:last-child { border-bottom:0; }
.bsvc-n { flex:1; min-width:0; font-size:17px; color:var(--ink); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.bsvc-n .dot { display:inline-block; width:9px; height:9px; border-radius:3px; margin-right:9px; }
.bsvc-d { flex:none; font-size:15px; color:var(--muted); }

.bkrow { display:flex; align-items:center; gap:14px; margin-top:6px; }
.bklab { font-size:16px; color:var(--ink); }
.bkrow select { max-width:200px; }

.bklink { display:flex; align-items:center; gap:12px; flex-wrap:wrap; }
.bklink code { flex:1; min-width:220px; font-family:ui-monospace, SFMono-Regular, Menlo, monospace; font-size:15px;
  color:var(--serif); background:var(--wash); border:1.5px solid var(--field); border-radius:12px;
  padding:13px 15px; overflow-x:auto; white-space:nowrap; }

@media (max-width: 720px) {
  .bkhead h2 { font-size:25px; }
  .bkavatar { width:86px; height:86px; top:-44px; left:20px; }
  .bkwho { padding:48px 20px 20px; }
}

/* A request is not a booking yet: dashed, so the grid reads at a glance as "held, not agreed". */
.ev.pending { border:2px dashed var(--ink, #8a5a3f); background:repeating-linear-gradient(135deg,
  var(--c, #f4ede9), var(--c, #f4ede9) 9px, rgba(255,255,255,.55) 9px, rgba(255,255,255,.55) 18px); }
.me.pending { border:1.5px dashed var(--ink, #8a5a3f); }

/* Announced above the grid, because a request can land three weeks out and a client who booked and
   heard nothing has been ignored, whatever the calendar says. */
.pendbar { display:flex; align-items:center; gap:14px; width:100%; text-align:left; font:inherit;
  border:0; cursor:pointer; background:linear-gradient(135deg, #f6e7d3, #f3ddc4); border-radius:16px;
  padding:14px 18px; margin-bottom:14px; box-shadow:0 6px 16px rgba(150,110,60,.14); }
.pendbar:hover { filter:brightness(.98); }
.pendbar b { font-size:17px; color:#6d4f2f; flex:none; }
.pendbar span { flex:1; min-width:0; font-size:15px; color:#8a6b48; overflow:hidden;
  text-overflow:ellipsis; white-space:nowrap; }
.pendbar em { flex:none; font-style:normal; font-size:15px; font-weight:600; color:#8a5a3f; }
.evnote.pend { background:#f8eeda; border-color:#e8d3ae; color:#6d4f2f; }

/* Deposit panel on a request: the amount she is waiting for, and one line on what to do. Turns amber
   when it has run past her deadline, so an overdue hold catches the eye without shouting. */
.deppanel { grid-column:1 / -1; background:#f3ede4; border:1px solid #e4d5c1; border-radius:12px; padding:12px 14px; }
.deppanel.over { background:#fbe9d3; border-color:#e6c58e; }
.deppanel.got { background:#e7f0e5; border-color:#c6ddc2; }
.deppanel.got .dep-lab { color:#3f7a43; }
.deprow { display:flex; align-items:center; justify-content:space-between; gap:12px; }
.dep-lab { font-size:14px; font-weight:600; color:#7a5a34; text-transform:uppercase; letter-spacing:.03em; }
.deppanel .dep-amt { max-width:150px; }
.dep-hint { margin:8px 0 0; font-size:13.5px; line-height:1.5; color:#8a7256; }
.dep-hint .dep-waive { font-size:13.5px; padding:0; margin-left:4px; }
.btn.ghost.dep-ask { grid-column:1 / -1; }
@media (max-width: 720px) {
  .pendbar { flex-wrap:wrap; gap:4px 12px; }
  .pendbar span { flex-basis:100%; }
}
/* On phone the header bell already carries waiting requests, so the calendar banner is redundant
   clutter. Hidden here only; laptop and tablet keep it (that call is made separately). */
@media (max-width: 640px) {
  .pendbar { display:none; }
}

/* the editor's extra fields */
.bkspecs { display:flex; flex-wrap:wrap; gap:6px 20px; margin-top:12px; }
.bkspec { font-size:13px; color:var(--faint); }
.bkgrid { display:grid; grid-template-columns:repeat(auto-fit, minmax(240px, 1fr)); gap:14px; }
/* One question-and-answer, editable: the question on top, the answer below, a quiet remove link. */
.bkfaq { border:1.5px solid var(--field); border-radius:14px; padding:12px; margin-bottom:12px; background:var(--wash); }
.bkfaq .bkfaq-q { font-weight:600; margin-bottom:8px; }
.bkfaq .bkfaq-a { width:100%; resize:vertical; }
.bkfaq .bkfaq-del { display:inline-block; margin-top:8px; color:#c07a6a; }

/* ---- Importing clients: the rapid entry, then the review with its confidence badges ---- */
.impmodal { width:min(620px, 94vw); }
.imp-lead { font-size:15px; line-height:1.5; color:var(--muted); margin:2px 0 16px; }
.imp-note { display:block; margin-top:8px; font-size:13px; color:var(--faint); }
/* Photo import: a grid of the sheets she has added, each a thumbnail with a remove corner. */
.pi-grid { display:flex; flex-wrap:wrap; gap:10px; margin-bottom:12px; }
.pi-grid:empty { display:none; }
.pi-thumb { position:relative; width:92px; height:92px; border-radius:12px; overflow:hidden; border:1.5px solid var(--field); }
.pi-thumb img { width:100%; height:100%; object-fit:cover; display:block; }
.pi-del { position:absolute; top:4px; right:4px; width:24px; height:24px; border:0; border-radius:50%;
  background:rgba(30,20,18,.62); color:#fff; font-size:16px; line-height:1; cursor:pointer; }
.pi-status { font-size:14px; color:var(--muted); margin:8px 0 0; min-height:18px; }
/* A PDF has no thumbnail, so its tile shows a badge and the file name instead of an image. */
.pi-thumb.pi-pdf { display:flex; flex-direction:column; align-items:center; justify-content:center; gap:6px; background:var(--wash-2); padding:8px; text-align:center; }
.pi-doc { font-size:12px; font-weight:700; color:var(--brown); letter-spacing:.05em; background:#fff; border:1.5px solid var(--field); border-radius:6px; padding:2px 8px; }
.pi-name { font-size:11px; color:var(--muted); line-height:1.2; overflow:hidden; word-break:break-word;
  display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical; }
.impcards { display:flex; flex-direction:column; gap:12px; margin:4px 0 4px; }
.impcard { border:1.5px solid var(--field); border-radius:14px; padding:14px; background:var(--wash); }
.imphead { margin-bottom:10px; }
.impbadge { display:inline-block; font-size:12px; font-weight:600; padding:4px 10px; border-radius:999px; letter-spacing:.02em; }
.impbadge.b-new { background:#e7f0e5; color:#3f7a43; }
.impbadge.b-match { background:#e6eef8; color:#3a6ea5; }
.impbadge.b-dup { background:#fbe9d3; color:#a5641f; }
.impfields { display:flex; flex-wrap:wrap; gap:8px; }
.impfields .tf-in { flex:1 1 150px; min-width:0; }
.imphint { font-size:13px; line-height:1.45; color:var(--muted); margin:10px 0 0; }
.impacts { display:flex; flex-wrap:wrap; gap:8px; margin-top:12px; }
.impact { font:inherit; font-size:14px; padding:8px 14px; border-radius:10px; cursor:pointer;
  border:1.5px solid var(--field); background:#fff; color:var(--muted); }
.impact.on { border-color:var(--bar); background:var(--bar); color:#fff; }
@media (max-width: 640px) {
  .impmodal h3 { font-size:22px; }
  .impmodal .imp-lead { font-size:14px; }
  .impact { font-size:13px; padding:7px 12px; }
}
.bkf { display:block; }
.bkf span { display:block; font-size:14px; color:var(--muted); margin-bottom:6px; }
.bkfeature { display:block; width:100%; aspect-ratio:3 / 1; border:1.5px dashed var(--field); border-radius:16px;
  background:var(--wash); cursor:pointer; overflow:hidden; padding:0; position:relative; }
.bkfeature img { width:100%; height:100%; display:block; }
.bkfeature.empty span { position:absolute; inset:0; display:flex; align-items:center; justify-content:center;
  color:var(--muted); font:inherit; font-size:16px; }
.bkfeature:hover { border-color:var(--brown); }
.bkmove { display:inline-flex; flex-direction:column; gap:2px; flex:none; }
.movebtn { width:26px; height:20px; border:1px solid var(--field); background:var(--card); border-radius:6px;
  color:var(--serif); font-size:12px; line-height:1; cursor:pointer; padding:0; }
.movebtn:hover:not(:disabled) { background:var(--wash); border-color:var(--bar); }
.movebtn:disabled { opacity:.32; cursor:default; }
.bkgroup { flex:none; width:150px; font-size:15px; padding:8px 11px; }
@media (max-width: 720px) {
  /* One service, one line: switch, name, price, then a compact reorder. The name wins the leftover
     room (flex:1, ellipsis) while everything else stays small and fixed, so it can never be crushed.
     The heading is "on demand" -- empty it collapses to a quiet "+ Group" link; typed, it becomes a
     small chip -- so a service with no group reads as a single clean row, not a full-width empty field. */
  .bsvc { width:100%; box-sizing:border-box; flex-wrap:nowrap; gap:6px; padding:10px 0; }
  .bsvc .switch { order:1; flex:none; width:40px; height:24px; }
  .bsvc .switch span { width:18px; height:18px; }
  .bsvc-n { order:2; flex:1 1 auto; min-width:0; font-size:13.5px; }
  .bsvc-d { order:3; flex:none; font-size:12px; white-space:nowrap; }
  .bsvc-d .bpre { display:none; }            /* drop the duration here (it stays in Settings and the
                                                public preview) so the name keeps a readable width */
  /* An empty text input keeps its ~170px intrinsic width, which would crush the name; pin a real
     width in both states. Empty: a slim, borderless "+ Group" link. Set: a small chip that ellipsizes. */
  .bkgroup { order:4; flex:none; width:20vw; max-width:20vw; font-size:12px; padding:5px 7px;
             overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  .bkgroup:placeholder-shown { width:72px; padding:4px 2px; font-size:11.5px; border-color:transparent;
             background:transparent; color:var(--brown); font-weight:600; text-overflow:clip; }
  .bkmove { order:5; flex:none; flex-direction:column; gap:3px; }
  .movebtn { width:22px; height:16px; }
}

/* The notification bell, in the header on every screen. Light on the header's dark gradient, quiet by
   default, a small count when something waits. It replaces the coloured banners, which read as heavy
   and blended into the app. */
.topbell { position:relative; flex:none; border:0; background:none; cursor:pointer; padding:7px;
  line-height:0; border-radius:50%; color:rgba(255,255,255,.88); }
.topbell:hover { background:rgba(255,255,255,.15); color:#fff; }
.topbell.lit { color:#fff; }
.topbell-dot { position:absolute; top:1px; right:1px; min-width:18px; height:18px; padding:0 4px;
  border-radius:9px; background:#e5342f; color:#fff; font-size:11px; font-weight:700;
  display:flex; align-items:center; justify-content:center; border:1.5px solid rgba(255,255,255,.85); }
.topbell-dot[hidden] { display:none; }
/* Unseen requests pulse a red ring until she opens the bell, then it settles to a static red badge. */
.topbell.unseen .topbell-dot { animation:notifpulse 1.5s ease-out infinite; }
@keyframes notifpulse {
  0%   { box-shadow:0 0 0 0 rgba(229,52,47,.55); }
  70%  { box-shadow:0 0 0 8px rgba(229,52,47,0); }
  100% { box-shadow:0 0 0 0 rgba(229,52,47,0); }
}
@media (prefers-reduced-motion: reduce) { .topbell.unseen .topbell-dot { animation:none; } }

/* On the phone the header drops its brown band: it sits transparent over the page's warm background,
   so the wordmark, the bell and the avatar read in ink instead of white. Profile, bell and logo all
   stay; only the band goes. Placed after the base .header and .topbell rules so it wins the cascade.
   Tablet and desktop keep the gradient band untouched. */
@media (max-width: 640px) {
  .header { background:none; border-radius:0; box-shadow:none; }
  .logo .word { color:var(--brown); }
  .avatar { border-color:var(--field); }
  .topbell, .topbell.lit { color:var(--brown); }
  .topbell:hover { background:rgba(138,90,63,.10); color:var(--brown); }
}

/* The panel behind the bell: a calm list, not a wall of colour. */
.modal.notif { max-width:400px; width:calc(100vw - 40px); text-align:left; }
.notif-head { display:flex; align-items:center; justify-content:space-between; margin-bottom:6px; }
.notif-head h3 { margin:0; font-size:19px; }
.notif-x { border:0; background:none; font-size:26px; line-height:1; color:var(--muted); cursor:pointer; padding:0 4px; }
.notif-group { margin:12px 2px 6px; font-size:12.5px; font-weight:700; letter-spacing:.02em;
  text-transform:uppercase; color:var(--rose-2); }
.notif-list { display:flex; flex-direction:column; gap:6px; margin:0 0 10px; }
.notif-row { display:flex; align-items:center; gap:12px; width:100%; text-align:left; font:inherit;
  border:0; background:#faf6f3; border-radius:14px; padding:12px 14px; cursor:pointer; }
.notif-row:hover { background:#f3ebe5; }
.notif-ini { flex:none; width:38px; height:38px; border-radius:50%; background:var(--rose-2); color:#fff;
  display:flex; align-items:center; justify-content:center; font-size:16px; font-weight:600; }
.notif-txt { flex:1; min-width:0; display:flex; flex-direction:column; gap:1px; }
.notif-txt b { font-size:15.5px; color:var(--serif, #4a3f3a); }
.notif-txt em { font-style:normal; font-size:13.5px; color:var(--muted); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.notif-go { flex:none; font-size:20px; color:var(--rose-2); }
.notif-note { display:block; width:100%; text-align:left; font:inherit; font-size:13.5px; color:var(--muted);
  border:0; background:none; padding:8px 4px 0; cursor:pointer; border-top:1px solid var(--line, #f0e8e3); margin-top:8px; }
.notif-note:hover { color:var(--brown, #6d5147); }
.notif-empty { color:var(--muted); font-size:14.5px; margin:6px 2px; }

/* ---- framing an image: move and zoom inside the exact frame the page uses ---- */
.adjustmodal { max-width:480px; }
.adjustwrap { display:flex; justify-content:center; margin:6px 0 14px; }
.adjustframe { position:relative; width:100%; max-width:420px; overflow:hidden; border-radius:14px;
  background:var(--wash-2); touch-action:none; cursor:grab; user-select:none; }
.adjustframe:active { cursor:grabbing; }
.adjustframe.round { max-width:280px; border-radius:50%; }
.adjustframe img { display:block; pointer-events:none; }
.adjustctl { display:flex; align-items:center; gap:14px; margin-bottom:6px; }
.adjustctl input[type=range] { flex:1; accent-color:var(--brown); }
.adjustctl .btn { width:44px; padding:10px 0; font-size:20px; line-height:1; }
.adjusthint { font-size:14px; color:var(--muted); margin:0 0 16px; text-align:center; }

/* ---- the preview: the real page in a phone-shaped window ---- */
.previewbg { z-index:90; }
/* The frame switches shape between the two screens a client really arrives on. Sized in the phone
   case to a phone, in the desktop case to a wide window scaled to fit — both showing the one real
   page in an iframe, never a second rendering that could drift. */
.previewbox { display:flex; flex-direction:column; background:var(--deep); border-radius:24px;
  overflow:hidden; box-shadow:0 30px 70px rgba(40,25,20,.5); transition:width .18s ease; }
.previewbox.phone { width:min(420px, 94vw); }
.previewbox.desktop { width:min(1080px, 96vw); }
.previewbar { display:flex; align-items:center; justify-content:space-between; gap:12px; padding:11px 14px; color:#fff; }
.previewbar-acts { display:flex; align-items:center; gap:10px; }
.previewbar .hlink { color:#f0d9c4; }
.previewbar .iconbtn { border:0; background:rgba(255,255,255,.14); color:#fff; width:32px; height:32px;
  border-radius:50%; cursor:pointer; font-size:15px; }
.previewbar .iconbtn:hover { background:rgba(255,255,255,.26); }
.pv-modes { display:inline-flex; background:rgba(255,255,255,.12); border-radius:20px; padding:3px; }
.pv-mode { border:0; background:none; color:rgba(255,255,255,.7); font:inherit; font-size:13px; font-weight:600;
  padding:6px 14px; border-radius:16px; cursor:pointer; }
.pv-mode.on { background:#fff; color:var(--deep); }
.previewstage { flex:1; min-height:0; background:#fff; }
/* The iframe is the real page at the width the frame gives it, so the phone view wraps exactly as a
   phone will and the desktop view lays two services across, as a laptop will. */
.previewstage iframe { width:100%; height:72vh; border:0; display:block; }

.bkhead-acts { display:flex; align-items:center; gap:16px; margin:0 4px 14px; }

/* ============================================================
   LOGIN GATE (auth-gate.js)
   The door in front of the app. Opaque, full screen, above everything, so nothing behind it can be
   read or touched until she is signed in. Warm background and the brand gradient button, so the very
   first screen already looks like Flit rather than a bare form.
   ============================================================ */
.authgate {
  position: fixed; inset: 0; z-index: 3000;
  display: flex; align-items: center; justify-content: center;
  padding: calc(env(safe-area-inset-top) + 24px) 22px calc(env(safe-area-inset-bottom) + 24px);
  background: linear-gradient(160deg, #fbf5f1 0%, #f3e7df 100%);
  overflow-y: auto;
}
.authgate.hidden { display: none; }
/* While the session is being checked, the card is hidden so the login form never flashes before we
   know whether she is already signed in. */
.authgate.authbusy .authcard { visibility: hidden; }

.authcard {
  width: 100%; max-width: 360px;
  background: #fff; border-radius: 22px; padding: 34px 28px 26px;
  box-shadow: 0 18px 50px rgba(90, 60, 50, .16); text-align: center;
}
.authbrand img { height: 44px; width: auto; margin-bottom: 18px; }
.authtitle { font-size: 22px; font-weight: 700; color: var(--ink); margin: 0 0 4px; }
.authsub { font-size: 14px; color: var(--muted); margin: 0 0 22px; }

#auth-form { text-align: left; }
.authrow { margin-bottom: 14px; }
.authrow label { display: block; font-size: 12px; font-weight: 600; color: var(--soft);
  text-transform: uppercase; letter-spacing: .04em; margin-bottom: 6px; }
.authrow input {
  width: 100%; box-sizing: border-box; font: inherit; font-size: 16px; color: var(--ink);
  padding: 12px 14px; border: 1.5px solid var(--field); border-radius: 12px; background: #fdfbfa;
  outline: none; transition: border-color .15s;
}
.authrow input:focus { border-color: var(--brown); }

.autherr { min-height: 18px; font-size: 13px; color: #c5604c; margin: 2px 2px 12px; }

.authbtn {
  width: 100%; border: 0; cursor: pointer; font: inherit; font-size: 16px; font-weight: 600;
  color: #fff; padding: 13px; border-radius: 13px;
  background: linear-gradient(115deg, #6d4a49 0%, #8a604f 46%, #c39c7b 100%);
  box-shadow: 0 6px 16px rgba(120, 80, 60, .28);
}
.authbtn:disabled { opacity: .6; cursor: default; }

.authtoggle {
  margin-top: 18px; border: 0; background: none; cursor: pointer; font: inherit; font-size: 14px;
  color: var(--muted);
}
.authtoggle b { color: var(--brown); font-weight: 700; }
/* The way back in when the password is gone: a quiet link under the password field. */
.authlink { display: block; margin: 8px 2px 0; margin-left: auto; width: max-content;
  border: 0; background: none; cursor: pointer; font: inherit; font-size: 13px; color: var(--brown); font-weight: 600; }

/* --- Password field extras on the login gate: reveal eye, live criteria, confirm --- */
.pwwrap { position: relative; }
.pwwrap input { padding-right: 44px; }
.pweye {
  position: absolute; top: 0; right: 0; height: 100%; width: 42px;
  border: 0; background: transparent; cursor: pointer; padding: 0;
  background-repeat: no-repeat; background-position: center; background-size: 21px 21px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%239a8a82' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M1 12s4-7 11-7 11 7 11 7-4 7-11 7-11-7-11-7z'/%3E%3Ccircle cx='12' cy='12' r='3'/%3E%3C/svg%3E");
}
.pweye.on {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%238a604f' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19m-6.72-1.07a3 3 0 1 1-4.24-4.24'/%3E%3Cline x1='1' y1='1' x2='23' y2='23'/%3E%3C/svg%3E");
}

.authcrit { list-style: none; margin: -4px 2px 14px; padding: 0; font-size: 12.5px; color: var(--muted); }
.authcrit li { display: flex; align-items: center; gap: 8px; padding: 3px 0; }
.authcrit li::before {
  content: "\2715"; /* a cross until met */
  width: 15px; text-align: center; font-weight: 700; color: var(--faint); flex: none;
}
.authcrit li.met { color: var(--ink); }
.authcrit li.met::before { content: "\2713"; color: #3f8a5a; }

/* ===== onboarding ===== */
/* The first-run walk-through. It sits at z-index 55: above the app shell (header 40, nav 45) so it
   fully covers the app, but below modals (60) so the booking preview and the client-import dialog it
   launches ride on top of it and, on close, reveal the step underneath. */
.onb-bg { position:fixed; inset:0; z-index:55; background:linear-gradient(160deg,#fbf5f1,#f4ebe6 60%,#efe4dd);
  display:flex; flex-direction:column;
  padding:calc(env(safe-area-inset-top) + 18px) calc(env(safe-area-inset-right) + 22px)
          calc(env(safe-area-inset-bottom) + 22px) calc(env(safe-area-inset-left) + 22px);
  animation:onb-fade .28s ease both; }
@keyframes onb-fade { from { opacity:0; } to { opacity:1; } }
.onb-shell { flex:1; width:100%; max-width:520px; margin:0 auto; display:flex; flex-direction:column; min-height:0; }
.onb-top { display:flex; align-items:center; gap:16px; }
.onb-prog { flex:1; height:6px; border-radius:999px; background:#e7d8cf; overflow:hidden; }
.onb-prog span { display:block; height:100%; border-radius:999px; background:var(--bar);
  transition:width .35s cubic-bezier(.4,0,.2,1); }
.onb-skip { border:0; background:none; font:inherit; font-size:15px; color:var(--muted); cursor:pointer; padding:4px 2px; }
.onb-skip:hover { color:var(--ink); }
.onb-scroll { flex:1; min-height:0; overflow-y:auto; display:flex; flex-direction:column; justify-content:center;
  -webkit-overflow-scrolling:touch; }
.onb-card { padding:28px 4px; }
.onb-title { font-size:30px; line-height:1.15; color:var(--deep); margin:0 0 12px; font-weight:600; }
.onb-sub { font-size:17px; line-height:1.5; color:var(--soft); margin:0 0 26px; max-width:440px; }
.onb-field { display:block; }
.onb-field span { display:block; font-size:14px; color:var(--muted); margin-bottom:8px; }
.onb-field .tf-in { width:100%; }
.onb-days { display:flex; flex-wrap:wrap; gap:10px; margin-bottom:26px; }
.onb-times { display:flex; gap:16px; }
.onb-times label { flex:1; display:flex; flex-direction:column; gap:8px; font-size:14px; color:var(--muted); }
.onb-times input { font:inherit; font-size:17px; padding:11px 12px; border:1.5px solid var(--field);
  border-radius:12px; background:var(--card); color:var(--ink); }
.onb-svc.chips { display:flex; flex-wrap:wrap; gap:10px; }
.onb-link { display:flex; align-items:stretch; gap:8px; margin-bottom:18px; }
.onb-link code { flex:1; min-width:0; display:flex; align-items:center; font-family:var(--sans); font-size:14px;
  color:var(--brown); word-break:break-all; background:var(--wash); border:1px solid var(--line);
  border-radius:12px; padding:12px 14px; }
.onb-copy { flex:none; border:1.5px solid var(--rose-2); background:none; color:var(--rose); font:inherit;
  font-weight:600; font-size:14px; border-radius:12px; padding:0 16px; cursor:pointer; }
.onb-copy:hover { background:var(--wash-2); }
.onb-acts.col { max-width:360px; margin:0 auto; }
.onb-acts { display:flex; gap:12px; flex-wrap:wrap; }
.onb-acts.col { flex-direction:column; align-items:stretch; }
.onb-note { font-size:14px; color:var(--faint); margin:18px 0 0; }
.onb-hero { text-align:center; padding:20px 0; }
.onb-hero .onb-title, .onb-hero .onb-sub { margin-left:auto; margin-right:auto; }
.onb-logo { font-family:var(--logo-font); font-size:44px; color:var(--serif); margin-bottom:22px; }
.onb-badge { font-size:52px; margin-bottom:14px; }
.onb-nav { display:flex; align-items:center; justify-content:space-between; gap:12px; padding-top:16px; }
.onb-navr { display:flex; gap:10px; align-items:center; }
@media (max-width:640px) {
  .onb-title { font-size:26px; }
  .onb-sub { font-size:16px; margin-bottom:22px; }
  .onb-logo { font-size:38px; }
  .onb-times { flex-direction:column; gap:12px; }
}

/* ===== onboarding: richer set-up steps ===== */
.onb-list { display:flex; flex-direction:column; gap:12px; margin-bottom:14px; }
.onb-item { position:relative; display:flex; flex-direction:column; gap:8px;
  background:var(--wash); border:1px solid var(--line); border-radius:14px; padding:14px; }
.onb-item.row { flex-direction:row; align-items:center; gap:10px; }
.onb-item.row .tf-in { flex:1; min-width:0; }
.onb-item .tf-in { width:100%; }
.onb-x { flex:none; border:0; background:none; cursor:pointer; color:var(--faint);
  font-size:22px; line-height:1; width:32px; height:32px; border-radius:8px; }
.onb-item:not(.row) .onb-x { position:absolute; top:8px; right:8px; }
.onb-x:hover { color:var(--rose); background:var(--wash-2); }
.onb-add { width:100%; }

/* Week: one row per day, a toggle chip and the hours that appear when it is on */
.onb-week { display:flex; flex-direction:column; gap:10px; }
/* Each weekday is one row that never wraps: a fixed day chip, then the hours (and studio) sharing the
   rest of the width and shrinking to fit rather than dropping to a second line. */
.onb-day { display:flex; align-items:center; gap:10px; flex-wrap:nowrap; }
.daytoggle { flex:0 0 auto; min-width:64px; text-align:center; }
.onb-day-when { display:flex; align-items:center; gap:6px; flex:1; min-width:0; flex-wrap:nowrap; }
.onb-day:not(.on) .onb-day-when { display:none; }
.onb-day-when input[type=time] { font:inherit; font-size:16px; padding:9px 8px; border:1.5px solid var(--field);
  border-radius:10px; background:var(--card); color:var(--ink); flex:1 1 0; min-width:0; }
.onb-day-when select { flex:1 1 0; min-width:0; }
.onb-dash { color:var(--faint); flex:0 0 auto; }

/* Scheduling rules: labelled rows with a switch, a segmented control, a coming-soon button */
.onb-set { display:flex; flex-direction:column; gap:4px; }
.onb-set-row { display:flex; align-items:center; justify-content:space-between; gap:16px;
  padding:16px 0; border-bottom:1px solid var(--line); }
.onb-set-row:last-child { border-bottom:0; }
.onb-set-row > div b { display:block; color:var(--ink); font-weight:600; }
.onb-set-row > div span { display:block; color:var(--faint); font-size:13px; margin-top:2px; max-width:320px; }
.onb-switch { flex:none; width:52px; height:30px; border-radius:999px; border:0; cursor:pointer;
  background:var(--field); position:relative; transition:background .18s; }
.onb-switch::after { content:""; position:absolute; top:3px; left:3px; width:24px; height:24px; border-radius:50%;
  background:#fff; box-shadow:0 1px 3px rgba(0,0,0,.2); transition:left .18s; }
.onb-switch.on { background:var(--bar); }
.onb-switch.on::after { left:25px; }
.onb-buf-min { padding:0 0 16px; border-bottom:1px solid var(--line); }
.onb-buf-min.off { display:none; }
.onb-buf-min label { display:flex; align-items:center; gap:10px; font-size:14px; color:var(--muted); }
.onb-buf-min input { width:96px; }
.onb-seg { flex:none; display:inline-flex; border:1.5px solid var(--field); border-radius:999px; overflow:hidden; }
.onb-seg-opt { border:0; background:var(--card); font:inherit; font-size:15px; padding:8px 16px; cursor:pointer; color:var(--muted); }
.onb-seg-opt.on { background:var(--bar); color:#fff; }

/* Services: price and duration side by side, with a currency prefix and a "min" suffix */
.onb-svc-nums { display:flex; gap:10px; }
.onb-money, .onb-mins { display:flex; align-items:center; gap:6px; flex:1; min-width:0;
  background:var(--card); border:1.5px solid var(--field); border-radius:10px; padding:0 12px; }
.onb-money span, .onb-mins span { color:var(--faint); font-size:15px; flex:none; }
.onb-money input, .onb-mins input { border:0; background:none; padding:11px 0; width:100%; min-width:0; font:inherit; font-size:16px; color:var(--ink); }
.onb-money input:focus, .onb-mins input:focus { outline:none; }
.onb-item select.tf-in { width:100%; }

/* ===== onboarding: phone harmonisation ===== */
/* Tighter type, spacing and controls on a phone, and a scroll area that never clips the top of a long
   step (safe center falls back to start when the content is taller than the screen). Placed last so it
   wins by cascade order over the base onboarding rules above. */
.onb-scroll { justify-content:safe center; }
@media (max-width: 640px) {
  .onb-bg { padding:calc(env(safe-area-inset-top) + 12px) calc(env(safe-area-inset-right) + 16px)
            calc(env(safe-area-inset-bottom) + 16px) calc(env(safe-area-inset-left) + 16px); }
  .onb-top { gap:12px; }
  .onb-card { padding:18px 2px; }
  .onb-title { font-size:22px; margin-bottom:8px; line-height:1.2; }
  .onb-sub { font-size:14px; line-height:1.45; margin-bottom:16px; }
  .onb-field { margin-bottom:2px; }
  .onb-field span { font-size:13px; margin-bottom:6px; }
  .onb-logo { font-size:32px; margin-bottom:12px; }
  .onb-badge { font-size:40px; margin-bottom:8px; }
  .onb-hero { padding:8px 0; }
  .onb-note { font-size:13px; margin-top:14px; }

  /* Fields: keep 16px text so iOS does not zoom on focus, but shrink the padding. */
  .onb-card .tf-in { font-size:16px; padding:10px 12px; }
  .onb-list { gap:10px; margin-bottom:10px; }
  .onb-item { padding:12px; gap:8px; border-radius:12px; }
  .onb-item.row { gap:8px; }
  .onb-x { width:30px; height:30px; font-size:20px; }

  /* Week: each day on ONE line. Fixed narrow day chip, hours and studio share the rest and shrink. */
  .onb-week { gap:8px; }
  .daytoggle { flex:0 0 auto; min-width:52px; font-size:14px; padding:8px 10px; }
  .onb-day { gap:8px; flex-wrap:nowrap; }
  .onb-day-when { gap:5px; flex:1; min-width:0; flex-wrap:nowrap; }
  .onb-day-when input[type=time] { font-size:14px; padding:8px 4px; flex:1 1 0; min-width:0; }
  .onb-day-when select { flex:1 1 0; min-width:0; font-size:14px; padding:8px 4px; }
  .onb-dash { display:none; }   /* the two time fields read clearly enough side by side on a phone */

  /* Scheduling rules */
  .onb-set-row { padding:13px 0; gap:12px; }
  .onb-set-row > div span { font-size:12.5px; }
  .onb-seg-opt { font-size:14px; padding:7px 13px; }

  /* Services price + minutes stay side by side but slimmer */
  .onb-svc-nums { gap:8px; }
  .onb-money, .onb-mins { padding:0 10px; }
  .onb-money input, .onb-mins input { font-size:16px; padding:10px 0; }

  /* Bottom bar buttons */
  .onb-nav { padding-top:12px; gap:10px; }
  .onb-nav .btn { font-size:15px; padding:11px 16px; }
  .onb-skip { font-size:14px; }
  .chip { font-size:15px; padding:7px 13px; }
}

/* ===== onboarding: final celebration ===== */
.onb-burst { position:relative; display:inline-block; margin-bottom:8px; }
.onb-celebrate .onb-badge { display:inline-block; animation:onb-pop .55s cubic-bezier(.2,.9,.3,1.5) both; }
@keyframes onb-pop { 0% { transform:scale(0) rotate(-18deg); } 60% { transform:scale(1.18) rotate(6deg); } 100% { transform:scale(1) rotate(0); } }
.onb-burst i { position:absolute; top:50%; left:50%; width:8px; height:8px; margin:-4px 0 0 -4px; border-radius:2px;
  opacity:0; animation:onb-confetti .75s ease-out both; animation-delay:.12s; }
.onb-burst i:nth-of-type(1) { --a:0deg;   background:var(--rose); }
.onb-burst i:nth-of-type(2) { --a:45deg;  background:var(--terra); }
.onb-burst i:nth-of-type(3) { --a:90deg;  background:var(--rose-2); }
.onb-burst i:nth-of-type(4) { --a:135deg; background:var(--bar); }
.onb-burst i:nth-of-type(5) { --a:180deg; background:var(--terra); }
.onb-burst i:nth-of-type(6) { --a:225deg; background:var(--rose); }
.onb-burst i:nth-of-type(7) { --a:270deg; background:var(--bar); }
.onb-burst i:nth-of-type(8) { --a:315deg; background:var(--rose-2); }
@keyframes onb-confetti {
  0%   { opacity:0; transform:rotate(var(--a)) translateY(-4px); }
  20%  { opacity:1; }
  100% { opacity:0; transform:rotate(var(--a)) translateY(-52px); }
}
.onb-celebrate .onb-title, .onb-celebrate .onb-sub { animation:onb-rise .5s ease both; animation-delay:.18s; }
@keyframes onb-rise { from { opacity:0; transform:translateY(8px); } to { opacity:1; transform:none; } }
@media (prefers-reduced-motion: reduce) {
  .onb-celebrate .onb-badge, .onb-burst i, .onb-celebrate .onb-title, .onb-celebrate .onb-sub { animation:none; opacity:1; }
  .onb-burst i { display:none; }
}

/* ===== onboarding: per-step artwork slot ===== */
.onb-art { text-align:center; margin:0 0 18px; }
.onb-art img { max-width:100%; max-height:200px; height:auto; object-fit:contain; }
@media (max-width: 640px) { .onb-art { margin-bottom:14px; } .onb-art img { max-height:150px; } }
