/* 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;
  --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{ min-width:0; padding-top:1.5rem; min-height:60vh; }   /* the blue top line + connector are drawn in #t2uConnector (SVG) */
.t2u-loader{ display:flex; align-items:center; justify-content:center; padding:4rem 0; }
/* 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; }
@media (max-width:700px){
  body{ overflow-x:hidden; }                                        /* no stray horizontal scroll on phones */
  .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; }
  /* static, not sticky: a sticky nav is its own stacking context, and the menu sheet inside it could never
     rise above the page's content, however high its z-index */
  .t2u-nav{ width:auto !important; position:static; }
  .t2u-connector{ display:none; }
  .t2u-content{ padding-top:0; }
  .page-menu-btn.has-menu{ display:inline-flex; }
  #appsBox{ display:none; }                                         /* one way in on a phone: the burger */
  .t2u-menu-head{ display:none !important; }                        /* no MENU header / collapse on mobile (override Bootstrap .d-flex) */
  /* On a phone the menu is a sheet: it takes the screen below the masthead, groups the modules by application
     exactly as the apps menu does on a desktop, and scrolls on its own. */
  .t2u-menu{
    position:fixed; left:0; right:0; bottom:0; z-index:1055;        /* top = under the masthead, set in JS */
    display:none; padding:1rem .9rem 2rem; overflow-y:auto;
    background:var(--surface); border-top:1px solid var(--hair); box-shadow:var(--shadow);
  }
  .t2u-menu.menu-open{ display:block; }
  .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; }
}
/* 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); }

/* period nav group */
#nav .btn, .btn-outline-secondary{
  border-color:var(--hair-strong); color:var(--ink-soft); background:var(--surface);
}
#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); }
.int-tile.on{ border-color:#16a34a; }
.int-tile.off{ border-color:#dc2626; }
.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). */
.mon-tile.mon-b-success{ border-color:var(--bs-success); }
.mon-tile.mon-b-danger{ border-color:var(--bs-danger); }
.mon-tile.mon-b-warning{ border-color:var(--bs-warning); }
.mon-tile.mon-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-end; }
.int-name{ font-weight:600; display:-webkit-box; -webkit-line-clamp:2; line-clamp:2; -webkit-box-orient:vertical; overflow:hidden; }
/* 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{ background:var(--paper); color:var(--muted); border:1px solid var(--hair-strong); font-weight:500; }
.badge-scope{ background:color-mix(in srgb, var(--muted) 14%, var(--surface)); color:var(--ink-soft); border:1px solid var(--hair-strong); font-weight:500; cursor:help; }
.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; }
.sec-rot-table{ font-size:.86rem; margin-bottom:.3rem; }
.sec-rot-table 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; }
/* Monitoring panel */
.mon-card{ border:1px solid var(--hair); border-radius:14px; background:var(--surface); padding:.9rem 1.1rem; }
.mon-table{ margin-top:.25rem; }
.mon-table td{ padding:.25rem .5rem; vertical-align:top; border-color:var(--hair); }
.mon-table td:first-child{ width:9.5rem; white-space:nowrap; }
/* Log card header: pinned to the top of the card (spans its full width via negative margins) so the Refresh button
   and health badge stay visible while the run rows scroll under it. */
.mon-loghead{ position:sticky; top:0; z-index:4; display:flex; justify-content:space-between; align-items:center; gap:.75rem;
  background:var(--surface); margin:-.9rem -1.1rem .6rem; padding:.65rem 1.1rem; border-bottom:1px solid var(--hair); border-radius:14px 14px 0 0; }
.mon-loghead-r{ display:flex; align-items:center; gap:.5rem; }
.mon-refresh{ font-size:.72rem; padding:.2rem .55rem; line-height:1.3; display:inline-flex; align-items:center; gap:.3rem; }
/* 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. */
.t2u-table{ width:100%; border-collapse:separate; border-spacing:0; margin:0; }
.t2u-table > thead > tr > th,
.t2u-table > tbody > tr > td{ padding:.55rem .6rem; vertical-align:middle; }
.t2u-table > tbody > tr > td{ border-top:1px solid var(--hair); }
.t2u-table > tbody > tr:hover > td{ background:var(--paper); }
.t2u-table > thead > tr:first-child > th{
  position:sticky; top:0; z-index:6; background:var(--surface);
  font-size:.7rem; font-weight:600; letter-spacing:.06em; text-transform:uppercase; color:var(--muted); white-space:nowrap;
}
/* a filter row is part of the header and sticks just under the labels */
.t2u-table > thead > tr.t2u-filters > th{ position:sticky; top:2.1rem; z-index:5; background:var(--surface); padding-top:.15rem; padding-bottom:.55rem; font-weight:400; }
.t2u-table > thead > tr.t2u-filters input, .t2u-table > thead > tr.t2u-filters select{ width:100%; }


/* 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{ color:var(--brand); }
.icon-btn.act-open:hover{ background:var(--brand); color:#fff; border-color:var(--brand); }
.icon-btn.act-del{ color:var(--danger); }
.icon-btn.act-del:hover{ background:var(--danger); color:#fff; border-color:var(--danger); }

/* token card badges */
.tok-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; }
.tok-badge.badge-entry{ background:var(--teal); }
.tok-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; }
.int-switch .form-check-input:not(:checked){ background-color:#dc2626; border-color:#dc2626; }
.int-switch .form-check-input:checked{ background-color:#16a34a; border-color:#16a34a; }
.int-switch .form-check-input:focus{ box-shadow:0 0 0 .2rem rgba(46,111,183,.25); }
.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 */
#supRoutesWrap{ overflow-x:auto; }
.sup-table{ font-size:.82rem; }
.sup-table th{ font-weight:600; white-space:nowrap; }
.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; }
.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. */
.usr-off{ opacity:.55; }
.usr-off select{ pointer-events:none; }

.sup-toolbar{ display:flex; flex-wrap:wrap; gap:.5rem; align-items:center; margin-bottom:.55rem; }
.sup-toolbar .sup-search{ flex:1 1 240px; min-width:180px; }
.sup-toolbar select, .sup-toolbar input[type="date"]{ width:auto; flex:0 0 auto; }
.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; }
.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-act{ display:inline-block; border:0; background:none; padding:.1rem .25rem; color:var(--brand); text-decoration:none; cursor:pointer; }
.sup-act:hover{ color:var(--brand-deep); }
.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;
  --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; }
.ts-nav input[type="date"]{ width:auto; }
.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 1.35rem; margin-bottom:1.5rem;
  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;
}
.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-task{ flex:1 1 auto; min-width:0; }
.ts-timer-on .ts-timer-task b{ 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; }
@keyframes ts-breathe{ 0%,100%{ color:var(--ink); } 50%{ color:var(--muted); } }
@media (prefers-reduced-motion:reduce){ .ts-pulse{ animation:none; } }
@media (max-width:700px){
  /* The card reads top-down: what you are on; the note with its billable flag; the start time and the clock;
     then the one button. Nothing shares a line unless it belongs together. */
  .ts-timer{ flex-wrap:wrap; row-gap:.75rem; column-gap:.6rem; }
  .ts-timer-task{ flex:1 1 100%; }
  .ts-timer .ts-note{ flex:1 1 auto; max-width:none; }
  .ts-timer .ts-bill{ flex:0 0 auto; }
  .ts-runfrom{ flex:0 0 auto; }
  .ts-elapsed{ flex:1 1 auto; font-size:1.7rem; text-align:right; }
  .ts-startbtn, .ts-timer-on .btn-danger{ flex:1 1 100%; width:100%; }
}
.ts-note{ flex:1 1 220px; max-width:360px; }
.ts-path{ font-size:.78rem; opacity:.7; }

.ts-group{ border:1px solid var(--bs-border-color); border-radius:.6rem; }   /* no overflow clip: the row's kebab menu must escape it */
.ts-group-h{ border-top-left-radius:.6rem; border-top-right-radius:.6rem; }
.ts-group-h{ align-items:center; padding:.55rem .9rem; border-bottom:1px solid var(--bs-border-color); font-weight:600; }
.ts-row{ display:flex; align-items:center; gap:.75rem; padding:.6rem .9rem; border-bottom:1px solid var(--bs-border-color); }
.ts-row:last-of-type{ border-bottom:0; }
.ts-row-task{ flex:1 1 260px; min-width:0; }
.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:right; }
/* 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; }
.ts-daysum-total{ font-weight:700; font-variant-numeric:tabular-nums; }

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

/* week grid: task x day, editable cells */
.ts-wk-wrap{ overflow-x:auto; }
/* fixed layout: the columns keep their width whatever the task is called or how long a cell reads. Every
   column states its width — `min-width` is ignored here — and the table is at least their sum, so nothing
   is squeezed into its neighbour; below that the wrapper scrolls. */
.ts-wk{ width:100%; min-width:900px; table-layout:fixed; }
.ts-wk th, .ts-wk td{ vertical-align:middle; padding:.55rem .35rem; }   /* the task's name sits on the same line as its time boxes */
.ts-wk-task{ width:28%; }
.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, .ts-wk-name .ts-path{ display:block; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.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; }
.ts-wk-day{ text-align:center; font-weight:600; }
.ts-wk-today{ color:var(--brand); }
/* A cell holds "12h 00m" — the longest thing it will ever say — so the type and the padding are cut to fit it
   whole. A number half-shown is worse than a smaller number. */
.ts-wk-cell{ width:9%; }
.ts-wk-cell input{ width:100%; padding:.3rem .15rem; font-size:.84rem; text-align:center; font-variant-numeric:tabular-nums; }
.ts-wk-total{ width:9%; text-align:right; font-size:.9rem; font-variant-numeric:tabular-nums; white-space:nowrap; }
.ts-wk-foot td{ border-top:2px solid var(--bs-border-color); }

/* 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; }
.pj-card.pj-off{ opacity:.6; }
.pj-head{ display:flex; align-items:center; gap:.6rem; padding:.6rem .8rem; }
.pj-toggle{ border:0; background:none; color:var(--muted); }
.pj-name{ flex:1 1 auto; min-width:0; }
.pj-actions{ flex:0 0 auto; }
.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; }
.ts-pick{ flex:1 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:1 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; }
.ts-timer-task{ border:0; background:none; text-align:left; color:inherit; }
.ts-pencil{ font-size:.72rem; opacity:.5; }

/* 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. */
.ts-new{ animation:ts-arrive .32s ease both, ts-flag 2.2s ease-out .32s both; }
@keyframes ts-arrive{ from{ opacity:0; transform:translateY(-6px); } to{ opacity:1; transform:none; } }
@keyframes ts-flag{
  0%   { background:color-mix(in srgb, var(--teal) 10%, transparent); box-shadow:inset 3px 0 0 var(--teal); }
  60%  { background:color-mix(in srgb, var(--teal) 10%, transparent); box-shadow:inset 3px 0 0 var(--teal); }
  100% { 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(--brand); opacity:1; }               /* billable is a state of the entry, in the app's own blue */
.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; }

/* 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; }
.ts-timer-off .ts-timer-task{ flex:1 1 260px; min-width:0; }
/* 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-timer-off .ts-timer-task:hover .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{ background:var(--teal); border-color:var(--teal); }
.ts-startbtn:hover, .ts-resume:hover, .ts-startbtn:focus-visible, .ts-resume:focus-visible,
.ts-startbtn:active, .ts-resume: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; padding:.7rem 1.4rem; border-radius:.6rem; }
.ts-timer-on .btn-danger{ flex:0 0 auto; white-space:nowrap; font-weight:700; padding:.6rem 1.2rem; font-size:1rem; border-radius:.6rem; }
/* play and stop carry the meaning of these two buttons, so they are read at the size of the label, not below it */
.ts-startbtn .bi, .ts-timer-on .btn-danger .bi{ font-size:1.25em; 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 | note | billable | times | duration | the one action group — the header rides it too, 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(190px,1fr) minmax(150px,340px) 2.2rem 12rem 6rem 5.6rem; column-gap:.75rem; }
/* 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-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{ border-color:var(--teal); }
/* 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. */
.ts-ghost{ display:flex; align-items:center; gap:.6rem; padding:.75rem .9rem; color:var(--muted);
  border-bottom:1px solid var(--bs-border-color); animation:ts-arrive .32s ease both;
  box-shadow:inset 3px 0 0 var(--teal); background:color-mix(in srgb, var(--teal) 8%, transparent); }
.ts-removing{ animation:ts-vanish .45s ease both; pointer-events:none; }
@keyframes ts-vanish{
  0%   { background:color-mix(in srgb, var(--danger) 14%, transparent); box-shadow:inset 3px 0 0 var(--danger); }
  70%  { background:color-mix(in srgb, var(--danger) 14%, transparent); box-shadow:inset 3px 0 0 var(--danger); opacity:1; }
  100% { opacity:0; transform:translateX(-10px); }
}
@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; }
.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. */
.pj-badge{ 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; }
.pj-badge > i{ color:var(--muted); font-weight:400; }
.pj-badge.pj-badge.tasks-toggle:hover{ border-color:var(--brand); color:var(--brand); }
.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-move{ display:inline-flex; flex-direction:column; line-height:.7; }
.pj-move button{ border:0; background:none; color:var(--muted); padding:0 .15rem; font-size:.7rem; }
.pj-move button:hover:not(:disabled){ color:var(--brand); }
.pj-move button:disabled{ opacity:.25; }
.pj-children .pj-toggle-sp{ display:inline-block; width:1.6rem; }   /* a leaf keeps the caret's space, so names line up */
.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 ===================== */
.home-h{ font-weight:700; letter-spacing:-.01em; }
.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); }
.apps-menu{ min-width:260px; padding:.5rem; z-index:1080; }
.apps-group + .apps-group{ margin-top:.5rem; border-top:1px solid var(--hair); padding-top:.5rem; }
.apps-group-h{ display:flex; align-items:center; gap:.4rem; font-size:.68rem; font-weight:700; letter-spacing:.08em; text-transform:uppercase; color:var(--muted); padding:.1rem .4rem .3rem; }
.apps-item{ display:flex; align-items:center; gap:.5rem; border-radius:.35rem; }
.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){
  /* Users: the table keeps its columns and scrolls; the filters ride with it */
  #users{ overflow-x:auto; }
  .usr-table{ min-width:820px; }
  /* 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; }
  /* Catalog: a project's badges wrap, and its actions drop to their own line rather than squeezing the name */
  .pj-head{ flex-wrap:wrap; }
  .pj-name{ flex:1 1 100%; }
  .pj-actions{ margin-left:auto; }
  .pj-node{ flex-wrap:wrap; }
  /* 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; }
}

/* ---------- 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 as three lines: the task; the note with its billable flag; then the times, the duration and the
     actions — which must hold ONE line, so nothing there is allowed to stretch. */
  .ts-row{ display:flex; flex-wrap:wrap; column-gap:.5rem; row-gap:.5rem; }
  .ts-group-h{ display:flex; align-items:center; gap:.75rem; }
  .ts-group-h .ts-row-task{ flex:0 0 auto; }
  .ts-addbtn{ margin-left:auto; }
  .ts-row-task{ flex:1 1 100%; }
  .ts-row .ts-note{ flex:1 1 auto; max-width:none; }
  .ts-row .ts-bill{ flex:0 0 auto; }
  .ts-row .ts-times{ flex:0 0 auto; text-align:left; }
  .ts-row .ts-start, .ts-row .ts-end{ width:4.6rem; }
  .ts-dur{ flex:0 0 auto; margin-left:auto; }
  .ts-actions{ flex:0 0 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; }
}

