@charset "UTF-8";
/* Salary Calculator stylesheet — source of truth.
 * Compiled at boot to src/public/css/app.css by \Tina4\ScssCompiler.
 * Don't edit the generated CSS by hand; it gets overwritten. */
:root {
  --bg: #f4f5f7;
  --surface: #ffffff;
  --text: #1f2933;
  --muted: #6b7280;
  --border: #d8dce1;
  --primary: #2563eb;
  --primary-dark: #1d4ed8;
  --danger: #dc2626;
  --danger-dark: #b91c1c;
  --ok-bg: #ecfdf5;
  --ok-border: #6ee7b7;
  --ok-text: #065f46;
  --error-bg: #fef2f2;
  --error-border: #fca5a5;
  --error-text: #991b1b;
}

* {
  box-sizing: border-box;
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  font-size: 15px;
  line-height: 1.5;
}

a {
  color: var(--primary);
}

.container {
  max-width: 980px;
  margin: 0 auto;
  padding: 0 20px;
}

/* Opt-in wider measure for pages whose content is a wide data table.
 *
 * 980px is chosen for PROSE — roughly 75 characters, which is where paragraphs
 * stay readable — and a ten-column editable table does not fit in it. Set by
 * `wide_layout` on the render, which puts `.wide-layout` on <body>.
 *
 * ⚠️ It hangs off BODY rather than the table's own page section, because the
 * nav renders `.container.topnav-inner` too: widening only <main> would leave
 * the nav capped at 980px and visibly out of line with the content below it.
 * One class widens both together.
 *
 * Flat, and winning on specificity (0,2,0 over 0,1,0) rather than source order —
 * ScssCompiler reorders nested blocks, so a nested override here could not be
 * trusted to beat the base rule. */
.wide-layout .container {
  max-width: 1360px;
}

/* Navigation */
.topnav {
  background: var(--surface);
  border-bottom: 1px solid var(--border);
}
.topnav-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding-top: 12px;
  padding-bottom: 12px;
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  font-weight: 700;
  font-size: 17px;
  color: var(--text);
  text-decoration: none;
}
.brand-logo {
  display: block;
  width: 28px;
  height: 28px;
}

.nav-links {
  display: flex;
  gap: 18px;
  align-items: center;
}
.nav-links a {
  color: var(--muted);
  text-decoration: none;
}
.nav-links a:hover {
  color: var(--text);
}
.nav-links a.active {
  color: var(--text);
  font-weight: 700;
  position: relative;
}
.nav-links a.active::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: -16px;
  height: 3px;
  background: var(--primary);
  border-radius: 2px 2px 0 0;
}

.nav-logout {
  border-left: 1px solid var(--border);
  padding-left: 18px;
}

/* Settings dropdown in the admin nav. Built on <details>/<summary> so the
 * keyboard story is native: Enter / Space on the summary toggles, Tab walks
 * the items. A tiny JS handler in pickers.js closes it on outside click. */
.nav-menu {
  position: relative;
  /* Hide the default disclosure triangle in every engine. */
}
.nav-menu[open] > summary {
  color: var(--text);
}
.nav-menu > summary {
  list-style: none;
  cursor: pointer;
  color: var(--muted);
  display: inline-flex;
  align-items: center;
  gap: 6px;
  position: relative;
  /* Mirrors the underline rule for direct nav links — the JS handler
 * adds .active to the summary when the current page is one of the
 * dropdown's destinations. */
}
.nav-menu > summary::-webkit-details-marker {
  display: none;
}
.nav-menu > summary:hover {
  color: var(--text);
}
.nav-menu > summary.active {
  color: var(--text);
  font-weight: 700;
}
.nav-menu > summary.active::after {
  content: "";
  position: absolute;
  left: 0;
  right: 18px;
  bottom: -16px;
  height: 3px;
  background: var(--primary);
  border-radius: 2px 2px 0 0;
}
.nav-menu[open] .nav-menu-caret {
  transform: rotate(180deg);
}

.nav-menu-caret {
  transition: transform 120ms ease;
}

.nav-menu-panel {
  position: absolute;
  top: calc(100% + 14px);
  right: 0;
  min-width: 240px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 8px;
  box-shadow: 0 12px 32px rgba(15, 23, 42, 0.12);
  padding: 8px;
  z-index: 50;
  display: flex;
  flex-direction: column;
  gap: 4px;
}

/* Left-aligned variant, for a menu that isn't at the right end of the nav.
 * The base panel is `right: 0`, which drops Settings neatly below its summary
 * but would hang the Reports panel off the left edge of the page.
 *
 * Top level and immediately AFTER .nav-menu-panel on purpose: same specificity,
 * so source order is what makes it win, and Tina4's ScssCompiler emits nested
 * children BEFORE their parent — nesting this under the base rule would silently
 * lose the cascade. Same reason .alert / .btn keep their modifiers up here. */
.nav-menu-panel-left {
  left: 0;
  right: auto;
}

.nav-menu-section {
  padding: 6px 4px;
}
.nav-menu-section + .nav-menu-section {
  border-top: 1px solid var(--border);
  margin-top: 4px;
  padding-top: 10px;
}
.nav-menu-section a {
  display: block;
  padding: 7px 10px;
  border-radius: 6px;
  color: var(--text);
  text-decoration: none;
  font-size: 14px;
  /* Dropdown items get a filled active state instead of the
 * underline used by top-level nav links — the underline rule
 * wouldn't make sense inside a floating panel. The ::after
 * suppression undoes the .nav-links a.active rule which
 * matches dropdown items via the .nav-links ancestor. */
}
.nav-menu-section a:hover, .nav-menu-section a:focus {
  background: rgba(37, 99, 235, 0.08);
  color: var(--primary);
  outline: none;
}
.nav-menu-section a.active {
  background: rgba(37, 99, 235, 0.12);
  color: var(--primary);
  font-weight: 600;
}
.nav-menu-section a.active::after {
  content: none;
}

.nav-menu-heading {
  display: block;
  padding: 4px 10px 6px;
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--muted);
  font-weight: 700;
}

/* Layout */
main.container {
  padding-top: 28px;
  padding-bottom: 48px;
}

.page-title {
  font-size: 24px;
  margin: 0 0 18px;
}

.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 22px;
  margin-bottom: 22px;
}
.card h2 {
  margin-top: 0;
  font-size: 17px;
}

.narrow {
  max-width: 420px;
}

.auth-card {
  margin: 60px auto 0;
}

.muted {
  color: var(--muted);
}

/* Alerts. NOTE: modifiers (.alert-error, .alert-ok) are kept at the top level
 * — NOT nested under .alert with &-error — because Tina4's ScssCompiler emits
 * nested children BEFORE their parent. The `.alert { border: 1px solid
 * transparent }` would then win the cascade and wipe out the modifier's
 * border-color. Source-order at the top level keeps the modifier after the
 * base rule so border-color overrides correctly. Same trick is used on .btn
 * below for the same reason. */
.alert {
  border-radius: 6px;
  padding: 12px 14px;
  margin-bottom: 18px;
  border: 1px solid transparent;
}

.alert-error {
  background: var(--error-bg);
  border-color: var(--error-border);
  color: var(--error-text);
}

.alert-ok {
  background: var(--ok-bg);
  border-color: var(--ok-border);
  color: var(--ok-text);
}

/* Forms */
.field {
  margin-bottom: 16px;
}
.field label {
  display: block;
  font-weight: 600;
  margin-bottom: 6px;
}

.field-row {
  display: flex;
  gap: 16px;
}
.field-row .field {
  flex: 1;
}

input[type=text],
input[type=password],
input[type=number],
input[type=email],
input[type=search],
input[type=date],
textarea,
select {
  width: 100%;
  padding: 9px 10px;
  border: 1px solid var(--border);
  border-radius: 6px;
  font-size: 14px;
  background: #fff;
  color: var(--text);
}

textarea {
  font-family: inherit;
  resize: vertical;
}

input:focus,
textarea:focus,
select:focus {
  outline: none;
  border-color: var(--primary);
  box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.15);
}

/* Tom Select — restyled to read like the Bootstrap selectpicker: the control
 * is a normal-looking form input with a caret, and the dropdown is a separate
 * elevated panel whose search box sits in its own header section above the
 * options list (the dropdown_input plugin in pickers.js renders that input).
 * app.css loads after tom-select.min.css, so these override the defaults. */
.ts-wrapper {
  /* The control = the "input" the user clicks. Mirror the native input,
 * leaving room on the right for the caret. */
  /* Caret — a CSS chevron pinned to the right of the control, flipped up
 * while the dropdown is open. */
  /* Focus / open ring matching the native inputs. */
}
.ts-wrapper .ts-control {
  min-height: 38px;
  padding: 8px 32px 8px 10px;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: #fff;
  color: var(--text);
  font-size: 14px;
  cursor: pointer;
}
.ts-wrapper::after {
  content: "";
  position: absolute;
  top: 50%;
  right: 13px;
  width: 7px;
  height: 7px;
  margin-top: -6px;
  border-right: 2px solid var(--muted);
  border-bottom: 2px solid var(--muted);
  transform: rotate(45deg);
  pointer-events: none;
  transition: transform 0.15s ease;
}
.ts-wrapper.dropdown-active::after {
  margin-top: -2px;
  transform: rotate(-135deg);
}
.ts-wrapper.focus .ts-control, .ts-wrapper.dropdown-active .ts-control {
  border-color: var(--primary);
  box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.15);
}

/* The dropdown = a distinct floating panel, clearly separated from the control
 * by a gap, border, and shadow — like the bootstrap-select menu. */
.ts-dropdown {
  margin-top: 4px;
  border: 1px solid var(--border);
  border-radius: 6px;
  box-shadow: 0 6px 20px rgba(15, 23, 42, 0.12);
  overflow: hidden;
  /* Search box — its own header section above the list. */
}
.ts-dropdown.plugin-dropdown_input .dropdown-input-wrap {
  padding: 8px;
  border-bottom: 1px solid var(--border);
  background: #f9fafb;
}
.ts-dropdown.plugin-dropdown_input .dropdown-input {
  width: 100%;
  padding: 7px 9px;
  border: 1px solid var(--border);
  border-radius: 5px;
  font-size: 14px;
  background: #fff;
}
.ts-dropdown.plugin-dropdown_input .dropdown-input:focus {
  outline: none;
  border-color: var(--primary);
  box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.15);
}
.ts-dropdown .ts-dropdown-content {
  padding: 4px;
}
.ts-dropdown .option {
  padding: 8px 10px;
  border-radius: 5px;
  font-size: 14px;
  color: var(--text);
}
.ts-dropdown .option.active {
  background: rgba(37, 99, 235, 0.1);
  color: var(--primary-dark);
}
.ts-dropdown .option.selected {
  font-weight: 600;
}
.ts-dropdown .no-results {
  padding: 8px 10px;
  color: var(--muted);
}

small.muted {
  display: block;
  margin-top: 4px;
  font-size: 12px;
}

/* Buttons. Modifiers are top-level (NOT nested with &-primary etc) so they
 * emit AFTER .btn in the compiled CSS and override its `border: 1px solid
 * transparent` shorthand — see note above .alert for the compiler quirk. */
.btn {
  /* inline-flex with align-items: center centres the text inside the box
 * regardless of the font's baseline geometry. inline-block left "Invite"
 * looking high in a small button because the line-box descender space
 * sat empty (no descender glyphs in the text). */
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 9px 16px;
  border: 1px solid transparent;
  border-radius: 6px;
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
  text-decoration: none;
  line-height: 1.4;
}

.btn[disabled],
.btn[aria-busy=true] {
  opacity: 0.65;
  cursor: progress;
  pointer-events: none;
}

.btn-primary {
  background: var(--primary);
  color: #fff;
}

.btn-primary:hover {
  background: var(--primary-dark);
}

.btn-secondary {
  background: #fff;
  color: var(--text);
  border-color: var(--border);
}

.btn-secondary:hover {
  background: var(--bg);
}

.btn-danger {
  background: var(--danger);
  color: #fff;
}

.btn-danger:hover {
  background: var(--danger-dark);
}

.btn-sm {
  padding: 5px 10px;
  font-size: 12px;
  font-weight: 600;
}

/* Form-footer action row — used by the preview / report-detail pages where
 * a row of buttons sits below a form. Scoped to non-table-cell elements so
 * it doesn't leak onto the `<td class="actions">` cells in data tables
 * (those want inline button layout inside a cell, not flex + margin-top). */
div.actions {
  display: flex;
  gap: 12px;
  margin-top: 18px;
}

.data-table td.actions {
  /* Buttons in an actions cell lay out inline with a small gap. flex would
 * stretch them inside the cell unevenly when there's a mix of links and
 * forms. */
  white-space: nowrap;
}
.data-table td.actions .btn + .btn,
.data-table td.actions .btn + form,
.data-table td.actions form + .btn,
.data-table td.actions form + form {
  margin-left: 6px;
}

.is-submitting {
  cursor: progress;
}

/* Inline busy spinner on a button — the no-reload counterpart to the blocking
 * overlay. Used by the payroll Recalculate button, which must NOT raise the
 * overlay: the point of that button is that the page stays put. Sized in `em`
 * and drawn in `currentColor` so it inherits the button it sits in.
 * @keyframes ui-spin lives in keyframes.css (see the .spinner note). */
.btn.is-busy::before {
  content: "";
  display: inline-block;
  width: 0.85em;
  height: 0.85em;
  margin-right: 8px;
  vertical-align: -0.08em;
  border: 2px solid currentColor;
  border-top-color: transparent;
  border-radius: 50%;
  animation: ui-spin 0.7s linear infinite;
}

/* Payroll figures that no longer match the chosen dates. Dimmed until
 * Recalculate runs, alongside a disabled Push — so the number pushed is always
 * the number on screen. Scoped to the Employees card: the payroll log below it
 * isn't period-dependent, so dimming it would just be a lie. */
#payroll-sections.is-stale .payroll-employees {
  opacity: 0.5;
  filter: grayscale(0.4);
}

.payroll-stale-note {
  margin-top: 14px;
  margin-bottom: 0;
}

/* Label/value detail table (a payroll run's header). Pinning the label column
 * stops long labels wrapping to three lines when the value column is greedy,
 * and gives the value column a stable edge to wrap against. Top-level, not
 * nested, per the ScssCompiler child-before-parent note above. */
.detail-table th {
  width: 190px;
  white-space: nowrap;
}

/* A raw API body dumped into a cell — one long unbroken JSON token. Without a
 * break rule it sets the cell's min-content width to the whole string, which
 * forces the auto-layout table past its card and drags the row borders out
 * with it.
 *
 * `anywhere`, NOT `break-word`: only `anywhere` shrinks min-content width,
 * which is the property that actually lets the table fit. Capped and
 * scrollable so a large body can't stretch the page either. */
.raw-payload {
  display: block;
  max-width: 100%;
  max-height: 9em;
  overflow-y: auto;
  overflow-wrap: anywhere;
  word-break: break-word;
  white-space: pre-wrap;
  font-size: 12px;
  line-height: 1.5;
  color: var(--muted);
}

/* Long values in a detail cell (an error message, a comma list of payslip
 * dates) wrap instead of widening the table. */
.detail-table td {
  overflow-wrap: anywhere;
}

/* Tables */
/* Filter row above a data-table. Layout matches a card form's field row so
 * the search input lines up with the table edges underneath. */
.table-toolbar {
  display: flex;
  align-items: center;
  gap: 16px;
  margin-bottom: 14px;
}

.table-filter-input {
  /* Inherits the global input styling but caps width so it doesn't sprawl
 * across a wide card — search boxes look weirdly empty at full bleed. */
  flex: 1;
  max-width: 360px;
}

.table-toolbar-count {
  font-size: 13px;
  white-space: nowrap;
}

.table-empty-cell {
  text-align: center;
  padding: 20px 12px;
}

.data-table {
  width: 100%;
  border-collapse: collapse;
  /* Pin every body row to the height of one with a btn-sm in its actions
 * cell. Without this, rows whose actions cell is empty render shorter,
 * so the bottom dividers fall at uneven pitch and look scuffed against
 * rows that do carry a button. `height` on a td is interpreted as a
 * minimum — cells expand to fill larger content but never collapse
 * below it. */
  /* Inactive rows recede so the visible bottom line is dominated by the
 * row divider, not the loud pink Inactive badge. The badge stays at
 * full opacity because it's a status signal — only the surrounding
 * cell content dims. */
}
.data-table th,
.data-table td {
  text-align: left;
  padding: 10px 12px;
  border-bottom: 1px solid var(--border);
  vertical-align: middle;
}
.data-table tbody td {
  height: 44px;
}
.data-table tbody tr.row-inactive td {
  color: var(--muted);
}
.data-table thead th {
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--muted);
}
.data-table .num {
  text-align: right;
}
.data-table td input[type=number] {
  max-width: 120px;
  margin-left: auto;
  text-align: right;
}

.total-row td {
  font-weight: 700;
  border-top: 2px solid var(--border);
  border-bottom: none;
}

.report-meta {
  margin-top: 0;
}

.inline-form {
  display: flex;
  gap: 8px;
  align-items: center;
}
.inline-form input[type=password] {
  max-width: 180px;
}

/* Several inline-forms grouped at one end of a card-header-row. */
.inline-actions {
  display: flex;
  gap: 8px;
  align-items: center;
}

/* Full-screen blocking overlay shown while long-running forms submit */
.ui-block-overlay {
  position: fixed;
  inset: 0;
  background: rgba(15, 23, 42, 0.55);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 9999;
}
.ui-block-overlay[hidden] {
  display: none;
}

/* AFK auto-logout warning modal (built by idle-logout.js). */
.idle-modal-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(15, 23, 42, 0.5);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
  z-index: 10000;
}
.idle-modal-backdrop[hidden] {
  display: none;
}

.idle-modal {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 10px;
  box-shadow: 0 12px 40px rgba(15, 23, 42, 0.28);
  padding: 24px 28px;
  max-width: 380px;
  width: 100%;
  text-align: center;
}
.idle-modal h2 {
  margin: 0 0 8px;
}
.idle-modal .form-actions-row {
  justify-content: center;
  margin-top: 18px;
}

.ui-block-card {
  background: var(--surface);
  border-radius: 10px;
  padding: 28px 36px;
  text-align: center;
  box-shadow: 0 12px 32px rgba(0, 0, 0, 0.25);
  min-width: 260px;
}

.spinner {
  width: 42px;
  height: 42px;
  border: 4px solid var(--border);
  border-top-color: var(--primary);
  border-radius: 50%;
  /* @keyframes ui-spin lives in keyframes.css — Tina4's ScssCompiler
 * doesn't special-case @keyframes the way it handles @media, so a
 * nested `to { ... }` would compile to invalid CSS. The keyframes
 * file is hand-maintained plain CSS, linked from base.twig. */
  animation: ui-spin 0.9s linear infinite;
  margin: 0 auto 14px;
}

.ui-block-message {
  margin: 0;
  color: var(--text);
  font-weight: 500;
}

/* Report detail / generated-reports list */
.ready-banner {
  font-size: 15px;
}

.kv {
  display: grid;
  grid-template-columns: max-content 1fr;
  column-gap: 24px;
  row-gap: 6px;
  margin: 0 0 18px;
}
.kv dt {
  color: var(--muted);
  font-weight: 500;
}
.kv dd {
  margin: 0;
  color: var(--text);
}

.actions-cell {
  display: flex;
  gap: 6px;
  align-items: center;
  flex-wrap: nowrap;
  white-space: nowrap;
}

/* Report preview — sectioned + grouped table */
.section-title {
  margin: 24px 0 10px;
  font-size: 17px;
  border-bottom: 2px solid var(--border);
  padding-bottom: 6px;
}

.report-table .group-header td {
  background: #f8fafc;
  color: var(--muted);
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  border-bottom: 1px solid var(--border);
  padding-top: 14px;
}
.report-table .col-include {
  width: 70px;
  text-align: center;
}
.report-table .row-excluded {
  opacity: 0.45;
}
.report-table .row-excluded input[type=text],
.report-table .row-excluded input[type=number] {
  background: var(--bg);
}
.report-table .type-select {
  width: auto;
  padding: 6px 8px;
}

/* /payroll/periods — the neighbouring year's months, shown so the seam between
 * years can be checked without leaving the page. Dimmed because they carry no
 * inputs and are never submitted; they are reference, not workspace.
 *
 * Flat selectors, since ScssCompiler reorders nested blocks — see the .alert
 * note above. */
.period-context td {
  background: var(--bg);
  color: var(--muted);
}

/* A row whose start does not follow the previous month's end. Advisory only —
 * the server re-checks the whole set on save and is what actually decides. */
.period-row-warn td {
  background: #fffbeb;
}

.period-flag {
  display: block;
  margin-top: 2px;
  font-size: 11px;
  line-height: 1.3;
  color: #92400e;
}

/* Wide tables scroll inside their own box rather than stretching the card or
 * squeezing their controls to a few characters. The card stays put; only the
 * table moves. */
.table-scroll {
  overflow-x: auto;
  /* Room for the focus ring on the last row's controls — overflow would
 * otherwise clip it. */
  padding-bottom: 2px;
}

/* /project-rates — ten columns, two of them interactive.
 *
 * The explicit widths reserve room for the Type select and the Rate input;
 * without them the browser gives the controls whatever the free-text columns
 * leave over, which is a few characters each.
 *
 * ⚠️ The declared widths below are only ADVISORY. `table-layout` is `auto`, so
 * when the row cannot fit, the browser takes the shortfall back out of these
 * columns rather than honouring them — measured at 894px of space, `col-type`
 * collapses to 62px and renders the select as "H⌄". `min-width` is therefore
 * the load-bearing part: it is the width below which the table scrolls inside
 * `.table-scroll` instead of squeezing its own controls. 1060px is where the
 * controls measurably stop collapsing, so it must not be lowered without
 * re-measuring. The page also opts into `.wide-layout`, which on a normal
 * desktop leaves enough room that the scroller never has to engage.
 *
 * ⚠️ Flat selectors, not nested inside .data-table. ScssCompiler emits nested
 * children BEFORE their parent, so a nested override can silently lose to a
 * shorthand it was meant to beat. These win on specificity, which the compiler
 * cannot rearrange. See the .alert / .btn note. */
.rates-table {
  min-width: 1060px;
}

.rates-table th.col-type,
.rates-table td.col-type {
  width: 130px;
}

.rates-table th.col-rate,
.rates-table td.col-rate {
  width: 130px;
}

.rates-table th.col-tracked,
.rates-table td.col-tracked {
  width: 96px;
  white-space: nowrap;
}

.rates-table th.col-status,
.rates-table td.col-status {
  width: 104px;
}

.rates-table th.col-billable,
.rates-table td.col-billable {
  width: 116px;
}

/* A rate that cannot pay anything, because none of the project's tracked time is
 * billable. Dimmed rather than disabled — a disabled input posts nothing, and the
 * flag can flip in Clockify on the next import. */
.rates-table td.rate-inert .rate-input {
  opacity: 0.55;
  background: var(--bg);
}

.rates-table .rate-inert-note {
  display: block;
  margin-top: 4px;
  font-size: 11px;
  line-height: 1.3;
  text-align: right;
}

.rates-table th.col-last-set,
.rates-table td.col-last-set {
  width: 128px;
  white-space: nowrap;
  font-size: 13px;
}

.rates-table td.col-include {
  text-align: center;
}

.rates-table th.col-include {
  width: 56px;
  text-align: center;
}

/* Fill the column width reserved above. */
.rates-table .type-select {
  width: 100%;
  padding: 7px 8px;
}

/* Overrides `.data-table td input[type="number"] { max-width: 120px }`, which
 * would otherwise cap this input below its column width. */
.rates-table td.col-rate .rate-input {
  max-width: none;
  width: 100%;
  text-align: right;
}

.field-check label {
  display: flex;
  gap: 10px;
  align-items: center;
  font-weight: 500;
}
.field-check input[type=checkbox] {
  width: auto;
  margin: 0;
}

.grand-total-card {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 14px 18px;
  margin-top: 18px;
  background: #eef2ff;
  border: 1px solid #c7d2fe;
  border-radius: 8px;
  font-weight: 700;
  font-size: 16px;
}
.grand-total-card .num {
  font-size: 20px;
}

.grand-total-values {
  display: flex;
  align-items: center;
  gap: 14px;
}

.grand-total-divider {
  color: var(--muted);
  font-size: 20px;
}

/* Filter forms */
.filter-card {
  padding: 14px 18px;
}

.filter-form {
  display: flex;
  gap: 12px;
  align-items: center;
  flex-wrap: wrap;
  /* Original native select — Tom Select hides this once it initialises but
 * we still want a sensible width during the brief pre-init flash. */
  /* Tom Select's replacement wrapper — what the user actually sees post-init.
 * Without this the wrapper collapses to its content width inside the flex
 * container and shows as a tiny "All users" pill. */
}
.filter-form label {
  font-weight: 600;
  color: var(--muted);
  margin: 0;
}
.filter-form select {
  min-width: 240px;
  width: auto;
}
.filter-form .ts-wrapper {
  min-width: 240px;
  width: auto;
}

.filter-inline {
  margin-bottom: 16px;
}

/* Toggle switch — a styled checkbox (e.g. the per-user auto-import toggle on
 * /clockify-users). Kept flat (no &-nesting) to dodge the ScssCompiler quirk. */
.switch {
  position: relative;
  display: inline-block;
  width: 40px;
  height: 22px;
  vertical-align: middle;
}

.switch input {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  margin: 0;
  opacity: 0;
  cursor: pointer;
}

.switch-slider {
  position: absolute;
  inset: 0;
  background: var(--border);
  border-radius: 999px;
  transition: background 0.15s ease;
  pointer-events: none;
}

.switch-slider::before {
  content: "";
  position: absolute;
  top: 3px;
  left: 3px;
  width: 16px;
  height: 16px;
  background: #fff;
  border-radius: 50%;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.25);
  transition: transform 0.15s ease;
}

.switch input:checked + .switch-slider {
  background: var(--primary);
}

.switch input:checked + .switch-slider::before {
  transform: translateX(18px);
}

.switch input:disabled + .switch-slider {
  opacity: 0.5;
}

.switch input:focus-visible + .switch-slider {
  box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.25);
}

/* "Auto" tag on scheduled import runs in the Recent imports table. */
.run-source-badge {
  display: inline-block;
  margin-left: 6px;
  padding: 1px 7px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.02em;
  background: #e0e7ff;
  color: #3730a3;
  vertical-align: middle;
}

/* Import audit log */
.audit-pill {
  display: inline-block;
  padding: 2px 8px;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 600;
  margin-right: 4px;
}
.audit-pill-inserted {
  background: #d1fae5;
  color: #065f46;
}
.audit-pill-updated {
  background: #fef3c7;
  color: #92400e;
}
.audit-pill-deleted {
  background: #fee2e2;
  color: #991b1b;
}

.audit-summary {
  text-decoration: none;
}

.audit-list {
  list-style: none;
  padding: 0;
  margin: 0;
}

.audit-item {
  border-left: 3px solid var(--border);
  padding: 14px 18px;
  margin-bottom: 14px;
  background: #fafbfd;
  border-radius: 4px;
}
.audit-item.audit-inserted {
  border-left-color: #10b981;
}
.audit-item.audit-updated {
  border-left-color: #f59e0b;
}
.audit-item.audit-deleted {
  border-left-color: #ef4444;
}

.audit-head {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  margin-bottom: 10px;
  font-size: 13px;
}

.audit-badge {
  padding: 3px 10px;
  border-radius: 4px;
  font-weight: 700;
  font-size: 11px;
  letter-spacing: 0.04em;
}
.audit-badge.audit-inserted {
  background: #d1fae5;
  color: #065f46;
}
.audit-badge.audit-updated {
  background: #fef3c7;
  color: #92400e;
}
.audit-badge.audit-deleted {
  background: #fee2e2;
  color: #991b1b;
}

.audit-diff {
  margin: 0;
}
.audit-diff code {
  font-size: 12px;
  color: var(--muted);
}

/* Role + invite-status badges (admin /accounts page). */
.role-badge,
.status-badge {
  display: inline-block;
  padding: 2px 8px;
  border-radius: 4px;
  font-weight: 600;
  font-size: 11px;
  letter-spacing: 0.03em;
}

.role-admin {
  background: #ede9fe;
  color: #5b21b6;
}

.role-employee {
  background: #dbeafe;
  color: #1e40af;
}

.status-active {
  background: #d1fae5;
  color: #065f46;
}

.status-invited {
  background: #fef3c7;
  color: #92400e;
}

.status-expired {
  background: #fee2e2;
  color: #991b1b;
}

.notice-card {
  border-left: 4px solid var(--primary);
}

/* Password strength meter on /invite/{token}. */
.password-meter {
  margin-top: 8px;
}

.password-meter-bar {
  background: var(--border);
  border-radius: 4px;
  height: 6px;
  overflow: hidden;
}

.password-meter-bar-fill {
  display: block;
  height: 100%;
  transition: width 150ms ease, background 150ms ease;
  width: 0;
}
.password-meter-bar-fill[data-score="0"] {
  width: 0;
}
.password-meter-bar-fill[data-score="1"] {
  width: 25%;
  background: #ef4444;
}
.password-meter-bar-fill[data-score="2"] {
  width: 50%;
  background: #f59e0b;
}
.password-meter-bar-fill[data-score="3"] {
  width: 75%;
  background: #10b981;
}
.password-meter-bar-fill[data-score="4"] {
  width: 100%;
  background: #059669;
}

.password-rules {
  list-style: none;
  padding: 0;
  margin: 8px 0 0;
  font-size: 13px;
}
.password-rules li {
  padding: 2px 0 2px 18px;
  position: relative;
  color: var(--muted);
}
.password-rules li::before {
  content: "○";
  position: absolute;
  left: 0;
}
.password-rules .rule-pass {
  color: #065f46;
}
.password-rules .rule-pass::before {
  content: "✓";
}
.password-rules .rule-fail {
  color: #991b1b;
}
.password-rules .rule-fail::before {
  content: "✗";
}

.password-errors {
  color: #991b1b;
  margin: 8px 0 0;
  padding-left: 18px;
}

.auth-card {
  max-width: 460px;
  margin: 40px auto;
  padding: 32px;
  background: var(--surface);
  border-radius: 8px;
  box-shadow: 0 8px 30px rgba(0, 0, 0, 0.06);
}

/* Admin /settings page. The form fills the card width like every other
 * admin form. Layout: a header row with title + status pill, then a lead
 * paragraph, then field-rows, then a left-aligned button row at the foot
 * of the card. Mirrors the shape of the reference design without the
 * STARTTLS toggle (we want explicit TLS / SSL / none control). */
.card-header-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 4px;
}
.card-header-row h2 {
  margin: 0;
}

.card-lead {
  margin: 8px 0 22px;
}

.status-pill {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 4px 12px;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.02em;
}
.status-pill-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: currentColor;
}
.status-pill-on {
  background: #d1fae5;
  color: #047857;
}
.status-pill-off {
  background: #f1f5f9;
  color: #64748b;
}

.required-marker {
  color: #dc2626;
  margin-left: 2px;
  font-weight: 700;
}

.field-narrow {
  max-width: 280px;
}

.form-actions-row {
  margin-top: 24px;
  padding-top: 18px;
  border-top: 1px solid var(--border);
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
}

.settings-test-form {
  display: flex;
  gap: 12px;
  align-items: center;
  /* Cap the input at something reader-friendly even though the form
 * itself fills the card — an unbounded email box looks silly. */
}
.settings-test-form input[type=email] {
  flex: 1;
  max-width: 380px;
}

/* Screen-reader-only labels. Visually hidden but kept in the accessibility
 * tree so a screen reader announces the field, and any future tooling that
 * walks form labels still finds them. */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* Dashboard charts. Two side by side on a wide screen, stacked on a narrow one.
 * The fixed height is required, not cosmetic: Chart.js with
 * maintainAspectRatio:false sizes to its container, and a canvas in an
 * unconstrained block resolves to zero height and renders nothing. */
#dashboard-charts {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
  gap: 20px;
}

.chart-box {
  position: relative;
  height: 260px;
  min-width: 0;
}
