/* Ishraf.UI.Controls consumes host-owned design tokens; it intentionally defines no theme. */
@font-face {
  font-family: "Material Symbols Rounded";
  font-style: normal;
  font-weight: 400;
  src: url("../fonts/materialsymbols-1.woff2") format("woff2");
}

.msr {
  font-family: "Material Symbols Rounded", sans-serif; font-weight: normal; font-style: normal;
  line-height: 1; letter-spacing: normal; text-transform: none; white-space: nowrap;
  direction: ltr; font-feature-settings: "liga"; -webkit-font-smoothing: antialiased;
  user-select: none; font-variation-settings: "FILL" 0, "wght" 400, "GRAD" 0, "opsz" 24;
}
.fl-sel { position: relative; }
.fl-sel-btn {
  display: flex; align-items: center; gap: 8px; width: 100%; height: 40px; padding: 0 12px;
  box-sizing: border-box; border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--surface); color: var(--ink); font: inherit; font-size: .88rem;
  outline: none; text-align: start; cursor: pointer;
  transition: border-color .15s ease, box-shadow .15s ease;
}
.fl-sel-btn:hover { border-color: color-mix(in srgb, var(--brand) 40%, var(--line)); }
.fl-sel-btn:focus,
.fl-sel--open .fl-sel-btn { border-color: var(--brand); box-shadow: 0 0 0 3px var(--brand-tint); }
.fl-sel-btn:disabled {
  background: var(--disabled-bg, var(--surface-2));
  color: var(--disabled-fg, var(--faint));
  border-color: var(--disabled-border, var(--line));
  opacity: 1;
  cursor: not-allowed;
}
.fl-sel-btn.fl-input--error,
.fl-sel-btn.fl-input--error:hover { border-color: var(--error); }
.fl-sel-btn.fl-input--error:focus { border-color: var(--error); box-shadow: 0 0 0 3px var(--error-bg); }
.fl-sel-value { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.fl-sel-caret { font-size: 20px; color: var(--faint); flex-shrink: 0; transition: transform .16s ease; }
.fl-sel--open .fl-sel-caret { transform: rotate(180deg); }
.fl-sel-menu {
  position: fixed; top: -9999px; inset-inline-start: auto; left: -9999px; z-index: 21;
  width: max-content; max-width: min(360px, 92vw);
  display: flex; flex-direction: column; gap: 2px;
  background: var(--surface); border: 1px solid var(--line); border-radius: 12px;
  box-shadow: var(--shadow-lg); padding: 6px; max-height: 340px; overflow-y: auto;
  box-sizing: border-box; animation: fl-control-pop .13s ease backwards;
}
.fl-sel-search {
  position: sticky; top: -6px; z-index: 1;
  display: flex; align-items: center; gap: 7px;
  margin: -6px -6px 4px; padding: 10px 12px;
  background: var(--surface); border-bottom: 1px solid var(--line-soft);
  border-radius: 12px 12px 0 0;
}
.fl-sel-searchicon { font-size: 17px; color: var(--faint); flex-shrink: 0; }
.fl-sel-searchinput {
  flex: 1; min-width: 0; border: none; background: none; outline: none;
  color: var(--ink); font: inherit; font-size: .87rem;
}
.fl-sel-searchinput::placeholder { color: var(--faint); font-weight: 500; }
/* The options sit in their own element because role=listbox only admits options and groups — the
   search box and the empty-state message are siblings of it, not children. The menu stays the
   scroll container so the sticky search header keeps working. */
.fl-sel-list { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.fl-sel-empty { padding: 14px 11px; color: var(--faint); font-size: .85rem; text-align: center; }
.fl-sel-opt {
  display: flex; align-items: center; gap: 8px; width: 100%; box-sizing: border-box;
  padding: 9px 10px; border: none; border-radius: var(--radius); background: transparent;
  color: var(--ink); font: inherit; font-size: .87rem; font-weight: 600;
  text-align: start; cursor: pointer;
}
.fl-sel-opt > span:first-child { white-space: nowrap; }
.fl-sel-opt:hover,
.fl-sel-opt--hl { background: var(--surface-2); }
.fl-sel-opt--on { color: var(--brand); }
.fl-sel-check { font-size: 18px; flex-shrink: 0; margin-inline-start: auto; }

.fl-autocomplete { position: relative; }
.fl-autocomplete-field {
  display: flex; align-items: center; gap: 8px; height: 40px; padding: 0 10px;
  border: 1px solid var(--line); border-radius: 8px; background: var(--surface);
  transition: border-color .15s ease, box-shadow .15s ease;
}
.fl-autocomplete-field:focus-within { border-color: var(--brand); box-shadow: 0 0 0 3px var(--brand-tint); }
.fl-autocomplete--invalid .fl-autocomplete-field { border-color: var(--error); }
.fl-autocomplete:has(.fl-autocomplete-input:disabled) .fl-autocomplete-field {
  background: var(--disabled-bg, var(--surface-2));
  border-color: var(--disabled-border, var(--line));
}
.fl-autocomplete-lead { font-size: 18px; color: var(--faint); flex-shrink: 0; }
.fl-autocomplete-input {
  flex: 1; border: none; outline: none; background: transparent; color: var(--ink);
  font: inherit; font-size: .88rem; min-width: 0;
}
.fl-autocomplete-input:disabled {
  background: transparent;
  color: var(--disabled-fg, var(--faint));
  cursor: not-allowed;
}
.fl-autocomplete-clear {
  width: 24px; height: 24px; flex-shrink: 0; display: flex; align-items: center;
  justify-content: center; border: none; border-radius: 6px; background: transparent;
  color: var(--faint); cursor: pointer;
}
.fl-autocomplete-clear:hover { background: var(--surface-2); color: var(--ink); }
.fl-autocomplete-clear .msr { font-size: 16px; }
.fl-autocomplete-menu {
  position: absolute; top: calc(100% + 6px); inset-inline: 0; z-index: 60;
  max-height: 280px; overflow-y: auto; padding: 6px; background: var(--surface);
  border: 1px solid var(--line); border-radius: 12px; box-shadow: var(--shadow-lg);
  animation: fl-control-pop .15s ease backwards;
}
.fl-autocomplete-option {
  display: block; width: 100%; text-align: start; padding: 9px 10px; border: none;
  border-radius: var(--radius); background: transparent; color: var(--ink); font: inherit;
  font-size: .86rem; cursor: pointer;
}
.fl-autocomplete-option:hover,
.fl-autocomplete-option--active { background: var(--surface-2); }
.fl-autocomplete-option--selected { color: var(--brand); }
.fl-autocomplete-empty { padding: 10px; font-size: .84rem; color: var(--faint); text-align: center; }

.fl-search {
  display: flex; align-items: center; gap: 8px; height: 40px; padding-inline: 13px;
  box-sizing: border-box; border: 1px solid var(--line); border-radius: 11px;
  background: var(--surface); min-width: 230px; flex: 0 1 280px;
}
.fl-search:focus-within { border-color: var(--brand); box-shadow: 0 0 0 3px var(--brand-tint); }
.fl-search-icon { font-size: 18px; color: var(--faint); flex-shrink: 0; }
.fl-search-input {
  flex: 1; min-width: 0; border: none; background: transparent; color: var(--ink);
  font: inherit; font-size: .85rem; outline: none;
}
.fl-search-clear {
  border: none; background: transparent; color: var(--faint); cursor: pointer; padding: 0;
  display: flex; align-items: center;
}
.fl-search-clear:hover { color: var(--error); }
.fl-search-clear:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }
.fl-search-clear:disabled { cursor: not-allowed; opacity: .55; }
.fl-search-clear .msr { font-size: 17px; }

/* ---- FlDataGrid: table shell, and the loading / error / empty states around it ----------
   Structural only, and scoped to the grid. `.fl-table` is an old, widely-used class name: a host
   that had its own standalone `<table class="fl-table">` before it referenced this library would
   otherwise find its tables silently re-padded and re-sized just by linking controls.css, and the
   damage is worst where the host sets only *some* of the same properties, so the two rulesets
   interleave. Everything FlDataGrid actually renders lives inside `.fl-data-grid`, so scoping the
   structural rules there costs the grid nothing and leaves a host's own tables alone. A host that
   wants this chrome on a standalone table owns the geometry and typography in its own stylesheet. */
.fl-data-grid .fl-tablewrap { overflow-x: auto; border: 1px solid var(--line-soft); border-radius: var(--radius); background: var(--surface); }
.fl-data-grid .fl-table { width: 100%; border-collapse: collapse; font-size: .78rem; }
.fl-data-grid .fl-table th { padding: 11px 13px; background: var(--surface-2); color: var(--muted); text-align: start; font-size: .7rem; white-space: nowrap; }
.fl-data-grid .fl-table td { padding: 12px 13px; border-top: 1px solid var(--line-soft); vertical-align: middle; }
.fl-data-grid .fl-table td small { display: block; margin-top: 3px; color: var(--faint); }
/* Money columns: header and values centered together. */
.fl-data-grid .fl-table th.fl-col-num, .fl-data-grid .fl-table td.fl-col-num { text-align: center; }
.fl-data-grid .fl-clickrow { cursor: pointer; }
.fl-data-grid .fl-clickrow:hover { background: var(--brand-tint-2); }
/* A clickable row is tabbable, so it needs a visible focus ring like any other target. Inset,
   because an outline on a <tr> is clipped by the scrolling wrapper at the table's edges. */
.fl-data-grid .fl-clickrow:focus-visible { outline: 2px solid var(--brand); outline-offset: -2px; background: var(--brand-tint-2); }

/* Cell-content helpers, not table geometry: a RowTemplate puts these on its own <td> contents, and
   they carry no padding, border or sizing, so they stay unscoped and usable outside the grid. */
/* Numeric sub-line (e.g. phone) rendered LTR but aligned to the row's start, level with the name above. */
.fl-num-start { direction: ltr; text-align: right; }
/* Click-to-copy affordance (e.g. a phone number inside a clickable row). */
.fl-copyable { cursor: copy; }
.fl-copyable:hover { color: var(--brand); text-decoration: underline; }

/* The loading placeholder mirrors the table card so nothing reflows when the rows arrive.
   The caller's column count arrives as --fl-skeleton-columns rather than being baked in here. */
.fl-data-grid__skeleton {
  overflow: hidden; border: 1px solid var(--line-soft); border-radius: var(--radius); background: var(--surface);
}
.fl-data-grid__skeleton-row {
  display: grid; grid-template-columns: repeat(var(--fl-skeleton-columns, 4), minmax(0, 1fr));
  align-items: center; gap: 14px; min-height: 45px; padding: 12px 13px;
  border-top: 1px solid var(--line-soft); pointer-events: none;
}
.fl-data-grid__skeleton-row:first-child { border-top: 0; }
.fl-data-grid__skeleton-row .fl-skel { width: 100%; }

/* The shimmer is two stops travelling across a bar, so it is only as visible as the gap between
   them. Falling back to --surface-2 and --sunken keeps a host that defines neither working, but
   those two are picked for panel chrome, not for contrast with each other: in a typical light
   theme they land a couple of steps apart and the animation all but disappears, while the same
   pair in a dark theme happens to be far apart and reads clearly. --fl-skeleton-base and
   --fl-skeleton-highlight let a host set the pair deliberately per mode instead of inheriting
   whatever distance its surface tokens happen to have. */
.fl-skel {
  display: block; height: 12px; border-radius: 6px;
  background: linear-gradient(90deg,
    var(--fl-skeleton-base, var(--surface-2)),
    var(--fl-skeleton-highlight, var(--sunken)),
    var(--fl-skeleton-base, var(--surface-2)));
  background-size: 200% 100%; animation: fl-shimmer 1.2s ease-in-out infinite;
}
.fl-skel--avatar { width: 38px; height: 38px; flex: none; border-radius: 10px; }
.fl-skel--name { width: min(260px, 75%); }
.fl-skel--meta { width: min(160px, 46%); }
@keyframes fl-shimmer { from { background-position: 200% 0; } to { background-position: -200% 0; } }
@media (prefers-reduced-motion: reduce) { .fl-skel { animation: none; } }

/* The one empty card: icon, title, and whatever call to action the caller adds under them. */
.fl-inv-empty {
  display: flex; flex-direction: column; align-items: center; gap: 12px;
  padding: 56px 20px; border: 1px solid var(--line); border-radius: 6px;
  background: var(--surface); text-align: center;
}
.fl-inv-emptyicon { color: var(--faint); font-size: 44px; }
.fl-inv-emptytitle { font-size: .98rem; font-weight: 700; }

/* A standalone loading / error / empty banner in its own card. Hosts that drop one inside a
   panel un-box it there with a more specific rule; the card is the free-standing default. */
.fl-state {
  min-height: 180px; display: flex; align-items: center; justify-content: center; gap: 10px;
  color: var(--muted); background: var(--surface); border: 1px solid var(--line-soft);
  border-radius: 8px; padding: 24px 16px; box-sizing: border-box;
}
.fl-state--error, .fl-state--empty, .fl-state--success { flex-direction: column; text-align: center; }
.fl-state--error { color: var(--error); }
.fl-state--empty .msr, .fl-state--success .msr { font-size: 42px; color: var(--brand); }
.fl-state--success .msr { color: var(--success); }

/* Announced to screen readers, painted for nobody — the skeleton above it is decorative. */
.fl-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;
}

.fl-li-pagelabel { font-size: .78rem; color: var(--muted); font-variant-numeric: tabular-nums; }
.fl-li-pagebtn {
  display: inline-flex; align-items: center; gap: 3px; height: 32px; padding: 0 10px;
  border: 1px solid var(--line); border-radius: var(--radius); background: var(--surface);
  color: var(--ink); font: inherit; font-size: .8rem; font-weight: 700; cursor: pointer;
}
.fl-li-pagebtn:hover:not(:disabled) { border-color: var(--brand); color: var(--brand); }
.fl-li-pagebtn:disabled { opacity: .45; cursor: default; }
.fl-li-pagebtn .msr { font-size: 18px; }
.fl-li-pagebtn:dir(rtl) .msr { transform: scaleX(-1); }
/* The header lays prev/next out by dir, but the ligature glyphs are fixed: mirror them in RTL. */
.fl-date-picker[dir="rtl"] .fl-date-head .fl-picker-icon .msr { transform: scaleX(-1); }
.fl-inv-pagerbar { display: flex; align-items: center; justify-content: space-between; gap: 12px 16px; margin-top: 18px; flex-wrap: wrap; }
.fl-inv-pagerbar--center { justify-content: center; }
.fl-inv-pagerbar--start { justify-content: flex-start; }
.fl-inv-pager { display: inline-flex; align-items: center; gap: 8px; }
.fl-inv-pagerange { color: var(--muted); }

.fl-password { position: relative; display: flex; }
.fl-password .fl-password-input { width: 100%; padding-inline-end: 44px; }
/* WebView2 adds a partial-eye button while typing. This library owns the single, always-present reveal
   control so password fields remain identical across WPF, browser and MAUI. */
.fl-password .fl-password-input::-ms-reveal { display: none; }
.fl-password-toggle {
  position: absolute; inset-inline-end: 4px; top: 50%; transform: translateY(-50%);
  display: grid; place-items: center; width: 36px; height: 36px; padding: 0;
  border: none; border-radius: 8px; background: transparent; color: var(--faint); cursor: pointer;
}
.fl-password-toggle:hover { color: var(--brand); }
.fl-password-toggle:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }
.fl-password-toggle:disabled { cursor: not-allowed; opacity: .55; }
.fl-password-toggle .msr { font-size: 19px; }

/* Money keeps the amount LTR while placing its currency after the figure in the page's reading
   direction. It lives with the reusable component so every consuming UI gets the same contract. */
.fl-money { display: inline-flex; align-items: baseline; gap: 5px; white-space: nowrap; direction: ltr; }
.fl-money:dir(rtl) { direction: rtl; }
.fl-money-value { font-variant-numeric: tabular-nums; }
.fl-money-cur { font-size: 0.72em; font-weight: 700; color: var(--faint); letter-spacing: 0.02em; }

/* DateTimePill — the shared read-only style for a moment: a date chip and an optional time chip,
   each a rounded pill with a leading icon. Sizes in em so it fits a 1.2rem header and a 0.8rem
   table row alike; colours come from host design tokens so it inherits each app's theme. The date
   figure is left in its content direction; the time is pinned LTR by the component. */
.fl-dtpill { display: inline-flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.fl-dtpill-part {
    display: inline-flex; align-items: center; gap: 5px;
    padding: 3px 9px; border-radius: 999px; white-space: nowrap;
    background: var(--surface-2); border: 1px solid var(--line);
    font-size: 0.82em; font-weight: 600; color: var(--muted);
}
.fl-dtpill-icon { font-size: 1.05em; color: var(--faint); }
.fl-dtpill-text { font-variant-numeric: tabular-nums; }

/* Numeric values are entered directly or through the app's explicit steppers, so FlNumberInput
   suppresses the native spinners. Scoped to the class that control renders and no wider: a bare
   `input[type=number]` selector would strip the spinners off every number field in the host,
   including ones written long before it referenced this library. Linking a control library must
   not change markup the library did not render. */
.fl-number { -moz-appearance: textfield; appearance: textfield; }
.fl-number::-webkit-outer-spin-button,
.fl-number::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }

/* A date range is structural only; its two fields retain the consuming feature's grid/flex layout. */
.fl-date-range { display: contents; }

/* Date and time use app-owned dialogs so WebView2, browser and MAUI render the same controls. */
.fl-date,
.fl-time { position: relative; min-width: 0; }
.fl-date-field,
.fl-time-field { position: relative; cursor: pointer; }
/* Geometry only. Field chrome — border, background, focus ring — is host-owned, so a host either
   passes its own field class through Class= or styles `.fl-date-field > input` itself. Painting
   it here would outrank a caller's single-class field style and override deliberately bare
   variants (inline filter fields, for instance). */
.fl-date-field > input,
.fl-time-field > input { width: 100%; padding-inline-end: 42px; box-sizing: border-box; cursor: pointer; }
.fl-date-trigger,
.fl-time-trigger {
  position: absolute; top: 50%; inset-inline-end: 5px; transform: translateY(-50%);
  display: grid; place-items: center; width: 32px; height: 32px; padding: 0;
  border: none; border-radius: 7px; background: transparent; color: var(--faint); cursor: pointer;
}
.fl-date-trigger:hover,
.fl-time-trigger:hover { background: var(--surface-2); color: var(--brand); }
.fl-date-trigger:focus-visible,
.fl-time-trigger:focus-visible,
.fl-picker-icon:focus-visible,
.fl-date-title:focus-visible,
.fl-date-day:focus-visible,
.fl-date-month:focus-visible,
.fl-date-year:focus-visible,
.fl-time-step:focus-visible,
.fl-time-period-button:focus-visible,
.fl-picker-action:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }
.fl-date-trigger:disabled,
.fl-time-trigger:disabled { color: var(--faint); cursor: not-allowed; opacity: .6; }
.fl-date-trigger .msr,
.fl-time-trigger .msr { font-size: 19px; }

.fl-picker-layer {
  position: fixed; inset: 0; z-index: 1000; display: grid; place-items: center;
  padding: 12px; box-sizing: border-box; overflow: auto;
  /* Lighter than the modal scrim on purpose: a picker is a transient layer over a field the user
     is still reading, not a mode. Neutral fallback, host-overridable through the token. */
  background: var(--fl-picker-scrim, rgb(15 23 42 / .18));
}
.fl-date-picker,
.fl-time-picker {
  width: min(328px, calc(100vw - 24px)); max-height: calc(100vh - 24px);
  width: min(328px, calc(100dvw - 24px)); max-height: calc(100dvh - 24px); overflow: auto;
  box-sizing: border-box; padding: 12px; background: var(--surface); color: var(--ink);
  border: 1px solid var(--line); border-radius: var(--radius); box-shadow: var(--shadow-lg);
  animation: fl-control-pop .13s ease backwards;
}
.fl-date-head {
  display: grid; grid-template-columns: 36px minmax(0, 1fr) 36px; align-items: center; gap: 4px;
  margin-bottom: 8px;
}
.fl-picker-icon,
.fl-date-title,
.fl-date-day,
.fl-date-month,
.fl-date-year,
.fl-time-step,
.fl-picker-action {
  border: none; background: transparent; color: inherit; font: inherit; cursor: pointer;
}
.fl-picker-icon { display: grid; place-items: center; width: 34px; height: 34px; border-radius: var(--radius); }
.fl-picker-icon:hover { background: var(--surface-2); color: var(--brand); }
.fl-date-title { min-width: 0; height: 34px; border-radius: var(--radius); font-size: .9rem; font-weight: 800; }
.fl-date-title:hover { background: var(--surface-2); color: var(--brand); }
.fl-date-weekdays,
.fl-date-days { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: 3px; direction: ltr; }
.fl-date-weekdays { margin-bottom: 3px; }
.fl-date-weekdays span {
  display: grid; place-items: center; height: 26px; color: var(--faint); font-size: .7rem; font-weight: 700;
}
.fl-date-day {
  position: relative; aspect-ratio: 1; min-width: 0; border-radius: 9px; font-size: .82rem; font-weight: 650;
}
.fl-date-day:hover:not(:disabled) { background: var(--surface-2); }
.fl-date-day--outside { color: var(--faint); opacity: .62; }
.fl-date-day:disabled,
.fl-date-month:disabled,
.fl-date-year:disabled { color: var(--faint); opacity: .35; cursor: not-allowed; }
.fl-date-months,
.fl-date-years { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 7px; min-height: 246px; }
.fl-date-month,
.fl-date-year { min-height: 52px; padding: 5px; border-radius: 10px; font-size: .82rem; font-weight: 700; }
.fl-date-month:hover:not(:disabled),
.fl-date-year:hover:not(:disabled) { background: var(--surface-2); }

/* Today/selected painting is declared *after* every generic hover rule above. The cell hover
   rules share its specificity, so anything selected-related declared earlier would lose the
   cascade to a later `:hover` and the fill would flip back mid-hover. Colours come from the
   host's --brand/--on-brand pair, so the label stays legible in whichever theme is mounted. */
.fl-date-day--today,
.fl-date-month--today,
.fl-date-year--today { box-shadow: inset 0 0 0 2px var(--brand); color: var(--brand); }
.fl-date-day--selected,
.fl-date-month--selected,
.fl-date-year--selected { background: var(--brand); color: var(--on-brand); box-shadow: none; }
.fl-date-day--selected:hover:not(:disabled),
.fl-date-month--selected:hover:not(:disabled),
.fl-date-year--selected:hover:not(:disabled) {
  background: var(--brand-strong, var(--brand)); color: var(--on-brand);
}
.fl-date-day--selected.fl-date-day--today,
.fl-date-month--selected.fl-date-month--today,
.fl-date-year--selected.fl-date-year--today {
  box-shadow: inset 0 0 0 2px var(--on-brand), 0 0 0 2px var(--brand);
}
/* Backstop for the out-of-bounds case. The picker normalizes its draft so a disabled cell should
   never be the selected one, but if a host's own Min/Max churn ever produces it the cell must read
   as disabled rather than as brand fill under the .35-opacity faint text, which has no contrast. */
.fl-date-day--selected:disabled,
.fl-date-month--selected:disabled,
.fl-date-year--selected:disabled {
  background: transparent; color: var(--faint);
  box-shadow: inset 0 0 0 1px var(--line);
}
.fl-picker-actions {
  display: flex; justify-content: flex-end; gap: 6px; margin-top: 10px; padding-top: 9px;
  border-top: 1px solid var(--line-soft);
}
/* Pushes Today to the leading edge and the Apply/Cancel pair to the trailing one without taking
   any of them out of DOM order. */
.fl-picker-spacer { flex: 1; }
.fl-picker-action { min-height: 34px; padding: 0 11px; border-radius: 8px; font-size: .8rem; font-weight: 750; }
.fl-picker-action:hover:not(:disabled) { background: var(--surface-2); }
.fl-picker-action--primary { color: var(--brand); }
.fl-picker-action:disabled { color: var(--faint); cursor: not-allowed; opacity: .45; }

.fl-time-picker {
  width: min(300px, calc(100vw - 24px));
  width: min(300px, calc(100vw - 24px));
  width: min(300px, calc(100dvw - 24px));
}
.fl-time-parts { display: grid; grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr) minmax(52px, .8fr); align-items: center; gap: 6px; }
.fl-time-part { display: grid; grid-template-rows: auto 28px 48px 28px; align-items: center; justify-items: stretch; }
.fl-time-label { color: var(--faint); font-size: .7rem; font-weight: 700; text-align: center; }
.fl-time-step { display: grid; place-items: center; min-width: 0; border-radius: 7px; color: var(--faint); }
.fl-time-step:hover { background: var(--surface-2); color: var(--brand); }
.fl-time-part input {
  width: 100%; height: 42px; box-sizing: border-box; padding: 0 4px; text-align: center;
  border: 1px solid var(--line); border-radius: 9px; background: var(--surface); color: var(--ink);
  font: inherit; font-size: 1rem; font-weight: 800; outline: none;
}
.fl-time-part input:focus { border-color: var(--brand); box-shadow: 0 0 0 3px var(--brand-tint); }
.fl-time-separator { padding-top: 24px; color: var(--faint); font-size: 1.15rem; font-weight: 800; }
.fl-time-period { display: grid; grid-template-rows: auto 38px 38px; align-items: center; gap: 5px; }
.fl-time-period-button {
  min-width: 0; height: 34px; padding: 0 8px; border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--surface); color: var(--faint); font: inherit; font-size: .78rem; font-weight: 800; cursor: pointer;
}
.fl-time-period-button:hover { border-color: var(--brand); color: var(--brand); }
.fl-time-period-button.is-active { border-color: var(--brand); background: var(--brand-tint); color: var(--brand); }

@media (max-height: 430px) {
  .fl-picker-layer { place-items: start center; overflow: auto; }
}

@keyframes fl-control-pop {
  from { opacity: 0; transform: scale(.96) translateY(6px); }
  to { opacity: 1; transform: scale(1) translateY(0); }
}

/* ---- FlOrderInput -------------------------------------------------------
   A three-part control (step down, value, step up) painted as one field, so it reads as a single
   input rather than a number box with browser spinners bolted on. The bounds are printed in the
   trailing slot: the limit is part of the control instead of something the user discovers by
   being rejected. */
.fl-order {
  display: inline-flex; align-items: center; gap: 2px; width: fit-content; max-width: 100%;
  height: 38px; padding: 3px; box-sizing: border-box;
  border: 1px solid var(--line); border-radius: var(--radius); background: var(--surface);
  transition: border-color .15s ease, box-shadow .15s ease;
}
.fl-order:focus-within { border-color: var(--brand); box-shadow: 0 0 0 3px var(--brand-tint); }
.fl-order--invalid { border-color: var(--error); }
.fl-order--invalid:focus-within { border-color: var(--error); box-shadow: 0 0 0 3px var(--error-bg); }
.fl-order--disabled { background: var(--disabled-bg); border-color: var(--disabled-border); }

.fl-order-step {
  flex: 0 0 auto; display: inline-flex; align-items: center; justify-content: center;
  width: 30px; height: 30px; padding: 0;
  border: 0; border-radius: calc(var(--radius) - 3px); background: var(--surface-2);
  color: var(--muted); cursor: pointer;
  transition: background .15s ease, color .15s ease;
}
.fl-order-step:hover:not(:disabled) { background: var(--brand-tint); color: var(--brand); }
.fl-order-step:disabled { opacity: .4; cursor: not-allowed; }
.fl-order-step .msr { font-size: 17px; }

.fl-order-value {
  flex: 0 0 auto; width: 3ch; min-width: 0; height: 30px; padding: 0 6px;
  border: 0; background: none; color: var(--ink);
  font: inherit; font-size: .9rem; font-weight: 750; font-variant-numeric: tabular-nums;
  text-align: center; outline: none;
}
.fl-order-value:disabled { color: var(--disabled-fg); }

@media (max-width: 430px) {
  .fl-order { max-width: none; }
}

/* ---- FlSwitchRow --------------------------------------------------------
   The whole row is the <label>, so the hit target is the panel width rather than the 13px
   checkbox — which is what makes this usable on a touch host. The real checkbox stays in the DOM
   (visually hidden, never display:none) so it keeps its focus ring, its Space/Enter behaviour and
   its role="switch" announcement; the track and knob below are only paint.

   .fl-switch is published on its own, not just as FlSwitchRow's internals: a host that needs the
   painted toggle inside row markup of its own composes the same track/knob structure directly.
   That is why these rules live here rather than in scoped component CSS — scoping them to
   FlSwitchRow would leave every other consumer with an unpainted checkbox. */
.fl-switch { flex-shrink: 0; display: inline-flex; cursor: pointer; }
/* The checkbox stays focusable and screen-reader visible; the track is the painted control. */
.fl-switch input { position: absolute; opacity: 0; width: 0; height: 0; }
.fl-switch-track {
  width: 44px; height: 26px; border-radius: 999px; background: var(--line);
  display: flex; align-items: center; padding: 3px; transition: background .16s ease;
}
.fl-switch-knob {
  width: 20px; height: 20px; border-radius: 50%; background: var(--surface);
  /* --shadow-sm is optional (see README). The fallback is what keeps the knob distinguishable
     from the track on a host that never declares it; hosts that paint flat set it to `none`. */
  box-shadow: var(--shadow-sm, 0 1px 2px rgb(15 23 42 / .18));
  transition: transform .16s ease;
}
.fl-switch input:checked + .fl-switch-track { background: var(--brand); }
.fl-switch input:checked + .fl-switch-track .fl-switch-knob { transform: translateX(18px); }
/* Logical direction: the knob must travel the other way in RTL. */
[dir="rtl"] .fl-switch input:checked + .fl-switch-track .fl-switch-knob { transform: translateX(-18px); }
.fl-switch input:focus-visible + .fl-switch-track { box-shadow: 0 0 0 3px var(--brand-tint); }
/* Declared after the :checked rules so a disabled switch reads as disabled in both states. The
   knob keeps its travel, so on/off is still legible while the control is unavailable. */
.fl-switch:has(input:disabled) { cursor: not-allowed; }
.fl-switch input:disabled + .fl-switch-track { background: var(--disabled-bg); }
.fl-switch input:disabled + .fl-switch-track .fl-switch-knob { background: var(--disabled-fg); }

/* No margin-top: the gap between this row and whatever sits above it belongs to the layout that
   places it, not to the row. Owning it here means the row cannot be put in a flex/grid container
   with its own gap, or first in a panel, without the host fighting a margin it did not ask for. */
.fl-switchrow {
  display: flex; align-items: center; gap: 12px;
  padding: 12px 14px; border: 1px solid var(--line); border-radius: 12px;
  background: var(--surface-2); cursor: pointer;
  transition: border-color .15s ease, background .15s ease;
}
.fl-switchrow:hover { border-color: var(--brand); }
/* The ring is drawn on the row, not the track: the row is the label, so that is what the user is
   actually operating when the hidden checkbox takes focus. */
.fl-switchrow:has(input:focus-visible) { border-color: var(--brand); box-shadow: 0 0 0 3px var(--brand-tint); }
.fl-switchrow--disabled { cursor: not-allowed; opacity: .6; }
.fl-switchrow--disabled:hover { border-color: var(--line); }
.fl-switchrow-text { flex: 1; min-width: 0; }
.fl-switchrow-title { display: block; font-size: .85rem; font-weight: 700; }
.fl-switchrow-desc { display: block; margin-top: 2px; color: var(--faint); font-size: .74rem; text-wrap: pretty; }
.fl-switchrow-state { flex-shrink: 0; color: var(--muted); font-size: .72rem; font-weight: 750; }
.fl-switchrow-state--on { color: var(--success); }

/* ---- ReorderableList ----------------------------------------------------
   Pointer Events provide one drag path for mouse, touch and pen. The JS keeps the DOM order
   authoritative to the caller, while these transforms shift neighbouring rows live to preview
   the insertion slot. */
.fl-reorder { display: flex; flex-direction: column; }
.fl-reorder-row {
  display: flex; align-items: center; gap: 10px; min-height: 62px; padding: 10px 14px;
  border-top: 1px solid var(--line-soft); background: var(--surface);
  transform: translateY(var(--fl-shift-y, 0));
  transition: transform .16s ease, background .12s ease, box-shadow .12s ease, opacity .12s ease;
}
.fl-reorder-row:first-child { border-top: 0; }
.fl-reorder-row--selected { background: var(--brand-tint-2); }
.fl-reorder-body { display: flex; align-items: center; gap: 10px; flex: 1; min-width: 0; }
.fl-reorder-handle {
  flex-shrink: 0; display: inline-flex; align-items: center; justify-content: center;
  width: 30px; height: 34px; border-radius: 6px; color: var(--faint);
  cursor: grab; touch-action: none; -webkit-user-select: none; user-select: none;
  -webkit-touch-callout: none; -webkit-tap-highlight-color: transparent;
}
.fl-reorder-handle:hover { background: var(--sunken); color: var(--muted); }
.fl-reorder-handle:focus-visible { outline: 2px solid var(--brand, currentColor); outline-offset: 1px; }
.fl-reorder-handle .msr { font-size: 20px; pointer-events: none; }
.fl-reorder--dragging { cursor: grabbing; }
.fl-reorder--dragging .fl-reorder-handle { cursor: grabbing; }
.fl-reorder[data-fl-reorder-disabled] .fl-reorder-handle { cursor: not-allowed; opacity: .4; }
.fl-reorder-row--dragging {
  position: relative; z-index: 6; background: var(--surface);
  border-radius: 10px; border-top-color: transparent;
  transform: translateY(var(--fl-drag-dy, 0));
  box-shadow: var(--fl-reorder-shadow, 0 16px 34px rgba(0, 0, 0, .22), 0 4px 10px rgba(0, 0, 0, .14));
  transition: none;
}
.fl-reorder--dragging .fl-reorder-row:not(.fl-reorder-row--dragging):not(.fl-reorder-row--before):not(.fl-reorder-row--after) { opacity: .5; }
.fl-reorder-row--before { box-shadow: inset 0 3px 0 0 var(--brand); }
.fl-reorder-row--after { box-shadow: inset 0 -3px 0 0 var(--brand); }

@media (max-width: 560px) {
  .fl-reorder-row { flex-wrap: wrap; min-height: 0; }
  .fl-reorder-body { flex-basis: 100%; order: 2; }
}

/* An open dialog must not let the page behind it scroll. */
body:has(.fl-modal-overlay) { overflow: hidden; }
