@charset "UTF-8";
/* ==========================================================================
   OFFTO Admin — Design System  ·  offto.css
   --------------------------------------------------------------------------
   Built from scratch. No Bootstrap. No Metronic. No framework.
   • Modern CSS: @layer, native nesting, oklch(), color-mix(), :has(),
     container queries, logical properties (free RTL), @property,
     @starting-style, popover + <dialog> styling, view-transition ready.
   • Light + Dark are two designed themes, not an inversion.
   • Direction-agnostic: uses margin-inline / inset-inline everywhere, so the
     same file serves ar (RTL) and en (LTR) with zero overrides.
   ========================================================================== */

@layer reset, tokens, base, layout, components, plugins, utilities;

/* ==========================================================================
   TOKENS
   ========================================================================== */
@layer tokens {

  /* Animatable custom properties -------------------------------------- */
  @property --ring-a { syntax: "<number>"; inherits: false; initial-value: 0; }
  @property --grad-a { syntax: "<angle>"; inherits: false; initial-value: 180deg; }

  :root {
    /* ---- Brand — taken from offto_new_logo.png ----------------------- */
    /* logo teal  #00B6BC   ·   logo ink  #2D3243                        */
    --brand:            oklch(58% 0.100 199);      /* actions: darkened teal, AA on white */
    --brand-strong:     oklch(50% 0.092 199);      /* hover                              */
    --brand-soft:       oklch(95% 0.030 199);
    --accent:           oklch(70.5% 0.120 199);    /* #00B6BC the logo teal itself       */
    --accent-strong:    oklch(62.5% 0.104 199);
    --accent-soft:      oklch(95% 0.035 199);
    --ink:              oklch(32% 0.031 272);      /* #2D3243 the logo wordmark colour   */
    --chart-2:          oklch(46% 0.078 272);      /* 2nd data series, ink family        */

    /* ---- Status ----------------------------------------------------- */
    --success:          oklch(62% 0.155 150);
    --success-soft:     oklch(95% 0.045 150);
    --warning:          oklch(75% 0.150 68);
    --warning-soft:     oklch(96% 0.055 78);
    --danger:           oklch(58% 0.205 20);
    --danger-soft:      oklch(95% 0.038 20);
    --info:             oklch(62% 0.130 240);
    --info-soft:        oklch(95% 0.035 240);

    /* ---- Neutral surfaces (light theme) ----------------------------- */
    --bg:               oklch(97.6% 0.005 272);
    --bg-grain:         oklch(96.2% 0.008 272);
    --surface:          oklch(100% 0 0);
    --surface-2:        oklch(98.4% 0.004 272);
    --surface-3:        oklch(96.4% 0.007 272);
    --surface-inset:    oklch(97% 0.006 272);
    --sidebar-bg:       oklch(100% 0 0);
    --topbar-bg:        color-mix(in oklab, var(--surface) 72%, transparent);

    --border:           oklch(91% 0.009 272);
    --border-soft:      oklch(94.5% 0.007 272);
    --border-strong:    oklch(85% 0.013 272);

    --text:             oklch(28% 0.030 272);      /* the logo ink */
    --text-2:           oklch(45% 0.026 272);
    --text-3:           oklch(60% 0.022 272);
    --text-inverse:     oklch(99% 0 0);

    /* ---- Elevation -------------------------------------------------- */
    --shadow-xs: 0 1px 2px oklch(32% 0.031 272 / .06);
    --shadow-sm: 0 1px 2px oklch(32% 0.031 272 / .06), 0 2px 6px oklch(32% 0.031 272 / .05);
    --shadow-md: 0 2px 4px oklch(32% 0.031 272 / .05), 0 8px 22px oklch(32% 0.031 272 / .08);
    --shadow-lg: 0 4px 8px oklch(32% 0.031 272 / .06), 0 18px 44px oklch(32% 0.031 272 / .12);
    --shadow-pop: 0 10px 34px oklch(32% 0.031 272 / .17), 0 2px 6px oklch(32% 0.031 272 / .08);
    --ring:      0 0 0 4px color-mix(in oklab, var(--brand) 18%, transparent);

    /* ---- Radii ------------------------------------------------------ */
    --r-xs: 7px;
    --r-sm: 10px;
    --r-md: 14px;
    --r-lg: 18px;
    --r-xl: 24px;
    --r-pill: 999px;

    /* ---- Type ------------------------------------------------------- */
    --font-sans: "IBM Plex Sans Arabic", ui-sans-serif, system-ui,
                 -apple-system, "Segoe UI", Roboto, sans-serif;
    --font-ar:   "IBM Plex Sans Arabic", ui-sans-serif, system-ui, sans-serif;
    --font-mono: ui-monospace, "JetBrains Mono", "SFMono-Regular", Menlo, monospace;
    --font-num:  "IBM Plex Sans Arabic", ui-sans-serif, system-ui, sans-serif;

    --fs-2xs: .6875rem;   /* 11 */
    --fs-xs:  .75rem;     /* 12 */
    --fs-sm:  .8125rem;   /* 13 */
    --fs-base:.875rem;    /* 14 */
    --fs-md:  .9375rem;   /* 15 */
    --fs-lg:  1.0625rem;  /* 17 */
    --fs-xl:  1.25rem;    /* 20 */
    --fs-2xl: 1.5rem;     /* 24 */
    --fs-3xl: clamp(1.6rem, 1.35rem + 1vw, 2rem);
    --fs-num: clamp(1.5rem, 1.2rem + 1vw, 1.9rem);

    /* ---- Layout metrics -------------------------------------------- */
    --sidebar-w: 272px;
    --sidebar-w-rail: 78px;
    --topbar-h: 66px;
    --page-max: 1560px;
    --gutter: clamp(1rem, .55rem + 1.4vw, 1.75rem);

    /* ---- Motion ----------------------------------------------------- */
    --ease: cubic-bezier(.32, .72, 0, 1);
    --ease-out: cubic-bezier(.16, 1, .3, 1);
    --t-fast: .14s;
    --t: .22s;
    --t-slow: .38s;

    color-scheme: light;
    accent-color: var(--brand);
  }

  /* ---- DARK THEME — a designed palette, not an inversion ------------ */
  :root[data-theme="dark"] {
    --brand:          oklch(72% 0.115 199);
    --brand-strong:   oklch(81% 0.105 199);
    --brand-soft:     oklch(33% 0.055 200);
    --accent:         oklch(84.5% 0.115 199);
    --accent-strong:  oklch(90% 0.095 199);
    --accent-soft:    oklch(33% 0.050 200);
    --ink:            oklch(88% 0.020 272);
    --chart-2:        oklch(80% 0.072 272);

    --success:        oklch(74% 0.150 152);
    --success-soft:   oklch(31% 0.060 152);
    --warning:        oklch(82% 0.140 74);
    --warning-soft:   oklch(33% 0.055 74);
    --danger:         oklch(70% 0.170 20);
    --danger-soft:    oklch(32% 0.070 20);
    --info:           oklch(72% 0.115 240);
    --info-soft:      oklch(32% 0.055 240);

    /* built on the logo ink #2D3243 */
    --bg:             oklch(19% 0.024 272);
    --bg-grain:       oklch(21% 0.026 272);
    --surface:        oklch(23.5% 0.028 272);
    --surface-2:      oklch(26.5% 0.029 272);
    --surface-3:      oklch(30% 0.030 272);
    --surface-inset:  oklch(21% 0.025 272);
    --sidebar-bg:     oklch(21.5% 0.026 272);
    --topbar-bg:      color-mix(in oklab, var(--surface) 66%, transparent);

    --border:         oklch(33.5% 0.026 272);
    --border-soft:    oklch(28.5% 0.024 272);
    --border-strong:  oklch(43% 0.028 272);

    --text:           oklch(95% 0.010 272);
    --text-2:         oklch(80% 0.014 272);
    --text-3:         oklch(66% 0.016 272);
    --text-inverse:   oklch(20% 0.028 272);

    --shadow-xs: 0 1px 2px oklch(0% 0 0 / .30);
    --shadow-sm: 0 1px 2px oklch(0% 0 0 / .32), 0 2px 6px oklch(0% 0 0 / .26);
    --shadow-md: 0 2px 6px oklch(0% 0 0 / .34), 0 10px 26px oklch(0% 0 0 / .34);
    --shadow-lg: 0 6px 14px oklch(0% 0 0 / .38), 0 22px 52px oklch(0% 0 0 / .46);
    --shadow-pop: 0 14px 40px oklch(0% 0 0 / .55), 0 2px 8px oklch(0% 0 0 / .4);
    --ring: 0 0 0 4px color-mix(in oklab, var(--brand) 26%, transparent);

    color-scheme: dark;
  }
}

/* ==========================================================================
   RESET
   ========================================================================== */
@layer reset {
  *, *::before, *::after { box-sizing: border-box; }

  * { margin: 0; padding: 0; }

  html {
    /* the off-canvas drawer sits translated outside the viewport; `clip` keeps it
       from creating a horizontal scrollbar without making a scroll container
       (so `position: sticky` on the topbar and sidebar keeps working) */
    overflow-x: clip;
    -webkit-text-size-adjust: 100%;
    text-size-adjust: 100%;
    scrollbar-color: var(--border-strong) transparent;
    scrollbar-width: thin;
  }

  body {
    min-height: 100dvh;
    font: 400 var(--fs-base)/1.55 var(--font-sans);
    color: var(--text);
    background: var(--bg);
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    text-rendering: optimizeLegibility;
  }

  :where(html[lang="ar"]) body { font-family: var(--font-ar); }

  img, svg, video, canvas { display: block; max-width: 100%; }
  svg { flex: none; }

  button, input, select, textarea, optgroup {
    font: inherit;
    color: inherit;
    background: none;
    border: 0;
  }
  button { cursor: pointer; }
  button:disabled, input:disabled, select:disabled, textarea:disabled { cursor: not-allowed; }

  a { color: var(--brand); text-decoration: none; }
  a:hover { color: var(--brand-strong); }

  ul, ol { list-style: none; }

  table { border-collapse: collapse; border-spacing: 0; }

  h1, h2, h3, h4, h5, h6 { font-weight: 700; line-height: 1.25; letter-spacing: -.014em; }

  :focus { outline: none; }
  :focus-visible {
    outline: 2px solid var(--brand);
    outline-offset: 2px;
    border-radius: var(--r-xs);
  }

  ::selection { background: color-mix(in oklab, var(--brand) 26%, transparent); }

  ::-webkit-scrollbar { width: 10px; height: 10px; }
  ::-webkit-scrollbar-track { background: transparent; }
  ::-webkit-scrollbar-thumb {
    background: color-mix(in oklab, var(--text-3) 40%, transparent);
    border: 3px solid transparent;
    border-radius: var(--r-pill);
    background-clip: content-box;
  }
  ::-webkit-scrollbar-thumb:hover { background: color-mix(in oklab, var(--text-3) 65%, transparent); background-clip: content-box; }

  [hidden] { display: none !important; }

  @media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
      animation-duration: .01ms !important;
      animation-iteration-count: 1 !important;
      transition-duration: .01ms !important;
      scroll-behavior: auto !important;
    }
  }
}

/* ==========================================================================
   BASE / TYPOGRAPHY HELPERS
   ========================================================================== */
@layer base {
  .h1 { font-size: var(--fs-3xl); font-weight: 800; letter-spacing: -.02em; }
  .h2 { font-size: var(--fs-2xl); font-weight: 750; }
  .h3 { font-size: var(--fs-xl);  font-weight: 700; }
  .h4 { font-size: var(--fs-lg);  font-weight: 700; }

  .lead   { font-size: var(--fs-md); color: var(--text-2); text-wrap: pretty; }
  .muted  { color: var(--text-3); }
  .soft   { color: var(--text-2); }
  .mono   { font-family: var(--font-mono); font-variant-numeric: tabular-nums; }
  .num    { font-variant-numeric: tabular-nums; font-feature-settings: "tnum" 1; letter-spacing: -.02em; }

  .eyebrow {
    font-size: var(--fs-2xs);
    font-weight: 700;
    letter-spacing: .09em;
    text-transform: uppercase;
    color: var(--text-3);
  }

  .link-quiet { color: var(--text-2); }
  .link-quiet:hover { color: var(--brand); }

  .icon { width: 1.25em; height: 1.25em; stroke-width: 1.75; }
  [data-icon] { display: inline-flex; align-items: center; flex: none; line-height: 0; }
  .icon-sm { width: 1em; height: 1em; }
  .icon-lg { width: 1.5em; height: 1.5em; }
  .icon-xl { width: 2em; height: 2em; }

  hr, .sep {
    border: 0;
    block-size: 1px;
    background: var(--border);
    margin-block: 1rem;
  }
  .sep-v {
    inline-size: 1px;
    align-self: stretch;
    background: var(--border);
    margin-inline: .25rem;
  }

  .sr-only {
    position: absolute; width: 1px; height: 1px;
    padding: 0; margin: -1px; overflow: hidden;
    clip-path: inset(50%); white-space: nowrap; border: 0;
  }
}

/* ==========================================================================
   LAYOUT — app shell
   ========================================================================== */
@layer layout {

  .app {
    --sb: var(--sidebar-w);
    display: grid;
    grid-template-columns: var(--sb) minmax(0, 1fr);
    min-height: 100dvh;
    background: var(--bg);
    transition: grid-template-columns var(--t) var(--ease);
  }
  .app[data-rail="true"] { --sb: var(--sidebar-w-rail); }

  /* ---------------- Sidebar ---------------- */
  .drawer-host { display: contents; }

  .sidebar {
    grid-area: 1 / 1;
    position: sticky;
    top: 0;
    height: 100dvh;
    display: flex;
    flex-direction: column;
    background: var(--sidebar-bg);
    border-inline-end: 1px solid var(--border);
    z-index: 40;
    overflow: clip;
  }

  .sidebar__brand {
    height: var(--topbar-h);
    flex: none;
    display: flex;
    align-items: center;
    gap: .7rem;
    padding-inline: 1.15rem;
    border-bottom: 1px solid var(--border-soft);
  }
  .brand-lockup { display: flex; align-items: center; gap: .65rem; min-width: 0; }
  .brand-lockup img { height: 27px; width: auto; }
  /* full wordmark: one per theme */
  /* the light/dark swap only worked inside .brand-lockup, so a logo used on
     its own (the standalone receipt page) rendered both files at once */
  :not(.brand-lockup) > .logo-dark { display: none; }
  :root[data-theme="dark"] :not(.brand-lockup) > .logo-light { display: none; }

  /* language-aware brand logos (official OFFTO artwork) */
  html[lang="ar"] .logo-en { display: none !important; }
  html:not([lang="ar"]) .logo-ar { display: none !important; }
  :root[data-theme="dark"] :not(.brand-lockup) > .logo-dark { display: block; }

  .brand-lockup .logo-full.logo-dark { display: none; }
  :root[data-theme="dark"] .brand-lockup .logo-full.logo-light { display: none; }
  :root[data-theme="dark"] .brand-lockup .logo-full.logo-dark { display: block; }
  /* the O + chevron mark is only for the collapsed rail */
  .brand-lockup .logo-mark,
  :root[data-theme="dark"] .brand-lockup .logo-mark { display: none; height: 26px; }
  .brand-mark {
    inline-size: 34px; block-size: 34px;
    flex: none;
    display: grid; place-items: center;
    border-radius: 11px;
    color: #fff;
    font-weight: 800;
    font-size: var(--fs-sm);
    letter-spacing: -.03em;
    background: var(--brand);
    box-shadow: 0 4px 12px color-mix(in oklab, var(--brand) 34%, transparent);
  }
  .brand-word { display: flex; flex-direction: column; line-height: 1.05; min-width: 0; }
  .brand-word b { font-size: var(--fs-md); font-weight: 800; letter-spacing: -.02em; }
  .brand-word span { font-size: var(--fs-2xs); color: var(--text-3); font-weight: 600; letter-spacing: .06em; text-transform: uppercase; }

  .sidebar__scroll {
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    overscroll-behavior: contain;
    padding: .85rem .7rem 1.2rem;
    scrollbar-width: thin;
  }

  .sidebar__foot {
    flex: none;
    padding: .7rem;
    border-top: 1px solid var(--border-soft);
    background: var(--sidebar-bg);
  }

  /* ---- nav ---- */
  .nav-group + .nav-group { margin-top: .35rem; }
  .nav-label {
    padding: .9rem .75rem .4rem;
    font-size: var(--fs-2xs);
    font-weight: 700;
    letter-spacing: .1em;
    text-transform: uppercase;
    color: var(--text-3);
    white-space: nowrap;
  }

  .nav-link {
    position: relative;
    display: flex;
    align-items: center;
    gap: .7rem;
    padding: .58rem .7rem;
    border-radius: var(--r-sm);
    color: var(--text-2);
    font-size: var(--fs-base);
    font-weight: 550;
    white-space: nowrap;
    transition: background var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
  }
  .nav-link > :is(.icon, [data-icon]) { color: var(--text-3); transition: color var(--t-fast) var(--ease); }
  .nav-link:hover { background: var(--surface-3); color: var(--text); }
  .nav-link:hover > :is(.icon, [data-icon]) { color: var(--brand); }

  .nav-link[aria-current="page"],
  .nav-link.is-active {
    background: color-mix(in oklab, var(--brand) 12%, transparent);
    color: var(--brand-strong);
    font-weight: 700;
  }
  :root[data-theme="dark"] .nav-link[aria-current="page"],
  :root[data-theme="dark"] .nav-link.is-active { color: var(--brand-strong); }
  .nav-link[aria-current="page"] > :is(.icon, [data-icon]),
  .nav-link.is-active > :is(.icon, [data-icon]) { color: var(--brand); }
  .nav-link[aria-current="page"]::before,
  .nav-link.is-active::before {
    content: "";
    position: absolute;
    inset-inline-start: -.7rem;
    inset-block: 20%;
    inline-size: 3px;
    border-start-end-radius: 3px;
    border-end-end-radius: 3px;
    background: var(--brand);
  }

  .nav-link__text { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; }

  .nav-caret {
    inline-size: 1rem; block-size: 1rem;
    color: var(--text-3);
    transition: transform var(--t) var(--ease);
  }
  .nav-parent[aria-expanded="true"] .nav-caret { transform: rotate(90deg); }
  html[dir="rtl"] .nav-caret { transform: scaleX(-1); }
  html[dir="rtl"] .nav-parent[aria-expanded="true"] .nav-caret { transform: scaleX(-1) rotate(-90deg); }

  .nav-parent { inline-size: 100%; text-align: start; }

  .nav-sub {
    display: grid;
    grid-template-rows: 0fr;
    transition: grid-template-rows var(--t) var(--ease);
  }
  .nav-sub > div { overflow: hidden; }
  .nav-parent[aria-expanded="true"] + .nav-sub { grid-template-rows: 1fr; }

  .nav-sub .nav-link {
    padding-inline-start: 2.6rem;
    font-size: var(--fs-sm);
    font-weight: 500;
    color: var(--text-3);
  }
  .nav-sub .nav-link::after {
    content: "";
    position: absolute;
    inset-inline-start: 1.42rem;
    inline-size: 5px; block-size: 5px;
    border-radius: 50%;
    background: var(--border-strong);
    transition: background var(--t-fast) var(--ease), transform var(--t-fast) var(--ease);
  }
  .nav-sub .nav-link:hover { color: var(--text); }
  .nav-sub .nav-link:hover::after { background: var(--brand); }
  .nav-sub .nav-link[aria-current="page"] { background: transparent; color: var(--brand-strong); font-weight: 700; }
  .nav-sub .nav-link[aria-current="page"]::before { content: none; }
  .nav-sub .nav-link[aria-current="page"]::after { background: var(--brand); transform: scale(1.5); }

  .nav-pill {
    margin-inline-start: auto;
    font-size: var(--fs-2xs);
    font-weight: 700;
    padding: .1rem .42rem;
    border-radius: var(--r-pill);
    background: var(--danger-soft);
    color: var(--danger);
  }

  /* ---- rail (collapsed) mode — desktop only, expands on hover ---- */
  @media (min-width: 1100px) {
    .app[data-rail="true"] .sidebar:not(:hover) {
      .nav-label, .brand-word, .nav-link__text, .nav-caret, .nav-pill,
      .sb-card, .sb-user__meta, .sb-user > [data-icon] { display: none; }
      .nav-link { justify-content: center; padding-inline: 0; }
      .nav-sub { display: none; }
      .sidebar__brand { justify-content: center; padding-inline: 0; }
      .sb-user { justify-content: center; }
    }
    .app[data-rail="true"] .sidebar:not(:hover) .brand-lockup .logo-full { display: none; }
    .app[data-rail="true"] .sidebar:not(:hover) .brand-lockup .logo-mark.logo-light { display: block; }
    :root[data-theme="dark"] .app[data-rail="true"] .sidebar:not(:hover) .brand-lockup .logo-mark.logo-light { display: none; }
    :root[data-theme="dark"] .app[data-rail="true"] .sidebar:not(:hover) .brand-lockup .logo-mark.logo-dark { display: block; }
    .app[data-rail="true"] .sidebar:hover {
      inline-size: var(--sidebar-w);
      box-shadow: var(--shadow-lg);
    }
  }

  /* ---------------- Main column ---------------- */
  .main { grid-area: 1 / 2; min-width: 0; display: flex; flex-direction: column; }

  .topbar {
    position: sticky;
    top: 0;
    z-index: 30;
    height: var(--topbar-h);
    flex: none;
    display: flex;
    align-items: center;
    gap: .5rem;
    padding-inline: var(--gutter);
    background: var(--topbar-bg);
    backdrop-filter: blur(14px) saturate(180%);
    -webkit-backdrop-filter: blur(14px) saturate(180%);
    border-bottom: 1px solid var(--border-soft);
  }
  .topbar__spacer { flex: 1; }

  /* command-palette trigger: a wide field on desktop, an icon button on phones */
  .topbar__search {
    min-inline-size: 14rem;
    justify-content: flex-start;
    gap: .5rem;
    color: var(--text-3);
  }
  @media (max-width: 860px) { .topbar__search { min-inline-size: 0; } .topbar__search kbd { display: none; } }
  @media (max-width: 720px) {
    .topbar { gap: .3rem; padding-inline: .75rem; }
    .topbar__search { inline-size: 2.1rem; padding-inline: 0; justify-content: center; }
    .topbar__search-label { display: none; }
  }

  .page {
    flex: 1;
    inline-size: 100%;
    max-inline-size: var(--page-max);
    margin-inline: auto;
    padding: clamp(1rem, .5rem + 1vw, 1.6rem) var(--gutter) 3rem;
    container-type: inline-size;
    container-name: page;
  }

  .page-head {
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 1rem;
    margin-bottom: 1.15rem;
  }
  .page-head__title { display: flex; flex-direction: column; gap: .3rem; min-width: 0; }
  .page-head h1 { font-size: var(--fs-2xl); font-weight: 800; letter-spacing: -.022em; }
  .page-head__actions { display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; }

  .breadcrumb { display: flex; align-items: center; gap: .3rem; flex-wrap: wrap; font-size: var(--fs-sm); }
  .breadcrumb a { color: var(--text-3); font-weight: 550; }
  .breadcrumb a:hover { color: var(--brand); }
  .breadcrumb [aria-current] { color: var(--text-2); font-weight: 650; }
  .breadcrumb .icon { inline-size: .85rem; block-size: .85rem; color: var(--text-3); opacity: .7; }
  html[dir="rtl"] .breadcrumb .icon { transform: scaleX(-1); }

  /* ---------------- Grid helpers ---------------- */
  /* the default single column is `minmax(0, 1fr)`, not `auto`: an implicit
     `auto` track is sized by its widest child, so one wide table or tab strip
     used to blow the whole page out sideways on a phone. */
  .grid { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--grid-gap, 1rem); }
  .cols-1 { grid-template-columns: minmax(0, 1fr); }
  .cols-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .cols-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .cols-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  .cols-auto { grid-template-columns: repeat(auto-fill, minmax(min(100%, 250px), 1fr)); }
  .span-2 { grid-column: span 2; }
  .span-3 { grid-column: span 3; }
  .span-full { grid-column: 1 / -1; }

  @container page (max-width: 1080px) {
    .cols-4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .cols-3 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .span-3 { grid-column: span 2; }
  }
  @container page (max-width: 640px) {
    .cols-2, .cols-3, .cols-4 { grid-template-columns: minmax(0, 1fr); }
    .span-2, .span-3 { grid-column: span 1; }
  }

  /* ---------------- Mobile drawer ---------------- */
  .sidebar__close { display: none; }
  .topbar__burger { display: none; }
  .scrim {
    position: fixed;
    inset: 0;
    z-index: 39;
    background: oklch(16% .03 272 / .5);
    backdrop-filter: blur(2px);
    opacity: 0;
    pointer-events: none;
    transition: opacity var(--t) var(--ease);
  }

  @media (max-width: 1099px) {
    .app { grid-template-columns: minmax(0, 1fr); }
    .main { grid-area: 1 / 1; }

    /* a viewport-sized clipping layer: the drawer slides inside it, so the page
       itself never gains scrollable overflow (and sticky keeps working) */
    .drawer-host {
      display: block;
      position: fixed;
      inset: 0;
      z-index: 40;
      overflow: clip;
      pointer-events: none;
    }
    .sidebar {
      position: absolute;
      inset-block: 0;
      inset-inline-start: 0;
      inline-size: min(86vw, var(--sidebar-w));
      transform: translateX(calc(var(--rtl, -1) * 100%));
      transition: transform var(--t-slow) var(--ease);
      box-shadow: var(--shadow-lg);
      pointer-events: auto;
    }
    html[dir="rtl"] .sidebar { --rtl: 1; }
    .scrim { position: absolute; }
    .app[data-drawer="open"] .scrim { pointer-events: auto; }
    .app[data-drawer="open"] .sidebar { transform: none; }
    .app[data-drawer="open"] .scrim { opacity: 1; pointer-events: auto; }
    .topbar__burger { display: inline-flex; }
    .sidebar__close { display: inline-flex; margin-inline-start: auto; }
  }
}

/* ==========================================================================
   COMPONENTS
   ========================================================================== */
@layer components {

  /* ---------------------------------------------------------------- BUTTON */
  .btn {
    --btn-bg: var(--surface);
    --btn-fg: var(--text);
    --btn-bd: var(--border);
    --btn-h: 2.5rem;
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: .45rem;
    block-size: var(--btn-h);
    padding-inline: .95rem;
    border-radius: var(--r-sm);
    border: 1px solid var(--btn-bd);
    background: var(--btn-bg);
    color: var(--btn-fg);
    font-size: var(--fs-base);
    font-weight: 650;
    line-height: 1;
    white-space: nowrap;
    user-select: none;
    box-shadow: var(--shadow-xs);
    transition: background var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease),
                color var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease),
                transform var(--t-fast) var(--ease);
  }
  .btn:hover { background: var(--surface-3); color: var(--text); }
  .btn:active { transform: translateY(1px); box-shadow: none; }
  .btn:focus-visible { box-shadow: var(--ring); outline: none; }
  .btn:disabled, .btn[aria-disabled="true"] { opacity: .5; pointer-events: none; }
  .btn > .icon, .btn > [data-icon] > .icon { inline-size: 1.05rem; block-size: 1.05rem; }

  .btn-primary {
    --btn-bg: var(--brand);
    --btn-fg: #fff;
    --btn-bd: transparent;
    box-shadow: 0 1px 2px color-mix(in oklab, var(--brand) 30%, transparent),
                0 6px 16px color-mix(in oklab, var(--brand) 24%, transparent);
  }
  .btn-primary:hover { --btn-bg: var(--brand-strong); color: #fff; }
  :root[data-theme="dark"] .btn-primary { --btn-fg: oklch(20% .028 272); }
  :root[data-theme="dark"] .btn-primary:hover { color: oklch(17% .028 272); }

  .btn-accent {
    --btn-bg: var(--accent-strong);
    --btn-fg: oklch(22% .04 199);
    --btn-bd: transparent;
    box-shadow: 0 1px 2px color-mix(in oklab, var(--accent) 34%, transparent),
                0 6px 16px color-mix(in oklab, var(--accent) 26%, transparent);
  }
  .btn-accent:hover { --btn-bg: var(--accent); color: oklch(20% .04 199); }

  .btn-dark { --btn-bg: var(--text); --btn-fg: var(--surface); --btn-bd: transparent; }
  .btn-dark:hover { --btn-bg: color-mix(in oklab, var(--text) 88%, var(--surface)); color: var(--surface); }

  .btn-ghost { --btn-bg: transparent; --btn-bd: transparent; --btn-fg: var(--text-2); box-shadow: none; }
  .btn-ghost:hover { background: var(--surface-3); color: var(--text); }

  .btn-outline { --btn-bg: transparent; --btn-bd: var(--border-strong); box-shadow: none; }
  .btn-outline:hover { background: var(--surface-3); }

  /* tinted variants */
  .btn-soft            { --btn-bd: transparent; box-shadow: none; }
  .btn-soft.is-primary { --btn-bg: color-mix(in oklab, var(--brand) 13%, transparent);   --btn-fg: var(--brand-strong); }
  .btn-soft.is-success { --btn-bg: color-mix(in oklab, var(--success) 15%, transparent); --btn-fg: var(--success); }
  .btn-soft.is-warning { --btn-bg: color-mix(in oklab, var(--warning) 18%, transparent); --btn-fg: color-mix(in oklab, var(--warning) 78%, var(--text)); }
  .btn-soft.is-danger  { --btn-bg: color-mix(in oklab, var(--danger) 14%, transparent);  --btn-fg: var(--danger); }
  .btn-soft.is-info    { --btn-bg: color-mix(in oklab, var(--info) 14%, transparent);    --btn-fg: var(--info); }
  .btn-soft:hover      { filter: brightness(.97) saturate(1.1); }
  :root[data-theme="dark"] .btn-soft:hover { filter: brightness(1.14); }

  .btn-danger { --btn-bg: var(--danger); --btn-fg: #fff; --btn-bd: transparent; }
  .btn-danger:hover { --btn-bg: color-mix(in oklab, var(--danger) 86%, black); color: #fff; }

  .btn-sm  { --btn-h: 2.1rem; padding-inline: .7rem;  font-size: var(--fs-sm); border-radius: var(--r-xs); }
  .btn-xs  { --btn-h: 1.75rem; padding-inline: .55rem; font-size: var(--fs-xs); border-radius: var(--r-xs); gap: .3rem; }
  .btn-lg  { --btn-h: 2.9rem; padding-inline: 1.35rem; font-size: var(--fs-md); border-radius: var(--r-md); }

  .btn-icon { padding-inline: 0; inline-size: var(--btn-h); }
  .btn-pill { border-radius: var(--r-pill); }
  .btn-block { inline-size: 100%; }

  /* loading */
  .btn[data-loading="true"] { color: transparent !important; pointer-events: none; }
  .btn[data-loading="true"] > * { visibility: hidden; }
  .btn[data-loading="true"]::after {
    content: "";
    position: absolute;
    inset-block-start: 50%; inset-inline-start: 50%;
    inline-size: 1.05rem; block-size: 1.05rem;
    margin: -.525rem 0 0 -.525rem;
    border: 2px solid color-mix(in oklab, currentColor 30%, transparent);
    border-top-color: var(--btn-fg);
    border-radius: 50%;
    animation: spin .7s linear infinite;
    visibility: visible;
  }
  @keyframes spin { to { transform: rotate(360deg); } }

  .btn-group { display: inline-flex; }
  .btn-group > .btn { border-radius: 0; margin-inline-start: -1px; box-shadow: none; }
  .btn-group > .btn:first-child { border-start-start-radius: var(--r-sm); border-end-start-radius: var(--r-sm); margin-inline-start: 0; }
  .btn-group > .btn:last-child  { border-start-end-radius: var(--r-sm);  border-end-end-radius: var(--r-sm); }
  .btn-group > .btn:hover { z-index: 1; }

  /* icon-only action buttons used inside tables */
  .act {
    --btn-h: 1.95rem;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    inline-size: 1.95rem;
    block-size: 1.95rem;
    border: 1px solid transparent;
    cursor: pointer;
    padding: 0;
    transition: background var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
    border-radius: 9px;
    background: var(--surface-3);
    border-color: transparent;
    color: var(--text-2);
    box-shadow: none;
  }
  .act:hover { background: color-mix(in oklab, var(--brand) 14%, transparent); color: var(--brand-strong); }
  .act.is-danger:hover  { background: color-mix(in oklab, var(--danger) 15%, transparent);  color: var(--danger); }
  .act.is-success:hover { background: color-mix(in oklab, var(--success) 16%, transparent); color: var(--success); }
  .act.is-warning:hover { background: color-mix(in oklab, var(--warning) 20%, transparent); color: color-mix(in oklab, var(--warning) 80%, var(--text)); }
  .act > .icon { inline-size: .95rem; block-size: .95rem; }
  .act-row { display: inline-flex; gap: .28rem; }

  /* ------------------------------------------------------------------ CARD */
  .card {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--r-lg);
    box-shadow: var(--shadow-sm);
    overflow: clip;
  }
  .card-hd {
    display: flex;
    align-items: center;
    gap: .75rem;
    flex-wrap: wrap;
    padding: 1rem 1.15rem;
    border-bottom: 1px solid var(--border-soft);
  }
  /* the title block takes the slack so a long sub-title wraps inside it
     instead of pushing the icon onto a line of its own */
  .card-hd > div:not([class]) { flex: 1 1 8rem; min-inline-size: 0; }
  /* a control that belongs to the whole card (Add row, Expand all) sits at
     the trailing end of its header rather than floating above the body */
  .card-hd__actions {
    margin-inline-start: auto;
    display: flex; align-items: center; gap: .5rem; flex-wrap: wrap;
  }
  .card-hd h2, .card-hd h3 { font-size: var(--fs-md); font-weight: 750; letter-spacing: -.012em; }
  .card-hd__sub { font-size: var(--fs-xs); color: var(--text-3); font-weight: 500; }
  .card-hd__tools { margin-inline-start: auto; display: flex; align-items: center; gap: .45rem; flex-wrap: wrap; }
  .card-bd { padding: 1.15rem; }
  .card-bd.is-flush { padding: 0; }
  .card-ft {
    padding: .9rem 1.15rem;
    border-top: 1px solid var(--border-soft);
    background: var(--surface-2);
    display: flex;
    align-items: center;
    gap: .6rem;
    flex-wrap: wrap;
  }
  .card-icon {
    inline-size: 2.1rem; block-size: 2.1rem;
    display: grid; place-items: center;
    border-radius: 10px;
    background: color-mix(in oklab, var(--brand) 12%, transparent);
    color: var(--brand);
  }

  /* ------------------------------------------------------------- STAT TILE */
  .stat {
    position: relative;
    display: flex;
    flex-direction: column;
    gap: .55rem;
    padding: 1.05rem 1.15rem 1.1rem;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--r-lg);
    box-shadow: var(--shadow-sm);
    overflow: clip;
    transition: transform var(--t) var(--ease), box-shadow var(--t) var(--ease), border-color var(--t) var(--ease);
  }
  .stat::after {
    content: "";
    position: absolute;
    inset-block-start: 0;
    inset-inline: 0;
    block-size: 3px;
    background: var(--stat-accent, var(--brand));
    opacity: .9;
  }
  a.stat, .stat[href] { color: inherit; }
  .stat:hover { transform: translateY(-2px); box-shadow: var(--shadow-md); border-color: var(--border-strong); }
  .stat__top { display: flex; align-items: center; gap: .6rem; }
  .stat__ico {
    inline-size: 2.2rem; block-size: 2.2rem;
    display: grid; place-items: center;
    border-radius: 11px;
    background: color-mix(in oklab, var(--stat-accent, var(--brand)) 14%, transparent);
    color: var(--stat-accent, var(--brand));
  }
  .stat__label { font-size: var(--fs-sm); font-weight: 650; color: var(--text-2); }
  .stat__value {
    font-size: var(--fs-num);
    font-weight: 800;
    letter-spacing: -.03em;
    font-variant-numeric: tabular-nums;
    line-height: 1.1;
  }
  .stat__foot { display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; font-size: var(--fs-xs); color: var(--text-3); }
  .stat--brand   { --stat-accent: var(--brand); }
  .stat--accent  { --stat-accent: var(--accent-strong); }
  .stat--success { --stat-accent: var(--success); }
  .stat--warning { --stat-accent: var(--warning); }
  .stat--danger  { --stat-accent: var(--danger); }
  .stat--info    { --stat-accent: var(--info); }

  .delta {
    display: inline-flex; align-items: center; gap: .18rem;
    font-size: var(--fs-xs); font-weight: 750;
    padding: .13rem .42rem;
    border-radius: var(--r-pill);
    font-variant-numeric: tabular-nums;
  }
  .delta.is-up   { background: color-mix(in oklab, var(--success) 16%, transparent); color: var(--success); }
  .delta.is-down { background: color-mix(in oklab, var(--danger) 15%, transparent);  color: var(--danger); }
  .delta.is-flat { background: var(--surface-3); color: var(--text-3); }
  .delta .icon { inline-size: .8rem; block-size: .8rem; }

  .spark { inline-size: 100%; block-size: 38px; overflow: visible; }

  /* ----------------------------------------------------------- BADGE / DOT */
  .badge {
    display: inline-flex; align-items: center; gap: .3rem;
    padding: .2rem .55rem;
    border-radius: var(--r-pill);
    font-size: var(--fs-xs);
    font-weight: 700;
    line-height: 1.35;
    background: var(--surface-3);
    color: var(--text-2);
    white-space: nowrap;
  }
  .badge.is-primary { background: color-mix(in oklab, var(--brand) 13%, transparent);   color: var(--brand-strong); }
  .badge.is-success { background: color-mix(in oklab, var(--success) 16%, transparent); color: var(--success); }
  .badge.is-warning { background: color-mix(in oklab, var(--warning) 20%, transparent); color: color-mix(in oklab, var(--warning) 76%, var(--text)); }
  .badge.is-danger  { background: color-mix(in oklab, var(--danger) 14%, transparent);  color: var(--danger); }
  .badge.is-info    { background: color-mix(in oklab, var(--info) 14%, transparent);    color: var(--info); }
  .badge.is-accent  { background: color-mix(in oklab, var(--accent) 20%, transparent);  color: var(--accent-strong); }
  .badge.is-outline { background: transparent; border: 1px solid var(--border-strong); color: var(--text-2); }

  .dot { inline-size: .45rem; block-size: .45rem; border-radius: 50%; background: currentColor; flex: none; }
  .status {
    display: inline-flex; align-items: center; gap: .4rem;
    font-size: var(--fs-sm); font-weight: 650;
  }
  .status.is-on  { color: var(--success); }
  .status.is-off { color: var(--text-3); }
  .status.is-warn { color: var(--warning); }
  .status.is-bad { color: var(--danger); }
  .status .dot { box-shadow: 0 0 0 3px color-mix(in oklab, currentColor 18%, transparent); }

  .pulse { position: relative; }
  .pulse::after {
    content: "";
    position: absolute;
    inset: -3px;
    border-radius: inherit;
    border: 1.5px solid var(--brand);
    animation: pulse-ring 1.8s var(--ease-out) infinite;
  }
  @keyframes pulse-ring {
    0%   { opacity: .55; transform: scale(.9); }
    100% { opacity: 0;   transform: scale(1.45); }
  }

  /* ---------------------------------------------------------------- AVATAR */
  .avatar {
    inline-size: 2.25rem; block-size: 2.25rem;
    border-radius: 50%;
    display: grid; place-items: center;
    flex: none;
    overflow: hidden;
    background: color-mix(in oklab, var(--brand) 22%, var(--surface-3));
    color: var(--brand-strong);
    font-weight: 800;
    font-size: var(--fs-sm);
    letter-spacing: -.02em;
    border: 1px solid var(--border);
  }
  .avatar img { inline-size: 100%; block-size: 100%; object-fit: cover; }
  .avatar-sm { inline-size: 1.75rem; block-size: 1.75rem; font-size: var(--fs-2xs); }
  .avatar-lg { inline-size: 3rem; block-size: 3rem; font-size: var(--fs-md); }
  .avatar-sq { border-radius: 11px; }

  /* ----------------------------------------------------------------- FORMS */
  .field { display: flex; flex-direction: column; gap: .35rem; min-width: 0; }
  .label {
    font-size: var(--fs-sm);
    font-weight: 650;
    color: var(--text-2);
    display: flex; align-items: center; gap: .25rem;
  }
  .label .req { color: var(--danger); font-weight: 800; }
  .hint { font-size: var(--fs-xs); color: var(--text-3); }
  .err  { font-size: var(--fs-xs); color: var(--danger); font-weight: 600; display: none; }

  .input, .select, .textarea {
    inline-size: 100%;
    min-block-size: 2.6rem;
    padding: .58rem .8rem;
    border-radius: var(--r-sm);
    border: 1px solid var(--border);
    background: var(--surface);
    color: var(--text);
    font-size: var(--fs-base);
    transition: border-color var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease), background var(--t-fast) var(--ease);
  }
  .input[type="search"] { appearance: none; -webkit-appearance: none; }
  .input[type="search"]::-webkit-search-decoration,
  .input[type="search"]::-webkit-search-cancel-button { -webkit-appearance: none; }
  .input::placeholder, .textarea::placeholder { color: var(--text-3); opacity: .85; }
  .input:hover, .select:hover, .textarea:hover { border-color: var(--border-strong); }
  .input:focus, .select:focus, .textarea:focus {
    border-color: var(--brand);
    box-shadow: var(--ring);
    background: var(--surface);
  }
  .input:disabled, .select:disabled, .textarea:disabled { background: var(--surface-3); color: var(--text-3); }
  .textarea { min-block-size: 6.5rem; resize: vertical; line-height: 1.6; }
  .input.is-invalid, .select.is-invalid, .textarea.is-invalid { border-color: var(--danger); }
  .field:has(.is-invalid) .err { display: block; }

  /* Metronic's filled variant, kept on ~290 migrated controls. Our forms use
     outlined fields, so a grey box next to a white one just looked broken —
     it is neutralised rather than removed from the markup. */
  .input-solid { background: var(--surface); border-color: var(--border); }
  .input-solid:focus { background: var(--surface); border-color: var(--brand); }

  /* The native dropdown list is painted by the OS, and an <option> with no
     background of its own falls back to the SYSTEM palette rather than the
     page's — so a dark-mode page on a light OS (or the reverse) renders the
     list inverted: light text on a light sheet. Paint the options with the
     theme's own colours so the list always matches the page. */
  option, optgroup {
    background-color: var(--surface);
    color: var(--text);
  }
  optgroup { color: var(--text-3); font-weight: 700; }
  option:checked, option[selected] {
    background-color: color-mix(in oklab, var(--brand) 18%, var(--surface));
    color: var(--text);
  }
  option:disabled { color: var(--text-3); }

  .select {
    appearance: none;
    padding-inline-end: 2.2rem;
    background-image: linear-gradient(45deg, transparent 50%, currentColor 50%),
                      linear-gradient(135deg, currentColor 50%, transparent 50%);
    background-position: calc(100% - 1.05rem) 1.15rem, calc(100% - .72rem) 1.15rem;
    background-size: 5px 5px, 5px 5px;
    background-repeat: no-repeat;
    color: var(--text);
  }
  html[dir="rtl"] .select {
    background-position: 1.05rem 1.15rem, .72rem 1.15rem;
    background-image: linear-gradient(135deg, currentColor 50%, transparent 50%),
                      linear-gradient(45deg, transparent 50%, currentColor 50%);
  }

  /* input with leading / trailing adornment */
  .input-wrap { position: relative; display: flex; align-items: center; inline-size: 100%; }
  .input-wrap > :is(.icon, [data-icon]) {
    position: absolute;
    inset-inline-start: .72rem;
    inline-size: 1.05rem; block-size: 1.05rem;
    color: var(--text-3);
    pointer-events: none;
    z-index: 1;
  }
  .input-wrap:focus-within > :is(.icon, [data-icon]) { color: var(--brand); }
  .input-wrap > .input { padding-inline-start: 2.4rem; }
  .input-wrap > .input-tail {
    position: absolute;
    inset-inline-end: .4rem;
    display: flex; align-items: center; gap: .2rem;
  }
  .input-wrap:has(.input-tail) > .input { padding-inline-end: 2.6rem; }

  /* a wrap whose only decoration is a trailing button (password reveal) —
     the leading padding rule above must not apply to it */
  .input-wrap.is-trailing > .input { padding-inline-start: .8rem; padding-inline-end: 2.6rem; }
  .input-wrap__btn {
    position: absolute;
    inset-inline-end: .35rem;
    inline-size: 1.9rem; block-size: 1.9rem;
    display: grid; place-items: center;
    border-radius: var(--r-sm);
    color: var(--text-3);
    cursor: pointer;
    transition: color var(--t-fast) var(--ease), background var(--t-fast) var(--ease);
  }
  .input-wrap__btn:hover { color: var(--text); background: var(--surface-3); }
  .input-wrap__btn[aria-pressed="true"] { color: var(--brand); }

  .input-group { display: flex; align-items: stretch; }
  .input-group > .input:not(:first-child), .input-group > .select:not(:first-child) { border-start-start-radius: 0; border-end-start-radius: 0; }
  .input-group > .input:not(:last-child),  .input-group > .select:not(:last-child)  { border-start-end-radius: 0; border-end-end-radius: 0; }
  .input-group__addon {
    display: inline-flex; align-items: center;
    padding-inline: .8rem;
    background: var(--surface-3);
    border: 1px solid var(--border);
    color: var(--text-3);
    font-size: var(--fs-sm);
    font-weight: 600;
    white-space: nowrap;
  }
  .input-group > .input-group__addon:first-child { border-start-start-radius: var(--r-sm); border-end-start-radius: var(--r-sm); border-inline-end: 0; }
  .input-group > .input-group__addon:last-child  { border-start-end-radius: var(--r-sm);  border-end-end-radius: var(--r-sm); border-inline-start: 0; }

  /* switch */
  /* Two markup shapes exist: ours (input + .switch__track) and the migrated
     Metronic one (<span class="switch"><label><input><span></span></label>),
     whose track span carries no class at all — which is why every one of the
     113 toggles in the project rendered as nothing. */
  .switch { display: inline-flex; align-items: center; gap: .6rem; cursor: pointer; user-select: none; }
  .switch > label { display: inline-flex; align-items: center; gap: .6rem; cursor: pointer; margin: 0; }
  .switch input { position: absolute; opacity: 0; inline-size: 0; block-size: 0; }
  .switch__track,
  .switch input + span:not([class]) {
    inline-size: 2.75rem; block-size: 1.6rem;
    border-radius: var(--r-pill);
    background: var(--border-strong);
    position: relative;
    flex: none;
    transition: background var(--t) var(--ease);
  }
  .switch__track::after,
  .switch input + span:not([class])::after {
    content: "";
    position: absolute;
    inset-block-start: 3px;
    inset-inline-start: 3px;
    inline-size: 1.1rem; block-size: 1.1rem;
    border-radius: 50%;
    background: #fff;
    box-shadow: var(--shadow-sm);
    transition: translate var(--t) var(--ease);
  }
  .switch input:checked + :is(.switch__track, span:not([class])) { background: var(--brand); }
  .switch input:checked + :is(.switch__track, span:not([class]))::after { translate: 1.15rem 0; }
  html[dir="rtl"] .switch input:checked + :is(.switch__track, span:not([class]))::after { translate: -1.15rem 0; }
  .switch input:focus-visible + :is(.switch__track, span:not([class])) { box-shadow: var(--ring); }
  .switch__label { font-size: var(--fs-base); font-weight: 600; color: var(--text-2); }

  /* checkbox + radio */
  .check { display: inline-flex; align-items: flex-start; gap: .55rem; cursor: pointer; font-size: var(--fs-base); }
  .check input { appearance: none; flex: none; inline-size: 1.15rem; block-size: 1.15rem; margin-block-start: .12rem;
    border: 1.5px solid var(--border-strong); border-radius: 6px; background: var(--surface);
    transition: background var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease); }
  .check input[type="radio"] { border-radius: 50%; }
  .check input:checked { background: var(--brand); border-color: var(--brand); }
  .check input[type="checkbox"]:checked {
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='3.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'/%3E%3C/svg%3E");
    background-size: 78%; background-position: center; background-repeat: no-repeat;
  }
  /* "some but not all" — without this an indeterminate parent box reads as
     empty, which is exactly the wrong answer */
  .check input[type="checkbox"]:indeterminate {
    background: var(--brand);
    border-color: var(--brand);
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='3.2' stroke-linecap='round'%3E%3Cline x1='6' y1='12' x2='18' y2='12'/%3E%3C/svg%3E");
    background-size: 78%; background-position: center; background-repeat: no-repeat;
  }
  .check input[type="radio"]:checked { box-shadow: inset 0 0 0 3.5px var(--surface); }
  .check input:focus-visible { box-shadow: var(--ring); }

  /* legacy avatar / image picker widget */
  .image-input {
    position: relative;
    display: inline-block;
    inline-size: 8.5rem;
    block-size: 8.5rem;
    border-radius: var(--r-md);
    background: var(--surface-3) center / cover no-repeat;
    border: 1px solid var(--border);
    box-shadow: var(--shadow-xs);
  }
  .image-input-wrapper {
    position: absolute;
    inset: 0;
    border-radius: inherit;
    background: center / cover no-repeat;
  }
  /* an empty widget has to look empty, not like a broken picture */
  .image-input.is-empty {
    background-image: none;
    border-style: dashed;
    border-color: var(--border-strong);
  }
  .image-input.is-empty::after {
    content: "";
    position: absolute;
    inset: 0;
    background: currentColor;
    color: var(--text-3);
    opacity: .35;
    mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='3' width='18' height='18' rx='3'/%3E%3Ccircle cx='8.7' cy='9' r='1.6'/%3E%3Cpath d='m4 18 5-5 3.5 3.5L16 13l4 4'/%3E%3C/svg%3E") center / 2.1rem no-repeat;
    pointer-events: none;
  }
  /* a picked-but-unsaved picture is flagged, so Cancel has a visible job */
  .image-input.is-changed { border-color: var(--brand); box-shadow: 0 0 0 3px color-mix(in oklab, var(--brand) 14%, transparent); }
  .image-input.is-empty > [data-action="remove"],
  .image-input:not(.is-changed) > [data-action="cancel"] { display: none; }
  .image-input > :is(label, span)[data-action] {
    position: absolute;
    z-index: 1;
    inline-size: 1.9rem;
    block-size: 1.9rem;
    display: grid;
    place-items: center;
    border-radius: 50%;
    background: var(--surface);
    border: 1px solid var(--border);
    box-shadow: var(--shadow-sm);
    color: var(--text-2);
    cursor: pointer;
    transition: color var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease);
  }
  .image-input > [data-action="change"] { inset-block-start: -.55rem; inset-inline-end: -.55rem; }
  .image-input > [data-action="cancel"] { inset-block-end: -.55rem; inset-inline-end: -.55rem; }
  .image-input > [data-action="remove"] { inset-block-end: -.55rem; inset-inline-start: -.55rem; }
  .image-input > [data-action]:hover { color: var(--brand); border-color: color-mix(in oklab, var(--brand) 45%, var(--border)); }
  .image-input > [data-action="remove"]:hover { color: var(--danger); border-color: color-mix(in oklab, var(--danger) 45%, var(--border)); }
  .image-input > [data-action] .icon { inline-size: .85rem; block-size: .85rem; }
  .image-input input[type="file"] {
    position: absolute;
    inset: 0;
    opacity: 0;
    cursor: pointer;
    padding: 0;
    border: 0;
    min-block-size: 0;
  }

  /* plain <input type="file"> (legacy markup) — styled, not left to the browser */
  input[type="file"] {
    inline-size: 100%;
    max-inline-size: 100%;
    min-block-size: 2.6rem;
    padding: .42rem .5rem;
    border: 1px solid var(--border);
    border-radius: var(--r-sm);
    background: var(--surface);
    color: var(--text-3);
    font-size: var(--fs-sm);
  }
  input[type="file"]:hover { border-color: var(--border-strong); }
  input[type="file"]:focus-visible { outline: none; border-color: var(--brand); box-shadow: var(--ring); }
  input[type="file"]::file-selector-button {
    margin-inline-end: .7rem;
    padding: .4rem .8rem;
    border: 1px solid var(--border);
    border-radius: var(--r-xs);
    background: var(--surface-3);
    color: var(--text-2);
    font: 650 var(--fs-sm)/1 var(--font-sans);
    cursor: pointer;
    transition: background var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
  }
  input[type="file"]::file-selector-button:hover {
    background: color-mix(in oklab, var(--brand) 13%, transparent);
    color: var(--brand-strong);
    border-color: transparent;
  }
  .dropzone input[type="file"] { padding: 0; border: 0; background: none; min-block-size: 0; }

  /* what you just picked, under a plain file input */
  .file-pick {
    display: flex; align-items: center; gap: .6rem; flex-wrap: wrap;
    margin-block-start: .5rem;
    padding: .45rem .55rem;
    border: 1px solid var(--border);
    border-radius: var(--r-sm);
    background: var(--surface-2);
  }
  .file-pick[hidden] { display: none; }
  .file-pick__item { display: flex; align-items: center; gap: .55rem; min-inline-size: 0; }
  .file-pick__item img {
    inline-size: 2.6rem; block-size: 2.6rem;
    border-radius: var(--r-xs);
    object-fit: cover;
    background: var(--surface-3);
    cursor: zoom-in;
  }
  .file-pick__item > span:first-child { color: var(--text-3); display: grid; place-items: center; }
  .file-pick__meta { min-inline-size: 0; display: grid; }
  .file-pick__meta b {
    font-size: var(--fs-sm); font-weight: 650; color: var(--text);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-inline-size: 14rem;
  }
  .file-pick__meta small { font-size: var(--fs-2xs); color: var(--text-3); }
  .file-pick > .btn { margin-inline-start: auto; }

  /* file drop */
  .dropzone {
    display: grid; place-items: center; gap: .5rem;
    padding: 1.6rem;
    text-align: center;
    border: 1.5px dashed var(--border-strong);
    border-radius: var(--r-md);
    background: var(--surface-2);
    color: var(--text-3);
    cursor: pointer;
    transition: border-color var(--t) var(--ease), background var(--t) var(--ease), color var(--t) var(--ease);
  }
  .dropzone:hover, .dropzone.is-over {
    border-color: var(--brand);
    background: color-mix(in oklab, var(--brand) 6%, var(--surface-2));
    color: var(--brand-strong);
  }
  .dropzone .icon { inline-size: 1.9rem; block-size: 1.9rem; }
  .dropzone strong { color: var(--text); font-size: var(--fs-base); }
  .dropzone input[type="file"] { display: none; }
  .thumbs { display: flex; flex-wrap: wrap; gap: .55rem; margin-top: .75rem; }
  .thumb {
    position: relative;
    inline-size: 76px; block-size: 76px;
    border-radius: var(--r-sm);
    overflow: hidden;
    border: 1px solid var(--border);
    background: var(--surface-3);
  }
  .thumb img { inline-size: 100%; block-size: 100%; object-fit: cover; }
  .thumb button {
    position: absolute; inset-block-start: 3px; inset-inline-end: 3px;
    inline-size: 1.25rem; block-size: 1.25rem;
    display: grid; place-items: center;
    border-radius: 50%;
    background: oklch(20% 0 0 / .6);
    color: #fff;
    backdrop-filter: blur(4px);
  }
  .thumb button .icon { inline-size: .7rem; block-size: .7rem; }

  /* a multi-select whose options arrive over ajax is empty on first paint;
     without a floor it collapses into a tall grey slab */
  select[multiple] {
    min-block-size: 2.75rem;
    max-block-size: 11rem;
    padding-block: .35rem;
  }
  select[multiple] option { padding: .3rem .5rem; border-radius: var(--r-xs); }
  select[multiple]:not(:has(option)) { block-size: 2.75rem; }

  /* form section layout */
  .form-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 1.1rem 1.15rem; align-items: start; }
  /* bare radios / checkboxes coming from migrated markup */
  .field :is(input[type="checkbox"], input[type="radio"]):not(.switch input) {
    inline-size: 1.05rem; block-size: 1.05rem; accent-color: var(--brand);
    margin-inline-end: .35rem; vertical-align: -.15em;
  }
  .field label:not(.label) { font-size: var(--fs-base); color: var(--text-2); margin-inline-end: .9rem; }
  .form-grid > .span-full { grid-column: 1 / -1; }
  /* three short fields that belong together — a title with a first and last
     name, or a number with its country and expiry */
  .form-grid.is-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  @container page (max-width: 900px) { .form-grid.is-3 { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
  @container page (max-width: 720px) {
    .form-grid { grid-template-columns: minmax(0, 1fr); }
    .form-grid.is-3 { grid-template-columns: minmax(0, 1fr); }
  }

  .form-section + .form-section { margin-top: 1.5rem; padding-top: 1.5rem; border-top: 1px solid var(--border-soft); }
  .form-section__hd { display: flex; align-items: center; gap: .6rem; margin-bottom: 1rem; }
  .form-section__hd h3 { font-size: var(--fs-base); font-weight: 750; }
  .form-section__hd .num-chip {
    inline-size: 1.5rem; block-size: 1.5rem;
    display: grid; place-items: center;
    border-radius: 8px;
    background: color-mix(in oklab, var(--brand) 13%, transparent);
    color: var(--brand-strong);
    font-size: var(--fs-xs); font-weight: 800;
  }

  /* ------------------------------------------------------------ SEGMENTED */
  .seg {
    display: inline-flex;
    padding: 3px;
    gap: 2px;
    background: var(--surface-inset);
    border: 1px solid var(--border-soft);
    border-radius: var(--r-sm);
  }
  .seg button {
    display: inline-flex; align-items: center; gap: .3rem;
    padding: .32rem .6rem;
    border-radius: 7px;
    font-size: var(--fs-xs);
    font-weight: 700;
    color: var(--text-3);
    transition: background var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
  }
  .seg button .icon { inline-size: .95rem; block-size: .95rem; }
  .seg button:hover { color: var(--text); }
  .seg button[aria-pressed="true"], .seg button.is-on {
    background: var(--surface);
    color: var(--text);
    box-shadow: var(--shadow-xs);
  }

  /* ------------------------------------------------------------------ TABS */
  .tabs { display: flex; gap: .15rem; border-bottom: 1px solid var(--border); overflow-x: auto; scrollbar-width: none; }
  .tabs::-webkit-scrollbar { display: none; }
  .tab {
    position: relative;
    padding: .7rem .9rem;
    font-size: var(--fs-base);
    font-weight: 650;
    color: var(--text-3);
    white-space: nowrap;
    display: inline-flex; align-items: center; gap: .4rem;
    transition: color var(--t-fast) var(--ease);
  }
  .tab:hover { color: var(--text); }
  .tab[aria-selected="true"] { color: var(--brand-strong); }
  .tab[aria-selected="true"]::after {
    content: "";
    position: absolute;
    inset-inline: .3rem;
    inset-block-end: -1px;
    block-size: 2px;
    border-radius: 2px 2px 0 0;
    background: var(--brand);
  }
  .tab-panel[hidden] { display: none; }

  /* --------------------------------------------------------------- POPOVER */
  [popover].pop {
    position: absolute;
    margin: 0;
    inline-size: max-content;
    min-inline-size: 12rem;
    max-inline-size: min(92vw, 22rem);
    padding: .4rem;
    background: var(--surface);
    color: var(--text);
    border: 1px solid var(--border);
    border-radius: var(--r-md);
    box-shadow: var(--shadow-pop);
    overflow: visible;
    opacity: 0;
    translate: 0 -6px;
    transition: opacity var(--t-fast) var(--ease), translate var(--t-fast) var(--ease), display var(--t-fast) allow-discrete;
  }
  [popover].pop:popover-open { opacity: 1; translate: 0 0; }
  @starting-style { [popover].pop:popover-open { opacity: 0; translate: 0 -6px; } }
  [popover].pop::backdrop { background: transparent; }
  .pop--wide { min-inline-size: 20rem; }

  .pop__hd {
    padding: .45rem .6rem .5rem;
    font-size: var(--fs-2xs);
    font-weight: 750;
    letter-spacing: .08em;
    text-transform: uppercase;
    color: var(--text-3);
  }
  .pop__item {
    display: flex; align-items: center; gap: .6rem;
    inline-size: 100%;
    padding: .48rem .6rem;
    border-radius: var(--r-xs);
    font-size: var(--fs-base);
    font-weight: 550;
    color: var(--text-2);
    text-align: start;
    transition: background var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
  }
  .pop__item :is(.icon) { inline-size: 1.05rem; block-size: 1.05rem; }
  .pop__item > [data-icon] { color: var(--text-3); }
  .pop__item:hover { background: var(--surface-3); color: var(--text); }
  .pop__item:hover > [data-icon] { color: var(--brand); }
  .pop__item.is-danger { color: var(--danger); }
  .pop__item.is-danger > [data-icon] { color: var(--danger); }
  .pop__item.is-danger:hover { background: color-mix(in oklab, var(--danger) 12%, transparent); }
  .pop__item kbd { margin-inline-start: auto; }
  .pop__sep { block-size: 1px; background: var(--border-soft); margin: .3rem .25rem; }

  kbd {
    font: 650 var(--fs-2xs)/1 var(--font-mono);
    padding: .2rem .35rem;
    border-radius: 5px;
    background: var(--surface-3);
    border: 1px solid var(--border);
    color: var(--text-3);
  }

  /* ---------------------------------------------------------------- DIALOG */
  dialog.modal {
    inline-size: min(92vw, var(--modal-w, 34rem));
    max-block-size: 86dvh;
    margin: auto;                 /* reset sets margin:0 — restore UA centering */
    padding: 0;
    border: 1px solid var(--border);
    border-radius: var(--r-xl);
    background: var(--surface);
    color: var(--text);
    box-shadow: var(--shadow-lg);
    overflow: clip;
    opacity: 0;
    scale: .96;
    transition: opacity var(--t) var(--ease), scale var(--t) var(--ease), overlay var(--t) allow-discrete, display var(--t) allow-discrete;
  }
  dialog.modal[open] { opacity: 1; scale: 1; }
  @starting-style { dialog.modal[open] { opacity: 0; scale: .96; } }
  dialog.modal::backdrop {
    background: oklch(16% .03 272 / .55);
    backdrop-filter: blur(3px);
    opacity: 0;
    transition: opacity var(--t) var(--ease), overlay var(--t) allow-discrete, display var(--t) allow-discrete;
  }
  dialog.modal[open]::backdrop { opacity: 1; }
  @starting-style { dialog.modal[open]::backdrop { opacity: 0; } }
  .modal__hd { display: flex; align-items: center; gap: .75rem; padding: 1.1rem 1.25rem; border-bottom: 1px solid var(--border-soft); }
  .modal__hd h2 { font-size: var(--fs-lg); font-weight: 750; }
  .modal__bd { padding: 1.25rem; overflow-y: auto; }
  .modal__ft { display: flex; gap: .6rem; justify-content: flex-end; padding: 1rem 1.25rem; border-top: 1px solid var(--border-soft); background: var(--surface-2); }
  .modal--wide { --modal-w: 52rem; }
  .modal--confirm { --modal-w: 27rem; }
  .modal__ico {
    inline-size: 3rem; block-size: 3rem;
    display: grid; place-items: center;
    border-radius: 50%;
    margin-inline: auto;
    margin-block-end: .9rem;
  }
  .modal__ico.is-danger  { background: color-mix(in oklab, var(--danger) 14%, transparent);  color: var(--danger); }
  .modal__ico.is-warning { background: color-mix(in oklab, var(--warning) 20%, transparent); color: color-mix(in oklab, var(--warning) 80%, var(--text)); }
  .modal__ico.is-success { background: color-mix(in oklab, var(--success) 16%, transparent); color: var(--success); }
  .modal__ico .icon { inline-size: 1.6rem; block-size: 1.6rem; }

  /* ----------------------------------------------------------------- TOAST */
  .toast-host {
    position: fixed;
    inset-block-start: calc(var(--topbar-h) + .6rem);
    inset-inline-end: 1rem;
    z-index: 90;
    display: flex;
    flex-direction: column;
    gap: .55rem;
    inline-size: min(92vw, 23rem);
    pointer-events: none;
  }
  .toast {
    pointer-events: auto;
    display: flex; align-items: flex-start; gap: .7rem;
    padding: .8rem .9rem;
    background: var(--surface);
    border: 1px solid var(--border);
    border-inline-start: 3px solid var(--toast-accent, var(--brand));
    border-radius: var(--r-md);
    box-shadow: var(--shadow-lg);
    animation: toast-in .32s var(--ease-out);
  }
  .toast.is-out { animation: toast-out .24s var(--ease) forwards; }
  .toast__ico { color: var(--toast-accent, var(--brand)); margin-block-start: .1rem; }
  .toast__bd { flex: 1; min-width: 0; }
  .toast__bd b { display: block; font-size: var(--fs-base); font-weight: 700; }
  .toast__bd p { font-size: var(--fs-sm); color: var(--text-2); margin-block-start: .1rem; }
  .toast.is-success { --toast-accent: var(--success); }
  .toast.is-danger  { --toast-accent: var(--danger); }
  .toast.is-warning { --toast-accent: var(--warning); }
  .toast.is-info    { --toast-accent: var(--info); }
  @keyframes toast-in  { from { opacity: 0; translate: 0 -10px; scale: .97; } }
  @keyframes toast-out { to   { opacity: 0; translate: 0 -6px;  scale: .98; } }

  /* ----------------------------------------------------------------- ALERT */
  .alert {
    display: flex; align-items: flex-start; gap: .7rem;
    padding: .85rem 1rem;
    border-radius: var(--r-md);
    background: color-mix(in oklab, var(--al, var(--info)) 10%, var(--surface));
    border: 1px solid color-mix(in oklab, var(--al, var(--info)) 26%, transparent);
    color: var(--text);
    font-size: var(--fs-base);
  }
  .alert > :is(.icon, [data-icon]) { color: var(--al, var(--info)); margin-block-start: .1rem; }
  .alert.is-success { --al: var(--success); }
  .alert.is-warning { --al: var(--warning); }
  .alert.is-danger  { --al: var(--danger); }
  .alert.is-brand   { --al: var(--brand); }

  /* -------------------------------------------------------------- PROGRESS */
  .progress { block-size: .45rem; border-radius: var(--r-pill); background: var(--surface-3); overflow: hidden; }
  .progress > span { display: block; block-size: 100%; border-radius: inherit;
    background: var(--brand); }

  .meter { display: flex; flex-direction: column; gap: .35rem; }
  .meter__top { display: flex; justify-content: space-between; font-size: var(--fs-xs); font-weight: 650; color: var(--text-2); }

  /* --------------------------------------------------------- EMPTY / SKEL */
  .empty {
    display: grid; place-items: center; gap: .55rem;
    padding: 3rem 1.5rem;
    text-align: center;
    color: var(--text-3);
  }
  .empty__ico {
    inline-size: 3.4rem; block-size: 3.4rem;
    display: grid; place-items: center;
    border-radius: var(--r-lg);
    background: var(--surface-3);
    color: var(--text-3);
    margin-block-end: .3rem;
  }
  .empty h3 { font-size: var(--fs-md); color: var(--text); }
  .empty p { font-size: var(--fs-sm); max-inline-size: 34ch; text-wrap: pretty; }

  .skel {
    background: linear-gradient(90deg, var(--surface-3) 25%, var(--surface-2) 50%, var(--surface-3) 75%);
    background-size: 200% 100%;
    animation: skel 1.3s linear infinite;
    border-radius: var(--r-xs);
    block-size: 1rem;
  }
  @keyframes skel { to { background-position: -200% 0; } }

  /* --------------------------------------------------------------- TOOLTIP */
  [data-tip] {
    position: relative;
    --tip-gap: .4rem;   /* distance from the control */
    --tip-y: -3px;      /* slide-in direction (negative = comes from below) */
  }
  /* `display: none` until hover, so a hidden tooltip can never widen the page */
  [data-tip]::after {
    content: attr(data-tip);
    display: none;
    position: absolute;
    inset-block-end: calc(100% + var(--tip-gap));
    /* Physical `left` on purpose: centring is symmetric, while
       `inset-inline-start: 50%` anchored the bubble by its *right* edge in RTL
       and threw it a whole bubble-width away from its icon.
       Centring lives in `transform`, the hover slide lives in `translate` —
       two separate properties, so neither one clobbers the other. */
    left: 50%;
    transform: translateX(-50%);
    padding: .34rem .6rem;
    border-radius: var(--r-xs);
    background: var(--text);
    color: var(--surface);
    font-size: var(--fs-xs);
    font-weight: 650;
    line-height: 1.5;          /* Arabic descenders were being cropped at 1 */
    white-space: nowrap;
    box-shadow: var(--shadow-md);
    opacity: 0;
    pointer-events: none;
    transition: opacity var(--t-fast) var(--ease), translate var(--t-fast) var(--ease),
                display var(--t-fast) allow-discrete;
    z-index: 60;
  }
  [data-tip]:hover::after,
  [data-tip]:focus-visible::after { display: block; opacity: 1; translate: 0 var(--tip-y); }
  @starting-style {
    [data-tip]:hover::after,
    [data-tip]:focus-visible::after { opacity: 0; translate: 0 0; }
  }

  /* Anything sitting in a bar at the very top of the screen has no room above
     it — the bubble was being cut off by the edge of the viewport. Flip it
     under the control instead. */
  :is(.topbar, .auth__bar, .lightbox__bar) [data-tip]::after,
  [data-tip][data-tip-pos="bottom"]::after {
    inset-block-end: auto;
    inset-block-start: calc(100% + var(--tip-gap));
  }
  :is(.topbar, .auth__bar, .lightbox__bar) [data-tip],
  [data-tip][data-tip-pos="bottom"] { --tip-y: 3px; }

  /* the controls at the far end of the bar would push their bubble past the
     edge of the window, so those hang from the end edge instead of centring */
  .topbar > :nth-last-child(-n+4)[data-tip]::after,
  .topbar > :nth-last-child(-n+4) [data-tip]::after {
    left: auto;
    inset-inline-end: 0;
    transform: none;
  }

  /* ------------------------------------------------------------ SIDEBAR CARD */
  .sb-card {
    padding: .85rem;
    border-radius: var(--r-md);
    background: color-mix(in oklab, var(--brand) 14%, var(--surface));
    border: 1px solid var(--border-soft);
    margin-block-end: .6rem;
  }
  .sb-card b { font-size: var(--fs-sm); display: block; }
  .sb-card p { font-size: var(--fs-xs); color: var(--text-2); margin-block: .2rem .6rem; }

  .sb-user { display: flex; align-items: center; gap: .6rem; inline-size: 100%; padding: .45rem; border-radius: var(--r-sm); }
  .sb-user:hover { background: var(--surface-3); }
  .sb-user__meta { min-width: 0; text-align: start; }
  .sb-user__meta b { display: block; font-size: var(--fs-sm); font-weight: 700; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .sb-user__meta span { font-size: var(--fs-2xs); color: var(--text-3); }

  /* ------------------------------------------------------------ BASE TABLE */
  .tbl-wrap { inline-size: 100%; overflow-x: auto; }
  table.tbl { inline-size: 100%; font-size: var(--fs-base); }
  /* equal columns for a short static table — auto layout packs the cells
     against one edge and leaves the values touching each other */
  table.tbl.is-fixed { table-layout: fixed; }
  table.tbl th {
    padding: .7rem .85rem;
    text-align: start;
    font-size: var(--fs-2xs);
    font-weight: 750;
    letter-spacing: .07em;
    text-transform: uppercase;
    color: var(--text-3);
    background: var(--surface-2);
    border-block-end: 1px solid var(--border);
    white-space: nowrap;
  }
  table.tbl td {
    padding: .78rem .85rem;
    border-block-end: 1px solid var(--border-soft);
    color: var(--text-2);
    vertical-align: middle;
  }
  table.tbl tbody tr { transition: background var(--t-fast) var(--ease); }
  table.tbl tbody tr:hover { background: color-mix(in oklab, var(--brand) 4%, transparent); }
  table.tbl tbody tr:last-child td { border-block-end: 0; }
  table.tbl .cell-strong { color: var(--text); font-weight: 650; }
  table.tbl .cell-id { font-family: var(--font-mono); font-size: var(--fs-xs); color: var(--text-3); }

  .cell-media { display: flex; align-items: center; gap: .6rem; min-width: 0; }
  .cell-media__meta { min-width: 0; }
  .cell-media__meta b { display: block; font-size: var(--fs-base); font-weight: 650; color: var(--text); }
  .cell-media__meta span { font-size: var(--fs-xs); color: var(--text-3); }

  /* --------------------------------------------------- KEY / VALUE LIST */
  .kv-list { display: grid; }
  .kv {
    display: flex; align-items: baseline; justify-content: space-between;
    gap: 1.25rem;
    padding-block: .7rem;
    font-size: var(--fs-base);
  }
  .kv + .kv { border-block-start: 1px dashed var(--border-soft); }
  .kv dt, .kv > :first-child {
    color: var(--text-3);
    font-size: var(--fs-sm);
    font-weight: 600;
    flex: none;
    max-inline-size: 45%;
  }
  .kv dd, .kv > :last-child {
    color: var(--text);
    font-weight: 650;
    text-align: end;
    min-width: 0;
    overflow-wrap: anywhere;
  }

  /* ------------------------------------------------------------ TOOLBAR */
  .toolbar {
    display: flex; align-items: center; gap: .55rem; flex-wrap: wrap;
    padding: .85rem 1.15rem;
    border-block-end: 1px solid var(--border-soft);
    background: var(--surface);
  }
  .toolbar__grow { flex: 1; min-inline-size: 12rem; }

  .filter-chips { display: flex; gap: .4rem; flex-wrap: wrap; }
  .chip {
    display: inline-flex; align-items: center; gap: .35rem;
    padding: .28rem .6rem;
    border-radius: var(--r-pill);
    background: var(--surface-3);
    border: 1px solid transparent;
    font-size: var(--fs-xs);
    font-weight: 650;
    color: var(--text-2);
    transition: all var(--t-fast) var(--ease);
  }
  .chip:hover { border-color: var(--border-strong); color: var(--text); }
  .chip[aria-pressed="true"], .chip.is-on {
    background: color-mix(in oklab, var(--brand) 13%, transparent);
    color: var(--brand-strong);
  }
  .chip__n { font-variant-numeric: tabular-nums; opacity: .75; }

  /* -------------------------------------------------------------- KBD HINT */
  .kbd-hint { display: inline-flex; align-items: center; gap: .25rem; font-size: var(--fs-2xs); color: var(--text-3); }
}

/* ==========================================================================
   PLUGINS — DataTables 2.x (+ legacy 1.x selectors), Select2, Summernote
   Styled from scratch against our tokens. No plugin theme CSS required.
   ========================================================================== */
@layer plugins {

  /* ---------------------------------------------------- DataTables shell */
  .dt-container,
  .dataTables_wrapper {
    display: flex;
    flex-direction: column;
    inline-size: 100%;
    font-size: var(--fs-base);
    color: var(--text-2);
  }

  .dt-layout-row { min-inline-size: 0;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: .75rem;
    flex-wrap: wrap;
    padding: .85rem 1.15rem;
  }
  .dt-layout-row:has(.dt-length, .dt-search) { border-block-end: 1px solid var(--border-soft); }
  .dt-layout-row:has(.dt-info, .dt-paging) { border-block-start: 1px solid var(--border-soft); background: var(--surface-2); }
  .dt-layout-cell { display: flex; align-items: center; gap: .6rem; flex-wrap: wrap; min-inline-size: 0; }
  .dt-layout-full { inline-size: 100%; }
  .dt-layout-table { padding: 0; overflow-x: auto; }

  /* length + search controls */
  .dt-length, .dt-search { display: inline-flex; align-items: center; gap: .45rem; font-size: var(--fs-sm); color: var(--text-3); }
  .dt-length label, .dt-search label { font-weight: 600; }
  .dt-length select,
  .dataTables_length select {
    appearance: none;
    min-block-size: 2.1rem;
    padding: .25rem 1.8rem .25rem .6rem;
    border-radius: var(--r-xs);
    border: 1px solid var(--border);
    background: var(--surface);
    color: var(--text);
    font-size: var(--fs-sm);
    font-weight: 650;
    background-image: linear-gradient(45deg, transparent 50%, currentColor 50%), linear-gradient(135deg, currentColor 50%, transparent 50%);
    background-position: calc(100% - .95rem) .95rem, calc(100% - .65rem) .95rem;
    background-size: 5px 5px, 5px 5px;
    background-repeat: no-repeat;
  }
  html[dir="rtl"] .dt-length select { padding: .25rem .6rem .25rem 1.8rem; background-position: .95rem .95rem, .65rem .95rem;
    background-image: linear-gradient(135deg, currentColor 50%, transparent 50%), linear-gradient(45deg, transparent 50%, currentColor 50%); }

  .dt-search input,
  .dataTables_filter input {
    min-block-size: 2.35rem;
    inline-size: min(16rem, 46vw);
    padding: .4rem .8rem .4rem 2.2rem;
    border-radius: var(--r-sm);
    border: 1px solid var(--border);
    background: var(--surface-inset)
      url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2394a3b8' stroke-width='2' stroke-linecap='round'%3E%3Ccircle cx='11' cy='11' r='7'/%3E%3Cpath d='m20 20-3.5-3.5'/%3E%3C/svg%3E")
      no-repeat .6rem center / 1rem;
    color: var(--text);
    transition: border-color var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease), background-color var(--t-fast) var(--ease);
  }
  html[dir="rtl"] .dt-search input, html[dir="rtl"] .dataTables_filter input {
    padding: .4rem 2.2rem .4rem .8rem;
    background-position: right .6rem center;
  }
  .dt-search input:focus, .dataTables_filter input:focus {
    outline: none;
    border-color: var(--brand);
    box-shadow: var(--ring);
    background-color: var(--surface);
  }

  /* ---------------------------------------------------- DataTables table */
  table.dataTable {
    inline-size: 100% !important;
    margin: 0 !important;
    border-collapse: separate !important;
    border-spacing: 0;
    font-size: var(--fs-base);
  }
  table.dataTable thead th,
  table.dataTable thead td {
    position: relative;
    padding: .75rem .85rem !important;
    text-align: start;
    font-size: var(--fs-2xs);
    font-weight: 750;
    letter-spacing: .07em;
    text-transform: uppercase;
    color: var(--text-3);
    background: var(--surface-2);
    border-block-end: 1px solid var(--border) !important;
    border-block-start: 0 !important;
    white-space: nowrap;
    cursor: default;
  }
  table.dataTable thead th.dt-orderable-asc,
  table.dataTable thead th.dt-orderable-desc,
  table.dataTable thead th.sorting,
  table.dataTable thead th.sorting_asc,
  table.dataTable thead th.sorting_desc { cursor: pointer; }
  table.dataTable thead th:hover:where(.dt-orderable-asc, .dt-orderable-desc, .sorting, .sorting_asc, .sorting_desc) { color: var(--text); }

  /* our own sort indicator; kill the plugin's */
  table.dataTable thead th.sorting::before, table.dataTable thead th.sorting::after,
  table.dataTable thead th.sorting_asc::before, table.dataTable thead th.sorting_asc::after,
  table.dataTable thead th.sorting_desc::before, table.dataTable thead th.sorting_desc::after { display: none !important; }
  table.dataTable thead th span.dt-column-order { display: none !important; }

  table.dataTable thead th:where(.dt-orderable-asc, .dt-orderable-desc, .sorting, .sorting_asc, .sorting_desc) .dt-column-title::after,
  table.dataTable thead th:where(.dt-orderable-asc, .dt-orderable-desc, .sorting, .sorting_asc, .sorting_desc)::after {
    content: "";
    display: inline-block;
    inline-size: .55rem; block-size: .55rem;
    margin-inline-start: .4rem;
    vertical-align: middle;
    background: currentColor;
    opacity: .35;
    clip-path: polygon(50% 0, 100% 45%, 62% 45%, 62% 100%, 38% 100%, 38% 45%, 0 45%);
    transition: opacity var(--t-fast) var(--ease), rotate var(--t-fast) var(--ease);
  }
  table.dataTable thead th:where(.dt-ordering-asc, .sorting_asc) .dt-column-title::after,
  table.dataTable thead th:where(.dt-ordering-asc, .sorting_asc)::after { opacity: 1; color: var(--brand); }
  table.dataTable thead th:where(.dt-ordering-desc, .sorting_desc) .dt-column-title::after,
  table.dataTable thead th:where(.dt-ordering-desc, .sorting_desc)::after { opacity: 1; color: var(--brand); rotate: 180deg; }
  /* avoid doubling when DT wraps titles in .dt-column-title */
  table.dataTable thead th:has(.dt-column-title)::after { display: none; }

  /* dense admin tables read better on one line + horizontal scroll than wrapped;
     add .dt-wrap to a cell/column to opt out */
  table.dataTable tbody td:not(.dt-wrap) { white-space: nowrap; }
  table.dataTable tbody td.dt-wrap { white-space: normal; min-inline-size: 14rem; }
  table.dataTable tbody tr.child td { white-space: normal !important; }

  table.dataTable tbody td {
    padding: .78rem .85rem !important;
    border-block-end: 1px solid var(--border-soft) !important;
    border-block-start: 0 !important;
    color: var(--text-2);
    vertical-align: middle;
    background: transparent;
  }
  table.dataTable tbody tr { background: transparent !important; transition: background var(--t-fast) var(--ease); }
  table.dataTable tbody tr:hover td { background: color-mix(in oklab, var(--brand) 4%, transparent); }
  table.dataTable tbody tr.selected td { background: color-mix(in oklab, var(--brand) 10%, transparent) !important; }
  table.dataTable tbody tr:last-child td { border-block-end: 0 !important; }
  table.dataTable.stripe tbody tr:nth-child(even) td,
  table.dataTable.display tbody tr:nth-child(even) td { background: var(--surface-2); }
  table.dataTable.row-border tbody th, table.dataTable.row-border tbody td { border-top: 0; }
  table.dataTable td.dt-empty, table.dataTable td.dataTables_empty {
    padding: 2.6rem 1rem !important;
    text-align: center;
    color: var(--text-3);
    font-size: var(--fs-sm);
  }
  table.dataTable th.dt-center, table.dataTable td.dt-center,
  table.dataTable th.text-center, table.dataTable td.text-center { text-align: center; }

  /* ---- scroll mode (scrollX / scrollY): DataTables clones the header into
     .dt-scroll-head and keeps a zero-height copy inside the body for sizing.
     Without the plugin's own CSS that copy shows as a duplicate header row. ---- */
  .dt-scroll, .dataTables_scroll { position: relative; inline-size: 100%; }
  .dt-scroll-head, .dataTables_scrollHead { overflow: hidden; background: var(--surface-2); }
  .dt-scroll-body, .dataTables_scrollBody { overflow: auto; overscroll-behavior-x: contain; }
  .dt-scroll-foot, .dataTables_scrollFoot { overflow: hidden; background: var(--surface-2); }

  .dt-scroll-body > table > thead > tr,
  .dt-scroll-body > table > tfoot > tr,
  .dataTables_scrollBody > table > thead > tr,
  .dataTables_scrollBody > table > tfoot > tr { block-size: 0; }

  .dt-scroll-body > table > :is(thead, tfoot) > tr > :is(th, td),
  .dataTables_scrollBody > table > :is(thead, tfoot) > tr > :is(th, td) {
    block-size: 0 !important;
    line-height: 0 !important;
    padding-block: 0 !important;
    border-block-width: 0 !important;
    overflow: hidden;
    visibility: hidden;
  }
  .dt-scroll-body > table > thead > tr > th::after,
  .dataTables_scrollBody > table > thead > tr > th::after { content: none !important; }
  .dt-scroll-body > table > thead div.dt-scroll-sizing,
  .dt-scroll-body > table > thead .dt-column-title {
    block-size: 0; overflow: hidden; margin: 0; padding: 0;
  }
  .dt-scroll-foot > table > tfoot:not(:has(input, select, button)),
  .dataTables_scrollFoot > table > tfoot:not(:has(input, select, button)) { display: none; }

  /* legacy tables ship a <tfoot> that mirrors <thead>; only keep it when it
     actually carries per-column filter controls */
  table.dataTable tfoot:not(:has(input, select, button)),
  table.tbl tfoot:not(:has(input, select, button)) { display: none; }
  table.dataTable tfoot th {
    padding: .6rem .85rem !important;
    background: var(--surface-2);
    border-block-start: 1px solid var(--border) !important;
  }

  /* info + paging */
  .dt-info, .dataTables_info { font-size: var(--fs-sm); color: var(--text-3); font-variant-numeric: tabular-nums; }
  .dt-paging, .dataTables_paginate { display: inline-flex; align-items: center; gap: .25rem; flex-wrap: wrap; }
  .dt-paging nav { display: inline-flex; align-items: center; gap: .25rem; flex-wrap: wrap; }
  .dt-paging-button,
  .dataTables_paginate .paginate_button {
    min-inline-size: 2.1rem;
    block-size: 2.1rem;
    padding-inline: .55rem;
    display: inline-flex; align-items: center; justify-content: center;
    border-radius: var(--r-xs);
    border: 1px solid transparent;
    background: transparent;
    color: var(--text-2) !important;
    font-size: var(--fs-sm);
    font-weight: 650;
    font-variant-numeric: tabular-nums;
    cursor: pointer;
    transition: background var(--t-fast) var(--ease), color var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease);
  }
  .dt-paging-button:hover:not(.disabled):not(.current),
  .dataTables_paginate .paginate_button:hover:not(.disabled):not(.current) {
    background: var(--surface-3);
    color: var(--text) !important;
  }
  .dt-paging-button.current,
  .dataTables_paginate .paginate_button.current {
    background: var(--brand);
    color: #fff !important;
    border-color: transparent;
    box-shadow: 0 2px 8px color-mix(in oklab, var(--brand) 34%, transparent);
  }
  :root[data-theme="dark"] .dt-paging-button.current { color: oklch(20% .028 272) !important; }
  .dt-paging-button.disabled,
  .dataTables_paginate .paginate_button.disabled { opacity: .38; pointer-events: none; }

  /* export buttons */
  .dt-buttons { display: inline-flex; gap: .4rem; flex-wrap: wrap; }
  .dt-button {
    display: inline-flex; align-items: center; gap: .35rem;
    block-size: 2.35rem;
    padding-inline: .8rem;
    border-radius: var(--r-sm);
    border: 1px solid var(--border);
    background: var(--surface);
    color: var(--text-2);
    font-size: var(--fs-sm);
    font-weight: 650;
    box-shadow: var(--shadow-xs);
    cursor: pointer;
  }
  .dt-button:hover { background: var(--surface-3); color: var(--text); }

  /* processing + responsive child rows */
  .dt-processing, .dataTables_processing {
    position: absolute;
    inset-inline: 0;
    inset-block-start: 40%;
    z-index: 5;
    margin-inline: auto;
    inline-size: max-content;
    padding: .55rem 1rem;
    border-radius: var(--r-pill);
    background: var(--surface);
    border: 1px solid var(--border);
    box-shadow: var(--shadow-md);
    font-size: var(--fs-sm);
    font-weight: 650;
    color: var(--text-2);
  }
  table.dataTable td.dt-control, table.dataTable td.control {
    cursor: pointer;
    color: var(--brand);
    text-align: center;
  }
  table.dataTable tr.child ul.dtr-details { inline-size: 100%; display: grid; gap: .35rem; }
  table.dataTable tr.child ul.dtr-details > li {
    display: flex; gap: .5rem; align-items: baseline;
    padding-block: .3rem;
    border-block-end: 1px dashed var(--border-soft);
    font-size: var(--fs-sm);
  }
  table.dataTable tr.child span.dtr-title { font-weight: 700; color: var(--text-3); min-inline-size: 8rem; }
  table.dataTable tbody tr.child td { background: var(--surface-2) !important; }
  table.dataTable.dtr-inline.collapsed > tbody > tr > td.dtr-control::before {
    background-color: var(--brand) !important;
    border: 0 !important;
    box-shadow: none !important;
    line-height: 1.05rem;
  }

  /* ------------------------------------------------------------- SELECT2 */
  .select2-container { inline-size: 100% !important; }
  .toolbar .select2-container,
  [data-select-width] .select2-container { max-inline-size: 100%; }
  .select2-container--default .select2-selection--single,
  .select2-container--default .select2-selection--multiple {
    min-block-size: 2.6rem;
    padding: .28rem .5rem;
    border-radius: var(--r-sm) !important;
    border: 1px solid var(--border) !important;
    background: var(--surface) !important;
    display: flex;
    align-items: center;
  }
  .select2-container--default .select2-selection--single .select2-selection__rendered {
    color: var(--text) !important;
    line-height: 1.9rem;
    padding-inline: .3rem;
  }
  .select2-container--default .select2-selection--single .select2-selection__placeholder { color: var(--text-3) !important; }
  .select2-container--default .select2-selection--single .select2-selection__arrow { block-size: 2.5rem; inset-inline-end: .4rem; inset-inline-start: auto; }
  .select2-container--default .select2-selection--single .select2-selection__arrow b { border-color: var(--text-3) transparent transparent transparent !important; }
  .select2-container--default.select2-container--open .select2-selection--single,
  .select2-container--default.select2-container--focus .select2-selection--multiple {
    border-color: var(--brand) !important;
    box-shadow: var(--ring);
  }
  .select2-dropdown {
    border: 1px solid var(--border) !important;
    border-radius: var(--r-md) !important;
    background: var(--surface) !important;
    box-shadow: var(--shadow-pop);
    overflow: clip;
  }
  .select2-search--dropdown { padding: .5rem; }
  .select2-container--default .select2-search--dropdown .select2-search__field {
    border: 1px solid var(--border) !important;
    border-radius: var(--r-xs);
    background: var(--surface-inset);
    color: var(--text);
    padding: .45rem .6rem;
  }
  .select2-container--default .select2-results__option {
    padding: .5rem .7rem;
    font-size: var(--fs-base);
    color: var(--text-2);
  }
  .select2-container--default .select2-results__option--highlighted[aria-selected],
  .select2-container--default .select2-results__option--highlighted {
    background: color-mix(in oklab, var(--brand) 13%, transparent) !important;
    color: var(--brand-strong) !important;
  }
  .select2-container--default .select2-results__option[aria-selected="true"] {
    background: var(--surface-3) !important;
    color: var(--text) !important;
    font-weight: 650;
  }
  .select2-container--default .select2-selection--multiple .select2-selection__choice {
    background: color-mix(in oklab, var(--brand) 13%, transparent) !important;
    border: 0 !important;
    border-radius: var(--r-pill) !important;
    color: var(--brand-strong) !important;
    padding: .1rem .55rem;
    font-size: var(--fs-xs);
    font-weight: 650;
  }

  /* the "clear" glyph is a bare × character — Cairo has no glyph for it, so it
     renders as tofu in Arabic. Force the latin face and give it a hit area. */
  .select2-container--default .select2-selection__clear {
    font-family: "IBM Plex Sans Arabic", ui-sans-serif, system-ui, sans-serif !important;
    font-size: 1.05rem !important;
    line-height: 1 !important;
    font-weight: 500 !important;
    color: var(--text-3) !important;
    margin-inline-end: .35rem;
    padding-inline: .2rem;
  }
  .select2-container--default .select2-selection__clear:hover { color: var(--danger) !important; }

  /* ------------------------------------------------------ RICH TEXT / MISC */
  .note-editor.note-frame, .ck-editor__editable {
    border: 1px solid var(--border) !important;
    border-radius: var(--r-sm) !important;
    background: var(--surface) !important;
    color: var(--text) !important;
  }
  .note-toolbar, .ck.ck-toolbar {
    background: var(--surface-2) !important;
    border-color: var(--border) !important;
  }
  .note-editable { background: var(--surface) !important; color: var(--text) !important; min-block-size: 8rem; }
  .note-btn { background: var(--surface) !important; border-color: var(--border) !important; color: var(--text-2) !important; }

  /* SweetAlert-ish (if used) */
  .swal2-popup {
    border-radius: var(--r-xl) !important;
    background: var(--surface) !important;
    color: var(--text) !important;
    font-family: var(--font-sans) !important;
  }
  .swal2-title { color: var(--text) !important; font-size: var(--fs-lg) !important; }
  .swal2-html-container { color: var(--text-2) !important; font-size: var(--fs-base) !important; }
  .swal2-styled.swal2-confirm { background: var(--brand) !important; border-radius: var(--r-sm) !important; }
  .swal2-styled.swal2-cancel { background: var(--surface-3) !important; color: var(--text-2) !important; border-radius: var(--r-sm) !important; }
}

/* ==========================================================================
   UTILITIES (tiny, intentional set)
   ========================================================================== */
@layer utilities {
  .row     { display: flex; align-items: center; gap: var(--g, .6rem); }
  .row-top { display: flex; align-items: flex-start; gap: var(--g, .6rem); }
  .col     { display: flex; flex-direction: column; gap: var(--g, .6rem); }
  .wrap    { flex-wrap: wrap; }
  .between { justify-content: space-between; }
  .center  { justify-content: center; }
  .end     { justify-content: flex-end; }
  .grow    { flex: 1; min-width: 0; }
  .g-0 { --g: 0 } .g-1 { --g: .25rem } .g-2 { --g: .5rem } .g-3 { --g: .75rem }
  .g-4 { --g: 1rem } .g-5 { --g: 1.25rem } .g-6 { --g: 1.5rem }
  .gap-1 { gap: .25rem } .gap-2 { gap: .5rem } .gap-3 { gap: .75rem } .gap-4 { gap: 1rem } .gap-5 { gap: 1.25rem }

  .mt-0 { margin-top: 0 } .mt-1 { margin-top: .25rem } .mt-2 { margin-top: .5rem }
  .mt-3 { margin-top: .75rem } .mt-4 { margin-top: 1rem } .mt-5 { margin-top: 1.5rem } .mt-6 { margin-top: 2rem }
  .mb-0 { margin-bottom: 0 } .mb-1 { margin-bottom: .25rem } .mb-2 { margin-bottom: .5rem }
  .mb-3 { margin-bottom: .75rem } .mb-4 { margin-bottom: 1rem } .mb-5 { margin-bottom: 1.5rem }
  .ms-auto { margin-inline-start: auto } .me-auto { margin-inline-end: auto }
  .mx-auto { margin-inline: auto }

  .p-0 { padding: 0 } .p-2 { padding: .5rem } .p-3 { padding: .75rem } .p-4 { padding: 1rem } .p-5 { padding: 1.25rem }

  .w-full { inline-size: 100% } .h-full { block-size: 100% }
  .truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
  .nowrap { white-space: nowrap }
  .balance { text-wrap: balance } .pretty { text-wrap: pretty }

  .t-start { text-align: start } .t-center { text-align: center } .t-end { text-align: end }
  .fs-xs { font-size: var(--fs-xs) } .fs-sm { font-size: var(--fs-sm) } .fs-md { font-size: var(--fs-md) }
  .fs-lg { font-size: var(--fs-lg) } .fs-xl { font-size: var(--fs-xl) }
  .fw-500 { font-weight: 500 } .fw-600 { font-weight: 600 } .fw-700 { font-weight: 700 } .fw-800 { font-weight: 800 }

  .c-brand { color: var(--brand) } .c-accent { color: var(--accent-strong) }
  .c-success { color: var(--success) } .c-warning { color: var(--warning) }
  .c-danger { color: var(--danger) } .c-muted { color: var(--text-3) } .c-text { color: var(--text) }

  .surface-2 { background: var(--surface-2) } .surface-3 { background: var(--surface-3) }
  .rounded { border-radius: var(--r-md) } .rounded-lg { border-radius: var(--r-lg) } .rounded-pill { border-radius: var(--r-pill) }
  .bordered { border: 1px solid var(--border) }
  .shadow-sm { box-shadow: var(--shadow-sm) } .shadow-md { box-shadow: var(--shadow-md) }

  .hide { display: none !important }
  @media (max-width: 720px)  { .hide-sm { display: none !important } }
  @media (max-width: 460px)  { .hide-xs { display: none !important } }

  /* a toggle that carries both of its icons and lets its own state pick one.
     Swapping data-icon in script does not work — the sprite is inlined once
     and the element is marked done, so the old glyph stays. */
  [aria-expanded="true"]  > [data-when="collapsed"],
  [aria-expanded="false"] > [data-when="expanded"] { display: none !important }
  @media (max-width: 1099px) { .hide-md { display: none !important } }
  @media (min-width: 1100px) { .only-md { display: none !important } }
}

/* ==========================================================================
   AUTH (login / 2fa) — standalone page shell
   --------------------------------------------------------------------------
   Both halves use the same three-row rhythm (mark · content · footnote) and
   the same 46px grid texture, so the split reads as one composition rather
   than two unrelated panels.
   ========================================================================== */
@layer layout {
  .auth {
    --auth-col: 26rem;         /* the shared content width on both sides */
    --auth-grid: 46px;         /* the shared background rhythm            */
    min-height: 100dvh;
    display: grid;
    grid-template-columns: 1fr 1fr;
  }
  /* ---------------- brand side ---------------- */
  .auth__aside {
    position: relative;
    overflow: hidden;
    display: grid;
    grid-template-rows: auto 1fr auto;
    gap: 1.5rem;
    padding: clamp(1.5rem, 1rem + 2vw, 3rem);
    color: #fff;
    border-inline-end: 1px solid oklch(80% 0.10 199 / .28);
    background: oklch(28% 0.038 272);
    isolation: isolate;
  }
  .auth__aside::before {
    content: "";
    position: absolute;
    inset: 0;
    z-index: -1;
    opacity: .1;
    background-image:
      linear-gradient(to right, #fff 1px, transparent 1px),
      linear-gradient(to bottom, #fff 1px, transparent 1px);
    background-size: var(--auth-grid) var(--auth-grid);
    mask-image: radial-gradient(70% 60% at 50% 40%, #000, transparent 78%);
  }
  /* every row shares one centred column, mirroring the form card */
  .auth__brand,
  .auth__pitch,
  .auth__foot { inline-size: min(100%, var(--auth-col)); margin-inline: auto; }
  .auth__pitch { align-self: center; }
  .auth__brand img { height: 44px; }
  .auth__aside h1 {
    font-size: clamp(1.6rem, 1.2rem + 1.3vw, 2.15rem);
    font-weight: 800;
    letter-spacing: -.03em;
    text-wrap: balance;
  }
  .auth__aside p { color: oklch(100% 0 0 / .74); font-size: var(--fs-base); text-wrap: pretty; }
  .auth__points { display: grid; gap: .65rem; margin-top: 1.5rem; }
  .auth__point {
    display: flex; align-items: center; gap: .65rem;
    font-size: var(--fs-base); font-weight: 600;
    color: oklch(100% 0 0 / .9);
  }
  .auth__point .icon-wrap {
    inline-size: 1.8rem; block-size: 1.8rem;
    flex: none;
    display: grid; place-items: center;
    border-radius: 9px;
    background: oklch(100% 0 0 / .14);
    border: 1px solid oklch(100% 0 0 / .18);
    backdrop-filter: blur(6px);
  }
  .auth__foot { align-self: end; font-size: var(--fs-xs); color: oklch(100% 0 0 / .55); }

  /* ---------------- form side ---------------- */
  .auth__main {
    position: relative;
    isolation: isolate;
    display: grid;
    grid-template-rows: auto 1fr auto;
    gap: 1.5rem;
    justify-items: center;
    padding: clamp(1.25rem, 1rem + 2vw, 3rem);
    background: var(--bg);
  }
  /* the same grid, faded away from the seam — ties the halves together */
  .auth__main::before {
    content: "";
    position: absolute;
    inset-block: 0;
    inset-inline-start: 0;
    inline-size: 60%;
    z-index: -1;
    opacity: .5;
    background-image:
      linear-gradient(to right, var(--border-soft) 1px, transparent 1px),
      linear-gradient(to bottom, var(--border-soft) 1px, transparent 1px);
    background-size: var(--auth-grid) var(--auth-grid);
    mask-image: linear-gradient(to right, #000, transparent);
  }
  html[dir="rtl"] .auth__main::before { mask-image: linear-gradient(to left, #000, transparent); }
  :root[data-theme="dark"] .auth__main::before { opacity: .3; }
  @media (max-width: 940px) { .auth__main::before { display: none; } }

  .auth__bar,
  .auth__card,
  .auth__legal { inline-size: min(100%, var(--auth-col)); }
  .auth__bar { display: flex; align-items: center; gap: .5rem; }
  .auth__bar-spacer { flex: 1; }
  .auth__card { align-self: center; display: flex; flex-direction: column; gap: 1.35rem; }
  .auth__legal { align-self: end; font-size: var(--fs-xs); color: var(--text-3); text-align: center; }

  .auth__head h2 { font-size: var(--fs-2xl); font-weight: 800; letter-spacing: -.025em; }
  .auth__head p { color: var(--text-3); font-size: var(--fs-base); margin-top: .3rem; }
  .auth__form { display: flex; flex-direction: column; gap: 1rem; }

  /* the mobile lock-up only exists when the brand panel is gone */
  .auth__mobile-brand { display: none; }
  /* on desktop there is no brand in the bar, so the controls sit on the text axis */
  @media (min-width: 941px) { .auth__bar-spacer { display: none; } }

  /* ---------------- narrow: one column, brand panel folded away ------------ */
  @media (max-width: 940px) {
    .auth { grid-template-columns: minmax(0, 1fr); }
    .auth__aside { display: none; }
    .auth__main { min-height: 100dvh; }
    .auth__mobile-brand { display: flex; }
    .auth__bar { justify-content: space-between; flex-wrap: wrap; }
    .auth__bar .seg { flex: none; }
  }
  @media (max-width: 420px) {
    .auth__main { gap: 1rem; padding-inline: 1rem; }
    .auth__bar { gap: .35rem; }
    .auth__mobile-brand img { height: 22px; }
  }
}

/* ==========================================================================
   RICH TEXT EDITOR (see mountEditor in offto.js)
   ========================================================================== */
@layer components {
  .ed {
    border: 1px solid var(--border);
    border-radius: var(--r-sm);
    background: var(--surface);
    overflow: clip;
    transition: border-color var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease);
  }
  .ed:focus-within { border-color: var(--brand); box-shadow: var(--ring); }

  .ed__bar {
    display: flex; align-items: center; gap: .1rem; flex-wrap: wrap;
    padding: .35rem .4rem;
    background: var(--surface-2);
    border-block-end: 1px solid var(--border-soft);
  }
  .ed__sep { inline-size: 1px; block-size: 1.1rem; background: var(--border); margin-inline: .25rem; }

  .ed-btn {
    min-inline-size: 1.9rem; block-size: 1.9rem;
    padding-inline: .3rem;
    display: inline-grid; place-items: center;
    border-radius: var(--r-xs);
    color: var(--text-2);
    font-size: var(--fs-xs);
    transition: background var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
  }
  .ed-btn:hover { background: var(--surface-3); color: var(--text); }
  .ed-btn[aria-pressed="true"] {
    background: color-mix(in oklab, var(--brand) 15%, transparent);
    color: var(--brand-strong);
  }
  .ed-btn__txt { font-weight: 800; font-size: var(--fs-xs); line-height: 1; }
  .ed-btn[data-cmd="italic"] .ed-btn__txt { font-style: italic; }
  .ed-btn[data-cmd="underline"] .ed-btn__txt { text-decoration: underline; }

  .ed__area {
    min-block-size: 9rem;
    max-block-size: 26rem;
    overflow-y: auto;
    padding: .8rem .9rem;
    font-size: var(--fs-base);
    line-height: 1.65;
    color: var(--text);
    outline: none;
  }
  .ed__area:empty::before {
    content: attr(data-placeholder);
    color: var(--text-3);
  }
  /* the content is user HTML, so it needs its own type scale back */
  .ed__area > * + * { margin-block-start: .7rem; }
  .ed__area h2 { font-size: var(--fs-lg); font-weight: 750; }
  .ed__area h3 { font-size: var(--fs-md); font-weight: 700; }
  .ed__area a { color: var(--brand-strong); text-decoration: underline; }
  .ed__area :is(ul, ol) { padding-inline-start: 1.4rem; }
  .ed__area ul { list-style: disc; }
  .ed__area ol { list-style: decimal; }
  .ed__area li { margin-block: .2rem; }
  .ed__area img { max-inline-size: 100%; height: auto; border-radius: var(--r-xs); }
  .ed__area hr { border: 0; border-block-start: 1px solid var(--border); margin-block: 1rem; }
  .ed__area blockquote {
    padding-inline-start: .9rem;
    border-inline-start: 3px solid var(--border-strong);
    color: var(--text-2);
  }

  /* the textarea lives inside the widget: hidden while editing visually,
     shown as the raw-HTML view when the code button is on */
  .ed > textarea.ed__source { display: none; }
  .ed.is-source > .ed__area { display: none; }
  .ed.is-source > textarea.ed__source {
    display: block;
    inline-size: 100%;
    min-block-size: 11rem;
    padding: .8rem .9rem;
    border: 0;
    border-radius: 0;
    background: var(--surface-inset);
    color: var(--text);
    font: 400 var(--fs-sm)/1.6 var(--font-mono);
    resize: vertical;
    outline: none;
    direction: ltr;
    text-align: start;
  }
}

/* ==========================================================================
   SETTINGS
   A settings page is a list of decisions, not a form grid. Each row says what
   the switch does before you have to guess from a field label.
   ========================================================================== */
@layer components {
  .setting-list { display: grid; }
  .setting-row {
    display: flex;
    align-items: center;
    gap: 1rem;
    padding: 1rem 1.15rem;
    flex-wrap: wrap;
  }
  .setting-row + .setting-row { border-block-start: 1px solid var(--border-soft); }
  .setting-row__ico {
    inline-size: 2.4rem; block-size: 2.4rem;
    flex: none;
    display: grid; place-items: center;
    border-radius: 11px;
    background: color-mix(in oklab, var(--brand) 12%, transparent);
    color: var(--brand-strong);
  }
  /* the tile colour is the state read-out */
  .setting-row[data-state="active"] .setting-row__ico {
    background: color-mix(in oklab, var(--success) 14%, transparent); color: var(--success);
  }
  .setting-row[data-state="soon"] .setting-row__ico {
    background: color-mix(in oklab, var(--info) 14%, transparent); color: var(--info);
  }
  .setting-row[data-state="maintenance"] .setting-row__ico {
    background: color-mix(in oklab, var(--warning) 20%, transparent);
    color: color-mix(in oklab, var(--warning) 76%, var(--text));
  }
  .setting-row[data-state="hidden"] .setting-row__ico { background: var(--surface-3); color: var(--text-3); }
  .setting-row[data-state="disabled"] .setting-row__ico {
    background: color-mix(in oklab, var(--danger) 12%, transparent); color: var(--danger);
  }

  .setting-row__bd { flex: 1 1 14rem; min-inline-size: 0; }
  .setting-row__bd b { display: block; font-weight: 650; color: var(--text); }
  .setting-row__bd p { font-size: var(--fs-sm); color: var(--text-3); margin-block-start: .15rem; text-wrap: pretty; }
  .setting-row__ctl { flex: 0 0 auto; display: flex; align-items: center; gap: .6rem; }
  /* a row whose switch is off keeps its controls visible but clearly inert */
  .setting-row.is-off :is(.setting-row__ico, .setting-row__bd) { opacity: .55; }
  .setting-row.is-off :is(.select, .input-group) { opacity: .5; }
  .setting-row__ctl .select { min-inline-size: 11rem; }

  /* ---------------------------------------------------- weekly schedule */
  .day-row {
    display: grid;
    grid-template-columns: minmax(10rem, 1fr) minmax(0, 9.5rem) auto minmax(0, 9.5rem);
    align-items: center;
    gap: .6rem 1rem;
    padding: .8rem 1.15rem;
  }
  .day-row + .day-row { border-block-start: 1px solid var(--border-soft); }
  .day-row__name { display: flex; align-items: center; gap: .6rem; font-weight: 650; min-inline-size: 0; }
  .day-row__state {
    font-size: var(--fs-xs); font-weight: 700;
    color: var(--text-3);
    padding: .1rem .5rem;
    border-radius: var(--r-pill);
    background: var(--surface-3);
  }
  .day-row.is-open .day-row__state {
    color: var(--success);
    background: color-mix(in oklab, var(--success) 14%, transparent);
  }
  .day-row__sep { color: var(--text-3); font-size: var(--fs-sm); }
  .day-row .input { inline-size: 100%; }
  .day-row .field-time { display: block; min-inline-size: 0; }
  .day-row .field-time > span { display: none; }
  /* a closed day keeps its hours on screen but greys them out */
  .day-row:not(.is-open) :is(.input, .day-row__sep) { opacity: .45; }
  .day-row__head {
    display: grid;
    grid-template-columns: minmax(10rem, 1fr) minmax(0, 9.5rem) auto minmax(0, 9.5rem);
    gap: .6rem 1rem;
    padding: .6rem 1.15rem;
    background: var(--surface-2);
    border-block-end: 1px solid var(--border);
    font-size: var(--fs-2xs); font-weight: 750;
    letter-spacing: .07em; text-transform: uppercase;
    color: var(--text-3);
  }

  @container page (max-width: 720px) {
    .day-row, .day-row__head { grid-template-columns: 1fr 1fr; }
    .day-row__head { display: none; }
    .day-row__name { grid-column: 1 / -1; }
    .day-row__sep { display: none; }
    /* the column header is gone, so each input names itself again */
    .day-row .field-time { display: flex; flex-direction: column; gap: .25rem; }
    .day-row .field-time > span {
      display: block;
      font-size: var(--fs-2xs); font-weight: 700;
      letter-spacing: .05em; text-transform: uppercase; color: var(--text-3);
    }
    .setting-row { padding: .9rem .85rem; }
    .setting-row__ctl { flex: 1 1 100%; }
    .setting-row__ctl .select { inline-size: 100%; }
  }
}

/* ==========================================================================
   DIFF TABLE — audit-log "before → current"
   Reading a change log means finding the two rows that moved, so the changed
   rows are the ones that carry colour and weight; everything else recedes.
   ========================================================================== */
@layer components {
  .diff-head {
    display: flex; align-items: center; gap: .6rem; flex-wrap: wrap;
    padding: .8rem 1.15rem;
    border-block-end: 1px solid var(--border-soft);
  }
  .diff-head__spacer { flex: 1; min-inline-size: 1rem; }

  .legend-dot {
    inline-size: .6rem; block-size: .6rem;
    border-radius: 50%;
    flex: none;
    background: var(--brand);
  }
  .legend-dot.is-added   { background: var(--success); }
  .legend-dot.is-removed { background: var(--danger); }

  table.diff { inline-size: 100%; }
  table.diff thead th {
    padding: .6rem .9rem;
    text-align: start;
    font-size: var(--fs-2xs); font-weight: 750;
    letter-spacing: .07em; text-transform: uppercase;
    color: var(--text-3);
    background: var(--surface-2);
    border-block-end: 1px solid var(--border);
  }
  table.diff tbody td { padding: .6rem .9rem; vertical-align: middle; border-block-end: 1px solid var(--border-soft); }
  table.diff tbody tr:last-child td { border-block-end: 0; }

  /* three tracks: the field, then the two values side by side */
  table.diff .diff__key   { inline-size: 32%; min-inline-size: 11rem; }
  table.diff .diff__before,
  table.diff .diff__after { inline-size: 34%; }

  .diff__key b { display: block; font-weight: 650; color: var(--text); }
  .diff__key code {
    font: 500 var(--fs-2xs)/1.5 var(--font-mono);
    color: var(--text-3);
  }
  .diff__empty { color: var(--text-3); }
  .diff__secret { font-family: var(--font-mono); letter-spacing: .1em; color: var(--text-3); }
  .diff__url {
    display: inline-block;
    max-inline-size: 22rem;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
    vertical-align: bottom;
    color: var(--brand-strong); font-weight: 600;
  }
  .diff__file { display: inline-flex; align-items: center; gap: .5rem; min-inline-size: 0; }
  .diff__file img {
    inline-size: 2.25rem; block-size: 2.25rem;
    border-radius: var(--r-xs);
    object-fit: cover;
    background: var(--surface-3);
    color: transparent;
  }

  /* ---- state ---- */
  table.diff tbody tr[data-state="same"] :is(.diff__before, .diff__after) { color: var(--text-3); }
  table.diff tbody tr:not([data-state="same"]) {
    background: color-mix(in oklab, var(--brand) 3.5%, transparent);
  }
  table.diff tbody tr:not([data-state="same"]) .diff__before {
    color: var(--text-3);
    text-decoration: line-through;
    text-decoration-color: color-mix(in oklab, var(--danger) 60%, transparent);
    text-decoration-thickness: 1.5px;
  }
  table.diff tbody tr:not([data-state="same"]) .diff__after { color: var(--text); font-weight: 650; }
  /* a marker in the gutter, so the changed rows are findable at a glance */
  table.diff tbody tr:not([data-state="same"]) .diff__key {
    box-shadow: inset 3px 0 0 var(--brand);
  }
  html[dir="rtl"] table.diff tbody tr:not([data-state="same"]) .diff__key {
    box-shadow: inset -3px 0 0 var(--brand);
  }
  table.diff tbody tr[data-state="added"] .diff__key   { box-shadow: inset 3px 0 0 var(--success); }
  table.diff tbody tr[data-state="removed"] .diff__key { box-shadow: inset 3px 0 0 var(--danger); }
  html[dir="rtl"] table.diff tbody tr[data-state="added"] .diff__key   { box-shadow: inset -3px 0 0 var(--success); }
  html[dir="rtl"] table.diff tbody tr[data-state="removed"] .diff__key { box-shadow: inset -3px 0 0 var(--danger); }

  table.diff[data-show="changed"] tbody tr[data-state="same"] { display: none; }

  /* ---- phone: three columns will not fit, so each field becomes a block --- */
  @container page (max-width: 720px) {
    table.diff, table.diff tbody { display: block; }
    table.diff thead { display: none; }
    table.diff tbody tr {
      display: grid;
      grid-template-columns: minmax(0, 1fr);
      gap: .3rem;
      padding: .7rem .85rem;
      border: 1px solid var(--border);
      border-radius: var(--r-md);
      background: var(--surface);
    }
    table.diff tbody tr + tr { margin-block-start: .5rem; }
    table.diff tbody td { display: block; inline-size: auto !important; padding: 0; border: 0; }
    table.diff .diff__key { box-shadow: none !important; margin-block-end: .15rem; }
    table.diff .diff__before::before,
    table.diff .diff__after::before {
      content: attr(data-side);
      display: inline-block;
      min-inline-size: 4.5rem;
      font-size: var(--fs-2xs); font-weight: 750;
      letter-spacing: .05em; text-transform: uppercase;
      color: var(--text-3);
    }
    table.diff tbody tr:not([data-state="same"]) {
      border-inline-start: 3px solid var(--brand);
    }
    table.diff tbody tr[data-state="added"]   { border-inline-start-color: var(--success); }
    table.diff tbody tr[data-state="removed"] { border-inline-start-color: var(--danger); }
  }
}

/* ==========================================================================
   FILTERS — the toolbar above a table
   One bar (search + a toggle + the page tools) with a collapsible grid of
   fields under it. Every control is the same height and every column the
   same width, which is what the old "one row of random-width boxes" lacked.
   ========================================================================== */
@layer components {
  .filters { --ctl-h: 2.5rem; display: block; }

  .filters__bar {
    display: flex; align-items: center; gap: .5rem; flex-wrap: wrap;
    padding: .8rem 1.15rem;
    border-block-end: 1px solid var(--border-soft);
  }
  .filters__search { flex: 1 1 15rem; min-inline-size: 0; max-inline-size: 26rem; }
  .filters__search .input { block-size: var(--ctl-h); }
  .filters__bar .sep-v { block-size: 1.4rem; }
  .filters__tools { display: flex; align-items: center; gap: .35rem; margin-inline-start: auto; }

  .filters__toggle { position: relative; }
  .filters__toggle .filters__caret { transition: rotate var(--t-fast) var(--ease); }
  .filters[data-open="true"] .filters__toggle .filters__caret { rotate: 180deg; }
  .filters__count {
    min-inline-size: 1.15rem;
    padding-inline: .3rem;
    border-radius: var(--r-pill);
    background: var(--brand);
    color: var(--on-brand, #fff);
    font-size: var(--fs-2xs); font-weight: 800;
    font-variant-numeric: tabular-nums;
    line-height: 1.35;
  }
  .filters__count[hidden] { display: none; }

  /* ------------------------------------------------------------- panel */
  .filters__panel {
    padding: 1rem 1.15rem 1.05rem;
    background: var(--surface-2);
    border-block-end: 1px solid var(--border-soft);
  }
  .filters__panel[hidden] { display: none; }

  /* uniform tracks: no more 60px-wide selects next to 400px inputs */
  .filters__grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(13.5rem, 1fr));
    gap: .8rem .9rem;
    align-items: end;
  }
  .filters__field { display: flex; flex-direction: column; gap: .3rem; min-inline-size: 0; }
  .filters__field > .label,
  .filters__field > label {
    font-size: var(--fs-2xs);
    font-weight: 750;
    letter-spacing: .05em;
    text-transform: uppercase;
    color: var(--text-3);
    margin: 0;
  }
  .filters__field :is(.input, .select, input, select) {
    inline-size: 100%;
    min-inline-size: 0;
    block-size: var(--ctl-h);
    min-block-size: var(--ctl-h);
    /* background-color, not the shorthand: the shorthand wipes the CSS-drawn
       select arrow and resets its size, which blew it up to fill the box */
    background-color: var(--surface);
  }
  .filters__field .input-group { inline-size: 100%; }
  /* select2 replaces the <select>, so it needs the same height by hand */
  .filters__field .select2-container { inline-size: 100% !important; }
  .filters__field .select2-container--default .select2-selection--single {
    block-size: var(--ctl-h) !important;
    min-block-size: var(--ctl-h) !important;
    background-color: var(--surface) !important;
  }
  .filters__field .select2-container--default .select2-selection--single .select2-selection__rendered {
    line-height: calc(var(--ctl-h) - 2px) !important;
  }
  .filters__field .select2-container--default .select2-selection--single .select2-selection__arrow {
    block-size: var(--ctl-h) !important;
  }

  .filters__foot {
    display: flex; align-items: center; gap: .5rem; flex-wrap: wrap;
    margin-block-start: .9rem;
    padding-block-start: .85rem;
    border-block-start: 1px dashed var(--border);
  }
  .filters__chips { display: flex; gap: .35rem; flex-wrap: wrap; flex: 1; min-inline-size: 0; }
  .filters__chip {
    display: inline-flex; align-items: center; gap: .35rem;
    padding: .2rem .3rem .2rem .6rem;
    padding-inline: .6rem .3rem;
    border-radius: var(--r-pill);
    background: color-mix(in oklab, var(--brand) 12%, transparent);
    color: var(--brand-strong);
    font-size: var(--fs-xs); font-weight: 650;
    max-inline-size: 16rem;
  }
  .filters__chip b { font-weight: 800; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .filters__chip button {
    inline-size: 1.15rem; block-size: 1.15rem;
    display: grid; place-items: center;
    border-radius: 50%;
    color: inherit; opacity: .65;
  }
  .filters__chip button:hover { opacity: 1; background: color-mix(in oklab, var(--brand) 22%, transparent); }
  .filters__chip .icon { inline-size: .7rem; block-size: .7rem; }

  @container page (max-width: 640px) {
    .filters__bar { padding: .7rem .8rem; }
    .filters__panel { padding: .85rem .8rem .9rem; }
    .filters__grid { grid-template-columns: minmax(0, 1fr); }
    .filters__search { flex: 1 1 8rem; max-inline-size: none; }
    .filters__foot .btn { flex: 1; justify-content: center; }
  }
}

/* ==========================================================================
   RESPONSIVE TABLES
   A wide admin table cannot shrink to a phone, and side-scrolling a 14-column
   grid is miserable. Below the breakpoint each row becomes a small card and
   every cell carries its column name, injected as data-label by offto.js.
   ========================================================================== */
@layer components {
  /* horizontal scroll gets a visible edge so it is obvious there is more */
  .tbl-wrap, .dt-layout-table, .dt-scroll-body {
    scrollbar-width: thin;
    scrollbar-color: var(--border-strong) transparent;
  }
  .tbl-wrap::-webkit-scrollbar, .dt-layout-table::-webkit-scrollbar { block-size: 8px; }
  .tbl-wrap::-webkit-scrollbar-thumb, .dt-layout-table::-webkit-scrollbar-thumb {
    background: var(--border-strong); border-radius: 99px;
  }

  /* a wide table clipped by the card edge looks like the data just stops.
     initScrollShadows() in offto.js flags which edges can still scroll. */
  :is(.tbl-wrap, .dt-layout-table, .dt-scroll-body) { position: relative; }
  .scroll-x { position: relative; }
  .scroll-x::before, .scroll-x::after {
    content: "";
    position: absolute;
    inset-block: 0;
    inline-size: 2.5rem;
    pointer-events: none;
    opacity: 0;
    transition: opacity var(--t) var(--ease);
    z-index: 3;
  }
  .scroll-x::before { inset-inline-start: 0; background: linear-gradient(to right, var(--surface), transparent); }
  .scroll-x::after  { inset-inline-end: 0;  background: linear-gradient(to left,  var(--surface), transparent); }
  html[dir="rtl"] .scroll-x::before { background: linear-gradient(to left, var(--surface), transparent); }
  html[dir="rtl"] .scroll-x::after  { background: linear-gradient(to right, var(--surface), transparent); }
  .scroll-x.can-start::before { opacity: 1; }
  .scroll-x.can-end::after { opacity: 1; }
  .scroll-x.can-end .scroll-x__hint { opacity: 1; }

  /* the actions column stays narrow and never wraps */
  :is(table.tbl, table.dataTable) :is(th, td).col-actions {
    inline-size: 1%;
    white-space: nowrap;
    text-align: end;
  }
  .row-actions { display: inline-flex; align-items: center; gap: .2rem; justify-content: flex-end; }
  /* menu rows: start-aligned, with a fixed gutter so every label lines up */
  .pop .pop__item {
    justify-content: flex-start;
    text-align: start;
    white-space: nowrap;
  }
  .pop .pop__item > :is(svg, i, [data-icon]):first-child,
  .pop .pop__item > :is(.icon, .navi-icon) { flex: 0 0 1.1rem; }

  @container page (max-width: 780px) {
    :is(table.tbl, table.dataTable):is([data-cards], .dt-cards) {
      display: block;
      /* !important because DataTables writes a pixel width straight onto the
         table element once it has measured the columns */
      inline-size: 100% !important;
      max-inline-size: 100% !important;
      /* several legacy tables carry an inline min-width:700px */
      min-inline-size: 0 !important;
    }
    :is(table.tbl, table.dataTable)[data-cards] > tbody > tr > :is(td, th) {
      inline-size: auto !important;
    }
    :is(table.tbl, table.dataTable)[data-cards] > :is(thead, .dt-scroll-head) { display: none; }
    :is(table.tbl, table.dataTable)[data-cards] > tbody { display: grid; gap: .6rem; }
    :is(table.tbl, table.dataTable)[data-cards] > tbody > tr {
      display: grid;
      /* an implicit `auto` track is sized by its widest cell — that is what
         made a 14-column row 900px wide inside a 358px card */
      grid-template-columns: minmax(0, 1fr);
      gap: .1rem;
      padding: .75rem .85rem;
      border: 1px solid var(--border);
      border-radius: var(--r-md);
      background: var(--surface);
      box-shadow: var(--shadow-xs);
    }
    /* flex, not grid: a cell can hold several elements (avatar + name + mail)
       and they must flow after the label instead of each claiming a new row.
       min-inline-size: 0 everywhere is what stops a long e-mail from making
       the card wider than the screen. */
    :is(table.tbl, table.dataTable)[data-cards] > tbody > tr > :is(td, th) {
      display: flex;
      flex-wrap: wrap;
      align-items: center;
      gap: .25rem .75rem;
      padding: .34rem 0;
      border: 0;
      min-inline-size: 0;
      white-space: normal !important;
      overflow-wrap: break-word;
      text-align: start;
      background: none;
    }
    :is(table.tbl, table.dataTable)[data-cards] > tbody > tr > :is(td, th) > * { min-inline-size: 0; max-inline-size: 100%; }
    :is(table.tbl, table.dataTable)[data-cards] > tbody > tr > :is(td, th) + td {
      border-block-start: 1px dashed var(--border-soft);
    }
    :is(table.tbl, table.dataTable)[data-cards] > tbody > tr > :is(td, th)::before {
      content: attr(data-label);
      flex: 0 0 clamp(4.5rem, 30%, 9rem);
      align-self: center;
      font-size: var(--fs-2xs);
      font-weight: 750;
      letter-spacing: .05em;
      text-transform: uppercase;
      color: var(--text-3);
    }
    /* cells with no header text, and the actions row, span the full width */
    :is(table.tbl, table.dataTable)[data-cards] > tbody > tr > :is(td, th)[data-label=""]::before { display: none; }
    :is(table.tbl, table.dataTable)[data-cards] > tbody > tr > :is(td, th).col-actions::before { display: none; }
    :is(table.tbl, table.dataTable)[data-cards] > tbody > tr > :is(td, th).col-actions {
      justify-content: flex-end;
      gap: .25rem;
      margin-block-start: .35rem;
      padding-block-start: .55rem;
      border-block-start: 1px solid var(--border-soft) !important;
    }
    :is(table.tbl, table.dataTable)[data-cards] > tbody > tr > :is(td, th).dt-empty { justify-content: center; }
    :is(table.tbl, table.dataTable)[data-cards] > tbody > tr > :is(td, th).dt-empty::before { display: none; }
    /* the wrapper no longer needs to scroll once the rows are cards */
    .card:has(table[data-cards]) :is(.tbl-wrap, .dt-layout-table) { overflow-x: visible; }
    .dt-layout-table:has(table[data-cards]) { padding-inline: .8rem; }
  }
}

/* ==========================================================================
   LEGACY BOOTSTRAP / METRONIC COMPAT
   The DataTables render functions in the real project emit Bootstrap 4 +
   Metronic markup at runtime, so it can never be rewritten at build time.
   These rules give that markup our look instead of leaving it unstyled.
   Selectors stay compound on purpose — `.label` alone is our form label.
   ========================================================================== */
@layer plugins {

  /* --------------------------------------- Bootstrap's 12-column grid
     Only a handful of legacy pages still use it. Rather than reimplement the
     breakpoints, the columns become flexible tracks that wrap — which is what
     the 12-column grid was approximating anyway. */
  .row:has(> [class*="col-"]) { flex-wrap: wrap; align-items: flex-start; }
  [class*="col-"]:not(.col-actions, .col-form-label, .dt-layout-cell) {
    flex: 1 1 13rem;
    min-inline-size: 0;
    max-inline-size: 100%;
  }
  :is(.col-12, .col-sm-12, .col-md-12, .col-lg-12, .col-xl-12) { flex-basis: 100%; }

  /* ---------------------------------------------------- display & flex */
  .d-flex { display: flex; }
  .d-inline-flex { display: inline-flex; }
  .d-block { display: block; }
  .d-inline-block { display: inline-block; }
  .d-inline { display: inline; }
  .d-none { display: none; }
  .flex-column { flex-direction: column; }
  .flex-row { flex-direction: row; }
  .flex-wrap { flex-wrap: wrap; }
  .flex-grow-1, .flex-fill { flex: 1 1 auto; min-inline-size: 0; }
  .flex-shrink-0 { flex: none; }
  /* legacy flex rows never set this, so one long e-mail stretched the row */
  :is(.d-flex, .d-inline-flex) > * { min-inline-size: 0; }
  .align-items-center { align-items: center; }
  .align-items-start { align-items: flex-start; }
  .align-items-end { align-items: flex-end; }
  .align-self-center { align-self: center; }
  .justify-content-center { justify-content: center; }
  .justify-content-between { justify-content: space-between; }
  .justify-content-end { justify-content: flex-end; }
  .justify-content-start { justify-content: flex-start; }
  .w-100 { inline-size: 100%; }
  .h-100 { block-size: 100%; }
  .text-nowrap { white-space: nowrap; }

  /* ---------------------------------------------------- text & weight */
  .text-center { text-align: center; }
  .text-right, .text-lg-right, .text-md-right, .text-sm-right { text-align: end; }
  .text-left, .text-lg-left { text-align: start; }
  .text-uppercase { text-transform: uppercase; letter-spacing: .05em; }
  .text-muted, .text-dark-50 { color: var(--text-3); }
  .text-primary, .text-hover-primary:hover { color: var(--brand-strong); }
  .text-danger { color: var(--danger); }
  .text-success { color: var(--success); }
  .text-warning { color: color-mix(in oklab, var(--warning) 78%, var(--text)); }
  .text-info { color: var(--info); }
  .text-dark { color: var(--text); }
  .font-weight-normal { font-weight: 400; }
  .font-weight-bold { font-weight: 650; }
  .font-weight-bolder, .font-weight-boldest { font-weight: 750; }
  .font-size-xs { font-size: var(--fs-2xs); }
  .font-size-sm { font-size: var(--fs-xs); }
  .font-size-lg { font-size: var(--fs-md); }
  .font-size-h6 { font-size: var(--fs-md); font-weight: 700; }

  .m-0 { margin: 0; }
  .m-1 { margin: .25rem; }
  .m-2 { margin: .5rem; }
  .m-3 { margin: .75rem; }
  .m-4 { margin: 1rem; }
  .m-5 { margin: 1.5rem; }
  .m-6 { margin: 2rem; }
  .m-7 { margin: 2.25rem; }
  .m-8 { margin: 2.5rem; }
  .m-9 { margin: 2.75rem; }
  .m-10 { margin: 3rem; }
  .m-11 { margin: 3.5rem; }
  .m-12 { margin: 4rem; }
  .p-0 { padding: 0; }
  .p-1 { padding: .25rem; }
  .p-2 { padding: .5rem; }
  .p-3 { padding: .75rem; }
  .p-4 { padding: 1rem; }
  .p-5 { padding: 1.5rem; }
  .p-6 { padding: 2rem; }
  .p-7 { padding: 2.25rem; }
  .p-8 { padding: 2.5rem; }
  .p-9 { padding: 2.75rem; }
  .p-10 { padding: 3rem; }
  .p-11 { padding: 3.5rem; }
  .p-12 { padding: 4rem; }
  .ml-0 { margin-inline-start: 0; }
  .ml-1 { margin-inline-start: .25rem; }
  .ml-2 { margin-inline-start: .5rem; }
  .ml-3 { margin-inline-start: .75rem; }
  .ml-4 { margin-inline-start: 1rem; }
  .ml-5 { margin-inline-start: 1.5rem; }
  .ml-6 { margin-inline-start: 2rem; }
  .ml-7 { margin-inline-start: 2.25rem; }
  .ml-8 { margin-inline-start: 2.5rem; }
  .ml-9 { margin-inline-start: 2.75rem; }
  .ml-10 { margin-inline-start: 3rem; }
  .ml-11 { margin-inline-start: 3.5rem; }
  .ml-12 { margin-inline-start: 4rem; }
  .mr-0 { margin-inline-end: 0; }
  .mr-1 { margin-inline-end: .25rem; }
  .mr-2 { margin-inline-end: .5rem; }
  .mr-3 { margin-inline-end: .75rem; }
  .mr-4 { margin-inline-end: 1rem; }
  .mr-5 { margin-inline-end: 1.5rem; }
  .mr-6 { margin-inline-end: 2rem; }
  .mr-7 { margin-inline-end: 2.25rem; }
  .mr-8 { margin-inline-end: 2.5rem; }
  .mr-9 { margin-inline-end: 2.75rem; }
  .mr-10 { margin-inline-end: 3rem; }
  .mr-11 { margin-inline-end: 3.5rem; }
  .mr-12 { margin-inline-end: 4rem; }
  .mt-0 { margin-block-start: 0; }
  .mt-1 { margin-block-start: .25rem; }
  .mt-2 { margin-block-start: .5rem; }
  .mt-3 { margin-block-start: .75rem; }
  .mt-4 { margin-block-start: 1rem; }
  .mt-5 { margin-block-start: 1.5rem; }
  .mt-6 { margin-block-start: 2rem; }
  .mt-7 { margin-block-start: 2.25rem; }
  .mt-8 { margin-block-start: 2.5rem; }
  .mt-9 { margin-block-start: 2.75rem; }
  .mt-10 { margin-block-start: 3rem; }
  .mt-11 { margin-block-start: 3.5rem; }
  .mt-12 { margin-block-start: 4rem; }
  .mb-0 { margin-block-end: 0; }
  .mb-1 { margin-block-end: .25rem; }
  .mb-2 { margin-block-end: .5rem; }
  .mb-3 { margin-block-end: .75rem; }
  .mb-4 { margin-block-end: 1rem; }
  .mb-5 { margin-block-end: 1.5rem; }
  .mb-6 { margin-block-end: 2rem; }
  .mb-7 { margin-block-end: 2.25rem; }
  .mb-8 { margin-block-end: 2.5rem; }
  .mb-9 { margin-block-end: 2.75rem; }
  .mb-10 { margin-block-end: 3rem; }
  .mb-11 { margin-block-end: 3.5rem; }
  .mb-12 { margin-block-end: 4rem; }
  .mx-0 { margin-inline: 0; }
  .mx-1 { margin-inline: .25rem; }
  .mx-2 { margin-inline: .5rem; }
  .mx-3 { margin-inline: .75rem; }
  .mx-4 { margin-inline: 1rem; }
  .mx-5 { margin-inline: 1.5rem; }
  .mx-6 { margin-inline: 2rem; }
  .mx-7 { margin-inline: 2.25rem; }
  .mx-8 { margin-inline: 2.5rem; }
  .mx-9 { margin-inline: 2.75rem; }
  .mx-10 { margin-inline: 3rem; }
  .mx-11 { margin-inline: 3.5rem; }
  .mx-12 { margin-inline: 4rem; }
  .my-0 { margin-block: 0; }
  .my-1 { margin-block: .25rem; }
  .my-2 { margin-block: .5rem; }
  .my-3 { margin-block: .75rem; }
  .my-4 { margin-block: 1rem; }
  .my-5 { margin-block: 1.5rem; }
  .my-6 { margin-block: 2rem; }
  .my-7 { margin-block: 2.25rem; }
  .my-8 { margin-block: 2.5rem; }
  .my-9 { margin-block: 2.75rem; }
  .my-10 { margin-block: 3rem; }
  .my-11 { margin-block: 3.5rem; }
  .my-12 { margin-block: 4rem; }
  .pl-0 { padding-inline-start: 0; }
  .pl-1 { padding-inline-start: .25rem; }
  .pl-2 { padding-inline-start: .5rem; }
  .pl-3 { padding-inline-start: .75rem; }
  .pl-4 { padding-inline-start: 1rem; }
  .pl-5 { padding-inline-start: 1.5rem; }
  .pl-6 { padding-inline-start: 2rem; }
  .pl-7 { padding-inline-start: 2.25rem; }
  .pl-8 { padding-inline-start: 2.5rem; }
  .pl-9 { padding-inline-start: 2.75rem; }
  .pl-10 { padding-inline-start: 3rem; }
  .pl-11 { padding-inline-start: 3.5rem; }
  .pl-12 { padding-inline-start: 4rem; }
  .pr-0 { padding-inline-end: 0; }
  .pr-1 { padding-inline-end: .25rem; }
  .pr-2 { padding-inline-end: .5rem; }
  .pr-3 { padding-inline-end: .75rem; }
  .pr-4 { padding-inline-end: 1rem; }
  .pr-5 { padding-inline-end: 1.5rem; }
  .pr-6 { padding-inline-end: 2rem; }
  .pr-7 { padding-inline-end: 2.25rem; }
  .pr-8 { padding-inline-end: 2.5rem; }
  .pr-9 { padding-inline-end: 2.75rem; }
  .pr-10 { padding-inline-end: 3rem; }
  .pr-11 { padding-inline-end: 3.5rem; }
  .pr-12 { padding-inline-end: 4rem; }
  .pt-0 { padding-block-start: 0; }
  .pt-1 { padding-block-start: .25rem; }
  .pt-2 { padding-block-start: .5rem; }
  .pt-3 { padding-block-start: .75rem; }
  .pt-4 { padding-block-start: 1rem; }
  .pt-5 { padding-block-start: 1.5rem; }
  .pt-6 { padding-block-start: 2rem; }
  .pt-7 { padding-block-start: 2.25rem; }
  .pt-8 { padding-block-start: 2.5rem; }
  .pt-9 { padding-block-start: 2.75rem; }
  .pt-10 { padding-block-start: 3rem; }
  .pt-11 { padding-block-start: 3.5rem; }
  .pt-12 { padding-block-start: 4rem; }
  .pb-0 { padding-block-end: 0; }
  .pb-1 { padding-block-end: .25rem; }
  .pb-2 { padding-block-end: .5rem; }
  .pb-3 { padding-block-end: .75rem; }
  .pb-4 { padding-block-end: 1rem; }
  .pb-5 { padding-block-end: 1.5rem; }
  .pb-6 { padding-block-end: 2rem; }
  .pb-7 { padding-block-end: 2.25rem; }
  .pb-8 { padding-block-end: 2.5rem; }
  .pb-9 { padding-block-end: 2.75rem; }
  .pb-10 { padding-block-end: 3rem; }
  .pb-11 { padding-block-end: 3.5rem; }
  .pb-12 { padding-block-end: 4rem; }
  .px-0 { padding-inline: 0; }
  .px-1 { padding-inline: .25rem; }
  .px-2 { padding-inline: .5rem; }
  .px-3 { padding-inline: .75rem; }
  .px-4 { padding-inline: 1rem; }
  .px-5 { padding-inline: 1.5rem; }
  .px-6 { padding-inline: 2rem; }
  .px-7 { padding-inline: 2.25rem; }
  .px-8 { padding-inline: 2.5rem; }
  .px-9 { padding-inline: 2.75rem; }
  .px-10 { padding-inline: 3rem; }
  .px-11 { padding-inline: 3.5rem; }
  .px-12 { padding-inline: 4rem; }
  .py-0 { padding-block: 0; }
  .py-1 { padding-block: .25rem; }
  .py-2 { padding-block: .5rem; }
  .py-3 { padding-block: .75rem; }
  .py-4 { padding-block: 1rem; }
  .py-5 { padding-block: 1.5rem; }
  .py-6 { padding-block: 2rem; }
  .py-7 { padding-block: 2.25rem; }
  .py-8 { padding-block: 2.5rem; }
  .py-9 { padding-block: 2.75rem; }
  .py-10 { padding-block: 3rem; }
  .py-11 { padding-block: 3.5rem; }
  .py-12 { padding-block: 4rem; }

  /* ------------------------------------------------- Metronic .symbol */
  .symbol {
    display: inline-grid; place-items: center; flex: none;
    inline-size: 2.75rem; block-size: 2.75rem;
    overflow: hidden;
    border-radius: var(--r-sm);
    background: var(--surface-3);
  }
  .symbol.symbol-circle, .symbol.symbol-circle > * { border-radius: 50%; }
  .symbol.symbol-25 { inline-size: 1.6rem;  block-size: 1.6rem; }
  .symbol.symbol-30 { inline-size: 1.9rem;  block-size: 1.9rem; }
  .symbol.symbol-35 { inline-size: 2.2rem;  block-size: 2.2rem; }
  .symbol.symbol-40 { inline-size: 2.5rem;  block-size: 2.5rem; }
  .symbol.symbol-45 { inline-size: 2.8rem;  block-size: 2.8rem; }
  .symbol.symbol-50 { inline-size: 3.1rem;  block-size: 3.1rem; }
  .symbol.symbol-60 { inline-size: 3.75rem; block-size: 3.75rem; }
  .symbol > img { inline-size: 100%; block-size: 100%; object-fit: cover; color: transparent; }
  .symbol .symbol-label {
    inline-size: 100%; block-size: 100%;
    display: grid; place-items: center;
    background: color-mix(in oklab, var(--brand) 13%, transparent);
    color: var(--brand-strong);
    font-weight: 750; font-size: var(--fs-sm);
  }

  /* ------------------------------------ Metronic .label used as a badge */
  .label:is(.label-inline, .label-pill, .label-rounded),
  .label[class*="label-light-"] {
    display: inline-flex; align-items: center; justify-content: center;
    gap: .3rem;
    padding: .2rem .55rem;
    border-radius: var(--r-pill);
    font-size: var(--fs-xs);
    font-weight: 700;
    line-height: 1.6;
    white-space: nowrap;
    background: var(--surface-3);
    color: var(--text-2);
  }
  .label:is(.label-light-success, .label-success) { background: color-mix(in oklab, var(--success) 16%, transparent); color: var(--success); }
  .label:is(.label-light-danger,  .label-danger)  { background: color-mix(in oklab, var(--danger) 14%, transparent);  color: var(--danger); }
  .label:is(.label-light-warning, .label-warning) { background: color-mix(in oklab, var(--warning) 22%, transparent); color: color-mix(in oklab, var(--warning) 76%, var(--text)); }
  .label:is(.label-light-primary, .label-primary) { background: color-mix(in oklab, var(--brand) 13%, transparent);   color: var(--brand-strong); }
  .label:is(.label-light-info,    .label-info)    { background: color-mix(in oklab, var(--info) 14%, transparent);    color: var(--info); }
  .label:is(.label-light-dark,    .label-dark)    { background: color-mix(in oklab, var(--text) 12%, transparent);    color: var(--text); }
  .label.label-lg[class*="label-"] { padding: .28rem .7rem; font-size: var(--fs-sm); }

  /* ------------------------------------------ Bootstrap modals
     66 of these sit inline in the markup across 11 pages. Bootstrap's CSS
     (which hid them) is gone, so each one was dumped into the middle of its
     page as ordinary content — the "THANK YOU / your link is live" panel in
     the middle of the new-payment form was one of them. */
  div.modal, section.modal { display: none; }
  div.modal.is-open, section.modal.is-open {
    display: grid;
    place-items: center;
    position: fixed;
    inset: 0;
    z-index: 200;
    padding: 1.25rem;
    overflow-y: auto;
    background: oklch(14% 0.02 272 / .55);
    backdrop-filter: blur(3px);
    animation: modal-in var(--t) var(--ease);
  }
  @keyframes modal-in { from { opacity: 0; } }
  .modal-dialog {
    inline-size: min(100%, 34rem);
    margin-inline: auto;
    animation: modal-pop var(--t) var(--ease);
  }
  @keyframes modal-pop { from { opacity: 0; scale: .96; } }
  .modal-dialog.modal-lg { inline-size: min(100%, 50rem); }
  .modal-dialog.modal-sm { inline-size: min(100%, 24rem); }
  .modal-content {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--r-xl);
    box-shadow: var(--shadow-lg);
    overflow: clip;
  }
  .modal-header {
    display: flex; align-items: center; gap: .75rem;
    padding: 1.05rem 1.25rem;
    border-block-end: 1px solid var(--border-soft);
  }
  .modal-title { font-size: var(--fs-lg); font-weight: 750; flex: 1; min-inline-size: 0; }
  .modal-body { padding: 1.25rem; }
  .modal-footer {
    display: flex; gap: .6rem; justify-content: flex-end; flex-wrap: wrap;
    padding: 1rem 1.25rem;
    border-block-start: 1px solid var(--border-soft);
    background: var(--surface-2);
  }
  .modal-header .close, .modal .close {
    margin-inline-start: auto;
    inline-size: 2rem; block-size: 2rem;
    display: grid; place-items: center;
    border-radius: var(--r-xs);
    font-size: 1.4rem; line-height: 1;
    color: var(--text-3);
    background: transparent;
  }
  .modal .close:hover { background: var(--surface-3); color: var(--text); }
  .modal-body img { max-inline-size: 100%; height: auto; }

  /* --------------------------------------------- dropdowns → popovers
     upgradeDropdowns() in offto.js turns these into real popovers. Until it
     runs (and if it somehow cannot) the menu must not spill into the page —
     that is what made every actions column unreadable. */
  .dropdown-menu:not([popover]) { display: none; }
  .dropdown, .dropdown-inline { position: relative; display: inline-block; }
  .dropdown-item, .navi-link {
    display: flex; align-items: center; gap: .55rem;
    padding: .48rem .6rem;
    border-radius: var(--r-xs);
    font-size: var(--fs-sm);
    font-weight: 600;
    color: var(--text-2);
    white-space: nowrap;
  }
  .dropdown-item:hover, .navi-link:hover { background: var(--surface-3); color: var(--text); }
  /* destructive rows stay red even though this layer wins over components */
  :is(.dropdown-item, .navi-link).is-danger { color: var(--danger); }
  :is(.dropdown-item, .navi-link).is-danger :is(i, .navi-icon, [data-icon], svg) { color: var(--danger); }
  :is(.dropdown-item, .navi-link).is-danger:hover {
    color: var(--danger);
    background: color-mix(in oklab, var(--danger) 12%, transparent);
  }
  .dropdown-item :is(i, .navi-icon, [data-icon]),
  .navi-link :is(i, .navi-icon, [data-icon]) { color: var(--text-3); margin: 0 !important; }
  .dropdown-item:hover :is(i, .navi-icon), .navi-link:hover :is(i, .navi-icon) { color: var(--brand); }
  .dropdown-divider { block-size: 1px; background: var(--border-soft); margin-block: .3rem; }
  .navi { list-style: none; display: grid; gap: .1rem; padding: 0; margin: 0; }
  .navi-item { display: block; }
  .navi-header {
    padding: .35rem .6rem .45rem;
    font-size: var(--fs-2xs); font-weight: 800;
    letter-spacing: .07em; text-transform: uppercase;
    color: var(--text-3);
  }
  .navi-text { flex: 1; min-inline-size: 0; }

  /* a bare Metronic icon button (the ⋯ in every actions column) */
  .btn.btn-clean, .btn.btn-icon-md {
    padding: 0;
    inline-size: 2.1rem; block-size: 2.1rem;
    display: inline-grid; place-items: center;
    border-radius: var(--r-xs);
    background: transparent;
    border: 1px solid transparent;
    color: var(--text-3);
  }
  .btn.btn-clean:hover, .btn.btn-icon-md:hover {
    background: var(--surface-3);
    border-color: var(--border);
    color: var(--text);
  }
}

/* ==========================================================================
   LIGHTBOX — full-size image viewer (see initLightbox in offto.js)
   ========================================================================== */
@layer components {
  img[data-zoomable] { cursor: zoom-in; }

  .lightbox {
    inline-size: 100vw;
    max-inline-size: 100vw;
    block-size: 100dvh;
    max-block-size: 100dvh;
    margin: 0;
    padding: 0;
    border: 0;
    background: transparent;
    color: var(--surface);
    overflow: hidden;
    display: none;
    grid-template-columns: auto 1fr auto;
    grid-template-rows: auto 1fr;
    align-items: center;
  }
  .lightbox[open] { display: grid; }
  .lightbox::backdrop {
    background: oklch(14% 0.02 272 / .82);
    backdrop-filter: blur(6px);
  }
  @starting-style { .lightbox[open]::backdrop { background: oklch(14% 0.02 272 / 0); } }
  .lightbox::backdrop { transition: background var(--t) var(--ease); }

  /* ---- top bar ---- */
  .lightbox__bar {
    grid-row: 1;
    grid-column: 1 / -1;
    display: flex;
    align-items: center;
    gap: .35rem;
    padding: .6rem .75rem calc(.6rem + env(safe-area-inset-top, 0px));
    color: oklch(97% 0 0);
  }
  .lightbox__count {
    font-size: var(--fs-xs); font-weight: 700;
    font-variant-numeric: tabular-nums;
    direction: ltr;   /* "1 / 3" is a fraction, not a sentence — never mirror it */
    padding: .2rem .55rem;
    border-radius: var(--r-pill);
    background: oklch(100% 0 0 / .12);
  }
  .lightbox__title {
    flex: 1; min-inline-size: 0;
    font-size: var(--fs-sm); font-weight: 600;
    opacity: .8;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
  .lightbox__dims {
    direction: ltr;
    font-size: var(--fs-2xs); font-weight: 650;
    font-variant-numeric: tabular-nums;
    opacity: .65;
    white-space: nowrap;
  }
  .lightbox__pct {
    min-inline-size: 3.6rem;
    padding: .34rem .5rem;
    border-radius: var(--r-xs);
    direction: ltr;
    font-size: var(--fs-xs); font-weight: 750;
    font-variant-numeric: tabular-nums;
    color: oklch(97% 0 0);
    background: oklch(100% 0 0 / .1);
    transition: background var(--t-fast) var(--ease);
  }
  .lightbox__pct:hover { background: oklch(100% 0 0 / .22); }

  .lightbox__bar .btn {
    color: oklch(97% 0 0);
    background: oklch(100% 0 0 / .1);
    border: 0;
  }
  .lightbox__bar .btn:hover { background: oklch(100% 0 0 / .22); color: oklch(100% 0 0); }

  /* ---- prev / next ---- */
  .lightbox__nav {
    grid-row: 2;
    inline-size: 2.75rem; block-size: 2.75rem;
    display: grid; place-items: center;
    margin-inline: .5rem;
    border-radius: 50%;
    background: oklch(100% 0 0 / .1);
    color: oklch(97% 0 0);
    transition: background var(--t-fast) var(--ease);
  }
  .lightbox__nav:hover { background: oklch(100% 0 0 / .24); }
  .lightbox__nav[hidden] { display: none; }
  /* the arrows point along the reading direction */
  html[dir="rtl"] .lightbox__nav .icon { scale: -1 1; }

  /* ---- the picture ---- */
  .lightbox__stage {
    grid-row: 2;
    grid-column: 2;
    place-self: stretch;
    display: grid;
    place-items: center;
    place-content: center;   /* a picture wider than the stage overflows, not shrinks */
    padding: 0 .5rem 1rem;
    overflow: auto;
    overscroll-behavior: contain;
  }
  /* Default: the picture's own pixels, one for one. `width` is set inline by
     lbApply(); nothing here may shrink it, or "100%" would be a lie. */
  .lightbox__stage img {
    max-inline-size: none;
    max-block-size: none;
    flex: none;
    border-radius: var(--r-sm);
    background: oklch(100% 0 0 / .05);
    box-shadow: 0 24px 70px -20px oklch(0% 0 0 / .7);
    cursor: zoom-out;
    touch-action: none;
    transition: opacity var(--t) var(--ease);
  }
  /* scaled down so the whole picture is visible at once */
  .lightbox.is-fit .lightbox__stage img {
    max-inline-size: 100%;
    max-block-size: 100%;
    object-fit: contain;
    cursor: zoom-in;
  }
  .lightbox.is-panning .lightbox__stage img { cursor: grabbing; }
  .lightbox.is-loading .lightbox__stage img { opacity: 0; }
  .lightbox.is-loading .lightbox__stage::after {
    content: "";
    grid-area: 1 / 1;
    inline-size: 1.75rem; block-size: 1.75rem;
    border: 2.5px solid oklch(100% 0 0 / .25);
    border-block-start-color: oklch(100% 0 0 / .9);
    border-radius: 50%;
    animation: lb-spin .7s linear infinite;
  }
  @keyframes lb-spin { to { rotate: 360deg; } }

  @media (max-width: 640px) {
    /* on a phone there is no room for arrows beside the picture, so they move
       below it and the image gets the full width */
    .lightbox { grid-template-columns: minmax(0, 1fr); grid-template-rows: auto 1fr auto; }
    .lightbox__stage { grid-column: 1; padding-inline: .35rem; }
    .lightbox__nav { grid-row: 3; grid-column: 1; margin-block-end: calc(1rem + env(safe-area-inset-bottom, 0px)); }
    [data-lb-prev] { justify-self: start; }
    [data-lb-next] { justify-self: end; }
    /* the bar is tight on a phone: the file size and the title give way first */
    .lightbox__dims { display: none; }
    .lightbox__title { display: none; }
  }
  @media (prefers-reduced-motion: reduce) {
    .lightbox::backdrop, .lightbox__stage img { transition: none; }
  }
}

/* ==========================================================================
   RESPONSIVE SAFETY NET
   Migrated markup carries hard pixel widths and long unbreakable strings. None
   of it is allowed to make the page scroll sideways on a phone.
   ========================================================================== */
@layer components {
  /* flex items refuse to shrink below their content unless told to */
  .tabs, .page-head__actions, .toolbar { min-inline-size: 0; max-inline-size: 100%; }
  /* inline `width: 900px` from the old templates (maps, embeds, fixed panels) */
  .page [style*="width:"] { max-inline-size: 100%; }
  .page :is(img, svg:not(.icon), video, canvas, iframe, embed, object) { max-inline-size: 100%; }
  /* URLs, tokens and IDs with no break opportunity */
  /* `anywhere` (not `break-word`) on table cells on purpose: only `anywhere`
     lowers the min-content width, which is what lets a wide table shrink
     instead of pushing the page sideways. Card mode relaxes it back. */
  .page :is(td, th) { overflow-wrap: anywhere; }
  .page :is(dd, .kv > *, .hint, .lead, p) { overflow-wrap: break-word; }
}

/* ==========================================================================
   STICKY SAVE BAR
   Long forms put their primary action in the page header. On a phone that
   header scrolls away, so the same action is repeated in a bar that sticks to
   the bottom of the page. Desktop keeps the header actions only.
   ========================================================================== */
@layer components {
  .save-bar {
    display: none;
    position: sticky;
    inset-block-end: 0;
    z-index: 15;
    align-items: center;
    gap: .5rem;
    margin-block-start: 1.25rem;
    padding: .7rem .85rem calc(.7rem + env(safe-area-inset-bottom, 0px));
    border: 1px solid var(--border);
    border-radius: var(--r-md) var(--r-md) 0 0;
    background: color-mix(in oklab, var(--surface) 86%, transparent);
    backdrop-filter: saturate(180%) blur(12px);
    box-shadow: 0 -6px 20px -12px oklch(0% 0 0 / .35);
  }
  .save-bar__note { font-size: var(--fs-xs); color: var(--text-3); margin-inline-end: auto; }
  .save-bar .btn { flex: 1 1 auto; justify-content: center; }
  .save-bar__note ~ .btn { flex: 0 1 auto; }

  @container page (max-width: 860px) {
    .save-bar { display: flex; }
    /* the header copy of the same actions would be redundant and scrolls away */
    .page:has(.save-bar) .page-head__actions { display: none; }
  }
}

/* ==========================================================================
   VIEW SPLIT
   The standard shape of a "look at one record" page: the thing itself on the
   left, the facts about it on the right. The aside is a fixed 21rem so the
   main column keeps a comfortable reading measure instead of stretching to
   the full 1440px, and it stacks *under* the main column on narrow screens
   because the record matters more than its metadata.
   ========================================================================== */
@layer layout {
  .view-split {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 21rem;
    gap: 1rem;
    align-items: start;
  }
  .view-split__main, .view-split__side { min-inline-size: 0; display: grid; gap: 1rem; align-content: start; }

  /* The aside follows you down a long list — and it has to follow all of
     it, not just the first screenful. A sticky box taller than the window
     only pins its top edge: the filters and the price sat below the fold
     and you had to scroll past every result to reach them. So the column
     pins under the topbar at the height of the window and scrolls inside
     itself. What is in it stays put while the results move. */
  .view-split__side {
    position: sticky;
    inset-block-start: calc(var(--topbar-h, 4rem) + 1rem);
    max-block-size: calc(100vh - var(--topbar-h, 4rem) - 2rem);
    max-block-size: calc(100dvh - var(--topbar-h, 4rem) - 2rem);
    overflow-y: auto;
    /* a flick inside the filters must not carry on scrolling the results */
    overscroll-behavior: contain;
    scrollbar-width: thin;
    /* room for the scrollbar so it never sits on top of a control */
    padding-inline-end: .15rem;
  }

  /* The filters that go back to the supplier are applied on a button, not on
     every tick — so the button has to be reachable without scrolling the
     panel back down. It sits at the foot of the card and stays there. */
  .filter-ft {
    position: sticky;
    inset-block-end: 0;
    z-index: 2;
    display: grid;
    gap: .5rem;
    background: var(--surface-2);
    border-top: 1px solid var(--border-soft);
    padding: .9rem 1.15rem;
  }
  .filter-ft__note {
    display: none;
    font-size: .8rem;
    color: color-mix(in oklab, var(--warning) 78%, var(--text));
  }
  .filter-ft.is-dirty .filter-ft__note { display: block; }

  @container page (max-width: 960px) {
    .view-split { grid-template-columns: minmax(0, 1fr); }
    .view-split__side {
      position: static;
      max-block-size: none;
      overflow: visible;
      padding-inline-end: 0;
    }
  }
}

/* ==========================================================================
   MESSAGE
   A piece of text a human wrote — a contact form message, a note, a reply.
   The body keeps the author's own line breaks (`white-space: pre-wrap`),
   which is the whole reason this is not just a <dd>.
   ========================================================================== */
@layer components {
  .msg { display: grid; gap: .9rem; }

  .msg__head {
    display: flex;
    align-items: center;
    gap: .75rem;
    flex-wrap: wrap;
  }
  .msg__who { min-inline-size: 0; flex: 1 1 12rem; }
  .msg__who b {
    display: block;
    font-weight: 650;
    color: var(--text);
    overflow-wrap: anywhere;
  }
  .msg__meta {
    display: flex; align-items: center; gap: .4rem; flex-wrap: wrap;
    margin-block-start: .1rem;
    font-size: var(--fs-xs);
    color: var(--text-3);
  }
  .msg__meta > .sep { opacity: .5; }
  /* the note in a card footer takes the slack so the action stays at the end */
  .card-ft > .msg__meta { margin-inline-end: auto; flex: 1 1 12rem; }

  .msg__body {
    padding: 1rem 1.1rem;
    border: 1px solid var(--border-soft);
    border-radius: var(--r-md);
    background: var(--surface-2);
    /* the author's newlines are content, not formatting noise */
    white-space: pre-wrap;
    unicode-bidi: plaintext;
    overflow-wrap: anywhere;
    line-height: 1.75;
    color: var(--text-2);
    /* a quiet quote bar on the leading edge — logical, so it flips in RTL */
    border-inline-start: 3px solid color-mix(in oklab, var(--brand) 55%, transparent);
  }
  /* in the narrow aside the label would otherwise claim 14rem and push the
     trailing button onto its own line */
  .view-split__side .setting-row { padding-inline: 1rem; }
  .view-split__side .setting-row__bd { flex: 1 1 7rem; }
  /* a lone icon button never deserves a full-width row of its own */
  .view-split__side .setting-row__ctl { flex: 0 0 auto; }

  .msg__body:empty::before {
    content: attr(data-empty);
    color: var(--text-3);
    font-style: italic;
  }
}

/* ==========================================================================
   RECORD VIEW
   The shape every "look at one booking" page takes. The old pages printed
   four <table>s of label/value pairs in a maroon that belongs to no palette;
   the information a human actually needs first is the money and the state,
   so those get the top of the page and everything else reads as supporting
   detail underneath.
   ========================================================================== */
@layer components {

  /* ---- the money band: paid / cost / profit, side by side -------------- */
  .money {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
  }
  .money__item { padding: 1.1rem 1.15rem; min-inline-size: 0; }
  /* a logical border so the dividers land between columns in both scripts */
  .money__item + .money__item { border-inline-start: 1px solid var(--border-soft); }
  .money__k {
    display: flex; align-items: center; gap: .35rem;
    font-size: var(--fs-2xs);
    font-weight: 700;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--text-3);
  }
  .money__k .icon { inline-size: .9rem; block-size: .9rem; }
  .money__v {
    display: flex; align-items: baseline; gap: .35rem;
    margin-block-start: .35rem;
    font-size: clamp(1.5rem, 1.15rem + 1.1vw, 2rem);
    font-weight: 700;
    letter-spacing: -.02em;
    font-variant-numeric: tabular-nums;
    overflow-wrap: anywhere;
  }
  .money__u { font-size: var(--fs-sm); font-weight: 600; color: var(--text-3); }
  .money__sub { margin-block-start: .2rem; font-size: var(--fs-xs); color: var(--text-3); }

  .money__item[data-tone="pos"]  .money__v { color: var(--success); }
  .money__item[data-tone="neg"]  .money__v { color: var(--danger); }
  .money__item[data-tone="due"]  .money__v { color: var(--warning); }
  .money__item[data-tone="brand"] .money__v { color: var(--brand-strong); }
  .money__item[data-tone="pos"]  .money__sub { color: var(--success); }
  .money__item[data-tone="neg"]  .money__sub { color: var(--danger); }

  /* ---- a dense read-only grid of label/value pairs --------------------- */
  .facts {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr));
    gap: 1rem 1.5rem;
  }
  .fact { min-inline-size: 0; }
  .fact__k {
    font-size: var(--fs-2xs);
    font-weight: 700;
    letter-spacing: .05em;
    text-transform: uppercase;
    color: var(--text-3);
  }
  .fact__v {
    margin-block-start: .2rem;
    font-weight: 600;
    color: var(--text);
    overflow-wrap: anywhere;
    /* values arrive in whichever script the customer typed */
    unicode-bidi: plaintext;
  }
  .fact__v.is-mono { font-family: var(--font-mono); font-weight: 500; font-size: var(--fs-sm); }
  .fact__v:empty::before { content: "—"; color: var(--text-3); font-weight: 500; }
  .fact--wide { grid-column: 1 / -1; }

  /* text we wrote ourselves — a policy line, a weight, a fee — belongs with
     the page. `plaintext` above is for values a customer typed, where letting
     the value pick its own side is right; here it just pushes "7 KG" to the
     far edge while its own label stays on the other one. */
  .bidi-page { unicode-bidi: normal; }

  /* ---- a list of things that are included ----------------------------- */
  .tick { display: grid; gap: .45rem; margin: 0; padding: 0; list-style: none; }
  .tick > li {
    position: relative;
    padding-inline-start: 1.4rem;
    font-size: var(--fs-sm);
    color: var(--text-2);
  }
  .tick > li::before {
    content: "";
    position: absolute;
    inset-inline-start: .15rem;
    inset-block-start: .42em;
    inline-size: .5rem; block-size: .26rem;
    border: 2px solid var(--success);
    border-block-start: 0;
    border-inline-end: 0;
    transform: rotate(-45deg);
  }

  /* short facts (a weight, a fee) don't need a 12rem column each — this keeps
     four of them on one line on a desktop and two on a phone */
  .facts.is-tight {
    grid-template-columns: repeat(auto-fit, minmax(8.5rem, 1fr));
    gap: .8rem 1.25rem;
  }

  /* ---- a section label above a group ---------------------------------- */
  .sec-title {
    display: flex; align-items: center; gap: .5rem;
    font-size: var(--fs-xs);
    font-weight: 700;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--text-3);
  }
  .sec-title .icon { inline-size: 1.05rem; block-size: 1.05rem; color: var(--brand); }

  /* ---- one booked item (a hotel stay, a flight leg) -------------------- */
  .item {
    border: 1px solid var(--border);
    border-radius: var(--r-md);
    background: var(--surface);
    overflow: clip;
  }
  .item + .item { margin-block-start: .75rem; }
  .item__hd {
    display: flex; align-items: flex-start; gap: .75rem; flex-wrap: wrap;
    padding: .85rem 1rem;
    background: var(--surface-2);
    border-block-end: 1px solid var(--border-soft);
  }
  .item__ttl { min-inline-size: 0; flex: 1 1 14rem; }
  .item__ttl b { display: block; font-weight: 650; overflow-wrap: anywhere; }
  .item__meta {
    display: flex; align-items: center; gap: .35rem; flex-wrap: wrap;
    margin-block-start: .15rem;
    font-size: var(--fs-xs);
    color: var(--text-3);
  }
  .item__meta .icon { inline-size: .9rem; block-size: .9rem; }
  .item__tags { display: flex; align-items: center; gap: .4rem; flex-wrap: wrap; }
  .item__bd { padding: .9rem 1rem; }

  /* ---- notes and activity --------------------------------------------- */
  .composer {
    border: 1px solid var(--border);
    border-radius: var(--r-md);
    background: var(--surface);
    overflow: clip;
  }
  .composer:focus-within { border-color: var(--brand); box-shadow: var(--ring); }
  .composer textarea {
    display: block;
    inline-size: 100%;
    border: 0;
    background: none;
    padding: .8rem .9rem;
    color: var(--text);
    font: inherit;
    resize: vertical;
    min-block-size: 5rem;
  }
  .composer textarea:focus { outline: none; }
  .composer__ft {
    display: flex; align-items: center; gap: .5rem; flex-wrap: wrap;
    padding: .55rem .7rem;
    background: var(--surface-2);
    border-block-start: 1px solid var(--border-soft);
    font-size: var(--fs-xs);
    color: var(--text-3);
  }
  .composer__ft .btn { margin-inline-start: auto; }

  .note { display: flex; gap: .75rem; padding-block: .9rem; }
  .note + .note { border-block-start: 1px solid var(--border-soft); }
  .note__bd { min-inline-size: 0; flex: 1; }
  .note__hd { display: flex; align-items: baseline; gap: .5rem; flex-wrap: wrap; }
  .note__hd b { font-weight: 650; }
  .note__hd time { font-size: var(--fs-xs); color: var(--text-3); font-variant-numeric: tabular-nums; }
  .note__txt {
    margin-block-start: .25rem;
    color: var(--text-2);
    white-space: pre-wrap;
    unicode-bidi: plaintext;
    overflow-wrap: anywhere;
  }
  .note__txt .mention { color: var(--brand-strong); font-weight: 600; }

  /* ---- a raw payload (a gateway error, a supplier response) ------------ */
  .payload {
    margin: 0;
    padding: .8rem .9rem;
    border-radius: var(--r-sm);
    background: var(--surface-inset);
    border: 1px solid var(--border-soft);
    font: 500 var(--fs-xs)/1.7 var(--font-mono);
    color: var(--text-2);
    white-space: pre-wrap;
    overflow-wrap: anywhere;
    direction: ltr;
    text-align: start;
  }

  @media print {
    .app-nav, .topbar, .sidebar, .save-bar, .page-head__actions, .composer, .no-print { display: none !important; }
    .card { break-inside: avoid; box-shadow: none; }
  }
}

/* ==========================================================================
   MAP HINT — the small placeholder that stands in for a real map preview
   ========================================================================== */
@layer components {
  .map-hint {
    display: grid;
    justify-items: center;
    gap: .6rem;
    padding: 1.25rem 1rem;
    border: 1px dashed var(--border-strong);
    border-radius: var(--r-md);
    background: var(--surface-2);
    text-align: center;
    color: var(--text-3);
  }
  .map-hint > [data-icon] > .icon { inline-size: 1.6rem; block-size: 1.6rem; }
}

/* ==========================================================================
   STAR RATING
   A hotel's class is a five-point scale, and a <select> of "1,2,3,4,5" makes
   you translate a number back into the thing it means. Five radios drawn as
   stars say it directly, and the radios keep the form submitting a number.
   ========================================================================== */
@layer components {
  .stars {
    display: inline-flex;
    flex-direction: row-reverse;   /* lets ~ light every star before the hovered one */
    justify-content: flex-end;
    gap: .15rem;
  }
  .stars input {
    position: absolute;
    inline-size: 1px; block-size: 1px;
    clip-path: inset(50%);
    overflow: hidden;
  }
  .stars label {
    display: grid; place-items: center;
    inline-size: 2rem; block-size: 2rem;
    margin: 0;
    border-radius: var(--r-sm);
    color: var(--text-3);
    cursor: pointer;
    transition: color var(--t-fast) var(--ease), background var(--t-fast) var(--ease);
  }
  .stars label .icon { inline-size: 1.3rem; block-size: 1.3rem; }
  /* the star itself and every star before it (which, reversed, is every
     following sibling) */
  .stars label:hover,
  .stars label:hover ~ label,
  .stars input:checked + label,
  .stars input:checked + label ~ label {
    color: var(--warning);
  }
  :is(.stars label:hover,
      .stars label:hover ~ label,
      .stars input:checked + label,
      .stars input:checked + label ~ label) .icon { fill: currentColor; }
  .stars input:focus-visible + label { box-shadow: var(--ring); }
  .stars-wrap { display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; }
  .stars__out { font-size: var(--fs-sm); color: var(--text-3); font-variant-numeric: tabular-nums; }
}

/* ==========================================================================
   PERMISSION MATRIX
   339 checkboxes printed as one long ribbon is unreadable; but 58 modules ×
   the same 7 verbs is a *table*, and a table lets you answer "who can delete
   anything?" by reading down one column. The odd module-specific permissions
   that don't fit the 7 verbs get an "Other" cell rather than 20 half-empty
   extra columns.
   ========================================================================== */
@layer components {
  .perm-toolbar {
    display: flex; align-items: center; gap: .6rem; flex-wrap: wrap;
    padding: .85rem 1.15rem;
    border-block-end: 1px solid var(--border-soft);
  }
  .perm-toolbar .input-wrap { flex: 1 1 15rem; }
  .perm-count {
    font-size: var(--fs-xs);
    color: var(--text-3);
    font-variant-numeric: tabular-nums;
    margin-inline-start: auto;
  }
  .perm-count b { color: var(--text); }

  .perm-table { inline-size: 100%; border-collapse: collapse; }
  .perm-table :is(th, td) { padding: .5rem .6rem; text-align: start; }

  .perm-table thead th {
    position: sticky;
    inset-block-start: 0;
    z-index: 2;
    background: var(--surface-2);
    border-block-end: 1px solid var(--border);
    font-size: var(--fs-2xs);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .04em;
    color: var(--text-3);
    white-space: nowrap;
  }
  .perm-table thead th .check { margin-inline-end: .35rem; }

  .perm-table tbody tr + tr > * { border-block-start: 1px solid var(--border-soft); }
  .perm-table tbody tr:hover > * { background: var(--surface-2); }
  .perm-table tbody tr[hidden] { display: none; }

  .perm-mod {
    font-weight: 600;
    color: var(--text);
    inline-size: 1%;
    white-space: nowrap;
  }
  .perm-mod .check { align-items: center; }

  /* a module that simply has no such permission — not an unticked box */
  .perm-na { color: var(--text-3); opacity: .45; }

  .perm-other { display: flex; gap: .35rem; flex-wrap: wrap; }
  .perm-chip {
    display: inline-flex; align-items: center; gap: .35rem;
    padding: .15rem .5rem .15rem .3rem;
    border: 1px solid var(--border);
    border-radius: 999px;
    font-size: var(--fs-2xs);
    color: var(--text-2);
    cursor: pointer;
    white-space: nowrap;
  }
  .perm-chip input { inline-size: .9rem; block-size: .9rem; }
  .perm-chip:has(input:checked) {
    border-color: var(--brand);
    background: color-mix(in oklab, var(--brand) 10%, transparent);
    color: var(--brand-strong);
  }

  /* below the fold of a phone the table becomes one block per module */
  @container page (max-width: 900px) {
    .perm-table, .perm-table tbody, .perm-table tr { display: block; }
    .perm-table thead { display: none; }
    .perm-table tbody tr {
      border: 1px solid var(--border);
      border-radius: var(--r-md);
      padding: .5rem .6rem;
      margin-block-end: .6rem;
    }
    .perm-table tbody tr + tr > * { border-block-start: 0; }
    .perm-table td {
      display: flex; align-items: center; justify-content: space-between;
      gap: 1rem;
      padding: .35rem .2rem;
    }
    .perm-table td::before {
      content: attr(data-label);
      font-size: var(--fs-xs);
      color: var(--text-3);
    }
    .perm-mod {
      display: block;
      inline-size: auto;
      padding: .2rem .2rem .5rem;
      border-block-end: 1px solid var(--border-soft);
      margin-block-end: .3rem;
    }
    .perm-other { justify-content: flex-end; }
  }
}

/* ==========================================================================
   Q&A LIST
   A questionnaire answer set. A two-column table forces the question and the
   answer onto one line and turns unreadable on a phone; stacking them and
   making the answer the visually stronger of the two reads as a form the
   applicant filled in, which is what it is.
   ========================================================================== */
@layer components {
  .qa { display: grid; }
  .qa__row {
    display: grid;
    gap: .3rem;
    padding-block: .85rem;
    counter-increment: qa;
  }
  .qa { counter-reset: qa; }
  .qa__row + .qa__row { border-block-start: 1px dashed var(--border-soft); }

  .qa__q {
    display: flex;
    gap: .5rem;
    font-size: var(--fs-sm);
    color: var(--text-3);
    text-wrap: pretty;
  }
  .qa__q::before {
    content: counter(qa) ".";
    color: var(--text-3);
    opacity: .7;
    font-variant-numeric: tabular-nums;
    flex: none;
  }
  .qa__a {
    /* answers arrive in whichever language the traveller used */
    unicode-bidi: plaintext;
    font-weight: 600;
    color: var(--text);
    padding-inline-start: 1.35rem;   /* line up under the question, past its number */
    overflow-wrap: anywhere;
  }
  /* a value the applicant never filled in */
  .is-muted { color: var(--text-3); font-weight: 500; font-style: italic; }

  .qa__a:empty::before {
    content: attr(data-empty);
    font-weight: 500;
    color: var(--text-3);
    font-style: italic;
  }
}

/* ==========================================================================
   TYPE PICKER
   A radio group that reads as a choice of *kind* rather than a choice of
   value: each option carries an icon, a name and a line explaining what it
   changes, because picking one rewrites the rest of the form. The native
   radio stays in the DOM (it is what the form submits and what keyboard
   users move through with the arrow keys); it is only visually replaced.
   ========================================================================== */
@layer components {
  .type-picker {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
    gap: .75rem;
  }

  .type-card {
    position: relative;
    display: flex;
    align-items: flex-start;
    gap: .75rem;
    margin: 0;
    padding: .85rem .9rem;
    border: 1px solid var(--border);
    border-radius: var(--r-md);
    background: var(--surface);
    cursor: pointer;
    transition: border-color .15s, background-color .15s, box-shadow .15s;

    /* the radio is kept reachable for a11y, just not painted */
    > input[type="radio"] {
      position: absolute;
      inline-size: 1px; block-size: 1px;
      margin: 0; padding: 0; border: 0;
      clip-path: inset(50%);
      overflow: hidden;
      white-space: nowrap;
    }

    &:hover { border-color: color-mix(in oklab, var(--brand) 45%, var(--border)); }

    /* :has beats a sibling selector here because the checked input is a
       *child*, and the whole label has to react — not just what follows it */
    &:has(> input:checked) {
      border-color: var(--brand);
      background: color-mix(in oklab, var(--brand) 7%, var(--surface));
      box-shadow: inset 0 0 0 1px var(--brand);
    }
    &:has(> input:focus-visible) { outline: 2px solid var(--brand); outline-offset: 2px; }
  }

  .type-card__ico {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    inline-size: 2.25rem;
    block-size: 2.25rem;
    border-radius: var(--r-sm);
    background: color-mix(in oklab, var(--brand) 12%, transparent);
    color: var(--brand);

    > .icon { inline-size: 1.15rem; block-size: 1.15rem; }
  }

  .type-card__bd {
    display: grid;
    gap: .15rem;
    min-inline-size: 0;

    > b { font-size: var(--fs-sm); font-weight: 600; color: var(--text-1); }
    > small { font-size: var(--fs-xs); line-height: 1.5; color: var(--text-3); }
  }

  /* a check mark on the chosen card, drawn by the card itself so the markup
     stays three elements */
  .type-card:has(> input:checked)::after {
    content: "";
    position: absolute;
    inset-block-start: .55rem;
    inset-inline-end: .55rem;
    inline-size: .5rem;
    block-size: .5rem;
    border-radius: 50%;
    background: var(--brand);
  }
}

/* ==========================================================================
   REPEATER
   Rows the user adds and removes — airports, phone numbers, prices. One row
   is a flexible control plus a delete button, so the control keeps growing
   and the button never wraps under it.
   ========================================================================== */
@layer components {
  .repeater {
    display: grid;
    gap: .5rem;

    /* an empty repeater should not leave a gap above its hint */
    &:empty { display: none; }
  }

  /* A row of *fields* rather than a single control: a bordered strip so the
     eye can tell where one entry stops and the next begins, which a bare
     grid of inputs cannot do once there are four of them per line. */
  .repeater__item {
    display: grid;
    grid-template-columns: auto 1fr auto;
    gap: .75rem 1rem;
    align-items: start;
    padding: .85rem .9rem;
    border: 1px solid var(--border);
    border-radius: var(--r-md);
    background: var(--surface-2);
  }
  .repeater__item > .repeater__fields {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
    gap: .75rem 1rem;
    min-inline-size: 0;
  }
  .repeater__num {
    inline-size: 1.6rem; block-size: 1.6rem;
    display: grid; place-items: center;
    border-radius: 50%;
    background: var(--surface-3);
    color: var(--text-3);
    font-size: var(--fs-2xs);
    font-weight: 700;
    font-variant-numeric: tabular-nums;
  }
  /* numbering without an id in the markup — the DOM order is the number */
  .repeater { counter-reset: rep; }
  .repeater__item { counter-increment: rep; }
  .repeater__num::before { content: counter(rep); }

  /* Line the delete button up with the CONTROLS. Centring it in the row
     floats it up into the label band, and aligning it to the row's end drops
     it below the fields whenever one of them is taller (an image picker).
     Anchor it to the top and push it down by exactly the label's height, so
     it always starts where the first control starts. */
  .repeater__item > [data-repeater-delete] {
    align-self: start;
    margin-block-start: 1.625rem;   /* label line (20px) + its 6px gap */
    inline-size: 2.625rem;
    block-size: 2.625rem;
    color: var(--text-3);
  }
  /* rows without labels (a bare control per row) centre as before */
  .repeater__item:not(:has(.label)) > [data-repeater-delete] {
    align-self: center;
    margin-block-start: 0;
  }
  .repeater__item > [data-repeater-delete]:hover {
    color: var(--danger);
    background: color-mix(in oklab, var(--danger) 10%, transparent);
  }

  @container page (max-width: 640px) {
    .repeater__item { grid-template-columns: auto 1fr; }
    .repeater__item > [data-repeater-delete] { grid-column: 2; justify-self: end; }
  }

  /* the 8.5rem picker is a page-level control; inside a list row it needs to
     be thumbnail-sized or it dictates the row height */
  .image-input.is-xs {
    inline-size: 3.5rem;
    block-size: 3.5rem;
    border-radius: var(--r-sm);
  }
  .image-input.is-xs > :is(label, span)[data-action] {
    inline-size: 1.35rem;
    block-size: 1.35rem;
  }
  .image-input.is-xs > :is(label, span)[data-action] > .icon { inline-size: .7rem; block-size: .7rem; }
  .image-input.is-xs.is-empty::after { mask-size: 1.25rem; }

  .repeater__row {
    display: flex;
    align-items: center;
    gap: .5rem;

    > :is(.select, .input, .field, select, input) {
      flex: 1 1 auto;
      min-inline-size: 0;
    }
    > [data-repeater-delete] {
      flex: 0 0 auto;
      color: var(--text-3);
      &:hover { color: var(--danger); background: color-mix(in oklab, var(--danger) 10%, transparent); }
    }
  }
}

/* ==========================================================================
   UNLAYERED OVERRIDES — these must beat every @layer above
   ========================================================================== */
.sidebar__close { display: none !important; }
.topbar__burger { display: none !important; }
@media (max-width: 1099px) {
  .sidebar__close { display: inline-flex !important; margin-inline-start: auto; }
  .topbar__burger { display: inline-flex !important; }
}
@media (min-width: 1100px) { .only-md { display: none !important; } }
@media (max-width: 1099px) { .hide-md { display: none !important; } }
@media (max-width: 720px)  { .hide-sm { display: none !important; } }
@media (max-width: 460px)  { .hide-xs { display: none !important; } }
.hide { display: none !important; }

/* a directional arrow inside a button has to point the way the text reads */
html[dir="rtl"] .rtl-flip > .icon { scale: -1 1; }

/* ==========================================================================
   CLICK TARGETS
   Every legacy row handler is written as
       $(table).on("click", "td button", e => { if (e.target.id === "delete_btn") … })
   so the click has to *land on the button*. Once the button contains an icon
   or a label, the <svg>/<span> becomes e.target and the handler silently does
   nothing — which is why Delete / Disable / Activate stopped responding.
   Making the decoration transparent to the pointer restores all of them
   without touching a single page script.
   `input` is deliberately excluded: the avatar picker is a <label class="btn">
   wrapped around a file input that must stay clickable.
   ========================================================================== */
:is(.btn, .pop__item, .dropdown-item, .navi-link, .chip, .seg button) > :not(input):not(select):not(textarea) {
  pointer-events: none;
}

/* ==========================================================================
   BOOKING SEARCH
   The admin books on the customer's behalf, so these screens are the public
   site's search — same shape, same vocabulary — rendered in the admin theme.
   Every widget here is generic: the same markup drives hotels, flights and
   the city lookup.
   ========================================================================== */
@layer components {

  /* ---- the connected search bar ---------------------------------------- */
  .searchbar {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
    align-items: stretch;
    border: 1px solid var(--border);
    border-radius: var(--r-lg);
    background: var(--surface);
    box-shadow: var(--shadow-sm);
    overflow: clip;
  }
  .searchbar__seg {
    display: flex;
    align-items: center;
    gap: .6rem;
    padding: .7rem .9rem;
    min-inline-size: 0;
    text-align: start;
    background: none;
    cursor: pointer;
    transition: background var(--t-fast) var(--ease);
  }
  .searchbar__seg + .searchbar__seg { border-inline-start: 1px solid var(--border-soft); }
  .searchbar__seg:hover { background: var(--surface-2); }
  .searchbar__seg[aria-expanded="true"] { background: color-mix(in oklab, var(--brand) 7%, var(--surface)); }
  .searchbar__seg > [data-icon] > .icon { inline-size: 1.15rem; block-size: 1.15rem; color: var(--brand); }
  .searchbar__bd { min-inline-size: 0; flex: 1; }
  .searchbar__k { display: block; font-size: var(--fs-2xs); color: var(--text-3); font-weight: 600; }
  .searchbar__v {
    display: block;
    font-weight: 650;
    color: var(--text);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }
  .searchbar__v.is-empty { color: var(--text-3); font-weight: 500; }
  .searchbar__go {
    display: flex; align-items: center; justify-content: center; gap: .45rem;
    padding: .8rem 1.4rem;
    background: var(--accent);
    color: #fff;
    font-weight: 700;
    border: 0;
    cursor: pointer;
  }
  .searchbar__go:hover { background: color-mix(in oklab, var(--accent) 88%, black); }
  .searchbar__go .icon { inline-size: 1.1rem; block-size: 1.1rem; }

  /* the panels the segments open */
  .sbpop {
    position: fixed;
    z-index: 60;
    inline-size: max-content;
    max-inline-size: min(92vw, 36rem);
    padding: .8rem;
    border: 1px solid var(--border);
    border-radius: var(--r-md);
    background: var(--surface);
    box-shadow: var(--shadow-lg);
  }
  .sbpop[hidden] { display: none; }
  .sbpop__ft {
    display: flex; align-items: center; gap: .6rem;
    margin-block-start: .7rem;
    padding-block-start: .7rem;
    border-block-start: 1px solid var(--border-soft);
    font-size: var(--fs-xs);
    color: var(--text-3);
  }
  .sbpop__ft .btn { margin-inline-start: auto; }

  /* ---- autocomplete ---------------------------------------------------- */
  .ac__list { max-block-size: 19rem; overflow: auto; margin: 0; padding: 0; list-style: none; }
  .ac__group {
    display: flex; align-items: center; gap: .5rem;
    padding: .45rem .55rem .3rem;
    font-size: var(--fs-2xs);
    font-weight: 700;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: var(--text-3);
    position: sticky;
    inset-block-start: 0;
    background: var(--surface);
  }
  .ac__item {
    display: flex; align-items: center; gap: .6rem;
    inline-size: 100%;
    padding: .5rem .55rem;
    border-radius: var(--r-sm);
    text-align: start;
    cursor: pointer;
    background: none;
  }
  .ac__item:hover, .ac__item[aria-selected="true"] { background: var(--surface-2); }
  /* a hotel belongs to the city above it — the indent and the rule are the
     only things saying so, so they carry the whole relationship */
  .ac__item.is-child {
    margin-inline-start: 1.15rem;
    padding-inline-start: .75rem;
    border-inline-start: 1px solid var(--border);
  }
  .ac__item.is-child b { font-weight: 600; }
}

/* a filter list long enough to need its own scroller — the supplier offers
   twenty-five property types, and they must not push the price slider off
   the panel */
@layer components {
  .filterlist {
    max-block-size: 13rem;
    overflow-y: auto;
    overscroll-behavior: contain;
    scrollbar-width: thin;
    padding-inline-end: .25rem;
  }
  .ac__item .icon { inline-size: 1.05rem; block-size: 1.05rem; color: var(--text-3); flex: none; }
  .ac__flag { font-size: 1.15rem; line-height: 1; flex: none; }
  /* some endpoints hand the flag over as an image rather than an emoji */
  .ac__flag img {
    display: block;
    inline-size: 1.25rem; block-size: .9rem;
    object-fit: cover;
    border-radius: 2px;
    border: 1px solid var(--border-soft);
  }
  .ac__bd { min-inline-size: 0; }
  .ac__bd b { display: block; font-weight: 600; }
  .ac__bd small { color: var(--text-3); font-size: var(--fs-xs); }
  .ac__empty { padding: 1rem .6rem; color: var(--text-3); font-size: var(--fs-sm); text-align: center; }

  /* ---- two-month range calendar ---------------------------------------- */
  .cal { display: grid; gap: .9rem; inline-size: min(88vw, 32rem); }
  .cal[data-range="single"] { inline-size: min(88vw, 16.5rem); }
  .cal__hd { display: flex; align-items: center; justify-content: space-between; gap: .5rem; }
  /* two fixed tracks, so a month can never wrap under its neighbour */
  .cal__months { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 1.5rem; }
  .cal[data-range="single"] .cal__months { grid-template-columns: minmax(0, 1fr); }
  .cal__month { min-inline-size: 0; }
  @container page (max-width: 620px) {
    .cal { inline-size: min(88vw, 17rem); }
    .cal__months { grid-template-columns: minmax(0, 1fr); }
  }
  .cal__title { text-align: center; font-weight: 700; margin-block-end: .5rem; }
  .cal__grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px; }
  .cal__dow {
    text-align: center;
    font-size: var(--fs-2xs);
    color: var(--text-3);
    font-weight: 600;
    padding-block-end: .25rem;
  }
  .cal__day {
    aspect-ratio: 1;
    display: grid; place-items: center;
    border: 0;
    border-radius: 999px;
    background: none;
    font-size: var(--fs-sm);
    font-variant-numeric: tabular-nums;
    color: var(--text);
    cursor: pointer;
  }
  .cal__day:hover:not(:disabled) { background: var(--surface-3); }
  .cal__day:disabled { color: var(--text-3); opacity: .45; cursor: default; }
  .cal__day.is-out { visibility: hidden; }
  /* the run between the two ends is a band, the ends themselves are solid */
  .cal__day.is-between { background: color-mix(in oklab, var(--brand) 14%, transparent); border-radius: 0; }
  .cal__day.is-start, .cal__day.is-end { background: var(--brand); color: #fff; font-weight: 700; }
  .cal__day.is-start { border-start-end-radius: 0; border-end-end-radius: 0; }
  .cal__day.is-end   { border-start-start-radius: 0; border-end-start-radius: 0; }
  .cal__day.is-start.is-end { border-radius: 999px; }
  .cal__ft { text-align: center; font-size: var(--fs-sm); color: var(--brand-strong); font-weight: 650; }

  /* ---- guest / room steppers ------------------------------------------- */
  .room { border: 1px solid var(--border-soft); border-radius: var(--r-md); padding: .7rem .8rem; }
  .room + .room { margin-block-start: .6rem; }
  .room__hd {
    display: flex; align-items: center; gap: .5rem;
    margin-block-end: .4rem;
    font-weight: 700;
    color: var(--brand-strong);
    font-size: var(--fs-sm);
  }
  .room__hd .btn { margin-inline-start: auto; }
  .stepper { display: flex; align-items: center; gap: .75rem; padding-block: .45rem; }
  .stepper__bd { flex: 1; min-inline-size: 0; }
  .stepper__bd b { display: block; font-weight: 650; }
  .stepper__bd small { color: var(--text-3); font-size: var(--fs-xs); }
  .stepper__ctl { display: flex; align-items: center; gap: .5rem; }
  .stepper__btn {
    inline-size: 2rem; block-size: 2rem;
    display: grid; place-items: center;
    border: 1.5px solid var(--brand);
    border-radius: 50%;
    color: var(--brand);
    background: none;
    cursor: pointer;
    transition: background var(--t-fast) var(--ease), opacity var(--t-fast) var(--ease);
  }
  .stepper__btn:hover:not(:disabled) { background: color-mix(in oklab, var(--brand) 12%, transparent); }
  .stepper__btn:disabled { border-color: var(--border-strong); color: var(--text-3); opacity: .5; cursor: default; }
  .stepper__btn .icon { inline-size: .9rem; block-size: .9rem; }
  .stepper__n { min-inline-size: 1.5rem; text-align: center; font-weight: 700; font-variant-numeric: tabular-nums; }
  .ages {
    margin-block-start: .5rem;
    padding: .6rem .7rem;
    border-radius: var(--r-sm);
    background: var(--surface-2);
  }
  .ages__k { font-size: var(--fs-xs); color: var(--text-3); margin-block-end: .4rem; }
  /* Three per line, so adding a fourth child wraps instead of stretching
     the panel wider and wider. */
  .ages__row {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: .5rem;
  }
  @media (max-width: 460px) {
    .ages__row { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  }

  /* ---- loading -------------------------------------------------------- */
  .loading-hero {
    display: grid; justify-items: center; gap: .5rem;
    padding: 2.5rem 1rem;
    border-radius: var(--r-lg);
    background: var(--brand-strong);
    color: #fff;
    text-align: center;
  }
  .loading-hero .icon { inline-size: 2.2rem; block-size: 2.2rem; }
  .loading-hero h2 { color: #fff; font-size: var(--fs-xl); }
  .loading-hero p { color: color-mix(in oklab, #fff 80%, transparent); font-size: var(--fs-sm); }

  .skel {
    border-radius: var(--r-sm);
    background: linear-gradient(90deg,
      var(--surface-3) 25%,
      color-mix(in oklab, var(--surface-3) 55%, var(--surface)) 37%,
      var(--surface-3) 63%);
    background-size: 400% 100%;
    animation: skel 1.4s ease infinite;
  }
  @keyframes skel { 0% { background-position: 100% 50%; } 100% { background-position: 0 50%; } }
  @media (prefers-reduced-motion: reduce) { .skel { animation: none; } }
  .skel-card { display: grid; gap: .6rem; padding: 1rem; border: 1px solid var(--border-soft); border-radius: var(--r-md); }

  /* ---- result cards ---------------------------------------------------- */
  .sorttabs {
    display: flex;
    gap: .25rem;
    overflow-x: auto;
    scrollbar-width: none;
    padding: .3rem;
    border: 1px solid var(--border);
    border-radius: var(--r-md);
    background: var(--surface-2);
  }
  .sorttabs::-webkit-scrollbar { display: none; }
  /* the same control also serves as in-page navigation, where the items are
     links rather than buttons */
  .sorttabs.is-sticky {
    position: sticky;
    inset-block-start: calc(var(--topbar-h, 4rem) + .5rem);
    z-index: 12;
    background: color-mix(in oklab, var(--surface-2) 88%, transparent);
    backdrop-filter: saturate(180%) blur(10px);
  }
  .sorttabs :is(button, a) {
    flex: 1 0 auto;
    padding: .5rem .8rem;
    border-radius: var(--r-sm);
    font-size: var(--fs-sm);
    font-weight: 650;
    color: var(--text-3);
    white-space: nowrap;
    cursor: pointer;
    background: none;
  }
  .sorttabs :is(button, a):hover { color: var(--text); }
  .sorttabs :is(button, a):is([aria-pressed="true"], [aria-current="true"]) {
    background: var(--surface);
    color: var(--brand-strong);
    box-shadow: var(--shadow-xs);
  }

  .res {
    display: grid;
    grid-template-columns: 15rem minmax(0, 1fr) auto;
    gap: 0;
    border: 1px solid var(--border);
    border-radius: var(--r-md);
    background: var(--surface);
    overflow: clip;
    transition: border-color var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease);
  }
  .res + .res { margin-block-start: .75rem; }
  .res:hover { border-color: color-mix(in oklab, var(--brand) 45%, var(--border)); box-shadow: var(--shadow-sm); }
  .res__img { background: var(--surface-3) center / cover no-repeat; min-block-size: 9.5rem; }

  /* the photo, plus whatever has to sit on top of it */
  .res__media { position: relative; min-block-size: 11rem; background: var(--surface-3); overflow: clip; }
  .res__media img {
    inline-size: 100%; block-size: 100%;
    display: block;
    object-fit: cover;
  }
  .res__media .badge {
    position: absolute;
    inset-block-start: .5rem; inset-inline-start: .5rem;
    backdrop-filter: saturate(160%) blur(6px);
  }
  .res__shots {
    position: absolute;
    inset-block-end: .5rem; inset-inline-end: .5rem;
    display: inline-flex; align-items: center; gap: .3rem;
    padding: .2rem .45rem;
    border-radius: var(--r-sm);
    background: oklch(0% 0 0 / .55);
    color: #fff;
    font-size: var(--fs-2xs);
    font-weight: 700;
  }
  .res__shots .icon { inline-size: .8rem; block-size: .8rem; }
  .res__bd { padding: .9rem 1rem; min-inline-size: 0; }
  .res__ttl { display: flex; align-items: baseline; gap: .5rem; flex-wrap: wrap; }
  .res__ttl b { font-size: var(--fs-md); font-weight: 700; }
  .res__meta { display: flex; align-items: center; gap: .4rem; flex-wrap: wrap; margin-block-start: .2rem; font-size: var(--fs-xs); color: var(--text-3); }
  .res__meta .icon { inline-size: .9rem; block-size: .9rem; }
  .res__tags { display: flex; gap: .35rem; flex-wrap: wrap; margin-block-start: .6rem; }
  .res__buy {
    display: grid; align-content: center; justify-items: end; gap: .35rem;
    padding: .9rem 1rem;
    border-inline-start: 1px dashed var(--border);
    background: var(--surface-2);
    text-align: end;
    min-inline-size: 11rem;
  }
  .res__was { font-size: var(--fs-xs); color: var(--text-3); text-decoration: line-through; }
  .res__price { font-size: var(--fs-xl); font-weight: 800; letter-spacing: -.02em; font-variant-numeric: tabular-nums; }
  .res__unit { font-size: var(--fs-xs); color: var(--text-3); }
  .res__stars { display: flex; gap: .1rem; color: var(--warning); }
  .res__stars .icon { inline-size: .9rem; block-size: .9rem; fill: currentColor; }
  .score {
    display: inline-flex; align-items: center; gap: .35rem;
    padding: .15rem .45rem;
    border-radius: var(--r-sm);
    background: color-mix(in oklab, var(--success) 15%, transparent);
    color: var(--success);
    font-weight: 700;
    font-size: var(--fs-xs);
  }

  /* a flight leg: times either end, the route drawn between them */
  .leg { display: grid; grid-template-columns: auto 1fr auto; align-items: center; gap: .9rem; }
  .leg + .leg { margin-block-start: .75rem; padding-block-start: .75rem; border-block-start: 1px dashed var(--border-soft); }
  .leg__t { text-align: center; }
  .leg__t b { display: block; font-size: var(--fs-md); font-weight: 700; font-variant-numeric: tabular-nums; }
  .leg__t small { color: var(--text-3); font-size: var(--fs-xs); }
  .leg__mid { text-align: center; min-inline-size: 0; }
  .leg__dur { font-size: var(--fs-xs); color: var(--text-3); }
  .leg__line {
    position: relative;
    block-size: 2px;
    margin: .35rem 0;
    background: var(--border-strong);
  }
  .leg__line::before, .leg__line::after {
    content: "";
    position: absolute;
    inset-block-start: -3px;
    inline-size: 8px; block-size: 8px;
    border-radius: 50%;
    background: var(--brand);
  }
  .leg__line::before { inset-inline-start: 0; }
  .leg__line::after  { inset-inline-end: 0; }
  .leg__stops { font-size: var(--fs-xs); color: var(--text-3); }
  .leg__stops.is-direct { color: var(--success); font-weight: 650; }

  /* ---- the guest score, as its own mark ------------------------------- */
  .rate { display: flex; align-items: center; gap: .5rem; }
  .rate__n {
    display: grid; place-items: center;
    min-inline-size: 2.6rem;
    padding: .3rem .45rem;
    border-radius: var(--r-sm);
    background: var(--brand);
    color: var(--on-brand, #fff);
    font-size: var(--fs-md);
    font-weight: 800;
    font-variant-numeric: tabular-nums;
    letter-spacing: -.01em;
  }
  .rate__bd b { display: block; font-size: var(--fs-sm); font-weight: 700; }
  .rate__bd small { font-size: var(--fs-xs); color: var(--text-3); }

  /* ---- what makes this rate worth taking today ------------------------ */
  .deal { display: flex; flex-wrap: wrap; gap: .4rem; }
  .deal__item {
    display: inline-flex; align-items: center; gap: .35rem;
    padding: .35rem .6rem;
    border-radius: var(--r-sm);
    font-size: var(--fs-xs);
    font-weight: 650;
  }
  .deal__item .icon { inline-size: .95rem; block-size: .95rem; }
  .deal__item.is-save   { background: color-mix(in oklab, var(--success) 14%, transparent); color: var(--success); }
  .deal__item.is-urgent { background: color-mix(in oklab, var(--danger) 12%, transparent);  color: var(--danger); }

  @container page (max-width: 780px) {
    .res { grid-template-columns: minmax(0, 1fr); }
    .res__img { min-block-size: 8rem; }
    .res__media { min-block-size: 10rem; }
    .res__buy {
      border-inline-start: 0;
      border-block-start: 1px dashed var(--border);
      justify-items: stretch;
      text-align: start;
    }
    .res__buy .btn { justify-content: center; }
  }
}

/* ==========================================================================
   INLINE AUTOCOMPLETE
   The popover version lives inside .sbpop; this is the same list used as an
   ordinary form field, so it only appears while the field has the focus.
   ========================================================================== */
@layer components {
  .ac-inline { position: relative; }
  .ac-inline .ac__list {
    position: absolute;
    inset-inline: 0;
    inset-block-start: calc(100% + .35rem);
    z-index: 20;
    max-block-size: 15rem;
    overflow-y: auto;
    margin: 0;
    padding: .3rem;
    border: 1px solid var(--border);
    border-radius: var(--r-sm);
    background: var(--surface);
    box-shadow: var(--shadow-md);
  }
  /* the paging row at the end of a remote list */
  .ac__more {
    justify-content: center;
    inline-size: 100%;
    font-weight: 650;
    color: var(--brand-strong);
  }

  .ac-inline:not(:focus-within) .ac__list,
  .ac-inline[data-picked] .ac__list { display: none; }
}

/* ==========================================================================
   GALLERY — one photograph large enough to judge, the rest as evidence there
   are more. The whole block is one click target for the lightbox.
   ========================================================================== */
@layer components {
  .gallery {
    position: relative;
    display: grid;
    grid-template-columns: 2fr 1fr 1fr;
    grid-template-rows: repeat(2, 1fr);
    gap: .35rem;
    block-size: clamp(16rem, 32vw, 24rem);
    border-radius: var(--r-md);
    overflow: clip;
    background: var(--surface-3);
  }
  .gallery a {
    display: block;
    min-inline-size: 0;
    overflow: clip;
    background: var(--surface-3);
  }
  .gallery a:first-child { grid-row: span 2; }
  .gallery img {
    inline-size: 100%; block-size: 100%;
    display: block;
    object-fit: cover;
    transition: transform var(--t-med) var(--ease);
  }
  .gallery a:hover img { transform: scale(1.04); }
  .gallery a:focus-visible { outline: 2px solid var(--brand); outline-offset: -2px; }

  .gallery__more {
    position: absolute;
    inset-block-end: .7rem; inset-inline-end: .7rem;
    z-index: 2;
  }

  @container page (max-width: 720px) {
    .gallery { grid-template-columns: 1fr 1fr; block-size: 15rem; }
    .gallery a:first-child { grid-column: span 2; grid-row: auto; }
    .gallery a:nth-child(n + 4) { display: none; }
  }
}

/* ==========================================================================
   RATE ROW — one bookable combination of a room, a board basis and a
   cancellation rule. The room above it is the same room every time; what
   changes between these lines is what you are agreeing to, so that is what
   the row leads with.
   ========================================================================== */
@layer components {
  .rates { display: grid; }
  .rate-row {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    gap: .75rem 1rem;
    align-items: center;
    padding: .8rem .9rem;
    border-block-start: 1px dashed var(--border);
  }
  .rate-row:hover { background: var(--surface-2); }
  .rate-row__bd { min-inline-size: 0; display: grid; gap: .3rem; }
  .rate-row__ttl { display: flex; align-items: center; gap: .45rem; flex-wrap: wrap; font-weight: 650; }
  .rate-row__ttl .icon { inline-size: 1rem; block-size: 1rem; color: var(--text-3); }
  .rate-row__meta {
    display: flex; align-items: center; gap: .2rem .55rem; flex-wrap: wrap;
    font-size: var(--fs-xs);
    color: var(--text-3);
  }
  .rate-row__meta > span + span::before { content: "·"; margin-inline-end: .55rem; color: var(--border-strong); }
  .rate-row__buy { display: grid; justify-items: end; gap: .25rem; text-align: end; }
  .rate-row__was { font-size: var(--fs-xs); color: var(--text-3); text-decoration: line-through; }
  .rate-row__p { font-size: var(--fs-lg); font-weight: 800; font-variant-numeric: tabular-nums; letter-spacing: -.02em; }
  .rate-row__u { font-size: var(--fs-2xs); color: var(--text-3); }
  .rate-row.is-picked { background: color-mix(in oklab, var(--brand) 7%, transparent); }

  @container page (max-width: 560px) {
    .rate-row { grid-template-columns: minmax(0, 1fr); }
    .rate-row__buy { justify-items: stretch; text-align: start; }
    .rate-row__buy .btn { justify-content: center; }
  }
}

/* ==========================================================================
   MAP PLACEHOLDER — a block that says "a map goes here" without pretending
   to be one. The grid and the pin are drawn, so nothing is fetched.
   ========================================================================== */
@layer components {
  .mapbox {
    position: relative;
    display: grid; place-items: center;
    min-block-size: 13rem;
    border: 1px solid var(--border);
    border-radius: var(--r-sm);
    overflow: clip;
    background:
      linear-gradient(color-mix(in oklab, var(--border-soft) 70%, transparent) 1px, transparent 1px) 0 0 / 100% 2.2rem,
      linear-gradient(90deg, color-mix(in oklab, var(--border-soft) 70%, transparent) 1px, transparent 1px) 0 0 / 2.2rem 100%,
      var(--surface-2);
  }
  .mapbox__pin {
    display: grid; place-items: center;
    inline-size: 2.5rem; block-size: 2.5rem;
    border-radius: 50%;
    background: var(--brand);
    color: var(--on-brand, #fff);
    box-shadow: 0 0 0 .5rem color-mix(in oklab, var(--brand) 22%, transparent);
  }
  .mapbox__bd { position: absolute; inset-block-end: .6rem; inset-inline: .6rem; }
}

/* ==========================================================================
   SCORE LIST — sub-scores read down a column, so the bar needs the room a
   definition list will not give it.
   ========================================================================== */
@layer components {
  .scorelist {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
    gap: .55rem 1.75rem;
  }
  .scorelist__row {
    display: grid;
    grid-template-columns: minmax(6rem, 9rem) minmax(0, 1fr);
    gap: .75rem;
    align-items: center;
    font-size: var(--fs-sm);
  }
  .scorelist__row > :first-child { color: var(--text-2); min-inline-size: 0; }
}

/* ==========================================================================
   MATRIX — a wide pivot of counts. Four hundred rows of digits is not a table
   anybody reads, so the number carries its own weight as colour and the row
   and column headers stay put while you scan.
   ========================================================================== */
@layer components {
  .matrix-wrap {
    max-block-size: 70vh;
    overflow: auto;
    border: 1px solid var(--border);
    border-radius: var(--r-sm);
  }
  table.matrix {
    inline-size: 100%;
    border-collapse: separate;
    border-spacing: 0;
    font-size: var(--fs-sm);
    font-variant-numeric: tabular-nums;
  }
  table.matrix th, table.matrix td {
    padding: .45rem .6rem;
    white-space: nowrap;
    border-block-end: 1px solid var(--border-soft);
  }
  table.matrix thead th {
    position: sticky;
    inset-block-start: 0;
    z-index: 3;
    background: var(--surface-2);
    font-size: var(--fs-2xs);
    font-weight: 700;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: var(--text-3);
    text-align: center;
    border-block-end: 1px solid var(--border);
  }
  table.matrix :is(thead th, tbody th):first-child {
    position: sticky;
    inset-inline-start: 0;
    z-index: 2;
    background: var(--surface);
    text-align: start;
    text-transform: none;
    letter-spacing: 0;
    font-size: var(--fs-sm);
    font-weight: 600;
    color: var(--text);
    /* the shadow is what tells you the column is floating over the rest */
    box-shadow: 1px 0 0 var(--border-soft);
  }
  table.matrix thead th:first-child { z-index: 4; background: var(--surface-2); }
  table.matrix td { text-align: center; color: var(--text-2); }
  table.matrix tbody tr:hover :is(td, th) { background: color-mix(in oklab, var(--brand) 5%, var(--surface)); }

  /* --t is 0…1, how big this count is against the busiest cell in the table */
  table.matrix td.heat {
    background: color-mix(in oklab, var(--brand) calc(var(--t, 0) * 62%), transparent);
    color: var(--text);
    font-weight: 650;
    border-radius: var(--r-xs, 4px);
  }
  table.matrix td.is-zero { color: var(--text-3); opacity: .5; }
  table.matrix tfoot th, table.matrix tfoot td {
    position: sticky;
    inset-block-end: 0;
    background: var(--surface-2);
    font-weight: 700;
    color: var(--text);
    border-block-start: 1px solid var(--border);
    border-block-end: 0;
  }
  table.matrix tfoot th:first-child { z-index: 4; }
}

/* ==========================================================================
   PICK SLOT — the tray beside a wizard step: the one, two or three things
   chosen so far, each removable, with empty places shown as places.
   ========================================================================== */
@layer components {
  .slots { display: grid; gap: .6rem; }
  .slot {
    position: relative;
    display: grid;
    grid-template-columns: auto minmax(0, 1fr) auto;
    gap: .6rem;
    align-items: start;
    padding: .65rem .7rem;
    border: 1px solid var(--border);
    border-radius: var(--r-sm);
    background: var(--surface);
    font-size: var(--fs-sm);
  }
  .slot__n {
    display: grid; place-items: center;
    inline-size: 1.6rem; block-size: 1.6rem;
    flex: none;
    border-radius: 50%;
    background: var(--brand);
    color: var(--on-brand, #fff);
    font-size: var(--fs-2xs);
    font-weight: 700;
  }
  .slot__bd { min-inline-size: 0; display: grid; gap: .15rem; }
  .slot__bd b { font-weight: 650; overflow-wrap: anywhere; }
  .slot__meta { font-size: var(--fs-xs); color: var(--text-3); }
  .slot.is-empty {
    border-style: dashed;
    background: transparent;
    color: var(--text-3);
  }
  .slot.is-empty .slot__n { background: var(--surface-3); color: var(--text-3); }
}

/* ==========================================================================
   DUAL RANGE — two thumbs on one track
   ========================================================================== */
@layer components {
  .range { display: grid; gap: .5rem; }
  .range__track {
    position: relative;
    block-size: 1.6rem;
    display: grid;
    align-items: center;
  }
  .range__track::before {
    content: "";
    position: absolute;
    inset-inline: 0;
    block-size: 4px;
    border-radius: 999px;
    background: var(--surface-3);
  }
  .range__fill {
    position: absolute;
    block-size: 4px;
    border-radius: 999px;
    background: var(--brand);
  }
  /* both inputs sit on the same line; only the thumbs take pointer events, so
     whichever thumb is under the cursor is the one that moves */
  .range__track input[type="range"] {
    position: absolute;
    inset-inline: 0;
    inline-size: 100%;
    margin: 0;
    background: none;
    appearance: none;
    pointer-events: none;
    block-size: 1.6rem;
  }
  .range__track input[type="range"]::-webkit-slider-thumb {
    appearance: none;
    pointer-events: auto;
    inline-size: 1.15rem; block-size: 1.15rem;
    border-radius: 50%;
    background: var(--surface);
    border: 3px solid var(--brand);
    box-shadow: var(--shadow-sm);
    cursor: grab;
  }
  .range__track input[type="range"]::-moz-range-thumb {
    pointer-events: auto;
    inline-size: 1.15rem; block-size: 1.15rem;
    border-radius: 50%;
    background: var(--surface);
    border: 3px solid var(--brand);
    cursor: grab;
  }
  .range__track input[type="range"]:focus-visible::-webkit-slider-thumb { box-shadow: var(--ring); }
  .range__out {
    display: flex; align-items: center; justify-content: space-between;
    font-size: var(--fs-xs);
    color: var(--text-3);
    font-variant-numeric: tabular-nums;
  }
  .range__out b { color: var(--text); }

  /* ---- cabin class picker --------------------------------------------- */
  /* three equal cells on one line: the panel is max-content sized, so it
     widens to fit rather than wrapping the third option onto its own row */
  .cabin {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: .5rem;
  }
  @media (max-width: 460px) {
    .cabin { grid-template-columns: minmax(0, 1fr); }
  }
  .cabin label {
    position: relative;
    display: inline-flex; align-items: center; justify-content: center; gap: .4rem;
    white-space: nowrap;
    padding: .45rem .7rem;
    margin: 0;
    border: 1px solid var(--border);
    border-radius: var(--r-sm);
    font-size: var(--fs-sm);
    font-weight: 600;
    color: var(--text-2);
    cursor: pointer;
  }
  .cabin input { position: absolute; inline-size: 1px; block-size: 1px; clip-path: inset(50%); }
  .cabin label .icon { inline-size: 1rem; block-size: 1rem; }
  .cabin label:has(input:checked) {
    border-color: var(--brand);
    background: color-mix(in oklab, var(--brand) 10%, transparent);
    color: var(--brand-strong);
  }
  .cabin label:has(input:focus-visible) { box-shadow: var(--ring); }

  /* ---- airline mark ---------------------------------------------------- */
  .airline {
    inline-size: 2.5rem; block-size: 2.5rem;
    flex: none;
    display: grid; place-items: center;
    border: 1px solid var(--border);
    border-radius: var(--r-sm);
    background: var(--surface);
    font: 800 var(--fs-xs)/1 var(--font-mono);
    letter-spacing: .02em;
    color: var(--text-2);
  }
}

/* ==========================================================================
   COUNT BAR — a number and the bar that makes it comparable at a glance
   ========================================================================== */
@layer components {
  .bar { display: flex; align-items: center; gap: .6rem; min-inline-size: 8rem; }
  .bar__n { font-weight: 700; font-variant-numeric: tabular-nums; min-inline-size: 3.2rem; }
  .bar__track {
    flex: 1;
    block-size: 6px;
    border-radius: 999px;
    background: var(--surface-3);
    overflow: clip;
    min-inline-size: 3rem;
  }
  .bar__fill {
    display: block;
    block-size: 100%;
    border-radius: 999px;
    background: var(--brand);
  }
}

/* ==========================================================================
   FLIGHT ITINERARY CARD
   One card is one thing you can buy — which for a round trip means two legs
   stacked, each with its own airline, times and flight number, and a single
   price underneath for the whole itinerary.
   ========================================================================== */
@layer components {
  .fl {
    border: 1px solid var(--border);
    border-radius: var(--r-md);
    background: var(--surface);
    overflow: clip;
    transition: border-color var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease);
  }
  .fl + .fl { margin-block-start: .75rem; }
  .fl:hover { border-color: color-mix(in oklab, var(--brand) 45%, var(--border)); box-shadow: var(--shadow-sm); }

  .fl__hd {
    display: flex; align-items: center; gap: .5rem; flex-wrap: wrap;
    padding: .55rem .9rem;
    background: var(--surface-2);
    border-block-end: 1px solid var(--border-soft);
    font-size: var(--fs-xs);
    color: var(--text-3);
  }
  .fl__bd { padding: .9rem; display: grid; gap: .9rem; }

  .fl__leg {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr) auto;
    align-items: center;
    gap: 1rem;
  }
  .fl__leg + .fl__leg { padding-block-start: .9rem; border-block-start: 1px dashed var(--border-soft); }
  .fl__no { text-align: end; min-inline-size: 4.5rem; }
  .fl__no small { display: block; font-size: var(--fs-2xs); color: var(--text-3); }
  .fl__no b { font-variant-numeric: tabular-nums; }

  .fl__ft {
    display: flex; align-items: center; gap: .75rem; flex-wrap: wrap;
    padding: .75rem .9rem;
    border-block-start: 1px dashed var(--border);
    background: var(--surface-2);
  }
  .fl__price { font-size: var(--fs-xl); font-weight: 800; letter-spacing: -.02em; font-variant-numeric: tabular-nums; }
  .fl__price small { font-size: var(--fs-xs); font-weight: 600; color: var(--text-3); }
  .fl__note { font-size: var(--fs-xs); color: var(--text-3); }
  .fl__ft .btn:last-child { margin-inline-start: auto; }

  .fl__more { padding: .9rem; border-block-start: 1px solid var(--border-soft); background: var(--surface); }
  .fl__more[hidden] { display: none; }

  /* the vertical timeline used inside the details panel */
  .tl { display: grid; gap: 0; }
  .tl__row { display: grid; grid-template-columns: 5.5rem auto minmax(0, 1fr); gap: .75rem; align-items: start; }
  .tl__t { text-align: end; font-variant-numeric: tabular-nums; }
  .tl__t b { display: block; }
  .tl__t small { color: var(--text-3); font-size: var(--fs-xs); }
  .tl__dot {
    inline-size: 10px; block-size: 10px;
    margin-block-start: .35rem;
    border-radius: 50%;
    border: 2px solid var(--brand);
    background: var(--surface);
  }
  .tl__mid { padding-block: .6rem; }
  .tl__line {
    grid-column: 2;
    inline-size: 2px;
    min-block-size: 2.2rem;
    margin-inline: 4px;
    background: var(--border-strong);
  }

  /* one leg of the itinerary inside the details panel: a heading that says
     where it goes and how long it takes, then the segment timeline */
  .itin-leg + .itin-leg {
    margin-block-start: 1rem;
    padding-block-start: 1rem;
    border-block-start: 1px dashed var(--border);
  }
  .itin-leg__hd {
    display: flex; align-items: baseline; gap: .25rem .6rem; flex-wrap: wrap;
    margin-block-end: .8rem;
  }
  .itin-leg__hd b { font-size: var(--fs-md); font-weight: 700; }
  .itin-leg__hd span { font-size: var(--fs-xs); color: var(--text-3); }

  /* the facts about one flown segment — number, length, cabin, aircraft */
  .segmeta {
    display: flex; flex-wrap: wrap; gap: .2rem .55rem;
    font-size: var(--fs-xs);
    color: var(--text-3);
  }
  .segmeta > span { display: inline-flex; align-items: center; gap: .3rem; }
  .segmeta > span + span::before {
    content: "·";
    margin-inline-end: .3rem;
    color: var(--border-strong);
  }
  .segmeta b { color: var(--text-2); font-weight: 650; font-variant-numeric: tabular-nums; }

  /* the gap between two segments is the part of a trip people misread, so it
     gets its own band rather than another line of grey text */
  .tl__stop {
    display: flex; align-items: center; gap: .25rem .5rem; flex-wrap: wrap;
    margin-block: .5rem;
    padding: .5rem .7rem;
    border-radius: var(--r-sm);
    border: 1px dashed color-mix(in oklab, var(--warning) 50%, var(--border));
    background: color-mix(in oklab, var(--warning) 10%, transparent);
    font-size: var(--fs-xs);
    color: var(--text-2);
  }
  .tl__stop .icon { inline-size: 1rem; block-size: 1rem; color: var(--warning); flex: none; }
  .tl__stop b { color: var(--text); font-weight: 700; }
  .tl__stop .sep-dot::before { content: "·"; color: var(--border-strong); }

  @container page (max-width: 640px) {
    .fl__leg { grid-template-columns: auto minmax(0, 1fr); }
    .fl__no { grid-column: 2; text-align: start; }
    .tl__row { grid-template-columns: 4.5rem auto minmax(0, 1fr); }
  }
}

/* ==========================================================================
   CHIPSET — a wrapping set of choices backed by real radios or checkboxes.
   Radios in a filter panel read better as pills than as a stack of dots, and
   because the input is still there the keyboard and the form both still work.
   ========================================================================== */
@layer components {
  .chipset { display: flex; flex-wrap: wrap; gap: .4rem; }
  .chipset label {
    position: relative;
    display: inline-flex; align-items: center; gap: .35rem;
    margin: 0;
    padding: .38rem .7rem;
    border: 1px solid var(--border);
    border-radius: 999px;
    font-size: var(--fs-xs);
    font-weight: 650;
    color: var(--text-2);
    white-space: nowrap;
    cursor: pointer;
    transition: border-color var(--t-fast) var(--ease), background var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
  }
  .chipset input {
    position: absolute;
    inline-size: 1px; block-size: 1px;
    clip-path: inset(50%);
  }
  .chipset label:hover { border-color: var(--border-strong); color: var(--text); }
  .chipset label:has(input:checked) {
    border-color: var(--brand);
    background: color-mix(in oklab, var(--brand) 12%, transparent);
    color: var(--brand-strong);
  }
  .chipset label:has(input:focus-visible) { box-shadow: var(--ring); }

  .chipset.is-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .chipset.is-grid label { justify-content: center; }
}

/* ==========================================================================
   STEPS — where you are in a flow that has a beginning and an end.
   Built like .sorttabs on purpose: same pill-in-a-trough shape, so a booking
   flow and a result list read as parts of one product.
   ========================================================================== */
@layer components {
  .steps {
    display: flex;
    gap: .25rem;
    padding: .35rem;
    border: 1px solid var(--border);
    border-radius: var(--r-md);
    background: var(--surface-2);
    overflow-x: auto;
    scrollbar-width: none;
    list-style: none;
    margin: 0;
  }
  .steps::-webkit-scrollbar { display: none; }

  .step {
    flex: 1 0 auto;
    display: inline-flex; align-items: center; gap: .5rem;
    padding: .5rem .8rem;
    border-radius: var(--r-sm);
    font-size: var(--fs-sm);
    font-weight: 650;
    color: var(--text-3);
    white-space: nowrap;
  }
  .step__n {
    display: grid; place-items: center;
    inline-size: 1.5rem; block-size: 1.5rem;
    flex: none;
    border: 1px solid var(--border-strong);
    border-radius: 50%;
    font-size: var(--fs-2xs);
    font-weight: 700;
    font-variant-numeric: tabular-nums;
  }
  .step__n .icon { inline-size: .85rem; block-size: .85rem; }

  /* a finished step is not the point of the page any more, so it recedes —
     but it keeps a tick, because "did that save?" is a real question */
  .step.is-done { color: var(--text-2); }
  .step.is-done .step__n {
    border-color: transparent;
    background: color-mix(in oklab, var(--success) 18%, transparent);
    color: var(--success);
  }
  .step.is-now {
    background: var(--surface);
    color: var(--brand-strong);
    box-shadow: var(--shadow-xs);
  }
  .step.is-now .step__n {
    border-color: transparent;
    background: var(--brand);
    color: var(--on-brand, #fff);
  }
}

/* ==========================================================================
   PRICE LIST — what makes up a total, one line each, the total set apart.
   ========================================================================== */
@layer components {
  .pricelist { display: grid; gap: .5rem; }
  .pricelist__row {
    display: flex; align-items: baseline; justify-content: space-between; gap: 1rem;
    font-size: var(--fs-sm);
  }
  .pricelist__row > :first-child { color: var(--text-2); min-inline-size: 0; }
  .pricelist__row b { font-variant-numeric: tabular-nums; white-space: nowrap; }
  .pricelist__row.is-soft { font-size: var(--fs-xs); }
  .pricelist__row.is-soft > :first-child,
  .pricelist__row.is-soft b { color: var(--text-3); font-weight: 600; }

  .pricelist__total {
    display: flex; align-items: baseline; justify-content: space-between; gap: 1rem;
    margin-block-start: .8rem;
    padding-block-start: .8rem;
    border-block-start: 1px dashed var(--border);
    font-weight: 700;
  }
  .pricelist__total b {
    font-size: var(--fs-lg);
    letter-spacing: -.02em;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
  }
}

/* ==========================================================================
   OCR STRIP — an offer to fill the form from a document instead of by hand.
   ========================================================================== */
@layer components {
  .ocr {
    display: flex; align-items: center; gap: .75rem; flex-wrap: wrap;
    padding: .7rem .85rem;
    border: 1px dashed var(--border-strong);
    border-radius: var(--r-sm);
    background: var(--surface-2);
  }
  .ocr__ico {
    display: grid; place-items: center;
    inline-size: 2.25rem; block-size: 2.25rem;
    flex: none;
    border-radius: var(--r-sm);
    background: color-mix(in oklab, var(--brand) 12%, transparent);
    color: var(--brand-strong);
  }
  .ocr__ico .icon { inline-size: 1.15rem; block-size: 1.15rem; }
  .ocr__bd { flex: 1 1 13rem; min-inline-size: 0; }
  .ocr__bd b { display: block; font-size: var(--fs-sm); font-weight: 650; }
  .ocr__bd p { margin: .1rem 0 0; font-size: var(--fs-xs); color: var(--text-3); }
  .ocr > .btn { flex: none; }
}

/* ==========================================================================
   SUPPLIER PROSE — the description, the policies and the fee tables arrive
   as the supplier's own HTML. It is shown as written, so it needs the
   handful of tags it actually uses to look like part of the panel.
   ========================================================================== */
@layer components {
  .rich { font-size: var(--fs-sm); line-height: 1.75; color: var(--text-2); }
  .rich > :first-child { margin-block-start: 0; }
  .rich > :last-child { margin-block-end: 0; }
  .rich p { margin: .55rem 0; }
  .rich b, .rich strong { color: var(--text); font-weight: 650; }
  .rich ul, .rich ol { margin: .55rem 0; padding-inline-start: 1.15rem; display: grid; gap: .3rem; }
  .rich li { margin: 0; }
  .rich h3, .rich h4 { margin: .8rem 0 .3rem; font-size: var(--fs-sm); color: var(--text); }
  .rich table { inline-size: 100%; border-collapse: collapse; }
  .rich td, .rich th { padding: .35rem .5rem; border-block-end: 1px dashed var(--border-soft); text-align: start; }

  /* a block of it that opens on demand */
  .fold {
    border: 1px solid var(--border-soft);
    border-radius: var(--r-sm);
    padding: .1rem .8rem;
    background: var(--surface-2);
  }
  .fold + .fold { margin-block-start: .5rem; }
  .fold > summary {
    cursor: pointer;
    padding: .6rem 0;
    font-size: var(--fs-sm);
    font-weight: 650;
    list-style: none;
    display: flex;
    align-items: center;
    gap: .4rem;
  }
  .fold > summary::-webkit-details-marker { display: none; }
  .fold > summary::before {
    content: "";
    inline-size: .45rem; block-size: .45rem;
    border-inline-end: 2px solid var(--text-3);
    border-block-end: 2px solid var(--text-3);
    transform: rotate(-45deg);
    transition: transform var(--t-fast, .15s) var(--ease, ease);
  }
  html[dir="rtl"] .fold > summary::before { transform: rotate(-135deg); }
  .fold[open] > summary::before { transform: rotate(45deg); }
  .fold > summary:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; border-radius: var(--r-xs, 4px); }
  .fold > :not(summary) { padding-block-end: .7rem; }
}

/* ==========================================================================
   RESULTS TOOLBAR — on a narrow screen the filter panel is not beside the
   list any more, so it needs a way in and a way back out.
   ========================================================================== */
@layer components {
  .resbar { display: none; gap: .5rem; margin-block-end: .75rem; }
  .resbar .btn { flex: 1 1 0; justify-content: center; }
  .resbar .badge { font-variant-numeric: tabular-nums; }

  /* controls that only make sense once the panel has stopped being a column
     beside the list — same breakpoint as the stack, so they never disagree */
  .res-narrow { display: none; }

  @container page (max-width: 960px) {
    .resbar { display: flex; }
    .res-narrow { display: inline-flex; }
    /* filters belong above the results they filter, not below them */
    .view-split.is-filters-first .view-split__side { order: -1; }
    /* scrolling to either half must not park its heading under the topbar */
    .view-split.is-filters-first > * { scroll-margin-block-start: calc(var(--topbar-h, 4rem) + .75rem); }
  }
}

/* ==========================================================================
   STATS PANEL — a label column with its controls beside it, and a rank/count
   pair that can be read down the column
   ========================================================================== */
@layer components {
  .stat-filters {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    gap: .6rem .9rem;
    align-items: center;
  }
  .stat-filters > .label { margin: 0; white-space: nowrap; }
  .stat-filters__ctl { display: flex; gap: .5rem; flex-wrap: wrap; }
  .stat-filters__ctl > .select { flex: 1 1 6rem; min-inline-size: 0; }
  .stat-filters__ctl > .input-wrap { flex: 1 1 10rem; }

  @container page (max-width: 560px) {
    .stat-filters { grid-template-columns: minmax(0, 1fr); }
    .stat-filters > .label { margin-block-start: .4rem; }
  }

  .rank {
    display: grid; place-items: center;
    inline-size: 1.7rem; block-size: 1.7rem;
    border-radius: var(--r-sm);
    background: color-mix(in oklab, var(--warning) 22%, transparent);
    color: color-mix(in oklab, var(--warning) 70%, var(--text));
    font-size: var(--fs-xs);
    font-weight: 800;
    font-variant-numeric: tabular-nums;
  }
  /* the top three read as a podium without needing a legend */
  tr:nth-child(1) .rank { background: color-mix(in oklab, var(--warning) 38%, transparent); }
  tr:nth-child(n+11) .rank { background: var(--surface-3); color: var(--text-3); }

  /* the number carries its own share bar, so the column stays narrow */
  .count {
    position: relative;
    display: inline-block;
    padding: .2rem .55rem;
    border-radius: var(--r-sm);
    background: color-mix(in oklab, var(--brand) 10%, transparent);
    color: var(--brand-strong);
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    overflow: clip;
    min-inline-size: 5rem;
    text-align: end;
  }
  /* the share is painted as a background band rather than a child element,
     so the number always sits on top of it without a stacking context */
  .count {
    background-image: linear-gradient(color-mix(in oklab, var(--brand) 20%, transparent) 0 100%);
    background-repeat: no-repeat;
    background-size: var(--w, 0%) 100%;
    background-position: left center;
  }
  html[dir="rtl"] .count { background-position: right center; }
}


/* ==========================================================================
   MINI SELECT — a select whose list we draw ourselves
   The native dropdown is an OS widget: on some browsers it keeps the system
   palette whatever the page asks for, so a dark panel gets a white list.
   Inside themed panels we own the control instead.
   ========================================================================== */
@layer components {
  .minisel { position: relative; min-inline-size: 0; }

  .minisel__btn {
    display: flex; align-items: center; justify-content: space-between; gap: .35rem;
    inline-size: 100%;
    padding: .4rem .55rem;
    border: 1px solid var(--border);
    border-radius: var(--r-sm);
    background: var(--surface);
    color: var(--text);
    font-size: var(--fs-sm);
    font-weight: 600;
    cursor: pointer;
    text-align: start;
  }
  .minisel__btn > [data-lbl] {
    min-inline-size: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  .minisel__btn .icon { inline-size: .85rem; block-size: .85rem; color: var(--text-3); flex: none; }
  .minisel__btn:hover { border-color: var(--border-strong); }
  .minisel__btn[aria-expanded="true"] { border-color: var(--brand); box-shadow: var(--ring); }

  .minisel__list {
    position: fixed;
    z-index: 70;
    max-block-size: 14rem;
    overflow-y: auto;
    padding: .25rem;
    border: 1px solid var(--border);
    border-radius: var(--r-sm);
    background: var(--surface);
    box-shadow: var(--shadow-lg);
  }
  .minisel__list[hidden] { display: none; }

  .minisel__opt {
    display: block;
    inline-size: 100%;
    padding: .35rem .55rem;
    border-radius: var(--r-xs);
    background: none;
    color: var(--text);
    font-size: var(--fs-sm);
    text-align: start;
    white-space: nowrap;
    cursor: pointer;
  }
  .minisel__opt:hover { background: var(--surface-2); }
  .minisel__opt[aria-selected="true"] {
    background: color-mix(in oklab, var(--brand) 16%, transparent);
    color: var(--brand-strong);
    font-weight: 700;
  }
}
