/* Time2U — refined DRIVEN2U brand theme (shared by index.html + admin.html).
   Layered over Bootstrap: overrides the generic look with brand palette, typography,
   editorial tables and subtle atmosphere. Distinctive but corporate-sober. */

:root{
  --paper:#F4F6F9;
  --surface:#FFFFFF;
  --ink:#0E2440;          /* deep navy ink */
  --ink-soft:#33455F;
  --muted:#697892;
  --hair:#E2E7EF;
  --hair-strong:#CDD6E3;
  --brand:#4472C4;        /* corporate blue */
  --brand-deep:#345a9e;
  --brand-ink:#0B2E57;
  --teal:#5B9BD5;         /* corporate light blue — the wordmark's 'Time', and the colour of tracking time */
  --teal-deep:#4682B8;    /* the same blue, deepened: hover/active on the tracking controls */
  --ok:#1E7F5C;
  --danger:#B23A48;
  --warn-bg:#FBF3E2; --warn-ink:#8A6420; --warn-bd:#ECDBB4; --warning:#B7791F;   /* amber for the archive/deactivate hover */
  --header-bg:rgba(255,255,255,.82);
  --tip-bg:var(--ink);
  --page-bg:
    radial-gradient(58rem 38rem at 8% -12%, rgba(46,111,183,.12), transparent 60%),
    radial-gradient(46rem 36rem at 112% 6%, rgba(26,161,180,.10), transparent 55%),
    var(--paper);

  --font-display:'REM',system-ui,-apple-system,Segoe UI,sans-serif;
  --font-sans:'REM',system-ui,-apple-system,Segoe UI,sans-serif;
  --font-mono:'REM',system-ui,-apple-system,Segoe UI,sans-serif;   /* the theme font; numeric cells add tabular-nums for aligned digits */
  --font-code:ui-monospace,'SFMono-Regular',Menlo,Consolas,monospace;   /* real code blocks only */

  --radius:14px;
  --shadow-sm:0 1px 2px rgba(14,36,64,.05), 0 1px 1px rgba(14,36,64,.04);
  --shadow:0 18px 48px -28px rgba(14,36,64,.45);

  /* Bootstrap remaps */
  --bs-body-font-family:var(--font-sans);
  --bs-body-color:var(--ink);
  --bs-body-bg:transparent;
  --bs-border-color:var(--hair);
}

*{ -webkit-font-smoothing:antialiased; }
/* The scrollbar's width is always reserved, so a long module (Security) and a short one (the timesheet) frame
   their content at exactly the same width — the page never widens or narrows as the bar comes and goes. */
html{ scrollbar-gutter:stable; }
html,body{ min-height:100%; }
/* Brand-tinted scrollbars across the whole app (light-blue thumb, darker on hover).
   WebKit (Chrome/Edge/Safari) uses the ::-webkit-scrollbar pseudo-elements; the standard scrollbar-* is applied
   ONLY where those pseudo-elements are unsupported (Firefox), because setting scrollbar-width/color disables the
   pseudo-elements in Chrome. */
::-webkit-scrollbar{ width:12px; height:12px; }
::-webkit-scrollbar-track{ background:transparent; }
::-webkit-scrollbar-thumb{ background:var(--brand-ink); border-radius:999px; border:3px solid transparent; background-clip:padding-box; }
::-webkit-scrollbar-thumb:hover{ background:var(--brand-deep); border:3px solid transparent; background-clip:padding-box; }
@supports not selector(::-webkit-scrollbar){
  *{ scrollbar-width:thin; scrollbar-color:var(--brand-ink) transparent; }
}
body{
  font-family:var(--font-sans);
  color:var(--ink);
  display:flex; flex-direction:column; min-height:100vh;
  background:var(--page-bg);
  background-attachment:fixed;
  position:relative;
}
/* fine grain overlay */
body::before{
  content:""; position:fixed; inset:0; z-index:0; pointer-events:none; opacity:.4;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.035'/%3E%3C/svg%3E");
}
.container, main{ position:relative; z-index:1; }
nav{ position:relative; z-index:1030; }   /* above main, so the apps menu opens over the page and not under it */


::selection{ background:rgba(46,111,183,.18); }

/* ---------- header ---------- */
.navbar{
  background:var(--header-bg)!important;
  backdrop-filter:saturate(140%) blur(8px);
  border-bottom:1px solid var(--hair);
  box-shadow:var(--shadow-sm);
}
.navbar .vr{ opacity:.35; }
/* bigger logo without growing the header: negative margins offset the extra height */
.brand-logo{ height:44px; margin:-7px 0; display:block; }
.brand-name{ font-family:var(--font-display); font-weight:600; font-size:1.18rem; letter-spacing:.2px; color:var(--ink); }
.brand-time{ color:var(--teal); }    /* corporate wordmark: Time (light blue) + 2U (blue) */
.brand-2u{ color:var(--brand); }
.brand-sub{ font-family:var(--font-sans); font-weight:600; font-size:.66rem; letter-spacing:.18em; text-transform:uppercase; color:#44546a; }
html[data-theme="dark"] .brand-sub{ color:#8ea3c0; }   /* lighten the corporate slate for contrast on the dark masthead */
.theme-toggle .icon-btn,.lang-toggle .icon-btn,.width-toggle .icon-btn{ display:inline-flex; align-items:center; justify-content:center; padding:.3rem .6rem; font-size:.78rem; line-height:1; }
.theme-toggle .icon-btn i,.width-toggle .icon-btn i{ font-size:.78rem; line-height:1; }
.theme-toggle .icon-btn.active,.lang-toggle .icon-btn.active,.width-toggle .icon-btn.active{ background:var(--brand); color:#fff; border-color:var(--brand); }
.theme-toggle .icon-btn.active:hover,.lang-toggle .icon-btn.active:hover,.width-toggle .icon-btn.active:hover{ background:var(--brand-deep); color:#fff; }
/* Admin left menu (Reports / Interfaces) — clear menu items whose selection swaps the right-hand content. */
.t2u-menu-head{ font-size:.66rem; font-weight:700; letter-spacing:.09em; text-transform:uppercase; color:var(--muted); padding:.1rem .6rem .4rem; }
.t2u-menu .t2u-menu-item{ display:flex; align-items:center; gap:.6rem; text-align:left; width:100%; border:1px solid var(--hair); border-radius:11px; padding:.55rem .7rem; margin-bottom:.4rem; color:var(--ink-soft); font-weight:600; background:var(--surface); transition:background .12s, color .12s, border-color .12s; }
.t2u-menu .t2u-menu-group + .t2u-menu-group{ margin-top:.55rem; }
.t2u-menu .t2u-menu-grouph{ font-size:.62rem; font-weight:700; letter-spacing:.09em; text-transform:uppercase; color:var(--muted); padding:.1rem .3rem .3rem; }
.t2u-menu .t2u-menu-item .t2u-menu-ic{ font-size:1.02rem; }
.t2u-menu .t2u-menu-item .t2u-menu-ch{ margin-left:auto; opacity:0; font-size:.8rem; transition:opacity .12s, transform .12s; transform:translateX(-3px); }
.t2u-menu .t2u-menu-item:hover{ background:var(--paper); color:var(--ink); border-color:var(--hair-strong); }
.t2u-menu .nav-pills .t2u-menu-item.active{ background:var(--brand); color:#fff; border-color:var(--brand); box-shadow:inset 4px 0 0 var(--brand-deep), var(--shadow-sm); }
.t2u-menu .t2u-menu-item.active .t2u-menu-ch{ opacity:1; transform:translateX(0); }
/* flex layout so the menu can collapse and the content reclaims the width */
.t2u-shell{ position:relative; gap:2.5rem; }   /* wider nav↔content gap so the connector's side gaps ~match the content top padding */
.t2u-nav{ flex:0 0 auto; width:200px; transition:width .2s ease; position:sticky; top:1rem; align-self:flex-start; overflow:visible; }   /* visible so right-placed menu tooltips aren't clipped (≤4 items never overflow) */
/* The frame owns the content's position: every module drops its markup here, at the same offset, so moving
   between them never shifts the title. Only what is inside changes. */
.t2u-content{ position:relative; min-width:0; padding-top:1.5rem; min-height:60vh; }   /* the blue top line + connector are drawn in #t2uConnector (SVG) */
.t2u-has-crumb{ margin-top:1.7rem; }   /* room above the content top for the breadcrumb, which sits over the line */
/* App › Module breadcrumb: a quiet eyebrow ABOVE the blue framing line, telling you where in Time2U you are. */
.t2u-crumb{ position:absolute; left:0; bottom:100%; margin-bottom:.4rem; display:flex; align-items:center; gap:.4rem; font-size:.72rem; font-weight:700; letter-spacing:.05em; text-transform:uppercase; color:var(--muted); }
.t2u-crumb-ic{ font-size:.95rem; color:var(--teal-deep); }
.t2u-crumb-sep{ font-size:.7rem; opacity:.55; }
.t2u-crumb-mod{ color:var(--brand); }
.t2u-loader{ padding:1.2rem .2rem; }   /* holds the boot skeleton, spanning the content width like the real list */
/* Every module opens the same way: no title (the menu says where you are), one info note, then its content. */
.t2u-hint{ display:flex; align-items:flex-start; gap:.6rem; font-size:.86rem; padding:.6rem .85rem; margin-bottom:1rem; }
.t2u-hint > i{ line-height:1.4; }
#t2uPageBar:empty, #msg:empty{ display:none; }   /* no key bar, no message -> no gap: every module starts at the same height */
.t2u-content.t2u-pending > *:not(.t2u-loader){ display:none; }   /* the module's own markup waits behind the one loader */
.t2u-connector{ position:absolute; top:0; left:0; pointer-events:none; overflow:visible; z-index:2; }
.t2u-connector path{ stroke:var(--brand); stroke-width:2; stroke-linecap:round; stroke-linejoin:round; }
.t2u-menu-collapse{ border:0; background:transparent; color:var(--muted); line-height:1; }
.t2u-menu-collapse:hover{ color:var(--brand); }
/* collapsed: icon-only, narrow */
.t2u-collapsed .t2u-nav{ width:52px; }   /* set on <html> before the first paint, so it never draws wide first */
.t2u-collapsed .t2u-menu .t2u-menu-label{ display:none; }
.t2u-collapsed .t2u-menu .t2u-menu-grouph{ display:none; }   /* icon-only: no room for the app headers */
.t2u-collapsed .t2u-menu .t2u-menu-item span[data-i18n], .t2u-collapsed .t2u-menu .t2u-menu-item .t2u-menu-ch{ display:none; }
.t2u-collapsed .t2u-menu .t2u-menu-item{ justify-content:center; padding-left:.4rem; padding-right:.4rem; gap:0; }
/* Masthead page-menu burger: hidden by default (and on the report page); shown only on mobile admin (.has-menu) */
.page-menu-btn{ display:none; }
.t2u-menu-mhead{ display:none; }                                     /* the mobile sheet's own header (title + X); desktop uses .t2u-menu-head */
@media (max-width:700px){
  body{ overflow-x:hidden; }                                        /* no stray horizontal scroll on phones */
  html.t2u-menu-open, html.t2u-menu-open body{ overflow:hidden; }   /* freeze the page behind the full-screen sheet */
  /* The sheet's z-index lives inside .t2u-shell (a z-index:1 stacking context), so it can't by itself rise
     above the masthead <nav> (z-index:1030). While the menu is open, lift the whole shell over the masthead. */
  html.t2u-menu-open .t2u-shell{ z-index:1060; }
  .brand-sub{ display:none; }                                       /* "Time Tracking Tool" subtitle doesn't fit next to the brand */
  .width-toggle{ display:none; }                                    /* width toggle is meaningless on phones — always full width */
  .container, [data-width="wide"] .container{ max-width:100% !important; }
  .t2u-shell{ flex-direction:column; gap:0; }
  .t2u-nav{ width:auto !important; position:static; }
  .t2u-connector{ display:none; }
  .t2u-content{ padding-top:0; }
  .page-menu-btn.has-menu{ display:inline-flex; }
  .t2u-menu-head{ display:none !important; }                        /* the desktop MENU header / collapse control has no place on a phone */
  /* On a phone the menu is a full-screen sheet with its own X to close — independent of the masthead, so
     scrolling the page never shifts it. Modules are grouped by application, exactly as on the desktop. */
  .t2u-menu{
    position:fixed; inset:0; z-index:1055;
    display:none; padding:.6rem 1rem 2rem; overflow-y:auto;
    background:var(--surface);
  }
  .t2u-menu.menu-open{ display:block; }
  .t2u-menu-mhead{ display:flex; align-items:center; justify-content:space-between; position:sticky; top:0; margin:-.6rem -1rem .8rem; padding:.7rem 1rem; background:var(--surface); border-bottom:1px solid var(--hair); z-index:1; }
  .t2u-menu-mlabel{ font-size:.72rem; font-weight:700; letter-spacing:.09em; text-transform:uppercase; color:var(--muted); }
  .t2u-menu-x{ border:0; background:transparent; color:var(--ink-soft); font-size:1.3rem; line-height:1; padding:.15rem .35rem; border-radius:9px; }
  .t2u-menu-x:hover{ color:var(--brand); background:var(--paper); }
  .t2u-menu .nav-pills{ display:flex; }
  .t2u-menu .t2u-menu-group + .t2u-menu-group{ margin-top:1.1rem; }
  .t2u-menu .t2u-menu-grouph{ font-size:.66rem; padding-bottom:.45rem; }
  .t2u-menu .t2u-menu-item{ margin-bottom:.5rem; padding:.85rem 1rem; font-size:1.02rem; }
  .t2u-menu .t2u-menu-item .t2u-menu-ic{ font-size:1.15rem; }
  .t2u-menu .t2u-menu-item:last-child{ margin-bottom:0; }
  /* Collapse is a DESKTOP-only choice: on a phone the menu always shows full labels, whatever the saved state. */
  .t2u-collapsed .t2u-menu .t2u-menu-grouph{ display:block; }
  .t2u-collapsed .t2u-menu .t2u-menu-item span[data-i18n]{ display:inline; }
  .t2u-collapsed .t2u-menu .t2u-menu-item .t2u-menu-ch{ display:inline; }
  .t2u-collapsed .t2u-menu .t2u-menu-item{ justify-content:flex-start; padding:.85rem 1rem; gap:.6rem; }
}
/* Wide layout toggle (persisted like the theme): widen the main containers. */
[data-width="wide"] .container{ max-width:min(1800px,94vw) !important; }
/* Wide layout: saved-report cards flow into a responsive grid (more per row). */
[data-width="wide"] #saved{ display:grid; grid-template-columns:repeat(auto-fill,minmax(560px,1fr)); gap:.75rem; align-items:start; }
[data-width="wide"] #saved .tok-grid{ margin-bottom:0 !important; }
.lang-toggle .icon-btn{ font-weight:600; font-family:var(--font-mono); }
/* masthead controls (language / theme / width): keep right-aligned, incl. when they wrap on mobile */
.navbar .container{ flex-wrap:wrap; }
.navbar .container > .no-print{ margin-left:auto; }

/* ---------- footer ---------- */
#t2uFooter{ margin-top:auto; }
.app-footer{ padding:1.4rem 0; border-top:1px solid var(--hair); background:var(--header-bg); backdrop-filter:saturate(140%) blur(8px); }
.app-footer .footer-brand{ color:var(--ink-soft); font-size:.8rem; font-weight:500; }
.app-footer .footer-sub{ color:var(--muted); font-size:.66rem; letter-spacing:.18em; text-transform:uppercase; font-weight:600; }

/* ---------- masthead (client report) ---------- */
.masthead{ padding:2.6rem 0 1.4rem; }
.eyebrow{
  font-weight:600; font-size:.7rem; letter-spacing:.22em; text-transform:uppercase;
  color:var(--brand); display:flex; align-items:center; gap:.6rem;
}
.eyebrow::before{ content:""; width:26px; height:2px; background:linear-gradient(90deg,var(--brand),var(--teal)); display:inline-block; }
.mh-project{
  font-family:var(--font-display); font-weight:600; font-optical-sizing:auto;
  font-size:clamp(1.9rem,4.2vw,3rem); line-height:1.05; letter-spacing:-.01em;
  color:var(--ink); margin:.5rem 0 1.1rem;
}
.mh-state{ min-height:1.2rem; font-size:.86rem; color:var(--muted); margin-top:.4rem; }
.mh-state.error{ color:var(--danger); }
.mh-rule{ height:1px; background:linear-gradient(90deg,var(--hair-strong),transparent); margin:1.3rem 0 .2rem; }

/* ---------- toolbar / controls ---------- */
.form-label{ font-weight:600; font-size:.72rem; letter-spacing:.12em; text-transform:uppercase; color:var(--muted); margin-bottom:.35rem; }
.form-select,.form-control{
  font-family:var(--font-sans); color:var(--ink); border-color:var(--hair-strong);
  border-radius:10px; box-shadow:none; background-color:var(--surface);
}
.form-select:focus,.form-control:focus{ border-color:var(--brand); box-shadow:0 0 0 3px rgba(46,111,183,.15); background-color:var(--surface); }

/* period nav group */
#nav .btn, .btn-outline-secondary{
  border-color:var(--hair-strong); color:var(--ink-soft); background:var(--surface);
  /* hover AND open/pressed (e.g. the user-selector dropdown) resolve to brand blue, so Bootstrap's default
     grey active fill never flashes between the two states. Set via Bootstrap's own vars to avoid specificity wars. */
  --bs-btn-hover-bg:var(--brand); --bs-btn-hover-border-color:var(--brand); --bs-btn-hover-color:#fff;
  --bs-btn-active-bg:var(--brand); --bs-btn-active-border-color:var(--brand); --bs-btn-active-color:#fff;
  --bs-btn-focus-shadow-rgb:68,114,196;   /* the focus ring is brand-tinted, not Bootstrap's default grey */
}
#nav .btn:hover, .btn-outline-secondary:hover{ background:var(--brand); border-color:var(--brand); color:#fff; }
#rangeLabel.disabled{ color:var(--ink)!important; opacity:1; font-weight:600; font-variant-numeric:tabular-nums; background:var(--surface)!important; }
.btn{ border-radius:10px; font-weight:600; }
.btn-primary{ background:var(--brand); border-color:var(--brand); }
.btn-primary:hover{ background:var(--brand-deep); border-color:var(--brand-deep); }

/* ---------- tabs (underline indicator) ---------- */
.nav-tabs{ border-bottom:1px solid var(--hair); gap:.4rem; }
.nav-tabs .nav-link{
  border:0; border-bottom:2px solid transparent; color:var(--muted); font-weight:600;
  font-size:.82rem; letter-spacing:.06em; text-transform:uppercase; padding:.55rem .25rem; margin-right:1.1rem;
  background:transparent;
}
.nav-tabs .nav-link:hover{ color:var(--ink); border-bottom-color:var(--hair-strong); }
.nav-tabs .nav-link.active{ color:var(--brand-deep); border-bottom-color:var(--brand); background:transparent; }

/* ---------- tables (editorial) ---------- */
.pane-wrap{ border:1px solid var(--hair); border-radius:var(--radius); background:var(--surface); overflow:visible; }
.table{ margin:0; color:var(--ink); --bs-table-bg:transparent; }
.table thead th{
  font-weight:600; font-size:.68rem; letter-spacing:.14em; text-transform:uppercase; color:var(--muted);
  border-bottom:1px solid var(--hair); padding:.7rem .9rem; background:transparent;
}
.table tbody td{ border-bottom:1px solid var(--hair); padding:.5rem .9rem; vertical-align:middle; color:var(--ink); }
.table tbody tr:last-child td{ border-bottom:0; }
/* group (month or description) rows */
.table tr.table-light{
  --bs-table-bg:transparent; background:linear-gradient(90deg,rgba(46,111,183,.06),transparent)!important;
}
.table tr.table-light td{ color:var(--brand-ink); font-weight:600; border-bottom:1px solid var(--hair-strong); }
.table tr.table-light td:first-child{ box-shadow:inset 3px 0 0 var(--brand); }
/* hours column = tabular mono */
.table td.text-end, .table th.text-end{ font-family:var(--font-mono); font-variant-numeric:tabular-nums; }
.table tbody tr:not(.table-light):hover td{ background:rgba(46,111,183,.04); }
.table td.ps-4{ color:var(--ink-soft); }

/* ---------- no-access message ---------- */
#noaccess .alert{
  border:1px solid var(--warn-bd); background:var(--warn-bg); color:var(--warn-ink);
  border-radius:var(--radius); font-weight:500; box-shadow:var(--shadow-sm);
}

/* ---------- admin: cards / inputs / token rows ---------- */
.card{ border:1px solid var(--hair); border-radius:var(--radius); box-shadow:var(--shadow-sm); background:var(--surface); }
.input-group-text{ background:var(--paper); border-color:var(--hair-strong); color:var(--muted); font-weight:600; font-size:.8rem; letter-spacing:.06em; text-transform:uppercase; }
h4{ font-family:var(--font-display); font-weight:600; letter-spacing:-.01em; color:var(--ink); }
.form-check-input:checked{ background-color:var(--brand); border-color:var(--brand); }
.form-check-label{ color:var(--ink-soft); }
.alert{ border-radius:12px; }
.alert-success{ background:#E7F3EE; color:var(--ok); border:1px solid #BFE0D2; }
.alert-warning{ background:var(--warn-bg); color:var(--warn-ink); border:1px solid var(--warn-bd); }
/* token row card (admin "Existing tokens") */
#saved .border{ border:1px solid var(--hair)!important; border-radius:12px!important; background:var(--surface); transition:box-shadow .2s,border-color .2s; }
#saved .border:hover{ border-color:var(--hair-strong)!important; box-shadow:var(--shadow-sm); }
#saved .fw-semibold{ color:var(--ink); }
#saved input[readonly]{ font-family:var(--font-mono); font-size:.82rem; color:var(--ink-soft); background:var(--paper); }
.btn-group .btn i{ pointer-events:none; }

/* tab count badges */
.nav-tabs .nav-link .badge{
  font-family:var(--font-mono); font-weight:600; font-size:.64rem; line-height:1;
  background:var(--brand); color:#fff; border-radius:999px; padding:.28em .5em;
  margin-left:.5rem; vertical-align:middle;
}
.nav-tabs .nav-link:not(.active) .badge{ background:var(--hair-strong); color:var(--ink-soft); }
.nav-tabs .nav-link .badge:empty{ display:none; }
/* token tree grows with the page (no inner scroll) */
#tree{ max-height:none!important; overflow:visible!important; background:var(--surface); }
#viewsBox{ background:var(--surface); }
#tree .form-check{ padding:.12rem 0 .12rem 1.9rem; }

.mh-project{ margin:.4rem 0 0; }

/* masthead: title left, stat cards right */
.mh-head{ display:flex; justify-content:space-between; align-items:flex-start; gap:2rem; flex-wrap:wrap; }
.mh-title{ flex:1 1 320px; }
.stat-cards{ display:flex; gap:1rem; flex-wrap:wrap; }
.stat-card{ text-align:center; min-width:132px; padding:1rem 1.5rem; border-radius:16px;
  background:linear-gradient(180deg,var(--surface),var(--paper)); border:1px solid var(--hair);
  box-shadow:0 16px 36px -24px rgba(14,36,64,.55); }
.stat-card .stat-label{ font-size:.62rem; letter-spacing:.22em; text-transform:uppercase; color:var(--muted); font-weight:600; }
.stat-card .stat-num{ font-family:var(--font-mono); font-variant-numeric:tabular-nums; font-size:2.2rem; line-height:1.1; color:var(--brand-ink); font-weight:500; margin-top:.3rem; }
.stat-cards .stat-card:nth-child(1){ border-top:3px solid var(--brand); }
.stat-cards .stat-card:nth-child(2){ border-top:3px solid var(--teal); }
.mh-period{ color:var(--ink-soft); font-size:.85rem; margin-top:.5rem; }
.mh-period .mh-period-lbl{ color:var(--muted); font-weight:600; font-size:.7rem; letter-spacing:.12em; text-transform:uppercase; }
.mh-asof{ color:var(--muted); font-size:.72rem; margin-top:.25rem; }
.mh-asof:empty{ display:none; }
/* Interfaces master grid (admin) — square-ish tiles; status shown by dot + border only */
.int-grid{ display:grid; grid-template-columns:repeat(auto-fill, minmax(190px,1fr)); gap:.7rem; }
.int-tile{ display:flex; flex-direction:column; gap:.55rem; text-align:left; min-height:92px; padding:.75rem .85rem; border:2px solid var(--border,#d0d5dd); border-radius:14px; background:var(--surface); color:var(--ink); cursor:pointer; box-shadow:var(--shadow-sm); transition:box-shadow .15s ease, border-color .15s ease, transform .04s ease; }
.int-tile:hover{ box-shadow:0 3px 12px rgba(0,0,0,.12); }
.int-tile:active{ transform:translateY(1px); }
/* The interface tile's border shows its run health (the ON/OFF badge inside shows the enabled flag). */
.int-tile.int-sel{ box-shadow:0 0 0 3px rgba(46,111,183,.28); }
/* Monitoring tiles: border colour mirrors the health badge (OK/warning/error/idle). */
.int-tile.int-b-success{ border-color:var(--bs-success); }
.int-tile.int-b-danger{ border-color:var(--bs-danger); }
.int-tile.int-b-warning{ border-color:var(--bs-warning); }
.int-tile.int-b-secondary{ border-color:var(--bs-secondary); }
.int-top{ display:flex; align-items:center; width:100%; }
.int-top .badge{ font-size:.6rem; font-weight:500; line-height:1; padding:.28em .55em; border-radius:999px; }   /* status + frequency badges share one size */
.int-badges{ display:flex; gap:.3rem; flex-wrap:wrap; justify-content:flex-start; }
.int-name{ font-weight:600; display:-webkit-box; -webkit-line-clamp:2; line-clamp:2; -webkit-box-orient:vertical; overflow:hidden; }
.int-foot{ margin-top:auto; align-self:flex-end; }   /* the frequency badge sits in the card's bottom-right corner */
/* status badges in the interface test/run result modal — match the rest (mono, semibold, pill) */
#opBody .badge{ font-family:var(--font-mono); font-weight:500; font-size:.62rem; border-radius:999px; padding:.26em .55em; }
.slack-preview{ background:var(--paper); border:1px solid var(--hair); border-radius:10px; padding:.5rem .7rem; font-size:.9rem; color:var(--ink-soft); line-height:1.45; }
/* Cosmos storage bar (admin): time2u containers + rest of the shared account, out of the 25 GB free tier */
.storage-bar{ height:14px; border-radius:8px; background:var(--paper); border:1px solid var(--hair); overflow:hidden; display:flex; }
.storage-mine{ background:var(--brand); }
.storage-other{ background:var(--muted); }
.storage-key{ display:inline-block; width:10px; height:10px; border-radius:2px; vertical-align:middle; }
/* Infrastructure section (admin) */
.rg-card{ border:1.5px solid var(--brand); border-radius:14px; background:color-mix(in srgb, var(--brand) 5%, var(--surface)); margin-bottom:1rem; overflow:hidden; }
.rg-head{ display:flex; align-items:center; gap:.45rem; padding:.7rem .95rem; background:transparent; border-bottom:1px solid color-mix(in srgb, var(--brand) 22%, transparent); }
.rg-ic{ color:var(--brand); font-size:1.05rem; }
.rg-body{ padding:.8rem .9rem; display:grid; grid-template-columns:repeat(auto-fill,minmax(320px,1fr)); gap:.6rem; }
.infra-card--wide{ grid-column:span 2; }
@media (max-width:719px){ .infra-card--wide{ grid-column:span 1; } }
.infra-card{ display:flex; gap:.75rem; align-items:flex-start; padding:.7rem .85rem; border:1.5px solid color-mix(in srgb, var(--teal) 55%, transparent); border-radius:12px; background:var(--surface); }
.infra-ic{ flex:0 0 auto; width:34px; height:34px; border-radius:9px; display:flex; align-items:center; justify-content:center; background:color-mix(in srgb, var(--teal) 12%, var(--surface)); color:var(--teal); font-size:1.05rem; }
.infra-name-row{ display:flex; align-items:center; gap:.35rem; flex-wrap:nowrap; }
.infra-badges{ display:flex; gap:.35rem; flex-wrap:wrap; margin-top:.35rem; }
.infra-cost{ font-size:.78rem; color:var(--muted); }
.infra-cost .bi{ color:var(--teal); }
.infra-cost strong{ color:var(--ink-soft); font-weight:600; }
.infra-name{ font-weight:600; color:var(--ink); }
.badge-type{ background:color-mix(in srgb, var(--brand) 14%, var(--surface)); color:var(--brand-ink); border:1px solid color-mix(in srgb, var(--brand) 34%, transparent); font-weight:500; }
.badge-tier{ background:color-mix(in srgb, var(--teal) 16%, var(--surface)); color:var(--teal); border:1px solid color-mix(in srgb, var(--teal) 34%, transparent); font-weight:500; }
.badge-region, .badge-scope{ background:var(--paper); color:var(--muted); border:1px solid var(--hair-strong); font-weight:500; }
.copy-name{ border:0; background:transparent; color:var(--muted); padding:0 .15rem; cursor:pointer; font-size:.85rem; line-height:1; }
.copy-name:hover{ color:var(--brand); }
/* Security section (admin) */
.sec-group{ border:1.5px solid var(--border,#d0d5dd); border-radius:14px; background:var(--surface); margin-bottom:1rem; padding:.7rem .95rem; }
.sec-group-h{ display:flex; align-items:center; font-size:.68rem; font-weight:700; letter-spacing:.12em; text-transform:uppercase; color:var(--muted); margin-bottom:.5rem; }
.sec-item{ display:flex; align-items:center; justify-content:space-between; gap:.75rem; padding:.4rem 0; border-top:1px solid var(--hair,#eef0f4); }
.sec-item:first-of-type{ border-top:0; }
.sec-item-main{ display:flex; align-items:center; gap:.55rem; color:var(--ink); }
.sec-item-ic{ flex:0 0 auto; color:var(--teal); font-size:1rem; }
.sec-item .form-check-label{ font-weight:500; }
/* admin-key ON/OFF toggle: colored badge + a larger green(on)/red(off) switch, on the right */
.sec-keyswitch{ display:inline-flex; align-items:center; gap:.6rem; cursor:pointer; margin:0; }
.sec-keyswitch .badge{ font-size:.72rem; letter-spacing:.06em; }
.sec-keyswitch .form-switch{ display:inline-flex; align-items:center; padding-left:0; min-height:0; margin:0; }
.sec-keyswitch .form-switch .form-check-input{ width:2.6em; height:1.3em; margin:0; float:none; cursor:pointer; }
.sec-keyswitch .form-check-input:checked{ background-color:var(--bs-success); border-color:var(--bs-success); }
.sec-keyswitch .form-check-input:not(:checked){ background-color:color-mix(in srgb, var(--bs-danger) 22%, var(--surface)); border-color:var(--bs-danger); }
.sec-keyswitch .form-check-input:focus{ box-shadow:0 0 0 .2rem color-mix(in srgb, var(--brand) 25%, transparent); }
.sec-sub{ color:var(--muted); font-size:.86rem; }
/* Key/value secret-rotation reference: the shared table's rows, without its card chrome (it sits inside a group). */
.t2u-table.sec-rot-table{ font-size:.86rem; margin-bottom:.3rem; border:0; border-radius:0; box-shadow:none; background:transparent; }
.t2u-table.sec-rot-table > tbody > tr > td{ padding:.3rem .4rem; vertical-align:top; }
.sec-rot-name{ font-weight:600; color:var(--ink); white-space:nowrap; }
/* Public work-item detail page (/support/<token>) */
.wi-block{ background:var(--surface); border:1px solid var(--hair); border-radius:16px; padding:1.1rem 1.25rem; margin-bottom:1.25rem; }
.wi-block:last-child{ margin-bottom:0; }
.wi-titlecard{ padding:.85rem 1.25rem; margin-bottom:0; box-shadow:var(--shadow); }
.wi-titlewrap{ padding-bottom:1.25rem; }
/* Sticky title: the wrapper pins from the top carrying the EXACT page background (same fixed gradient), so the
   band above and the gap below the title card show the page colour instead of the description peeking through. */
@media (min-width:992px){
  .wi-titlewrap{ position:sticky; top:0; z-index:5; margin-top:-1.5rem; padding-top:1.5rem;
    background:var(--page-bg); background-attachment:fixed; }
  /* rounded reveal: the page background is carved out in a quarter-circle at each bottom corner, so the content
     scrolling under the title emerges with a card-style rounded top (concave corners, not convex bumps). */
  .wi-titlewrap::before, .wi-titlewrap::after{ content:''; position:absolute; top:100%; width:16px; height:16px; pointer-events:none;
    background:var(--page-bg); background-attachment:fixed; }
  .wi-titlewrap::before{ left:0; -webkit-mask:radial-gradient(16px at 100% 100%, transparent 15px, #000 16px); mask:radial-gradient(16px at 100% 100%, transparent 15px, #000 16px); }
  .wi-titlewrap::after{ right:0; -webkit-mask:radial-gradient(16px at 0 100%, transparent 15px, #000 16px); mask:radial-gradient(16px at 0 100%, transparent 15px, #000 16px); }
}
.wi-title{ margin:0; font-family:var(--font-display); font-weight:600; color:var(--ink); font-size:1.5rem; line-height:1.25; }
.wi-side{ display:flex; flex-direction:column; gap:1rem; }
@media (min-width:992px){ .wi-side{ position:sticky; top:1.5rem; } }
.wi-card{ border:1px solid var(--hair); border-radius:16px; background:var(--surface); padding:1rem 1.1rem; width:290px; }
@media (max-width:991px){ .wi-card, .wi-side{ width:auto; } #wiTail{ height:0 !important; } }
.wi-fields{ display:grid; grid-template-columns:auto 1fr; gap:.6rem .9rem; align-items:center; }
.wi-f-lbl{ font-size:.6rem; letter-spacing:.1em; text-transform:uppercase; color:var(--muted); font-weight:600; white-space:nowrap; }
.wi-f-val{ font-weight:600; color:var(--ink); font-size:.88rem; text-align:right; justify-self:end; min-width:0; white-space:nowrap; }
.wi-contact{ margin-bottom:.9rem; }   /* label + dropdown span the full card width, above the label|value meta grid */
.wi-meta-fields{ align-items:baseline; row-gap:.55rem; }   /* label and value share the same baseline */
.wi-meta-fields .wi-f-val{ text-align:left; justify-self:start; white-space:normal; word-break:break-word; }
.wi-badge{ min-width:80px; text-align:center; }
.wi-none{ color:var(--muted); font-weight:600; }
.wi-att{ display:flex; align-items:center; gap:.4rem; font-size:.84rem; font-weight:600; color:var(--brand); text-decoration:none; padding:.2rem 0; min-width:0; }
.wi-att.d-none{ display:none; }
.wi-att:hover{ text-decoration:underline; }
.wi-att i{ flex:0 0 auto; opacity:.8; }
.wi-att span{ min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }   /* one line; full name in the title tooltip */
.wi-jumps{ display:flex; flex-direction:column; gap:.25rem; }
.wi-jump{ display:flex; flex-direction:column; font-size:.82rem; font-weight:600; color:var(--brand); text-decoration:none; padding:.12rem 0; }
.wi-jump.d-none{ display:none; }
.wi-jump:hover .wi-jump-date{ text-decoration:underline; }
.wi-jump-by{ font-size:.72rem; font-weight:500; color:var(--muted); }
.wi-more-list{ display:block; margin-top:.5rem; }
.wi-section-h{ font-size:.7rem; font-weight:700; letter-spacing:.12em; text-transform:uppercase; color:var(--muted); border-bottom:1px solid var(--hair-strong); padding-bottom:.35rem; margin-bottom:.8rem; }
/* email-format styling (tables/rules from the ingested message) stays scoped to the description block */
.wi-desc{ color:var(--ink-soft); }
.wi-desc table{ font-size:.9rem; }
/* Embedded images (email inline images carry fixed width/height attrs) never overflow the column on narrow screens. */
.wi-desc img, .wi-update-body img{ max-width:100% !important; height:auto !important; }
.wi-update{ border:1px solid var(--hair); border-radius:12px; background:var(--paper); padding:.85rem 1rem; margin-bottom:.85rem; scroll-margin-top:2rem; }
@media (min-width:992px){ .wi-update{ scroll-margin-top:7rem; } }   /* clear the sticky title + leave a white gap above the anchored reply */
.wi-update.d-none{ display:none; }
.wi-update:last-child{ margin-bottom:0; }
.wi-update-date{ font-size:.72rem; color:var(--muted); font-weight:600; margin-bottom:.35rem; }
.wi-update-by{ color:var(--ink-soft); }
.wi-update-body{ color:var(--ink-soft); }
.wi-update-body.wi-clamp{ display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical; overflow:hidden; }
.wi-update-body .wi-code{ background:var(--surface); border:1px solid var(--hair); border-radius:8px; padding:.5rem .7rem; margin:.4rem 0; font-family:var(--font-code); font-size:.82rem; overflow-x:auto; white-space:pre; }
.wi-toggle{ margin-top:.35rem; font-size:.78rem; font-weight:600; color:var(--brand); background:none; border:0; padding:0; cursor:pointer; }
.wi-toggle:hover{ text-decoration:underline; }
.wi-error-ic{ font-size:2.4rem; color:var(--muted); opacity:.75; }
/* The description carries arbitrary email HTML authored for a light background; in dark mode force readable text
   on everything except links and highlighted (background-colored) spans, whose own colors must win. */
html[data-theme="dark"] .wi-desc, html[data-theme="dark"] .wi-update-body{ color:var(--ink-soft); }
html[data-theme="dark"] .wi-desc *:not(a):not(mark):not([style*="background"]),
html[data-theme="dark"] .wi-update-body *:not(a):not(mark):not([style*="background"]){ color:var(--ink-soft) !important; }
/* A run log (Interfaces → Logs tab) reuses the shared table's row styling (hairlines + hover) but drops its card
   chrome — it sits inside the tab — and runs compact. */
.t2u-table.t2u-logtable{ margin-top:.25rem; border:0; border-radius:0; box-shadow:none; background:transparent; }
.t2u-table.t2u-logtable > tbody > tr > td{ padding:.35rem .55rem; font-size:.84rem; vertical-align:top; }
.t2u-table.t2u-logtable > tbody > tr > td:first-child{ width:9.5rem; white-space:nowrap; }
/* Live preview of a reply's signature + ticket link in the route modal. */
.rm-preview{ border:1px solid var(--hair); border-radius:12px; background:var(--paper); padding:.85rem 1rem; min-height:8rem; font-size:.9rem; color:var(--ink-soft); }
.rm-prev-body{ color:var(--muted); font-style:italic; margin-bottom:1rem; }
.rm-prev-sig{ margin-bottom:1rem; white-space:normal; }
/* Architecture diagram (inline SVG, theme-aware via CSS vars) */
.arch-diagram{ overflow-x:auto; padding:.4rem 0; }
.arch-svg{ width:100%; min-width:900px; height:auto; }
.arch-node{ fill:var(--surface); stroke:var(--hair-strong); stroke-width:1.3; }
.arch-node.own{ fill:color-mix(in srgb, var(--brand) 10%, var(--surface)); stroke:var(--brand); }
.arch-node.db{ fill:color-mix(in srgb, var(--teal) 12%, var(--surface)); stroke:var(--teal); }
.arch-node.ext{ fill:var(--paper); stroke:var(--hair-strong); }
/* node content (icon + title + optional subtitle), rendered as HTML in a foreignObject */
.arch-fo{ width:100%; height:100%; display:flex; align-items:center; justify-content:flex-start; gap:10px; padding:0 16px; box-sizing:border-box; font-family:var(--font-sans); pointer-events:none; }
.arch-fo .arch-ic{ flex:0 0 auto; font-size:17px; line-height:1; }
.arch-fo.own .arch-ic{ color:var(--brand); }
.arch-fo.db .arch-ic{ color:var(--teal); }
.arch-fo.ext .arch-ic{ color:var(--muted); }
.arch-txt{ min-width:0; text-align:left; }
.arch-title{ font-weight:600; font-size:13px; color:var(--ink); line-height:1.15; white-space:nowrap; }
.arch-res{ font-family:var(--font-mono, ui-monospace, monospace); font-size:9.5px; color:var(--brand); line-height:1.2; margin-top:1px; white-space:nowrap; letter-spacing:.2px; }
.arch-fo.db .arch-res{ color:var(--teal); }
.arch-fo.ext .arch-res{ color:var(--muted); }
.arch-sub{ font-weight:400; font-size:10px; color:var(--muted); line-height:1.2; margin-top:1px; white-space:normal; }
.arch-open{ font-size:10px; color:var(--muted); margin-left:5px; vertical-align:baseline; }
.arch-a{ cursor:pointer; text-decoration:none; }
.arch-a *{ text-decoration:none; }
.arch-a .arch-title{ color:var(--ink); }   /* keep the ink color, not the browser link blue/underline */
.arch-a:hover .arch-node.ext{ stroke:var(--brand); stroke-width:1.8; }
.arch-a:hover .arch-title, .arch-a:hover .arch-open{ color:var(--brand); }
.arch-edge{ fill:none; stroke:var(--muted); stroke-width:1.5; }
.arch-ah{ fill:var(--muted); }
.arch-elbg{ fill:var(--paper); opacity:.92; }
.arch-el{ fill:var(--ink-soft); font-size:10.5px; font-weight:600; text-anchor:middle; }
.arch-group{ fill:none; stroke:var(--hair-strong); stroke-width:1.2; stroke-dasharray:4 4; }
.arch-group.own-g{ stroke:var(--brand); opacity:.6; }
.arch-gt{ fill:var(--muted); font-size:11px; font-weight:700; letter-spacing:.07em; text-anchor:middle; }

/* chart hover tooltip */
.chart-tip{ position:fixed; z-index:60; pointer-events:none; background:var(--tip-bg); color:#fff;
  font-family:var(--font-mono); font-size:.74rem; padding:.32rem .55rem; border-radius:8px;
  opacity:0; transition:opacity .12s; box-shadow:var(--shadow); white-space:nowrap; }
.chart-tip.show{ opacity:1; }

/* update transitions for chart + tables */
@keyframes fadeUp{ from{ opacity:0; transform:translateY(7px) } to{ opacity:1; transform:none } }
.chart{ animation:fadeUp .35s ease both; }
.pane-wrap table{ animation:fadeUp .3s ease both; }

/* wider period label (week range fits) */
#rangeLabel{ width:auto!important; min-width:248px; }

/* visible checkboxes (admin token tree) */
.form-check-input{ border:1.5px solid var(--hair-strong); background-color:var(--surface); }
.form-check-input:focus{ border-color:var(--brand); box-shadow:0 0 0 3px rgba(46,111,183,.15); }
.form-check-input:checked{ background-color:var(--brand); border-color:var(--brand); }

/* bar chart */
.chart-wrap{ background:var(--surface); border:1px solid var(--hair); border-radius:var(--radius); padding:1rem 1.2rem .4rem; box-shadow:var(--shadow-sm); }
.chart{ width:100%; height:auto; display:block; }
.ct-grid{ stroke:var(--hair); stroke-width:1; }
.ct-bar{ fill:var(--brand); transition:fill .15s; }
.ct-bar:hover{ fill:var(--brand-deep); }
.ct-axis{ fill:var(--muted); font-size:13px; font-family:var(--font-mono); }
.ct-val{ fill:var(--brand-ink); font-size:13px; font-family:var(--font-mono); font-weight:600; }
.ct-x{ fill:var(--muted); font-size:12px; font-family:var(--font-sans); }

/* 3-level (all-projects) tables */
.table tr.subgroup td{ color:var(--ink); font-weight:600; background:rgba(46,111,183,.03); }
.table td.ps-5{ color:var(--ink-soft); padding-left:2.5rem!important; }

/* inline entry detail (web only) */
tr.leaf{ cursor:pointer; }
tr.leaf:hover > td{ background:rgba(46,111,183,.06); }
.no-detail tr.leaf{ cursor:default; }
.no-detail tr.leaf:hover > td{ background:transparent; }
.no-detail .leaf-caret{ visibility:hidden; }
.leaf-caret{ display:inline-block; width:1.2em; margin-right:.4rem; color:var(--brand); font-size:1rem; line-height:1; transition:transform .18s; }
tr.leaf.open .leaf-caret{ transform:rotate(90deg); }
/* deep-nesting indent: Bootstrap only ships ps-0..ps-5, so extend the scale (1.5rem/level) for N-level trees */
.pane-wrap .ps-6{ padding-left:4.5rem!important; } .pane-wrap .ps-7{ padding-left:6rem!important; }
.pane-wrap .ps-8{ padding-left:7.5rem!important; } .pane-wrap .ps-9{ padding-left:9rem!important; }
tr.entries-detail > td{ padding:0!important; background:var(--surface); box-shadow:inset 3px 0 0 var(--teal); }
@keyframes edIn{ from{ opacity:0; transform:translateY(-6px) } to{ opacity:1; transform:none } }
.ed-wrap{ max-height:340px; overflow:auto; padding:0 .9rem .6rem 2.8rem; animation:edIn .22s ease both; }
.ed-row{ display:grid; grid-template-columns:104px 1.3fr 2fr 60px 60px 84px; gap:.7rem; align-items:center; padding:.22rem 0; border-bottom:1px solid var(--hair); font-size:.84rem; }
.ed-row:last-child{ border-bottom:0; }
.ed-head{ position:sticky; top:0; z-index:1; background:var(--surface); padding-top:.45rem; font-size:.62rem; letter-spacing:.1em; text-transform:uppercase; color:var(--muted); font-weight:600; }
.ed-head span:last-child{ text-align:right; }
.ed-date,.ed-user,.ed-note,.ed-time{ font-family:var(--font-mono); color:var(--ink-soft); font-weight:400; }
.ed-note{ overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.ed-h{ font-family:var(--font-mono); text-align:right; color:var(--brand-ink); }

/* make Bootstrap muted text follow the theme palette (readable in dark) */
.text-muted,.form-text{ color:var(--muted)!important; }
/* readable input placeholders in both themes */
.form-control::placeholder,.form-select::placeholder{ color:var(--muted); opacity:1; }
/* donuts */
.donuts-wrap{ display:flex; gap:1rem; flex-wrap:wrap; }
.donut{ flex:1 1 380px; min-width:330px; background:var(--surface); border:1px solid var(--hair); border-radius:var(--radius); box-shadow:var(--shadow-sm); padding:1rem 1.1rem; animation:fadeUp .3s ease both; }
.dn-title{ font-size:.66rem; letter-spacing:.2em; text-transform:uppercase; color:var(--muted); font-weight:600; margin-bottom:.6rem; }
.dn-body{ display:flex; flex-direction:row; align-items:flex-start; gap:1.4rem; }   /* donut left (top-aligned), legend right */
.dn-svg{ width:170px; height:170px; flex:0 0 auto; }
.dn-svg path, .dn-svg circle{ cursor:pointer; transition:opacity .12s; }
.dn-svg:hover path:not(:hover), .dn-svg:hover circle:not(:hover){ opacity:.55; }
.dn-center{ font-family:var(--font-mono); font-size:15px; fill:var(--brand-ink); font-weight:500; }
.dn-legend{ flex:1 1 auto; min-width:0; }
.dn-li{ display:grid; grid-template-columns:12px 1fr auto 3em; gap:.5rem; align-items:center; font-size:.78rem; padding:.12rem 0; }
.dn-sw{ width:10px; height:10px; border-radius:2px; display:inline-block; }
.dn-name{ color:var(--ink); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.dn-h{ font-family:var(--font-mono); color:var(--ink-soft); }
.dn-pct{ font-family:var(--font-mono); color:var(--muted); text-align:right; }

/* report view selector (segmented control) + sticky table header on scroll */
.report-toolbar{ display:flex; justify-content:space-between; align-items:center; gap:1rem; flex-wrap:wrap; }
.view-seg{ display:inline-flex; gap:.25rem; background:var(--paper); border:1px solid var(--hair-strong); border-radius:12px; padding:.25rem; }
.view-seg .btn{ border:0; border-radius:9px; padding:.42rem .95rem; font-weight:600; font-size:.85rem; color:var(--ink-soft); background:transparent; box-shadow:none; }
.view-seg .btn:hover{ color:var(--ink); background:var(--surface); }
.view-seg .btn.active{ background:var(--brand); color:#fff; }
/* By Users secondary-grouping control */
.us-group-bar{ display:flex; align-items:center; gap:.6rem; }
.us-group-lbl{ font-size:.7rem; font-weight:700; letter-spacing:.06em; text-transform:uppercase; color:var(--muted); }
.us-seg .btn{ font-size:.78rem; padding:.3rem .7rem; }
/* end-of-report legend (also printed) */
.report-note{ display:flex; align-items:center; gap:.45rem; margin-top:1.25rem; padding-top:.85rem; border-top:1px solid var(--hair); font-size:.8rem; font-style:italic; color:var(--muted); }
.pane-wrap thead th{ position:sticky; top:0; z-index:20; background:var(--surface); }

/* ===================== Tables =====================
   One look for every list table (users, clients, support). A row is .6rem tall, hairlines between rows, a
   quiet hover, and the header — plus any filter row that sits on it — STICKS to the top so the columns stay
   labelled however far the list scrolls. Column widths and per-page tweaks are added by the table's own class. */
/* The table is a CARD: a perimeter border, rounded corners and a soft shadow, on --surface (white) which
   already reads apart from the page's --paper. The header sits on a --paper band, sticky, so the columns stay
   labelled however far the list scrolls. Corners are rounded on the corner CELLS, not by clipping the box —
   overflow:hidden would break the sticky header. */
.t2u-table{ width:100%; border-collapse:separate; border-spacing:0; margin:0;
  border:1px solid var(--hair-strong); border-radius:.8rem; background:var(--surface); box-shadow:var(--shadow-sm); }
.t2u-table > thead > tr > th,
.t2u-table > tbody > tr > td{ padding:.6rem .7rem; vertical-align:middle; }
.t2u-table > tbody > tr > td{ border-top:1px solid var(--hair); }
.t2u-table > tbody > tr:hover > td{ background:color-mix(in srgb, var(--brand) 5%, var(--surface)); }
.t2u-table > tbody > tr:last-child > td:first-child{ border-bottom-left-radius:.8rem; }
.t2u-table > tbody > tr:last-child > td:last-child{ border-bottom-right-radius:.8rem; }
.t2u-table > thead > tr:first-child > th{
  position:sticky; top:0; z-index:6; background:var(--paper);
  font-size:.7rem; font-weight:700; letter-spacing:.06em; text-transform:uppercase; color:var(--muted); white-space:nowrap;
}
.t2u-table > thead > tr:first-child > th:first-child{ border-top-left-radius:.8rem; }
.t2u-table > thead > tr:first-child > th:last-child{ border-top-right-radius:.8rem; }
/* Filters and the add action live above the table, in a toolbar — not inside the header. Search grows to fill,
   the selects keep a sensible width, and the add button is pushed to the far right. */
.t2u-toolbar{ display:flex; flex-wrap:wrap; gap:.5rem; align-items:center; margin-bottom:.6rem; }
.t2u-toolbar .t2u-tb-search{ flex:1 1 240px; min-width:180px; }
.t2u-toolbar .t2u-tb-sel{ flex:0 0 auto; width:auto; min-width:150px; }
.t2u-toolbar select, .t2u-toolbar input[type="date"]{ flex:0 0 auto; width:auto; }   /* bare selects/dates (support) sit next to the labelled ones */
.t2u-toolbar .t2u-tb-add{ margin-left:auto; flex:0 0 auto; }
/* a sortable header is a button: the label, and a caret that lights up and points once the column is the sort key */
.t2u-sort{ display:inline-flex; align-items:center; gap:.3rem; border:0; background:none; padding:0; margin:0; font:inherit;
  letter-spacing:inherit; text-transform:inherit; color:inherit; cursor:pointer; }
.t2u-sort .bi{ font-size:.72rem; opacity:.35; transition:opacity .12s, transform .12s; }
.t2u-sort:hover .bi{ opacity:.7; }
.t2u-sort.on{ color:var(--brand); }
.t2u-sort.on .bi{ opacity:1; color:var(--brand); }


/* modal (delete confirm) — body bg is transparent, force opaque surface */
.modal-content{ background:var(--surface); border:1px solid var(--hair); box-shadow:var(--shadow-lg,0 1rem 3rem rgba(0,0,0,.2)); }
.modal-header,.modal-footer{ border-color:var(--hair); }

/* uniform icon buttons (admin token actions) */
.icon-btn{ border:1px solid var(--hair-strong); color:var(--ink-soft); background:var(--surface); }
.icon-btn:hover{ background:var(--paper); color:var(--ink); border-color:var(--hair-strong); }
.icon-btn.act-open, .icon-btn.act-copyurl, .icon-btn.sup-edit{ color:var(--brand); }
.icon-btn.act-open:hover, .icon-btn.act-copyurl:hover, .icon-btn.sup-edit:hover{ background:var(--brand); color:#fff; border-color:var(--brand); }
.icon-btn.act-del, .icon-btn.sup-del{ color:var(--danger); }
.icon-btn.act-del:hover, .icon-btn.sup-del:hover{ background:var(--danger); color:#fff; border-color:var(--danger); }

/* token card badges */
.t2u-badge{ font-family:var(--font-mono); font-weight:500; font-size:.6rem; background:var(--brand); color:#fff; border-radius:999px; padding:.22em .5em; vertical-align:middle; }
/* token config column + differentiated badge backgrounds (source vs reports vs entry detail) */
.tok-config{ display:flex; flex-direction:column; gap:.35rem; align-items:flex-start; max-width:230px; }
.t2u-badge.badge-entry{ background:var(--teal); }
.t2u-badge.int-freq{ background:#d97706; }
/* project/task picker: split projects into two columns */
.tree-cols{ display:grid; grid-template-columns:1fr 1fr; column-gap:1.5rem; align-items:start; }
@media (max-width:700px){ .tree-cols{ grid-template-columns:1fr; } }
/* interface detail header: the title rendered as big badges (each half of "X → Y") joined by a direction arrow */
.int-title-row{ display:flex; align-items:center; flex-wrap:wrap; gap:.5rem; }
.int-titlebadge{ font-size:.95rem; font-weight:600; padding:.35rem .7rem; border-radius:9px; background:color-mix(in srgb, var(--brand) 12%, var(--surface)); color:var(--brand); border:1px solid color-mix(in srgb, var(--brand) 30%, transparent); }
/* alias-route "Reply" mode badge — bigger so the text (incl. the mark prefix) reads clearly */
.route-reply{ font-size:.8rem; font-weight:600; padding:.4em .65em; border-radius:7px; }
.int-arrow-lg{ color:var(--muted); font-size:1.2rem; font-weight:600; line-height:1; }
/* interface detail card: only the border reflects on/off (body stays editable, like the small tiles) */
.int-card{ border-width:2px; }
.int-card.on{ border-color:#16a34a; }
.int-card.off{ border-color:#dc2626; }
/* interface enable switch: obviously interactive (pointer, larger); danger when off, success when on */
.int-switch{ display:flex; align-items:center; gap:.4rem; padding-left:2.9em; cursor:pointer; }
.int-switch .form-check-input{ cursor:pointer; width:2.6em; height:1.4em; margin-top:0; margin-left:-2.9em; border:0; }
.int-switch .form-check-input:not(:checked){ background-color:#dc2626; }
.int-switch .form-check-input:checked{ background-color:#16a34a; }
.int-switch .form-check-input:focus{ box-shadow:0 0 0 .2rem rgba(46,111,183,.25); outline:none; }
.int-switch .form-check-label{ cursor:pointer; font-weight:600; user-select:none; color:#dc2626; }
.int-switch .form-check-input:checked ~ .form-check-label{ color:#16a34a; }
/* support-email interface: alias -> ADO routes summary table (the .sup-table look lives with the tickets table) */
#supRoutesWrap{ overflow-x:auto; }
.ig-lbl{ flex:0 0 11rem; justify-content:flex-start; white-space:nowrap; }   /* fixed, equal-width input-group labels (Data source / Name / Slug) */
#slugPreview{ min-height:2.6rem; }   /* reserve space for up to 2 lines so the button doesn't jump */
.tok-lbl-copy{ border:0; background:transparent; color:var(--muted); padding:0 .35rem; font-size:.82rem; line-height:1; cursor:pointer; vertical-align:middle; }
.tok-lbl-copy:hover{ color:var(--brand); }
.tok-date{ display:block; width:100%; text-align:center; font-weight:500; font-size:.62rem; line-height:1.4; background:var(--paper); color:var(--brand-deep); border:1px solid var(--hair); border-radius:10px; padding:.35em .6em; }
.tok-date .tok-date-t{ font-weight:500; color:var(--muted); }
/* saved-report card: 3-col x 2-row grid (name|·|toolbar / slug badge|config|dates) */
.tok-grid{ display:grid; grid-template-columns:1fr auto auto; column-gap:1rem; row-gap:.4rem; align-items:start; }
.tok-slug-badge{ display:inline-block; max-width:230px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; vertical-align:bottom; font-family:var(--font-mono); font-weight:500; font-size:.66rem; background:var(--paper); color:var(--brand-deep); border:1px solid var(--hair); border-radius:10px; padding:.32em .6em; cursor:pointer; text-decoration:none; transition:border-color .15s,color .15s; }
.tok-slug-badge:hover{ border-color:var(--brand); color:var(--brand); }
.tok-more{ text-decoration:none; font-weight:600; }
#tree .toggle i{ color:var(--brand); }
#saved input[readonly]{ font-family:var(--font-mono); font-size:.78rem; }

/* tooltips (theme-dark bg + arrow, all placements via the Bootstrap variable) */
.tooltip{ --bs-tooltip-bg:var(--tip-bg); --bs-tooltip-color:#fff; --bs-tooltip-opacity:1; }
.tooltip-inner{ font-family:var(--font-sans); font-size:.75rem; padding:.35rem .6rem; border-radius:8px; }
/* Warning-styled tooltip (amber), e.g. the "check the auto-picked task" nudge on the timer. */
.t2u-tip-danger{ --bs-tooltip-bg:var(--danger); }
.t2u-tip-danger .tooltip-inner{ font-weight:600; }

/* Date inputs wear the app's own calendar affordance: the browser's picker indicator (its grey icon and its
   un-themeable native tooltip) is hidden and replaced by a branded button that opens the picker on click. */
.t2u-datewrap{ position:relative; display:inline-flex; align-items:center; }
.t2u-datewrap-block{ display:block; }
.t2u-datewrap > input[type=date]{ padding-right:2rem; }
.t2u-datewrap-block > input[type=date]{ width:100%; }
.t2u-datewrap > input[type=date]::-webkit-calendar-picker-indicator{ display:none; -webkit-appearance:none; }
.t2u-date-btn{
  position:absolute; right:.3rem; top:50%; transform:translateY(-50%); z-index:2;
  border:0; background:none; padding:.1rem .2rem; line-height:1; cursor:pointer;
  color:var(--brand); display:inline-flex; align-items:center;
}
.t2u-date-btn:hover{ color:var(--teal-deep); }
.t2u-date-btn:focus-visible{ outline:2px solid var(--brand); outline-offset:1px; border-radius:4px; }
.tooltip.show{ opacity:1!important; }

/* spinner (homogeneous loading indicator) */
@keyframes spin{ to{ transform:rotate(360deg) } }
.spinner{ display:inline-block; width:20px; height:20px; border:2.5px solid var(--hair-strong); border-top-color:var(--brand); border-radius:50%; animation:spin .7s linear infinite; vertical-align:middle; }
.spinner-sm{ width:13px; height:13px; border-width:2px; }

/* ---------- Tickets (admin) ---------- */
/* Users: a deactivated person stays listed but reads as switched off. */
/* A deactivated/archived row reads as switched off — but its actions are still live, so only the informational
   cells dim; the actions cell stays at full strength (opacity on the row itself can't be undone per-cell). */
.t2u-off > td{ opacity:.55; }
.t2u-off > td.usr-acts, .t2u-off > td.text-end{ opacity:1; }
.t2u-off select{ pointer-events:none; }
/* Name and email share one column: the name leads, the email sits under it in a quieter tone. */
.usr-id{ display:flex; flex-direction:column; line-height:1.25; }
.usr-id .usr-name{ font-weight:600; }
.usr-id .usr-email{ font-size:.82em; color:var(--ink-soft); }

.sup-group{ border:1px solid var(--hair-strong); border-radius:12px; margin:.9rem 0; overflow:hidden; background:var(--surface); }
.sup-group>summary{ cursor:pointer; padding:.5rem .85rem; font-weight:600; display:flex; align-items:center; gap:.4rem; background:color-mix(in srgb, var(--brand) 5%, var(--surface)); list-style:none; }
.sup-g-head{ display:flex; align-items:center; gap:.4rem; min-width:0; }
.sup-g-actions{ margin-left:auto; display:flex; gap:.4rem; flex:0 0 auto; }
.sup-group>summary::-webkit-details-marker{ display:none; }
.sup-group>summary::before{ content:"\25B8"; color:var(--muted); transition:transform .15s; display:inline-block; }
.sup-group[open]>summary::before{ transform:rotate(90deg); }
.sup-g-ic{ color:var(--brand); }
.sup-g-mb{ color:var(--brand-ink); }
.sup-g-al{ font-family:var(--font-mono); font-weight:500; color:var(--muted); font-size:.85rem; }
.sup-table-wrap{ overflow-x:auto; padding:.5rem .65rem .65rem; }   /* the rounded table floats with a margin inside the mailbox, so its corners don't clash with the card's */
.sup-table{ margin:0; font-size:.84rem; white-space:nowrap; }
.sup-table th{ color:var(--muted); font-weight:600; white-space:nowrap; }
.sup-mono{ font-family:var(--font-mono); font-size:.8rem; }
.sup-title{ max-width:260px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.sup-del:hover{ color:#b02a37; }
.sup-orphan-row td{ background:color-mix(in srgb, #dc3545 8%, transparent); }
.spin-center{ display:flex; align-items:center; justify-content:center; padding:1.1rem; min-height:140px; }
.report-loading{ display:flex; align-items:center; justify-content:center; min-height:300px; }

/* ---------- entrance animations ---------- */
@keyframes riseIn{ from{ opacity:0; transform:translateY(12px) } to{ opacity:1; transform:none } }
.reveal{ animation:riseIn .6s cubic-bezier(.2,.75,.2,1) both; }
.d-1{ animation-delay:.05s } .d-2{ animation-delay:.13s } .d-3{ animation-delay:.22s }
@media (prefers-reduced-motion:reduce){ .reveal{ animation:none } body{ background-attachment:initial } }

/* ---------- dark theme ---------- */
html[data-theme="dark"]{
  --paper:#0E1726;
  --surface:#16212E;
  --ink:#E7EDF6;
  --ink-soft:#C2CDDC;
  --muted:#8B9AB0;
  --hair:#26344A;
  --hair-strong:#3A4D69;
  --brand:#4C8FD6;
  --brand-deep:#2E6FB7;
  --brand-ink:#A9C8EA;
  --header-bg:rgba(16,23,38,.82);
  --tip-bg:#0A1320;
  --page-bg:
    radial-gradient(58rem 38rem at 8% -12%, rgba(76,143,214,.16), transparent 60%),
    radial-gradient(46rem 36rem at 112% 6%, rgba(26,161,180,.12), transparent 55%),
    var(--paper);
  --warn-bg:#3A300F; --warn-ink:#E8C877; --warn-bd:#574613; --warning:#C99A3B;
  --shadow-sm:0 1px 2px rgba(0,0,0,.35), 0 1px 1px rgba(0,0,0,.3);
}
html[data-theme="dark"] .navbar img.brand-logo{ filter:brightness(0) invert(1); }
/* light dropdown caret in dark mode (Bootstrap's default chevron SVG is dark) */
html[data-theme="dark"] .form-select{ background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath fill='none' stroke='%23E7EDF6' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3E%3C/svg%3E"); }

/* print / export to PDF: keep header + masthead + chart + active table */
@media print{
  /* always print in light palette, regardless of active theme */
  html, html[data-theme="dark"]{
    --paper:#fff; --surface:#fff; --ink:#0E2440; --ink-soft:#33455F; --muted:#697892;
    --hair:#E2E7EF; --hair-strong:#CDD6E3; --header-bg:#fff;
  }
  html[data-theme="dark"] .navbar img.brand-logo{ filter:none; }
  *{ -webkit-print-color-adjust:exact!important; print-color-adjust:exact!important; }
  .mh-head, .stat-cards{ flex-wrap:nowrap!important; }
  body{ background:#fff!important; }
  body::before{ display:none!important; }
  .navbar{ box-shadow:none; border-bottom:1px solid #d0d0d0; }
  .no-print{ display:none!important; }
  #report.container{ max-width:none!important; width:100%!important; padding-left:0!important; padding-right:0!important; }   /* use the full page width, no side gutters */
  .leaf-caret{ display:none!important; }   /* entry detail isn't printed, so the drill-down caret is meaningless */
  .chart, .chart-wrap{ width:100%!important; }
  .chart-wrap, .pane-wrap, .stat-card, .donut{ box-shadow:none!important; }
  #donutsSection{ break-before:page; page-break-before:always; }
  .donuts-wrap{ flex-direction:column; gap:1.4rem; }   /* stack full-width; each donut is donut-left + legend-right (base) -> 2 per page */
  .donut{ break-inside:avoid; flex:0 0 auto!important; }   /* size to content height (in a column, flex-basis would set height and stretch) */
  .pane-wrap{ break-before:page; page-break-before:always; }
  .pane-wrap thead th{ position:static!important; }
  .entries-detail{ display:none!important; }
  .reveal, .chart, .pane-wrap table, .donut{ animation:none!important; }
  @page{ size:A4 landscape; margin:1.2cm; }
}

/* ===================== Timesheet ===================== */
.ts-bar{ display:flex; flex-wrap:wrap; gap:.75rem; align-items:center; justify-content:space-between; margin:.5rem 0 1rem; }
.ts-nav{ display:flex; align-items:center; gap:.4rem; }
/* The date field is sized to its content (plus room for the calendar button), so there's no dead space between
   the date and the icon. */
.ts-nav input[type="date"]{ width:auto; }
.ts-nav .t2u-datewrap > input[type=date]{ width:8.3rem; padding-right:1.8rem; }
.ts-title{ font-weight:600; margin-left:.4rem; }
.ts-tools{ display:flex; align-items:center; gap:.5rem; }
.ts-usermenu{ padding:.5rem; min-width:260px; max-height:340px; overflow:auto; }
.ts-you{ color:var(--brand); font-size:.78rem; }

/* THE TIMER — the one thing this page is for. Everything else on the timesheet is review; this is the act.
   It gets the page's largest type (the running clock), a rail that only lights up while time is being tracked,
   and the only oversized button in the app. The rest of the day stays deliberately quiet underneath. */
.ts-timer{
  position:relative; display:flex; align-items:center; gap:1rem;
  padding:1.15rem .9rem 1.15rem 1.35rem; margin-bottom:1.5rem;   /* right pad matches the rows, so edges align */
  border:1px solid var(--hair);
  border-left:5px solid var(--teal);   /* the rail IS the card's left border, so it follows the corner exactly */
  border-radius:.9rem; background:var(--surface); box-shadow:var(--shadow-sm);
  transition:border-color .18s, box-shadow .18s, background .18s;
}
/* The running timer's right block mirrors a row's times+duration+actions in width, so the billable $ at its
   left lines up under the rows' $ and the stop button lines up under the rows' play button. */
.ts-timer-right{ flex:0 0 auto; width:calc(13.5rem + 6rem + 5.6rem + 1.5rem); display:flex; align-items:center; gap:.75rem; min-width:0; }
.ts-timer-right .ts-elapsed{ flex:1 1 auto; text-align:center; min-width:0; }
/* A row's times sit at the LEFT of their column so the $ has a fixed x that the timer's $ aligns to. */
.ts-row .ts-times{ justify-content:flex-start; }
.ts-timer-off:hover{ border-top-color:var(--hair-strong); border-right-color:var(--hair-strong); border-bottom-color:var(--hair-strong); box-shadow:var(--shadow); }
/* Running: the whole card wears the wordmark's light blue — the same colour that starts the clock. */
.ts-timer-on{
  border-color:var(--teal);
  box-shadow:0 0 0 1px var(--teal) inset, var(--shadow);
  background:linear-gradient(90deg, color-mix(in srgb, var(--teal) 8%, var(--surface)), var(--surface) 55%);
}
.ts-timer .ts-taskblock{ flex:1 1 auto; min-width:0; }
.ts-timer-on .ts-crumb-leaf{ font-size:1.06rem; }
/* the running clock is the biggest thing on the page, in the app's mono face, digits that never jump */
.ts-elapsed{ font-family:var(--font-mono); font-variant-numeric:tabular-nums; font-weight:700; font-size:2rem; letter-spacing:-.02em; line-height:1; }
/* The hourglass sits INSIDE the field, like a unit: it belongs to the hour, not beside it. */
.ts-runfrom{ position:relative; display:inline-flex; align-items:center; color:var(--teal); }
.ts-runfrom .ts-start{ width:5.6rem; padding-left:1.7rem; padding-right:.4rem; text-align:center; }
.ts-runfrom-ic{ position:absolute; left:.55rem; font-size:.9rem; pointer-events:none; }
/* a running duration breathes: the colour drifts to a lighter tone and back, so the page reads as live */
.ts-pulse{ animation:ts-breathe 2.4s ease-in-out infinite; }
/* The running clock breathes between the two brand blues — deep ink and the wordmark's light blue — so it
   reads as alive without a spinner. */
@keyframes ts-breathe{ 0%,100%{ color:var(--ink); } 50%{ color:var(--teal); } }
@media (prefers-reduced-motion:reduce){ .ts-pulse{ animation:none; } }
@media (max-width:700px){
  /* The card reads top-down: the task block (breadcrumb + note) on its own; then the start time and the clock
     on one line; then the full-width button. Nothing shares a line unless it belongs together. */
  .ts-timer{ flex-wrap:wrap; row-gap:.75rem; column-gap:.6rem; }
  .ts-timer .ts-taskblock{ flex:1 1 100%; }
  .ts-timer-right{ width:100%; flex-wrap:wrap; column-gap:.6rem; }
  .ts-runfrom{ flex:0 0 auto; }
  .ts-elapsed{ flex:1 1 auto; font-size:1.7rem; text-align:right; }
  .ts-startbtn.ts-iconbtn, .ts-timer-on .btn-danger.ts-iconbtn{ flex:1 1 100%; width:100%; align-self:auto; padding:.6rem; }
}
/* In the task block (a column) the note keeps its natural height and full width — it must never stretch tall. */
.ts-taskblock .ts-note{ flex:0 0 auto; width:100%; max-width:none; }
/* The note reads as plain text until touched: no frame at rest, the input box appears on hover/focus. It is set
   smaller than the breadcrumb above it, so the task path leads and the note is the quieter, secondary line. */
.ts-note{ border-color:transparent; background:transparent; font-size:.82rem; transition:border-color .12s, background .12s; }
.ts-note:hover{ border-color:var(--hair-strong); background:var(--surface); }
.ts-path{ font-size:.78rem; opacity:.7; }

.ts-group{ border:1px solid var(--hair-strong); border-radius:.7rem; background:var(--surface); box-shadow:var(--shadow-sm); }   /* card, like the tables; no overflow clip so the kebab menu escapes */
.ts-group-h{ border-top-left-radius:.6rem; border-top-right-radius:.6rem; }
.ts-group-h{ align-items:center; padding:.6rem .9rem; border-bottom:1px solid var(--hair); font-weight:600; background:var(--paper); border-top-left-radius:.7rem; border-top-right-radius:.7rem; }
.ts-row{ display:flex; align-items:center; gap:.75rem; padding:.6rem .9rem; border-bottom:1px solid var(--bs-border-color); position:relative; }
.ts-row:has(.dropdown-menu.show){ z-index:1081; }   /* the row whose kebab is open rises above the rows below it */
.ts-row:last-of-type{ border-bottom:0; }
/* The header title of the Working day and the Day summary read the same: a small uppercase eyebrow, muted. */
.bd-title, .ts-col-task{ min-width:0; font-size:.72rem; font-weight:700; letter-spacing:.05em; text-transform:uppercase; color:var(--muted); }
.ts-times{ font-variant-numeric:tabular-nums; opacity:.8; white-space:nowrap; }
.ts-dur{ font-variant-numeric:tabular-nums; font-weight:600; min-width:5.5rem; text-align:center; }
/* The day's span and total, in the group header: read at a glance, whatever the list does below. */
.ts-daysum-span{ color:var(--muted); font-variant-numeric:tabular-nums; text-align:center; }
/* The day total reads the same in the Working day header and the Day summary — brand blue, tabular. */
.ts-daysum-total{ color:var(--brand); font-weight:700; font-variant-numeric:tabular-nums; }

.ts-empty{ padding:1.2rem; text-align:center; opacity:.65; }

/* Day summary: a stacked bar of the day's hours by project, a chip per project, and a drill-down into a
   project's tasks/subtasks when its chip is opened. Read-only — a picture of where the day went. */
/* Working day and Day summary are two tabs; the timer above keeps its own bottom margin, so the tab strip needs
   none, and the content sits a touch below the strip. */
.ts-daytabc{ padding-top:.9rem; }
#tsBreakdown{ margin-top:0; }
.bd-card{ border:1px solid var(--hair-strong); border-radius:.7rem; background:var(--surface); box-shadow:var(--shadow-sm); overflow:hidden; }
.bd-head{ display:flex; align-items:center; justify-content:space-between; padding:.55rem .9rem; background:var(--paper); border-bottom:1px solid var(--hair); }
.bd-total{ color:var(--brand); font-size:.95rem; font-weight:700; font-variant-numeric:tabular-nums; }
.bd-body{ padding:.9rem; }
/* horizontal bars: one row per project (longest on top), a coloured fill sized to its share, and the badge
   (dot · name · hours · %) to its right. Clicking a row opens that project's breakdown just below it. */
.bd-hbars{ display:flex; flex-direction:column; gap:.15rem; }
.bd-hrow{ display:flex; align-items:center; gap:.75rem; width:100%; border:0; background:none; text-align:left; cursor:pointer; padding:.4rem .3rem; border-radius:9px; transition:background .12s; }
.bd-hrow:hover, .bd-hitem.open > .bd-hrow{ background:var(--paper); }
.bd-htrack{ flex:1 1 auto; min-width:3rem; height:.9rem; background:var(--hair); border-radius:999px; overflow:hidden; }
.bd-hfill{ display:block; height:100%; min-width:3px; border-radius:999px; background:var(--c); }
/* the badge is a FIXED-width grid so (a) every track (flex:1) ends up the same width and (b) the name, hours and
   % line up in their own columns across every row — name left (truncates), hours and % right. */
.bd-hbadge{ flex:0 0 24rem; display:grid; grid-template-columns:auto minmax(0,1fr) 5.2rem 2.8rem 1rem; align-items:center; gap:.45rem; font-size:.84rem; color:var(--ink-soft); }
.bd-hbadge .bd-dot{ width:.7rem; height:.7rem; border-radius:999px; background:var(--c); }
.bd-hname{ font-weight:600; color:var(--ink); min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.bd-hhrs{ text-align:right; font-variant-numeric:tabular-nums; color:var(--ink); font-weight:700; }
.bd-hpct{ text-align:right; font-size:.74rem; color:var(--muted); font-variant-numeric:tabular-nums; }
.bd-hchev{ text-align:right; font-size:.7rem; color:var(--muted); }
/* drill-down: the open project's tasks and subtasks, indented, with a left accent in the project's colour */
.bd-panel{ margin-top:.7rem; border-left:3px solid var(--c); border-radius:.1rem; padding:.1rem 0 .1rem .85rem; }
.bd-row{ display:flex; align-items:center; justify-content:space-between; gap:1rem; padding:.32rem .1rem; padding-left:calc(.1rem + var(--d,0) * 1.3rem); }
.bd-row + .bd-row{ border-top:1px solid var(--hair); }
.bd-name{ overflow:hidden; text-overflow:ellipsis; white-space:nowrap; font-size:.86rem; }
.bd-h{ font-variant-numeric:tabular-nums; white-space:nowrap; }
/* Tasks (top of the drill-down) read stronger; their subtasks are lighter, so the two levels are told apart. */
.bd-d0 .bd-name{ color:var(--ink); font-weight:600; }
.bd-d0 .bd-h{ color:var(--ink); font-weight:700; }
.bd-d1 .bd-name{ color:var(--ink-soft); font-weight:400; }
.bd-d1 .bd-h{ color:var(--ink-soft); font-weight:500; }

/* ---- Skeleton: the ONE loading placeholder for the whole site — a shimmering bar. Every module builds a
   block of these to preview the content that is landing (T2Ulayout.skeleton(rows, cols)); no per-page CSS. ---- */
.t2u-skel{ display:block; height:.85rem; border-radius:.4rem; background:linear-gradient(90deg, var(--hair) 25%, color-mix(in srgb, var(--hair) 45%, var(--surface)) 37%, var(--hair) 63%); background-size:400% 100%; animation:t2u-shimmer 1.3s ease-in-out infinite; }
@keyframes t2u-shimmer{ 0%{ background-position:100% 0; } 100%{ background-position:0 0; } }
@media (prefers-reduced-motion:reduce){ .t2u-skel{ animation:none; } }
.t2u-skel-list{ pointer-events:none; }                                   /* a block of skeleton rows: inert while it shimmers */
.t2u-skel-row{ display:flex; align-items:center; gap:.9rem; padding:.6rem .2rem; }
.t2u-skel-row + .t2u-skel-row{ border-top:1px solid color-mix(in srgb, var(--hair) 55%, transparent); }
/* The timesheet day skeleton reuses the primitive on the day's own grid, so each bar sits where its entry will. */
.ts-skel{ pointer-events:none; }
.ts-skel .ts-taskblock .t2u-skel + .t2u-skel{ margin-top:.5rem; }

/* ---------- week grid: a carded ledger, task × day ----------
   The signature is the heatmap: a cell with time carries a teal wash that deepens with the hours logged, so a
   glance shows where the week's effort landed. The Total row and column sit on paper as a distinct summary
   frame — the reading layer, set apart from the white editable interior. Today's column runs a teal accent. */
.ts-wk-wrap{ overflow-x:auto; border:1px solid var(--hair-strong); border-radius:.8rem; background:var(--surface); box-shadow:var(--shadow-sm); }
/* fixed layout: every column states its width, so nothing is squeezed into its neighbour; below the min the
   wrapper scrolls. border-collapse:separate lets the card corners round without clipping the sticky header. */
.ts-wk{ width:100%; min-width:940px; table-layout:fixed; border-collapse:separate; border-spacing:0; margin:0; }
.ts-wk th, .ts-wk td{ vertical-align:middle; padding:.5rem .4rem; }
.ts-wk tbody td{ border-top:1px solid var(--hair); }

/* header band */
.ts-wk thead th{ position:sticky; top:0; z-index:3; background:var(--paper); border-bottom:1px solid var(--hair-strong); }
.ts-wk thead th:first-child{ border-top-left-radius:.8rem; }
.ts-wk thead th:last-child{ border-top-right-radius:.8rem; }
.ts-wk-day{ text-align:center; line-height:1.15; }
.ts-wk-day .d-name{ font-size:.66rem; font-weight:700; letter-spacing:.06em; text-transform:uppercase; color:var(--muted); }
.ts-wk-day .d-date{ font-size:.8rem; font-weight:600; color:var(--ink-soft); }

/* task column */
.ts-wk-task{ width:26%; text-align:left; }
.ts-wk-taskwrap{ display:flex; align-items:center; gap:.5rem; flex-wrap:nowrap; }   /* a div, not the cell: a flex <td> stops being a table cell and the row falls apart */
.ts-wk-name{ flex:1 1 auto; min-width:0; }
.ts-wk-name b{ display:block; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.ts-wk-name .ts-path{ display:block; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; font-size:.75rem; color:var(--muted); }
.ts-wk-del{ flex:0 0 auto; opacity:0; transition:opacity .12s; }   /* stays on the name's line, never under it */
.ts-wk tbody tr:hover .ts-wk-del, .ts-wk-del:focus-visible{ opacity:1; }

/* editable cells — quiet until they hold time or take focus */
.ts-wk-cell{ width:9%; padding:.3rem; }
.ts-cell{ width:100%; padding:.32rem .1rem; font-size:.84rem; text-align:center; font-variant-numeric:tabular-nums;
  border:1px solid transparent; border-radius:.45rem; background:transparent; color:var(--ink); transition:border-color .12s, background .12s, box-shadow .12s; }
.ts-cell::placeholder{ color:transparent; }
.ts-cell:hover{ border-color:var(--hair-strong); background:var(--surface); }
.ts-cell:focus{ border-color:var(--brand); background:var(--surface); box-shadow:0 0 0 3px rgba(46,111,183,.15); outline:none; }
/* the heatmap: filled cells wash teal, deeper with more hours */
.ts-wk-has{ font-weight:600; }
.ts-wk-l1{ background:color-mix(in srgb, var(--teal) 12%, var(--surface)); }
.ts-wk-l2{ background:color-mix(in srgb, var(--teal) 22%, var(--surface)); }
.ts-wk-l3{ background:color-mix(in srgb, var(--teal) 34%, var(--surface)); }
.ts-wk-l4{ background:color-mix(in srgb, var(--teal) 48%, var(--surface)); color:var(--brand-ink); }

/* today's column: a teal accent on the header and a faint wash down the body */
.ts-wk-today{ background:color-mix(in srgb, var(--teal) 7%, transparent); }
.ts-wk thead th.ts-wk-today{ box-shadow:inset 0 3px 0 var(--teal); }
.ts-wk thead th.ts-wk-today .d-name, .ts-wk thead th.ts-wk-today .d-date{ color:var(--teal-deep); }

/* add-task row */
.ts-wk-addrow td{ border-top:1px dashed var(--hair-strong)!important; padding:0; }
.ts-wk-add{ display:flex; align-items:center; justify-content:flex-start; gap:.4rem; width:100%; padding:.55rem .9rem; border:0; background:none; color:var(--teal-deep); font-weight:600; transition:background .12s; }
.ts-wk-add:hover{ background:color-mix(in srgb, var(--teal) 8%, var(--surface)); }

/* summary frame: the total column and the totals row read on paper, set apart from the editable interior */
.ts-wk-total{ width:10%; text-align:center; font-size:.86rem; font-variant-numeric:tabular-nums; white-space:nowrap; font-weight:600; background:var(--paper); color:var(--ink-soft); }
.ts-wk thead th.ts-wk-total{ font-size:.66rem; font-weight:700; letter-spacing:.06em; text-transform:uppercase; color:var(--muted); }
.ts-wk-foot td{ background:var(--paper); border-top:2px solid var(--hair-strong)!important; font-weight:700; color:var(--ink); }
.ts-wk-foot .ts-wk-tasktot{ font-size:.66rem; letter-spacing:.06em; text-transform:uppercase; color:var(--muted); }
.ts-wk-foot .ts-wk-total{ color:var(--ink); }
.ts-wk-grand{ color:var(--brand)!important; font-size:1rem; }
.ts-wk tbody tr:last-child td:first-child{ border-bottom-left-radius:.8rem; }
.ts-wk tbody tr:last-child td:last-child{ border-bottom-right-radius:.8rem; }

/* The picker is the screen where a person spends time hunting for a task: give it room. It grows with the
   viewport instead of a fixed 360px box, so the catalog tree can actually be browsed. */
.ts-pick-dlg{ max-width:min(760px, 95vw); }
.ts-pick-dlg .modal-content{ max-height:88vh; }
.ts-pick-list{ max-height:calc(88vh - 11rem); min-height:22rem; overflow:auto; display:flex; flex-direction:column; }
.ts-pick{ text-align:left; background:none; border:0; padding:.4rem .5rem; border-radius:.35rem; }
.ts-pick:hover{ background:var(--bs-tertiary-bg); }

/* ===================== Catalog (projects.html) ===================== */
.pj-card{ border:1px solid var(--bs-border-color); border-radius:.6rem; margin-bottom:.6rem; overflow:hidden; background:var(--surface); box-shadow:var(--shadow-sm); transition:box-shadow .15s, border-color .15s; }
.pj-card:hover{ border-color:var(--hair-strong); box-shadow:var(--shadow); }
.pj-card.pj-off{ opacity:.6; }
.pj-head{ display:flex; align-items:center; gap:.6rem; padding:.6rem .8rem; }
/* the caret reads as a button: a soft hover, and it turns brand blue */
.pj-toggle{ border:0; background:none; color:var(--muted); border-radius:.35rem; padding:.1rem .3rem; transition:background .12s, color .12s; }
.pj-toggle:hover{ background:var(--bs-tertiary-bg); color:var(--brand); }
/* Small consumption pie just left of a row's action group: the share of the estimate consumed
   (green/amber/red, filled from 12 o'clock), with the exact "logged / estimated h · %" on hover. */
.pj-right{ display:flex; align-items:center; gap:.5rem; margin-left:auto; flex:0 0 auto; }
.pj-pie{ flex:0 0 auto; width:20px; height:20px; border-radius:50%;
  background:conic-gradient(var(--c) calc(var(--pct,0) * 1%), var(--hair) 0); }
.pj-pie.ok{ --c:var(--ok); }
.pj-pie.warn{ --c:var(--warning); }
.pj-pie.over{ --c:var(--danger); }
.pj-logged-ref{ background:var(--paper); color:var(--ink-soft); max-width:6rem; }
/* Drag handle beside a task's name: grab it to reorder among siblings. The hovered row shows a brand line on the
   edge the drop will land, and the dragged row dims. */
.pj-grip{ display:inline-flex; align-items:center; cursor:grab; color:var(--muted); opacity:.45; flex:0 0 auto; touch-action:none; user-select:none; -webkit-user-select:none; }
.pj-grip:hover{ opacity:1; color:var(--brand); }
.pj-grip:active{ cursor:grabbing; }
.pj-node.pj-dragging{ opacity:.45; }
.pj-node.pj-drop-before{ box-shadow:inset 0 2px 0 var(--brand); }
.pj-node.pj-drop-after{ box-shadow:inset 0 -2px 0 var(--brand); }
/* The worksheet the Estimate button opens (mode toggle, per-task inputs, totals). */
.pj-est-head{ margin-bottom:.75rem; }
.pj-est-projrow{ display:flex; align-items:center; gap:.5rem; margin-bottom:.75rem; }
.pj-est-projrow input{ max-width:8rem; }
.pj-est-table td, .pj-est-table th{ padding:.35rem .5rem; vertical-align:middle; }
.pj-est-table .pj-est-parent{ font-weight:600; }
.pj-est-cell input{ max-width:7rem; margin-left:auto; text-align:right; }
.pj-est-foot{ margin-top:.75rem; text-align:right; font-variant-numeric:tabular-nums; }
/* Name, badges, add and actions are flat siblings of the head, so on a phone the badges can drop to their own
   line while the name keeps the first line to itself. The action bar is pushed to the far right. */
.pj-nm{ flex:0 1 auto; min-width:0; }
.pj-badges{ display:inline-flex; align-items:center; flex-wrap:wrap; gap:.25rem; }
.pj-badges .t2u-badge-count{ margin-left:0; }   /* spacing comes from the container gap, not a per-badge margin */
.pj-actions{ flex:0 0 auto; margin-left:auto; }
/* Row action groups (catalog, clients, users) read as one control: every button shares the neutral border and
   surface. Delete keeps a red ICON at rest and only fills red on hover, when the destructive action is a click
   away — a permanent red border next to the others looked alarmed for no reason. */
/* :where() keeps the resting rule at one-class weight so the semantic :hover below always wins, whatever
   container a page wraps its action group in (.pj-actions in the tree, td .btn-group in the tables). */
:where(.pj-actions, td .btn-group) > .btn{ border-color:var(--hair-strong); background:var(--surface); color:var(--ink-soft); }
:where(.pj-actions, td .btn-group) > .btn-outline-danger{ color:var(--danger); }   /* red icon at rest */
/* At rest each icon already wears its semantic colour, so the group reads without hovering: edit/reorder/estimate
   brand blue, archive/deactivate amber, (re)activate green (delete is already red above). The hover fills the button. */
.pj-edit, .cl-edit, .usr-edit, .pj-up, .pj-down, .pj-est-btn{ color:var(--brand); }
.pj-arch, .cl-arch, .usr-deact{ color:var(--warning); }
.usr-act{ color:var(--ok); }
/* Hover says what each button DOES, by colour: edit is a safe change (brand blue), archive/deactivate is a
   pause (amber), delete is destructive (red), (re)activate is a restore (green). */
.pj-edit:hover, .cl-edit:hover, .usr-edit:hover, .pj-up:hover, .pj-down:hover,
.pj-edit:focus-visible, .cl-edit:focus-visible, .usr-edit:focus-visible, .pj-up:focus-visible, .pj-down:focus-visible{ background:var(--brand); border-color:var(--brand); color:#fff; }
.pj-arch:hover, .cl-arch:hover, .usr-deact:hover,
.pj-arch:focus-visible, .cl-arch:focus-visible, .usr-deact:focus-visible{ background:var(--warning); border-color:var(--warning); color:#fff; }
.pj-del:hover, .cl-del:hover, .usr-del:hover,
.pj-del:focus-visible, .cl-del:focus-visible, .usr-del:focus-visible{ background:var(--danger); border-color:var(--danger); color:#fff; }
.usr-act:hover, .usr-act:focus-visible{ background:var(--ok); border-color:var(--ok); color:#fff; }
.pj-children{ border-top:1px solid var(--bs-border-color); padding:.4rem .8rem .6rem; }
.pj-node{ display:flex; align-items:center; gap:.6rem; padding:.35rem 0 .35rem calc(var(--lvl,1) * 1.2rem); border-bottom:1px dashed var(--bs-border-color); }
.pj-node:last-of-type{ border-bottom:0; }
.pj-members{ display:grid; grid-template-columns:repeat(auto-fill,minmax(180px,1fr)); gap:.1rem .6rem; margin-bottom:.6rem; }

/* task picker: favourites, suggested, and the catalog tree (leaves only are pickable) */
.ts-chips{ display:flex; flex-wrap:wrap; gap:.4rem; margin-bottom:.75rem; }
.ts-chip{ display:inline-flex; align-items:center; gap:.15rem; border:1px solid var(--bs-border-color); border-radius:999px; padding:.1rem .3rem .1rem .6rem; transition:background .12s, border-color .12s; }
.ts-chip:hover{ background:var(--bs-tertiary-bg); border-color:var(--hair-strong); }   /* a favourite is clickable: say so */
.ts-chip-pick{ border:0; background:none; color:inherit; font-size:.86rem; }
.ts-pick-h{ font-size:.7rem; font-weight:700; letter-spacing:.08em; text-transform:uppercase; color:var(--muted); margin:.6rem 0 .3rem; }
.ts-pick-row{ display:flex; align-items:center; gap:.25rem; }
/* The pick sizes to its content so the favourite star sits right next to the task, not out at the row's edge. */
.ts-pick{ flex:0 1 auto; text-align:left; background:none; border:0; padding:.35rem .5rem; border-radius:.35rem; color:inherit; }
.ts-pick:hover{ background:var(--bs-tertiary-bg); }
.ts-pick .ts-path{ margin-left:.5rem; display:inline; }
.ts-pick-inline{ flex:0 1 auto; }
.ts-star{ border:0; background:none; color:var(--muted); padding:.15rem .35rem; }
.ts-star.on{ color:var(--brand); }
.ts-node{ padding-left:calc(var(--d,0) * .9rem); }
.ts-node-h{ display:flex; align-items:center; gap:.15rem; }
.ts-node-name{ padding:.35rem .5rem; font-weight:600; }
.ts-caret{ border:0; background:none; color:var(--muted); padding:.15rem .3rem; }
.ts-caret-sp{ display:inline-block; width:1.4rem; }
/* Hovering the breadcrumb hints it's editable by turning the leaf the timer's teal — handled on .ts-crumb-btn. */

/* Day view: rows and the totals footer share one grid, so the day's span and its total line up with the
   times and durations above them. */
.ts-row{ display:grid; grid-template-columns:minmax(200px,1fr) minmax(160px,380px) 130px 6rem 2.4rem 2.4rem; align-items:center; column-gap:.75rem; }
.ts-times{ text-align:center; }

/* the user picker is a real menu, not a see-through overlay */
.ts-usermenu{ background:var(--surface); border:1px solid var(--hair); box-shadow:var(--shadow); }
html[data-theme="dark"] .ts-usermenu{ background:var(--surface); }
.ts-usermenu .dropdown-item{ border-radius:.35rem; }
/* A row that has just arrived — the timer stopped, time added by hand, a row duplicated — slides into place
   and then says which one it is: the list is sorted by time, so an entry lands wherever its hours put it, not
   necessarily where the eye was looking. It wears the timer's blue for a moment and lets it go. */
/* Arriving is ONE motion: the row drops in from above while lit teal, and the teal decays smoothly as it settles
   — no separate second flash. Both tracks start together (no delay) so it reads as a single curtain drop. */
.ts-new{ animation:ts-arrive .4s ease both, ts-fade 1.4s ease-out both; }
@keyframes ts-arrive{ from{ opacity:0; transform:translateY(-16px); } to{ opacity:1; transform:none; } }
@keyframes ts-fade{
  from { background:color-mix(in srgb, var(--teal) 13%, transparent); box-shadow:inset 3px 0 0 var(--teal); }
  to   { background:transparent; box-shadow:inset 3px 0 0 transparent; }
}
@media (prefers-reduced-motion:reduce){ .ts-new{ animation:none; } }


/* Day rows gained an editable billable flag and editable clock times, so the grid has one more column. */
.ts-row-pick{ border:0; background:none; text-align:left; color:inherit; padding:0; }
.ts-row-pick:hover b, .ts-row-pick:hover .ts-path{ color:var(--brand); }   /* the whole path answers to the hover, not just the task */
.ts-bill{ border:0; background:none; color:var(--muted); opacity:.45; padding:.1rem; }
.ts-bill.on{ color:var(--teal); opacity:1; -webkit-text-stroke:.6px var(--teal); }   /* billable: the timer's light blue, drawn bolder so the $ reads as active */
.ts-times{ display:flex; align-items:center; gap:.3rem; justify-content:center; }
.ts-times input[type="time"]{ width:6.5rem; text-align:center; font-variant-numeric:tabular-nums; }
.ts-dash{ opacity:.6; }
/* An entry that shares minutes with another (e.g. a fresh duplicate) is flagged amber until its times are fixed. */
.ts-overlap{ background:color-mix(in srgb, var(--warning) 7%, transparent); box-shadow:inset 3px 0 0 var(--warning); }
.ts-ov-flag{ color:var(--warning); font-size:.9rem; }
/* A draft entry (adding / duplicating) reads as "being edited", in the timer's teal, until it is saved. */
.ts-draft{ background:color-mix(in srgb, var(--teal) 9%, transparent); box-shadow:inset 3px 0 0 var(--teal); }
/* A brief amber pulse on the entries a rejected timer-start would have clashed with, so the eye finds them. */
.ts-clash-flash{ animation:ts-clash 2.4s ease-out both; }
@keyframes ts-clash{ 0%,55%{ background:color-mix(in srgb, var(--warning) 24%, transparent); box-shadow:inset 3px 0 0 var(--warning); } 100%{ background:transparent; box-shadow:inset 3px 0 0 transparent; } }
@media (prefers-reduced-motion:reduce){ .ts-clash-flash{ animation:none; } }
/* Overlap dialog: the entry being added and each clash, as a compact table (task + hours). */
.ts-clash-h{ font-size:.68rem; font-weight:700; letter-spacing:.05em; text-transform:uppercase; color:var(--muted); margin:.6rem 0 .3rem; }
.ts-clash-h:first-child{ margin-top:0; }
.ts-clash-tbl{ width:100%; border-collapse:collapse; }
.ts-clash-tbl td{ padding:.34rem .6rem; border-top:1px solid var(--hair); vertical-align:top; font-size:.9rem; }
.ts-clash-tbl tr:first-child td{ border-top:0; }
.ts-clash-tbl .ts-clash-task{ width:100%; }   /* the breadcrumb inside bolds only the leaf; ancestors stay muted */
.ts-clash-tbl .ts-clash-task .ts-crumb{ font-size:.9rem; }
.ts-clash-tbl .ts-clash-hrs{ text-align:right; white-space:nowrap; font-variant-numeric:tabular-nums; color:var(--ink-soft); }
/* The entry being added: one soft-blue strip over the whole row (not per cell), rounded. */
.ts-clash-new{ background:color-mix(in srgb, var(--brand) 8%, transparent); border-radius:8px; overflow:hidden; }
.ts-clash-new td{ border-top:0; }
/* "en curso" sits under the times, right-aligned, pulsing softly. */
.ts-clash-timer{ display:block; width:fit-content; margin:.25rem 0 0 auto; font-size:.6rem; font-weight:700; text-transform:uppercase; letter-spacing:.04em; color:#fff; background:var(--teal); border-radius:999px; padding:.08rem .45rem; animation:ts-blink 1.6s ease-in-out infinite; }
@keyframes ts-blink{ 0%,100%{ opacity:1; } 50%{ opacity:.4; } }
@media (prefers-reduced-motion:reduce){ .ts-clash-timer{ animation:none; } }

/* idle timer bar: what you are working on, a note, and START TIMER on the right (the action of the bar) */
.ts-timer-off{ gap:1rem; }
/* No task picked yet: the prompt reads as the link it is — clicking it opens the picker. */
.ts-ph{ color:var(--teal); font-weight:600; font-size:1.06rem; }
.ts-crumb-empty:hover .ts-ph, .ts-crumb-empty:focus-visible .ts-ph{ color:var(--teal-deep); text-decoration:underline; }
/* Starting the clock — and resuming a task, which is the same act from a row — wear the wordmark's light blue:
   the invitation to track time is its own colour, distinct from the app's ordinary primary actions.
   Hovering deepens that same blue; it never jumps to another one. */
.ts-startbtn, .ts-resume, .ts-draft-save{ background:var(--teal); border-color:var(--teal); }
.ts-startbtn:hover, .ts-resume:hover, .ts-draft-save:hover, .ts-startbtn:focus-visible, .ts-resume:focus-visible, .ts-draft-save:focus-visible,
.ts-startbtn:active, .ts-resume:active, .ts-draft-save:active{ background:var(--teal-deep); border-color:var(--teal-deep); }
/* the only oversized button in the app: starting the clock is what this page is for */
.ts-startbtn{ margin-left:auto; flex:0 0 auto; white-space:nowrap; font-weight:700; letter-spacing:.01em; font-size:1rem; border-radius:.6rem; align-self:stretch; }
.ts-timer-on .btn-danger{ flex:0 0 auto; white-space:nowrap; font-weight:700; font-size:1rem; border-radius:.6rem; align-self:stretch; }
/* Start/stop are icon-only (the label lives in the tooltip) and take the same width as the header's add-manual
   button (5.6rem — the actions column), so the two twins of the day line up. Scoped to outweigh their base rules. */
.ts-startbtn.ts-iconbtn, .ts-timer-on .btn-danger.ts-iconbtn{ padding:.55rem; width:5.6rem; display:inline-flex; align-items:center; justify-content:center; }
.ts-startbtn .bi, .ts-timer-on .btn-danger .bi{ font-size:1.9em; vertical-align:-.12em; }

/* Day | Week reads like the EN | ES and theme toggles in the masthead */
.view-toggle .icon-btn{ display:inline-flex; align-items:center; justify-content:center; padding:.3rem .75rem; font-size:.82rem; line-height:1; font-weight:600; }
.view-toggle .icon-btn.active{ background:var(--brand); color:#fff; border-color:var(--brand); }
.view-toggle .icon-btn.active:hover{ background:var(--brand-deep); color:#fff; }

/* ===================== Toasts ===================== */
/* A result or an error is information, not a decision: it is shown without stopping the person's work. */
.t2u-toasts{ position:fixed; right:1rem; bottom:1rem; z-index:1090; display:flex; flex-direction:column; gap:.5rem; max-width:min(420px,90vw); }
.t2u-toast{ display:flex; align-items:flex-start; gap:.6rem; padding:.7rem .85rem; border-radius:.6rem; background:var(--surface); border:1px solid var(--hair); box-shadow:var(--shadow); font-size:.9rem; animation:t2uToastIn .18s ease-out; }
.t2u-toast.out{ opacity:0; transform:translateY(6px); transition:opacity .2s, transform .2s; }
.t2u-toast i{ margin-top:.1rem; }
.t2u-toast span{ flex:1 1 auto; min-width:0; overflow-wrap:anywhere; }
.t2u-toast-x{ border:0; background:none; color:var(--muted); line-height:1; font-size:1.15rem; padding:0 .1rem; }
.t2u-toast-error{ border-left:4px solid var(--danger); }
.t2u-toast-error i{ color:var(--danger); }
.t2u-toast-success{ border-left:4px solid var(--ok); }
.t2u-toast-success i{ color:var(--ok); }
.t2u-toast-info{ border-left:4px solid var(--brand); }
.t2u-toast-info i{ color:var(--brand); }
@keyframes t2uToastIn{ from{ opacity:0; transform:translateY(8px); } to{ opacity:1; transform:none; } }

/* One more action per row (duplicate), and the clock fields are plain HH:MM text boxes — no locale spinner. */
/* task block (breadcrumb over note) | times | duration | the one action group — the header rides the same
   grid, so the day's span lines up under the times and its total under the durations. */
/* Every row is its own grid, so EVERY column must be fixed or shared — an `auto` last column let the header
   (one button) and the rows (two) size it differently, and the whole line drifted. */
.ts-row, .ts-group-h{ display:grid; grid-template-columns:minmax(240px,1fr) 13.5rem 6rem 5.6rem; column-gap:.75rem; align-items:center; }
.ts-row{ padding:.6rem .9rem; }

/* The task block: the breadcrumb on top, the note (with its billable flag) below it. Shared by the day rows
   and the timer card, so both read the same way. */
.ts-taskblock{ display:flex; flex-direction:column; gap:.4rem; min-width:0; }
/* The breadcrumb is inset to the same left edge as the note's text below it, so the block reads as one column. */
.ts-crumb-btn{ border:0; background:none; text-align:left; padding:.1rem .5rem; color:inherit; min-width:0; max-width:100%; cursor:pointer; }
.ts-crumb{ display:flex; align-items:baseline; min-width:0; font-size:1rem; line-height:1.2; }
.ts-crumb-lead{ flex:0 1 auto; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; color:var(--muted); font-weight:400; }
.ts-crumb-sep{ flex:0 0 auto; margin:0 .35rem; color:var(--muted); font-weight:400; }
.ts-crumb-leaf{ flex:0 0 auto; white-space:nowrap; color:var(--ink); font-weight:700; }
.ts-crumb-btn:hover .ts-crumb-leaf, .ts-crumb-btn:focus-visible .ts-crumb-leaf{ color:var(--teal-deep); }
/* The action group and the header's add button fill the same column, so they are the same size and line up. */
.ts-actions, .ts-addbtn{ width:100%; }
.ts-addbtn{ background:var(--teal); border-color:var(--teal); }
.ts-addbtn:hover, .ts-addbtn:focus-visible{ background:var(--teal-deep); border-color:var(--teal-deep); }
.ts-actions .btn{ flex:1 1 0; }
/* The overflow menu is the last BUTTON, but the dropdown panel is the last child — Bootstrap rounds by child
   and squares off anything that is not the last one. Say it here, and loudly: Bootstrap's own selector carries
   more weight than ours. */
.ts-actions .ts-more{
  border-top-right-radius:var(--bs-border-radius) !important;
  border-bottom-right-radius:var(--bs-border-radius) !important;
}
/* One control, two buttons, everywhere: resume — the thing you do to a row — and the menu that holds the rest.
   The same shape on a phone and on a desktop, so there is one layout to reason about and one to look at. */
.ts-dup, .ts-del{ display:none; }        /* the real buttons; the menu presses them */
.dropdown-menu{ z-index:1080; }   /* rendered against <body> (data-bs-container), above the page */
.ts-actions .btn{ border-color:var(--hair-strong); }
.ts-actions .ts-resume, .ts-actions .ts-draft-save{ border-color:var(--teal); }   /* Save reads like Resume: blue fill, teal border */
.ts-draft-cancel{ --bs-btn-bg:var(--surface); }   /* Cancel: white at rest; outline-danger keeps the red border and red hover */
/* The kebab is the group's neutral action, so it stays in the family instead of Bootstrap's grey fill: a faint
   tint on hover, with the border and icon in the timer's blue. */
.ts-actions .ts-more{ color:var(--muted); }
.ts-actions .ts-more:hover, .ts-actions .ts-more:focus-visible, .ts-actions .ts-more.show{
  background:color-mix(in srgb, var(--teal) 14%, var(--surface)); border-color:var(--teal); color:var(--teal-deep);
}

/* Saving a new entry: the row shows up the moment you ask for it, and holds a spinner until the entry exists.
   Deleting: the row goes red and slides out, so the removal is seen happening, not just gone. */
/* The optimistic placeholder appears at once (no slide): only the real row that replaces it on reload animates,
   so adding by hand or copying never plays the arrival twice. */
.ts-ghost{ display:flex; align-items:center; gap:.6rem; padding:.75rem .9rem; color:var(--muted);
  border-bottom:1px solid var(--bs-border-color);
  box-shadow:inset 3px 0 0 var(--teal); background:color-mix(in srgb, var(--teal) 8%, transparent); }
/* Leaving is the curtain going UP: the row fades and collapses its own height to zero, so the rows below rise
   smoothly to close the gap. */
.ts-removing{ animation:ts-vanish .42s ease both; pointer-events:none; overflow:hidden; }
@keyframes ts-vanish{
  0%   { opacity:1; max-height:6rem; box-shadow:inset 3px 0 0 var(--danger); background:color-mix(in srgb, var(--danger) 8%, transparent); }
  35%  { opacity:.5; max-height:6rem; box-shadow:inset 3px 0 0 var(--danger); background:color-mix(in srgb, var(--danger) 8%, transparent); }
  100% { opacity:0; max-height:0; padding-top:0; padding-bottom:0; transform:translateY(-6px); box-shadow:inset 3px 0 0 transparent; background:transparent; }
}
@media (prefers-reduced-motion:reduce){ .ts-ghost, .ts-removing{ animation:none; } }
.ts-times input{ width:4.6rem; text-align:center; font-variant-numeric:tabular-nums; letter-spacing:.02em; }
/* Like the note, the clock fields read as plain text until touched: no frame at rest, the box appears on hover/focus. */
.ts-start, .ts-end{ border-color:transparent; background:transparent; transition:border-color .12s, background .12s; }
.ts-start:hover, .ts-end:hover{ border-color:var(--hair-strong); background:var(--surface); }
.ts-times input:focus{ border-color:var(--brand); }

/* work that spans midnight: an arrow to the other half, on the side the other day is on */
.ts-goday{ border:0; background:none; color:var(--brand); line-height:1; padding:0 .1rem; font-size:1.1rem; }
.ts-goday:hover{ color:var(--brand-deep); }

/* Row actions (timesheet AND catalog) sit on the row's own background, so they get the surface — but only at
   rest: on hover Bootstrap fills them and turns the icon white, and a white fill would swallow it. */
.ts-row .ts-dup:not(:hover):not(:focus),
.ts-row .ts-del:not(:hover):not(:focus),


/* Users: the filter row sits on the header, right over the columns it filters. */

.usr-acts{ white-space:nowrap; }

/* Catalog: a project reads as a row with badges; its tasks are indented, in the order the PM set. */
/* One badge everywhere the catalog and the report tree count something: a hairline pill, the icon muted,
   the number in ink. Consistent whether it says tasks, members, a client or a budget. */
.t2u-badge-count{ display:inline-flex; align-items:center; gap:.3rem; font-size:.72rem; font-weight:600; color:var(--ink-soft);
  border:1px solid var(--hair-strong); border-radius:999px; padding:.08rem .5rem; margin-left:.35rem; white-space:nowrap; }
.t2u-badge-count > i{ color:var(--muted); font-weight:400; }
.t2u-badge-count:empty{ display:none; }   /* a count pill with nothing in it yet (e.g. before the report list loads) shows nothing */
/* Report header icons (copy · visibility lock · project count) — all at the copy icon's size, no pill chrome. */
.tok-ico{ display:inline-flex; align-items:center; gap:.25rem; font-size:.82rem; line-height:1; font-weight:500; color:var(--muted); vertical-align:middle; }
.tok-projs{ font-variant-numeric:tabular-nums; color:var(--ink-soft); }
.tok-projs > i{ color:var(--muted); }
/* The report name shares its line with the copy/projects/visibility icons: it truncates, the icons stay whole. */
.tok-head-row{ flex-wrap:nowrap; min-width:0; }
.tok-name{ min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.tok-head-row .tok-lbl-copy, .tok-head-row .tok-ico{ flex:0 0 auto; }
.vis-private, .vis-private > i{ color:var(--danger); }   /* closed lock = private */
.vis-public, .vis-public > i{ color:var(--ok); }         /* open lock = public */
.pj-node{ display:flex; align-items:center; gap:.5rem; padding:.35rem 0 .35rem calc(var(--lvl,1) * 1.4rem); border-bottom:1px dashed var(--hair); }
.pj-children .pj-toggle-sp{ display:inline-block; width:1.6rem; }   /* a leaf keeps the caret's space, so names line up */
/* Rename in place: the name reads as plain text until touched, then shows an editable box like the note field. */
.pj-nm-edit, .cl-nm-edit{ border:1px solid transparent; border-radius:.35rem; padding:.05rem .35rem; margin:0 -.15rem; outline:none; cursor:text; transition:border-color .12s, background .12s, box-shadow .12s; }
.pj-nm-edit:hover, .cl-nm-edit:hover{ border-color:var(--hair-strong); background:var(--surface); }
.pj-nm-edit:focus, .cl-nm-edit:focus{ border-color:var(--brand); background:var(--surface); box-shadow:0 0 0 3px rgba(46,111,183,.15); cursor:text; }
.cl-nm-edit{ font-weight:700; display:inline-block; }
.pj-add{ border:0; background:none; color:var(--brand); font-size:.78rem; font-weight:600; padding:.05rem .4rem; margin-left:.35rem; border-radius:.35rem; }
.pj-add i{ margin-right:.2rem; }
.pj-add:hover{ background:var(--bs-tertiary-bg); color:var(--brand-deep); }

/* ===================== Home: the applications a person reaches ===================== */
/* The landing hero: the wordmark (Time light-blue, 2U blue, like the masthead) leads, then the sign-in — the
   primary way most people arrive — with opening a report by token as a quieter, framed option below. */
.home-hero{ padding:2.75rem 0 .5rem; }
.home-wm{ font-family:var(--font-display); font-weight:700; font-size:3rem; letter-spacing:-.01em; margin:0 0 .35rem; line-height:1; }
.home-tagline{ color:var(--muted); font-size:1rem; }
.home-signin{ font-weight:600; padding:.6rem 1.7rem; }
.home-or{ display:flex; align-items:center; gap:1rem; max-width:600px; margin:2.75rem auto 1.25rem; color:var(--muted); font-size:.72rem; font-weight:700; text-transform:uppercase; letter-spacing:.1em; }
.home-or::before, .home-or::after{ content:""; flex:1 1 auto; height:1px; background:var(--hair); }
.home-report{ max-width:600px; border:1px solid var(--hair-strong); border-radius:.7rem; background:var(--surface); box-shadow:var(--shadow-sm); padding:1rem 1.1rem; }
.home-report-h{ display:flex; align-items:center; font-size:.72rem; font-weight:700; letter-spacing:.05em; text-transform:uppercase; color:var(--muted); margin-bottom:.6rem; }
.home-report-h > i{ color:var(--brand); }
.home-grid{ display:grid; grid-template-columns:repeat(auto-fit,minmax(190px,220px)); gap:1rem; justify-content:center; }
.home-card{ display:flex; flex-direction:column; align-items:center; justify-content:center; gap:.5rem; aspect-ratio:1; padding:1.25rem;
  border:1px solid var(--hair); border-radius:var(--radius); background:var(--surface); box-shadow:var(--shadow-sm);
  color:var(--ink); text-decoration:none; text-align:center; transition:transform .12s, box-shadow .12s, border-color .12s; }
.home-card:hover{ transform:translateY(-2px); box-shadow:var(--shadow); border-color:var(--brand); color:var(--brand-deep); }
.home-card > i{ font-size:2.2rem; color:var(--brand); }
.home-card-n{ font-weight:700; font-size:1.02rem; }
.home-card-m{ font-size:.74rem; color:var(--muted); line-height:1.3; }

/* ===================== Apps menu + module grants ===================== */
/* --bs-body-bg is transparent (the page paints its own gradient), and Bootstrap's dropdown inherits it — an
   opaque surface has to be named here or the menu shows the page through it. */
.dropdown-menu{ background-color:var(--surface); }
.mod-list{ display:flex; flex-wrap:wrap; gap:.25rem; align-items:center; }
.mod-badge{ font-size:.7rem; border:1px solid var(--brand); border-radius:999px; padding:.05rem .45rem; color:var(--brand); }
.mod-granted{ background:var(--brand); color:#fff; font-weight:600; }   /* handed out one by one, not by the role */

/* ===================== Phones =====================
   Every module has to read on a phone, so the wide things either wrap or scroll on their own — the page body
   never scrolls sideways. Tables that cannot shrink (users, the report panes) keep their shape and scroll. */
@media (max-width:820px){
  /* Toolbars (users, catalog…): the search takes the whole first row, the selects pair up two-per-row, and the
     add button spans the width — no half-empty row with a lone right-aligned action. */
  .t2u-toolbar{ gap:.45rem; }
  .t2u-toolbar .t2u-tb-search{ flex:1 1 100%; }
  .t2u-toolbar .t2u-tb-sel, .t2u-toolbar select, .t2u-toolbar .t2u-datewrap{ flex:1 1 calc(50% - .45rem); min-width:0; width:auto; }
  .t2u-toolbar .t2u-datewrap{ display:flex; }
  .t2u-toolbar .t2u-datewrap > input[type=date]{ width:100%; }
  .t2u-toolbar .t2u-tb-add{ margin-left:0; flex:1 1 100%; justify-content:center; }
  /* Card tables (.t2u-cards): on a phone each row becomes a stacked card — the header row is dropped and every
     cell shows its column LABEL (from data-label) beside its value, so a wide list reads top-down instead of
     scrolling sideways. The first cell is the title (no label); the actions cell (.text-end) sits at the foot,
     right-aligned. Shared by the users and clients lists (and any future record table that opts in). */
  #users{ overflow-x:visible; }
  .t2u-cards{ min-width:0; border:0; box-shadow:none; background:transparent; }
  .t2u-cards > thead{ display:none; }
  .t2u-cards, .t2u-cards > tbody, .t2u-cards > tbody > tr, .t2u-cards > tbody > tr > td{ display:block; width:100%; }
  .t2u-cards > tbody > tr{ border:1px solid var(--hair); border-radius:12px; background:var(--surface); margin-bottom:.6rem; padding:.55rem .8rem; box-shadow:var(--shadow-sm); }
  .t2u-cards > tbody > tr > td{ border:0!important; border-radius:0!important; padding:.32rem 0; display:flex; align-items:center; gap:.6rem; }
  .t2u-cards > tbody > tr > td[data-label]::before{ content:attr(data-label); flex:0 0 5rem; font-size:.66rem; font-weight:700; letter-spacing:.05em; text-transform:uppercase; color:var(--muted); }
  .t2u-cards > tbody > tr > td:first-child{ display:block; padding:.1rem 0 .45rem; margin-bottom:.35rem; border-bottom:1px solid var(--hair)!important; }
  .t2u-cards > tbody > tr > td.text-end{ justify-content:flex-end; padding-top:.5rem; }
  .t2u-cards .usr-role{ flex:1 1 auto; max-width:12rem; }
  .t2u-cards .mod-list{ flex:1 1 auto; }
  /* Report access: a token's name, its links and its dates stack instead of fighting for one row */
  .tok-grid{ grid-template-columns:1fr; }
  .tok-grid .text-end{ text-align:left!important; }
  [data-width="wide"] #saved{ display:block; }   /* the wide multi-column grid (min 560px cols) would overflow a phone */
  /* Catalog card reads over three lines: name (beside the caret), then badges, then add (left) + actions (right). */
  .pj-head, .pj-node{ flex-wrap:wrap; align-items:center; gap:.35rem .5rem; }
  .pj-nm{ flex:1 1 auto; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }   /* the name stays on the first line beside the caret, truncating if long */
  .pj-nm-edit:focus{ overflow:visible; white-space:normal; }   /* but shows in full while it is being edited */
  .pj-badges{ flex:1 1 100%; }              /* the badges drop to their own line below */
  .pj-add{ flex:0 0 auto; margin-left:0; }  /* next line, left */
  .pj-actions{ margin-left:auto; }          /* line 3, right */
  /* Security: a line's state badge sits under its label when the two do not fit */
  .sec-item{ flex-wrap:wrap; }
  .sec-rot-table{ display:block; overflow-x:auto; }
  /* Report: the month/task/user panes keep their columns and scroll inside their card */
  .pane-wrap{ overflow-x:auto; }
  /* Infrastructure: one resource per row */
  .rg-body{ grid-template-columns:1fr; }
  /* Interfaces: the alias-route table scrolls rather than crushing its columns */
  #supRoutesWrap{ overflow-x:auto; }
  /* Support: the mailbox header drops its Sync/delete actions to a second full-width line so they never overlap
     the address; the tickets table sheds its secondary columns (contact, priority, severity) — the essentials
     stay, and still scroll if needed. (The filters ride on the shared .t2u-toolbar rules above.) */
  .sup-group > summary{ flex-wrap:wrap; }
  .sup-g-head{ flex:1 1 100%; min-width:0; }
  .sup-g-mb{ min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  .sup-g-al{ flex:0 0 auto; }
  .sup-g-actions{ margin-left:0; flex:1 1 100%; }
  .sup-g-actions .btn{ flex:1 1 auto; }
  .sup-table th:nth-child(3), .sup-table td:nth-child(3),
  .sup-table th:nth-child(4), .sup-table td:nth-child(4),
  .sup-table th:nth-child(5), .sup-table td:nth-child(5){ display:none; }
  .sup-title{ max-width:46vw; }
}

/* ---------- the report on a phone ----------
   The report is read by clients, often on a phone: the two figures sit centred under the title, and every
   control spans the width it has instead of huddling on the left. */
@media (max-width:700px){
  .stat-cards{ justify-content:center; width:100%; }
  .stat-cards .stat-card{ flex:1 1 0; min-width:0; }
  .mh-head{ flex-direction:column; align-items:stretch; }

  /* period: the picker and the ‹ month › stepper each take the full row */
  #projWrap, #proj, #period{ width:100%!important; }
  #nav{ display:flex; width:100%; }
  #rangeLabel{ flex:1 1 auto; width:auto!important; min-width:0!important; }
  #prev, #next{ flex:0 0 44px; }
  #customRange{ flex-wrap:wrap; }
  #customRange > div{ flex:1 1 45%; }

  /* which report: the three choices share the row evenly */
  .report-toolbar{ align-items:stretch; }
  .view-seg{ display:flex; width:100%; }
  .view-seg .btn{ flex:1 1 0; padding:.5rem .35rem; }
  #exportPdf{ width:100%; }
}

/* ===================== Working =====================
   While the app is waiting on the API, a bar runs under the masthead and the content dims: a click that seems
   to have done nothing is visibly doing something. Set on <html> by layout.js (T2Ulayout.busy). */
html.t2u-busy::after{
  content:""; position:fixed; left:0; right:0; top:0; height:3px; z-index:2000;
  background:linear-gradient(90deg, transparent, var(--teal), var(--brand), transparent);
  background-size:40% 100%; background-repeat:no-repeat;
  animation:t2u-progress 1.1s ease-in-out infinite;
}
@keyframes t2u-progress{ 0%{ background-position:-40% 0; } 100%{ background-position:140% 0; } }
html.t2u-busy .t2u-content{ opacity:.55; transition:opacity .12s; }
@media (prefers-reduced-motion:reduce){ html.t2u-busy::after{ animation:none; background:var(--teal); } }

/* The phone rules come LAST: they undo the desktop grid above, and a later rule of equal weight wins. */
@media (max-width:820px){
  /* A row reads top-down: the task block (breadcrumb + note) on its own; then billable, times, duration and the
     actions all on ONE line below, compact so they fit together. */
  .ts-row{ display:flex; flex-wrap:wrap; column-gap:.4rem; row-gap:.6rem; align-items:center; }
  /* Header: two rows — [Project/task | +] on top, [start-end | duration] below. */
  .ts-group-h{ display:grid; grid-template-columns:1fr auto; grid-template-areas:"title add" "span total"; align-items:center; gap:.3rem .6rem; }
  .ts-col-task{ grid-area:title; }
  .ts-addbtn{ grid-area:add; flex:0 0 auto; width:5.6rem; }
  .ts-daysum-span{ grid-area:span; text-align:left; }
  .ts-daysum-total{ grid-area:total; text-align:right; min-width:auto; }
  .ts-taskblock{ flex:1 1 100%; }
  /* The entry row reads over three lines: the breadcrumb, then billable + times + duration + actions, then the
     note LAST. The task block is unwrapped (display:contents) so its breadcrumb and note become row items and
     can sit on either side of the times/actions line between them. */
  .ts-row .ts-taskblock{ display:contents; }
  .ts-row .ts-row-pick{ order:1; flex:1 1 100%; }
  .ts-row .ts-times{ order:2; flex:0 0 auto; text-align:left; }
  .ts-row .ts-start, .ts-row .ts-end{ width:4rem; }
  .ts-row .ts-dur{ order:2; flex:0 0 auto; min-width:auto; margin-left:0; }
  .ts-actions{ order:2; flex:0 0 auto; width:auto; margin-left:auto; }
  .ts-actions .btn{ flex:0 0 auto; }
  .ts-row .ts-row-note{ order:3; flex:1 1 100%; }
  /* Day/Month summary: the horizontal bars keep the bar but let the badge wrap under it, so a long name + hours
     + % never overflows a narrow phone row. */
  .bd-hrow{ flex-wrap:wrap; }
  .bd-htrack{ flex:1 1 100%; }
  .bd-hbadge{ flex:1 1 100%; }
  .bd-hname{ max-width:none; margin-right:auto; }
  /* The day being edited is the heading of the page on a phone: it goes on its own line, above the controls,
     instead of wrapping into two lines beside them. */
  .ts-nav{ flex-wrap:wrap; row-gap:.5rem; }
  .ts-title{ order:-1; flex:1 1 100%; margin-left:0; font-size:1.05rem; }
  .ts-nav input[type="date"]{ flex:1 1 auto; }
}

