/* ============================================================
   domwell — tokens + components (mirrors ../design/domwell-ds/DESIGN-SYSTEM.md)
   Light tokens on :root, dark on [data-theme="dark"] (any ancestor) or prefers-color-scheme.
   Class names are kept from the previous system so the views keep working; their styling is new.
   v3 (design/DOMWELL-V3.md) layers three rules on top: ink = "do this" (one primary per screen,
   the today marker, the `me` avatar); brass tint (--select) = "you are here" for every selected
   state; lists live in bordered boxes (.lbox) with inset hairlines — this replaces the older
   "whitespace divides rows, no hairlines" rule. Radii shrink to 6/12/16/24/pill.
   ============================================================ */

/* ---------- fonts (self-hosted variable files; Latin + Latin-Ext for ą ć ę ł ń ó ś ź ż) ---------- */
@font-face{font-family:"Outfit";font-style:normal;font-weight:100 900;font-display:swap;src:url(/fonts/outfit-latin-ext.woff2) format("woff2");unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}
@font-face{font-family:"Outfit";font-style:normal;font-weight:100 900;font-display:swap;src:url(/fonts/outfit-latin.woff2) format("woff2");unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
@font-face{font-family:"Manrope";font-style:normal;font-weight:200 700;font-display:swap;src:url(/fonts/manrope-latin-ext.woff2) format("woff2");unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}
@font-face{font-family:"Manrope";font-style:normal;font-weight:200 700;font-display:swap;src:url(/fonts/manrope-latin.woff2) format("woff2");unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}

/* ---------- tokens ---------- */
:root{
  /* grounds. v3: --paper is the page, --box the list-box/card plane that sits on it (the same white
     in light; one step up in dark), --canvas the desktop rail. --plaster/--plaster-2 are one step
     lighter than before and are the --surface-2/--surface-3 fills (chips, hover, box headers). */
  --paper:#FFFFFF; --box:#FFFFFF; --canvas:#FAF8F5; --plaster:#F3F0EA; --plaster-2:#E9E4DB; --hair:var(--line);
  /* --line is the one visible 1px line (box edges, dividers, rims); --field-border the input border and
     check ring, 3.6:1 on white (non-text needs 3:1) */
  --line:#E5E0D6; --field-border:#8F8679;
  /* selection: the brass-tinted "you are here" ground, with an optional 1px inner line on chips */
  --select:#F4EBDA; --select-line:#E3CFA8;
  /* elevation: --shadow-card is the only shadow a box/card may carry (none in dark); --shadow-thumb the
     raised segmented thumb; --shadow-float is for floating things only (FAB, toast, sheet, dialog) */
  --shadow-card:0 1px 2px rgba(28,25,23,.05);
  --shadow-thumb:0 1px 2px rgba(28,25,23,.14),0 0 0 1px rgba(28,25,23,.06);
  --shadow-float:0 10px 28px rgba(28,25,23,.18),0 2px 6px rgba(28,25,23,.10);
  /* avatar / project-disc tint recipe (§2.9): ground = --pc at --tint over --box, initials = --pc at 72%
     toward --tint-ink. Measured >= 5.9:1 for all 50 --house-N and the neutral fallback, both themes. */
  --tint:18%; --tint-ink:#000;
  /* ink */
  --ink:#1C1917; --ink-2:#4E4842; --ink-3:#635C54;
  /* brass states facts, never actions */
  --brass:#A07D3E; --brass-text:#7A5D2A; --brass-halo:rgba(160,125,62,.18); --brass-fill:#E8C87A; --brass-fill-on:#1C1917;
  /* two semantic hues */
  --clay:#A8392A; --clay-soft:#FBE9E5; --moss:#3D6B45; --moss-soft:#E5F0E3;
  /* inversion */
  --inverse-bg:#1C1917; --inverse-ink:#F4F1EA; --scrim:rgba(28,25,23,.45); --focus:#1C1917;
  /* The rim: where two surfaces OVERLAP — the sticky app bar, the sticky filter bar, the fixed
     total bar, a floating sheet/dialog over the scrim, and the sheet's commit footer. v3: it is
     now simply --line (rows are divided by the list box's hairlines, so the rim is no longer the
     app's only line; it is the same line). --rim-strong stays for the dark sheet edge.
     --e-float is the floating-surface elevation, i.e. --shadow-float (dark carries a 1px light
     ring in it, so a sheet on the scrim keeps an edge). --e-1/2/3 stay `none`. */
  --rim:var(--line); --rim-strong:rgba(28,25,23,.16);
  --e-float:var(--shadow-float);
  /* ---------- the layer scale. Every z-index in the app is one of these ten steps and nothing
     declares a bare number. Two reasons it has to be tokens and not numbers: a raw z-index is a
     claim about the WHOLE app made from inside one view, and view CSS is injected into <head>,
     so the claim lands everywhere that class appears; and at equal z-index the later element in
     DOM order wins — the tab bar is rendered into .nav-slot BEFORE <main>, so for anything in the
     page a tie with the chrome is a LOSS. That is exactly how .cg-now (3) came to paint over
     .tabbar (3) on a phone, which is the bug this scale was cut for.
     Ten apart, so a future element slots between two tiers without renumbering anything.

       --z-base     order inside one component: the month cell's paint under its day number
       --z-raised   the sibling that lifts: a hovered calendar block
       --z-marker   a rule drawn across content: the current-time line, the today line. Above the
                    blocks it crosses, below the head it scrolls under.
       --z-sticky   a head that pins while its own content scrolls: .filterbar, .subnav, .cg-top,
                    the board's .bhead
       --z-drag     the element under the pointer. BELOW the chrome, deliberately — see below.
       --z-float    fixed furniture floating over the page: the FAB, the running-total bar
       --z-chrome   the frame itself: the app bar and the tab bar / side rail. Nothing in the
                    page may tie this, let alone beat it.
       --z-popover  a fields.js dropdown / calendar popover (fixed-positioned). Above the chrome,
                    below the scrim: on a page, a sheet opened over it covers it. INSIDE an overlay
                    (.sheet, .dialog, .fdlg all set z-index, so each is a stacking context) the
                    value is local to that overlay — the popover paints over the dialog's own body
                    and footer, and under anything opened on top of the dialog.
       --z-scrim    the dim behind an overlay
       --z-overlay  .sheet, .dialog and the laptop form dialog .fdlg
       --z-toast    #toasts — over everything, including an open sheet

     Why a drag sits UNDER the chrome: the tab bar is fixed furniture, so a card that slides
     beneath it reads as a card passing behind a bar; a card floating OVER the navigation reads
     as a broken app. Nothing functional argues the other way — neither drag hit-tests with
     elementFromPoint (planner.js measures column rects, houses.js measures section rects, and
     both hold a pointer capture), so what paints on top has no bearing on where the entry lands.
     An element the finger is on can never be more important than the app's own frame. */
  --z-base:10; --z-raised:20; --z-marker:30; --z-sticky:40; --z-drag:50;
  --z-float:60; --z-chrome:70; --z-popover:75; --z-scrim:80; --z-overlay:90; --z-toast:100;
  /* identity colours 1–50 (HANDOFF v3 §4; generated by design/v3-ds/_palette.py — OKLCH, three lightness tiers,
     17 hues). --house-N paints a disc, bar or swatch — always beside its number, initials or name; --house-N-on is
     the only colour allowed as text on it. Never text on paper, never a state.
     PASTEL, client review 26.09 §6.5 ("zmienić paletę kolorów na bardziej pastelowe"): every tier lifted as far as
     the two hard rules allow and the chroma trimmed — tiers now L .655 / .560 / .505 at C .115 / .118 / .110 (was
     .64 / .52 / .40 at .13 / .125 / .10), so no colour in the set is dark any more. The COUNT is unchanged and must
     stay 50: houses.color, people.color and labels.color each carry CHECK (color BETWEEN 1 AND 50), and SQLite
     cannot alter a CHECK — changing the count is a three-table rebuild (migration 11), not an edit here.
     Measured after the change: swatch vs paper >= 3.39:1, vs plaster >= 3.00:1 (unchanged floors); initials on the
     swatch >= 4.51:1 light and >= 5.64:1 dark, both measured on the quantised hex that actually ships. */
  --house-1:#C97084; --house-1-on:var(--ink);
  --house-2:#6D7E1F; --house-2-on:var(--paper);
  --house-3:#006E95; --house-3-on:var(--paper);
  --house-4:#B176B7; --house-4-on:var(--ink);
  --house-5:#9B6900; --house-5-on:var(--paper);
  --house-6:#00746F; --house-6-on:var(--paper);
  --house-7:#8284D2; --house-7-on:var(--ink);
  --house-8:#AE5844; --house-8-on:var(--paper);
  --house-9:#33753D; --house-9-on:var(--paper);
  --house-10:#3C93C8; --house-10-on:var(--ink);
  --house-11:#A7557C; --house-11-on:var(--paper);
  --house-12:#6E6700; --house-12-on:var(--paper);
  --house-13:#009B9D; --house-13-on:var(--ink);
  --house-14:#895FA8; --house-14-on:var(--paper);
  --house-15:#90540F; --house-15-on:var(--paper);
  --house-16:#459A66; --house-16-on:var(--ink);
  --house-17:#5571BA; --house-17-on:var(--paper);
  --house-18:#9A484A; --house-18-on:var(--paper);
  --house-19:#8B9033; --house-19-on:var(--ink);
  --house-20:#007FA1; --house-20-on:var(--paper);
  --house-21:#8C4A7B; --house-21-on:var(--paper);
  --house-22:#B97E33; --house-22-on:var(--ink);
  --house-23:#008476; --house-23-on:var(--paper);
  --house-24:#6A569C; --house-24-on:var(--paper);
  --house-25:#CC7268; --house-25-on:var(--ink);
  --house-26:#4A833E; --house-26-on:var(--paper);
  --house-27:#3267A2; --house-27-on:var(--paper);
  --house-28:#C0719F; --house-28-on:var(--ink);
  --house-29:#877400; --house-29-on:var(--paper);
  --house-30:#007281; --house-30-on:var(--paper);
  --house-31:#9B7CC7; --house-31-on:var(--ink);
  --house-32:#A85F25; --house-32-on:var(--paper);
  --house-33:#00775A; --house-33-on:var(--paper);
  --house-34:#628CD2; --house-34-on:var(--ink);
  --house-35:#AE5461; --house-35-on:var(--paper);
  --house-36:#556F1F; --house-36-on:var(--paper);
  --house-37:#0097B4; --house-37-on:var(--ink);
  --house-38:#9B5994; --house-38-on:var(--paper);
  --house-39:#815E00; --house-39-on:var(--paper);
  --house-40:#099C83; --house-40-on:var(--ink);
  --house-41:#7267B5; --house-41-on:var(--paper);
  --house-42:#984C2F; --house-42-on:var(--paper);
  --house-43:#6C964B; --house-43-on:var(--ink);
  --house-44:#2E7AB5; --house-44-on:var(--paper);
  --house-45:#954763; --house-45-on:var(--paper);
  --house-46:#A58728; --house-46-on:var(--ink);
  --house-47:#00838C; --house-47-on:var(--paper);
  --house-48:#7D4F8E; --house-48-on:var(--paper);
  --house-49:#C6774C; --house-49-on:var(--ink);
  --house-50:#10865B; --house-50-on:var(--paper);
  /* type */
  --f-display:"Outfit","Poppins","Avenir Next","Futura",system-ui,sans-serif;
  --f-ui:"Manrope","Inter",system-ui,-apple-system,"Segoe UI",Roboto,sans-serif;
  /* space · radii · targets · motion */
  --s-1:4px; --s-2:8px; --s-3:12px; --s-4:16px; --s-5:24px; --s-6:32px; --s-7:48px; --s-8:64px; --s-9:96px;
  /* Dense tier (visual review §3.1-3.2). 2 / 6 / 10 are not drift: ~1,400 measured uses between
     them, and they are used where a 4px step is genuinely too coarse — a 2px gap between calendar
     cells, 6px inside a chip or a meta row, 10px inside a 64px row. The views were right and the
     scale was short, so the scale gains three half-steps rather than the views leaving it. */
  --s-h:2px; --s-1h:6px; --s-2h:10px;
  /* v3 radius scale 6 / 12 / 16 / 24 / pill — radius grows with the object (Primer 3/6/12, Atlassian
     containers <= 16). --r-chip (xs): labels, counters, calendar cells, gantt segments. --r-tile (md):
     inputs, search, row hover ground, notices. --r-panel (lg): list boxes, cards, panels, banners,
     dialogs. --r-sheet (xl): the bottom sheet's top corners. Pill: buttons, chips, segmented, FAB. */
  --r-pill:999px; --r-tile:12px; --r-panel:16px; --r-sheet:24px; --r-chip:6px;
  --r-xs:var(--r-chip); --r-md:var(--r-tile); --r-lg:var(--r-panel); --r-xl:var(--r-sheet);
  /* phone gutter 16 (was 20): a list box already adds 16px inner padding, so 20+16 wasted 36px of a
     390 screen. --row-inset follows it so a row outside a box lines its ring up with the gutter. */
  --tap:44px; --row:64px; --row-gap:4px; --group-gap:32px; --gutter:16px; --row-inset:16px;
  --dur-1:140ms; --dur-2:240ms; --dur-3:360ms;
  --ease-out:cubic-bezier(.2,.7,.2,1); --ease-in:cubic-bezier(.4,0,1,1);
  color-scheme:light;
}
[data-theme="dark"]{
  /* v3: the page goes one step deeper (#151311) so the box plane (#1D1A17) can rise above it */
  --paper:#151311; --box:#1D1A17; --canvas:#1A1714; --plaster:#26221E; --plaster-2:#312C27; --hair:var(--line);
  --line:#302A25; --field-border:#7D7468;
  --select:#3A3122; --select-line:#5A4A30;
  --shadow-card:none;
  --shadow-thumb:0 1px 2px rgba(0,0,0,.5),0 0 0 1px rgba(255,255,255,.08);
  --shadow-float:0 0 0 1px rgba(255,255,255,.10),0 14px 36px rgba(0,0,0,.55);
  --tint:22%; --tint-ink:#fff;
  --ink:#F2EEE7; --ink-2:#CFC7BB; --ink-3:#A39B8F;
  --brass:#C9A263; --brass-text:#D8B679; --brass-halo:rgba(201,162,99,.22); --brass-fill:#D8B679; --brass-fill-on:#1C1917;
  --clay:#EC8C7E; --clay-soft:#3D2420; --moss:#8FC497; --moss-soft:#22301F;
  --inverse-bg:#F2EEE7; --inverse-ink:#1C1917; --scrim:rgba(0,0,0,.6); --focus:#F2EEE7;
  --rim:var(--line); --rim-strong:rgba(242,238,231,.18);
  --e-float:var(--shadow-float);
  /* identity colours, dark solve (same hue/tier per number) */
  --house-1:#FFB4C3; --house-1-on:var(--paper);
  --house-2:#AABB6B; --house-2-on:var(--paper);
  --house-3:#3FA2D0; --house-3-on:var(--paper);
  --house-4:#EBB7F0; --house-4-on:var(--paper);
  --house-5:#D7A860; --house-5-on:var(--paper);
  --house-6:#18ADA5; --house-6-on:var(--paper);
  --house-7:#C3C7FF; --house-7-on:var(--paper);
  --house-8:#EC9884; --house-8-on:var(--paper);
  --house-9:#65AA6D; --house-9-on:var(--paper);
  --house-10:#97D5FF; --house-10-on:var(--paper);
  --house-11:#E595B8; --house-11-on:var(--paper);
  --house-12:#A29A3F; --house-12-on:var(--paper);
  --house-13:#79E0E1; --house-13-on:var(--paper);
  --house-14:#C59EE4; --house-14-on:var(--paper);
  --house-15:#C88647; --house-15-on:var(--paper);
  --house-16:#9ADFB0; --house-16-on:var(--paper);
  --house-17:#93AFF5; --house-17-on:var(--paper);
  --house-18:#D3797A; --house-18-on:var(--paper);
  --house-19:#CDD389; --house-19-on:var(--paper);
  --house-20:#5CBFE4; --house-20-on:var(--paper);
  --house-21:#C37BAF; --house-21-on:var(--paper);
  --house-22:#F5C186; --house-22-on:var(--paper);
  --house-23:#56C7B7; --house-23-on:var(--paper);
  --house-24:#9C88D5; --house-24-on:var(--paper);
  --house-25:#FFB7AE; --house-25-on:var(--paper);
  --house-26:#8DC281; --house-26-on:var(--paper);
  --house-27:#629ADB; --house-27-on:var(--paper);
  --house-28:#FAB3DB; --house-28-on:var(--paper);
  --house-29:#C3B25F; --house-29-on:var(--paper);
  --house-30:#19A9BE; --house-30-on:var(--paper);
  --house-31:#D8BEFF; --house-31-on:var(--paper);
  --house-32:#E59F6E; --house-32-on:var(--paper);
  --house-33:#3FAD8A; --house-33-on:var(--paper);
  --house-34:#AFCEFF; --house-34-on:var(--paper);
  --house-35:#EC959E; --house-35-on:var(--paper);
  --house-36:#86A353; --house-36-on:var(--paper);
  --house-37:#7EDCF6; --house-37-on:var(--paper);
  --house-38:#D898D1; --house-38-on:var(--paper);
  --house-39:#B8903A; --house-39-on:var(--paper);
  --house-40:#84E1C9; --house-40-on:var(--paper);
  --house-41:#AEA6F1; --house-41-on:var(--paper);
  --house-42:#D17E5F; --house-42-on:var(--paper);
  --house-43:#B4DA99; --house-43-on:var(--paper);
  --house-44:#76B8F1; --house-44-on:var(--paper);
  --house-45:#CF7895; --house-45-on:var(--paper);
  --house-46:#E4CA82; --house-46-on:var(--paper);
  --house-47:#4DC5CF; --house-47-on:var(--paper);
  --house-48:#B280C5; --house-48-on:var(--paper);
  --house-49:#FFBA97; --house-49-on:var(--paper);
  --house-50:#6EC69B; --house-50-on:var(--paper);
  color-scheme:dark;
}
@media (prefers-color-scheme: dark){
  :root:not([data-theme="light"]){
  /* v3: the page goes one step deeper (#151311) so the box plane (#1D1A17) can rise above it */
  --paper:#151311; --box:#1D1A17; --canvas:#1A1714; --plaster:#26221E; --plaster-2:#312C27; --hair:var(--line);
  --line:#302A25; --field-border:#7D7468;
  --select:#3A3122; --select-line:#5A4A30;
  --shadow-card:none;
  --shadow-thumb:0 1px 2px rgba(0,0,0,.5),0 0 0 1px rgba(255,255,255,.08);
  --shadow-float:0 0 0 1px rgba(255,255,255,.10),0 14px 36px rgba(0,0,0,.55);
  --tint:22%; --tint-ink:#fff;
  --ink:#F2EEE7; --ink-2:#CFC7BB; --ink-3:#A39B8F;
  --brass:#C9A263; --brass-text:#D8B679; --brass-halo:rgba(201,162,99,.22); --brass-fill:#D8B679; --brass-fill-on:#1C1917;
  --clay:#EC8C7E; --clay-soft:#3D2420; --moss:#8FC497; --moss-soft:#22301F;
  --inverse-bg:#F2EEE7; --inverse-ink:#1C1917; --scrim:rgba(0,0,0,.6); --focus:#F2EEE7;
  --rim:var(--line); --rim-strong:rgba(242,238,231,.18);
  --e-float:var(--shadow-float);
  /* identity colours, dark solve (same hue/tier per number) */
  --house-1:#FFB4C3; --house-1-on:var(--paper);
  --house-2:#AABB6B; --house-2-on:var(--paper);
  --house-3:#3FA2D0; --house-3-on:var(--paper);
  --house-4:#EBB7F0; --house-4-on:var(--paper);
  --house-5:#D7A860; --house-5-on:var(--paper);
  --house-6:#18ADA5; --house-6-on:var(--paper);
  --house-7:#C3C7FF; --house-7-on:var(--paper);
  --house-8:#EC9884; --house-8-on:var(--paper);
  --house-9:#65AA6D; --house-9-on:var(--paper);
  --house-10:#97D5FF; --house-10-on:var(--paper);
  --house-11:#E595B8; --house-11-on:var(--paper);
  --house-12:#A29A3F; --house-12-on:var(--paper);
  --house-13:#79E0E1; --house-13-on:var(--paper);
  --house-14:#C59EE4; --house-14-on:var(--paper);
  --house-15:#C88647; --house-15-on:var(--paper);
  --house-16:#9ADFB0; --house-16-on:var(--paper);
  --house-17:#93AFF5; --house-17-on:var(--paper);
  --house-18:#D3797A; --house-18-on:var(--paper);
  --house-19:#CDD389; --house-19-on:var(--paper);
  --house-20:#5CBFE4; --house-20-on:var(--paper);
  --house-21:#C37BAF; --house-21-on:var(--paper);
  --house-22:#F5C186; --house-22-on:var(--paper);
  --house-23:#56C7B7; --house-23-on:var(--paper);
  --house-24:#9C88D5; --house-24-on:var(--paper);
  --house-25:#FFB7AE; --house-25-on:var(--paper);
  --house-26:#8DC281; --house-26-on:var(--paper);
  --house-27:#629ADB; --house-27-on:var(--paper);
  --house-28:#FAB3DB; --house-28-on:var(--paper);
  --house-29:#C3B25F; --house-29-on:var(--paper);
  --house-30:#19A9BE; --house-30-on:var(--paper);
  --house-31:#D8BEFF; --house-31-on:var(--paper);
  --house-32:#E59F6E; --house-32-on:var(--paper);
  --house-33:#3FAD8A; --house-33-on:var(--paper);
  --house-34:#AFCEFF; --house-34-on:var(--paper);
  --house-35:#EC959E; --house-35-on:var(--paper);
  --house-36:#86A353; --house-36-on:var(--paper);
  --house-37:#7EDCF6; --house-37-on:var(--paper);
  --house-38:#D898D1; --house-38-on:var(--paper);
  --house-39:#B8903A; --house-39-on:var(--paper);
  --house-40:#84E1C9; --house-40-on:var(--paper);
  --house-41:#AEA6F1; --house-41-on:var(--paper);
  --house-42:#D17E5F; --house-42-on:var(--paper);
  --house-43:#B4DA99; --house-43-on:var(--paper);
  --house-44:#76B8F1; --house-44-on:var(--paper);
  --house-45:#CF7895; --house-45-on:var(--paper);
  --house-46:#E4CA82; --house-46-on:var(--paper);
  --house-47:#4DC5CF; --house-47-on:var(--paper);
  --house-48:#B280C5; --house-48-on:var(--paper);
  --house-49:#FFBA97; --house-49-on:var(--paper);
  --house-50:#6EC69B; --house-50-on:var(--paper);
  color-scheme:dark;
  }
}
/* office density: desktop drops rows to 48px / 15px (headings never shrink); gutter 32 */
@media (min-width:1024px){:root{--row:48px;--row-gap:0px;--group-gap:40px;--gutter:32px}}
/* laptop layout tokens (DOMWELL-V3-LAPTOP §1). --rail is the side nav: a 72px icon rail at
   1024–1279, the full 232px list from 1280. Only defined at >=1024 — nothing on the phone reads them. */
@media (min-width:1024px){
  :root{
    --rail:72px;
    --header-h:64px;
    --subbar-h:48px;
    --gutter-desk:32px;
    --w-canvas:1600px;
    --w-list:1012px;
    --w-list-solo:1040px;
    --w-doc:720px;
    --w-aside:300px;
    --w-props:300px;
    --row-desk:44px;
  }
}
@media (min-width:1280px){:root{--rail:232px}}

/* ---------- compatibility: the previous token names, resolved into this palette.
   Every value below is a deliberate mapping (not a hex): surfaces go white/plaster, the orange
   action becomes ink, warn-ochre becomes plain ink, dividers vanish, elevation is gone,
   the mono face is the UI face with tabular figures. ---------- */
:root,[data-theme="dark"]{
  --bg:var(--paper); --surface:var(--paper); --surface-2:var(--plaster); --surface-3:var(--plaster-2);
  --border:transparent; --border-strong:var(--ink-3);
  --accent:var(--ink); --accent-text:var(--ink); --accent-soft:var(--plaster); --on-accent:var(--paper);
  --success:var(--moss); --success-soft:var(--moss-soft); --success-text:var(--moss);
  --danger:var(--clay); --danger-soft:var(--clay-soft);
  --warn:var(--ink-2); --warn-soft:var(--plaster);
  --font-sans:var(--f-ui); --font-mono:var(--f-ui);
  --r-1:999px; --r-2:var(--r-tile); --r-3:var(--r-panel); --r-full:var(--r-pill);
  --e-1:none; --e-2:none; --e-3:none;
  --on-house:var(--paper);
  /* --house-1…50 live in the theme blocks above; --house-0 is "no project" */
  --house-0:var(--ink-3);
  /* importance (migration 18; public/js/importance.js): the client's green · gold/yellow · red resolved into the
     palette, one token set for the calendar entry and the task. Green is the default and draws nothing (its token
     exists for the picker's swatch); gold is brass — facts, never actions; red is clay. --brass-text, not --brass:
     the tag is small text and --brass is 3.4:1 on plaster. Each resolves per theme through its source token. */
  --importance-normal:var(--moss); --importance-normal-soft:var(--moss-soft);
  --importance-important:var(--brass-text); --importance-important-soft:var(--brass-halo);
  /* A card-sized fill needs a lighter gold than the text token: --brass-text at 40x100px reads bronze, not
     the yellow the client asked for. Ink on it, not paper — 10.8:1 light, 9.1:1 dark. */
  --importance-important-fill:var(--brass-fill); --importance-important-on:var(--brass-fill-on);
  --importance-urgent:var(--clay); --importance-urgent-soft:var(--clay-soft);
  /* Calendar event fills, taken straight from Google Calendar's event palette (client 30.09):
     Tomato / Banana / Sage. Same in both themes, as Google's are. The TEXT colour is ours: Google
     draws white on all three, which is 1.69:1 on Banana and 2.59:1 on Sage — unreadable on site. */
  --gcal-tomato:#D50000; --gcal-tomato-on:#FFFFFF;
  --gcal-banana:#F6BF26; --gcal-banana-on:#1C1917;
  --gcal-sage:#33B679;   --gcal-sage-on:#1C1917;
}

/* ---------- identity colour picker (houses.js, people.js) — a disc always carries its number ---------- */
.cpick{display:flex;flex-wrap:wrap;gap:var(--s-2h) var(--s-2);align-items:flex-start}
.cpick-c{display:flex;flex-direction:column;align-items:center;gap:4px;padding:0;background:none;min-width:44px;color:var(--ink-3)}
.cpick-c .d{width:44px;height:44px;border-radius:50%;background:var(--house-c);color:var(--house-on,var(--paper));display:inline-flex;align-items:center;justify-content:center;font-family:var(--f-display);font-weight:700;font-size:14px;font-variant-numeric:tabular-nums;letter-spacing:.02em}
.cpick-c .d svg.ic{stroke-width:3}
.cpick-c .n{font-size:12px;line-height:14px;font-weight:700;font-variant-numeric:tabular-nums}
.cpick-c.on{color:var(--ink)}
.cpick-c.on .d{box-shadow:0 0 0 2px var(--paper),0 0 0 4px var(--ink)}
.cpick-c.used .d{opacity:.45}
.cpick-more{height:44px;padding:0 14px;border-radius:var(--r-pill);background:transparent;box-shadow:inset 0 0 0 1.5px var(--ink-3);font-weight:700;font-size:15px;color:var(--ink);font-variant-numeric:tabular-nums}
.cpick-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(44px,1fr));gap:var(--s-2h) var(--s-1);padding:4px 0 8px}
.cpick-grid .cpick-c{min-width:0;min-height:44px;justify-content:center;gap:var(--s-h)}
.cpick-grid .cpick-c .d{width:32px;height:32px;font-size:12px}
.cpick-grid .cpick-c .n{font-size:12px;line-height:14px}

/* ---------- base ---------- */
*,*::before,*::after{box-sizing:border-box}
html,body{margin:0}
button,input,select,textarea{font:inherit;color:inherit}
button{background:none;border:0;padding:0;cursor:pointer}
a{color:inherit}
svg.ic{width:24px;height:24px;stroke:currentColor;fill:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;flex:none}
svg.ic.sm{width:20px;height:20px}
svg.ic.xs{width:16px;height:16px;stroke-width:2.25}
svg.ic.lg{width:40px;height:40px;stroke-width:1.75}
.mono,.num{font-family:var(--f-ui);font-variant-numeric:tabular-nums;font-feature-settings:"tnum" 1;font-size:15px;line-height:20px;font-weight:600}
.eyebrow{display:inline-flex;align-items:center;gap:12px;font-size:12px;line-height:16px;font-weight:700;letter-spacing:.18em;text-transform:uppercase;color:var(--ink-2)}
.eyebrow .money,.eyebrow .cnt,.eyebrow .n{text-transform:none;letter-spacing:.02em;font-variant-numeric:tabular-nums;color:var(--ink-3)}
.eyebrow.danger{color:var(--clay)}
/* the brass dash from domwell.pl marks a PAGE-level label only (v3 §2.5): .page-head, .eyebrow.dash,
   .datehead. Group headings inside a page (.sec, the planner's day blocks) are no longer tracked caps
   with a dash — see "section headings" below. */
.datehead>.eyebrow::before,.page-head>.eyebrow::before,.eyebrow.dash::before{content:"";width:28px;height:1px;background:var(--brass);flex:none}
.eyebrow.dash.danger::before{background:var(--clay)}
.h1{font-family:var(--f-display);font-size:28px;line-height:32px;font-weight:700;letter-spacing:-.015em;margin:0}
.h2{font-family:var(--f-display);font-size:22px;line-height:28px;font-weight:700;letter-spacing:-.01em;margin:0}
.display{font-family:var(--f-display);font-size:40px;line-height:44px;font-weight:700;letter-spacing:-.02em;margin:0}
.d1{font-family:var(--f-display);font-size:56px;line-height:56px;font-weight:700;letter-spacing:-.02em;margin:0}
.small{font-size:15px;line-height:20px}
.caption{font-size:13px;line-height:18px;font-weight:600}
.muted{color:var(--ink-3)}
.ink2{color:var(--ink-2)}
.danger{color:var(--clay)}
.success{color:var(--moss)}
.warn{color:var(--ink-2)}
.brass{color:var(--brass-text)}
.krok-num{font-family:var(--f-display);font-weight:800;color:var(--brass);font-variant-numeric:tabular-nums;letter-spacing:-.02em;line-height:1}
.sr{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}
:focus-visible{outline:3px solid var(--focus);outline-offset:2px}

/* ---------- brand ---------- */
/* the wordmark is an SVG (ui.js wordmark()); it is sized by height, never by font-size */
.wordmark{display:inline-block;height:20px;color:var(--ink);line-height:0}
.wordmark svg{height:100%;width:auto;display:block}
.wordmark.lg{height:28px}
.wordmark.xl{height:38px}
.logo{display:inline-flex;align-items:center;justify-content:center;width:auto;height:32px;color:var(--ink);background:none;border-radius:0}

/* ---------- panel: v3 a box plane with a 1px line (was a plaster fill), like .lbox and .card ---------- */
.panel{background:var(--box);border:1px solid var(--line);border-radius:var(--r-panel);box-shadow:var(--shadow-card);padding:var(--s-5)}
/* Settings/menu row. Shared vocabulary: nine views use it (lists, people, houses, schedule,
   task, product sheet, rzuty, timeoff, project menu). It lived in list.js's injected CSS,
   which meant every other view rendered it unstyled until you had visited a list. Anything
   more than one view uses belongs here, not in a view's own stylesheet. */
.ls-row{display:flex;align-items:center;gap:12px;min-height:56px;padding:8px 0;border-bottom:1px solid var(--rim);width:100%;text-align:left;background:none}
.ls-row:last-child{border-bottom:0}
.ls-row .grow .caption{font-weight:400;color:var(--ink-3)}
.ls-row.danger{color:var(--danger)}
.ls-row .v{margin-left:auto;color:var(--ink-2);display:inline-flex;align-items:center;gap:var(--s-1h);text-align:right}


/* ---------- app bar ---------- */
.appbar{min-height:56px;display:flex;align-items:center;gap:8px;padding:0 8px 0 var(--gutter);flex:none;position:relative}
.appbar .title{flex:1;min-width:0;font-family:var(--f-display);font-size:22px;line-height:28px;font-weight:700;letter-spacing:-.01em;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.appbar .title.sub{font-size:20px;line-height:26px}
.appbar .brandslot{flex:1;min-width:0;display:flex;align-items:center;gap:var(--s-2h)}
.appbar .brandslot .title{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}
.iconbtn{width:44px;height:44px;display:inline-flex;align-items:center;justify-content:center;border-radius:50%;color:var(--ink);flex:none}
.iconbtn:hover,.iconbtn.on{background:var(--plaster)}
.page-title{font-family:var(--f-display);font-size:32px;line-height:36px;font-weight:700;letter-spacing:-.02em;margin:8px 0 12px}

/* ---------- status bars / banners ---------- */
.offline-bar{display:flex;align-items:center;gap:var(--s-2h);min-height:40px;margin:8px var(--gutter) 0;padding:8px 16px;border-radius:var(--r-pill);background:var(--inverse-bg);color:var(--inverse-ink);font-size:14px;line-height:18px;font-weight:700;flex:none}
.offline-bar svg.ic{width:18px;height:18px}
.banner-error{display:grid;grid-template-columns:20px minmax(0,1fr) auto;gap:8px 12px;align-items:center;padding:var(--s-4);margin:0 0 16px;background:var(--box);border:1px solid var(--line);color:var(--ink);border-radius:var(--r-panel);font-size:15px;line-height:20px;font-weight:600}
.banner-error svg.ic{color:var(--clay)}

/* §7.6 banner: a layout element, not a floating pill. A box like .banner-error (v3: box + line), but with
   a 3px left rule inside the rounded edge — nothing else in the app has one — brass for a fact
   you can undo, clay for a problem. Persistent: it always carries an ×, and never a timer. */
.banner{position:relative;display:grid;grid-template-columns:20px minmax(0,1fr) 44px;gap:0 12px;align-items:start;padding:var(--s-4) var(--s-4) var(--s-4) 26px;background:var(--box);border:1px solid var(--line);color:var(--ink);border-radius:var(--r-panel);font-size:15px;line-height:20px}
.banner::before{content:'';position:absolute;left:12px;top:var(--s-4);bottom:var(--s-4);width:3px;border-radius:var(--r-pill);background:var(--brass)}
.banner.clay::before{background:var(--clay)}
.banner>svg.ic{color:var(--brass-text);margin-top:1px;flex:none}
.banner.clay>svg.ic{color:var(--clay)}
.banner .bn-txt{min-width:0}
.banner .bn-t{font-weight:700}
.banner p{margin:2px 0 0;color:var(--ink-2);font-weight:500}
.banner .bn-acts{display:flex;flex-wrap:wrap;gap:8px;margin-top:var(--s-2h)}
.banner .bn-x{margin:calc(var(--s-2h) * -1) calc(var(--s-1h) * -1) 0 0}
.pending{display:inline-flex;align-items:center;gap:var(--s-1);color:var(--ink-3);font-size:13px;line-height:16px;font-weight:700}

/* ---------- buttons. v3: ink is the one primary; secondary and danger are soft fills, not outlines ---------- */
.btn{display:inline-flex;align-items:center;justify-content:center;gap:8px;min-height:48px;min-width:44px;padding:0 20px;border-radius:var(--r-pill);font-size:16px;line-height:24px;font-weight:700;text-decoration:none;border:0;transition:background var(--dur-1) var(--ease-out),transform var(--dur-1) var(--ease-out)}
.btn:active{transform:scale(.98)}
.btn.primary{background:var(--ink);color:var(--paper)}
.btn.secondary{background:var(--surface-2);color:var(--ink)}
.btn.secondary:hover{background:var(--surface-3)}
/* the weakest action tier reads as a button, not a link: a 2px underline on a 17px label was
   the loudest link signal in the sheet. Genuine navigation keeps .linklike. */
.btn.tertiary{background:transparent;color:var(--ink-2);min-height:44px;padding:0 var(--s-3);text-decoration:none}
.btn.tertiary:hover,.btn.tertiary:focus-visible{background:var(--plaster);color:var(--ink)}
.btn.danger{background:var(--clay-soft);color:var(--clay)}
.btn.block{width:100%}
.btn.sm{min-height:40px;font-size:15px;line-height:20px;padding:0 14px}
.btn.tertiary.sm{padding:0 var(--s-1h)}
.btn[aria-disabled="true"],.btn:disabled{opacity:.4;cursor:not-allowed}
@media (min-width:1024px){.btn{min-height:44px}}
.spinner{width:20px;height:20px;border-radius:50%;border:2.5px solid currentColor;border-right-color:transparent;animation:spin .8s linear infinite}
@keyframes spin{to{transform:rotate(360deg)}}
.linklike{background:none;color:var(--ink);font-weight:700;text-decoration:underline;text-underline-offset:3px;padding:0;min-height:44px}

/* ---------- fields ---------- */
.field{display:flex;flex-direction:column;gap:8px;margin-bottom:16px}
/* v3: inputs are 12px-radius fields, not pills, so the 18px label indent that sat over a pill's curve
   is gone. 16px text everywhere also stops iOS zooming the page on focus. */
.field label{font-size:14px;line-height:20px;font-weight:600;color:var(--ink-2);padding-left:0}
.field .help{font-size:13px;line-height:18px;color:var(--ink-3);font-weight:600;padding-left:0}
.field .err,.err{display:flex;gap:6px;align-items:center;font-size:13px;line-height:18px;color:var(--clay);font-weight:700;padding-left:0}
.input{display:flex;align-items:center;gap:10px;min-height:48px;padding:0 14px;border:1px solid var(--field-border);border-radius:var(--r-tile);background:var(--box);color:var(--ink);font-size:16px;line-height:22px;width:100%}
.input:focus-within{border-color:var(--ink);box-shadow:0 0 0 3px var(--brass-halo)}
.input.error{border-color:var(--clay)}
.input.focus{border-color:var(--ink);box-shadow:0 0 0 3px var(--brass-halo)}
.input .ph{color:var(--ink-3)}
.input.mono{font-variant-numeric:tabular-nums}
.input textarea,.input input{border:0;background:none;flex:1;min-width:0;outline:none;padding:0;color:inherit}
.input.mono input,.input.mono textarea{font-size:16px}   /* <16px makes iOS zoom the page on focus */
.textarea,.input.textarea{min-height:96px;align-items:flex-start;padding:12px 14px;border-radius:var(--r-tile)}
.stepper{display:inline-flex;align-items:center;border:1.5px solid var(--field-border);border-radius:var(--r-pill);background:transparent;height:48px}
.stepper button{width:48px;height:100%;display:inline-flex;align-items:center;justify-content:center;border-radius:50%}
.stepper .val{min-width:48px;text-align:center;font-weight:700;font-variant-numeric:tabular-nums}
/* segmented: a raised white thumb, never an ink fill (v3 rule 2 — ink is for the one action). The
   36px visual height sits in a 42px track; a pseudo hit area keeps each option at 44px. */
.segmented{display:flex;background:var(--surface-2);border-radius:var(--r-pill);padding:3px;gap:2px}
.segmented button{flex:1;min-height:36px;border-radius:var(--r-pill);font-weight:600;font-size:15px;color:var(--ink-2);display:inline-flex;align-items:center;justify-content:center;gap:6px;padding:0 12px;white-space:nowrap;position:relative}
.segmented button::after{content:"";position:absolute;left:0;right:0;top:-4px;bottom:-4px}
.segmented button.on{background:var(--box);color:var(--ink);box-shadow:var(--shadow-thumb)}
/* the three calendars behind the Kalendarz tab (views/calendarSeg.js); Ekipy waits for its slice */
.calseg{margin:8px 0 4px}
.calseg button[disabled]{opacity:.45;cursor:default}
.switch{width:52px;height:32px;border-radius:var(--r-pill);background:transparent;border:1.5px solid var(--field-border);position:relative;flex:none;display:inline-flex;align-items:center;justify-content:flex-end;padding:0 7px}
.switch::after{content:"";position:absolute;left:4.5px;top:4.5px;width:20px;height:20px;border-radius:50%;background:var(--ink-2);transition:transform var(--dur-1) var(--ease-out)}
.switch.on{background:var(--ink);border-color:var(--ink)}
.switch.on::after{background:var(--paper);transform:translateX(20px)}
.switch svg{display:none}

/* ---------- circle check: a 24px ring (v3) inside a 44px control, so the hit area stays thumb-sized.
   .check .box is the ring — not the .lbox list container. ---------- */
.check{width:44px;height:44px;display:inline-flex;align-items:center;justify-content:center;flex:none;border-radius:50%}
.check .box{width:24px;height:24px;border-radius:50%;border:2px solid var(--field-border);display:inline-flex;align-items:center;justify-content:center;background:transparent;transition:background var(--dur-1) var(--ease-out)}
.check.on .box{background:var(--ink);border-color:var(--ink)}
.check .box svg{width:14px;height:14px;stroke:var(--paper);stroke-width:3;display:none}
.check.on .box svg{display:block}
.check.pending-sync .box{border-style:dashed}

/* ---------- lists / rows. v3: a group of rows sits in a .lbox (see "list box" below); outside a box
   rows still stand on whitespace. Cards are box planes with a 1px line, not plaster fills. ---------- */
.card{background:var(--box);border:1px solid var(--line);border-radius:var(--r-panel);box-shadow:var(--shadow-card);padding:20px}
.card > .h2:first-child{margin:0 0 12px}
.card > * + *{margin-top:var(--s-2h)}
.card .kv{padding:var(--s-2) 0;min-height:40px;margin-top:0;background:transparent}
.rows{display:flex;flex-direction:column;gap:var(--row-gap);background:transparent;border-radius:0;box-shadow:none;overflow:visible}
.rows>*+*{border-top:0}
/* section heading (v3 §2.5): 24px above, 10px below; the label is a 20px Outfit sentence-case heading,
   not tracked caps. The planner's day-block heading (.db-h) is the same kind of group heading.
   A count inside it (.cnt / .n) renders as a .ctr pill; views should print <span class="ctr">5</span>
   rather than "(5)". Time sub-groups inside a day use .sub-label. */
.sec{display:flex;align-items:center;justify-content:space-between;gap:8px;margin:var(--s-5) 0 var(--s-2h);min-height:24px}
.sec:first-child,.datehead+.sec,.searchbox+.sec{margin-top:16px}
.sec>.eyebrow,.db-h .eyebrow{display:inline-flex;align-items:center;gap:8px;font-family:var(--f-display);font-size:20px;line-height:26px;font-weight:700;letter-spacing:-.01em;text-transform:none;color:var(--ink)}
.sec>.eyebrow::before,.db-h .eyebrow::before{display:none}
.sec>.eyebrow.danger,.db-h .eyebrow.danger{color:var(--clay)}
.sec>.eyebrow :is(.cnt,.n),.db-h .eyebrow :is(.cnt,.n),.ctr{display:inline-grid;place-items:center;min-width:24px;height:22px;padding:0 7px;border-radius:var(--r-pill);background:var(--surface-2);font-family:var(--f-ui);font-size:12px;line-height:1;font-weight:700;letter-spacing:0;color:var(--ink-2);font-variant-numeric:tabular-nums;text-transform:none;flex:none}
.sec>.eyebrow .money,.db-h .eyebrow .money{font-family:var(--f-ui);font-size:14px;line-height:20px;font-weight:600;letter-spacing:0}
.sec>.eyebrow svg.ic{width:18px;height:18px}
.sub-label{display:flex;align-items:center;gap:8px;margin:0 0 var(--s-2);font-size:12px;line-height:16px;font-weight:700;letter-spacing:.06em;text-transform:uppercase;color:var(--ink-3)}

/* rows (v3 §2.4): a 28px ring column + 12px gap, 12/16 padding — a two-line row is ~70px, not ~112.
   The .check stays a 44px control; the negative margin centres its 24px ring in the 28px column. */
.task-row{display:grid;grid-template-columns:28px minmax(0,1fr) auto;align-items:start;column-gap:var(--s-3);min-height:var(--row);position:relative;background:transparent;transition:background var(--dur-2) var(--ease-out);padding:var(--s-3) var(--row-inset);margin-inline:calc(var(--row-inset) * -1);border-radius:var(--r-tile)}
.task-row .hbar{display:none}
.task-row .check,.product-row .check{margin:-10px 0 0 -10px}
.task-row .body{min-width:0;padding:0;display:flex;flex-direction:column;gap:4px}
.task-row .title{font-size:16px;line-height:22px;font-weight:600;overflow:hidden;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical}
.task-row .meta{display:flex;align-items:center;gap:var(--s-1) var(--s-2h);flex-wrap:wrap;font-size:14px;line-height:20px;color:var(--ink-3);font-weight:500;min-width:0;max-width:100%}
.task-row .meta .mono{font-size:14px;line-height:20px;font-weight:700;color:var(--ink-2)}
.task-row .meta .house-chip{font-size:14px;font-weight:600;color:var(--ink-2)}
.task-row .meta .overdue-tag{font-size:14px}
.task-row.done{background:transparent}
.task-row.done .title{text-decoration:line-through;text-decoration-thickness:2px;color:var(--ink-3);font-weight:500}
/* exceptional states are a glyph and a word, never a colour: "W trakcie" inline, Wstrzymane on its own line */
.task-row .meta .state-inline{display:inline-flex;align-items:center;gap:var(--s-1h);font-weight:700;color:var(--ink-2)}
.task-row .meta .pill.sm{height:24px;padding:0 8px;font-size:12px;line-height:14px;gap:4px;display:inline-flex;align-items:center;border-radius:var(--r-pill);background:var(--plaster);color:var(--ink-2);font-weight:700;white-space:nowrap}
.task-row:hover .meta .pill.sm,.task-row:focus-within .meta .pill.sm{background:var(--paper)}
.task-row .state{display:flex;align-items:flex-start;gap:var(--s-1h);font-size:14px;line-height:20px;font-weight:700;color:var(--ink-2)}
.task-row .state>svg.ic{margin-top:2px;stroke-width:2.5}
.task-row .state .rsn{font-weight:600;color:var(--ink-3)}
.task-row:hover,.task-row:focus-within{background:var(--plaster)}
/* a busy block — another account's private task (server/sync.js busyBlock): hatched, no ring, nothing to press */
.task-row.busy,.task-row.busy:hover,.task-row.busy:focus-within{background:repeating-linear-gradient(135deg,var(--plaster) 0 6px,transparent 6px 12px);cursor:default}
.task-row.busy .busy-lock{display:flex;align-items:center;justify-content:center;width:28px;min-height:22px;margin-left:0;color:var(--ink-3)}
.task-row.busy .title{color:var(--ink-2)}
.task-row .meta .state-inline.priv{color:var(--ink-3)}
.overdue-tag{display:inline-flex;align-items:center;gap:var(--s-1h);color:var(--clay);font-weight:700;font-size:15px;line-height:20px;letter-spacing:0;text-transform:none}
.overdue-tag svg{width:16px;height:16px;fill:none;stroke:var(--clay);stroke-width:2.5;stroke-linecap:round;stroke-linejoin:round}
.overdue-tag .mono{color:var(--clay)}

.product-row{display:grid;grid-template-columns:28px minmax(0,1fr) auto;align-items:start;column-gap:var(--s-3);min-height:var(--row);position:relative;background:transparent;transition:background var(--dur-2) var(--ease-out);padding:var(--s-3) var(--row-inset);margin-inline:calc(var(--row-inset) * -1);border-radius:var(--r-tile)}
.product-row .body{min-width:0;padding:0;display:flex;flex-direction:column;gap:4px}
.product-row .name{font-size:16px;line-height:22px;font-weight:600}
.product-row .sub{display:flex;align-items:center;gap:4px 10px;flex-wrap:wrap;font-size:14px;line-height:20px;color:var(--ink-3);font-weight:500}
.product-row .sub .mono{font-size:14px;line-height:20px;font-weight:600;color:var(--ink-2)}
.product-row .qty{flex:none;min-width:72px;text-align:right;padding:0;font-variant-numeric:tabular-nums;font-size:16px;line-height:22px;font-weight:700}
.product-row .qty small{display:block;font-size:13px;line-height:18px;font-weight:500;color:var(--ink-3)}
.product-row.bought{background:transparent}
.product-row.bought .name{text-decoration:line-through;text-decoration-thickness:2px;color:var(--ink-3);font-weight:500}
.product-row.bought .qty,.product-row.bought .sub .mono{color:var(--ink-3);font-weight:600}
.product-row:hover,.product-row:focus-within{background:var(--plaster)}
.product-row.has-photo{grid-template-columns:28px minmax(0,1fr) auto auto}
.product-row > .body,.task-row > .body,.alt-row > .body{text-align:left;width:100%}
@supports selector(:has(*)) {
  .task-row:has(> .body:focus-visible),
  .product-row:has(> .body:focus-visible),
  .alt-row:has(> .body:focus-visible){outline:3px solid var(--focus);outline-offset:-2px}
  .task-row > .body:focus-visible,
  .product-row > .body:focus-visible,
  .alt-row > .body:focus-visible{outline:none}
}

.list-card{display:block;background:var(--box);border:1px solid var(--line);border-radius:var(--r-panel);box-shadow:var(--shadow-card);padding:18px 20px;color:inherit;text-decoration:none;min-height:88px}
.list-card .top{display:flex;align-items:flex-start;gap:var(--s-2h);justify-content:space-between}
.list-card .name{font-family:var(--f-display);font-size:22px;line-height:28px;font-weight:700;letter-spacing:-.01em;min-width:0}
.list-card .counts{font-size:15px;line-height:20px;color:var(--ink-2);margin-top:var(--s-1h);font-weight:600}
.list-card .houses{display:flex;gap:var(--s-1h) var(--s-3);margin-top:12px;flex-wrap:wrap;align-items:center}

/* ---------- project mark (was: house chip) — number/name beside a 10px material disc ---------- */
.house-chip{display:inline-flex;align-items:center;gap:7px;height:auto;padding:0;border-radius:0;background:transparent;color:var(--ink);font-size:15px;line-height:20px;font-weight:700;white-space:nowrap;max-width:100%}
.house-chip .nm{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.house-chip .nm .pn{font-family:var(--f-display);font-weight:700;letter-spacing:.01em}
.house-chip .nm .kind{font-weight:600;color:var(--ink-3);font-size:13px;letter-spacing:.04em;text-transform:uppercase;margin-left:6px}
.task-row .meta .house-chip,.product-row .house-chip,.list-card .house-chip,.ghead .house-chip{min-width:0}
.filters .house-chip,.filterbar .house-chip{flex:none;min-width:max-content}
.units,.chips{flex-wrap:wrap;row-gap:8px}
.units .house-chip,.chips .house-chip{flex:0 1 auto;min-width:0;max-width:100%}
.house-chip .sw{width:10px;height:10px;border-radius:50%;background:var(--house-c,var(--ink-3));flex:none;display:inline-flex;align-items:center;justify-content:center;color:var(--paper)}
.house-chip .sw svg{display:none}
.house-chip.sm{font-size:14px;line-height:16px;gap:var(--s-1h)}
.house-chip.sm .nm .kind{font-size:12px}
.house-chip.sm .sw{width:8px;height:8px}
/* pill variants: pickers and filter bars */
.house-chip.filter,.house-chip.selected,.units .house-chip,.chips .house-chip,.ghead .house-chip,.ts .kv .v .house-chip{height:36px;padding:0 14px 0 12px;border-radius:var(--r-pill);background:var(--plaster);gap:8px}
/* unselected project filter = an unselected .chip: the --surface-2 fill, no outline */
.house-chip.filter{background:var(--surface-2);color:var(--ink-2);box-shadow:none}
/* selected = brass tint (v3 rule 2), the same "you are here" as .chip.on and the tab bar */
.house-chip.selected{background:var(--select);color:var(--ink);box-shadow:inset 0 0 0 1px var(--select-line)}
.house-chip.selected .nm .kind{color:var(--ink-3)}
.house-chip.selected .sw{background:var(--house-c,var(--ink-3))}
.house-chip.finished{color:var(--ink-3)}
.house-mark{display:inline-flex;align-items:center;gap:6px;height:20px;border-radius:0;background:transparent;color:var(--ink);font-family:var(--f-display);font-size:14px;line-height:1;font-weight:700;letter-spacing:.02em}
.house-mark::before{content:"";width:10px;height:10px;border-radius:50%;background:var(--house-c,var(--ink-3));flex:none}
.house-dot{width:10px;height:10px;border-radius:50%;background:var(--house-c);flex:none;display:inline-block}

/* ---------- importance tag (ui.js importanceTag): always glyph + word, never colour alone. v3 §2.10: one
   label shape — a 22px pill, 12px/700, soft ground + strong text. "Ważne" is a brass-tint pill (settles
   VISUAL-REVIEW V15: one object everywhere), "Pilne" a clay pill; a normal task has no tag at all.
   (The yellow --brass-fill on calendar blocks stays: that is a block fill, not a label.) ---------- */
.imp{display:inline-flex;align-items:center;gap:4px;font-weight:700;letter-spacing:0;text-transform:none;white-space:nowrap;line-height:16px;vertical-align:middle}
.imp svg.ic{width:14px;height:14px;stroke-width:2.5;flex:none}
.imp.important,.imp.urgent{font-size:12px;min-height:22px;padding:0 8px 0 6px;border-radius:var(--r-pill)}
.imp.important{color:var(--brass-text);background:var(--select)}
.imp.urgent{color:var(--importance-urgent);background:var(--importance-urgent-soft)}
/* the picker's swatch: a disc in the level's colour beside the word, ringed in paper so it keeps its edge on an ink-filled chip */
.imp-dot{display:inline-block;width:12px;height:12px;border-radius:50%;flex:none;box-shadow:0 0 0 2px var(--paper)}
.imp-dot.normal{background:var(--importance-normal)}
.imp-dot.important{background:var(--importance-important)}
.imp-dot.urgent{background:var(--importance-urgent)}

/* ---------- privacy pill: always icon + word ---------- */
.privacy{display:inline-flex;align-items:center;gap:var(--s-1h);height:32px;padding:0 var(--s-3) 0 var(--s-2h);border-radius:var(--r-pill);background:var(--plaster);color:var(--ink-2);border:0;font-size:14px;line-height:16px;font-weight:700;white-space:nowrap;flex:none}
.privacy svg{width:16px;height:16px;stroke-width:2.25}
.privacy.public{background:var(--plaster);color:var(--ink-2)}
.privacy.large{height:40px;padding:0 16px 0 12px;font-size:15px}
.privacy.large svg{width:20px;height:20px}

/* ---------- avatar: circle initials; "me" is the one filled circle. v3 §2.9: others are tinted with the
   member's identity colour — ui.js sets --pc:var(--house-N) inline; without it the neutral --ink-3 tint
   (still >= 4.5:1). The recipe lives in --tint / --tint-ink per theme, so there is no dark twin rule. ---------- */
.avatar{width:32px;height:32px;border-radius:50%;background:color-mix(in oklab,var(--pc,var(--ink-3)) var(--tint),var(--box));color:color-mix(in oklab,var(--pc,var(--ink-3)) 72%,var(--tint-ink));display:inline-flex;align-items:center;justify-content:center;font-family:var(--f-display);font-size:12px;font-weight:700;letter-spacing:.02em;flex:none;border:0}
.avatar.me{background:var(--ink);color:var(--paper)}
.avatar.md{width:40px;height:40px;font-size:14px}
.avatar.lg{width:64px;height:64px;font-size:22px}
.avatar.xs{width:24px;height:24px;font-size:12px;line-height:14px}
/* project disc (v3 §2.9): the same tint recipe with --pc:var(--house-N); initials or the project number */
.pdisc{width:40px;height:40px;border-radius:50%;display:inline-grid;place-items:center;flex:none;font-family:var(--f-display);font-size:14px;line-height:1;font-weight:700;letter-spacing:.02em;font-variant-numeric:tabular-nums;background:color-mix(in oklab,var(--pc,var(--ink-3)) var(--tint),var(--box));color:color-mix(in oklab,var(--pc,var(--ink-3)) 72%,var(--tint-ink))}
.pdisc.lg{width:48px;height:48px;font-size:16px}

/* ---------- tab bar (v3 §2.2): translucent paper + blur + a 1px line, square top (Instagram/Spotify);
   active = the brass-tint "you are here" pill behind the icon, never ink ---------- */
.tabbar{position:absolute;left:0;right:0;bottom:0;height:auto;padding:8px 6px 20px;background:color-mix(in srgb,var(--paper) 86%,transparent);-webkit-backdrop-filter:blur(16px);backdrop-filter:blur(16px);border-top:0;border-radius:0;box-shadow:0 -1px 0 0 var(--line);display:flex;z-index:var(--z-chrome)}
.tabbar a{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:4px;color:var(--ink-3);text-decoration:none;font-size:12px;line-height:14px;font-weight:600;position:relative;min-width:44px;border-radius:var(--r-tile)}
.tabbar a svg.ic{width:24px;height:24px;box-sizing:content-box;padding:4px 18px;border-radius:var(--r-pill)}
.tabbar a.active{color:var(--ink);font-weight:700}
.tabbar a.active::before{display:none}
.tabbar a.active svg.ic{background:var(--select);color:var(--ink);stroke-width:2}
.tabbar .badge{position:absolute;top:0;left:calc(50% + 10px);min-width:20px;height:20px;padding:0 var(--s-1h);border-radius:var(--r-pill);background:var(--clay);color:#fff;font-size:12px;line-height:20px;font-weight:700;text-align:center;font-variant-numeric:tabular-nums}
[data-theme="dark"] .tabbar .badge{color:#1C1917}
@media (prefers-color-scheme: dark){:root:not([data-theme="light"]) .tabbar .badge{color:#1C1917}}

/* ---------- FAB: the one ink-filled control, and one of four floating things that carry --shadow-float ---------- */
.fab{position:absolute;right:16px;bottom:100px;height:56px;min-width:56px;padding:0 20px 0 var(--s-4);border-radius:var(--r-pill);background:var(--ink);color:var(--paper);display:inline-flex;align-items:center;justify-content:center;gap:8px;font-weight:700;font-size:16px;box-shadow:var(--shadow-float);z-index:var(--z-float)}
.fab.round{padding:0;width:56px;border-radius:50%}

/* ---------- sheet + dialog: floating, so they carry --e-float (= --shadow-float) over the scrim ---------- */
.scrim{position:absolute;inset:0;background:var(--scrim);z-index:var(--z-scrim)}
/* Width cap and centring for the live overlay live in app.css (layout owns breakpoints). */
.sheet{position:absolute;left:0;right:0;bottom:0;background:var(--paper);border-radius:var(--r-sheet) var(--r-sheet) 0 0;box-shadow:var(--e-float);z-index:var(--z-overlay);display:flex;flex-direction:column;max-height:92%}
.sheet .grab{width:40px;height:4px;border-radius:var(--r-pill);background:var(--ink-3);opacity:.35;margin:var(--s-2h) auto 0}
/* 20px left, not 24: the title lines up with .content's own 20px inset. */
.sheet .head{display:flex;align-items:center;gap:8px;padding:8px 12px 8px 20px}
.sheet .head .h2{flex:1}
.sheet .content{padding:4px 20px 12px;overflow:hidden}
/* the commit bar, not another field: .content is always mid-scroll, so the footer needs the
   rim (P2, use 5) and its own ground for the chips to scroll under. */
.sheet .foot{display:flex;gap:12px;align-items:center;padding:12px 20px 32px;background:var(--paper);box-shadow:0 -1px 0 0 var(--rim)}
.sheet .foot .btn.primary{flex:1}
.dialog{position:absolute;left:20px;right:20px;top:50%;transform:translateY(-50%);background:var(--paper);border-radius:var(--r-panel);box-shadow:var(--e-float);z-index:var(--z-overlay);padding:28px 24px 24px}

/* ---------- toast: inverted pill, floating (--shadow-float) ---------- */
.toast{position:absolute;left:16px;right:16px;bottom:96px;background:var(--inverse-bg);color:var(--inverse-ink);border-radius:var(--r-pill);padding:14px 20px;display:flex;align-items:center;gap:12px;font-size:15px;line-height:20px;font-weight:600;z-index:var(--z-toast);box-shadow:var(--shadow-float)}
.toast .act{margin-left:auto;color:inherit;font-weight:700;min-height:44px;display:inline-flex;align-items:center;padding:0 8px;text-decoration:underline;text-underline-offset:3px}
.toast.success svg.ic{color:var(--moss)}
.toast.error{background:var(--inverse-bg);color:var(--inverse-ink)}
.toast.error svg.ic{color:var(--clay)}
[data-theme="dark"] .toast.success svg.ic{color:#3D6B45}
[data-theme="dark"] .toast.error svg.ic{color:#A8392A}
@media (prefers-color-scheme: dark){:root:not([data-theme="light"]) .toast.success svg.ic{color:#3D6B45}:root:not([data-theme="light"]) .toast.error svg.ic{color:#A8392A}}

/* ---------- skeleton ---------- */
.skel{background:var(--plaster-2);border-radius:var(--r-pill);animation:pulse 1.2s ease-in-out infinite;display:block}
@keyframes pulse{0%,100%{opacity:1}50%{opacity:.55}}
.skel.t{height:16px;width:70%}
.skel.s{height:12px;width:45%}
.skel.sq{width:28px;height:28px;border-radius:50%}
.skel-row{display:flex;align-items:center;gap:12px;min-height:var(--row);padding:var(--s-2h) 0 var(--s-2h) var(--s-2);background:transparent}
.skel-row .col{flex:1;display:flex;flex-direction:column;gap:8px}

/* ---------- empty: heading, one sentence, one action ---------- */
.empty{display:flex;flex-direction:column;align-items:flex-start;text-align:left;padding:56px 0 24px;gap:12px;color:var(--ink)}
.empty svg.ic{color:var(--brass);width:40px;height:40px;stroke-width:1.75}
.empty .h2{font-size:28px;line-height:32px;margin-top:4px;max-width:18ch}
.empty p{margin:0;color:var(--ink-2);max-width:34ch}
.empty .btn{margin-top:8px}
/* an empty state is not the screen's primary action (the FAB is), so its button drops to secondary */
.empty .btn.primary{background:var(--surface-2);color:var(--ink)}

/* ---------- chips / filter bar ---------- */
.filters{display:flex;align-items:center;gap:8px;overflow:hidden;padding:8px 0 4px;flex-wrap:nowrap}
.chip{display:inline-flex;align-items:center;gap:var(--s-1h);height:36px;padding:0 var(--s-3);border-radius:var(--r-pill);background:var(--plaster);color:var(--ink-2);border:0;font-size:15px;font-weight:700;white-space:nowrap}
.chip.on{background:var(--select);color:var(--ink);box-shadow:inset 0 0 0 1px var(--select-line)}
.chip svg.ic{width:16px;height:16px;stroke-width:2.25}

/* (v3: the "pills inside a plaster panel get a paper ground" override is gone — cards are box planes now,
   so plaster pills already read on them) */

/* ---------- misc ---------- */
.hr{height:1px;background:var(--line);margin:16px 0}
.kv{display:flex;align-items:center;justify-content:space-between;gap:12px;min-height:56px;padding:8px 16px;background:transparent}
.kv .k{font-weight:600}
.kv .v{color:var(--ink-2);display:inline-flex;align-items:center;gap:var(--s-1h);font-weight:600}
.total{display:flex;justify-content:space-between;align-items:baseline;padding:14px 20px;background:var(--box);border:1px solid var(--line);border-radius:var(--r-panel);box-shadow:var(--shadow-card);font-weight:700}
.total .mono{font-family:var(--f-display);font-size:24px;line-height:28px;font-weight:700;letter-spacing:-.01em}
/* week strip (v3): the selected day is the brass-tint ground; "today" is only its number in a 36px ink
   circle — no longer a tall ink capsule. The .today rules are doubled-class so they outrank planner.js's
   injected `.week .d.today{color:var(--bg)}`, which would turn the weekday label invisible. */
.week{display:grid;grid-template-columns:repeat(7,1fr);gap:2px}
.week .d{display:flex;flex-direction:column;align-items:center;gap:3px;padding:6px 0 7px;border-radius:var(--r-tile);min-height:64px;background:transparent;box-shadow:none;font-size:12px;line-height:16px;font-weight:600;color:var(--ink-3)}
.week .d .n{width:36px;height:36px;border-radius:50%;display:grid;place-items:center;font-family:var(--f-display);font-size:17px;line-height:1;font-weight:600;color:var(--ink);font-variant-numeric:tabular-nums}
.week .d.today.today{background:transparent;color:var(--ink-3)}
.week .d.today.today .n{background:var(--ink);color:var(--paper);font-weight:700}
.week .d .dots{display:flex;gap:3px;height:6px;align-items:center}
.week .d .dots .house-dot{width:5px;height:5px}
.week .d.sel,.week .d.today.today.sel{background:var(--select);box-shadow:none}

/* ---------- list box (v3 rule 3, §2.3): a group of rows in a bordered box — GitHub's Box, iOS grouped lists.
   Named .lbox because .check .box is the check ring. Markup:
     <section class="lbox">
       <div class="lbox-h">Rano <span class="ctr">3</span><span class="m">1 240 zł</span></div>   (optional)
       <div class="task-row">…</div><div class="task-row">…</div>
     </section>
   Rows may also sit in a .rows wrapper inside the box. Between rows: a 1px hairline inset to the text edge,
   drawn by ::before at --lbox-inset — 56px (16 pad + 28 ring + 12 gap) for task/product rows, 16px for
   anything else; set --lbox-inset on the box or a row to change it (68px for rows led by a 40px .pdisc).
   Rows inside a box lose their negative margin and radius; hover is a square --surface-2 ground. ---------- */
.lbox{background:var(--box);border:1px solid var(--line);border-radius:var(--r-panel);overflow:hidden;box-shadow:var(--shadow-card)}
.lbox+.lbox,.lbox+.sub-label{margin-top:var(--s-4)}
.lbox-h{display:flex;align-items:center;gap:var(--s-2);min-height:40px;padding:var(--s-2h) var(--s-4);background:var(--surface-2);border-bottom:1px solid var(--line);font-size:14px;line-height:20px;font-weight:700;color:var(--ink)}
.lbox-h .m{margin-left:auto;font-weight:600;color:var(--ink-3);font-variant-numeric:tabular-nums;white-space:nowrap}
.lbox-h .ctr{background:var(--box)}
.lbox>.rows{gap:0}
.lbox>:where(:not(.lbox-h,.rows)),.lbox>.rows>*{position:relative}
.lbox>:is(.task-row,.product-row,.compact-row,.ls-row,.kv,.person-row,.house-card,.alt-row),
.lbox>.rows>:is(.task-row,.product-row,.compact-row,.ls-row,.kv,.person-row,.house-card,.alt-row){margin-inline:0;border-radius:0;padding-inline:var(--s-4);border-bottom:0}
.lbox :is(.task-row,.product-row){--lbox-inset:56px}
.lbox>:where(:not(.lbox-h,.rows))+:where(:not(.lbox-h,.rows))::before,
.lbox>.rows>*+*::before{content:"";position:absolute;top:0;left:var(--lbox-inset,var(--s-4));right:0;height:1px;background:var(--line);pointer-events:none}
.lbox>:is(.task-row,.product-row,.compact-row,.ls-row,.kv,.person-row,.house-card,.alt-row):is(:hover,:focus-within),
.lbox>.rows>:is(.task-row,.product-row,.compact-row,.ls-row,.kv,.person-row,.house-card,.alt-row):is(:hover,:focus-within){background:var(--surface-2)}

/* ---------- underline tabs (v3 §3, project page): Harmonogram / Zakupy / Rzuty with counters. Pills stay
   for filters only. Markup: <nav class="utabs"><a class="on" href="…">Zakupy <span class="ctr">12</span></a>…</nav>
   (also button.on / [aria-selected="true"] / [aria-current="page"]). The 1px base line and the 2px
   underline are inset shadows, so the strip can scroll sideways without clipping them. ---------- */
.utabs{display:flex;gap:22px;margin:var(--s-3) 0;overflow-x:auto;scrollbar-width:none;box-shadow:inset 0 -1px 0 0 var(--line)}
.utabs::-webkit-scrollbar{display:none}
.utabs>:is(a,button,span){display:inline-flex;align-items:center;gap:7px;min-height:44px;padding:0;background:none;border:0;font-size:15px;line-height:20px;font-weight:600;color:var(--ink-3);text-decoration:none;white-space:nowrap;flex:none;box-shadow:inset 0 -2px 0 0 transparent}
.utabs>:is(.on,[aria-selected="true"],[aria-current="page"]){color:var(--ink);box-shadow:inset 0 -2px 0 0 var(--ink)}

/* ---------- stats strip (v3 §3, project page): three facts in one bordered strip with 1px dividers.
   Markup: <div class="stats-strip"><div><b>12</b><span>otwarte</span></div><div class="late">…</div>…</div>
   The legacy .stats/.stat/.n/.l markup works too: <div class="stats stats-strip"><div class="stat">… ---------- */
.stats-strip{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));background:var(--box);border:1px solid var(--line);border-radius:var(--r-panel);box-shadow:var(--shadow-card);overflow:hidden}
.stats-strip>*{min-width:0;padding:var(--s-3) 14px}
.stats-strip>*+*{border-left:1px solid var(--line)}
.stats-strip :is(b,.n){display:block;font-family:var(--f-display);font-size:24px;line-height:28px;font-weight:700;letter-spacing:-.02em;font-variant-numeric:tabular-nums}
.stats-strip :is(span,.l){display:block;font-size:13px;line-height:18px;font-weight:600;color:var(--ink-3)}
.stats-strip .late :is(b,.n,span,.l){color:var(--clay)}

/* ---------- laptop components (DOMWELL-V3-LAPTOP §2). Classes no phone markup uses; the
   ones that restyle shared markup sit inside >=1024 queries, so the phone is untouched. ---------- */

/* width switches: render both headers, show one. */
@media (max-width:1023px){.d-only{display:none!important}}
@media (min-width:1024px){.m-only{display:none!important}}

/* keyboard hint: <kbd>N</kbd>, small, 1px inset line */
kbd{display:inline-flex;align-items:center;justify-content:center;min-width:20px;height:20px;padding:0 6px;border-radius:var(--r-chip);background:var(--box);box-shadow:inset 0 0 0 1px var(--line);color:var(--ink-3);font:600 12px/1 var(--f-ui);letter-spacing:0;white-space:nowrap;font-variant-numeric:tabular-nums}

@media (min-width:1024px){
  /* compact segmented switcher for the page header: auto width, 30px buttons, 13.5px. Never flex:1. */
  .segmented.compact{display:inline-flex;flex:none;width:auto}
  .segmented.compact button{flex:none;min-height:30px;padding:0 14px;font-size:13.5px;line-height:18px}
  .segmented.compact button::after{top:-2px;bottom:-2px}
}

/* .dtable — desktop list table (§2.5). A .lbox-like container; every row is a CSS grid whose
   columns come from --dt-cols on the table (or on a row):
     <div class="dtable" style="--dt-cols:36px minmax(0,1fr) 150px 44px 96px 96px">
       <div class="dt-row dt-head"><span></span><span>Produkt</span>…<span class="dt-num">Kwota</span></div>
       <div class="dt-row dt-group"><span>Łazienka</span><span class="dt-m">3 · 420 zł</span></div>
       <div class="dt-row">cells…</div>             (.done strikes the .dt-main cell)
     </div>
   Cells: .dt-main (600, ellipsis) · .dt-trunc (ellipsis) · .dt-muted (--ink-3) · .dt-num (right, tabular).
   A group row is flex, not grid: its title left, .dt-m pushed right. */
.dtable{background:var(--box);border:1px solid var(--line);border-radius:var(--r-panel);overflow:hidden;box-shadow:var(--shadow-card);font-size:14px;line-height:20px}
.dtable+.dtable{margin-top:var(--s-4)}
.dt-row{display:grid;grid-template-columns:var(--dt-cols,minmax(0,1fr));align-items:center;column-gap:8px;min-height:var(--row-desk,44px);padding:0 14px;border-top:1px solid var(--line);color:var(--ink);text-decoration:none;position:relative}
.dt-row:first-child{border-top:0}
.dt-row>*{min-width:0}
.dt-head{min-height:36px;background:var(--surface-2);font-size:12px;line-height:16px;font-weight:700;letter-spacing:.06em;text-transform:uppercase;color:var(--ink-3)}
.dt-head+.dt-row{border-top:0}
.dt-group{display:flex;gap:8px;min-height:38px;background:color-mix(in srgb,var(--surface-2) 55%,var(--box));font-size:13.5px;line-height:18px;font-weight:700}
.dt-group .dt-m{margin-left:auto;font-weight:600;color:var(--ink-3);font-variant-numeric:tabular-nums;white-space:nowrap}
.dt-group>button{display:inline-flex;align-items:center;gap:8px;min-height:38px;font:inherit;color:inherit;background:none;border:0;padding:0;cursor:pointer}
.dt-main{font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.dt-trunc{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.dt-muted{color:var(--ink-3)}
.dt-num{text-align:right;font-variant-numeric:tabular-nums;white-space:nowrap}
.dt-row.done .dt-main{text-decoration:line-through;color:var(--ink-3);font-weight:500}
.dt-row.done .dt-num{color:var(--ink-3)}
:is(a,button).dt-row,.dt-row[role="button"],.dt-row.link{cursor:pointer}
.dt-row:not(.dt-head,.dt-group):is(:hover,:focus-within){background:var(--surface-2)}
/* the check ring shrinks to 18px on a desk pointer; the 32px hit area stays */
@media (min-width:1024px){
  .dtable .check{width:32px;height:32px;margin:0}
  .dtable .check .box{width:18px;height:18px}
  .dtable .check .box svg{width:11px;height:11px;stroke-width:3.2}
}

/* hover reveal (§2.7): hidden until the .hover-host ancestor is hovered or holds focus. Desk
   pointers only — on touch it stays visible. Opacity, not display, so it keeps its place and
   stays reachable by Tab (focusing it reveals it). */
@media (hover:hover) and (min-width:1024px){
  .hover-reveal{opacity:0;transition:opacity var(--dur-1) var(--ease-out)}
  .hover-host:is(:hover,:focus-within) .hover-reveal,.hover-reveal:focus-visible{opacity:1}
}

/* ---------- reduced motion ---------- */
@media (prefers-reduced-motion: reduce){
  :root{--dur-1:0ms;--dur-2:0ms;--dur-3:0ms}
  *,*::before,*::after{animation-duration:0ms!important;transition-duration:0ms!important}
}
