/* Rightman OS — canonical stylesheet.

   Owns the design system: palette, type, and the shared components
   (buttons, tables, forms, cards, badges, shell). Page-specific
   layout rules can still live in template <style> blocks, but those
   blocks should reference the custom properties below — no hardcoded
   hex codes anywhere.

   The strict CSP allows 'unsafe-inline' for <style> blocks but not
   for <script>; self-hosted fonts + this stylesheet stay within the
   policy (`style-src 'self' 'unsafe-inline'`). No CDN.
*/

/* --- Fonts --------------------------------------------------------- */

@font-face {
  font-family: 'Inter';
  src: url('/static/fonts/Inter-Regular.woff2') format('woff2');
  font-weight: 400;
  font-display: swap;
  font-style: normal;
}
@font-face {
  font-family: 'Inter';
  src: url('/static/fonts/Inter-Medium.woff2') format('woff2');
  font-weight: 500;
  font-display: swap;
  font-style: normal;
}
@font-face {
  font-family: 'Inter';
  src: url('/static/fonts/Inter-SemiBold.woff2') format('woff2');
  font-weight: 600;
  font-display: swap;
  font-style: normal;
}
@font-face {
  font-family: 'Inter';
  src: url('/static/fonts/Inter-Bold.woff2') format('woff2');
  font-weight: 700;
  font-display: swap;
  font-style: normal;
}

/* --- Palette + tokens --------------------------------------------- */

/* The palette is the one the Rightman proposal documents use (2026-09-02,
   design pass 1 — Eduard's call: "the platform, in the same hand as the
   proposals"). One cool ground, ink for text and chrome, ONE action
   accent (mid blue), amber reserved for "needs a person". The token NAMES
   are kept so every existing component and per-page block picks the new
   values up unchanged: `--color-navy` IS the accent, whatever its hue. */
/* Dark is the DEFAULT (Eduard, 2026-09-02); the light set applies under
   <html data-theme="light">, which app.core.theme stamps from the
   rightman_theme cookie. Non-colour tokens live once, here. */
:root {
  --color-paper-fixed: #FFFFFF;  /* white in every theme: what the website's own header sits on (editor logo preview) */

  /* Type scale — a real hierarchy: titles lead, body stays dense enough
     for an operator tool, labels are small caps. */
  --font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
  --font-display: 32px;
  --font-h1: 26px;
  --font-h2: 19px;
  --font-h3: 15px;
  --font-lead: 15px;
  --font-body: 14px;
  --font-small: 13px;
  --font-caption: 12px;
  --font-micro: 11px;
  --tracking-kicker: 0.12em;

  /* Surfaces are flat: a 1px line and an 8px radius say "object"; shadow
     is spent only on things that float (popovers, the mobile drawer). */
  --radius: 6px;
  --radius-card: 8px;
  --shadow-card: none;

  /* Motion — Monday-calibrated: fast, eased functional feedback (hover,
     reveal, swap-settle). Animation must never sit between the operator
     and the data. (Slow/overshoot tokens arrive with the item-panel +
     celebration passes that need them.) */
  --motion-fast: 100ms;
  --motion-med: 180ms;
  --ease-standard: cubic-bezier(0.4, 0, 0.2, 1);
  /* A confident, product-grade ease for lifts/reveals — emphasis without
     a cartoonish overshoot. */
  --ease-emphasize: cubic-bezier(0.2, 0.8, 0.2, 1);

  /* Colours — the DARK set (default). The light set is below. */
  --color-navy: #7FB0E0;
  --color-navy-deep: #9CC3EA;
  --color-navy-light: #1D3049;
  --color-chrome: #0A111B;
  --color-amber: #E8A020;
  --color-amber-bright: #F0B043;
  --color-amber-wash: #241B0C;
  --color-on-accent: #0E1B2E;
  --color-ochre: #E8A020;
  --color-rust: #E8A020;
  --color-sand: #16202E;
  --color-off-white: #16202E;

  --color-text: #E8EDF4;
  --color-text-muted: #A7B4C4;
  --color-text-subtle: #7F8DA0;
  --color-border: #2A3644;
  --color-border-warm: #2A3644;
  --color-bg: #0F1722;
  --color-bg-elevated: #0F1722;
  --color-bg-section: #16202E;
  --color-plan: #9AA8B8;
  --color-plan-bg: #1C2530;

  --color-success: #6FCE9A;
  --color-success-bg: #12301F;
  --color-success-border: #1E5A3A;
  --color-warning: #E8A020;
  --color-warning-bg: #241B0C;
  --color-warning-border: #7A5A1A;
  --color-danger: #F09A9A;
  --color-danger-bg: #3A1A1A;
  --color-danger-border: #6A2A2A;
  --color-info: #7FB0E0;
  --color-info-bg: #1D3049;
  --color-info-border: #2C4A6B;
  /* Team-schedule shift washes (migration 0083): keys of team.service.COLORS. */
  --color-shift-blue: #1D3049;
  --color-shift-green: #12301F;
  --color-shift-violet: #2C2147;
  --color-shift-teal: #0F3433;
  --color-shift-rose: #3A1E2B;
  --color-shift-sand: #33291A;

  --shadow-pop: 0 8px 24px rgba(0, 0, 0, .5);
  /* The edge of a box that scrolls sideways (the client portal's people
     table): a soft shade on the side that has more to see. */
  --scroll-edge-shadow: rgba(0, 0, 0, .55);
  --hover-wash: rgba(232, 237, 244, 0.07);
  --shadow-card-hover: 0 4px 14px rgba(0, 0, 0, .35), 0 2px 6px rgba(0, 0, 0, .25);
}
:root[data-theme="light"] {
  --color-navy: #2F5D8F;          /* the one action accent (mid blue) */
  --color-navy-deep: #244B75;
  --color-navy-light: #DCE7F2;    /* accent wash: active nav, focus, chips */
  --color-chrome: #0E1B2E;        /* topbar — ink, like the proposals' chrome */
  --color-amber: #A3690A;         /* "needs a person": pending, attention */
  --color-amber-bright: #E8A020;
  --color-amber-wash: #FDF6E9;
  --color-on-accent: #FFFFFF;
  --color-ochre: #A3690A;
  --color-rust: #A3690A;
  --color-sand: #F4F6F9;
  --color-off-white: #F4F6F9;
  --color-text: #0E1B2E;
  --color-text-muted: #3D4C60;
  --color-text-subtle: #6B7A8F;
  --color-border: #D9E0E8;
  --color-border-warm: #D9E0E8;   /* the warm border is gone; one line colour */
  --color-bg: #FFFFFF;            /* paper */
  --color-bg-elevated: #FFFFFF;
  --color-bg-section: #F4F6F9;    /* wash: sidebar, secondary panels */
  --color-plan: #5A6A7E;          /* inert / roadmap / inactive */
  --color-plan-bg: #EDF1F5;
  --color-success: #1E7A46;
  --color-success-bg: #E6F4EC;
  --color-success-border: #BFE3CC;
  --color-warning: #A3690A;       /* = amber: a warning needs a person */
  --color-warning-bg: #FDF6E9;
  --color-warning-border: #E8A020;
  --color-danger: #9B2C2C;
  --color-danger-bg: #FBE9E9;
  --color-danger-border: #E9B9B9;
  --color-info: #2F5D8F;
  --color-info-bg: #DCE7F2;
  --color-info-border: #B9CFE6;
  --color-shift-blue: #DCEBFA;
  --color-shift-green: #E2F4E8;
  --color-shift-violet: #ECE6FA;
  --color-shift-teal: #DDF3F1;
  --color-shift-rose: #FBE6EE;
  --color-shift-sand: #F7EEDC;
  --shadow-pop: 0 8px 24px rgba(14, 27, 46, .14);
  --scroll-edge-shadow: rgba(14, 27, 46, .22);
  --hover-wash: rgba(107, 122, 143, 0.10);
  --shadow-card-hover: 0 4px 14px rgba(14, 27, 46, .08), 0 2px 6px rgba(14, 27, 46, .05);
}

/* --- Colour schemes (Eduard, 2026-09-29) ---------------------------------
   <html data-scheme="pink|babyblue">, stamped by app.core.theme from the
   rightman_scheme cookie (never stamped for the default). A scheme swaps
   the ACCENT family only — buttons, active nav, focus rings, links, the
   info colour and the topbar chrome — plus a tinted section wash in
   light. Grounds, text and the amber / green / red signals stay, so a
   warning means the same thing in every scheme. Each scheme has a dark
   set (the default theme) and a light set; `[data-theme="light"]
   [data-scheme=…]` outranks the plain light block by specificity.
   Accent text colours in the light sets hold ≥ 4.5:1 on white. */
:root[data-scheme="pink"] {
  --color-navy: #F4A6C9;
  --color-navy-deep: #F8C2DA;
  --color-navy-light: #3B1C2C;
  --color-on-accent: #2B0E1D;
  --color-chrome: #2A1020;
  --color-info: #F4A6C9;
  --color-info-bg: #3B1C2C;
  --color-info-border: #6E3553;
}
:root[data-theme="light"][data-scheme="pink"] {
  --color-navy: #B4366F;
  --color-navy-deep: #8E2757;
  --color-navy-light: #FBE4EF;
  --color-on-accent: #FFFFFF;
  --color-chrome: #3D1429;
  --color-info: #B4366F;
  --color-info-bg: #FBE4EF;
  --color-info-border: #F0BCD5;
  --color-bg-section: #FCF3F7;
  --color-sand: #FCF3F7;
  --color-off-white: #FCF3F7;
}
:root[data-scheme="babyblue"] {
  /* The default dark accent is already a light blue, so baby blue in dark
     earns its name through the sky tone AND a blue chrome + wash. */
  --color-navy: #8FDDFF;
  --color-navy-deep: #B8EAFF;
  --color-navy-light: #103A52;
  --color-on-accent: #062233;
  --color-chrome: #0C2A3D;
  --color-info: #8FDDFF;
  --color-info-bg: #103A52;
  --color-info-border: #22607F;
  --color-bg-section: #102334;
}
:root[data-theme="light"][data-scheme="babyblue"] {
  --color-navy: #1D6F9E;
  --color-navy-deep: #155A82;
  --color-navy-light: #DCF0FB;
  --color-on-accent: #FFFFFF;
  --color-chrome: #154E70;
  --color-info: #1D6F9E;
  --color-info-bg: #DCF0FB;
  --color-info-border: #AFDAF3;
  --color-bg-section: #F1F9FE;
  --color-sand: #F1F9FE;
  --color-off-white: #F1F9FE;
}

/* --- The party layer (Eduard, 2026-09-29: "a gimmick, so make it
   extreme"). Pink and baby blue only; the default scheme is untouched.
   Loud chrome, glowing actions, gradient titles — but the DATA surfaces
   (tables, forms, cards' text) keep their tokens, and every effect is
   decoration: the canvas takes no clicks, and the global reduced-motion
   rule stills every animation here. /static/scheme-fx.js draws the
   rainbows and splashes. */
.scheme-fx-canvas { position: fixed; inset: 0; pointer-events: none; z-index: 9999; }
/* "Welcome back, <name>" — once per tab, at most twice a day (scheme-fx.js). */
.scheme-welcome {
  position: fixed; left: 50%; top: calc(env(safe-area-inset-top, 0px) + 72px); z-index: 10000;
  transform: translateX(-50%); max-width: calc(100vw - 32px); box-sizing: border-box;
  padding: 14px 26px; border-radius: 999px; cursor: pointer;
  background: var(--color-bg-elevated); border: 1px solid var(--party-t2);
  box-shadow: 0 0 0 1px var(--party-glow), 0 10px 36px var(--party-glow);
  animation: scheme-welcome-in 700ms cubic-bezier(.2, 1.4, .4, 1) both;
}
.scheme-welcome-text {
  font-size: 1.25rem; font-weight: 800; letter-spacing: -.01em; white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis; display: block;
  background: linear-gradient(90deg, var(--party-t1), var(--party-t2), var(--party-t3), var(--party-t1));
  background-size: 300% 100%; -webkit-background-clip: text; background-clip: text; color: transparent;
  animation: party-slide 4s linear infinite;
}
.scheme-welcome.is-leaving { animation: scheme-welcome-out 500ms ease-in both; }
@keyframes scheme-welcome-in { from { opacity: 0; transform: translate(-50%, -24px) scale(.85); } to { opacity: 1; transform: translate(-50%, 0) scale(1); } }
@keyframes scheme-welcome-out { to { opacity: 0; transform: translate(-50%, -16px) scale(.95); } }
:root[data-scheme="pink"] { --party-a: #7A1446; --party-b: #C2307A; --party-c: #5B1A6E; --party-glow: rgba(255, 79, 163, .55); --party-t1: #FF4FA3; --party-t2: #FF9AD5; --party-t3: #C86BFF; }
:root[data-scheme="babyblue"] { --party-a: #0C4A6E; --party-b: #1D6F9E; --party-c: #0B5E7E; --party-glow: rgba(110, 200, 255, .55); --party-t1: #3DB8FF; --party-t2: #9EDCFF; --party-t3: #7AA8FF; }
/* On a white page the bright title tones would wash out — darker ones. */
:root[data-theme="light"][data-scheme="pink"] { --party-t1: #D6247F; --party-t2: #B4366F; --party-t3: #8A2BE2; }
:root[data-theme="light"][data-scheme="babyblue"] { --party-t1: #1570A8; --party-t2: #0F5E8E; --party-t3: #3F55C9; }
:root[data-scheme="pink"] header.topbar,
:root[data-scheme="babyblue"] header.topbar {
  background: linear-gradient(110deg, var(--party-a), var(--party-b), var(--party-c), var(--party-b), var(--party-a));
  background-size: 300% 100%;
  animation: party-slide 9s linear infinite;
  box-shadow: 0 2px 18px var(--party-glow);
}
@keyframes party-slide { from { background-position: 0% 50%; } to { background-position: 300% 50%; } }
:root[data-scheme="pink"] .btn-primary,
:root[data-scheme="babyblue"] .btn-primary {
  box-shadow: 0 0 0 1px var(--party-glow), 0 4px 16px var(--party-glow);
  transition: transform var(--motion-fast) var(--ease-standard), box-shadow var(--motion-med) var(--ease-standard);
}
:root[data-scheme="pink"] .btn-primary:hover,
:root[data-scheme="babyblue"] .btn-primary:hover { transform: translateY(-1px) scale(1.03); box-shadow: 0 0 0 2px var(--party-glow), 0 6px 26px var(--party-glow); }
:root[data-scheme="pink"] .page-header h1,
:root[data-scheme="babyblue"] .page-header h1 {
  background: linear-gradient(90deg, var(--party-t1), var(--party-t2), var(--party-t3), var(--party-t1));
  background-size: 300% 100%;
  -webkit-background-clip: text; background-clip: text; color: transparent;
  animation: party-slide 6s linear infinite;
}
:root[data-scheme="pink"] .nav-item.active a,
:root[data-scheme="babyblue"] .nav-item.active a { box-shadow: inset 3px 0 0 var(--party-t1), 0 0 14px var(--party-glow); }

/* The scheme picker: a swatch per scheme (fixed colours — a swatch shows
   the scheme you WOULD get, whatever is active now). */
.scheme-select { display: inline-flex; flex-wrap: wrap; gap: 6px; margin: 0; }
.scheme-btn { display: inline-flex; align-items: center; gap: 8px; min-height: 36px; padding: 4px 8px; border: 1px solid var(--color-border); border-radius: 999px; background: transparent; color: var(--color-text-muted); font: inherit; font-size: var(--font-small); cursor: pointer; }
.scheme-btn:hover { background: var(--color-bg-section); color: var(--color-text); }
.scheme-btn-active { border-color: var(--color-navy); box-shadow: 0 0 0 2px var(--color-navy-light); color: var(--color-text); cursor: default; }
.scheme-dot { display: inline-block; width: 20px; height: 20px; border-radius: 999px; border: 1px solid rgba(127, 127, 127, .35); }
.scheme-dot-default { background: linear-gradient(135deg, #2F5D8F 50%, #7FB0E0 50%); }
.scheme-dot-pink { background: linear-gradient(135deg, #B4366F 50%, #F4A6C9 50%); }
.scheme-dot-babyblue { background: linear-gradient(135deg, #1D6F9E 50%, #8FDDFF 50%); }

/* The projects module used to wear its own indigo accent (scoped token
   override on main.pj-app). Folded into the one app-wide accent on
   2026-09-02 — Eduard's call in the design pass: one accent everywhere.
   The .pj-app class stays on the wrapper (projects-board.js and the
   module's own blocks scope to it); only the colour override is gone. */
/* A restrained one-shot pulse when an item reaches a terminal (Done)
   status — the small "it's done" moment, no confetti. Fires only on the
   just-changed item's chip (server tags it after the move); the global
   prefers-reduced-motion block collapses it to nothing. */
.pj-app .pj-celebrate { animation: pj-done-pulse 520ms var(--ease-emphasize); transform-origin: left center; }
@keyframes pj-done-pulse {
  0%   { transform: scale(1); }
  35%  { transform: scale(1.18); }
  62%  { transform: scale(0.97); }
  100% { transform: scale(1); }
}

/* Horizontal-scroll wrapper so a wide table scrolls sideways inside its
   own box on a narrow screen instead of clipping or pushing the page
   wide. App-wide-safe (additive). */
.table-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }

/* Accessibility + trust: honour the OS "reduce motion" setting everywhere
   — animations collapse to near-instant, no parallax/scroll hijack. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

html { color-scheme: dark; }
:root[data-theme="light"] { color-scheme: light; }
/* Rendered source previews (spreadsheets, PDFs, photos) are documents
   and stay light in both themes. */
.source-frame iframe { background: #FFFFFF; }

/* --- Reset + base ------------------------------------------------- */

*, *::before, *::after { box-sizing: border-box; }
html, body { height: 100%; }
body {
  margin: 0;
  background: var(--color-bg);
  color: var(--color-text);
  font-family: var(--font-family);
  font-size: var(--font-body);
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}
a { color: inherit; }

h1, h2, h3, h4, h5, h6 {
  line-height: 1.25;
  margin: 0 0 0.5em;
  text-wrap: balance;
}
h1 { font-size: var(--font-h1); font-weight: 700; letter-spacing: -0.02em; }
h2 { font-size: var(--font-h2); font-weight: 700; letter-spacing: -0.01em; }
h3 { font-size: var(--font-h3); font-weight: 600; }

/* --- Page header pattern ------------------------------------------ */
/* Kicker (the module the page belongs to, set by base.html from the
   active nav group) above the page's own <h1>; a lead sentence and a
   folded "How this page works" replace the old beige help panel
   (_page_help.html). The kicker is a small-caps label in the accent —
   the same eyebrow the proposal documents open every section with. */
.page-kicker {
  margin: 0 0 0.3rem;
  font-size: var(--font-micro);
  font-weight: 700;
  letter-spacing: var(--tracking-kicker);
  text-transform: uppercase;
  color: var(--color-navy);
}
.page-help { margin: -0.2rem 0 1.4rem; max-width: 70ch; }
.page-lead {
  margin: 0;
  font-size: var(--font-lead);
  line-height: 1.5;
  color: var(--color-text-muted);
}
.page-how { margin: 0.35rem 0 0; font-size: var(--font-small); color: var(--color-text-muted); }
.page-how > summary {
  cursor: pointer;
  list-style: none;
  color: var(--color-navy);
  font-weight: 600;
  user-select: none;
}
.page-how > summary::-webkit-details-marker { display: none; }
.page-how > summary::before {
  content: "\25B8";  /* ▸ — rotates to ▾ when open */
  display: inline-block;
  margin-right: 0.35rem;
  font-size: 0.75em;
  transition: transform var(--motion-fast) var(--ease-standard);
}
.page-how[open] > summary::before { transform: rotate(90deg); }
.page-how p { margin: 0.4rem 0 0; line-height: 1.55; }

p { margin: 0 0 1rem; }
code {
  font-family: ui-monospace, 'SF Mono', Consolas, monospace;
  font-size: 0.9em;
}

/* --- Keyboard focus ----------------------------------------------- */
/* Every interactive control needs a visible focus indicator for keyboard
   operators (WCAG 2.4.7). :focus-visible keeps the ring off mouse clicks
   but shows it on Tab. Form inputs keep their own border+ring rule below.
   :where() carries zero specificity, so any component can still override. */
:where(a, button, summary, [tabindex="0"]):focus-visible {
  outline: 2px solid var(--color-navy);
  outline-offset: 2px;
}
/* The topbar sits on navy — a navy ring would vanish there, so the
   controls inside it get the light-blue token instead. */
.topbar :where(a, button, label):focus-visible {
  outline-color: var(--color-navy-light);
}

/* --- App shell ---------------------------------------------------- */
/* One shell, three shapes:
   - desktop (>=769px): fixed topbar + 16rem sidebar, only .content
     scrolls. The burger collapses the sidebar to a 3.5rem icon rail —
     <html data-nav="collapsed">, remembered per browser in a cookie the
     burger's handler writes (shell.js) and the server reads
     (app.core.theme), so the rail never flashes open on load.
   - phone / tablet (<=768px): sticky topbar, the sidebar becomes an
     off-canvas drawer (CSS checkbox, no JS), a bottom tab bar carries the
     four most-used destinations + Menu, and the page scrolls normally.
   - installed as an app (standalone): the same, plus safe-area padding
     under the phone's status bar and above its home indicator
     (viewport-fit=cover in the page bases).
   Touch: 44px rows in the drawer and tab bar, 40px controls. */
:root {
  --topbar-h: 3.25rem;
  --sidebar-w: 16rem;
  --rail-w: 3.5rem;
  --tabbar-h: 3.5rem;
  --safe-top: env(safe-area-inset-top, 0px);
  /* 0 in a BROWSER on purpose — see the standalone override below. */
  --safe-bottom: 0px;
  --safe-left: env(safe-area-inset-left, 0px);
  --safe-right: env(safe-area-inset-right, 0px);
}

/* The bottom inset applies only to the INSTALLED app.
   `viewport-fit=cover` lets the page paint under the phone's chrome, and
   `env(safe-area-inset-bottom)` says how much to keep clear. Installed,
   that value is static. In a browser tab it is not: the UA's own toolbar
   hides as you scroll and the inset grows, so the fixed tab bar, the
   drawer and `main.content`'s bottom padding — every consumer of this
   one variable — resized mid-scroll (Eduard, 2026-09-25: "when scrolling
   the bottom menu bar increases in size"). It showed up on /clients and
   /workers first because those are the long lists. A browser tab keeps
   its own chrome above the home indicator, so 0 is right there; the
   installed app, which has no chrome, still gets the real inset. */
@media (display-mode: standalone), (display-mode: fullscreen), (display-mode: minimal-ui) {
  :root { --safe-bottom: env(safe-area-inset-bottom, 0px); }
}

.app {
  display: grid;
  grid-template-rows: auto 1fr;
  /* minmax(0,1fr) lets the column shrink below its content's min-content,
     so a wide child (table, 2-col widget) scrolls inside .content instead
     of blowing the whole shell wider than the viewport. */
  grid-template-columns: minmax(0, 1fr);
  min-height: 100vh;
  min-height: 100dvh;
}

header.topbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  padding: var(--safe-top) calc(0.9rem + var(--safe-right)) 0 calc(0.6rem + var(--safe-left));
  height: calc(var(--topbar-h) + var(--safe-top));
  background: var(--color-chrome);
  color: #fff;
  border-bottom: 1px solid rgba(255, 255, 255, 0.08);
  position: relative;
  z-index: 30;
}
.topbar-left { display: flex; align-items: center; gap: 0.35rem; min-width: 0; }
.nav-burger {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  border-radius: 6px;
  color: #fff;
  cursor: pointer;
  flex: none;
}
.nav-burger:hover { background: rgba(255, 255, 255, 0.12); }
.burger-icon {
  width: 22px;
  height: 22px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
}
/* Visually-hidden checkbox that drives the phone drawer (kept operable). */
.nav-toggle { position: absolute; width: 1px; height: 1px; opacity: 0; pointer-events: none; }
.nav-backdrop { display: none; }
.wordmark { display: flex; align-items: center; text-decoration: none; min-width: 0; }
.wordmark-logo { display: block; height: 36px; width: auto; }
.topbar-right { display: flex; align-items: center; gap: 0.5rem; flex: none; min-width: 0; }
/* The person as a chip → /preferences. Initials always; the name only
   where there is room (hidden on phones). */
.user-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  min-height: 40px;
  padding: 0 0.6rem 0 0.3rem;
  border-radius: 999px;
  color: rgba(255, 255, 255, 0.85);
  text-decoration: none;
  font-size: var(--font-small);
  max-width: 16rem;
}
.user-chip:hover, .user-chip.active { background: rgba(255, 255, 255, 0.1); color: #fff; }
.user-chip .avatar-chip {
  width: 28px;
  height: 28px;
  background: rgba(255, 255, 255, 0.16);
  color: #fff;
  font-size: var(--font-caption);
}
.user-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.signout-form { display: block; margin: 0; }
/* Account menu — a native <details> popover under the chip. */
.user-menu { position: relative; }
.user-menu > summary { list-style: none; user-select: none; }
.user-menu > summary::-webkit-details-marker { display: none; }
.user-menu[open] > summary { background: rgba(255, 255, 255, 0.14); color: #fff; }
.user-menu-panel {
  position: absolute;
  top: calc(100% + 6px);
  right: 0;
  z-index: 60;
  width: min(19rem, calc(100vw - 1rem));
  padding: 0.5rem;
  background: var(--color-bg-elevated);
  color: var(--color-text);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-pop);
  font-size: var(--font-small);
}
.user-menu-head { display: flex; flex-direction: column; gap: 1px; padding: 0.45rem 0.6rem 0.6rem; border-bottom: 1px solid var(--color-border); margin-bottom: 0.35rem; }
.user-menu-head strong { color: var(--color-text); font-weight: 600; }
.user-menu-head span { color: var(--color-text-subtle); font-size: var(--font-caption); overflow-wrap: anywhere; }
.user-menu-row { display: flex; align-items: center; justify-content: space-between; gap: 0.75rem; padding: 0.35rem 0.6rem; }
.user-menu-label { color: var(--color-text-muted); }
/* The switches take the segmented look here (their default is white-on-chrome). */
.user-menu-panel .lang-select { display: inline-flex; gap: 0; border: 1px solid var(--color-border); border-radius: var(--radius); overflow: hidden; background: var(--color-bg-elevated); }
.user-menu-panel .lang-btn { min-height: 36px; padding: 4px 12px; border: 0; border-right: 1px solid var(--color-border); border-radius: 0; color: var(--color-text-muted); background: transparent; }
.user-menu-panel .lang-btn:last-child { border-right: 0; }
.user-menu-panel .lang-btn:hover { background: var(--color-bg-section); color: var(--color-text); }
.user-menu-panel .lang-btn-active { background: var(--color-navy); color: var(--color-on-accent); }
.user-menu-item {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  width: 100%;
  min-height: 40px;
  padding: 6px 0.6rem;
  margin-top: 2px;
  border: 0;
  border-radius: var(--radius);
  background: none;
  color: var(--color-text);
  font: inherit;
  font-size: var(--font-small);
  font-weight: 500;
  text-align: left;
  text-decoration: none;
  cursor: pointer;
}
.user-menu-item:hover { background: var(--hover-wash); }
.user-menu-item .nav-icon { color: var(--color-text-subtle); }
.user-menu-panel .signout-form { border-top: 1px solid var(--color-border); margin-top: 0.35rem; padding-top: 0.35rem; }
/* The Preferences gear: the same pill as the person chip, icon + word;
   on a phone the word goes and the gear stays (40px target). */
.prefs-btn { padding: 0 0.7rem 0 0.55rem; gap: 0.4rem; }
.prefs-btn .nav-icon { width: 20px; height: 20px; flex: none; }
.prefs-panel { width: min(17rem, calc(100vw - 1rem)); }

/* Language / theme selectors on the LOGIN card (the topbar no longer
   carries them — see /preferences). Default styling is white-on-dark;
   body.auth overrides it for the card below. CSP-safe submit groups. */
.lang-select { display: inline-flex; gap: 2px; margin: 0; }
.lang-btn {
  font: inherit;
  font-size: var(--font-small);
  color: rgba(255, 255, 255, 0.7);
  background: transparent;
  border: 1px solid rgba(255, 255, 255, 0.3);
  padding: 3px 8px;
  border-radius: var(--radius);
  cursor: pointer;
}
.lang-btn:hover { background: rgba(255, 255, 255, 0.1); color: #fff; }
.lang-btn-active { background: rgba(255, 255, 255, 0.2); color: #fff; cursor: default; }

.layout {
  display: grid;
  grid-template-columns: var(--sidebar-w) minmax(0, 1fr);
  min-width: 0;
  min-height: 0;
}
/* Sidebar on the wash, items as quiet rounded rows, the active one on the
   accent wash in ink. Group headers are kicker labels (small caps in the
   accent) rather than icon rows, so the eye reads the page names, not
   the chrome. The footer (Preferences, Sign out) is pinned to the bottom. */
aside.sidebar {
  background: var(--color-bg-section);
  border-right: 1px solid var(--color-border);
  padding: 0.75rem 0.6rem;
  display: flex;
  flex-direction: column;
}
.sidebar-nav { flex: 1 1 auto; }
.nav-footer { margin-top: 0.75rem; padding-top: 0.6rem; border-top: 1px solid var(--color-border); }
.nav-list { list-style: none; margin: 0; padding: 0; }
.nav-item a, .nav-signout {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  width: 100%;
  padding: 7px 10px;
  margin: 1px 0;
  border: 0;
  border-radius: var(--radius);
  background: none;
  color: var(--color-text-muted);
  text-decoration: none;
  font: inherit;
  font-size: var(--font-small);
  font-weight: 500;
  text-align: left;
  cursor: pointer;
}
.nav-icon {
  flex: 0 0 auto;
  width: 16px;
  height: 16px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.75;
  stroke-linecap: round;
  stroke-linejoin: round;
  color: var(--color-text-subtle);
}
.nav-label { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.nav-item a:hover, .nav-signout:hover {
  background: var(--hover-wash);
  color: var(--color-text);
}
.nav-item a:hover .nav-icon, .nav-signout:hover .nav-icon { color: var(--color-text-muted); }
.nav-item.active a {
  background: var(--color-navy-light);
  color: var(--color-text);
  font-weight: 600;
}
.nav-item.active a .nav-icon { color: var(--color-navy); }
/* "Admin" group label above the admin-only links. */
.nav-section {
  margin: 0.9rem 0 0.2rem;
  padding: 0 10px;
  font-size: var(--font-micro);
  font-weight: 700;
  letter-spacing: var(--tracking-kicker);
  text-transform: uppercase;
  color: var(--color-navy);
}

/* --- Sidebar feature groups + roadmap rows ------------------------ */
/* Each live feature is a collapsible <details> group; the timesheet
   feature is open by default. Native <details> keeps this CSS/JS-free
   and CSP-safe (no inline script). The summary renders as a kicker
   label; its icon is hidden and the caret stays as a small affordance. */
.nav-group { list-style: none; }
.nav-group-summary {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  margin: 0.9rem 0 0.2rem;
  padding: 0 10px;
  color: var(--color-navy);
  font-size: var(--font-micro);
  font-weight: 700;
  letter-spacing: var(--tracking-kicker);
  text-transform: uppercase;
  cursor: pointer;
  list-style: none;             /* hide the default disclosure triangle */
  user-select: none;
}
.nav-group-summary::-webkit-details-marker { display: none; }
.nav-group-summary:hover { color: var(--color-navy-deep); }
.nav-group-summary .nav-icon { display: none; }
.nav-caret {
  flex: 0 0 auto;
  width: 12px;
  height: 12px;
  margin-left: auto;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
  color: var(--color-text-subtle);
  transition: transform 0.18s ease;
}
.nav-group-details[open] > .nav-group-summary .nav-caret { transform: rotate(180deg); }
/* A group's items sit inside a thin guide line, so where a group ENDS is
   visible — open or folded — and the ungrouped items under their own
   "More" heading never read as the last group's tail (Eduard, 2026-09-29). */
.nav-sublist { margin: 0 0 0.35rem 12px; padding-left: 2px; border-left: 1px solid var(--color-border); }
.nav-sublist .nav-item a { padding-left: 10px; }

/* Roadmap features — visible but inert, with a "Soon" pill. */
.nav-item-soon .nav-soon-row {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  padding: 7px 10px;
  margin: 1px 0;
  color: var(--color-text-subtle);
  font-size: var(--font-small);
  cursor: default;
}
.nav-item-soon .nav-icon { color: var(--color-text-subtle); opacity: 0.7; }
.nav-soon-badge {
  margin-left: auto;
  flex: 0 0 auto;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-plan);
  background: var(--color-plan-bg);
  border: 1px solid var(--color-plan);
  border-radius: 999px;
  padding: 0 7px;
  line-height: 1.5;
}

main.content { padding: 1.6rem 1.9rem 2rem; min-width: 0; }

/* --- Phone tab bar --------------------------------------------------- */
/* Fixed to the bottom on phones (hidden on desktop below): the four
   most-used destinations + Menu. Labels are tiny on purpose — the icon
   is the target, the word confirms it. */
.tabbar {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 30;
  display: flex;
  align-items: stretch;
  height: calc(var(--tabbar-h) + var(--safe-bottom));
  padding: 0 var(--safe-right) var(--safe-bottom) var(--safe-left);
  background: var(--color-bg-elevated);
  border-top: 1px solid var(--color-border);
}
.tabbar-item {
  flex: 1 1 0;
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 3px;
  padding: 6px 2px;
  color: var(--color-text-subtle);
  text-decoration: none;
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.01em;
  cursor: pointer;
  user-select: none;
}
.tabbar-item .nav-icon { width: 22px; height: 22px; color: inherit; stroke-width: 1.6; }
.tabbar-item span { max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tabbar-item.active { color: var(--color-navy); }
.tabbar-item:hover { color: var(--color-text); }

/* Fixed app shell (desktop): pin the shell to the viewport so the topbar
   and sidebar stay put and only .content scrolls. Each region owns its
   overflow; min-height:0 lets the grid items shrink to the track instead
   of growing with their content. The collapsed rail keeps every item as
   an icon with its title as the tooltip; group kickers become thin rules
   so the groups stay open. */
@media (min-width: 769px) {
  .app { height: 100vh; height: 100dvh; }
  .layout { min-height: 0; }
  aside.sidebar { min-height: 0; overflow-y: auto; }
  main.content { min-height: 0; overflow-y: auto; }
  .tabbar { display: none; }

}
/* The icon rail. Shown when the person collapsed the sidebar, AND by
   default between 769px and 1023px (a tablet, a landscape phone), where a
   16rem sidebar would take a third of the screen — unless they explicitly
   expanded it (data-nav="expanded"). */
@media (min-width: 769px) and (max-width: 1023px) {
  html:not([data-nav="expanded"]) .layout { grid-template-columns: var(--rail-w) minmax(0, 1fr); }
  html:not([data-nav="expanded"]) aside.sidebar { padding: 0.75rem 0.4rem; overflow-x: hidden; }
  html:not([data-nav="expanded"]) .nav-label,
  html:not([data-nav="expanded"]) .nav-caret,
  html:not([data-nav="expanded"]) .nav-section,
  html:not([data-nav="expanded"]) .nav-soon-badge { display: none; }
  html:not([data-nav="expanded"]) .nav-item a,
  html:not([data-nav="expanded"]) .nav-sublist .nav-item a,
  html:not([data-nav="expanded"]) .nav-soon-row,
  html:not([data-nav="expanded"]) .nav-signout { justify-content: center; padding: 9px 0; }
  html:not([data-nav="expanded"]) .nav-icon { width: 18px; height: 18px; }
  html:not([data-nav="expanded"]) .nav-sublist { margin: 0; padding: 0; border-left: 0; }
  html:not([data-nav="expanded"]) .nav-group-summary {
    height: 0;
    margin: 0.55rem 0.35rem;
    padding: 0;
    border-top: 1px solid var(--color-border);
    pointer-events: none;
    overflow: hidden;
  }
  main.content { padding: 1.2rem 1.25rem 1.6rem; }
}
@media (min-width: 769px) {
  html[data-nav="collapsed"] .layout { grid-template-columns: var(--rail-w) minmax(0, 1fr); }
  html[data-nav="collapsed"] aside.sidebar { padding: 0.75rem 0.4rem; overflow-x: hidden; }
  html[data-nav="collapsed"] .nav-label,
  html[data-nav="collapsed"] .nav-caret,
  html[data-nav="collapsed"] .nav-section,
  html[data-nav="collapsed"] .nav-soon-badge { display: none; }
  html[data-nav="collapsed"] .nav-item a,
  html[data-nav="collapsed"] .nav-sublist .nav-item a,
  html[data-nav="collapsed"] .nav-soon-row,
  html[data-nav="collapsed"] .nav-signout { justify-content: center; padding: 9px 0; }
  html[data-nav="collapsed"] .nav-icon { width: 18px; height: 18px; }
  html[data-nav="collapsed"] .nav-sublist { margin: 0; padding: 0; border-left: 0; }
  html[data-nav="collapsed"] .nav-group-summary {
    height: 0;
    margin: 0.55rem 0.35rem;
    padding: 0;
    border-top: 1px solid var(--color-border);
    pointer-events: none;
    overflow: hidden;
  }
}
/* Touch sizing wherever the pointer is a finger — an iPad at 1024px is
   still touched, not clicked. Same rules the phone layer applies by width. */
@media (pointer: coarse) {
  main.content input:not([type="checkbox"]):not([type="radio"]):not([type="file"]):not([type="range"]),
  main.content select,
  main.content textarea { font-size: 16px !important; min-height: 44px; }
  main.content textarea { min-height: 5rem; }
  .btn-primary, .btn-secondary, .btn-danger, .btn-quiet, .chip-btn, .pager-link, .seg-btn { min-height: 40px; }
  .page-how > summary { display: inline-flex; align-items: center; min-height: 32px; }
  main.content input[type="checkbox"], main.content input[type="radio"] { width: 20px; height: 20px; }
  table.data td.actions a, table.overview td.actions a { display: inline-block; padding: 8px 0; }
}
/* A landscape phone is short, not narrow: the tab bar would take a fifth
   of the height. The drawer (burger) still carries everything. */
@media (max-width: 768px) and (max-height: 500px) {
  .tabbar { display: none; }
  main.content { padding-bottom: 1rem; }
}

/* --- Phone shell ------------------------------------------------------ */
/* Below 768px the sidebar is an off-canvas drawer toggled by #nav-toggle
   (CSS-only); the topbar sticks; the tab bar (above) takes the bottom. */
@media (max-width: 768px) {
  header.topbar { position: sticky; top: 0; }
  .layout { grid-template-columns: minmax(0, 1fr); }
  aside.sidebar {
    position: fixed;
    top: calc(var(--topbar-h) + var(--safe-top));
    left: 0;
    bottom: 0;
    width: min(var(--sidebar-w), 86vw);
    z-index: 40;
    transform: translateX(-100%);
    transition: transform 0.22s var(--ease-standard);
    overflow-y: auto;
    box-shadow: 2px 0 16px rgba(0, 0, 0, 0.28);
    padding-left: calc(0.6rem + var(--safe-left));
    padding-bottom: calc(0.75rem + var(--safe-bottom));
  }
  #nav-toggle:checked ~ .app aside.sidebar { transform: translateX(0); }
  .nav-backdrop {
    position: fixed;
    inset: calc(var(--topbar-h) + var(--safe-top)) 0 0 0;
    z-index: 35;
    background: rgba(0, 0, 0, 0.45);
  }
  #nav-toggle:checked ~ .nav-backdrop { display: block; }
  /* 44px rows: a thumb, not a cursor. */
  .nav-item a, .nav-sublist .nav-item a, .nav-signout, .nav-soon-row { min-height: 44px; padding: 10px 12px; }
  .nav-group-summary { min-height: 40px; align-items: center; margin-top: 0.5rem; }
  main.content {
    padding: 0.9rem calc(0.9rem + var(--safe-right)) calc(var(--tabbar-h) + var(--safe-bottom) + 1.25rem) calc(0.9rem + var(--safe-left));
    /* A page never scrolls sideways on a phone: anything wider than the
       screen is a bug in that page (it should scroll inside its own box
       or collapse to cards), and the phone layer at the end of this file
       handles the shared cases. `clip` keeps this from becoming a
       scroll container (so sticky children still work); `hidden` is the
       fallback for older engines. */
    overflow-x: hidden;
    overflow-x: clip;
  }
  .user-name { display: none; }
  .prefs-label { display: none; }
  .prefs-btn { padding: 0 0.55rem; }
  .wordmark-logo { height: 32px; }
}

/* --- Buttons ------------------------------------------------------ */

.btn-primary,
.btn-secondary,
.btn-text,
.btn-danger {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font: inherit;
  font-size: var(--font-small);
  font-weight: 600;
  padding: 8px 14px;
  border-radius: var(--radius);
  cursor: pointer;
  text-decoration: none;
  line-height: 1.2;
  transition: background-color var(--motion-fast) var(--ease-standard),
    border-color var(--motion-fast) var(--ease-standard),
    box-shadow var(--motion-fast) var(--ease-standard),
    color var(--motion-fast) var(--ease-standard);
}
.btn-primary:active:not(:disabled),
.btn-secondary:active,
.btn-text:active,
.btn-danger:active { transform: translateY(0.5px); }
.btn-primary {
  background: var(--color-navy);
  color: var(--color-on-accent);
  border: 1px solid var(--color-navy);
}
.btn-primary:hover:not(:disabled) { background: var(--color-navy-deep); border-color: var(--color-navy-deep); }
.btn-primary:disabled {
  background: var(--color-text-subtle);
  border-color: var(--color-text-subtle);
  cursor: not-allowed;
}
/* Secondary is a quiet paper button: line border, ink text. The accent
   is spent on primary only, so a row of secondaries never shouts. */
.btn-secondary {
  background: var(--color-bg-elevated);
  color: var(--color-text);
  border: 1px solid var(--color-border);
}
.btn-secondary:hover { background: var(--color-bg-section); border-color: var(--color-text-subtle); }
.btn-text {
  background: transparent;
  color: var(--color-navy);
  border: none;
  padding: 4px 8px;
}
.btn-text:hover { background: var(--color-navy-light); }
.btn-danger {
  background: var(--color-bg-elevated);
  color: var(--color-danger);
  border: 1px solid var(--color-danger-border);
}
.btn-danger:hover { background: var(--color-danger-bg); }

/* --- Tables ------------------------------------------------------- */

table.data {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--font-small);
  background: var(--color-bg-elevated);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-card);
  overflow: hidden;
}
/* Column heads are kicker labels in the accent on plain paper — the
   proposal documents' table voice. No filled header band. */
table.data th {
  text-align: left;
  padding: 9px 12px;
  font-weight: 700;
  color: var(--color-navy);
  font-size: var(--font-micro);
  text-transform: uppercase;
  letter-spacing: 0.1em;
  border-bottom: 1px solid var(--color-border);
}
table.data td {
  padding: 10px 12px;
  border-bottom: 1px solid var(--color-border);
  vertical-align: top;
}
table.data tbody tr:last-child td { border-bottom: none; }
table.data tbody tr:hover { background: var(--hover-wash); }
table.data td.muted { color: var(--color-text-subtle); }
table.data td.num { text-align: right; font-variant-numeric: tabular-nums; }
table.data tr.row-link { cursor: pointer; }
table.data tr.row-link a { color: inherit; text-decoration: none; }
table.data tr.row-link a:hover { color: var(--color-text); }
/* Whole-row click affordance for list tables (workers, clients): the row
   hovers as a unit and the first cell carries the link that fills the row. */
table.data tr.row-link:hover { background: var(--hover-wash); }

/* --- Tab strip ------------------------------------------------------ */
/* One underline tab voice for every page with tabs (review queues,
   dedup, projects). The active tab is ink with an ink rule; counts are
   tabular and quiet, except a count that needs a person (.hot). */
.tabs {
  display: flex;
  flex-wrap: wrap;
  gap: 1.4rem;
  border-bottom: 1px solid var(--color-border);
  margin: 0 0 1.25rem;
}
.tabs a, .tabs span.tab {
  display: inline-block;
  padding: 0.5rem 0;
  margin-bottom: -1px;
  color: var(--color-text-muted);
  text-decoration: none;
  font-size: var(--font-body);
  font-weight: 500;
  border-bottom: 2px solid transparent;
  white-space: nowrap;
}
.tabs a:hover { color: var(--color-text); }
.tabs a.active, .tabs span.tab.active {
  color: var(--color-text);
  font-weight: 600;
  border-bottom-color: var(--color-text);
}
.tabs .count {
  color: var(--color-text-subtle);
  font-weight: 400;
  margin-left: 0.3rem;
  font-variant-numeric: tabular-nums;
}
.tabs .count.hot { color: var(--color-amber); font-weight: 700; }

/* --- Pager ---------------------------------------------------------- */
.pager {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 1rem;
  margin-top: 1rem;
  font-size: var(--font-body);
}
.pager-link {
  padding: 6px 14px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  text-decoration: none;
  color: var(--color-navy);
  background: var(--color-bg-elevated);
  font-weight: 500;
}
.pager-link:hover { background: var(--color-bg-section); }
.pager-link.disabled {
  color: var(--color-text-subtle);
  background: var(--color-bg-section);
  pointer-events: none;
}
.pager-status { color: var(--color-text-muted); font-variant-numeric: tabular-nums; }

/* --- Empty state ---------------------------------------------------- */
.empty-state {
  text-align: center;
  color: var(--color-text-subtle);
  padding: 3rem 1rem;
  background: var(--color-bg-elevated);
  border: 1px dashed var(--color-border);
  border-radius: var(--radius-card);
  font-size: var(--font-body);
}

/* --- Stat tile ------------------------------------------------------ */
/* A figure with a small-caps label and a note under it — the dashboard
   counts, the metrics headline rates, the projects cockpit. On the wash
   so a row of them reads as one strip, not four boxes. `.attn` is the
   amber "needs a person" figure; `.good` the green one. */
.stat {
  background: var(--color-bg-section);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-card);
  padding: 16px 18px 14px;
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-width: 0;
}
.stat-label {
  font-size: var(--font-micro);
  font-weight: 700;
  letter-spacing: var(--tracking-kicker);
  text-transform: uppercase;
  color: var(--color-navy);
}
.stat-value {
  font-size: var(--font-display);
  font-weight: 700;
  letter-spacing: -0.025em;
  line-height: 1.05;
  color: var(--color-text);
  font-variant-numeric: tabular-nums;
}
.stat-value.attn { color: var(--color-amber); }
.stat-value.good { color: var(--color-success); }
.stat-note { font-size: var(--font-small); color: var(--color-text-muted); }
.stat-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 0.75rem;
  margin: 0 0 1rem;
}

/* --- Quiet button + chip button ------------------------------------- */
/* .btn-quiet: the routine, low-emphasis action inside a table row or a
   toolbar (remove, update, zoom). Line border, muted text, ink on hover;
   danger colour only on hover when it also carries .btn-quiet-danger.
   .chip-btn: a suggestion the operator can take in one click ("Did you
   mean?" workers, worker-vote clients) — accent outline, fills on hover. */
.btn-quiet {
  font: inherit;
  font-size: var(--font-small);
  color: var(--color-text-muted);
  background: transparent;
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  padding: 4px 10px;
  cursor: pointer;
  line-height: 1.4;
  text-decoration: none;
}
.btn-quiet:hover { background: var(--color-bg-section); color: var(--color-text); }
.btn-quiet-danger:hover { border-color: var(--color-danger); color: var(--color-danger); background: transparent; }
.btn-quiet[aria-disabled="true"] { opacity: 0.5; cursor: default; }
/* form[data-submit-once] after the first press (review-actions.js) */
form[data-submitted] button[aria-disabled="true"] { opacity: 0.6; cursor: progress; }
.chip-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font: inherit;
  font-size: var(--font-small);
  font-weight: 500;
  color: var(--color-navy);
  background: var(--color-bg-elevated);
  border: 1px solid var(--color-navy);
  border-radius: 999px;
  padding: 3px 11px;
  cursor: pointer;
  text-decoration: none;
}
.chip-btn:hover { background: var(--color-navy); color: var(--color-on-accent); }
.chip-btn small { font-size: var(--font-micro); opacity: 0.7; }

/* --- Period state badge --------------------------------------------- */
/* The one chip for a tracker period's state, wherever a period appears
   (review header, month siblings, clients/workers period lists). Same
   voice as .badge; the state classes are what tests and templates key
   on, so they stay. */
.state-badge {
  display: inline-block;
  font-size: var(--font-micro);
  font-weight: 700;
  padding: 1px 8px;
  border-radius: 999px;
  border: 1px solid currentColor;
  line-height: 1.5;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  white-space: nowrap;
}
.state-pending_review { background: var(--color-navy-light); color: var(--color-navy); }
.state-accepted { background: var(--color-success-bg); color: var(--color-success); }
.state-rejected { background: var(--color-danger-bg); color: var(--color-danger); }

/* --- Notices -------------------------------------------------------- */
/* An in-page message with a left rail: info explains something the
   platform did, warning asks the operator to decide, danger blocks.
   Pages add their own class for layout (.provenance, .overlap-warning…)
   and take colour from here. */
.notice {
  padding: 10px 14px;
  border: 1px solid var(--color-border);
  border-left: 4px solid var(--color-text-subtle);
  border-radius: var(--radius);
  background: var(--color-bg-section);
  font-size: var(--font-small);
  color: var(--color-text);
  line-height: 1.5;
}
.notice ul { margin: 6px 0 0; padding-left: 18px; }
.notice li { margin-top: 3px; }
.notice-info { background: var(--color-info-bg); border-color: var(--color-info-border); border-left-color: var(--color-info); }
.notice-warning { background: var(--color-warning-bg); border-color: var(--color-warning-border); border-left-color: var(--color-amber-bright); }
.notice-danger { background: var(--color-danger-bg); border-color: var(--color-danger-border); border-left-color: var(--color-danger); }
.notice-success { background: var(--color-success-bg); border-color: var(--color-success-border); border-left-color: var(--color-success); }

/* --- Review per-worker accordion ---------------------------------- */
/* Collapses a period's flat day-by-day list into one expandable group
   per worker (summary = days + total hours + status). */
.worker-groups { display: flex; flex-direction: column; gap: 0.5rem; }
.worker-group {
  border: 1px solid var(--color-border);
  border-radius: 6px;
  background: var(--color-bg-elevated);
  overflow: hidden;
  /* No `content-visibility: auto` here any more (2026-11-10). It was added
     on 2026-05-28 for a 17-worker / 340-entry period whose every group
     was open; since the worker-by-worker accordion (2026-09-07) a period
     with more than ten entries opens ONE group, and a closed <details>
     renders only its summary, so it saved nothing. It cost a layout jump:
     an offscreen group was laid out at the 180px placeholder and grew to
     its real height only as it scrolled into view, pushing everything
     below it — Accept & save — down by the difference while the operator
     scrolled towards it. In WebKit a click on Accept then missed (CI,
     2026-11-10: a 312px group, Accept moved 132px between the aim and the
     press; tests/e2e/test_month_guards.py pins that nothing moves). */
}
.worker-group.wg-unresolved { border-color: var(--color-danger-border); }
.wg-summary {
  display: flex;
  align-items: center;
  gap: 0.625rem;
  padding: 0.6rem 0.875rem;
  cursor: pointer;
  list-style: none;
  user-select: none;
}
.wg-summary::-webkit-details-marker { display: none; }
.wg-summary::before {
  content: "\25B8";  /* ▸ — rotates to ▾ when open */
  color: var(--color-text-subtle);
  font-size: 11px;
  transition: transform 0.15s ease;
}
.worker-group[open] > .wg-summary::before { transform: rotate(90deg); }
.wg-summary:hover { background: var(--color-off-white); }
.wg-name { font-weight: 600; color: var(--color-text); }
.wg-meta {
  color: var(--color-text-muted);
  font-size: var(--font-small);
  font-variant-numeric: tabular-nums;
}
.wg-summary .badge { margin-left: auto; }
.worker-group > table.data {
  border: 0;
  border-radius: 0;
  border-top: 1px solid var(--color-border);
}

/* --- Forms -------------------------------------------------------- */

input[type="text"], input[type="email"], input[type="password"],
input[type="number"], input[type="date"], input[type="search"],
select, textarea {
  font: inherit;
  font-size: var(--font-body);
  padding: 8px 12px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  background: var(--color-bg-elevated);
  color: var(--color-text);
  width: 100%;
}
input:focus, select:focus, textarea:focus {
  outline: none;
  border-color: var(--color-navy);
  box-shadow: 0 0 0 3px var(--color-navy-light);
}
textarea { min-height: 5rem; resize: vertical; }
label {
  display: block;
  font-size: var(--font-small);
  font-weight: 500;
  color: var(--color-text-muted);
  margin-bottom: 4px;
}

/* --- Cards -------------------------------------------------------- */

.card {
  background: var(--color-bg-elevated);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-card);
  padding: 18px 20px;
}
.card-header {
  font-size: var(--font-micro);
  font-weight: 700;
  color: var(--color-navy);
  text-transform: uppercase;
  letter-spacing: var(--tracking-kicker);
  margin-bottom: 12px;
}

/* --- Badges ------------------------------------------------------- */
/* One chip voice for every state in the app: small caps, a 1px border in
   the state's own colour, a wash behind. The border is what makes the
   chip read at a glance in a table of fifty rows. */

.badge {
  display: inline-block;
  font-size: var(--font-micro);
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  padding: 1px 8px;
  border-radius: 999px;
  border: 1px solid currentColor;
  line-height: 1.5;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
.badge-green { background: var(--color-success-bg); color: var(--color-success); }
.badge-yellow { background: var(--color-warning-bg); color: var(--color-warning); }
.badge-red { background: var(--color-danger-bg); color: var(--color-danger); }
/* Conduct (0091): the yellow / red flag beside a person's name, and the
   "I know this person is Red" tick on a placement form. */
.conduct-badge { vertical-align: middle; }
.conduct-red-confirm { display: inline-flex; gap: 6px; align-items: center; color: var(--color-danger); font-weight: 600; font-size: var(--font-small); }
/* Main name everywhere (2026-11-10, app/core/display_name.py): a worker
   row's own spelling under the person's main name, and the "Not matched" /
   "Check the match" chip. Wraps on a phone, never pushes the row wider. */
.mn-ts { display: block; font-size: var(--font-small); font-weight: 400; color: var(--color-text-muted); line-height: 1.35; overflow-wrap: anywhere; letter-spacing: normal; text-transform: none; }
.mn-ts-inline { display: inline; }
.mn-flag { vertical-align: middle; text-decoration: none; }

/* --- Status chips -------------------------------------------------- */
/* Colored status pills (projects boards; per-board status sets pick
   from this fixed named-token palette — service.STATUS_COLORS must
   stay in sync with the color classes here). */
.status-chip {
  display: inline-block;
  font-size: var(--font-micro);
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  padding: 1px 9px;
  border-radius: 999px;
  border: 1px solid currentColor;
  line-height: 1.5;
  white-space: nowrap;
}
.status-chip.gray { background: var(--color-plan-bg); color: var(--color-plan); }
.status-chip.blue { background: var(--color-info-bg); color: var(--color-info); }
.status-chip.green { background: var(--color-success-bg); color: var(--color-success); }
.status-chip.yellow { background: var(--color-warning-bg); color: var(--color-warning); }
.status-chip.red { background: var(--color-danger-bg); color: var(--color-danger); }
.status-chip.navy { background: var(--color-navy-light); color: var(--color-navy); }
/* Solid variant — the Monday-style filled block (saturated background,
   white text): a pattern you SEE across fifty rows, not a detail you
   read. Used by the status picker chips and kanban column heads. */
.status-chip.solid { border-color: transparent; }
.status-chip.solid.gray { background: var(--color-text-subtle); color: var(--color-on-accent); }
.status-chip.solid.blue { background: var(--color-info); color: var(--color-on-accent); }
.status-chip.solid.green { background: var(--color-success); color: var(--color-on-accent); }
.status-chip.solid.yellow { background: var(--color-warning); color: var(--color-on-accent); }
.status-chip.solid.red { background: var(--color-danger); color: var(--color-on-accent); }
.status-chip.solid.navy { background: var(--color-navy); color: var(--color-on-accent); }

/* Group color rails — Monday's colored left-edge accent per group. */
.rail-gray { border-left: 4px solid var(--color-text-subtle); }
.rail-blue { border-left: 4px solid var(--color-info); }
.rail-green { border-left: 4px solid var(--color-success); }
.rail-yellow { border-left: 4px solid var(--color-warning); }
.rail-red { border-left: 4px solid var(--color-danger); }
.rail-navy { border-left: 4px solid var(--color-navy); }

/* Status picker — CSP-safe popover on native <details>: the summary is
   the current status as a solid chip; options are one solid chip button
   per status (hx-post via hx-vals). No JS, no native <select>. */
.chip-picker { position: relative; display: inline-block; }
.chip-picker > summary { list-style: none; cursor: pointer; user-select: none; }
.chip-picker > summary::-webkit-details-marker { display: none; }
.chip-picker[open] > summary .status-chip { box-shadow: 0 0 0 2px var(--color-navy-light); }
.chip-picker-menu {
  position: absolute;
  z-index: 30;
  top: calc(100% + 4px);
  left: 0;
  min-width: 150px;
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 8px;
  background: var(--color-bg-elevated);
  border: 1px solid var(--color-border);
  border-radius: 8px;
  box-shadow: var(--shadow-pop);
}
.chip-picker-menu button {
  border: 0;
  padding: 0;
  background: none;
  cursor: pointer;
  text-align: left;
}
.chip-picker-menu .status-chip {
  display: block;
  text-align: center;
  padding: 5px 10px;
  transition: transform var(--motion-fast) var(--ease-standard);
}
.chip-picker-menu button:hover .status-chip { transform: scale(1.04); }

/* Battery — Monday's most recognizable pixel after status colors: a
   proportional segmented bar of a board's status distribution. Segment
   widths are inline styles (style-src allows); colors are the tokens. */
.battery {
  display: flex;
  height: 8px;
  border-radius: 999px;
  overflow: hidden;
  background: var(--color-bg-section);
  min-width: 120px;
}
.battery .seg { display: block; height: 100%; }
.battery .seg.gray { background: var(--color-text-subtle); }
.battery .seg.blue { background: var(--color-info); }
.battery .seg.green { background: var(--color-success); }
.battery .seg.yellow { background: var(--color-warning); }
.battery .seg.red { background: var(--color-danger); }
.battery .seg.navy { background: var(--color-navy); }

/* --- Avatar chip ---------------------------------------------------- */
/* Initials circle for owners (projects kanban cards; reusable anywhere
   a compact person marker is needed). */
.avatar-chip {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: var(--color-navy-light);
  color: var(--color-navy);
  font-size: var(--font-micro);
  font-weight: 600;
  letter-spacing: 0.02em;
  flex: none;
}

/* --- Alerts ------------------------------------------------------- */

.alert {
  padding: 10px 14px;
  border-radius: var(--radius-card);
  font-size: var(--font-body);
  margin-bottom: 1rem;
}
.alert-error {
  background: var(--color-danger-bg);
  color: var(--color-danger);
  border: 1px solid var(--color-danger-border);
}
.alert-warning {
  background: var(--color-warning-bg);
  color: var(--color-warning);
  border: 1px solid var(--color-warning-border);
}
.alert-info {
  background: var(--color-bg-section);
  color: var(--color-text-muted);
  border: 1px solid var(--color-border-warm);
}

/* --- Flash messages ---------------------------------------------- */
/* Rendered above each page's content by base.html. Carry the level   */
/* (success / info / warning / error) as a class. The optional         */
/* `flash-token` block shows a one-shot copyable value (currently the */
/* setup-URL after creating a user).                                   */
.flashes { margin: 0 0 1rem; display: flex; flex-direction: column; gap: 0.5rem; }
.flash {
  padding: 0.6rem 0.9rem;
  border-radius: var(--radius-card);
  font-size: var(--font-small);
  line-height: 1.5;
  border: 1px solid var(--color-border);
  background: var(--color-bg-elevated);
}
.flash p { margin: 0; }
.flash-success { background: var(--color-success-bg); color: var(--color-success); border-color: var(--color-success-border); }
.flash-info { background: var(--color-bg-section); color: var(--color-text-muted); border-color: var(--color-border-warm); }
.flash-warning { background: var(--color-warning-bg); color: var(--color-warning); border-color: var(--color-warning-border); }
.flash-error { background: var(--color-danger-bg); color: var(--color-danger); border-color: var(--color-danger-border); }
/* Two rows at two clients not merged (_cross_client_merge.html): the
   reason in a few lines, then the links — wrapping on a phone. */
.merge-cross { margin: 0 0 0.75rem; overflow-wrap: anywhere; }
.merge-cross p + p { margin-top: 0.35rem; }
.merge-cross-links { display: flex; flex-wrap: wrap; gap: 0.25rem 1rem; }
.flash-token {
  display: block;
  margin-top: 0.5rem;
  padding: 0.5rem 0.75rem;
  background: var(--color-bg-elevated);
  border: 1px solid var(--color-border);
  border-radius: 4px;
  color: var(--color-text);
  font-size: 12px;
  word-break: break-all;
  font-family: ui-monospace, "SF Mono", Consolas, monospace;
}

/* --- Source-preview empty state ---------------------------------- */
/* Rendered in the review screen's source panel when an attachment    */
/* mime type isn't previewable in-browser (or when the storage path   */
/* can't be resolved). Same .source-empty class also gets emitted in  */
/* the iframe body by the routes when S3 returns 404 — the inline    */
/* CSS in that response mirrors the rules below.                     */
.source-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.25rem;
  padding: 2rem 1.5rem;
  text-align: center;
  background: var(--color-bg-section);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-card);
  color: var(--color-text-muted);
  font-size: var(--font-small);
  min-height: 8rem;
}
.source-empty p { margin: 0; }
.source-empty-hint {
  color: var(--color-text-subtle);
  font-size: 12px;
}
.source-empty a {
  color: var(--color-navy);
  text-decoration: none;
  font-weight: 500;
  margin-top: 0.5rem;
}
.source-empty a:hover { text-decoration: underline; }

/* --- Auth pages (centered card) ----------------------------------- */

/* Language selector on the light auth card (overrides the dark-topbar
   defaults above): right-aligned above the logo, dark-on-light. */
body.auth .lang-select {
  display: flex;
  justify-content: flex-end;
  margin-bottom: 0.5rem;
}
body.auth .lang-btn {
  color: var(--color-text-muted);
  background: var(--color-bg-elevated);
  border: 1px solid var(--color-border);
}
body.auth .lang-btn:hover {
  color: var(--color-navy);
  border-color: var(--color-navy);
  background: transparent;
}
body.auth .lang-btn-active {
  color: var(--color-on-accent);
  background: var(--color-navy);
  border-color: var(--color-navy);
}

body.auth {
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 16px;
  background: var(--color-bg);
}
body.auth { background: var(--color-bg-section); }
body.auth main {
  width: 100%;
  max-width: 28rem;
  padding: 2rem;
  background: var(--color-bg-elevated);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-card);
}
body.auth header { margin-bottom: 1.5rem; }
body.auth .auth-switches { display: flex; justify-content: flex-end; gap: 0.5rem; margin-bottom: 0.5rem; }
body.auth .auth-switches .lang-select { margin-bottom: 0; }
body.auth .auth-logo {
  display: block;
  height: 72px;
  width: auto;
  margin: 0 auto 1.25rem;
}
/* Theme-aware logo: one <img> per theme, the other hidden. These come
   AFTER the generic rule above on purpose — same specificity, so source
   order decides, and the other way round both logos render. */
body.auth .auth-logo-light { display: none; }
:root[data-theme="light"] body.auth .auth-logo-light { display: block; }
:root[data-theme="light"] body.auth .auth-logo-dark { display: none; }
body.auth h1 { margin: 0.25rem 0 0; font-size: 1.5rem; font-weight: 700; letter-spacing: -0.02em; }
body.auth form { display: flex; flex-direction: column; gap: 1rem; }
body.auth .hint {
  margin: 4px 0 0;
  font-size: 12px;
  color: var(--color-text-subtle);
}
body.auth button[type="submit"] {
  /* Inherits .btn-primary look without the class — keeps existing */
  /* auth templates compatible without restructuring their markup.  */
  padding: 10px 16px;
  font: inherit;
  font-size: var(--font-small);
  font-weight: 600;
  color: var(--color-on-accent);
  background: var(--color-navy);
  border: 0;
  border-radius: var(--radius);
  cursor: pointer;
}
body.auth button[type="submit"]:hover { background: var(--color-navy-deep); }
/* The RO/EN and ☾/☀ switches are submit buttons too; `[type="submit"]`
   counts as a class, so the card rule above out-specified .lang-btn and
   painted all four as filled primaries. Re-assert the quiet chip look. */
body.auth .lang-select .lang-btn {
  padding: 4px 10px;
  min-height: 32px;
  font-size: var(--font-small);
  font-weight: 500;
  color: var(--color-text-muted);
  background: var(--color-bg-elevated);
  border: 1px solid var(--color-border);
}
body.auth .lang-select .lang-btn:hover { color: var(--color-navy); border-color: var(--color-navy); background: transparent; }
body.auth .lang-select .lang-btn-active { color: var(--color-on-accent); background: var(--color-navy); border-color: var(--color-navy); }
body.auth .auth-switches { flex-wrap: nowrap; }
/* `body.auth form` stacks its children (the login fields); the switch
   forms are rows of two buttons and must not inherit that. Also live on
   prod: the four switches rendered as a 2x2 block of filled buttons. */
body.auth .lang-select { flex-direction: row; gap: 4px; }


/* --- Page header ------------------------------------------------------ */
/* Title row: the page's <h1> on the left, its primary action(s) on the
   right. Pages used to declare this themselves (a dozen copies); it is
   shared now. On phones it wraps (phone layer). */
.page-header {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  margin-bottom: 1rem;
}
.page-header h1 { margin: 0; }
.page-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem; }
/* Lead duplicated inside the fold for phones (see _page_help.html). */
.page-lead-fold { display: none; }

/* --- Segmented control -------------------------------------------------- */
/* A short exclusive choice (language, theme): one row of joined buttons,
   the active one filled in the accent. Plain submit buttons — CSP-safe. */
.segmented {
  display: inline-flex;
  flex-wrap: wrap;
  margin: 0;
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  overflow: hidden;
  background: var(--color-bg-elevated);
}
.seg-btn {
  font: inherit;
  font-size: var(--font-small);
  font-weight: 500;
  padding: 8px 16px;
  min-height: 40px;
  background: transparent;
  color: var(--color-text-muted);
  border: 0;
  border-right: 1px solid var(--color-border);
  cursor: pointer;
}
.seg-btn:last-child { border-right: 0; }
.seg-btn:hover { background: var(--color-bg-section); color: var(--color-text); }
.seg-btn.active { background: var(--color-navy); color: var(--color-on-accent); cursor: default; }

/* --- Key / value list --------------------------------------------------- */
/* A <dl> of labelled facts (account details, a record's fields). Two
   columns on desktop, stacked on narrow phones. */
.kv {
  display: grid;
  grid-template-columns: max-content minmax(0, 1fr);
  gap: 0.4rem 1.25rem;
  margin: 0;
  font-size: var(--font-small);
}
.kv dt { color: var(--color-text-muted); font-weight: 500; }
.kv dd { margin: 0; color: var(--color-text); overflow-wrap: anywhere; }

/* --- Split browse (list + detail) ---------------------------------------- */
/* The registry screens: a searchable list on the left, the selected
   record on the right. On a phone the two cannot share the screen, so
   the list is the page until a record is chosen, then the record is the
   page with a back link (.split-back) at the top. Each page sets its
   own column width; this owns the phone behaviour.

   `has-selection` means the URL NAMED a record, never that the server
   filled the detail pane for the desktop's benefit: /clients and
   /workers auto-select the first match so the wide layout has no empty
   column, and marking that as a selection hid the list on a phone,
   leaving the first record with no way back to the others (Cristian,
   2026-09-24: "it shows one client only"). So a phone shows the pane
   only when the selection is explicit — the auto-selected pane is
   rendered and hidden, which is what keeps the desktop unchanged. */
.split-back { display: none; }
@media (max-width: 880px) {
  .split-browse { display: block; }
  .split-browse.has-selection > .split-list { display: none; }
  .split-browse:not(.has-selection) > .split-pane { display: none; }
  /* The auto-selected row is the pane's row — with the pane hidden it
     would claim a record is open that the phone is not showing. */
  .split-browse:not(.has-selection) .split-list a.active {
    background: none;
    border-left-color: transparent;
  }
  .split-back {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    min-height: 40px;
    margin: 0 0 0.5rem;
    color: var(--color-navy);
    text-decoration: none;
    font-size: var(--font-small);
    font-weight: 600;
  }
}

/* --- Phone layer --------------------------------------------------------- */
/* Device-level rules for viewports <=768px. A page decides its desktop
   layout in its own <style> block (which comes later in the cascade); on
   a phone the DEVICE decides, so the few rules below that must win carry
   !important on purpose: inputs must not trigger iOS focus-zoom (16px),
   controls must be tappable (>=40px), and a table must never push the
   page wide — `table.data` becomes stacked cards, each cell prefixed by
   its column head (shell.js copies the <th> text into data-label).
   Opt a table out with `no-cards` (it then needs a .table-scroll box). */
@media (max-width: 768px) {
  main.content h1 { font-size: 22px; }
  .page-kicker { display: none; }
  .page-help { margin: 0 0 0.9rem; }
  .page-lead { display: none; }
  .page-help-lead-only .page-lead { display: block; font-size: var(--font-body); }
  .page-how .page-lead-fold { display: block; margin: 0.4rem 0 0; color: var(--color-text); }
  .page-header { flex-wrap: wrap; align-items: center; gap: 0.5rem 0.75rem; margin-bottom: 0.8rem; }
  .card { padding: 0.9rem 1rem; }
  .flashes { margin-bottom: 0.75rem; }

  main.content input:not([type="checkbox"]):not([type="radio"]):not([type="file"]):not([type="range"]),
  main.content select,
  main.content textarea { font-size: 16px !important; min-height: 44px; }
  main.content textarea { min-height: 5rem; }
  main.content input[type="file"] { font-size: 14px !important; }
  .btn-primary, .btn-secondary, .btn-danger, .btn-quiet, .chip-btn, .pager-link, .seg-btn { min-height: 40px; }
  .btn-text { min-height: 36px; }

  .tabs { gap: 1.1rem; flex-wrap: nowrap; overflow-x: auto; -webkit-overflow-scrolling: touch; scrollbar-width: none; }
  .tabs::-webkit-scrollbar { display: none; }
  .tabs a, .tabs span.tab { padding: 0.65rem 0; }

  .stat-row { grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: 0.5rem; }
  .stat { padding: 12px 14px 10px; }
  .stat-value { font-size: 26px; }

  /* Tables as cards. */
  table.data:not(.no-cards), table.cards-on-mobile:not(.no-cards) {
    display: block;
    border: 0;
    border-radius: 0;
    background: none;
    overflow: visible;
    width: auto;
  }
  table.data:not(.no-cards) thead, table.cards-on-mobile:not(.no-cards) thead { display: none; }
  table.data:not(.no-cards) tbody, table.cards-on-mobile:not(.no-cards) tbody,
  table.data:not(.no-cards) tfoot, table.cards-on-mobile:not(.no-cards) tfoot { display: block; }
  table.data:not(.no-cards) tr, table.cards-on-mobile:not(.no-cards) tr {
    display: block;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-card);
    background: var(--color-bg-elevated);
    padding: 0.35rem 0;
    margin-bottom: 0.6rem;
  }
  table.data:not(.no-cards) tbody tr:hover, table.cards-on-mobile:not(.no-cards) tbody tr:hover { background: var(--color-bg-elevated); }
  table.data:not(.no-cards) td, table.cards-on-mobile:not(.no-cards) td,
  table.data:not(.no-cards) th, table.cards-on-mobile:not(.no-cards) th {
    display: grid;
    grid-template-columns: minmax(5.5rem, 7.5rem) minmax(0, 1fr);
    align-items: baseline;
    gap: 0.25rem 0.75rem;
    padding: 5px 12px;
    border: 0;
    text-align: left;
    white-space: normal;
    overflow-wrap: anywhere;
  }
  table.data:not(.no-cards) td::before, table.cards-on-mobile:not(.no-cards) td::before {
    content: attr(data-label);
    font-weight: 600;
    color: var(--color-text-muted);
    font-size: var(--font-micro);
    text-transform: uppercase;
    letter-spacing: .04em;
    text-align: left;
    flex: none;
  }
  table.data:not(.no-cards) td:not([data-label])::before, table.cards-on-mobile:not(.no-cards) td:not([data-label])::before { content: none; }
  table.data:not(.no-cards) td:not([data-label]), table.cards-on-mobile:not(.no-cards) td:not([data-label]) { grid-template-columns: minmax(0, 1fr); }
  table.data:not(.no-cards) td.num, table.cards-on-mobile:not(.no-cards) td.num { text-align: right; }
  table.data:not(.no-cards) td.actions, table.cards-on-mobile:not(.no-cards) td.actions,
  table.data:not(.no-cards) td.cl-row-actions, table.cards-on-mobile:not(.no-cards) td.cl-row-actions,
  table.data:not(.no-cards) td.pj-row-actions, table.cards-on-mobile:not(.no-cards) td.pj-row-actions { grid-template-columns: minmax(0, 1fr); padding-top: 8px; }
  table.data:not(.no-cards) td.actions::before, table.cards-on-mobile:not(.no-cards) td.actions::before,
  table.data:not(.no-cards) td.cl-row-actions::before, table.cards-on-mobile:not(.no-cards) td.cl-row-actions::before,
  table.data:not(.no-cards) td.pj-row-actions::before, table.cards-on-mobile:not(.no-cards) td.pj-row-actions::before { content: none; }
  /* The first cell is the card's title line — full width, no label. */
  table.data:not(.no-cards) td:first-child, table.cards-on-mobile:not(.no-cards) td:first-child {
    display: block;
    text-align: left;
    font-weight: 600;
    padding-bottom: 0.1rem;
  }
  table.data:not(.no-cards) td:first-child::before, table.cards-on-mobile:not(.no-cards) td:first-child::before { content: none; }
  /* Spanning cells (group heads, empty states) read as a plain line. */
  table.data:not(.no-cards) td[colspan], table.cards-on-mobile:not(.no-cards) td[colspan] { display: block; text-align: left; }
  /* A cell with nothing to show collapses (no empty labelled line);
     shell.js marks whitespace-only cells, which :empty cannot see. */
  table.data:not(.no-cards) td:empty, table.cards-on-mobile:not(.no-cards) td:empty,
  table.data:not(.no-cards) td[data-empty], table.cards-on-mobile:not(.no-cards) td[data-empty] { display: none; }
  /* Editable cells: the control fills the value column. */
  table.data:not(.no-cards) td > input, table.data:not(.no-cards) td > select,
  table.cards-on-mobile:not(.no-cards) td > input, table.cards-on-mobile:not(.no-cards) td > select { width: 100%; min-width: 0; }
  table.data:not(.no-cards) td.num, table.cards-on-mobile:not(.no-cards) td.num { font-variant-numeric: tabular-nums; }

  /* Remaining tap targets: folds, back links, tiny controls. Labels are
     not targets; the checkbox/radio itself grows to a thumb size. */
  .page-how > summary { display: inline-flex; align-items: center; min-height: 32px; }
  .crumbs a, .pj-back, .back-link, .ca-new, .et-link-block, .et-hint a, .et-create { display: inline-flex; align-items: center; min-height: 36px; }
  main.content input[type="checkbox"], main.content input[type="radio"] { width: 20px; height: 20px; margin: 0 6px 0 0; vertical-align: middle; }
  .src-expand { padding: 6px 12px; font-size: 16px; line-height: 1.2; }
  main.content .cl-confirm { width: 26px; height: 26px; font-size: 12px; }
  .chip-picker > summary { display: inline-flex; align-items: center; min-height: 32px; }
  .page-header .btn-primary, .page-header .btn-secondary { white-space: nowrap; }
  .tt-tab { white-space: nowrap; }
  .pj-filters select { flex: 1 1 45%; width: auto; }

  /* Registry record on a phone: the page header + help fold go — the
     record's own title and the back link are the page. */
  main.content:has(.split-browse.has-selection) > .page-header,
  main.content:has(.split-browse.has-selection) > .page-help { display: none; }

  /* Anything that stays a table scrolls inside its own box. */
  .table-scroll { margin: 0 -0.25rem; padding: 0 0.25rem; }
}
@media (max-width: 768px) {
  /* Auth card: same iOS focus-zoom guard as the app pages (no main.content here). */
  body.auth input:not([type="checkbox"]):not([type="radio"]), body.auth select, body.auth textarea { font-size: 16px !important; min-height: 44px; }
  body.auth button[type="submit"] { min-height: 44px; }
}
@media (max-width: 480px) {
  body.auth { padding: 12px; }
  body.auth main { padding: 1.35rem 1.2rem; }
  .kv { grid-template-columns: 1fr; gap: 0.15rem; }
  .kv dt { margin-top: 0.5rem; font-size: var(--font-micro); text-transform: uppercase; letter-spacing: 0.06em; }
  .kv dt:first-child { margin-top: 0; }
}


/* --- Focus mode ------------------------------------------------------
   <html data-focus="on">: the shell — topbar, sidebar, tab bar — goes
   away and the page takes the whole viewport, for working a wide sheet
   (the salary run). Per browser: shell.js writes the `rightman_focus`
   cookie on the toggle and asks the browser for fullscreen; the server
   stamps the attribute before first paint. A page offers the toggle with
   `[data-focus-toggle]`; `.focus-exit` is its fixed exit button, shown
   only in focus. */
html[data-focus="on"] header.topbar,
html[data-focus="on"] aside.sidebar,
html[data-focus="on"] .tabbar { display: none !important; }
html[data-focus="on"] .layout { grid-template-columns: minmax(0, 1fr) !important; }
html[data-focus="on"] main.content { padding: 0.9rem 1.1rem 1.4rem; }
/* In focus the page's own toggle steps aside; the fixed exit button is the way out. */
html[data-focus="on"] [data-focus-toggle]:not(.focus-exit) { display: none !important; }
.focus-exit { display: none; }
html[data-focus="on"] .focus-exit {
  display: inline-flex;
  position: fixed;
  right: 14px;
  bottom: 14px;
  z-index: 60;
  box-shadow: 0 6px 18px -6px rgba(0, 0, 0, 0.5);
}

/* --- Dates as dd/mm/yyyy (date-field.js, 2026-10-06) ---------------
   A native date input shows the browser's locale format; the script puts
   a dd/mm/yyyy text box in front of it and keeps the native one, hidden,
   for the form value and the calendar popup. */
.dmy-field { position: relative; display: inline-flex; align-items: center; max-width: 100%; vertical-align: middle; }
.dmy-field.dmy-full { display: flex; width: 100%; }
.dmy-field .dmy-text { width: 11.5em; max-width: 100%; padding-right: 2.2rem; font-variant-numeric: tabular-nums; }
.dmy-field.dmy-full .dmy-text { width: 100%; }
/* Always room for a full dd/mm/yyyy beside the calendar button (Safari,
   2026-10-28: the year was cut off). The script copies the hidden native
   input's width, which in WebKit is narrower than the text needs, and page
   rules restyle `input.dmy-text` padding — so this selector outranks them
   (0,2,2) and the floor is a min-width that no inline width can undercut. */
span.dmy-field > input.dmy-text { padding-right: 2.2rem; min-width: calc(10ch + 2.2rem + 1.5rem); }
.dmy-field .dmy-pick { position: absolute; right: 4px; top: 50%; transform: translateY(-50%); display: inline-flex; align-items: center; justify-content: center; min-width: 28px; min-height: 28px; padding: 0; border: 0; background: none; color: var(--color-text-subtle); cursor: pointer; }
.dmy-field .dmy-pick:hover { color: var(--color-text); }
.dmy-field .dmy-pick:disabled { opacity: .4; cursor: default; }
.dmy-field .dmy-native { position: absolute; left: 0; bottom: 0; width: 100%; height: 1px; padding: 0; margin: 0; border: 0; opacity: 0; pointer-events: none; }

/* --- Personal-data watermark (2026-10-06) ------------------------------
   The viewer's e-mail + the date, faint and diagonal, over the persons,
   workers and salary screens (base.html). A deterrent that makes a leaked
   screenshot or printout traceable — the platform cannot block either.
   Never takes a click (pointer-events: none) and stays behind dialogs. */
.pd-watermark {
  position: fixed;
  inset: 0;
  pointer-events: none;
  overflow: hidden;
  z-index: 3;
}
.pd-watermark::before {
  content: attr(data-wm) "        " attr(data-wm) "\A\A\A" attr(data-wm) "        " attr(data-wm) "\A\A\A" attr(data-wm) "        " attr(data-wm);
  white-space: pre;
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%) rotate(-24deg);
  font-size: var(--font-small);
  font-weight: 600;
  line-height: 2.4;
  color: var(--color-text);
  opacity: 0.05;
  text-align: center;
}
@media print { .pd-watermark::before { opacity: 0.12; } }

/* --- Record page (2026-10-28) -------------------------------------------
   A record (worker first; client and person next) is a summary header
   that never changes with the tab, then a row of tabs and the selected
   tab's panel. Macros: app/web/templates/_record_page.html. The header
   holds the name, chips, one subline and the actions (Edit + a "More"
   menu); a warnings line under it has one chip per thing to look at,
   each leading to its tab. On a phone the tab row scrolls sideways
   inside itself (never the page) and every tab is a 44px target. */
.rec-head {
  padding-bottom: 0.9rem;
  margin-bottom: 0.9rem;
  border-bottom: 1px solid var(--color-border);
}
.rec-head-top { display: flex; align-items: flex-start; justify-content: space-between; gap: 0.75rem 1rem; }
.rec-head-main { min-width: 0; }
.rec-title { display: flex; align-items: center; flex-wrap: wrap; gap: 0.4rem 0.65rem; }
.rec-title h1 { margin: 0; font-size: var(--font-display); line-height: 1.15; letter-spacing: -0.01em; overflow-wrap: anywhere; }
.rec-chips { display: inline-flex; flex-wrap: wrap; gap: 0.35rem; align-items: center; }
.rec-chip {
  display: inline-flex; align-items: center; white-space: nowrap;
  font-size: var(--font-micro); font-weight: 700; text-transform: uppercase; letter-spacing: 0.06em;
  padding: 3px 10px; border-radius: 999px; text-decoration: none;
  color: var(--color-text-muted); background: var(--color-bg-section); border: 1px solid var(--color-border);
}
.rec-chip-ok { color: var(--color-success); background: var(--color-success-bg); border-color: var(--color-success-border); }
.rec-chip-warn { color: var(--color-warning); background: var(--color-warning-bg); border-color: var(--color-warning-border); }
.rec-chip-off { color: var(--color-text-subtle); }
.rec-chip-info { color: var(--color-info); background: var(--color-info-bg); border-color: var(--color-info-border); }
a.rec-chip:hover { text-decoration: underline; }
.rec-sub { margin: 0.35rem 0 0; font-size: var(--font-small); color: var(--color-text-muted); line-height: 1.5; }
.rec-sub a { color: var(--color-navy); font-weight: 600; text-decoration: none; }
.rec-sub a:hover { text-decoration: underline; }
.rec-sub-k { color: var(--color-text-subtle); }
.rec-meta { margin: 0.25rem 0 0; font-size: var(--font-micro); color: var(--color-text-subtle); }
.rec-actions { display: flex; gap: 0.5rem; flex-shrink: 0; align-items: flex-start; }

/* The "More" menu: a native <details>; shell.js closes it on a click
   outside or Escape. */
.rec-more { position: relative; }
.rec-more > summary { list-style: none; cursor: pointer; gap: 0.35rem; }
.rec-more > summary::-webkit-details-marker { display: none; }
.rec-more-menu {
  position: absolute; right: 0; top: calc(100% + 4px); z-index: 20;
  min-width: 15rem; max-width: min(20rem, calc(100vw - 2rem));
  display: flex; flex-direction: column; padding: 0.3rem 0;
  background: var(--color-bg-elevated); border: 1px solid var(--color-border);
  border-radius: var(--radius-card); box-shadow: var(--shadow-pop);
}
.rec-more-item {
  display: flex; align-items: center; min-height: 40px; padding: 0.45rem 0.9rem;
  color: var(--color-text); text-decoration: none; font-size: var(--font-small);
  background: none; border: 0; font: inherit; text-align: left; cursor: pointer;
}
.rec-more-item:hover { background: var(--color-bg-section); color: var(--color-navy); }

/* The warnings line. */
.rec-warn { list-style: none; margin: 0.7rem 0 0; padding: 0; display: flex; flex-wrap: wrap; gap: 0.4rem; }
.rec-warn-chip {
  display: inline-flex; align-items: center; min-height: 28px; padding: 2px 11px; border-radius: 999px;
  font-size: var(--font-caption); font-weight: 600; text-decoration: none; border: 1px solid;
}
.rec-warn-chip:hover { text-decoration: underline; }
.rec-warn-yellow { color: var(--color-warning); background: var(--color-warning-bg); border-color: var(--color-warning-border); }
.rec-warn-red { color: var(--color-danger); background: var(--color-danger-bg); border-color: var(--color-danger-border); }

/* The tab row: a nav of links; the current one carries aria-current. */
/* position: relative keeps the visually-hidden count label (absolute)
   inside the scroll box: an absolute child of a static box escapes its
   overflow and widened a 360px phone page to 433px. */
/* The base line is an inset shadow, not a border + a -1px tab margin: the
   row scrolls (overflow auto on both axes), which would clip that pixel. */
.rec-tabs { position: relative; margin: 0 0 1.1rem; box-shadow: inset 0 -1px 0 var(--color-border); overflow-x: auto; overflow-y: hidden; scrollbar-width: thin; }
.rec-tabs ul { list-style: none; margin: 0; padding: 0; display: flex; gap: 0.8rem; }
.rec-tab {
  position: relative;
  display: inline-flex; align-items: center; gap: 0.35rem; min-height: 40px; padding: 0.35rem 0.3rem;
  border-bottom: 2px solid transparent; white-space: nowrap;
  color: var(--color-text-muted); text-decoration: none; font-size: var(--font-body); font-weight: 500;
}
.rec-tab:hover { color: var(--color-text); }
/* The row clips what sticks out of it (it scrolls), so the keyboard ring
   is drawn inside the tab instead of around it. */
.rec-tab:focus-visible { outline-offset: -2px; }
.rec-tab[aria-current="page"] { color: var(--color-text); font-weight: 600; border-bottom-color: var(--color-text); }
.rec-tab-count {
  display: inline-flex; align-items: center; justify-content: center; min-width: 1.3rem; padding: 0 5px;
  border-radius: 999px; font-size: var(--font-micro); font-weight: 700; font-variant-numeric: tabular-nums;
}
.rec-tab-count-yellow { color: var(--color-warning); background: var(--color-warning-bg); }
.rec-tab-count-red { color: var(--color-danger); background: var(--color-danger-bg); }
/* The tab links name #rec-body as their hx-indicator (rec_nav): htmx puts
   htmx-request on it while the next tab loads. */
.rec-body.htmx-request .rec-panel { opacity: 0.6; transition: opacity var(--motion-med) var(--ease-standard); }

/* "All details (N more)", an on-demand form, an empty section. */
.rec-all { margin-top: 0.9rem; padding-top: 0.6rem; border-top: 1px solid var(--color-border); }
.rec-all > summary, .rec-action > summary { cursor: pointer; color: var(--color-navy); font-size: var(--font-small); font-weight: 500; }
.rec-all[open] > summary { margin-bottom: 0.75rem; }
.rec-action { margin-top: 0.75rem; }
.rec-action[open] > summary { margin-bottom: 0.4rem; }
.rec-action > summary .rec-empty-text { color: var(--color-text-subtle); font-weight: 400; margin-right: 0.35rem; }
.rec-action > summary .rec-action-label { font-weight: 600; }
.rec-empty { font-size: var(--font-small); color: var(--color-text-subtle); }
.rec-sr {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
}
/* Read-only details: a grid of label (.k) / value (.v) pairs. */
.rec-fields { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(205px, 100%), 1fr)); gap: 1rem 1.75rem; }
.rec-field { min-width: 0; }
.rec-field .k { font-size: var(--font-micro); color: var(--color-text-subtle); text-transform: uppercase; letter-spacing: .04em; margin-bottom: 2px; }
.rec-field .v { font-size: var(--font-small); line-height: 1.4; overflow-wrap: anywhere; }
.rec-field .v.muted { color: var(--color-text-subtle); }
.rec-field .v.wrap { white-space: pre-wrap; }
.rec-field .v a { color: var(--color-navy); text-decoration: none; font-weight: 500; }
.rec-field .v a:hover { text-decoration: underline; }
.rec-field-wide { grid-column: 1 / -1; }

@media (max-width: 880px) {
  .rec-head-top { flex-wrap: wrap; }
  .rec-title h1 { font-size: 24px; }
}
@media (max-width: 768px), (pointer: coarse) {
  .rec-tab { min-height: 44px; }
  .rec-warn-chip { min-height: 36px; }
  .rec-more-item { min-height: 44px; }
  .rec-all > summary, .rec-action > summary { display: flex; align-items: center; flex-wrap: wrap; min-height: 44px; }
}
@media (max-width: 768px) {
  .rec-tabs ul { gap: 0.6rem; }
  .rec-actions { width: 100%; }
  .rec-more-menu { right: auto; left: 0; }
}

/* --- Record panel (2026-11-03; first the job order's person panel, #470) --
   One modal <dialog id="record-panel"> per page (`_record_panel.html`,
   shell.js section 5): a WORKER row, a PERSON or a CLIENT opened over the
   page, edited and saved without leaving it. A drawer from the right on a
   laptop, the full screen at <= 600 px. The modal sits in the top layer;
   html.record-panel-open stops the page behind from scrolling. */
html.record-panel-open, html.record-panel-open body { overflow: hidden; }
dialog.record-panel { position: fixed; inset: 0 0 0 auto; margin: 0; padding: 0; width: min(36rem, 100vw); max-width: 100vw; height: 100vh; height: 100dvh; max-height: none; border: 0; border-left: 1px solid var(--color-border); background: var(--color-bg-elevated); color: var(--color-text); box-shadow: var(--shadow-pop); overflow: hidden; }
dialog.record-panel[open] { display: flex; flex-direction: column; }
dialog.record-panel::backdrop { background: var(--color-navy-deep); opacity: .45; }
.record-panel-bar { display: flex; align-items: center; justify-content: space-between; gap: .5rem; padding: .5rem 1rem; border-bottom: 1px solid var(--color-border); flex: none; }
.record-panel-close { min-height: 44px; min-width: 44px; margin-left: auto; }
.record-panel-body { flex: 1 1 auto; overflow-y: auto; overscroll-behavior: contain; padding: .75rem 1rem 2rem; overflow-wrap: anywhere; }
.rp-muted { color: var(--color-text-muted); font-size: var(--font-small); }
.rp-head { display: flex; flex-wrap: wrap; gap: .5rem; align-items: center; justify-content: space-between; margin-bottom: .75rem; }
.rp-head h2 { margin: 0; font-size: var(--font-h3); }
.rp-head h2:focus { outline: none; }
.rp-sec { border-top: 1px solid var(--color-border); padding-top: .75rem; margin-top: .9rem; }
.rp-sec h3 { margin: 0 0 .5rem; font-size: var(--font-body); }
.rp-sec h4 { margin: .9rem 0 .35rem; font-size: var(--font-small); color: var(--color-text-muted); }
/* A panel form: labelled boxes in a grid that folds to one column. */
.rp-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(13rem, 100%), 1fr)); gap: .65rem .85rem; margin: 0 0 .75rem; }
.rp-grid label, .rp-line label { display: flex; flex-direction: column; gap: .25rem; font-size: var(--font-small); color: var(--color-text-muted); min-width: 0; }
.rp-grid input, .rp-grid select { width: 100%; max-width: 100%; min-width: 0; }
.rp-grid label.rp-check { flex-direction: row; align-items: center; gap: .5rem; color: var(--color-text); }
.rp-grid label.rp-check input { width: auto; }
.rp-line { display: flex; flex-wrap: wrap; gap: .5rem .75rem; align-items: end; margin: 0 0 .75rem; }
.rp-hint { font-size: var(--font-small); color: var(--color-text-muted); margin: -.25rem 0 .75rem; }
.record-panel form button, .record-panel .btn-primary, .record-panel .btn-secondary { min-height: 44px; }
.rp-list { list-style: none; margin: 0; padding: 0; }
.rp-list li { display: flex; flex-wrap: wrap; gap: .35rem .75rem; justify-content: space-between; padding: .4rem 0; border-bottom: 1px solid var(--color-border); font-size: var(--font-small); }
/* The client page's Worker pay card, reused inside the panel. */
.record-panel .cl-card { margin: .9rem 0 0; border-top: 1px solid var(--color-border); padding-top: .75rem; }
.record-panel .cl-workers-head { display: flex; align-items: center; justify-content: space-between; gap: .75rem; flex-wrap: wrap; margin: 0 0 .5rem; }
.record-panel .cl-workers-head h2 { margin: 0; font-size: var(--font-body); }
.record-panel .cl-muted { color: var(--color-text-subtle); font-size: var(--font-small); }
.record-panel .cl-wf-error { background: var(--color-danger-bg); color: var(--color-danger); border: 1px solid var(--color-danger-border); border-radius: var(--radius); padding: 7px 11px; font-size: var(--font-small); margin-bottom: .65rem; }
.record-panel .cl-wf-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(11rem, 100%), 1fr)); gap: .65rem .85rem; }
.record-panel .cl-wf-grid label { display: flex; flex-direction: column; gap: 4px; font-size: var(--font-small); color: var(--color-text-muted); min-width: 0; }
.record-panel .cl-wf-grid input, .record-panel .cl-wf-grid select { width: 100%; max-width: 100%; min-width: 0; }
.record-panel .cl-wf-actions { display: flex; flex-wrap: wrap; gap: .5rem; margin-top: .5rem; }
@media (prefers-reduced-motion: no-preference) {
  dialog.record-panel[open] { animation: record-panel-in .18s ease-out; }
  @keyframes record-panel-in { from { transform: translateX(100%); } to { transform: none; } }
}
@media (max-width: 600px) {
  dialog.record-panel { width: 100vw; border-left: 0; box-shadow: none; }
}
