/* The staff portal's paint chart (design 7d "Cupertino", 2026-09-21).
   The portal owns its colours here, as directory.css does for the admin:
   named by meaning, once, light and dark — no literal colour below this block.
   No cards, no shadows, no gradients: hierarchy is type size and weight, rows
   part on one hairline, and the accent is only ever something you can tap.
   The "C Suite" palette of the New Design (Haoming, 2026-09-22): navy ink
   and accent, warm greys. **The shifts wear the admin side's colours**
   (the demo's feedback, 2026-10-01: a second palette on the phone would
   confuse) — Sister's four Excel fills, nurse pink and amber, HCA cyan and
   green.
   The blue and beige tried on 2026-09-22 are gone. On a dark phone the
   fill is a deep tone of the same hue and the Excel colour is the ink. */
:root {
    /* the typeface, named once (Haoming, 2026-10-08): the phone's own system font first —
       San Francisco on an iPhone, Roboto on Android, nothing to download — with Inter,
       the open face nearest San Francisco, behind it for a laptop */
    --sans:-apple-system, system-ui, "Inter", sans-serif;
    /* Sister's four fills — roster_view's CELL_COLOURS, the same on every
       theme (a test holds them equal) */
    --fill-nurse-day:#ff99ff; --fill-nurse-night:#ffd966; --fill-hca-day:#66ffff; --fill-hca-night:#99ff99;
    /* what a dot or a swatch shows: the fill itself, whatever the theme */
    --am-fill:var(--fill-nurse-day); --pm-fill:var(--fill-nurse-night);
    /* The refresh (Haoming's prototype, 2026-10-16): navy ink, a warm grey ground under
       white cards, the prototype's own greys and skies — every shift still in Sister's fills */
    --bg:#f4f3f0; --ground:#f4f3f0; --card:#ffffff; --lift:#f1f3f6;    /* every light screen stands on the warm ground the hub had (Haoming, 2026-10-26, from a reference he brought); the cards stay white and lift on their own */
    --ink:#1f314e; --muted:#4f5866; --muted-2:#6b7280; --line:#e6e8ec; --line-soft:#eef0f3;
    --chevron:#9aa3af; --tab-off:#6b7280; --tabbar:#ffffff; --tab-on:#e6ecf3;
    --accent:#1f314e; --on-accent:#ffffff;
    --danger:#b42318; --on-danger:#ffffff; --danger-soft:#fef0ee;
    --amber-ink:#8a4b00;
    --overdue:#ff0f0f;    /* a request waiting past seven days says its age in this red — Haoming's pick (2026-10-26), the same on a dark phone */
    --danger-btn:#c8483e; --on-danger-btn:#ffffff;    /* the filled Decline button, his reference's brick red with white on it (2026-10-26) */
    --ph:#c2410c;         /* a public holiday's dot on a cell (2026-09-30) */
    /* Month's skies: the hero follows the shift (night · day · off · a month not out) */
    --sky-night:#1f314e; --sky-day:#fce6fe; --sky-off:#e6ecf3; --sky-none:#efebe3;
    --hero-ink:#1f314e; --hero-ink-night:#ffffff; --ring-today:rgba(31,49,78,.55);
    /* the scenes' tinted parts on a light sky; on a dark sky (a night, or a dark phone) they go white */
    --sc-steam:#aeb7c4; --sc-ripple:#8e99ab; --sc-white:#f2a7a9; --sc-skyline:#f6cfcf;
    --sc-snow:#f2c14e; --sc-navyish:#1f314e; --sc-rays:0.5;
    /* Services' tiles and the Inbox's cards (the refresh, sitting two): the tones, the
       corner drawings' strokes, the navy button, the positive green, the chips and quotes */
    --tile-amber:#fdf0c4; --tile-blue:#e6ecf3; --tile-pink:#fce6fe; --tile-dash:#c9cdd4;
    --glyph-amber:#edc54e; --glyph-pink:#eba6f2; --glyph-grey:#e3e6ea; --glyph-dash:#dadde2; --glyph-cloud:rgba(255,255,255,.9);
    --dot-empty:#6b7280; --dot-on:#1f314e; --on-dot:#ffffff;
    --navy-btn:#1f314e; --on-navy:#ffffff; --soft-btn:#ffffff; --shift-ink:#1f314e;
    --positive:#2e8b5e; --positive-soft:#e7f4ec;
    --track:#eceae5; --field:#f1efea; --field-edge:transparent;   /* Claimed time's switch track and fields (Haoming's design, 2026-10-19) */
    --chip-blue:#e6ecf3; --quote:#f4f3f0; --quote-amber:rgba(255,255,255,.7); --meta-amber:#6b5a2a;
    --card-shadow:0 1px 2px rgba(31,49,78,.04), 0 8px 20px rgba(31,49,78,.05); --row-shadow:0 1px 2px rgba(31,49,78,.04);    /* quieter on the ground (2026-10-26) */
    /* Me (the refresh, 2026-10-19): the navy sky, the badge card, the record card behind it */
    --me-sky:#1f314e; --mb-card:#ffffff; --mb-face:#e6ecf3; --mb-pill:#f4f3f0; --mb-shadow:0 30px 60px rgba(0,0,0,.35);
    --rec:#fdf0c4; --rec-meta:#6b5a2a; --rec-dash:#b8a36a; --rec-line:rgba(138,75,0,.14); --me-arrow:#f9db78;
    --sheet-shadow:rgba(25,49,80,.16);
    /* the cells — a nurse's AM and PM, an HCA's AM and PM (ground and ink), and
       the resting grey */
    --am:var(--fill-nurse-day); --am-ink:#193150;
    --pm:var(--fill-nurse-night); --pm-ink:#193150;
    --hca-am:var(--fill-hca-day); --hca-am-ink:#193150;
    --hca-pm:var(--fill-hca-night); --hca-pm-ink:#193150;
    /* a tile ticked in a sheet: a step lighter than the cell (Haoming, 2026-10-23 — a choice, not a
       placed shift), navy ink on it in both themes */
    --am-soft:#ffccff; --pm-soft:#ffecb2; --hca-am-soft:#b2ffff; --hca-pm-soft:#ccffcc; --on-soft:#193150;
    --rest:#f1f0ed; --rest-ink:#6b655b;
    --layer-1:#e2dfd8; --layer-2:#d5d1c8;   /* the two card edges peeking under an Inbox stack (2026-10-23) */
    --closed-card:rgba(241,240,237,.78); --closed-halo:#f1f0ed;   /* behind the word over a month that closed early (2026-10-05): the grey, translucent */
    --done:#49d149; --on-done:#193150;   /* the pill's done moment — Haoming's green, rgb(73,209,73), navy ink on it (2026-10-05) */
    --strip-plain:#ecebe7;               /* a Requests card's strip for a kind whose tile has no tone (2026-10-26) */
    --shade:#e7e4df; --band:#dce3f0;      /* Claimed time: a taken day's pill, the picked range's band (2026-10-06) */
    --scrim:rgba(25,49,80,.28);           /* the dim behind an alert */
    /* The sign-in's badge (Haoming's reference D4e, 2026-10-14): a white card on the navy
       ground, hanging from a lanyard in the logo's blue. A card is a card — its own colours
       never follow the phone's theme; the ground alone does. */
    --brand:#00a7e1; --brand-ink:#0b86b8; --brand-glow:rgba(0,167,225,.15);   /* Crawfurd's logo blue (sampled from logo.png); its darker self for small text on white; the focus halo */
    --door-ground:#193150; --on-ground:#ffffff; --on-ground-soft:rgba(255,255,255,.1);
    --badge:#ffffff; --badge-ink:#193150; --badge-muted:#4f5866; --badge-field:#f0f2f5; --badge-line:#e1ded9;
    --badge-danger:#b3432b; --badge-danger-soft:#fbe7e1; --badge-shadow:rgba(0,0,0,.4);
    --clip:#aeb7c4; --clip-shade:rgba(0,0,0,.12);
}
/* Dark: when the phone says so unless the person chose Light, and whenever
   the person chose Dark (Me → Settings → Appearance, a cookie, 2026-09-22).
   The same values twice — the two selectors cannot share one block. */
@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) {
        --bg:#0e1726; --ground:#0e1726; --card:#17223a; --lift:#22395e;
        --ink:#eef2f8; --muted:#aeb8c7; --muted-2:#8e99ab; --line:#263248; --line-soft:#263248;
        --chevron:#8e99ab; --tab-off:#8e99ab; --tabbar:#17223a; --tab-on:#22395e;
        --accent:#9dd0ed; --on-accent:#0b1e2e;
        --danger:#ff8a80; --on-danger:#2a0f08; --danger-soft:#3b1b13;
        --amber-ink:#f2c46b; --overdue:#ff0f0f; --danger-btn:#c8483e; --on-danger-btn:#ffffff;
        --ph:#f4a582;
        --sky-night:#1b2f55; --sky-day:#3a2442; --sky-off:#1c2a40; --sky-none:#2a2620;
        --hero-ink:#eef2f8; --hero-ink-night:#ffffff; --ring-today:rgba(238,242,248,.55);
        --sc-steam:#ffffff; --sc-ripple:#ffffff; --sc-white:#ffffff; --sc-skyline:#2b416a;
        --sc-snow:#ffffff; --sc-navyish:#ffffff; --sc-rays:0.12;
        --tile-amber:#3a311b; --tile-blue:#1f2e47; --tile-pink:#35213f; --tile-dash:#3a4760;
        --glyph-amber:#8a7432; --glyph-pink:#8a5a93; --glyph-grey:#2a3650; --glyph-dash:#33405a; --glyph-cloud:rgba(74,98,134,.9);
        --dot-empty:#8e99ab; --dot-on:#eef2f8; --on-dot:#0e1726;
        --navy-btn:#22395e; --on-navy:#ffffff; --soft-btn:#22304a;
        --positive:#6fcf97; --positive-soft:#16302a;
        --track:#0a111e; --field:#0e1726; --field-edge:#263248;
        --chip-blue:#1f2e47; --quote:#0e1726; --quote-amber:rgba(255,255,255,.08); --meta-amber:#d9c38a;
        --danger-soft:#3b1e21;
        --card-shadow:none; --row-shadow:none;
        --me-sky:#22395e; --mb-card:#17223a; --mb-face:#1f2e47; --mb-pill:#0e1726;
        --rec:#3a311b; --rec-meta:#d9c38a; --rec-dash:#8c7a45; --rec-line:rgba(217,195,138,.16);
        --sheet-shadow:rgba(0,0,0,.55);
        /* a shift cell: the Excel hue at 12 points more lightness than before (Haoming,
           2026-10-23 — the deep tones sank into the card), the Excel colour as its ink */
        --am:#763176; --am-ink:var(--fill-nurse-day);
        --pm:#7f641e; --pm-ink:var(--fill-nurse-night);
        --hca-am:#1d7777; --hca-am-ink:var(--fill-hca-day);
        --hca-pm:#317531; --hca-pm-ink:var(--fill-hca-night);
        --am-soft:var(--fill-nurse-day); --pm-soft:var(--fill-nurse-night); --hca-am-soft:var(--fill-hca-day); --hca-pm-soft:var(--fill-hca-night);   /* the ticked tile is the Excel colour itself, bright on the dark card */
        --rest:#1c1c1e; --rest-ink:#a8a39b;
        --layer-1:#1f2c47; --layer-2:#18233a;
        --closed-card:transparent; --closed-halo:#000000;
        --done:#49d149; --on-done:#0b1e2e;
        --strip-plain:#22304a;
        --shade:#2a2826; --band:#1c2c3d; --scrim:rgba(0,0,0,.6);
        --door-ground:#0b1620;
    }
}
:root[data-theme="dark"] {
    --bg:#0e1726; --ground:#0e1726; --card:#17223a; --lift:#22395e;
    --ink:#eef2f8; --muted:#aeb8c7; --muted-2:#8e99ab; --line:#263248; --line-soft:#263248;
    --chevron:#8e99ab; --tab-off:#8e99ab; --tabbar:#17223a; --tab-on:#22395e;
    --accent:#9dd0ed; --on-accent:#0b1e2e;
    --danger:#ff8a80; --on-danger:#2a0f08; --danger-soft:#3b1b13;
    --amber-ink:#f2c46b; --overdue:#ff0f0f; --danger-btn:#c8483e; --on-danger-btn:#ffffff;
    --ph:#f4a582;
    --sky-night:#1b2f55; --sky-day:#3a2442; --sky-off:#1c2a40; --sky-none:#2a2620;
    --hero-ink:#eef2f8; --hero-ink-night:#ffffff; --ring-today:rgba(238,242,248,.55);
    --sc-steam:#ffffff; --sc-ripple:#ffffff; --sc-white:#ffffff; --sc-skyline:#2b416a;
    --sc-snow:#ffffff; --sc-navyish:#ffffff; --sc-rays:0.12;
    --tile-amber:#3a311b; --tile-blue:#1f2e47; --tile-pink:#35213f; --tile-dash:#3a4760;
    --glyph-amber:#8a7432; --glyph-pink:#8a5a93; --glyph-grey:#2a3650; --glyph-dash:#33405a; --glyph-cloud:rgba(74,98,134,.9);
    --dot-empty:#8e99ab; --dot-on:#eef2f8; --on-dot:#0e1726;
    --navy-btn:#22395e; --on-navy:#ffffff; --soft-btn:#22304a;
    --positive:#6fcf97; --positive-soft:#16302a;
    --track:#0a111e; --field:#0e1726; --field-edge:#263248;
    --chip-blue:#1f2e47; --quote:#0e1726; --quote-amber:rgba(255,255,255,.08); --meta-amber:#d9c38a;
    --danger-soft:#3b1e21;
    --card-shadow:none; --row-shadow:none;
    --me-sky:#22395e; --mb-card:#17223a; --mb-face:#1f2e47; --mb-pill:#0e1726;
    --rec:#3a311b; --rec-meta:#d9c38a; --rec-dash:#8c7a45; --rec-line:rgba(217,195,138,.16);
    --sheet-shadow:rgba(0,0,0,.55);
    --am:#763176; --am-ink:var(--fill-nurse-day);
    --pm:#7f641e; --pm-ink:var(--fill-nurse-night);
    --hca-am:#1d7777; --hca-am-ink:var(--fill-hca-day);
    --hca-pm:#317531; --hca-pm-ink:var(--fill-hca-night);
        --am-soft:var(--fill-nurse-day); --pm-soft:var(--fill-nurse-night); --hca-am-soft:var(--fill-hca-day); --hca-pm-soft:var(--fill-hca-night);   /* the ticked tile is the Excel colour itself, bright on the dark card */
    --rest:#1c1c1e; --rest-ink:#a8a39b;
    --layer-1:#1f2c47; --layer-2:#18233a;
    --closed-card:transparent; --closed-halo:#000000;
    --done:#49d149; --on-done:#0b1e2e;
    --strip-plain:#22304a;
    --shade:#2a2826; --band:#1c2c3d; --scrim:rgba(0,0,0,.6);
    --door-ground:#0b1620;
}

/* ---------------------------------------------------------------------------
   Motion foundation (2026-10-05): the easings and keyframes every screen
   shares, used by the Rest days screen first — the others join one by one.

   The HTMX rule. An element that changes STATE across a swap keeps a stable
   id and changes state through classes: htmx settles such an element with
   its old attributes first and its new ones a moment later, so a CSS
   transition runs between them. An element that APPEARS for the first time
   uses a keyframe animation. And an entrance keyframe rides only on a class
   a full page render sets, never on a fragment: the Rest days block
   replaces itself every 45 s, and a refresh that changes nothing must look
   like nothing. Only opacity, transform, filter and max-height ever move —
   never width, top or margin. Colours stay in the paint chart above.
   --------------------------------------------------------------------------- */
:root {
    --ease-out:cubic-bezier(.2,.8,.2,1);              /* arrives fast, lands soft */
    --ease-spring:cubic-bezier(.34,1.56,.64,1);        /* overshoots and settles — judged per use (springy pops were cut from Month's intro) */
    --ease-spring-soft:cubic-bezier(.34,1.3,.64,1);    /* a smaller overshoot */
}
@keyframes rise-in  { from { opacity:0; transform:translateY(var(--rise, 14px)); } to { opacity:1; transform:none; } }
@keyframes fade-in  { from { opacity:0; } to { opacity:1; } }
@keyframes chip-in  { from { opacity:0; transform:scale(.55); } to { opacity:1; transform:none; } }
@keyframes cell-in  { from { opacity:0; transform:scale(.8); } to { opacity:1; transform:none; } }
@keyframes label-in { from { opacity:0; transform:translateY(5px); } to { opacity:1; transform:none; } }
@keyframes dot-pop  { 0% { transform:scale(0); } 60% { transform:scale(1.5); } 100% { transform:scale(1); } }
@keyframes shake    { 0%, 100% { transform:translateX(0); } 20% { transform:translateX(-5px); } 40% { transform:translateX(5px); }
                      60% { transform:translateX(-3px); } 80% { transform:translateX(3px); } }
@keyframes bump     { 0%, 100% { transform:none; } 35% { transform:translateY(-6px) scale(1.12); } }
@keyframes nudge    { 0%, 100% { transform:none; } 50% { transform:translateX(5px); } }
@keyframes turn     { from { transform:rotate(0); } to { transform:rotate(360deg); } }      /* the banner's clock hands, once round */
@keyframes slide-in { from { opacity:0; transform:translateX(var(--from, 36px)); } to { opacity:1; transform:none; } }   /* a month arriving from the side */
@keyframes alert-in   { from { opacity:0; transform:scale(1.08); } to { opacity:1; transform:none; } }   /* an alert settling in, Apple's */
@keyframes label-out  { to { opacity:0; transform:translateY(-8px); } }                  /* a button's old words, lifting away */
@keyframes label-rise { from { opacity:0; transform:translateY(8px); } to { opacity:1; transform:none; } }   /* its new words, rising in */
@keyframes band-sweep { from { transform:scaleX(0); } to { transform:none; } }   /* Claimed time's band, filling left to right */
@keyframes drop     { from { transform:translateY(var(--drop, -2.5px)); } to { transform:none; } }   /* the lock's shackle, into place */
/* a ring that draws itself round: a registered angle the browser can transition, used as
   a conic mask's edge (a browser without @property shows the finished ring at once) */
@property --sweep { syntax:"<angle>"; inherits:false; initial-value:0deg; }
/* the lanyard's turn, an angle the strap transitions and its slices read (the sign-in's badge) */
@property --turn { syntax:"<angle>"; inherits:true; initial-value:0deg; }
/* Motion off (the phone's own setting), on every screen that has joined (`moves`,
   set by the base page on the title — Rest days, Services): every animation and
   transition collapses to 1 ms with no delay, so the final state shows at once —
   1 ms rather than none, so an animation still ends and a script waiting for that
   end still hears it. The done pill's hold is the one delay kept: it is how long
   the word stays, not a motion. */
@media (prefers-reduced-motion: reduce) {
    .moves *, .moves *::before, .moves *::after {
        animation-duration:1ms !important; animation-delay:0ms !important;
        transition-duration:1ms !important; transition-delay:0ms !important;
    }
    .moves .send.done, .moves #claim-send .primary.done { animation-delay:var(--done-for) !important; }
    .moves .entry-note.fleeting { animation-delay:var(--show-for) !important; }   /* the three seconds are how long the line stays, not a motion */
}

/* An HCA's colours: anything wearing `hca` — a cell, a legend, the day sheet,
   the extras block — reads the HCA pair through the same am/pm names, so no
   rule below needs an HCA twin (and none can be forgotten: the extras
   circles showed an HCA the nurse colours until 2026-10-01). */
.hca {
    --am:var(--hca-am); --am-ink:var(--hca-am-ink); --am-fill:var(--fill-hca-day); --am-soft:var(--hca-am-soft);
    --pm:var(--hca-pm); --pm-ink:var(--hca-pm-ink); --pm-fill:var(--fill-hca-night); --pm-soft:var(--hca-pm-soft);
}

* { box-sizing:border-box; }
html { -webkit-text-size-adjust:100%; }
body {
    margin:0 auto; max-width:480px; min-height:100dvh;
    background:var(--bg); color:var(--ink);
    font:400 16px/1.4 var(--sans);
    -webkit-font-smoothing:antialiased;
    /* a tap is a tap (Haoming, 2026-10-14): no double-tap-to-zoom anywhere in
       the app and no 300 ms wait for a second tap — pinch-to-zoom stays, so
       the type can still be made bigger (never user-scalable=no, which
       Safari ignores and accessibility forbids) */
    touch-action:manipulation;
}

/* One screen: 24 px gutters, room at the foot for the tab bar. */
.screen {
    padding:calc(40px + env(safe-area-inset-top)) 24px calc(118px + env(safe-area-inset-bottom));   /* the foot clears the floating tab bar */
}

/* --- The sign-in: the badge is the login (Haoming's reference D4e, 2026-10-14) ---
   One staff badge on a lanyard in the logo's blue, hanging on the navy
   ground; three sides — the email, the code, Need access? — and the badge
   turns on its lanyard between them (`data-side` on the stage; the script
   in signin.html moves it). The badge is its own object: the page's names
   for ink, muted, the field grey, the accent and danger are remapped on
   the face to the card's fixed palette, so the entry, the boxes, the pill
   and the lines keep their rules below and never follow the dark theme.
   Its controls are squarer than the page's pills — 54 px, 14 px corners —
   the card's own geometry. The picture (`.screen.door`) is the whole
   screen: no gutters, no tab bar, the ground on the page itself. */
html:has(.screen.door), body:has(.screen.door) { background:var(--door-ground); }
.screen.door { padding:0; }
.stage { --badge-w:min(342px, calc(100vw - 48px)); --flip:750ms;    /* one turn, badge and strap alike */
         position:relative; height:100dvh; min-height:640px;    /* a fixed height, so the strap (not the page) takes the spare room; a very short screen scrolls */
         display:flex; flex-direction:column; align-items:center; padding-bottom:env(safe-area-inset-bottom);
         color:var(--on-ground); }
/* the back arrow, top left on the code and help sides */
.door-back { position:absolute; top:calc(20px + env(safe-area-inset-top)); left:16px; z-index:3; display:none; align-items:center; justify-content:center;
             width:44px; height:44px; border-radius:50%; background:var(--on-ground-soft); color:var(--on-ground); }
.door-back svg { width:20px; height:20px; }
#door[data-side="code"] .door-back[data-for="code"], #door[data-side="help"] .door-back[data-for="help"] {
    display:flex; --arrow-in:250ms; animation:fade-in var(--arrow-in) ease-out both; }
/* the lanyard drops in on a load (1.1 s, a swing and a settle) and hangs still after */
.lanyard { flex:1; min-height:0; width:100%; display:flex; flex-direction:column; align-items:center; transform-origin:50% 0;
           --drop:1100ms; animation:badge-drop var(--drop) cubic-bezier(.22,1,.36,1) both; }
@keyframes badge-drop {
    0%   { transform:translateY(-160px) rotate(-4deg); opacity:0; }
    45%  { opacity:1; }
    60%  { transform:translateY(12px) rotate(2deg); }
    78%  { transform:translateY(-5px) rotate(-1deg); }
    92%  { transform:translateY(2px) rotate(.4deg); }
    100% { transform:none; }
}
/* The strap twists with the badge (Haoming, 2026-10-14): forty slices, each turned a
   little more than the one above — flat at the neck, right round at the clip — so one
   ribbon turns over with the card and settles after it (`--twist`, a fifth slower than
   the badge's turn, the same spring). The turn is one registered angle the strap
   transitions; each slice reads its own angle from it, and its width is that angle's
   cosine — negative past a quarter turn, which is the back of the ribbon, the lettering
   mirrored. A slice is cut to a trapezoid whose top and bottom match its neighbours'
   widths (the wider end sets the scale, the narrower is clipped to), so the ribbon's
   edge is one line, never a staircase (Haoming's catch, 2026-10-14). The lettering is
   one text, drawn on every slice from that slice's own offset, so the slices read as one
   strap. A browser without the maths functions shows the strap flat. */
.strap { --n:40; --turn:0deg; --twist:900ms; flex:1; min-height:72px; width:36px; display:flex; flex-direction:column;
         margin-top:-24px;   /* 24 px above the screen, so the lanyard's tug never shows the strap's end (2026-10-15) */
         transition:--turn var(--twist) cubic-bezier(.3,1.25,.5,1); }
.twist { position:relative; flex:1; overflow:hidden; background:var(--brand);
         --a:calc(var(--turn) * var(--i) / (var(--n) - 1));            /* the angle at this slice's top */
         --b:calc(var(--turn) * (var(--i) + 1) / (var(--n) - 1));      /* and at its foot */
         --wt:abs(cos(var(--a))); --wb:abs(cos(var(--b))); --w:max(var(--wt), var(--wb));
         transform:scaleX(calc(sign(cos((var(--a) + var(--b)) / 2)) * var(--w)));
         clip-path:polygon(calc(50% - 50% * var(--wt) / var(--w)) 0, calc(50% + 50% * var(--wt) / var(--w)) 0,
                           calc(50% + 50% * var(--wb) / var(--w)) 100%, calc(50% - 50% * var(--wb) / var(--w)) 100%); }
/* each slice laps two pixels over the one above (`--lap`): turned, every slice is its own
   layer with soft edges, and where two soft edges met the ground showed through as a
   hairline (Haoming, 2026-10-14); the lettering's offset allows for the lap, so it stays
   one continuous line across the joins */
.strap { --lap:2px; }
.twist + .twist { margin-top:calc(-1 * var(--lap)); }
.twist span { position:absolute; left:50%; top:calc(var(--i) * (var(--lap) - 100%)); transform:translateX(-50%);
              writing-mode:vertical-rl; white-space:nowrap; padding-top:6px; font:700 9px/1 var(--sans); letter-spacing:.32em; color:var(--badge-ink); }
#door[data-side="code"] .strap, #door[data-side="help"] .strap { --turn:180deg; }
/* the clip reaches through the slot: its foot sits a few px into the hole (Haoming, 2026-10-14) */
.clip { position:relative; z-index:2; width:28px; height:30px; margin-top:-6px; border-radius:6px; background:var(--clip);
        box-shadow:inset 0 -3px 0 var(--clip-shade); }
/* the badge: two faces in one grid cell, so both share one height; it turns
   on its top edge, the face turned away hidden */
.badge-wrap { width:var(--badge-w); margin-top:-19px; perspective:1400px; }
.badge { display:grid; grid-template-rows:minmax(480px, auto); transform-style:preserve-3d; transform-origin:50% 0;
         transition:transform var(--flip) cubic-bezier(.3,1.25,.5,1); }
#door[data-side="code"] .badge, #door[data-side="help"] .badge { transform:rotateY(180deg); }
.face { position:relative; grid-area:1 / 1; display:flex; flex-direction:column; align-items:center; overflow:hidden;
        border-radius:26px; background:var(--badge); box-shadow:0 30px 70px var(--badge-shadow);
        -webkit-backface-visibility:hidden; backface-visibility:hidden; }
.face.rear { transform:rotateY(180deg); }     /* `rear`, not `back` — the Back link's class */
/* the remap: inside the card, and on the dev door's card, the page's names mean the card's colours */
.face, .door-dev {
    --bg:var(--badge); --ink:var(--badge-ink); --muted:var(--badge-muted); --line:var(--badge-line); --rest:var(--badge-field);
    --accent:var(--badge-ink); --on-accent:var(--badge); --danger:var(--badge-danger); --danger-soft:var(--badge-danger-soft);
    color:var(--ink);
}
/* the back holds two panels and shows one: the code, or Need access? (`badge-band`, not `band` — Claimed time's) */
.panel { display:contents; }
.panel[hidden], #door[data-back="help"] #panel-code, #door[data-back="code"] #panel-help { display:none; }
.badge-band { width:100%; height:96px; padding-top:16px; background:var(--brand); color:var(--badge-ink);
        display:flex; flex-direction:column; align-items:center; gap:12px; }
.slot { width:44px; height:8px; border-radius:4px; background:var(--badge-ink); }
/* the hospital's logo on the band, in navy (Haoming, 2026-10-14): the logo file is the
   mask and the ink is the colour, so the mark keeps its shape — its own blue would
   vanish on the band */
.badge-logo { display:block; width:150px; height:37px; background:var(--badge-ink);
              -webkit-mask:url(/portal/static/logo.png) center / contain no-repeat; mask:url(/portal/static/logo.png) center / contain no-repeat; }
.band-label { margin-top:2px; font:700 12px/1 var(--sans); letter-spacing:.22em; }
.strip { width:100%; height:8px; background:var(--brand); }
.spacer { flex:1; }
.titles { display:flex; flex-direction:column; align-items:center; gap:4px; padding:28px 24px 0; text-align:center; }
#panel-code .titles { padding-top:34px; }   /* Verify code sits a touch lower (Haoming, 2026-10-14) */
.badge-title { margin:0; font:700 24px/1.2 var(--sans); letter-spacing:-.015em; }
.badge-sub { font-size:13px; color:var(--muted); }
.badge-line { margin:6px 0 0; font-size:14px; line-height:1.45; color:var(--muted); text-wrap:pretty; }
.titles.help { padding:28px 32px 0; gap:14px; }
.titles.help .badge-line { margin:0; font-size:15px; line-height:1.55; }
/* Need access? flies up from the link into its place (the script, Web Animations), then the line rises in */
#help-title { --fly:960ms; --fly-wait:120ms; }
#help-body.arrive { --body-in:400ms; --body-wait:650ms; --rise:6px; animation:rise-in var(--body-in) ease-out var(--body-wait) both; }
/* the greeting after the right code: home for a beat, then on */
.face.hello { --hello-for:600ms; }
/* the forms on the card (the blocks the answers swap are full width: the face centres its children) */
#entry, #code-entry { width:100%; }
.face .entry-form { width:100%; margin:0; padding:0 24px; display:flex; flex-direction:column; gap:12px; }   /* no padding of its own: the spacers either side are equal, so the gaps are */
.field-label { font:700 13px/1.3 var(--sans); margin-bottom:-4px; }
.entry { display:block; width:100%; min-height:54px; padding:0 18px; border:0; border-radius:14px;
         background:var(--rest); color:var(--ink); font:inherit; font-size:16px; outline:none;
         -webkit-appearance:none; appearance:none; }
.entry::placeholder { color:var(--muted); }
.entry:focus { background:var(--bg); box-shadow:0 0 0 2px var(--brand), 0 0 0 6px var(--brand-glow); }
.face .primary { margin-top:4px; min-height:54px; border-radius:14px; }
/* The Email pill drops into Continue (Haoming's reference c-roster-email-drop.html,
   2026-10-15): a solid navy pill — Continue's own fill, white word — lies over the
   field's slot; the label, field and Continue beneath keep their room but not their ink
   until the form is `open`, so nothing else moves. The fall, the unroll, the word change
   and the lanyard's tug are the page's script's (Web Animations, the reference's
   timings); the stylesheet holds the two states. */
/* The pill and the field share one grid cell, both in flow — the pill never positioned or
   stacked: Safari gives a positioned, stacked child of a turning face a layer of its own
   and drew it through the help side, mirrored, as the badge turned (Haoming's phone,
   2026-10-15). In flow, it flattens into the face like the title. */
.slot-email { display:grid; }
.slot-email > * { grid-area:1 / 1; }
.email-btn { display:grid; place-items:center; width:100%; min-height:54px; border:0; border-radius:27px;
             background:var(--accent); color:var(--on-accent); font:700 17px/1 var(--sans); cursor:pointer; }
.email-btn > span { grid-area:1 / 1; }
.email-btn:focus { outline:none; }
.email-btn:focus-visible { outline:3px solid var(--brand); outline-offset:3px; }   /* a keyboard's ring, in the badge's blue */
.email-btn .alt { opacity:0; }
.email-form:not(.open) .field-label, .email-form:not(.open) .entry, .email-form:not(.open) .primary, .email-form:not(.open) .entry-note { opacity:0; }
.email-form:not(.open) .entry, .email-form:not(.open) .primary, .email-form:not(.open) .entry-note { pointer-events:none; }
.email-form.open .email-btn { display:none; }
.face .helper.fine { margin:12px 0 0; padding:0 24px; text-align:center; }
/* while the answer is on its way: the button's words give way to a spinner and what is
   happening (htmx's request class on the form — never a timer); on the code side the boxes
   dim and a line says Verifying… */
.spinner { flex:none; width:18px; height:18px; border-radius:50%; border:2.5px solid currentColor; border-top-color:transparent; opacity:.9;
           --spin:800ms; animation:turn var(--spin) linear infinite; }
.btn-busy { display:none; align-items:center; gap:10px; }
.entry-form.htmx-request .btn-words { display:none; }
.entry-form.htmx-request .btn-busy { display:inline-flex; }
.entry-form.htmx-request .primary { cursor:progress; }
.verifying { display:none; align-items:center; justify-content:center; gap:8px; margin:0; font-size:14px; color:var(--muted); }
.code-form.htmx-request .verifying { display:flex; }
.code-form.htmx-request .otp { opacity:.5; }
.code-form.htmx-request .entry-note { display:none; }
/* the code as six boxes (2026-10-05): the real field lies over them, out of
   sight but focusable; a box lights where the next digit goes */
.otp { position:relative; display:grid; grid-template-columns:repeat(6, minmax(0, 1fr)); gap:8px; }
.otp-input { position:absolute; inset:0; width:100%; height:100%; opacity:0; font-size:16px; cursor:text; }
.otp-box { display:flex; align-items:center; justify-content:center; height:56px; border-radius:12px;
           background:var(--rest); color:var(--ink); font:600 24px/1 var(--sans); font-variant-numeric:tabular-nums;
           --calm:400ms; transition:background-color var(--calm) ease-out, box-shadow var(--calm) ease-out; }
.otp-box.active { background:var(--bg); box-shadow:0 0 0 2px var(--brand), 0 0 0 6px var(--brand-glow); }
.otp.wrong .otp-box { background:var(--danger-soft); box-shadow:inset 0 0 0 2px var(--danger); }
.otp.wrong { --shake:380ms; --shake-wait:250ms; --red-for:2000ms;
             animation:entry-shake var(--shake) ease-in-out var(--shake-wait) 1; }
/* Resend as a countdown under the boxes: "Didn't get it? Resend in 0:30", then "Resend code" */
.resend-row { display:flex; justify-content:center; align-items:center; gap:4px; margin:0; padding:0 24px; font-size:13px; color:var(--muted); }
.resend { min-height:44px; padding:0 6px; font-size:13px; color:var(--brand-ink); font-variant-numeric:tabular-nums; }
.resend:disabled { color:var(--muted); cursor:default; }
/* the line under Verify code takes turns after half a minute */
.code-hint { --hint-after:30000ms; --hint-every:10000ms; --hint-fade:300ms; transition:opacity var(--hint-fade) ease-in-out; }
.code-hint.fading { opacity:0; }
/* a refused answer (Haoming, 2026-10-02): the field turns light red, ringed
   in red, and shakes its head once — the lock screen's "no". It waits for
   the page's cross-fade to bring it in, stays red for two seconds, then
   fades back to plain (Haoming, the same day) — or at once if the person
   types first. The line under it stays. Under reduced motion: red, no
   shake, no fade. */
.entry { --calm:400ms; transition:background-color var(--calm) ease-out, box-shadow var(--calm) ease-out; }
.entry.wrong { background:var(--danger-soft); box-shadow:inset 0 0 0 2px var(--danger);
               --shake:380ms; --shake-wait:250ms;
               --red-for:2000ms;   /* how long it stays red before fading back (the page's script reads this) */
               animation:entry-shake var(--shake) ease-in-out var(--shake-wait) 1; }
@keyframes entry-shake {
    0%, 100% { transform:translateX(0); }
    20% { transform:translateX(-8px); } 40% { transform:translateX(7px); }
    60% { transform:translateX(-5px); } 80% { transform:translateX(3px); }
}
@media (prefers-reduced-motion: reduce) {
    .entry, .otp-box { transition:none; } .entry.wrong, .otp.wrong { animation:none; }
    .code-hint { --hint-fade:0ms; transition:none; }
    .moves .spinner { animation:none !important; }    /* a spinner at 1 ms would flicker: still */
}
.entry-note { margin:-2px 4px 0; font-size:14px; }
/* the cookies line stays three seconds, then fades (Haoming, 2026-10-15); its room is kept */
.entry-note.fleeting { --show-for:3000ms; --fade:400ms; animation:fade-out var(--fade) ease-out var(--show-for) forwards; pointer-events:none; }
@keyframes fade-out { to { opacity:0; } }
.centre { text-align:center; }
/* the link under the badge follows the side — Need access?, Use a different email, Log in — and
   rises in when it changes; on a load it waits for the badge to land */
.below { min-height:78px; display:flex; align-items:flex-start; justify-content:center; }
.door-link { display:none; align-items:center; min-height:44px; margin-top:14px; padding:0 12px; color:var(--on-ground);
             font:700 15px/1.2 var(--sans); text-decoration:underline; text-underline-offset:3px;
             --link-in:350ms; --link-wait:350ms; --rise:6px; }
#door[data-side="front"] .door-link[data-for="front"], #door[data-side="code"] .door-link[data-for="code"], #door[data-side="help"] .door-link[data-for="help"] {
    display:flex; animation:rise-in var(--link-in) ease-out var(--link-wait) both; }
#door.enter .door-link { --link-in:450ms; --link-wait:850ms; }
/* the dev stand-in, on a card of its own under the badge */
.door-dev { width:var(--badge-w); margin:0 auto 40px; padding:4px 24px 20px; border-radius:26px; background:var(--bg); }
.title { margin:0 0 10px; font:700 30px/1.1 var(--sans); letter-spacing:-.02em; }
.title-inbox { font-size:36px; line-height:1; letter-spacing:-.025em; }
.helper { margin:0 0 18px; font-size:16px; color:var(--muted); }
.eyebrow { margin:0 0 6px; font:600 12px/1.3 var(--sans); letter-spacing:.06em; text-transform:uppercase; color:var(--muted); }

/* Hairline rows. A row that goes somewhere wears a chevron; the accent is
   kept for text that is itself the action. */
.rows { margin-top:22px; border-top:1px solid var(--line); }
.row {
    display:flex; justify-content:space-between; align-items:baseline; gap:16px;
    width:100%; min-height:52px; padding:15px 0;
    border:0; border-bottom:1px solid var(--line); background:none;
    color:inherit; font:inherit; font-size:17px; text-align:left; cursor:pointer;
}
.row-title { font-weight:600; }
.row-value { margin-left:auto; color:var(--muted); font-size:16px; white-space:nowrap; }
.row-label { flex:none; margin:0; color:var(--muted); }
.helper.fine { margin-top:14px; font-size:14px; }
.row-go::after { content:"›"; color:var(--chevron); font-size:20px; line-height:1; }
/* a picker: one row per choice, the accent tick on the chosen one */
.row-pick::after { content:"✓"; color:var(--accent); font-size:18px; line-height:1; visibility:hidden; }
.row-pick[aria-checked="true"]::after { visibility:visible; }
/* a window's deadline, above the title: a slim strip — calm, then red for
   the last three hours */
.closes { display:flex; align-items:center; gap:8px; margin:0 0 18px; padding:10px 14px; border-radius:12px;
          background:var(--rest); color:var(--ink); font:600 14px/1.3 var(--sans); }
.closes.urgent { background:var(--danger); color:var(--on-danger); }
.closes-ico { flex:none; width:18px; height:18px; }
.back { display:inline-block; margin:-8px 0 14px -4px; padding:4px; color:var(--accent); font-size:17px; text-decoration:none; }
.back[hidden] { display:none; }
.section { margin:26px 0 6px; font:600 13px/1.3 var(--sans); letter-spacing:.05em; text-transform:uppercase; color:var(--muted); }
.row-danger { color:var(--danger); }

/* The one field: no box, a hairline that turns accent while typed in. */
.find input {
    width:100%; padding:14px 0; border:0; border-bottom:1px solid var(--line); border-radius:0;
    background:transparent; color:var(--ink); font:inherit; font-size:17px;
    outline:none; -webkit-appearance:none; appearance:none;
}
.find input::placeholder { color:var(--muted); }
.find input:focus { border-bottom-color:var(--accent); box-shadow:0 1px 0 var(--accent); }

a:focus-visible, button:focus-visible { outline:2px solid var(--accent); outline-offset:3px; border-radius:4px; }

/* The tab bar (the refresh, 2026-10-16; floating since 2026-10-26, Apple's own shape
   since iOS 26, from a reference Haoming brought): a capsule above the home indicator,
   inset from the edges, the card's colour with a hairline ring and the card's shadow so
   it lifts off the warm ground; the labels 12/600; the open tab's icon and label in a
   tinted lozenge (`--tab-on`), ink, 800, a heavier stroke */
.tabs {
    position:fixed; left:50%; bottom:calc(14px + env(safe-area-inset-bottom)); transform:translateX(-50%); z-index:10;   /* above a frosted month's overlay (z 1), under the sheets (40) */
    width:min(100% - 32px, 448px); box-sizing:border-box; display:grid; grid-auto-flow:column; grid-auto-columns:minmax(0, 1fr); gap:4px;
    padding:8px; border-radius:28px; background:var(--tabbar);
    box-shadow:0 0 0 1px var(--line-soft), var(--card-shadow);
}
.tab {
    position:relative; display:flex; flex-direction:column; align-items:center; justify-content:center; gap:4px;
    padding:6px 0; border-radius:20px; font:600 12px/1.2 var(--sans); color:var(--tab-off); text-decoration:none;
}
.tab-ico { width:24px; height:24px; stroke-width:1.8; }
.tab.on { background:var(--tab-on); color:var(--ink); font-weight:800; }
.tab.on .tab-ico { stroke-width:2.1; }
/* the open tab's lozenge as one thumb that glides between tabs (2026-10-26): the script
   places it by transform alone and takes the open tab's own tint off; without script the
   tint above stands; `still` lands it with no glide (first paint, a resize, motion off) */
.tab-thumb { position:absolute; top:8px; bottom:8px; left:0; width:var(--w, 0px); transform:translateX(var(--x, 0px));
             border-radius:20px; background:var(--tab-on); opacity:0; transition:transform 260ms var(--ease-spring-soft); }
.tabs.thumb .tab-thumb { opacity:1; }
.tabs.thumb .tab.on { background:transparent; }
.tab-thumb.still { transition:none; }
@media (prefers-reduced-motion: reduce) { .tab-thumb { transition:none; } }
/* the waiting count on the Requests tab (2026-10-16): Apple's red badge at the icon's corner */
.tab-badge { position:absolute; top:-1px; left:calc(50% + 3px); min-width:18px; height:18px; padding:0 5px; box-sizing:border-box;
             border:2px solid var(--tabbar); border-radius:11px; background:var(--danger); color:var(--on-danger); font:800 11px/14px var(--sans); text-align:center; }

/* --- Month: the shared cell rules stay; the screen's own are at the foot (2026-10-16) --- */

/* the month name left, the two arrows together on the right */
.mhead { display:flex; align-items:center; gap:10px; }
.mname { flex:1; margin:0; font:700 22px/1 var(--sans); letter-spacing:-.01em; }
.myear { font-weight:400; }
.mnavs { display:flex; margin-right:-12px; }
.mnav {
    width:44px; height:44px; display:flex; align-items:center; justify-content:center;
    font-size:26px; line-height:1; color:var(--accent); text-decoration:none;
}
.mnav.gone { visibility:hidden; }   /* the edge of the browsable year: no arrow, its place kept */
/* the tally as a legend: a dot in each cell's colour */
.legend { display:flex; flex-wrap:wrap; gap:14px; margin:6px 0 0; font-size:13px; color:var(--muted); }
.lg { display:inline-flex; align-items:center; gap:6px; }
.dot { width:8px; height:8px; border-radius:4px; background:var(--rest-ink); }
.dot.am, .dot.clinic { background:var(--am-fill); }
.dot.pm { background:var(--pm-fill); }
.dot.r, .dot.leave { background:var(--chevron); }
.msub { margin:4px 0 14px; font-size:13px; color:var(--muted); }

/* The grid sits 18 px from the screen edge (the gutter is 24), seven
   columns, 7 px apart, 50 px tall; the label is 12/700 so a code reads. */
.dow, .grid { display:grid; grid-template-columns:repeat(7, 1fr); gap:7px; margin:0 -6px; }
.dow span { text-align:center; font:600 12px/1 var(--sans); color:var(--muted); margin-bottom:8px; }
.c {
    position:relative; height:50px; border:0; border-radius:12px; padding:0;
    background:transparent; color:var(--ink); font:inherit; cursor:pointer;
    display:flex; flex-direction:column; align-items:center; justify-content:center; gap:2px;
    -webkit-touch-callout:none; user-select:none;   /* a hold is the app's, never the phone's copy menu */
}
.c .n { font:500 15px/1 var(--sans); }
.c .l { font:700 12px/1 var(--sans); letter-spacing:.01em; }
.c.am { background:var(--am); color:var(--am-ink); }
.c.pm { background:var(--pm); color:var(--pm-ink); }
.c.clinic { background:var(--am); color:var(--am-ink); }
/* a 24-hour day is AM then PM: the two fills share the cell, as Sister draws it */
.c.both { background:linear-gradient(135deg, var(--am) 50%, var(--pm) 50%); color:var(--am-ink); }
.c.r, .c.leave { background:var(--rest); color:var(--rest-ink); }
.c.leave .l { color:var(--ink); }
.c.gone { color:var(--chevron); background:repeating-linear-gradient(135deg, transparent 0 6px, var(--line) 6px 7px); }
.c.none .n { color:var(--chevron); font-weight:400; }    /* a month with no published copy: the days, quietly (2026-09-30) */
/* today is the bold number with the word under it; the tapped day wears
   the ring — never the same mark */
/* today: the bold number and a ring a hair thicker than the tapped day's (Haoming, 2026-10-06;
   the word "Today" on the cell came and went the same day) */
.c.today .n { font-weight:700; }
.c.sel { box-shadow:inset 0 0 0 1.5px var(--accent); }
.c.today { box-shadow:inset 0 0 0 2px var(--accent); }
.c.blank { pointer-events:none; }


/* --- Inbox --------------------------------------------------------------- */
.group { margin:22px 0 4px; font:700 18px/1.2 var(--sans); }
.log { list-style:none; margin:0; padding:0; }
.log-month { padding:22px 0 6px; font:700 18px/1.2 var(--sans); }
.log-item { padding:14px 0 16px; border-bottom:1px solid var(--line); }
/* the Open now rows: a bell, then the words */
.log.open .log-item, .log-item.quiet { display:flex; gap:12px; align-items:flex-start; }
.log-item.quiet .log-title { font-weight:400; }
.bell { flex:none; width:18px; height:18px; margin-top:2px; border:1.5px solid var(--muted); border-radius:9px 9px 3px 3px; position:relative; }
.bell::after { content:""; position:absolute; left:5px; bottom:-5px; width:5px; height:3px; border-radius:0 0 3px 3px; background:var(--muted); }
.log-head { display:flex; justify-content:space-between; align-items:baseline; gap:14px; }
.log-title { font-weight:600; font-size:17px; }
.log-when { flex:none; font-size:14px; color:var(--muted); }
/* the changed lines come one per line, as the mail has them */
.log-body { margin:5px 0 0; font-size:15px; color:var(--muted); white-space:pre-line; }

/* --- Services: the refreshed tiles are at the foot (2026-10-16) --- */
.req-act { margin-top:6px; }
.linkish { padding:0; border:0; background:none; color:var(--accent); font:inherit; font-size:15px; font-weight:600; cursor:pointer; }
/* the AL and CT forms: hairline rows, the phone's own pickers, one button */
.ask .row.field { cursor:default; }
.ask .row.field input {
    flex:1; min-width:0; margin-left:auto; padding:0; border:0; background:transparent;
    color:var(--ink); font:inherit; font-size:17px; text-align:right; outline:none;
    -webkit-appearance:none; appearance:none;
}
.ask .row.field input::placeholder { color:var(--chevron); }
.ask .msub { margin:10px 0 0; }
/* The phone's buttons are pills (Haoming's Login.png, 2026-10-02: "its size
   and round corners"): 56 px tall, fully rounded ends. The main one is
   solid in the accent; the second (`.secondary`) is the same shape,
   outlined. Full width in a form or a sheet (the old welcome's pair was narrower
   and centred, as in its reference). */
.primary, .secondary {
    display:flex; align-items:center; justify-content:center; width:100%; min-height:56px;
    margin-top:18px; padding:0 24px; border:0; border-radius:28px; text-align:center; text-decoration:none;
    font:600 17px/1.2 var(--sans); cursor:pointer;
}
.primary { background:var(--accent); color:var(--on-accent); }
.secondary { margin-top:12px; background:transparent; color:var(--accent); box-shadow:inset 0 0 0 2px var(--accent); }
/* what to call you: the first-run question stands alone, its Skip centred under the button */
.title.first { margin-top:24px; }
.ask .skip { display:block; margin:20px auto 0; }
/* month chips on the rest-days screen */
.chips { display:flex; gap:8px; flex-wrap:wrap; margin:0 0 18px; }
.chip { padding:7px 14px; border:1px solid var(--line); border-radius:20px; color:var(--ink); font-size:14px; text-decoration:none; }
.chip.on { background:var(--ink); color:var(--bg); border-color:var(--ink); }
.chip.off { color:var(--muted); border-style:dashed; }     /* a month that closed early */
.chip.on.off { color:var(--bg); border-style:solid; }
/* the picks grid: circles, a left rail with the week's working days */
.rest .mhead { margin-top:6px; }
.rest .count { font-weight:600; font-size:17px; }
/* a month that closed early (Haoming, 2026-10-05): the calendar stays as it
   stood — grey, dimmed and a touch out of focus (`--frost`, one number to
   tune on a phone), so the picks still read — and the word sits centred over
   it; nothing beneath answers a tap */
.rest.closed { position:relative; --frost:2px; }
/* the frost comes and goes as a transition when a month switch brings the change (sitting two) */
.rest-cal { --frost-in:520ms; --frost-wait:140ms; transition:filter var(--frost-in) var(--ease-out) var(--frost-wait); }
.rest-cal.off { filter:grayscale(1) opacity(.4) blur(var(--frost)); pointer-events:none; user-select:none; }
/* the drafted month's card, new to the page: it rises in, then the shackle drops (Haoming's flourish);
   a tap on the frosted calendar shakes it */
.closed-card.arrive { --rise:12px; --card-in:485ms; --card-at:230ms; animation:rise-in var(--card-in) var(--ease-out) var(--card-at) backwards; }
.closed-card.arrive .shackle { --shackle:520ms; --shackle-at:calc(var(--card-at) + var(--card-in) + 60ms); --drop:-2.2px; transform-box:fill-box;   /* only once the card has landed and the rest has settled; the lock sits low so the drop can be long and still clear the header line (Haoming, 2026-10-06) */   /* the lock sits low in the calendar and the drop is short, so the shackle never touches the header line (Haoming, 2026-10-05) */ animation:drop var(--shackle) var(--ease-spring-soft) var(--shackle-at) backwards; }
.closed-card.shake { animation:shake 380ms var(--ease-out); }
.rest-over { position:absolute; inset:0; z-index:1; display:flex; flex-direction:column; align-items:center; justify-content:center; padding:0 16px; text-align:center; }
/* the word on a light grey card over the white ground (Haoming, 2026-10-05); on black the card
   is nothing and a soft halo of the ground keeps the letters clear of the numbers behind them */
.closed-card { padding:22px 22px 24px; border-radius:18px; background:var(--closed-card); }
.closed-ico { width:46px; height:46px; color:var(--chevron); }   /* 15% up on 40 (Haoming, 2026-10-05: the shackle must be seen) */
.closed-title, .closed-text { text-shadow:0 0 10px var(--closed-halo), 0 0 10px var(--closed-halo), 0 0 18px var(--closed-halo); }
.closed-title { margin:14px 0 6px; font:700 20px/1.2 var(--sans); letter-spacing:-.015em; }
.closed-text { margin:0; max-width:30ch; font-size:15px; color:var(--muted); }
.rest .msub { min-height:18px; margin:6px 0 14px; }
.warn { color:var(--danger); }
.dow.rail, .grid.rail { grid-template-columns:22px repeat(7, 1fr); }
.wk { align-self:center; font:600 11px/1 var(--sans); color:var(--chevron); }
.c.pick { border-radius:25px; }
.c.pick .n { font-size:16px; }
/* the solid waiting ring is a layer of its own (`.ro`), drawn round clockwise when a send
   makes the day waiting and drawn back anticlockwise, slower, when a withdrawal frees it
   (Haoming, 2026-10-05: three quarters of a second) — the same conic mask as the dashed ring below */
.c.pick .ro { position:absolute; inset:0; border-radius:25px; border:2px solid var(--accent); pointer-events:none;
              opacity:0; --sweep:0deg; --ring-out:750ms;
              -webkit-mask-image:conic-gradient(#000 var(--sweep), transparent 0); mask-image:conic-gradient(#000 var(--sweep), transparent 0);
              transition:--sweep var(--ring-out) var(--ease-out), opacity var(--ring-out) var(--ease-out); }
.c.pick.waiting .ro { opacity:1; --sweep:360deg; --ring-in:480ms;
                      transition:--sweep var(--ring-in) var(--ease-out), opacity 120ms var(--ease-out); }
.c.pick.waiting .n { font-weight:600; }
.c.pick.waiting .l { color:var(--accent); }
.c.pick.held { background:var(--accent); color:var(--on-accent); }
.c.pick.held .l { color:var(--on-accent); }
.c.pick.taken { background:var(--rest); color:var(--rest-ink); cursor:default; }
.c.pick.past { color:var(--chevron); cursor:default; }
.c.pick.today .n { text-decoration:underline; text-underline-offset:3px; }
/* a tap marks, the one button sends (the team's ask, 2026-10-05): a picked day wears a
   dashed ring until sent, a waiting day being taken back fades; the button's place is kept.
   Motion (sitting one, 2026-10-05): the dashed ring is a layer that grows in from small
   when a tap marks the day (the soft spring — the finger's) and shrinks away unmarked;
   the solid ring thickens in from nothing; a press shrinks the cell a little. */
.c.pick { transition:opacity 250ms var(--ease-out); }
/* while the finger is down the number dips, and springs back on release (the dip is quick,
   the return the soft spring: each state names its own timing) */
button.c.pick .n { --press-back:300ms; transition:transform var(--press-back) var(--ease-spring-soft); }
button.c.pick:active .n { --press:90ms; transform:scale(.92); transition:transform var(--press) var(--ease-out); }
/* the dashed ring is always there, unseen; a mark DRAWS it round clockwise from the top
   (Haoming, 2026-10-05: "the completed ring animation") — a conic mask whose edge, the
   registered angle `--sweep`, turns from 0 to 360°; an unmark draws it back the other
   way, quicker — the timing of each way sits on the state it goes to */
.c.pick::after { content:""; position:absolute; inset:0; border-radius:25px; border:2px dashed var(--accent); pointer-events:none;
                 opacity:0; --sweep:0deg; --mark-out:250ms;
                 -webkit-mask-image:conic-gradient(#000 var(--sweep), transparent 0); mask-image:conic-gradient(#000 var(--sweep), transparent 0);
                 transition:--sweep var(--mark-out) var(--ease-out), opacity var(--mark-out) var(--ease-out); }
.c.pick.free .l { display:none; }
.c.pick.free.marked { color:var(--accent); }
.c.pick.free.marked::after { opacity:1; --sweep:360deg; --mark-in:480ms; --mark-fade:120ms;
                             transition:--sweep var(--mark-in) var(--ease-out), opacity var(--mark-fade) var(--ease-out); }
.c.pick.free.marked .n { font-weight:600; }
.c.pick.free.marked .l { display:block; }
.c.pick.waiting.marked { opacity:.4; }
/* after a send: the dashed ring fades where it stands while the solid ring draws round,
   one day after another in date order (`--i` from the server, 110 ms apart) */
.c.pick.sent::after { --sweep:360deg; transition:opacity 250ms var(--ease-out); }
.c.pick.sent .ro, .c.pick.sent::after { --stagger:110ms; transition-delay:calc(var(--i, 0) * var(--stagger)); }
/* the counter bumps on a mark, shakes on a refused fifth; at 4 of 4 a tick beside it */
#rest-count { display:inline-block; }
#rest-count.bump { animation:bump 360ms var(--ease-spring-soft); }
#rest-count.shake, .c.pick.shake { animation:shake 380ms var(--ease-out); }
.full-tick { width:16px; height:16px; margin-left:4px; vertical-align:-2px; color:var(--accent); opacity:0; transform:scale(.4); }
.rest.full .full-tick { opacity:1; transform:none; --tick-in:300ms; transition:transform var(--tick-in) var(--ease-spring-soft), opacity 200ms var(--ease-out); }
/* a refusal rises into the caption's place and stays until the next mark (no timed fade:
   under motion-off a timed word would never be read) */
.rest .msub.say { animation:label-in 260ms var(--ease-out); }
.send-slot { min-height:74px; }
/* the pill slides in from below when a mark makes it needed (Haoming, 2026-10-05) */
.send { --button-in:480ms; --button-fade:200ms;
        transition:transform var(--button-in) var(--ease-spring-soft), opacity var(--button-fade) var(--ease-out), visibility var(--button-fade); }
.send.idle { opacity:0; visibility:hidden; transform:translateY(24px); }
/* the done moment (Haoming, 2026-10-05): back from a send, the pill is green with a tick and
   the word for a second and a half (`--done-for`), then slides down and away (`--done-out`);
   the page's script makes it the plain button again when the slide ends, or at once on the next tap */
.send.done { --done-for:1500ms; --done-out:400ms; animation:send-done var(--done-out) ease-out var(--done-for) forwards; }
.send.done .primary { background:var(--done); color:var(--on-done); gap:8px; pointer-events:none; }
.send.done .tick { width:22px; height:22px; }
/* Claimed time's done moment, on the button itself (its wrapper keeps an id for the slide-up) */
/* the change-over: the old words lift and fade (`label-out`), the tick and "Requested" rise in
   (`label-rise`), and the green comes up as a layer under them (opacity, not a colour fade) —
   all in `--swap-in`; then the hold and the slide down, as on Rest days */
#claim-send .primary.done { --done-for:1500ms; --done-out:400ms; --swap-in:250ms; position:relative; overflow:hidden;
                            background:var(--accent); pointer-events:none;
                            animation:send-done var(--done-out) ease-out var(--done-for) forwards; }
#claim-send .primary.done::before { content:""; position:absolute; inset:0; border-radius:inherit; background:var(--done);
                                    animation:fade-in var(--swap-in) var(--ease-out) backwards; }
#claim-send .primary.done .lbl { position:relative; display:inline-flex; align-items:center; gap:8px; }
#claim-send .primary.done .lbl.was { position:absolute; inset:0; justify-content:center; color:var(--on-accent);
                                     animation:label-out var(--swap-in) var(--ease-out) forwards; }
#claim-send .primary.done .lbl.now { color:var(--on-done); animation:label-rise var(--swap-in) var(--ease-out) backwards; }
#claim-send .primary.done .tick { width:22px; height:22px; }
/* The entrance (motion, sitting one, 2026-10-05; shared by the four function screens
   since 2026-10-06): on a real page load only. `enter` sits on the page wrapper
   (`.page`), never on an element with an id, and the base page's script strips it the
   moment any swap begins — so a 45 s refresh and a send never replay it. Banner, title, helper, chips, month header, weekday letters, the rail row by
   row, the cells as a diagonal wave (row plus column, 12 ms apart), the legend — done
   in about 700 ms; the clock hands turn once round while the rest lands (Haoming's
   flourish, kept knowingly). `backwards`, so the finished look is the natural one. */
.page.enter {
    --in:260ms; --in-fade:240ms;
    --in-title:40ms;
    /* the title lands first; everything else begins once it has (Haoming, 2026-10-06; the
       back link alone is there at once) */
    --after:calc(var(--in-title) + var(--in));
    --in-banner:0ms; --in-help:30ms; --in-chips:60ms; --in-head:90ms;
    --in-dow:120ms; --in-rail:130ms; --in-rail-step:15ms; --in-cells:140ms; --in-step:12ms; --in-legend:260ms;
    --hands-at:40ms; --hands:900ms;
}
.page.enter .closes { animation:rise-in var(--in) var(--ease-out) calc(var(--after) + var(--in-banner)) backwards; }
.page.enter .closes-ico path { transform-box:view-box; transform-origin:12px 12px; animation:turn var(--hands) var(--ease-out) calc(var(--after) + var(--hands-at)) backwards; }
.page.enter .title { animation:rise-in var(--in) var(--ease-out) var(--in-title) backwards; }
.page.enter .helper { animation:rise-in var(--in) var(--ease-out) calc(var(--after) + var(--in-help)) backwards; }
.page.enter .chips { animation:rise-in var(--in) var(--ease-out) calc(var(--after) + var(--in-chips)) backwards; }
.page.enter .rest .mhead { animation:rise-in var(--in) var(--ease-out) calc(var(--after) + var(--in-head)) backwards; }
.page.enter .dow span { animation:fade-in var(--in-fade) var(--ease-out) calc(var(--after) + var(--in-dow)) backwards; }
.page.enter .wk { animation:fade-in var(--in-fade) var(--ease-out) calc(var(--after) + var(--in-rail) + var(--row, 0) * var(--in-rail-step)) backwards; }
.page.enter .c.pick { animation:cell-in var(--in) var(--ease-out) calc(var(--after) + var(--in-cells) + (var(--r, 0) + var(--c, 0)) * var(--in-step)) backwards; }
.page.enter .legend { animation:fade-in var(--in-fade) var(--ease-out) calc(var(--after) + var(--in-legend)) backwards; }
.page.enter .chip-on { animation:fade-in var(--in-fade) var(--ease-out) calc(var(--after) + var(--in-chips)) backwards; }
.page.enter .closed-card.arrive { --card-at:calc(var(--after) + 230ms); }
/* the request screens (Annual leave, Claimed time): the form, then the list of requests */
.page.enter .ask { --in-form:60ms; animation:rise-in var(--in) var(--ease-out) calc(var(--after) + var(--in-form)) backwards; }
.page.enter .section { --in-section:120ms; animation:rise-in var(--in) var(--ease-out) calc(var(--after) + var(--in-section)) backwards; }
.page.enter .log { --in-log:150ms; animation:rise-in var(--in) var(--ease-out) calc(var(--after) + var(--in-log)) backwards; }
/* Claimed time's range picker (Haoming's spec and "claim" reference, 2026-10-06). The grid has
   no column gap so the band runs unbroken; rows are 44 px with a 4 px gap, so a row's pitch is
   48 px. Behind the days, one layer: the taken days' pills, then the band. Each day is a button
   with a stable id holding a cap (always there; it grows in when the day starts or ends the
   range), its number and its shift dots. */
/* the switch between a day off and leaving early: Apple's segmented control */
.seg { display:grid; grid-template-columns:1fr 1fr; gap:4px; margin:0 0 18px; padding:3px; border-radius:12px; background:var(--rest); }
.seg.three { grid-template-columns:repeat(3, 1fr); }   /* Claimed time: Record · Day off · Leave early (2026-10-19) */
.seg-opt { padding:8px 0; border:0; border-radius:9px; background:transparent; color:var(--ink); font:600 15px/1.2 var(--sans); cursor:pointer; }
.seg-opt.on { background:var(--bg); box-shadow:0 1px 3px var(--sheet-shadow); cursor:default; }
/* leaving early: the usual amounts, then the minutes field */
.readback { display:grid; grid-template-columns:1fr 1fr; gap:12px; margin:4px 0 22px; }
.rb { padding:12px 16px; border-radius:16px; box-shadow:inset 0 0 0 1px var(--line); }
.rb.next { box-shadow:inset 0 0 0 2px var(--accent); }
.rb-label { display:block; font-size:14px; color:var(--muted); }
.rb-value { display:block; margin-top:4px; font:600 18px/1.2 var(--sans); }
.rb-value.empty { font-weight:500; color:var(--chevron); }
.cal-head { display:flex; align-items:center; margin:0 0 10px; }
.cal-head .mname { flex:1; }
.cal-navs { display:flex; gap:4px; }
.cal-nav { width:36px; height:36px; padding:0; border:0; background:none; color:var(--accent); font-size:26px; line-height:1; cursor:pointer; }
.cal-nav:disabled { color:var(--chevron); cursor:default; }
.cal { overflow-x:clip; }   /* a month's slide never widens the page */
.cal .dow { gap:0; margin:0; }
.cal-grid { position:relative; display:grid; grid-template-columns:repeat(7, 1fr); grid-auto-rows:44px; row-gap:4px; }
.cal-layer { position:absolute; inset:0; pointer-events:none; }
/* the week's working days beside each row (2026-11-10): Rest days' rail, in its type and grey, on annual
   leave and claimed time's day off — a column beside the grid, never in it (the band is placed in percent
   of the grid's width); its rows are the grid's own, so each number sits level with its week */
.picker .dow.rail { grid-template-columns:30px repeat(7, 1fr); }
.picker .dow .work { font:700 10px/1 var(--sans); letter-spacing:.04em; text-align:left; }
.picker .cal-rows { display:grid; grid-template-columns:30px 1fr; }
.picker .cal-rail { display:grid; grid-auto-rows:44px; row-gap:4px; }
.picker .cal-rail .wk { font:700 13px/1 var(--sans); color:var(--muted-2); font-variant-numeric:tabular-nums; }
.shade, .band { position:absolute; top:calc(var(--row) * 48px + 2px); height:40px; }
.shade { left:calc(var(--l) + 3px); width:calc(var(--w) - 6px); border-radius:20px; background:var(--shade); }
.band { left:var(--l); width:var(--w); background:var(--band); transform-origin:left center; }
.band.rl { border-radius:22px 0 0 22px; } .band.rr { border-radius:0 22px 22px 0; } .band.rl.rr { border-radius:22px; }
/* the sweep: each segment fills left to right, one after another (`--ms`, `--delay` from the server) */
.band.sweep { animation:band-sweep var(--ms) linear var(--delay) backwards; }
.cd { position:relative; z-index:1; display:grid; place-items:center; height:44px; padding:0; border:0; background:none;
      color:var(--ink); font:inherit; cursor:pointer; -webkit-tap-highlight-color:transparent;
      -webkit-touch-callout:none; user-select:none; }
.cd.blank { cursor:default; }
.cd .n { position:relative; z-index:1; font:500 17px/1 var(--sans);
         --press-back:300ms; transition:transform var(--press-back) var(--ease-spring-soft), color 200ms var(--ease-out); }
button.cd:active .n { --press:90ms; transform:scale(.92); transition:transform var(--press) var(--ease-out); }
.cd.today::before { content:""; position:absolute; left:50%; top:50%; width:40px; height:40px; margin:-20px 0 0 -20px;
                    border-radius:20px; box-shadow:inset 0 0 0 1.5px var(--accent); }
.cd.past .n, .cd.blocked:not(.taken) .n { color:var(--chevron); }
.cd.taken .n { color:var(--muted); }
.cd.blocked { cursor:default; }
.cd.shake { animation:shake 380ms var(--ease-out); }
/* the caps: small and unseen at rest; a start or an end grows with the soft spring (the finger's),
   the end waiting for the sweep to reach it (`--cap-wait`); a cap leaving shrinks with ease-out */
.cd .cap { position:absolute; left:50%; top:50%; width:40px; height:40px; margin:-20px 0 0 -20px; border-radius:20px;
           background:var(--accent); opacity:0; transform:scale(.4); --cap-out:200ms;
           transition:transform var(--cap-out) var(--ease-out), opacity var(--cap-out) var(--ease-out); }
.cd.start .cap, .cd.end .cap, .cd.pending .cap { opacity:1; transform:none; --cap-in:380ms; --cap-fade:200ms;
           transition:transform var(--cap-in) var(--ease-spring-soft) var(--cap-wait, 0ms), opacity var(--cap-fade) var(--ease-out) var(--cap-wait, 0ms); }
.cd.start .n, .cd.end .n, .cd.pending .n { color:var(--on-accent); font-weight:700; transition-delay:var(--cap-wait, 0ms); }
.cd .marks { position:absolute; z-index:1; bottom:3px; display:flex; gap:3px; }
.cd .mark { width:5px; height:5px; border-radius:3px; }
.mark.am { background:var(--am-fill); } .mark.pm { background:var(--pm-fill); }
.swatch { width:16px; height:10px; border-radius:5px; background:var(--shade); }
.claim-say { min-height:22px; margin:16px 0 0; font-weight:600; }
/* the note: a soft rounded field, no label column, growing to three lines */
.note-wrap { position:relative; margin:16px 0 0; }
.note-field { display:block; width:100%; box-sizing:border-box; min-height:50px; max-height:calc(3 * 1.4em + 28px);
              padding:14px 16px; border:0; border-radius:14px; background:var(--rest); color:var(--ink);
              font:400 16px/1.4 var(--sans); resize:none; overflow-y:auto; field-sizing:content; }
.note-field::placeholder { color:var(--muted); }
.note-field:focus { outline:none; box-shadow:inset 0 0 0 2px var(--accent); }
/* the Requests tab's late-start action and sheet (2026-11-09): the action in the
   title link's clothes; the sheet's fields in the note field's */
.rq-late-row { margin:-6px 0 14px; }
.rq-late-open { display:inline-flex; align-items:center; gap:2px; padding:0; border:0; background:none;
  color:var(--accent); font:600 15px/1.2 var(--sans); cursor:pointer; }
.rq-late-open svg { width:16px; height:16px; }
.sheet.late .sheet-count { margin:0 0 14px; }
.sheet.late { max-height:calc(100vh - 24px); overflow:auto; }   /* our month inside may outgrow a short phone */
.sheet.late .rq-who, .sheet.late .rq-min-wrap { display:block; width:100%; box-sizing:border-box;
  min-height:50px; margin:0 0 12px; padding:0 14px; border:0; border-radius:14px; background:var(--lift); color:var(--ink);
  font:500 16px/50px var(--sans); }
/* Who is typed (2026-11-10): the matches drop under the field, the Requests search's mark on the typed part */
.sheet.late .rq-who-wrap { position:relative; }
.sheet.late .rq-who::placeholder { color:var(--muted); }
.sheet.late .rq-people { display:flex; flex-direction:column; gap:2px; margin:-6px 0 12px; }
.sheet.late .rq-people:empty { display:none; }
.sheet.late .rq-person { display:block; width:100%; padding:11px 14px; border:0; border-radius:12px; background:var(--bg);
  color:var(--ink); font:500 16px/1.2 var(--sans); text-align:left; cursor:pointer; box-shadow:0 1px 3px var(--sheet-shadow); }
.sheet.late .rq-person mark { padding:0 1px; border-radius:3px; background:var(--tile-amber); color:inherit; }
/* Another day (2026-11-10): the pickers' month in the sheet, its rows a touch shorter */
.sheet.late .late-cal { margin:0 0 12px; }
.sheet.late .late-cal[hidden] { display:none; }
.sheet.late .late-readback { margin:0 0 8px; font:600 15px/1.2 var(--sans); color:var(--ink); }
.sheet.late .cal-grid { grid-auto-rows:40px; }
/* the shift dots, larger here with a hairline edge (2026-11-10: the five-pixel pink read faint on a
   white sheet — the same fill as the Month cell, a small patch of it); the 24 h legend dot two-tone */
.sheet.late .cd .mark { width:7px; height:7px; border-radius:4px; box-shadow:0 0 0 1px var(--chevron); }
.sheet.late .legend .dot { width:10px; height:10px; border-radius:5px; box-shadow:0 0 0 1px var(--chevron); }
.sheet.late .dot.d24 { background:linear-gradient(90deg, var(--am-fill) 50%, var(--pm-fill) 50%); }
.sheet.late .late-said { margin:-4px 0 12px; font:600 14px/1.35 var(--sans); color:var(--danger); }   /* a refusal, in the sheet */
.sheet.late .late-said[hidden] { display:none; }
.sheet.late .rq-min-wrap { display:flex; align-items:center; gap:8px; }
.sheet.late .rq-min-wrap span { color:var(--muted); font-size:15px; }
.sheet.late .rq-min { flex:1; min-width:0; border:0; background:none; color:var(--ink); font:600 18px/1 var(--mono); text-align:right; }
.sheet.late .rq-min:focus, .sheet.late .rq-who:focus { outline:none; box-shadow:inset 0 0 0 2px var(--accent); }
.sheet.late .seg { margin-bottom:12px; }
.sheet.late .note-wrap { margin:0 0 14px; }
.note-wrap:has(.note-count:not([hidden])) { margin-bottom:22px; }   /* room for the count under the field */
.note-count { position:absolute; right:14px; bottom:-20px; font-size:12px; color:var(--muted); font-variant-numeric:tabular-nums; }
.note-count.egg { animation:nudge 300ms var(--ease-out); }   /* full, and someone typed on */
/* the button's space on Claimed time opens only when something is picked, and closes again
   after the done moment — no empty gap kept under the note (Haoming, 2026-10-06) */
.claim-slot { min-height:0; }
#claim-send { max-height:80px; overflow:hidden; --slot:300ms;
              transition:max-height var(--slot) var(--ease-out), transform var(--button-in) var(--ease-spring-soft),
                         opacity var(--button-fade) var(--ease-out), visibility var(--button-fade); }
#claim-send.idle { max-height:0; }
#claim-send.spend { max-height:170px; }   /* the cost line or the refusal sits above the button (2026-10-19) */
/* Your requests, folded (Wallet's history behind a row; Reminders' "N Completed · Show") */
.reqs { margin:26px 0 0; border-top:1px solid var(--line); }
.reqs > summary, .reqs.empty { display:flex; align-items:center; gap:8px; padding:15px 0; list-style:none; cursor:pointer; }
.reqs.empty { cursor:default; }
.reqs > summary::-webkit-details-marker, .reqs-closed > summary::-webkit-details-marker { display:none; }
.reqs-title { font:600 17px/1.2 var(--sans); }
.reqs-count { flex:1; font-size:15px; color:var(--muted); }
.reqs .chev { width:18px; height:18px; color:var(--chevron); --turn:200ms; transition:transform var(--turn) var(--ease-out); }
.reqs[open] > summary .chev { transform:rotate(90deg); }
.reqs[open] > .reqs-body { animation:fade-in 220ms var(--ease-out); }
.reqs-none { margin:0 0 6px; font-size:15px; color:var(--muted); }
.reqs-closed > summary { padding:14px 0 6px; list-style:none; font-size:15px; color:var(--muted); cursor:pointer; }
.reqs-closed > summary .show, .reqs-closed > summary .hide { color:var(--accent); font-weight:600; }
.reqs-closed .hide, .reqs-closed[open] .show { display:none; }
.reqs-closed[open] .hide { display:inline; }
.reqs-closed[open] > .log { animation:fade-in 220ms var(--ease-out); }
/* Clear sits on the closed row, at its right, while the closed ones are shown */
.reqs-closed > summary { display:flex; justify-content:space-between; align-items:baseline; }
.clear-open { display:none; font-size:15px; }
.reqs-closed[open] .clear-open, .reqs-closed.always .clear-open, .reqs-closed.bare .clear-open { display:inline; }
/* a declined request in the open list (2026-10-15): the word in danger ink, Nursing
   Admin's line in ink under it; Clear in view without opening the closed fold */
.log-when.no { color:var(--danger); font-weight:600; }
.log-body.why { color:var(--ink); }
.reqs-closed.bare { display:flex; justify-content:flex-end; padding:14px 0 6px; }
/* the alert: centred, narrow, the question then Cancel and the red verb side by side */
dialog.alert { width:270px; padding:0; border:0; border-radius:14px; background:var(--bg); color:var(--ink);
               box-shadow:0 10px 40px var(--sheet-shadow); text-align:center; --alert-in:200ms;
               animation:alert-in var(--alert-in) var(--ease-out); }
dialog.alert::backdrop { background:var(--scrim); animation:fade-in 200ms var(--ease-out); }
.alert-title { margin:0; padding:20px 18px 18px; font:600 17px/1.3 var(--sans); }
.alert-acts { display:grid; grid-template-columns:1fr 1fr; margin:0; border-top:1px solid var(--line); }
.alert-btn { padding:13px 0; border:0; background:none; color:var(--accent); font:400 17px/1.2 var(--sans); cursor:pointer; }
.alert-btn + .alert-btn { border-left:1px solid var(--line); }
.alert-btn.danger { color:var(--danger); font-weight:600; }
.claim-say.say { animation:label-in 260ms var(--ease-out); }
/* sending: the band and the caps fade while htmx waits out the swap delay (320 ms), then the new
   request's shading fades in and the request rises into the list */
#claim-wrap.htmx-swapping .band, #claim-wrap.htmx-swapping .cap { --fade-out:320ms; opacity:0; transition:opacity var(--fade-out) var(--ease-out); }
.shade.arrive { --shade-in:420ms; animation:fade-in var(--shade-in) var(--ease-out) backwards; }
.log-item.arrive, .ct-line.arrive { animation:rise-in 360ms var(--ease-out) 120ms backwards; }
/* the entrance: the title first (the shared rules), then the read-back, the month, the days as a wave */
.page.enter .ct-bank { animation:rise-in var(--in) var(--ease-out) var(--after) backwards; }   /* Claimed time's bank, first (2026-10-19) */
.page.enter .seg { animation:rise-in var(--in) var(--ease-out) var(--after) backwards; }
.page.enter .ct-shifts { animation:rise-in var(--in) var(--ease-out) calc(var(--after) + 30ms) backwards; }
.page.enter .ct-hint { animation:fade-in var(--in-fade) var(--ease-out) calc(var(--after) + 60ms) backwards; }
.page.enter .readback { animation:rise-in var(--in) var(--ease-out) calc(var(--after) + 30ms) backwards; }
.page.enter .cal-head { animation:rise-in var(--in) var(--ease-out) calc(var(--after) + 60ms) backwards; }
/* the grey pills arrive with their days: a fade at the wave's moment for their first day */
.page.enter .shade { animation:fade-in var(--in) var(--ease-out) calc(var(--after) + var(--in-cells) + (var(--row, 0) + var(--col, 0)) * var(--in-step)) backwards; }
.page.enter .cd { animation:cell-in var(--in) var(--ease-out) calc(var(--after) + var(--in-cells) + (var(--r, 0) + var(--c, 0)) * var(--in-step)) backwards; }
.page.enter .reqs, .page.enter .note-wrap, .page.enter .waiting { animation:fade-in var(--in-fade) var(--ease-out) calc(var(--after) + var(--in-legend) + 60ms) backwards; }
.page.enter .claim-say, .page.enter .rows { animation:fade-in var(--in-fade) var(--ease-out) calc(var(--after) + var(--in-legend) + 40ms) backwards; }

/* Switching months (sitting two, 2026-10-05; every timing here 15% slower on Haoming's
   look the same day): the calendar slides in 36 px from the side it came from, with a
   fade; the slide rides on an id-less wrapper inside the block. The
   screen clips sideways overflow so the slide never widens the page. */
.rest-screen { overflow-x:clip; }
.slide.from-right { --from:36px; --slide:415ms; animation:slide-in var(--slide) var(--ease-out) backwards; }
.slide.from-left { --from:-36px; --slide:415ms; animation:slide-in var(--slide) var(--ease-out) backwards; }
/* the dark chip indicator: one element behind the chip row, placed by the page's script
   (`--x`, `--y`, `--w`) and gliding to its new chip with the soft spring; until the
   script has placed it, the `on` chip is its own dark pill, so nothing depends on it */
.chips-wrap { position:relative; }
.chip-on { position:absolute; top:0; left:0; width:var(--w, 0px); height:34px; border-radius:20px; background:var(--ink);
           transform:translate(var(--x, 0px), var(--y, 0px)); opacity:0; --glide:485ms;
           transition:transform var(--glide) var(--ease-spring-soft), width var(--glide) var(--ease-out); }
.chips-wrap.placed .chip-on { opacity:1; }
.chips-wrap.placed .chip.on { background:transparent; border-color:transparent; }
.chips-wrap .chip { position:relative; }
.chips-wrap.placed .chip.on.off { color:var(--bg); }
/* the banner and the helper fold shut on a month that closed early, and open again */
.fold { --fold:485ms; --fold-fade:300ms; max-height:120px; overflow:hidden;
        transition:max-height var(--fold) var(--ease-out), opacity var(--fold-fade) var(--ease-out), visibility 0s linear 0s; }
.fold.shut { max-height:0; opacity:0; visibility:hidden; transition:max-height var(--fold) var(--ease-out), opacity var(--fold-fade) var(--ease-out), visibility 0s linear var(--fold); }
/* the done pill leaves the way it came: down 24 px, fading as it goes (Haoming, 2026-10-05) */
@keyframes send-done { from { transform:none; opacity:1; } to { transform:translateY(24px); opacity:0; visibility:hidden; } }
/* the extras and dates screens: the day is its number with two pills under
   it, AM left and PM right (Haoming's reference 4a "Ink for yours",
   2026-10-23 — your roster in plain ink, colour only means extra; it
   replaced the half-circles of 2026-09-22, which cut the day in two and
   read as incomplete): the draft's own half in the muted ink, the other
   half a dark track that means nothing and only holds the place, so a
   night always sits right; a half asked for is a hollow pill in its
   shift's colour, approved it fills — the Excel colour on both themes, as
   the legend's dots are; a day with nothing on it has no pills; a leave
   day is the number with its code; the day's panel under */
.c.pick.x { display:grid; grid-template-columns:auto auto; column-gap:3px; row-gap:5px;
            align-content:center; justify-content:center; justify-items:center; border-radius:12px; }
/* the pills say it all here: no whole-cell fill from the rest-days grid, nor Month's cell
   fill, which reaches a rostered day through its am/pm/both class */
.c.pick.x.waiting, .c.pick.x.held, .c.pick.x.am, .c.pick.x.pm, .c.pick.x.both, .c.pick.x.leave { background:transparent; color:var(--ink); }
.c.pick.x .n { grid-column:1 / -1; font-weight:600; }
.c.pick.x .l { grid-column:1 / -1; font:600 10px/1 var(--sans); color:var(--muted); }
.c.pick.x.leave { cursor:default; }
.c.pick.x.past .n { color:var(--chevron); }
.c.pick.x.free .h, .c.pick.x.past .h { display:none; }
.c.pick.x .h.am { grid-area:2 / 1; }
.c.pick.x .h.pm { grid-area:2 / 2; }
.c.pick.x.sel { box-shadow:0 0 0 2.5px var(--ink); }   /* the tapped day while its sheet is up: Month's strong ring (2026-10-23) */
/* one pill: on the grid, in the legend and on the sheet's tile alike */
.h { display:inline-block; width:20px; height:7px; border-radius:4px; background:var(--line); }
.h.on { background:var(--muted); }
.h.am.held { background:var(--am-fill); }
.h.pm.held { background:var(--pm-fill); }
.h.am.wait { background:transparent; box-shadow:inset 0 0 0 1.5px var(--am-fill); }
.h.pm.wait { background:transparent; box-shadow:inset 0 0 0 1.5px var(--pm-fill); }
/* the tapped day's choice, inside the bottom sheet (`.sheet.ask`, 2026-10-01):
   the date, then a tile per half — an outline until ticked, then a bright
   tint of the shift's colour with navy ink and a navy tick (Haoming,
   2026-10-23: lighter than the roster's cell, a choice rather than a placed
   shift; the tick in navy because the dark theme's pale accent vanished on
   the yellow); a refused half greyed with its two words; one button under them */
.sheet.ask .sheet-count { margin:8px 0 14px; }
.ask-tiles { display:grid; grid-auto-flow:column; grid-auto-columns:1fr; gap:12px; }
.ask-tile { position:relative; display:flex; flex-direction:column; align-items:flex-start; min-height:124px;
            padding:14px; border-radius:16px; box-shadow:inset 0 0 0 1.5px var(--line); cursor:pointer;
            -webkit-tap-highlight-color:transparent; -webkit-touch-callout:none; user-select:none; }
.ask-tile input { position:absolute; opacity:0; pointer-events:none; }
.ask-tile::after { content:""; position:absolute; top:12px; right:12px; width:22px; height:22px; border-radius:11px;
                   box-shadow:inset 0 0 0 1.5px var(--chevron); font:700 13px/22px var(--sans); text-align:center; }
.ask-tile:has(input:checked) { background:var(--am-soft); color:var(--on-soft); box-shadow:none; }
.ask-tile.pm:has(input:checked) { background:var(--pm-soft); }
.ask-tile:has(input:checked)::after { content:"✓"; background:var(--on-soft); color:var(--am-soft); box-shadow:none; }
.ask-tile.pm:has(input:checked)::after { color:var(--pm-soft); }
.ask-tile:has(input:checked) .h { background:var(--on-soft); box-shadow:none; }   /* the half's pill, ink on a tile that is its colour */
.ask-tile:has(input:focus-visible) { outline:2px solid var(--accent); outline-offset:2px; }
.ask-tile.blocked { color:var(--chevron); cursor:default; }
.ask-tile.blocked::after { content:none; }
.ask-tile.approved { cursor:default; }
.ask-marks { display:flex; align-items:center; gap:10px; margin-bottom:10px; }
.ask-ico { width:26px; height:26px; }
.ask-name { font:700 19px/1.1 var(--sans); letter-spacing:-.01em; }
.ask-hours { margin-top:3px; font-size:14px; opacity:.72; }
.ask-state { margin-top:auto; padding-top:8px; font:600 13px/1.2 var(--sans); }
/* the sheet's button is not there until a tick changes something; its place is kept */
.ask-form .primary { --button-in:140ms; transition:opacity var(--button-in) ease-out; }
.ask-form .primary.idle { opacity:0; visibility:hidden; }
@media (prefers-reduced-motion: reduce) { .ask-form .primary { transition:none; } }
.ring.am { background:var(--am); border:1px solid var(--am-ink); }
.ring { width:12px; height:12px; border-radius:6px; }
.ring.waiting { box-shadow:inset 0 0 0 2px var(--accent); }
.ring.held { background:var(--accent); }

.sr { position:absolute; width:1px; height:1px; overflow:hidden; clip-path:inset(50%); white-space:nowrap; }

/* a dead link (2026-09-29): one line, the address small, one button */
.lost { text-align:center; padding:96px 0 0; }
.lost h1 { margin:0 0 8px; font:700 22px/1.2 var(--sans); letter-spacing:-.02em; }
.lost-path { margin:0 0 28px; font-size:12px; color:var(--muted); word-break:break-all; }
.lost .primary { display:inline-flex; width:auto; padding-left:32px; padding-right:32px; }

/* a public holiday (2026-09-30): a small dot in the cell's top-right corner,
   on Month, the rest-days circles and the extras circles alike; the day row
   names it */
.c.ph::before { content:""; position:absolute; top:5px; right:6px; width:5px; height:5px;
                border-radius:50%; background:var(--ph); }
.legend .dot.ph { width:5px; height:5px; background:var(--ph); }

/* the hold-to-see label (2026-09-30): the holiday's name above the cell */
.c.ph { -webkit-touch-callout:none; user-select:none; }
.peek-ph { position:absolute; transform:translate(-50%, -100%); padding:6px 10px; border-radius:8px;
           background:var(--ink); color:var(--bg); font:600 13px/1.2 var(--sans);
           white-space:nowrap; pointer-events:none; z-index:50; opacity:0;
           --peek-in:120ms; transition:opacity var(--peek-in) ease-out; }
.peek-ph.on { opacity:1; }
@media (prefers-reduced-motion: reduce) { .peek-ph { transition:none; } }

/* the day sheet (Haoming's slide.png, 2026-10-01): rises from the foot over
   the tab bar on a tap, only as tall as its rows; a grabber, the date, a
   count, then a row per fact — the hours, a dot in the cell's colour, what
   it is, the remark under it */
.sheet { position:fixed; left:50%; bottom:0; z-index:40; width:min(100%, 480px); box-sizing:border-box;
         /* it rises to two fifths of the screen whatever it holds (Haoming, 2026-10-01: blank
            below is fine), never past three quarters — longer content scrolls inside */
         min-height:40dvh; max-height:75dvh; display:flex; flex-direction:column;
         padding:8px 24px calc(26px + env(safe-area-inset-bottom)); background:var(--card);   /* a layer above the page: the card's white on the warm ground (2026-10-26) */
         border-radius:22px 22px 0 0; box-shadow:0 -10px 34px var(--sheet-shadow);
         transform:translate(-50%, 100%); --sheet-in:240ms;
         transition:transform var(--sheet-in) cubic-bezier(.2,0,0,1);
         /* it follows the finger down (2026-10-01): the browser leaves the drag to the
            page — only rows that really scroll keep their own */
         touch-action:none; }
.sheet.on { transform:translate(-50%, 0); }
.sheet[hidden] { display:none; }
.sheet.drag { transition:none; }     /* held: no easing while it follows the finger */
.sheet-grab { display:block; width:100%; height:22px; margin:0 0 6px; padding:0; border:0; background:none; cursor:pointer; }
.sheet-grab::before { content:""; display:block; width:38px; height:4px; margin:4px auto 0; border-radius:2px; background:var(--line); }
.sheet-title { margin:0; font:700 22px/1.2 var(--sans); letter-spacing:-.02em; }
.sheet-rel { font-weight:400; font-size:15px; color:var(--muted); letter-spacing:0; }
.sheet-count { margin:3px 0 10px; font-size:14px; color:var(--muted); }
.sheet-rows { flex:1; min-height:0; overflow-y:auto; overscroll-behavior:contain; }
.sheet-rows.scrolls { touch-action:pan-y; }
.sheet-row { display:flex; align-items:flex-start; gap:14px; padding:12px 0; border-top:1px solid var(--line); }
.sheet-time { flex:none; width:56px; display:flex; flex-direction:column; font-size:14px; line-height:1.4; color:var(--muted); }
.sheet-row .dot { flex:none; margin-top:6px; }
.sheet-row .dot.ph { background:var(--ph); }
.sheet-main { min-width:0; }
.sheet-what { margin:0; font-weight:600; font-size:16px; }
.sheet-info { margin:2px 0 0; font-size:14px; color:var(--muted); }
@media (prefers-reduced-motion: reduce) { .sheet { transition:none; } }

/* --- Requests: Nursing Admin's approvals (2026-10-16; Haoming's reference
   c-roster-admin-requests-A2.html, 2026-10-26; scoped to .page.rqs) -------------
   one card per ask: a strip naming the kind in its tile's tone (amber leave, blue
   rest days, pink the bank, plain the rest — one colour per kind across the phone,
   his pick over the reference's six), the name and how long it has waited, the
   span with its AM/PM chips in the Excel fills, a flag, the note in quotes, then
   Decline and Approve in the navy (his pick: the green is the stamp's alone). The
   done moment stamps the card on the answer and folds it; a card the refresh
   brings in rises into place. The refusal line and the alerts are the shared ones. */
.page.rqs .rq-lede { margin:4px 0 0; font-size:15px; color:var(--muted); }
.page.rqs .rq-lede b { color:var(--ink); }
.page.rqs .waiting .say-line { margin:12px 0 0; font-size:15px; font-weight:600; color:var(--muted); }
.page.rqs .waiting .say-line.no { color:var(--danger); }
.page.rqs .rq-sec { display:flex; align-items:baseline; justify-content:space-between; gap:10px; margin:20px 2px 6px; }
.page.rqs .rq-sec .group { margin:0; font:800 13px/1.2 var(--sans); letter-spacing:.06em; text-transform:uppercase; color:var(--muted); }
.page.rqs .rq-n { font-size:13px; color:var(--muted); font-variant-numeric:tabular-nums; }
.page.rqs .rq-list { list-style:none; margin:0; padding:0; }
.page.rqs .rq { position:relative; margin-top:10px; border-radius:18px; overflow:hidden; background:var(--card); box-shadow:var(--row-shadow);
                --strip:var(--strip-plain); --stamp:160ms; --fold:280ms; }
.page.rqs .rq.tone-amber { --strip:var(--tile-amber); }
.page.rqs .rq.tone-blue { --strip:var(--tile-blue); }
.page.rqs .rq.tone-pink { --strip:var(--tile-pink); }
.page.rqs .rq-strip { display:flex; align-items:center; gap:6px; height:26px; padding:0 14px; background:var(--strip); color:var(--ink);
                      font:800 11px/1 var(--sans); letter-spacing:.07em; text-transform:uppercase; }
.page.rqs .rq-strip svg { width:12px; height:12px; flex:none; }
.page.rqs .rq-body { position:relative; padding:14px; }
.page.rqs .rq-who { display:flex; align-items:center; gap:10px; }
.page.rqs .rq-name { min-width:0; font:700 16px/1.25 var(--sans); }
.page.rqs .rq-age { flex:none; margin-left:auto; font-size:13px; color:var(--muted); white-space:nowrap; }
.page.rqs .rq-age.old { color:var(--overdue); font-weight:600; }
.page.rqs .rq-what { display:flex; flex-wrap:wrap; align-items:center; gap:6px; margin:10px 0 0; font:600 15px/1.3 var(--sans); }
.page.rqs .rq-what .dim { color:var(--muted); font-weight:500; }
.page.rqs .rq-sub { flex-basis:100%; margin-top:-3px; font-size:14px; font-weight:500; color:var(--muted); }
/* the half's chip is the Excel fill on both themes, as the legend's dots are; an HCA's
   line wears `hca` and the chips read the HCA fills through the one remap */
.page.rqs .rq-sh { padding:2px 7px; border-radius:6px; background:var(--am-fill); color:var(--shift-ink); font:800 11px/1.4 var(--sans); }
.page.rqs .rq-sh.pm { background:var(--pm-fill); }
.page.rqs .rq-flag { display:flex; align-items:center; gap:6px; margin:4px 0 0; font:600 14px/1.3 var(--sans); color:var(--amber-ink); }
.page.rqs .rq-flag::before { content:""; width:6px; height:6px; border-radius:50%; background:var(--amber-ink); flex:none; }
.page.rqs .rq-note { margin:4px 0 0; font-size:14px; font-style:italic; color:var(--muted);
                     display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical; overflow:hidden; }
.page.rqs .rq-acts { display:flex; gap:8px; margin-top:12px; }
.page.rqs .rq-acts form { flex:1; display:flex; margin:0; }
.page.rqs .rq-ok, .page.rqs .rq-no { flex:1; height:44px; padding:0; border:0; border-radius:12px; font:700 15px/1 var(--sans); cursor:pointer; }
.page.rqs .rq-ok { background:var(--navy-btn); color:var(--on-navy); }
.page.rqs .rq-no { background:none; color:var(--ink); box-shadow:inset 0 0 0 1.5px var(--line); }
/* the tools (the reference, phase three): the search field and the sort button in a row,
   the chips scrolling sideways under the lede, Approve all's bar, and By name's head per
   person with that person's own Approve all; a card under a head drops its name row */
.page.rqs .rq-tools { display:flex; gap:8px; margin:14px 0 0; }
.page.rqs:has(.rq-empty) .rq-tools { display:none; }     /* nothing waiting: nothing to search */
.page.rqs .rq-search { flex:1; position:relative; }
.page.rqs .rq-search input { width:100%; height:44px; box-sizing:border-box; padding:0 38px; border:0; border-radius:12px;
                             background:var(--field); color:var(--ink); font:500 16px/44px var(--sans); outline:none; -webkit-appearance:none; appearance:none; }
.page.rqs .rq-search input:focus { box-shadow:inset 0 0 0 2px var(--accent); }
.page.rqs .rq-search input::placeholder { color:var(--muted-2); }
.page.rqs .rq-search input::-webkit-search-cancel-button, .page.rqs .rq-search input::-webkit-search-decoration { -webkit-appearance:none; appearance:none; }
.page.rqs .rq-search .mg { position:absolute; left:12px; top:12px; width:20px; height:20px; color:var(--muted-2); pointer-events:none; }
.page.rqs .rq-clear { position:absolute; right:8px; top:10px; display:none; place-items:center; width:24px; height:24px; padding:0; border:0; border-radius:50%; background:var(--muted-2); color:var(--bg); cursor:pointer; }
.page.rqs .rq-clear svg { width:12px; height:12px; }
.page.rqs .rq-search.has .rq-clear { display:grid; }
.page.rqs .rq-sortb { display:flex; align-items:center; gap:6px; flex:none; height:44px; padding:0 12px; border:0; border-radius:12px; background:var(--field); color:var(--ink); font:700 14px/1 var(--sans); white-space:nowrap; cursor:pointer; }
.page.rqs .rq-sortb svg { width:16px; height:16px; }
.page.rqs .rq-chips { display:flex; gap:6px; margin:12px -24px 0; padding:0 24px 2px; overflow-x:auto; scrollbar-width:none; }
.page.rqs .rq-chips::-webkit-scrollbar { display:none; }
.page.rqs .rq-chip { display:inline-flex; align-items:center; gap:6px; flex:none; padding:8px 12px; border:0; border-radius:999px; background:var(--card); color:var(--muted); font:700 14px/1.2 var(--sans); white-space:nowrap; cursor:pointer; box-shadow:var(--row-shadow); }
.page.rqs .rq-chip b { font-weight:800; opacity:.75; }
.page.rqs .rq-chip[aria-pressed="true"] { background:var(--ink); color:var(--bg); }
.page.rqs .dot { display:inline-block; flex:none; width:9px; height:9px; border-radius:3px; background:var(--strip-plain); }
.page.rqs .dot.amber { background:var(--tile-amber); }
.page.rqs .dot.blue { background:var(--tile-blue); }
.page.rqs .dot.pink { background:var(--tile-pink); }
.page.rqs .rq-chip[aria-pressed="true"] .dot.plain { background:var(--bg); opacity:.5; }
.page.rqs mark { padding:0 1px; border-radius:3px; background:var(--tile-amber); color:inherit; }
.page.rqs .rq-allbar { display:flex; align-items:center; justify-content:space-between; gap:10px; margin:16px 2px 0; }
.page.rqs .rq-none { padding:40px 10px 0; text-align:center; }
.page.rqs .rq-none .empty-title { margin:0 0 4px; font:700 18px/1.25 var(--sans); letter-spacing:-.01em; }
.page.rqs .rq-none .helper { margin:0; font-size:15px; }
.page.rqs .rq-person { display:flex; align-items:center; gap:10px; margin-top:20px; padding:12px 14px; border-radius:18px; background:var(--card); box-shadow:var(--row-shadow); }
.page.rqs .rq-ptx { flex:1; min-width:0; }
.page.rqs .rq-pname { margin:0; font:700 17px/1.25 var(--sans); }
.page.rqs .rq-psum { display:flex; flex-wrap:wrap; gap:2px 10px; margin:2px 0 0; font-size:13px; color:var(--muted); }
.page.rqs .rq-psum .pt { display:inline-flex; align-items:center; gap:5px; white-space:nowrap; }
.page.rqs .rq-psum .dot { width:8px; height:8px; }
.page.rqs .rq-pall { flex:none; height:40px; padding:0 14px; border:0; border-radius:12px; background:var(--navy-btn); color:var(--on-navy); font:800 14px/1 var(--sans); white-space:nowrap; cursor:pointer; }
.page.rqs .rq-group .rq { margin-left:10px; }
.page.rqs .rq.in .rq-what { margin-top:0; }
.page.rqs .rq.in .rq-what .rq-age { margin-left:auto; }
/* the sort sheet: the title with the shared ⓘ (its card lists what each sort does), then
   four plain rows with a radio dot; a tap chooses and closes, so there is no Done */
.sheet.sort .title-row { margin:0 0 6px; }
.sheet.sort .info-card { margin:0 0 10px; }
.sheet.sort .info-card li { display:block; }     /* one line each: the sort's name, then what it does */
.sheet.sort .info-card li b { margin-right:6px; color:var(--ink); }
.sheet.sort .rq-opts { display:flex; flex-direction:column; gap:8px; margin:6px 0 0; }
.sheet.sort .rq-opt { display:flex; align-items:center; gap:12px; width:100%; padding:13px 14px; border:0; border-radius:14px; background:var(--field); color:var(--ink); font:600 16px/1.3 var(--sans); text-align:left; cursor:pointer; }
.sheet.sort .rq-opt i { flex:none; width:20px; height:20px; border-radius:50%; box-shadow:inset 0 0 0 2px var(--muted-2); }
.sheet.sort .rq-opt[aria-checked="true"] i { box-shadow:inset 0 0 0 6px var(--ink); }
/* History (the reference, phase four): the link beside the title, the All / Approved /
   Declined switch, and the card without its buttons — the outcome as a chip at the name's
   right, the line in quotes, who and when under a hairline */
.title-row .title-link { display:inline-flex; align-items:center; gap:5px; margin-left:auto; color:var(--accent); font:600 15px/1 var(--sans); text-decoration:none; }
.title-row .title-link svg { width:18px; height:18px; }
.page.rqh .rq-lede { margin:4px 0 0; }
.page.rqh .rq-seg { display:flex; margin:12px 0 0; padding:3px; border-radius:12px; background:var(--card); box-shadow:var(--row-shadow); }
.page.rqh .rq-seg button { flex:1; padding:8px; border:0; border-radius:9px; background:none; color:var(--muted); font:700 14px/1.2 var(--sans); cursor:pointer; }
.page.rqh .rq-seg button[aria-pressed="true"] { background:var(--lift); color:var(--ink); }
.page.rqh .rq-out { display:inline-flex; align-items:center; gap:5px; flex:none; margin-left:auto; padding:3px 9px; border-radius:999px; font:800 12px/1.3 var(--sans); white-space:nowrap; }
.page.rqh .rq-out svg { width:11px; height:11px; }
.page.rqh .rq-out.ok { background:var(--positive-soft); color:var(--positive); }
.page.rqh .rq-out.no { background:var(--danger-soft); color:var(--danger); }
.page.rqh .rq-out.rm { background:var(--lift); color:var(--muted); }
.page.rqh .rq-why { margin:4px 0 0; font-size:14px; color:var(--muted); }
.page.rqh .rq-meta { display:flex; flex-wrap:wrap; align-items:center; gap:8px; margin:10px 0 0; padding-top:10px; border-top:1px solid var(--line); font-size:13px; color:var(--muted); }
.page.rqh .rq-meta .ovr { color:var(--amber-ink); font-weight:700; }
.page.rqh .rq-deskno { margin:22px 0 0; font-size:13px; color:var(--muted); text-align:center; }
.page.rqh .rq-none { padding:40px 10px 0; }
/* packed History (his catch, 2026-10-26): a batch folds to one card that opens on a tap,
   the chips sit above the list, older months fold closed, one person's counts open a search */
.page.rqh .rq-chips { margin-top:12px; }
.page.rqh .rq-person-sum { margin:14px 2px 0; font-size:14px; color:var(--muted); }
.page.rqh .rq-person-sum b { color:var(--ink); }
.page.rqh .rq-fold-item { margin-top:10px; }
.page.rqh .rq-fold > summary { display:block; margin-top:0; list-style:none; cursor:pointer; }
.page.rqh .rq-fold > summary::-webkit-details-marker { display:none; }
.page.rqh .rq-fold .rq-kinds { margin:6px 0 0; font:500 14px/1.3 var(--sans); color:var(--muted); }
.page.rqh .rq-chev { display:inline-flex; align-items:center; gap:2px; margin-left:auto; color:var(--accent); font-weight:600; }
.page.rqh .rq-chev svg { width:14px; height:14px; transition:transform 200ms var(--ease-out); }
.page.rqh .rq-chev .hide, .page.rqh .rq-fold[open] .rq-chev .show { display:none; }
.page.rqh .rq-fold[open] .rq-chev .hide { display:inline; }
.page.rqh .rq-fold[open] .rq-chev svg { transform:rotate(90deg); }
.page.rqh .rq-fold .rq-group { margin-top:0; }
.page.rqh .rq-month { margin-top:20px; }
.page.rqh .rq-month > summary { display:flex; align-items:baseline; justify-content:space-between; gap:10px; padding:6px 2px; list-style:none; cursor:pointer; }
.page.rqh .rq-month > summary::-webkit-details-marker { display:none; }
.page.rqh .rq-month > summary .group { font:800 13px/1.2 var(--sans); letter-spacing:.06em; text-transform:uppercase; color:var(--muted); }
.page.rqh .rq-month > summary .rq-n::after { content:" ›"; }
.page.rqh .rq-month[open] > summary .rq-n::after { content:" ⌄"; }
.page.rqh .rq-month .rq-sec { margin-top:14px; }
/* the done moment: the stamp fades in over the body on the answer, its dot pops; then
   the card folds to nothing (the script sets its height, so the transition has one) */
.page.rqs .rq-done { position:absolute; inset:0; display:flex; align-items:center; justify-content:center; gap:10px;
                     background:var(--card); color:var(--ink); font:800 17px/1 var(--sans); opacity:0; pointer-events:none;
                     transition:opacity var(--stamp) ease; }
.page.rqs .rq-done i { display:grid; place-items:center; width:34px; height:34px; border-radius:50%; background:var(--done); color:var(--on-done); }
.page.rqs .rq-done svg { width:18px; height:18px; }
.page.rqs .rq-done .x, .page.rqs .rq-done.no .t { display:none; }
.page.rqs .rq-done.no .x { display:block; }
.page.rqs .rq-done.no { color:var(--danger); }
.page.rqs .rq-done.no i { background:var(--danger-soft); color:var(--danger); }
.page.rqs .rq.out .rq-done { opacity:1; }
.page.rqs .rq.out .rq-done i { animation:dot-pop 300ms var(--ease-spring) both; }
.page.rqs .rq.fold { opacity:0; transition:height var(--fold) var(--ease-out), opacity var(--fold) ease, margin-top var(--fold) var(--ease-out); }
.page.rqs .rq.arrive { --rise:-8px; animation:rise-in 320ms var(--ease-out) both; }
/* the Undo bar (the reference): ink over the tab bar with the tick or the cross, what was
   done, Undo as a pale pill; the line under it drains for the five seconds the bar stays
   (`--hold`). Motion off draws no line: the stay is the page's timer, not a motion. */
.page.rqs .rq-undo { --hold:5s; position:fixed; left:50%; bottom:calc(100px + env(safe-area-inset-bottom)); z-index:11;
                     width:min(100% - 32px, 448px); border-radius:14px; overflow:hidden; background:var(--ink); color:var(--bg);
                     box-shadow:var(--row-shadow); transform:translate(-50%, 16px); opacity:0; pointer-events:none;
                     transition:transform 220ms var(--ease-spring-soft), opacity 200ms ease; }
.page.rqs .rq-undo.on { transform:translateX(-50%); opacity:1; pointer-events:auto; }
.page.rqs .rq-undo form { display:flex; align-items:center; gap:10px; margin:0; padding:12px 12px 14px 14px; }
.page.rqs .rq-undo-msg { flex:1; min-width:0; display:flex; align-items:center; gap:8px; font:600 14px/1.3 var(--sans); white-space:nowrap; overflow:hidden; }
.page.rqs .rq-undo-msg > span { overflow:hidden; text-overflow:ellipsis; }
.page.rqs .rq-undo-msg i { display:grid; place-items:center; flex:none; width:20px; height:20px; border-radius:50%; background:var(--done); color:var(--on-done); }
.page.rqs .rq-undo-msg svg { width:12px; height:12px; }
.page.rqs .rq-undo-msg .x, .page.rqs .rq-undo.no .rq-undo-msg .t { display:none; }
.page.rqs .rq-undo.no .rq-undo-msg .x { display:block; }
.page.rqs .rq-undo.no .rq-undo-msg i { background:var(--danger); color:var(--on-danger); }
.page.rqs .rq-undo button { flex:none; padding:6px 12px; border:0; border-radius:8px; background:var(--bg); color:var(--ink); font:800 14px/1.2 var(--sans); cursor:pointer; }
.page.rqs .rq-undo button:disabled { opacity:.5; }
.page.rqs .rq-undo-line { position:absolute; left:0; right:0; bottom:0; height:3px; background:var(--done); transform-origin:left; transform:scaleX(0); }
.page.rqs .rq-undo.on .rq-undo-line { animation:rq-drain var(--hold) linear forwards; }
@keyframes rq-drain { from { transform:scaleX(1); } to { transform:scaleX(0); } }
@media (prefers-reduced-motion: reduce) { .page.rqs .rq-undo-line { display:none; } }
/* nothing waiting: the tick, then the two lines */
.page.rqs .rq-empty { padding:48px 10px 0; text-align:center; }
.page.rqs .rq-tick { display:grid; place-items:center; width:64px; height:64px; margin:0 auto 14px; border-radius:50%; background:var(--done); color:var(--on-done); }
.page.rqs .rq-tick svg { width:32px; height:32px; }
.page.rqs .waiting .empty-title { margin:0 0 4px; font:700 20px/1.2 var(--sans); letter-spacing:-.02em; }
.page.rqs .waiting .helper { margin:0; font-size:15px; }
/* the decline sheet: the kind in the question, who and when, the field (its placeholder
   the only label), the suggested lines as pills in the reference's chip look (Haoming,
   2026-10-26: the lift grey, navy, 16 px), the red verb and a quiet Cancel. It floats as an iOS
   action sheet (Haoming, 2026-10-26): the card's width — the page less its gutters —
   all four corners, a gap off the bottom, sized to what it holds; away, it sits further
   down so no edge peeks. The sort sheet, a short choice too, floats the same; the
   shared sheet stays edge to edge for the day sheets. */
.sheet.decline, .sheet.sort { width:min(100% - 48px, 432px); min-height:0; bottom:calc(12px + env(safe-area-inset-bottom));
                 padding-bottom:24px; border-radius:22px; box-shadow:0 8px 34px var(--sheet-shadow);
                 transform:translate(-50%, calc(100% + 60px)); }
.sheet.decline.on, .sheet.sort.on { transform:translate(-50%, 0); }
.sheet.decline .note-wrap { margin:14px 0 10px; }
/* the pills are one row that scrolls sideways, Messages' way (Haoming's pick, 2026-10-26: four
   pills wrapped to three rows). Its solid part lines up with the field: the row reaches
   16 px past the field on each side (`--feather`) and a mask fades over that reach, so a pill
   dissolves as it crosses the field's edge and condenses as it arrives (his look) */
.sheet.decline .rq-quick { --feather:16px; display:flex; gap:8px; margin:0 calc(-1 * var(--feather)) 18px; padding:0 var(--feather);
                           overflow-x:auto; scrollbar-width:none; -webkit-overflow-scrolling:touch;
                           -webkit-mask-image:linear-gradient(to right, transparent, #000 var(--feather), #000 calc(100% - var(--feather)), transparent);
                           mask-image:linear-gradient(to right, transparent, #000 var(--feather), #000 calc(100% - var(--feather)), transparent); }
.sheet.decline .rq-quick::-webkit-scrollbar { display:none; }
.sheet.decline .rq-quick button { flex:none; white-space:nowrap; }
.sheet.decline .rq-quick button { padding:9px 14px; border:0; border-radius:12px; background:var(--lift); color:var(--ink); font:600 16px/1.2 var(--sans); cursor:pointer; }
.sheet.decline .primary.danger { width:100%; min-height:52px; border-radius:14px; background:var(--danger-btn); color:var(--on-danger-btn); }
.sheet.decline .rq-cancel { display:block; width:100%; margin-top:6px; padding:12px; border:0; background:none; color:var(--muted); font:600 15px/1.2 var(--sans); cursor:pointer; }
/* the fatigue alert's second line: who and when, then the rule (2026-10-16) */
.alert-text { margin:-8px 0 0; padding:0 18px 18px; font-size:14px; line-height:1.45; color:var(--muted); text-align:center; }
.alert-title:has(+ .alert-text) { text-align:center; }
.alert-acts.stack { grid-template-columns:1fr; }
.alert-acts.stack .alert-btn + .alert-btn { border-left:0; border-top:1px solid var(--line); }
dialog.alert:focus { outline:none; }

/* ============================================================================
   Month, redesigned (Haoming's prototype, M4 "Sky follows today" with the
   holiday heroes, 2026-10-16). The sky is the hero: its colour follows the
   shift, the scene's props rise over it (one file per scene under
   templates/scenes/), the day's words sit top left; the calendar card rises
   over the sky with rounded top corners. Idle motion is adopted (stars
   twinkle, clouds drift, the clock ticks) and still under reduced motion —
   every scene drawn once and left alone. The screen is full-bleed.
   ========================================================================= */
.month { margin:calc(-40px - env(safe-area-inset-top)) -24px 0; }     /* the sky runs under the status bar */
.sky { position:relative; height:calc(262px + env(safe-area-inset-top)); overflow:hidden; background:var(--sky-off); --hero-ink-here:var(--hero-ink);
       --sky-fade:1100ms; transition:background-color var(--sky-fade) ease; }
.sky.is-night { background:var(--sky-night); --hero-ink-here:var(--hero-ink-night);
                --sc-steam:#ffffff; --sc-ripple:#ffffff; --sc-white:#ffffff; --sc-skyline:#2b416a; --sc-snow:#ffffff; --sc-navyish:#ffffff; --sc-rays:0.12; }
.sky.is-day { background:var(--sky-day); }
.sky.is-off { background:var(--sky-off); }
.sky.is-none { background:var(--sky-none); }
.sky.is-holiday.is-off { background:var(--hol-sky); }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .sky.is-holiday.is-off { background:var(--hol-sky-dark); } }
:root[data-theme="dark"] .sky.is-holiday.is-off { background:var(--hol-sky-dark); }
.scenes { position:absolute; inset:env(safe-area-inset-top) 0 0; }
.scene { position:absolute; inset:0; }
.scene-art { position:absolute; inset:0; width:100%; height:100%; overflow:visible; }
/* the everyday props: hidden until their sky is on, then they rise or drift in;
   `enter` holds them down until the first frame has painted (the page's script) */
.scene .m4-moon, .scene .m4-sun { transform:translateY(190px); opacity:0; transition:transform 800ms cubic-bezier(.55,0,.8,.2), opacity 600ms ease; }
.sky.is-night:not(.is-holiday):not(.enter) .m4-moon { transform:none; opacity:1; transition:transform 900ms cubic-bezier(.22,1,.36,1) 250ms, opacity 700ms ease 250ms; }
.sky.is-day:not(.is-holiday):not(.enter) .m4-sun { transform:none; opacity:1; transition:transform 1000ms cubic-bezier(.22,1,.36,1) 300ms, opacity 700ms ease 300ms; }
.scene .m4-rays { transform-origin:322px 92px; transform-box:view-box; transform:rotate(-40deg) scale(0.7); transition:transform 1400ms cubic-bezier(.22,1,.36,1) 300ms; }
.sky.is-day:not(.enter) .m4-rays { transform:none; }
.scene .m4-clouds { transform:translateX(-60px); opacity:0; transition:transform 700ms ease, opacity 400ms ease; }
.sky.is-off:not(.is-holiday):not(.enter) .m4-clouds { transform:none; opacity:1; transition:transform 1300ms cubic-bezier(.22,1,.36,1) 250ms, opacity 700ms ease 250ms; }
.scene .m4-draft { transform:translateY(40px) rotate(6deg); transform-origin:316px 110px; transform-box:view-box; opacity:0; transition:transform 600ms ease, opacity 400ms ease; }
.sky.is-none:not(.enter) .m4-draft { transform:rotate(-4deg); opacity:1; transition:transform 1100ms cubic-bezier(.22,1,.36,1) 250ms, opacity 700ms ease 250ms; }
.scene .m4-stars { opacity:0; transition:opacity 400ms ease; }
.sky.is-night:not(.is-holiday):not(.enter) .m4-stars { opacity:1; transition:opacity 500ms ease 450ms; }
/* a holiday's props replace the scene's own; only the holiday's file is shown */
.scene-hol { opacity:0; transition:opacity 500ms ease 200ms; pointer-events:none; }
.sky:not(.enter) .scene-hol.on { opacity:1; }
/* idle motion, the prototype's: stars twinkle and sparkle, rays breathe, clouds drift, the clock ticks */
@keyframes m4-twinkle { 0%,100% { opacity:.9; transform:scale(1); } 50% { opacity:.2; transform:scale(.6); } }
@keyframes m4-sparkle { 0%,100% { opacity:0; transform:scale(.3) rotate(0deg); } 45% { opacity:1; transform:scale(1.1) rotate(25deg); } 60% { opacity:.9; transform:scale(1) rotate(30deg); } }
.m4-tw { transform-box:fill-box; transform-origin:center; animation:m4-twinkle 3s ease-in-out infinite; }
.m4-spark { transform-box:fill-box; transform-origin:center; animation:m4-sparkle 3.5s ease-in-out infinite; }
@keyframes m4-breathe { 0%,100% { transform:scale(1); } 50% { transform:scale(1.12); } }
.m4-rays-a, .m4-rays-b { transform-origin:322px 92px; transform-box:view-box; animation:m4-breathe 2.6s ease-in-out infinite; }
.m4-rays-b { animation-delay:-1.3s; }
@keyframes m4-drift { 0% { transform:translateX(-70px); opacity:0; } 15% { opacity:1; } 80% { opacity:1; } 100% { transform:translateX(110px); opacity:0; } }
.m4-cloud1 { animation:m4-drift 16s linear infinite; animation-delay:-5s; }
.m4-cloud2 { animation:m4-drift 22s linear infinite; animation-delay:-14s; }
.m4-cloud3 { animation:m4-drift 19s linear infinite; animation-delay:-2s; }
@keyframes m4-spin { to { transform:rotate(360deg); } }
.m4-minute, .m4-hour { transform-origin:352px 152px; transform-box:view-box; }
.m4-minute { animation:m4-spin 4s linear infinite; }
.m4-hour { animation:m4-spin 48s linear infinite; }
/* the holidays' own motion */
@keyframes hx-burst { 0% { transform:scale(.2); opacity:0; } 15% { opacity:1; } 55% { transform:scale(1); opacity:1; } 100% { transform:scale(1.08); opacity:0; } }
@keyframes hx-sway { 0%,100% { transform:rotate(-3deg); } 50% { transform:rotate(3deg); } }
@keyframes hx-sway-s { 0%,100% { transform:rotate(-1.2deg); } 50% { transform:rotate(1.2deg); } }
@keyframes hx-flicker { 0%,100% { transform:scaleY(1) scaleX(1); } 30% { transform:scaleY(1.12) scaleX(.92); } 60% { transform:scaleY(.9) scaleX(1.05); } }
@keyframes hx-twinkle { 0%,100% { opacity:1; } 50% { opacity:.25; } }
@keyframes hx-steam { 0% { transform:translateY(6px); opacity:0; } 30% { opacity:.9; } 100% { transform:translateY(-14px); opacity:0; } }
@keyframes hx-ripple { 0% { transform:scale(.6); opacity:.9; } 100% { transform:scale(1.25); opacity:0; } }
@keyframes hx-float { 0%,100% { transform:translateY(0); } 50% { transform:translateY(-5px); } }
@keyframes hx-breathe { 0%,100% { opacity:.7; } 50% { opacity:1; } }
@keyframes hx-glow { 0%,100% { transform:scale(1); opacity:1; } 50% { transform:scale(1.12); opacity:.85; } }
@keyframes hx-spin { to { transform:rotate(360deg); } }
@keyframes hx-petal { 0% { transform:translate(0,0) rotate(0); opacity:0; } 15% { opacity:1; } 100% { transform:translate(90px,34px) rotate(200deg); opacity:0; } }
.hx-burst { transform-box:view-box; animation:hx-burst 2.8s ease-out infinite; }
.hx-sway { transform-box:view-box; animation:hx-sway 3.6s ease-in-out infinite; }
.hx-sway-s { transform-box:view-box; animation:hx-sway-s 5s ease-in-out infinite; }
.hx-flicker { transform-box:view-box; animation:hx-flicker 1.1s ease-in-out infinite; }
.hx-twinkle { animation:hx-twinkle 2.4s ease-in-out infinite; }
.hx-steam { transform-box:fill-box; animation:hx-steam 2.8s ease-out infinite; }
.hx-ripple { transform-box:view-box; animation:hx-ripple 2.6s ease-out infinite; }
.hx-float { animation:hx-float 3.2s ease-in-out infinite; }
.hx-breathe { animation:hx-breathe 5s ease-in-out infinite; }
.hx-glow { transform-box:view-box; animation:hx-glow 2.6s ease-in-out infinite; }
.hx-spin { transform-box:view-box; animation:hx-spin 60s linear infinite; }
.hx-petal { transform-box:fill-box; animation:hx-petal 5s ease-in infinite; }
/* reduced motion: every scene a still, drawn once (Haoming, 2026-10-16) — the loops
   stop outright (never the 1 ms collapse, which would spin them without end) */
@media (prefers-reduced-motion: reduce) {
    .sky, .scene *, .scene-hol { transition:none !important; }
    .scene [class^="m4-"], .scene [class*=" m4-"], .scene [class^="hx-"], .scene [class*=" hx-"] { animation:none !important; }
    .m4-spark { opacity:.8; } .hx-burst { opacity:1; } .hx-petal { opacity:.8; }
}
/* the words over the sky: the layout follows the day — plain, a holiday on a shift,
   a holiday (or a day off in lieu) on a day off */
.hero-txt { position:absolute; top:calc(26px + env(safe-area-inset-top)); left:24px; right:24px; display:flex; flex-direction:column; gap:4px; color:var(--hero-ink-here); }
.hero-txt p { margin:0; }
.hero-txt p:empty { display:none; }
.h-greet { display:none; }
.h-line1 { font:700 14px/1.3 var(--sans); opacity:.8; }
.h-big { margin-top:6px !important; font:800 64px/1 var(--sans); letter-spacing:-.05em; }
.h-line3 { font:700 24px/1.2 var(--sans); letter-spacing:-.01em; font-variant-numeric:tabular-nums; }
.h-line4 { margin-top:4px !important; font:600 14px/1.3 var(--sans); opacity:.85; }
.hero-txt[data-layout="hol-shift"] .h-greet { display:block; font:800 15px/1.2 var(--sans); }
.hero-txt[data-layout="hol-shift"] .h-big { margin-top:4px !important; }
.hero-txt[data-layout="hol-off"] .h-big { display:none; }
.hero-txt[data-layout="hol-off"] .h-line1 { order:-1; }      /* "Public holiday" / "Off in lieu" sits above the greeting */
.hero-txt[data-layout="hol-off"] .h-greet { display:block; margin-top:2px; max-width:250px; font:800 30px/1.08 var(--sans); letter-spacing:-.025em; }
.hero-txt[data-layout="hol-off"] .h-line3 { margin-top:2px; font:700 15px/1.3 var(--sans); opacity:.85; }
@keyframes hero-in { from { opacity:0; transform:translateY(-14px); } to { opacity:1; transform:none; } }
.hero-txt.swap { animation:hero-in 520ms cubic-bezier(.22,1,.36,1) both; }
/* the calendar card over the sky */
/* Month's own card: scoped, the range picker's calendar shares the class name (it rose over the read-back boxes) */
.month .cal { position:relative; margin-top:-28px; padding:18px 20px 0; border-radius:28px 28px 0 0; background:var(--bg);
       display:flex; flex-direction:column; gap:10px; }
.month .mhead { display:flex; align-items:center; justify-content:space-between; gap:10px; }
.month .mname { flex:1; margin:0; font:800 22px/1.2 var(--sans); letter-spacing:-.02em; }
.month .myear { font-weight:500; color:var(--muted); }
.mctl { display:flex; align-items:center; gap:2px; margin-right:-10px; }
.today-btn { height:36px; padding:0 14px; margin-right:4px; border:0; border-radius:999px; background:var(--lift); color:var(--ink);
             font:800 14px/1 var(--sans); cursor:pointer; animation:today-in 320ms cubic-bezier(.22,1.4,.36,1) both; }
.today-btn[hidden] { display:none; }
@keyframes today-in { from { opacity:0; transform:scale(.7); } to { opacity:1; transform:none; } }
.month .mnav { width:40px; height:44px; display:flex; align-items:center; justify-content:center; color:var(--ink); text-decoration:none; }
.month .mnav svg { width:20px; height:20px; }
.month .mnav.gone { opacity:.3; visibility:visible; }
.mlegend { display:flex; align-items:center; justify-content:space-between; gap:10px; margin-top:-6px; font:600 13px/1.3 var(--sans); }
.mlegend .lgs { display:flex; flex-wrap:wrap; gap:10px 14px; }
.mlegend .lg { display:inline-flex; align-items:center; gap:6px; }
.mlegend .dot { width:10px; height:10px; border-radius:50%; }
.mlegend .dot.hol { background:var(--ph); }
.month .msub { margin:0; flex:none; font:400 12px/1.3 var(--sans); color:var(--muted-2); }
.notpub { display:flex; align-items:center; gap:8px; margin:-6px 0 0; font-size:13px; color:var(--muted); }
.notpub svg { width:15px; height:15px; flex:none; }
.month .dow, .month .grid { margin:0; gap:5px; }
.month .dow span { margin:0; font:700 11px/1.3 var(--sans); color:var(--muted-2); }
.month .c { height:44px; gap:0; border-radius:12px; line-height:1.1; font:600 15px/1.1 var(--sans);
            transition:box-shadow 300ms ease, transform 150ms ease; }
.month .c:active { transform:scale(.94); }
.month .c .n { font:700 14px/1.1 var(--sans); }
.month .c.off .n, .month .c.none .n, .month .c.gone .n, .month .c.r .n, .month .c.leave .n { font:600 15px/1.1 var(--sans); }
.month .c .l { font:800 10px/1.2 var(--sans); letter-spacing:0; }
.month .c.clinic { background:var(--lift); color:var(--ink); }
.month .c.r, .month .c.leave { background:var(--rest); color:var(--rest-ink); }
.month .c.leave .l { color:inherit; }
.month .c.none { border:1.5px dashed var(--line); background:transparent; color:var(--muted-2); cursor:default; }
.month .c.none .n { color:var(--muted-2); font-weight:600; }
.month .c.gone { background:repeating-linear-gradient(135deg, transparent 0 6px, var(--line) 6px 7px); color:var(--muted-2); }
/* today wears the small pill above its number and a faint inset ring; the tapped
   day the ring (the selected day's is the stronger) */
.month .c.today { box-shadow:inset 0 0 0 1.5px var(--ring-today); }
.month .c.sel { box-shadow:0 0 0 2.5px var(--ink); }
.month .c.today .n { font-weight:700; }
.month .c .now { position:absolute; top:-7px; left:50%; transform:translateX(-50%); padding:1px 5px; border-radius:6px;
                 background:var(--ink); color:var(--bg); font:800 8px/1.4 var(--sans); letter-spacing:.06em; text-transform:uppercase; }
.month .c.hol::before { content:""; position:absolute; top:5px; right:6px; width:5px; height:5px; border-radius:50%; background:var(--ph); }
.month .c.blank { pointer-events:none; }
/* the pointer row into Services */
.pointer { display:flex; align-items:center; gap:14px; margin-top:4px; padding:14px 16px; border-radius:18px; background:var(--card);   /* a card on the ground since the page went warm (2026-10-26) */
           color:inherit; text-decoration:none; }
.pointer-text { flex:1; min-width:0; display:flex; flex-direction:column; gap:3px; }
.pointer-main { font:800 16px/1.25 var(--sans); }
.pointer-sub { font:400 13px/1.3 var(--sans); color:var(--muted); }
.pointer-chev { width:18px; height:18px; flex:none; color:var(--muted-2); }

/* ============================================================================
   Services and Inbox, refreshed (Haoming's prototypes S2 and I3, 2026-10-16).
   Both sit on the warm ground; the big title 34/800; the tiles and the cards
   share a tone and a corner drawing per kind (_glyphs.html).
   ========================================================================= */
body:has(.on-ground) { background:var(--ground); }
.big-title { margin:0; font:800 34px/1 var(--sans); letter-spacing:-.03em; }
.glyph { stroke:var(--glyph); }
.tone-amber { --glyph:var(--glyph-amber); }
.tone-pink { --glyph:var(--glyph-pink); }
.tone-blue, .tone-white { --glyph:var(--glyph-grey); }
span.glyph svg { fill:var(--glyph-cloud); stroke:none; width:100%; height:100%; display:block; }
/* --- Services: picture tiles --- */
.hub { padding:4px 4px 0; }
.hub .tiles { display:grid; grid-template-columns:repeat(2, minmax(0, 1fr)); gap:12px; margin:16px -4px 0; }
.hub .tile { position:relative; height:164px; padding:16px; border-radius:22px; overflow:hidden; text-decoration:none; color:var(--ink);
             display:flex; flex-direction:column; gap:4px; background:var(--card); box-shadow:var(--row-shadow); border:0; }
.hub .tile.tone-amber { background:var(--tile-amber); box-shadow:none; }
.hub .tile.tone-blue { background:var(--tile-blue); box-shadow:none; }
.hub .tile.tone-pink { background:var(--tile-pink); box-shadow:none; }
.hub .tile.off { background:transparent; box-shadow:none; border:1.5px dashed var(--tile-dash); color:var(--muted-2); --glyph:var(--glyph-dash); }
.hub .tile > :not(.glyph) { position:relative; }
.tile-title { font:800 17px/1.25 var(--sans); }
.tile.off .tile-title { color:var(--muted); }
.tile-state { font:400 13px/1.3 var(--sans); color:var(--muted); }
.tile-when { margin-top:auto; font:700 12px/1.3 var(--sans); color:var(--muted); }
.tile.tone-amber .tile-when { color:var(--amber-ink); }
.tile-glyph { position:absolute; right:-18px; bottom:-18px; width:104px; height:104px; }
.tile.tone-blue .tile-glyph { right:-22px; bottom:-26px; width:116px; height:116px; }
.tile.tone-pink .tile-glyph { right:-20px; bottom:-20px; width:112px; height:112px; }
.tile.off .tile-glyph { right:-14px; bottom:-14px; width:96px; height:96px; }
.tile-dots { display:flex; gap:5px; margin-top:6px; }
.tdot { width:15px; height:15px; border-radius:50%; display:flex; align-items:center; justify-content:center; }
.tdot.empty { border:1.5px dashed var(--dot-empty); }
.tdot.dot, .tdot.tick { background:var(--dot-on); }
.tdot svg { width:9px; height:9px; stroke:var(--on-dot); }
a.tile { --press-back:300ms; transition:transform var(--press-back) var(--ease-spring-soft); }
a.tile:active { transform:scale(.97); transition:transform 150ms ease; }
/* the load-in, on a page load: the title, then each tile rising, its drawing sliding in from the
   corner, the dots popping, the cloud drifting and the clock's hands turning once */
@keyframes s2-in { from { opacity:0; transform:translateY(22px) scale(.95); } to { opacity:1; transform:none; } }
@keyframes s2-glyph { from { opacity:0; transform:translate(28px,28px) rotate(-10deg); } to { opacity:1; transform:none; } }
@keyframes s2-title { from { opacity:0; transform:translateY(8px); } to { opacity:1; transform:none; } }
@keyframes s2-spin { from { transform:rotate(-360deg); } to { transform:rotate(0deg); } }
@keyframes s2-spin-slow { from { transform:rotate(-90deg); } to { transform:rotate(0deg); } }
@keyframes s2-bob { 0%,100% { transform:translateX(0); } 50% { transform:translateX(-6px); } }
@keyframes s2-pop { 0% { transform:scale(.2); opacity:0; } 70% { transform:scale(1.25); opacity:1; } 100% { transform:scale(1); } }
.hub.enter .big-title { animation:s2-title 500ms cubic-bezier(.22,1,.36,1) both; }
.hub.enter .tile { animation:s2-in 560ms cubic-bezier(.22,1,.36,1) calc(60ms + var(--i, 0) * 70ms) both; }
.hub.enter .tile-glyph { animation:s2-glyph 800ms cubic-bezier(.22,1,.36,1) calc(240ms + var(--i, 0) * 70ms) both; }
.hub.enter .tdot:not(.empty) { animation:s2-pop 420ms cubic-bezier(.22,1,.36,1) calc(700ms + var(--d, 0) * 120ms) both; }
.hub .hand-m, .hub .hand-h { transform-origin:12px 12px; transform-box:view-box; }
.hub.enter .hand-m { animation:s2-spin 1100ms cubic-bezier(.22,1,.36,1) 450ms both; }
.hub.enter .hand-h { animation:s2-spin-slow 1100ms cubic-bezier(.22,1,.36,1) 450ms both; }
.hub span.glyph svg { animation:s2-bob 6s ease-in-out 1.2s infinite; }
/* --- Inbox: the card stack, the open row, Earlier --- */
.ib-page { position:relative; padding:4px 4px 0; --pull:300ms; transition:transform var(--pull) var(--ease-out); }
/* pull to refresh (2026-10-23): the page comes down with the finger (no easing while it does), the ring above
   the title filling and turning as it comes; past the mark it spins while the Inbox is fetched again */
.ib-page.pulling { transition:none; }
.pull { position:absolute; left:0; right:0; top:-40px; display:flex; justify-content:center; pointer-events:none; }
.pull-ring { width:22px; height:22px; border-radius:50%; border:2.5px solid var(--line); border-top-color:var(--ink);
             opacity:var(--p, 0); transform:scale(calc(.6 + .4 * var(--p, 0))) rotate(calc(var(--p, 0) * 300deg)); }
.ib-page.refreshing .pull-ring { --spin:800ms; animation:pull-spin var(--spin) linear infinite; }
@keyframes pull-spin { to { transform:rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .ib-page.refreshing .pull-ring { animation:none; } }   /* a loop stops outright, never a 1 ms spin */
.ib-head { display:flex; align-items:flex-end; justify-content:space-between; gap:12px; margin-bottom:12px; }
.ib-count { margin:4px 0 0; font:700 14px/1.3 var(--sans); color:var(--muted); }
.ib-head form { margin:0; }
.ib-all { min-height:44px; padding:0 4px; border:0; background:none; color:var(--ink); font:700 14px/1 var(--sans);
          text-decoration:underline; text-underline-offset:3px; cursor:pointer; }
.inbox-block .stack { position:relative; margin:4px -4px 0; padding-bottom:24px; }   /* scoped: the alerts' stacked buttons share the word */
.card { position:relative; display:flex; flex-direction:column; gap:6px; min-height:300px; padding:20px; border-radius:24px;
        background:var(--card); box-shadow:var(--card-shadow); overflow:hidden; color:var(--ink);
        transform-origin:50% 100%; transition:transform 420ms cubic-bezier(.2,.8,.2,1), opacity 320ms ease, filter 420ms ease; }
.card.tone-amber { background:var(--tile-amber); }
.card.tone-blue { background:var(--tile-blue); }
.card.tone-pink { background:var(--tile-pink); }
.card.top { z-index:3; touch-action:pan-y; }   /* the pile swipes sideways (2026-10-23); the page keeps its scroll */
.card.drag { transition:none; }                /* under the finger: no easing while it follows */
.card.under { position:absolute; inset:0 0 24px; z-index:2; transform:translateY(16px) scale(.94); pointer-events:none;
              --depth:3px; filter:blur(var(--depth)); }   /* soft at rest; it sharpens as the top card leaves (2026-10-23) */
.card.later { display:none; }
/* a card on the move between places (the swipe): sliding in or out behind the pile, or coming in on top */
.card.back { display:flex; position:absolute; inset:0 0 24px; z-index:1; pointer-events:none; }
.card.over { display:flex; position:absolute; inset:0 0 24px; z-index:4; pointer-events:none; }
.card > :not(.card-glyph) { position:relative; }
.card-glyph { position:absolute; right:-34px; top:22px; width:170px; height:170px; opacity:.55; }
.card-meta { display:flex; justify-content:space-between; margin:0; font:600 13px/1.3 var(--sans); color:var(--muted-2); }
.card.tone-amber .card-meta { color:var(--meta-amber); }
.card-status { display:flex; align-items:center; gap:6px; margin:10px 0 0; font:800 14px/1.2 var(--sans); color:var(--ink); }
.card-status svg, .ib-chip svg { width:15px; height:15px; flex:none; }
.card-status.declined { color:var(--danger); }
.card-status.approved { color:var(--positive); }
.card-head { margin:0; font:800 30px/1.05 var(--sans); letter-spacing:-.03em; }
.card-span { margin:0; font-size:15px; color:var(--muted); }
.quote { display:flex; flex-direction:column; gap:4px; margin:10px 0 0; padding:12px 14px; border-radius:12px; background:var(--quote);
         font-size:15px; line-height:1.4; color:var(--ink); }
.card.tone-amber .quote, .card.tone-blue .quote, .card.tone-pink .quote { background:var(--quote-amber); }
.quote.none { font-size:14px; font-style:italic; color:var(--muted-2); }
.quote-by { font-size:12px; font-weight:600; color:var(--muted-2); }
.card-acts { display:flex; gap:8px; margin-top:auto; padding-top:14px; }
.card-acts form { flex:1; margin:0; display:flex; }
.btn { flex:1; min-height:52px; border:0; border-radius:14px; display:flex; align-items:center; justify-content:center;
       font:800 15px/1.2 var(--sans); text-decoration:none; cursor:pointer; padding:0 12px; }
.card-acts > a.btn { flex:1.4; }
.btn.navy { background:var(--navy-btn); color:var(--on-navy); }
.btn.soft { background:var(--soft-btn); color:var(--ink); }
.card.tone-white .btn.soft { background:var(--lift); }
/* Got it: the top card flies off to the left as the next rises; Mark all read sends them all */
.inbox-block.htmx-swapping .card.top { transform:translate(-118%, 40px) rotate(-14deg); opacity:0; }
.inbox-block.htmx-swapping.all .card { transform:translate(118%, 40px) rotate(14deg); opacity:0; }
/* the roster's changed days */
.chg-rows { display:flex; flex-direction:column; margin-top:6px; }
.chg { display:flex; align-items:center; gap:8px; padding:8px 0; border-top:1px solid var(--line-soft); font-size:13px; }
.chg-when { flex:1; font:600 14px/1.3 var(--sans); }
.chg-was { color:var(--muted-2); text-decoration:line-through; }
.chg-arrow { color:var(--muted-2); }
.chg-now { padding:2px 8px; border-radius:6px; font-weight:800; background:var(--lift); color:var(--ink); }
.chg-now.am { background:var(--am-fill); color:var(--shift-ink); }
.chg-now.pm { background:var(--pm-fill); color:var(--shift-ink); }
.chg-now.off { padding:1px 8px; background:none; border:1.5px dashed var(--chevron); color:var(--muted); }
.chg-more { margin:6px 0 0; font-size:13px; color:var(--muted-2); }
.chg-all summary { display:inline-flex; align-items:center; gap:6px; min-height:44px; list-style:none; font:700 15px/1 var(--sans); cursor:pointer; }
.chg-all summary::-webkit-details-marker { display:none; }
.chg-all summary svg { width:16px; height:16px; transition:transform 200ms var(--ease-out); }
.chg-all[open] summary svg { transform:rotate(180deg); }
/* all caught up: the tick drawn, three sparks twinkling */
.caught-up { height:230px; display:flex; flex-direction:column; align-items:center; justify-content:center; gap:10px; text-align:center; }
.cu-art { position:relative; width:120px; height:96px; display:flex; align-items:center; justify-content:center; }
.cu-tick { width:76px; height:76px; border-radius:50%; background:var(--navy-btn); display:flex; align-items:center; justify-content:center;
           animation:i3-pop 520ms cubic-bezier(.3,1.5,.5,1) both; }
.cu-tick svg { width:36px; height:36px; stroke:var(--on-navy); }
.cu-tick path { stroke-dasharray:30; stroke-dashoffset:30; animation:i3-draw 420ms 260ms ease-out forwards; }
.spark { position:absolute; animation:i3-tw 1.8s ease-in-out infinite; }
.spark.s1 { left:6px; top:12px; width:14px; height:14px; fill:var(--pm-fill); }
.spark.s2 { right:10px; top:4px; width:10px; height:10px; fill:var(--am-fill); animation-delay:.6s; }
.spark.s3 { right:2px; bottom:14px; width:12px; height:12px; fill:var(--brand); animation-delay:1.1s; }
.cu-title { margin:0; font:800 22px/1.2 var(--sans); letter-spacing:-.02em; }
.cu-sub { margin:0; font-size:14px; color:var(--muted); }
@keyframes i3-pop { from { transform:scale(.4); opacity:0; } to { transform:scale(1); opacity:1; } }
@keyframes i3-draw { to { stroke-dashoffset:0; } }
@keyframes i3-tw { 0%,100% { opacity:.25; transform:scale(.7); } 50% { opacity:1; transform:scale(1); } }
@keyframes i3-in { from { opacity:0; transform:translateY(-10px); } to { opacity:1; transform:none; } }
/* the open window, or none */
.open-row { display:flex; align-items:center; gap:12px; margin:0 -4px 12px; padding:12px 14px; border-radius:16px; background:var(--card);
            color:var(--ink); text-decoration:none; box-shadow:var(--row-shadow); }
.open-ico { width:36px; height:36px; flex:none; border-radius:50%; background:var(--lift); display:flex; align-items:center; justify-content:center; }
.open-ico .glyph { width:18px; height:18px; stroke:var(--muted); stroke-width:1.9; }
.open-text { flex:1; min-width:0; display:flex; flex-direction:column; gap:1px; }
.open-title { font:700 15px/1.3 var(--sans); }
.open-sub { font-size:13px; color:var(--muted); }
.open-chev { width:18px; height:18px; color:var(--muted-2); flex:none; }
/* Earlier: one card per item, newest first */
.ib-group { margin:22px 0 10px; font:700 13px/1 var(--sans); letter-spacing:.08em; text-transform:uppercase; color:var(--muted-2); }
.earlier { display:flex; flex-direction:column; gap:12px; margin:0 -4px; }
.e1 { display:flex; flex-direction:column; gap:12px; padding:16px; border-radius:18px; background:var(--card); box-shadow:var(--row-shadow); }
.e1.arrive { animation:i3-in 420ms cubic-bezier(.2,.8,.2,1) 380ms both; }
.e1-top { display:flex; align-items:center; justify-content:space-between; font-size:13px; color:var(--muted-2); }
.ib-chip { display:inline-flex; align-items:center; gap:6px; height:26px; padding:0 10px 0 8px; border-radius:999px;
        background:var(--chip-blue); color:var(--ink); font:800 12px/1 var(--sans); }
.ib-chip svg { width:14px; height:14px; }
.ib-chip.declined { background:var(--danger-soft); color:var(--danger); }
.ib-chip.approved { background:var(--positive-soft); color:var(--positive); }
.e1-main { display:flex; flex-direction:column; gap:2px; }
.e1-head { margin:0; font:800 17px/1.25 var(--sans); letter-spacing:-.01em; }
.e1-span { margin:0; font-size:14px; color:var(--muted); }
.e1-act { align-self:flex-start; min-height:44px; margin:-6px 0 -10px; display:inline-flex; align-items:center; gap:6px;
          font:700 15px/1 var(--sans); color:var(--ink); text-decoration:none; }
.e1-act svg { width:16px; height:16px; }
.ib-none { margin:6px 0 0; font-size:15px; color:var(--muted); }
/* Earlier's months and the fold of what is older (2026-10-19) */
.ib-month { margin:16px 0 8px; font:700 15px/1.2 var(--sans); color:var(--muted); }
.ib-group + .ib-month { margin-top:0; }
.earlier + .earlier { margin-top:12px; }
.ib-older { margin:4px 0 0; }
.ib-older > summary { display:flex; align-items:center; justify-content:center; gap:6px; min-height:48px; list-style:none;
                      font:600 15px/1 var(--sans); color:var(--muted); cursor:pointer; }
.ib-older > summary::-webkit-details-marker { display:none; }
.ib-older > summary .show, .ib-older > summary .hide { color:var(--ink); font-weight:700; }
.ib-older .hide, .ib-older[open] .show { display:none; }
.ib-older[open] .hide { display:inline; }
.ib-older > summary svg { width:16px; height:16px; transition:transform 200ms var(--ease-out); }
.ib-older[open] > summary svg { transform:rotate(180deg); }
.ib-older[open] > summary ~ * { animation:fade-in 220ms var(--ease-out); }
.ib-keep { margin:18px 0 0; font-size:13px; color:var(--muted-2); text-align:center; }
/* a stack (Haoming's reference 2.1 "stacks", 2026-10-23): the front card over two edges peeking
   under it (one for a pair), the dates as chips with the half only when mixed, *See all 5* the
   real button and the whole card a bigger target; open, the edges and the front go and the rows
   fan out under the group's name with *Show less*; in the new pile the same chips and rows sit
   inside the batch's card behind a fold */
.ib-stack { position:relative; padding-bottom:18px; }
.ib-stack.two { padding-bottom:9px; }
.ib-ly { position:absolute; left:0; right:0; height:44px; border-radius:18px; }
.ib-ly1 { bottom:9px; transform:scaleX(.94); background:var(--layer-1); z-index:1; }
.ib-ly2 { bottom:0; transform:scaleX(.87); background:var(--layer-2); z-index:0; }
.ib-stack.two .ib-ly2 { display:none; }
.ib-stack.two .ib-ly1 { bottom:0; }
.ib-stack .front { position:relative; z-index:2; cursor:pointer; }
.ib-stack.open { padding-bottom:0; }
.ib-stack.open .ib-ly, .ib-stack.open .front { display:none; }
.ib-fan[hidden] { display:none; }
.ib-dates { display:flex; flex-wrap:wrap; gap:5px; }
.card .ib-dates { margin-top:8px; }
.ib-dchip { display:inline-flex; align-items:center; gap:5px; padding:4px 7px; border-radius:9px; background:var(--lift);
            font:600 13px/1.2 var(--sans); white-space:nowrap; }
.ib-dchip.more { color:var(--muted); }
.ib-sh { display:inline-block; padding:2px 6px; border-radius:5px; font:800 11px/1.3 var(--sans); color:var(--shift-ink); }
.ib-sh.am { background:var(--am-fill); }
.ib-sh.pm { background:var(--pm-fill); }
.ib-see { align-self:flex-start; min-height:44px; margin:-6px 0 -10px; padding:0; border:0; background:none; display:inline-flex;
          align-items:center; gap:6px; font:700 15px/1 var(--sans); color:var(--ink); cursor:pointer; }
.ib-see svg { width:16px; height:16px; }
.ib-ghead { display:flex; align-items:center; justify-content:space-between; margin:4px 4px 10px; font:700 17px/1.2 var(--sans); }
.ib-less { min-height:34px; padding:0 12px; border:0; border-radius:999px; background:var(--card); color:var(--ink);
           font:700 13px/1 var(--sans); display:inline-flex; align-items:center; gap:5px; cursor:pointer; box-shadow:var(--row-shadow); }
.ib-less svg { width:12px; height:12px; }
.ib-mini { display:flex; align-items:center; gap:12px; padding:14px 16px; border-radius:18px; background:var(--card); box-shadow:var(--row-shadow); }
.ib-mini + .ib-mini { margin-top:8px; }
.ib-mini .d { width:40px; flex:none; text-align:center; }
.ib-mini .d small { display:block; font:700 11px/1.2 var(--sans); letter-spacing:.04em; color:var(--muted); }
.ib-mini .d b { font:800 20px/1.05 var(--sans); }
.ib-mini .m { flex:1; min-width:0; display:flex; flex-direction:column; gap:1px; }
.ib-mini .m b { font:700 16px/1.3 var(--sans); }
.ib-mini .s { display:flex; align-items:center; gap:6px; font-size:14px; color:var(--muted); }
.ib-mini time { font-size:13px; color:var(--muted-2); white-space:nowrap; }
.ib-foot { flex-direction:column; align-items:stretch; gap:0; margin-top:10px; }
.ib-foot .quote { margin:0; }
.ib-foot .e1-act { margin:6px 0 -10px; }
.card .ib-mini { margin-top:8px; padding:10px 12px; background:var(--lift); box-shadow:none; }
/* the moves: the edges nudge once, the first time this phone sees a stack; an opened stack drops its
   rows in, 40 ms apart; a closed one settles back into place */
.ib-stack.hint { --nudge:1.1s; --nudge-at:500ms; }
.ib-stack.hint .ib-ly1 { animation:ib-nudge1 var(--nudge) cubic-bezier(.3,.7,.3,1) var(--nudge-at) both; }
.ib-stack.hint .ib-ly2 { animation:ib-nudge2 var(--nudge) cubic-bezier(.3,.7,.3,1) var(--nudge-at) both; }
@keyframes ib-nudge1 { 0%, 100% { transform:translateY(0) scaleX(.94); } 35% { transform:translateY(5px) scaleX(.94); } }
@keyframes ib-nudge2 { 0%, 100% { transform:translateY(0) scaleX(.87); } 35% { transform:translateY(10px) scaleX(.87); } }
.ib-stack .front.settle { --settle:300ms; animation:ib-settle var(--settle) cubic-bezier(.2,.8,.2,1) both; }
@keyframes ib-settle { from { transform:translateY(8px) scale(.985); opacity:.6; } to { transform:none; opacity:1; } }
.ib-stack.open .ib-mini { --drop:320ms; --drop-step:40ms; animation:ib-drop var(--drop) cubic-bezier(.2,.8,.2,1) calc(var(--i, 0) * var(--drop-step)) both; }
@keyframes ib-drop { from { opacity:0; transform:translateY(-16px) scale(.97); } to { opacity:1; transform:none; } }
/* reduced motion: every load-in and loop stops, drawn at rest */
@media (prefers-reduced-motion: reduce) {
    .hub.enter .big-title, .hub.enter .tile, .hub.enter .tile-glyph, .hub.enter .tdot, .hub .hand-m, .hub .hand-h,
    .hub span.glyph svg, .spark, .cu-tick, .e1.arrive { animation:none !important; }
    .cu-tick path { animation:none !important; stroke-dashoffset:0; }
    .card { transition:none !important; }
}

/* ============================================================================
   Me, refreshed (Haoming's prototype ME4c, 2026-10-19): the badge hangs in a
   navy sky that runs under the status bar; the record card behind it slides
   out from under the badge and tucks back; Settings below on the ground.
   ========================================================================= */
.me-page { padding-bottom:8px; }
.me-sky { position:relative; margin:calc(-40px - env(safe-area-inset-top)) -24px 0; padding:env(safe-area-inset-top) 0 92px;
          background:var(--me-sky); border-radius:0 0 32px 32px; overflow:hidden; display:flex; flex-direction:column; align-items:center; }
.me-title { position:absolute; left:24px; top:calc(26px + env(safe-area-inset-top)); margin:0; font:800 34px/1 var(--sans);
            letter-spacing:-.03em; color:#fff; z-index:3; }
.me-drop { width:100%; display:flex; flex-direction:column; align-items:center; transform-origin:50% 0; }
.me-strap { width:34px; height:58px; background:var(--brand); display:flex; justify-content:center; overflow:hidden; }
.me-strap span { writing-mode:vertical-rl; padding-top:6px; font:800 9px/1 var(--sans); letter-spacing:.32em; color:var(--me-sky); white-space:nowrap; }
.me-clip { position:relative; z-index:3; width:28px; height:22px; margin-top:-6px; border-radius:6px; background:var(--clip); box-shadow:inset 0 -3px 0 var(--clip-shade); }
.me-stage { position:relative; width:300px; margin-top:-10px; height:410px; transition:height 700ms cubic-bezier(.3,1.1,.5,1);
            clip-path:inset(0 -100% -100% -100%); }   /* nothing of the card above the badge's top, however tall it grows (2026-10-26) */
.me-sky.open .me-stage { height:calc(418px + var(--rec-h, 340px) + 6px); }
.me-badge { position:relative; z-index:2; height:400px; border-radius:24px; background:var(--mb-card); box-shadow:var(--mb-shadow);
            overflow:hidden; display:flex; flex-direction:column; align-items:center; color:var(--ink); }
.mb-band { width:100%; height:84px; padding-top:14px; background:var(--brand); display:flex; flex-direction:column; align-items:center; gap:12px; }
.mb-slot { width:44px; height:8px; border-radius:4px; background:var(--me-sky); }
.me-badge .mb-logo { width:118px; height:26px; background:#1f314e; }
.mb-face { margin-top:20px; width:88px; height:88px; border-radius:26px; background:var(--mb-face); display:flex; align-items:center; justify-content:center;
           font:800 30px/1 var(--sans); }
.mb-name { margin:14px 0 0; padding:0 20px; font:800 20px/1.2 var(--sans); letter-spacing:-.02em; text-align:center; }
.mb-full { margin:2px 0 0; padding:0 20px; font-size:13px; color:var(--muted-2); text-align:center; }
.mb-grade { margin:4px 0 0; font-size:14px; color:var(--muted); }
.mb-reg { margin:auto 0 18px; padding:8px 14px; border-radius:12px; background:var(--mb-pill); display:flex; gap:8px; align-items:baseline; }
.mb-reg span { font:800 10px/1 var(--sans); letter-spacing:.1em; text-transform:uppercase; color:var(--muted-2); }
.mb-reg b { font:800 13px/1 var(--sans); }
.mb-stripe { width:100%; height:8px; margin-top:auto; background:var(--brand); flex:none; }
.mb-reg + .mb-stripe { margin-top:0; }
/* the record card: behind the badge, a 10 px sliver showing — its top set from its own height
   (`--rec-h`, measured by the page's script; 340 px until then), so the sliver is the same whatever
   the card holds (Haoming, 2026-10-26: Sister's seventh row, Rostered, had pushed the card's foot
   line into view); out, below the badge, a touch askew — the way out is that height plus the 8 px
   drop, so it lands where it always did. Never anchored to the stage's bottom: the stage grows as
   the card comes out, and the card went with it. */
.me-record { position:absolute; left:6px; right:6px; top:calc(410px - var(--rec-h, 340px)); z-index:1; min-height:340px; border-radius:22px; background:var(--rec);
             box-shadow:0 20px 44px rgba(0,0,0,.3); display:flex; flex-direction:column; color:var(--ink);
             transform:translateY(0); transform-origin:50% 0; transition:transform 700ms cubic-bezier(.3,1.3,.5,1); }
.me-sky.open .me-record { transform:translateY(calc(var(--rec-h, 340px) + 8px)) rotate(-1.5deg); }
.rec-head { display:flex; align-items:center; justify-content:space-between; padding:14px 18px 6px; }
.rec-kicker { font:800 11px/1 var(--sans); letter-spacing:.22em; text-transform:uppercase; color:var(--rec-meta); }
.rec-slot { width:40px; height:7px; border-radius:4px; background:var(--me-sky); }
.rec-rows { margin:0; padding:0 18px; }
.rec-row { display:flex; align-items:center; justify-content:space-between; gap:12px; min-height:42px; border-top:1px solid var(--rec-line); }
.rec-row:first-child { min-height:50px; border-top:0; }
.rec-row dt { font-size:14px; color:var(--muted); }
.rec-row dd { margin:0; display:flex; flex-direction:column; align-items:flex-end; text-align:right; font:800 14px/1.3 var(--sans); }
.rec-row dd:has(.rec-tick) { flex-direction:row; align-items:center; gap:6px; }
/* a long value (Haoming, 2026-11-10: an email ran off the card): the label keeps its width, the value sits on
   one line in a window; one wider than it (`cut`, set by the page's script) ends in "…" over the card's own
   colour and takes a tap, which slides the whole text along until its end shows (`end`), the "…" now at the
   start; a second tap slides it back. The row never changes height. */
.rec-row dt { flex:none; }
.rec-row dd { min-width:0; }
.rec-clip { position:relative; display:block; max-width:100%; overflow:hidden; white-space:nowrap; }
.rec-run { display:inline-block; vertical-align:top; --slide:420ms; transition:transform var(--slide) var(--ease-out); }
.rec-row:has(.rec-clip.cut) { cursor:pointer; -webkit-tap-highlight-color:transparent; }   /* the whole row takes the tap */
.rec-clip.cut.end .rec-run { transform:translateX(var(--shift, 0px)); }
.rec-clip.cut::before, .rec-clip.cut::after { content:"…"; position:absolute; top:0; bottom:0; z-index:1; --dots:200ms;
    transition:opacity var(--dots) var(--ease-out); }
.rec-clip.cut::after { right:0; padding-left:14px; background:linear-gradient(to right, transparent, var(--rec) 10px); }
.rec-clip.cut::before { left:0; padding-right:14px; background:linear-gradient(to left, transparent, var(--rec) 10px); opacity:0; }
.rec-clip.cut.end::after { opacity:0; }
.rec-clip.cut.end::before { opacity:1; }
.rec-blank { padding:2px 8px; border-radius:7px; border:1.5px dashed var(--rec-dash); font:600 12px/1.3 var(--sans); color:var(--rec-meta); }
.rec-tick { width:18px; height:18px; border-radius:50%; background:var(--me-sky); display:flex; align-items:center; justify-content:center; }
.rec-tick svg { width:10px; height:10px; stroke:#fff; }
.rec-note { font:800 11px/1.3 var(--sans); color:var(--amber-ink); }
.rec-note.urgent { color:var(--danger); }
.rec-foot { margin:auto 0 0; padding:10px 18px 14px; font-size:12px; color:var(--rec-meta); }
/* the pull */
.me-pull { position:absolute; left:0; right:0; bottom:22px; margin:0 auto; width:max-content; min-height:48px; padding:0 20px; border:0;
           border-radius:14px; background:rgba(255,255,255,.12); color:#fff; font:800 15px/1 var(--sans); display:flex; align-items:center;
           gap:10px; white-space:nowrap; cursor:pointer; }
.me-pull svg { width:18px; height:18px; stroke:var(--me-arrow); transition:transform 300ms ease; }
.me-sky.open .me-pull svg { transform:rotate(180deg); }
.me-pull:focus-visible { outline:3px solid var(--brand); outline-offset:4px; }
/* Settings, on the ground */
.me-group { margin:22px 4px 10px; font:700 13px/1 var(--sans); letter-spacing:.08em; text-transform:uppercase; color:var(--muted-2); }
.me-card { padding:0 16px; border-radius:18px; background:var(--card); box-shadow:var(--row-shadow); }
.me-card form { margin:0; }
.me-row { display:flex; align-items:center; justify-content:space-between; gap:12px; width:100%; min-height:54px; padding:0;
          border:0; border-top:1px solid var(--line-soft); background:none; color:var(--ink); font:600 15px/1.2 var(--sans);
          text-decoration:none; text-align:left; cursor:pointer; }
.me-card > .me-row:first-child { border-top:0; }
.me-val { display:flex; align-items:center; gap:6px; font-weight:400; color:var(--muted-2); }
.me-val svg { width:18px; height:18px; color:var(--chevron); }
.me-out { color:var(--danger); font-weight:700; }
/* on a load: the badge drops on its lanyard, the pull fades in, the arrow nudges while tucked away */
@keyframes me-drop { 0% { transform:translateY(-160px) rotate(-4deg); opacity:0; } 45% { opacity:1; } 60% { transform:translateY(12px) rotate(2deg); }
                     78% { transform:translateY(-5px) rotate(-1deg); } 92% { transform:translateY(2px) rotate(.4deg); } 100% { transform:none; } }
@keyframes me-fade { from { opacity:0; transform:translateY(6px); } to { opacity:1; transform:none; } }
@keyframes me-nudge { 0%,80%,100% { transform:translateY(0); } 88% { transform:translateY(4px); } 94% { transform:translateY(-1px); } }
.me-drop { animation:me-drop 1100ms cubic-bezier(.22,1,.36,1) both; }
.me-pull { animation:me-fade 450ms ease-out 900ms both; }
.me-sky:not(.open) .me-pull svg { animation:me-nudge 3.2s ease-in-out 1.6s infinite; }
@media (prefers-reduced-motion: reduce) {
    .me-drop, .me-pull, .me-pull svg { animation:none !important; }
    .me-stage, .me-record, .me-pull svg, .rec-run, .rec-clip::before, .rec-clip::after { transition:none !important; }
}

/* ============================================================================
   Claimed time's bank and Record (Haoming's design c-roster-claimed-time,
   2026-10-19): the bank card in Claimed time's pink with the clock drawn in
   the corner; Record's shift rows, the shift chip in Sister's fills; the
   finish-time wheel opening at the rostered end. All `ct-`, scoped.
   ========================================================================= */
.ct-bank { position:relative; overflow:hidden; margin:0 0 14px; padding:16px 18px 18px; border-radius:22px; background:var(--tile-pink);
           display:flex; flex-direction:column; gap:4px; color:var(--ink); --glyph:var(--glyph-pink); }
.ct-bank > :not(.ct-bank-glyph) { position:relative; }
.ct-bank-glyph { position:absolute; right:-22px; bottom:-26px; width:128px; height:128px; }
.ct-bank-top { display:flex; align-items:center; justify-content:space-between; gap:10px; }
.ct-bank-link { display:inline-flex; align-items:center; gap:2px; min-height:32px; font:700 14px/1 var(--sans); color:var(--ink); text-decoration:none; }
.ct-bank-link svg { width:16px; height:16px; }
.ct-bank-label { margin:0; font:800 13px/1.2 var(--sans); letter-spacing:.06em; text-transform:uppercase; color:var(--muted); }
.ct-bank-big { margin:0; font:800 34px/1.05 var(--sans); letter-spacing:-.03em; font-variant-numeric:tabular-nums; }
.ct-bank-big small { margin-left:4px; font:700 15px/1 var(--sans); letter-spacing:0; color:var(--muted); }
.ct-bank-line { margin:2px 0 0; max-width:250px; display:flex; align-items:center; gap:7px; font-size:14px; color:var(--muted); }
.ct-bank-line svg { width:16px; height:16px; flex:none; }
.ct-pane { display:flex; flex-direction:column; gap:12px; }
.ct-shifts { display:flex; flex-direction:column; overflow:hidden; border-radius:18px; background:var(--card); box-shadow:inset 0 0 0 1px var(--line); }
.ct-shift { width:100%; min-height:68px; padding:12px 16px; border:0; background:transparent; display:flex; align-items:center; gap:14px;
            text-align:left; color:var(--ink); font:inherit; }
.ct-shift + .ct-shift { border-top:1px solid var(--line); }
.ct-shift.pick { cursor:pointer; }
.ct-shift.pick[aria-pressed="true"] { background:var(--chip-blue); }
.ct-chip { width:44px; height:44px; flex:none; border-radius:13px; display:flex; align-items:center; justify-content:center;
           font:800 13px/1 var(--sans); color:var(--shift-ink); }
.ct-chip.am { background:var(--am-fill); }
.ct-chip.pm { background:var(--pm-fill); }
.ct-chip.d24 { background:linear-gradient(135deg, var(--am-fill) 50%, var(--pm-fill) 50%); }
.ct-main { flex:1; min-width:0; display:flex; flex-direction:column; align-items:flex-start; gap:2px; }
.ct-day { font:800 16px/1.25 var(--sans); }
.ct-sub { font-size:13px; color:var(--muted); }
.ct-sub.last { color:var(--amber-ink); font-weight:700; }
.ct-back { margin-top:2px; font-size:13px; }
.ct-why { margin-top:2px; font-size:13px; color:var(--ink); }
.ct-radio { width:24px; height:24px; flex:none; border-radius:50%; border:2px solid var(--muted-2); display:flex; align-items:center; justify-content:center; }
.ct-shift[aria-pressed="true"] .ct-radio { border-color:var(--ink); background:var(--ink); }
.ct-shift[aria-pressed="true"] .ct-radio::after { content:""; width:8px; height:8px; border-radius:50%; background:var(--bg); }
.ct-status { display:flex; flex-direction:column; align-items:flex-end; gap:4px; }
.ct-state { display:inline-flex; align-items:center; height:24px; padding:0 9px; border-radius:999px; font:800 12px/1 var(--sans);
            background:var(--chip-blue); color:var(--ink); white-space:nowrap; }
.ct-state.approved { background:var(--positive-soft); color:var(--positive); }
.ct-state.rejected { background:var(--danger-soft); color:var(--danger); }
.ct-amt { font:800 15px/1 var(--sans); font-variant-numeric:tabular-nums; }
.ct-amt.struck { text-decoration:line-through; color:var(--muted-2); font-weight:600; }
.ct-empty { display:flex; align-items:center; gap:14px; padding:18px; border-radius:18px; border:1.5px dashed var(--line);
            font-size:15px; line-height:1.4; color:var(--muted); }
.ct-empty svg { width:18px; height:18px; flex:none; }
.ct-hint { margin:0 2px; font-size:14px; line-height:1.4; color:var(--muted); }
.ct-hint[hidden] { display:none; }
.ct-picker { display:flex; flex-direction:column; gap:12px; padding:16px; border-radius:22px; background:var(--card); box-shadow:inset 0 0 0 1px var(--line);
             animation:ct-reveal 300ms cubic-bezier(.22,1,.36,1) both; }
.ct-picker[hidden] { display:none; }
@keyframes ct-reveal { from { opacity:0; transform:translateY(-8px) scale(.98); } to { opacity:1; transform:none; } }
.ct-q { margin:0; font:800 17px/1.2 var(--sans); }
.ct-wheels { position:relative; height:200px; display:flex; align-items:center; justify-content:center; gap:6px; }
.ct-band { position:absolute; left:0; right:0; top:80px; height:40px; border-radius:12px; background:var(--chip-blue); pointer-events:none; }
.ct-wheel { position:relative; width:84px; height:200px; overflow-y:scroll; scroll-snap-type:y mandatory; scrollbar-width:none; border-radius:12px;
            -webkit-mask:linear-gradient(transparent, #000 30%, #000 70%, transparent); mask:linear-gradient(transparent, #000 30%, #000 70%, transparent); }
.ct-wheel::-webkit-scrollbar { display:none; }
.ct-wheel div { height:40px; display:flex; align-items:center; justify-content:center; font:700 24px/1 var(--sans); font-variant-numeric:tabular-nums;
                scroll-snap-align:center; color:var(--ink); }
.ct-wheel .pad { scroll-snap-align:none; }
.ct-colon { position:relative; font:800 24px/1 var(--sans); }
.ct-ot { display:flex; align-items:center; justify-content:space-between; gap:10px; padding:12px 14px; border-radius:16px; background:var(--tile-pink); }
.ct-ot-big { font:800 28px/1 var(--sans); letter-spacing:-.02em; font-variant-numeric:tabular-nums; }
.ct-ot-sub { font-size:13px; color:var(--muted); text-align:right; }
.ct-ot.zero { font:700 15px/1.3 var(--sans); color:var(--muted); }
.ct-field { width:100%; min-height:50px; box-sizing:border-box; padding:0 16px; border:0; border-radius:14px; background:var(--lift);
            font:400 16px/1.2 var(--sans); color:var(--ink); }
.ct-field::placeholder { color:var(--muted-2); }
.ct-btn { width:100%; height:52px; border:0; border-radius:14px; background:var(--navy-btn); color:var(--on-navy); font:700 16px/1 var(--sans); cursor:pointer; }
.ct-btn:disabled { opacity:.4; cursor:default; }
.ct-say { min-height:20px; margin:0 2px; font-size:14px; font-weight:600; color:var(--ink); }
.ct-say:empty { display:none; }
.ct-say.no { color:var(--danger); }
@media (prefers-reduced-motion: reduce) { .ct-picker { animation:none; } }

/* Claimed time's spend (pass two, 2026-10-19): the cost above the button, or the refusal in its place */
.ct-cost { margin:0 2px 10px; font-size:14px; color:var(--muted); }
.ct-cost b { color:var(--ink); }
.ct-cost[hidden], .ct-refusal[hidden], #claim-send .primary[hidden] { display:none; }
.ct-refusal { display:flex; gap:12px; align-items:flex-start; padding:14px 16px; border-radius:16px; background:var(--danger-soft);
              animation:fade-in 240ms var(--ease-out) both; }
.ct-refusal svg { width:22px; height:22px; flex:none; color:var(--danger); }
.ct-refusal > span { font-size:14px; line-height:1.4; color:var(--ink); }
.ct-refusal b { display:block; margin-bottom:2px; font-size:15px; color:var(--danger); }
/* the bank's history: month headings over a card of lines */
.ct-month { margin:22px 4px 8px; font:800 13px/1 var(--sans); letter-spacing:.08em; text-transform:uppercase; color:var(--muted-2); }
.ct-lines { overflow:hidden; border-radius:18px; background:var(--card); box-shadow:inset 0 0 0 1px var(--line); }
.ct-line { display:flex; gap:12px; align-items:flex-start; padding:14px 16px; }
.ct-line + .ct-line { border-top:1px solid var(--line); }
.ct-ico { width:36px; height:36px; flex:none; border-radius:11px; display:flex; align-items:center; justify-content:center;
          background:var(--chip-blue); color:var(--ink); }
.ct-ico.pink { background:var(--tile-pink); }
.ct-ico svg { width:18px; height:18px; }
.ct-quote { margin-top:4px; padding:10px 12px; border-radius:12px; background:var(--ground); font-size:14px; line-height:1.4; color:var(--ink); }
.ct-quote small { display:block; margin-top:3px; font-size:12px; color:var(--muted-2); }
.ct-history .ct-empty { margin-top:18px; }
@media (prefers-reduced-motion: reduce) { .ct-refusal { animation:none; } }
.card-amt { position:relative; margin:4px 0 0; font:800 34px/1.05 var(--sans); letter-spacing:-.03em; font-variant-numeric:tabular-nums; }
.card-amt.struck { font-size:28px; font-weight:600; text-decoration:line-through; color:var(--muted-2); }   /* a declined recording's minutes */

/* ============================================================================
   Claimed time in Haoming's design (c-roster-claimed-time, 2026-10-19), the
   whole screen: the title row with ⓘ, the switch, the from–to boxes, the
   circles, the stepper, the note, the button and the requests as bank lines.
   Scoped to its page (`.page.ct`), so the other pickers keep their look.
   ========================================================================= */
.title-row { display:flex; align-items:center; justify-content:space-between; gap:8px; margin:0 0 14px; }
.title-row .title { margin:0; font-weight:800; font-size:34px; line-height:1.05; letter-spacing:-.03em; }
.info-btn { width:44px; height:44px; margin-right:-8px; padding:0; border:0; border-radius:50%; background:transparent;
               color:var(--muted); display:flex; align-items:center; justify-content:center; cursor:pointer; }
.info-btn svg { width:24px; height:24px; }
.info-btn[aria-expanded="true"] { color:var(--ink); }
.info-card { margin:-6px 0 14px; padding:14px 16px; border-radius:18px; background:var(--card); box-shadow:inset 0 0 0 1px var(--line);
           display:flex; flex-direction:column; gap:10px; animation:ct-reveal 260ms cubic-bezier(.22,1,.36,1) both; }
.info-card[hidden] { display:none; }
.info-card p { margin:0; font-size:15px; line-height:1.4; }
.info-card ul { margin:0; padding:0; list-style:none; display:flex; flex-direction:column; gap:8px; }
.info-card li { display:flex; gap:10px; align-items:flex-start; font-size:14px; line-height:1.35; color:var(--muted); }
.info-card li svg { width:18px; height:18px; flex:none; margin-top:1px; color:var(--ink); }
.ct .seg { gap:4px; margin:0 0 14px; padding:4px; border-radius:14px; background:var(--track); box-shadow:inset 0 0 0 1px var(--field-edge); }
.ct .seg-opt { height:40px; padding:0; border-radius:11px; font:700 15px/1 var(--sans); }
.ct .seg-opt.on { background:var(--soft-btn); box-shadow:0 1px 3px var(--sheet-shadow); }
.picker .readback { gap:12px; margin:0 0 14px; }   /* the from–to cards, every picker (2026-10-22) */
.picker .rb { min-height:72px; padding:12px 16px; border-radius:18px; background:var(--card); box-shadow:inset 0 0 0 1.5px var(--line); }
.picker .rb.next { box-shadow:inset 0 0 0 2.5px var(--ink); }
.picker .rb-value { margin-top:2px; font:700 19px/1.2 var(--sans); }
.picker .rb-value.empty { font-weight:500; color:var(--muted-2); }
.ct .mname { font:800 22px/1 var(--sans); letter-spacing:-.02em; }
.ct .cal-nav { width:44px; height:44px; color:var(--ink); font-size:22px; }
.ct .cal-nav:disabled { color:var(--chevron); }
.ct .cd.today::before { box-shadow:inset 0 0 0 2px var(--ink); }
.ct .cd .cap { background:var(--ink); }
.ct .cd.start .n, .ct .cd.end .n, .ct .cd.pending .n { color:var(--card); }
.ct .band { background:var(--chip-blue); }
.ct .cd .marks { bottom:2px; }
.ct .cd .mark { width:6px; height:6px; }
.ct .dot.d24 { background:linear-gradient(90deg, var(--am-fill) 50%, var(--pm-fill) 50%); }
.ct .claim-say { margin:12px 2px 0; font-size:14px; font-weight:700; color:var(--ink); }
.ct .note-wrap { margin-top:12px; }
.ct .note-field { background:var(--field); box-shadow:inset 0 0 0 1px var(--field-edge); }
.ct #claim-send .primary { min-height:52px; margin-top:0; border-radius:14px; background:var(--navy-btn); color:var(--on-navy); font:700 16px/1 var(--sans); }
.ct .send-slot { margin-top:12px; }
/* Leave early's stepper: five minutes a tap, the time they would leave under it */
.ct-stepper { display:flex; align-items:center; justify-content:space-between; margin:12px 0 0; padding:10px 12px; border-radius:18px;
              background:var(--card); box-shadow:inset 0 0 0 1px var(--line); }
.ct-stepper[hidden] { display:none; }
.ct-step { width:44px; height:44px; padding:0; border:0; border-radius:50%; background:var(--chip-blue); color:var(--ink); font:700 22px/1 var(--sans); cursor:pointer; }
.ct-step:disabled { opacity:.35; cursor:default; }
.ct-step-val { text-align:center; }
.ct-step-val b { display:block; font:800 22px/1.2 var(--sans); font-variant-numeric:tabular-nums; }
.ct-step-val span { font-size:13px; color:var(--muted); }
/* the requests as bank lines, under the design's row */
.ct-reqs > summary, .ct-reqs.empty { min-height:56px; padding:0 2px; }
.ct-reqs .reqs-title { font:800 19px/1.2 var(--sans); }
ul.ct-lines { margin:0 0 12px; padding:0; list-style:none; }
.ct-state.withdrawn { background:var(--line-soft); color:var(--muted); }
/* switching Record · Day off · Leave early fades the new side in (the design's `fade`) */
.ct .pane.switched { --pane-in:240ms; animation:ct-pane-in var(--pane-in) ease both; }
@keyframes ct-pane-in { from { opacity:0; transform:translateY(6px); } to { opacity:1; transform:none; } }
@media (prefers-reduced-motion: reduce) { .info-card, .ct .pane.switched { animation:none; } }

/* ============================================================================
   Rest days in Haoming's design (c-roster-rest-days, sample A, 2026-10-19):
   the title with ⓘ, the count as dots, the WORK rail, the days as rings and
   fills with no R, the legend, the 52 px navy button. Scoped to its page
   (`.page.rd`); the chips, the banner, the closed month and every motion
   stay as they were (his answers, the same day).
   ========================================================================= */
.info-card li .k { flex:none; min-width:18px; text-align:center; font-weight:800; color:var(--ink); }
.info-card li .k .dot.ph { display:inline-block; width:6px; height:6px; border-radius:3px; vertical-align:2px; background:var(--ph); }
.rd .title-row { margin-bottom:14px; }
.rd .mname { font:800 22px/1 var(--sans); letter-spacing:-.02em; }
.rd .count { display:inline-flex; align-items:center; font-weight:800; font-size:15px; }
.rd #rest-count { display:inline-flex; align-items:center; gap:8px; }
.rd-dots { display:inline-flex; gap:6px; }
.rd-dot { display:inline-block; width:14px; height:14px; border-radius:50%; box-sizing:border-box; }
.rd-dot.free { border:1.5px solid var(--chevron); }
.rd-dot.picked { border:1.5px dashed var(--ink); }
.rd-dot.waiting { border:2px solid var(--ink); }
.rd-dot.approved { background:var(--ink); }
.rd-dot.pop { animation:dot-pop 320ms var(--ease-spring-soft); }
.legend .rd-dot { width:12px; height:12px; }
.rd .dow.rail, .rd .grid.rail { grid-template-columns:30px repeat(7, 1fr); }
.rd .dow .work { font:700 10px/1 var(--sans); letter-spacing:.04em; text-align:left; }
.rd .wk { font:700 13px/1 var(--sans); color:var(--muted-2); font-variant-numeric:tabular-nums; }
/* the days: picked a dashed ring, waiting a solid one, approved filled — all in ink */
.rd .c.pick::after { border-color:var(--ink); }
.rd .c.pick .ro { border:2.5px solid var(--ink); }
.rd .c.pick.free.marked { color:var(--ink); }
.rd .c.pick.free.marked .n, .rd .c.pick.waiting .n, .rd .c.pick.held .n { font-weight:700; }
.rd .c.pick.held { background:var(--ink); color:var(--card); }
.rd .send .primary { min-height:52px; border-radius:14px; background:var(--navy-btn); color:var(--on-navy); font:700 16px/1 var(--sans); }
.rd .send.done .primary { background:var(--done); color:var(--on-done); }
