/* App rules that cascade last (formerly tailwind.css, outside its `@layer` blocks): the desktop button twins, the by-name primitives, fonts,
 * the mobile/desktop shell variables and the touch/print blocks; the desktop button twins close the file. */

/* Primitives the kit and the TS toggles spell by name. `hidden` wins over a component's `display` (.btn, .alert, .icon-m) by
 * coming later at equal specificity, not by !important, so an inline `style.display` still reveals; the rules below keep winning
 * over it as before. `ink-*` = tone ink (was text-error/-success/-warning/-info). */
.hidden { display: none; }

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

.truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.ink-error { color: var(--c-error); }

.ink-success { color: var(--c-success); }

.ink-warning { color: var(--c-warning); }

.ink-info { color: var(--c-info); }

/*
 * Self-hosted IBM Plex Sans (OFL, variable). Screen font is bundled — not
 * `system-ui` — so every user renders the same typeface regardless of OS. The
 * variable weight axis (100 700) backs the discrete weights used across the app
 * (label 600, clickable-choice 500, body 400, bold 700) and leaves the lighter
 * end available. Latin and latin-ext cover PT-BR and EN content entirely.
 * Files served plain via the `/css/**` resource handler (WebMvcConfig).
 * PDF rendering keeps its own Noto Sans TTFs (PdfFonts.kt) — unrelated path.
 */
@font-face {
    font-family: 'IBM Plex Sans';
    font-style: normal;
    font-weight: 100 700;
    font-stretch: 100%;
    font-display: swap;
    src: url('/css/fonts/ibm-plex-sans-latin-b2c9031d9fd6493ccda94908cdba4abd.woff2') format('woff2');
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
    font-family: 'IBM Plex Sans';
    font-style: normal;
    font-weight: 100 700;
    font-stretch: 100%;
    font-display: swap;
    src: url('/css/fonts/ibm-plex-sans-latin-ext-f0e2925b3fa67a6f136f45479f19632b.woff2') format('woff2');
    unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/*
 * Italic faces (real IBM Plex Sans Italic, variable wght 100 700) — latin and
 * latin-ext only, matching the upright set above.
 */
@font-face {
    font-family: 'IBM Plex Sans';
    font-style: italic;
    font-weight: 100 700;
    font-stretch: 100%;
    font-display: swap;
    src: url('/css/fonts/ibm-plex-sans-latin-italic-ed273b4064f8cd44562c4f31db1ccaf5.woff2') format('woff2');
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
    font-family: 'IBM Plex Sans';
    font-style: italic;
    font-weight: 100 700;
    font-stretch: 100%;
    font-display: swap;
    src: url('/css/fonts/ibm-plex-sans-latin-ext-italic-f37d83ce57c151c0d41e55a9a8988b46.woff2') format('woff2');
    unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* DaisyUI's floor-browser color path. These MUST stay behind @supports: DaisyUI emits
   `var(--fallback-su, color-mix(in srgb, var(--c-success) calc(.1 * 100%), transparent))`, so a --fallback-* defined for every browser
   wins over the OKLCH branch and every /opacity utility (bg-success/10, bg-base-200/40,
   text-base-content/60) paints at full opacity. Safari 12 and the other floor browsers have
   no oklch(), take this block, and keep the flat colors.

   These values MIRROR the palette in tokens.css (L0) — they are a second
   copy of the same palette, not independent knobs. Change one side and you must change the
   other, or floor browsers silently keep the old colors (which is how the pre-2026-09-08
   success/warning/error values survived a theme darkening). */
@supports not (color: oklch(0% 0 0)) {
    :root {
        --fallback-p: #1A3A5C;
        --fallback-pc: #ffffff;
        --fallback-s: #162B44;
        --fallback-sc: #ffffff;
        --fallback-a: #3A7A9E;
        --fallback-ac: #ffffff;
        --fallback-n: #374151;
        --fallback-nc: #ffffff;
        --fallback-b1: #ffffff;
        --fallback-b2: #EDF1F7;
        --fallback-b3: #D0D7E3;
        --fallback-bc: #0B111C;
        --fallback-in: #2563EB;
        --fallback-inc: #ffffff;
        --fallback-su: #166534;
        --fallback-suc: #ffffff;
        --fallback-wa: #9A3412;
        --fallback-wac: #ffffff;
        --fallback-er: #991B1B;
        --fallback-erc: #ffffff;
    }
}

:root {
    --mobile-safe-area-top: env(safe-area-inset-top, 0px);
    --mobile-safe-area-bottom: env(safe-area-inset-bottom, 0px);
    /* Mobile top app bar height (below the status-bar safe area). M1: 48px, secondary to the
       bottom bar (was 64px when it was the only nav entry point). Fixed-position content
       reserves a top strip of this size so the bar never overlaps page headers, and the
       mobile nav dropdown hangs from the bottom of this strip. */
    --mobile-topbar-height: var(--h-topbar);
    --mobile-menu-top-strip: calc(var(--mobile-safe-area-top) + var(--mobile-topbar-height));
    /* Everything that reserves or anchors to the top strip reads this. It equalled the safe area
       alone while the bar hid on scroll (M1, until 2026-09-28); the bar is pinned now, so the
       two strips are the same size, and the name stays only so the readers need no rename. */
    --mobile-topbar-live-strip: var(--mobile-menu-top-strip);
    /* M2 bottom nav bar (logged-in shell pages only, below lg). */
    --mobile-bottom-nav-height: 4rem;
    --mobile-bottom-nav-strip: calc(var(--mobile-bottom-nav-height) + var(--mobile-safe-area-bottom));
    /* Bottom-chrome equivalent of --mobile-topbar-live-strip: the pre-auth login page and any
       other bottom-bar-less shell page keep the plain safe area; a page with .mobile-bottom-nav
       reserves the bar's full strip instead. Doesn't need a "live"/hidden distinction — the bar
       itself never hides on scroll (M2 is the primary nav, only the top bar is secondary/M1). */
    --mobile-chrome-bottom-strip: var(--mobile-safe-area-bottom);
}

body:has(.mobile-bottom-nav) {
    --mobile-chrome-bottom-strip: var(--mobile-bottom-nav-strip);
}

/* html-level copy: scroll-padding-* is declared on <html> itself (see below), which is body's
   ANCESTOR and so never inherits a custom property redeclared on body. :has() lets the same
   override reach the html element's own value instead. */
html:has(.mobile-bottom-nav) {
    --mobile-chrome-bottom-strip: var(--mobile-bottom-nav-strip);
}

/* Form focus mode (F10, 2026-10-09): below lg a form page drops the M2 bar — the sticky Salvar bar is the
   thumb-zone action and the top-bar ← is the way out — so the strip every bottom-anchored rule reads
   (sticky bar, toast, FAB, scroll-padding) collapses to the safe area. Both html and body copies, as above. */
@media (max-width: 1023.98px) {
    /* `.form-focus` is set only by formActions (Actions.kt): detail pages, the checklist footer and
       fotos-depois also emit a `.sticky-action-bar` and keep their bar. */
    body:has(.sticky-action-bar.form-focus) .mobile-bottom-nav {
        display: none;
    }

    body:has(.sticky-action-bar.form-focus),
    html:has(.sticky-action-bar.form-focus) {
        --mobile-chrome-bottom-strip: var(--mobile-safe-area-bottom);
    }
}

/* Desktop has no fixed bar (sidebar is a permanent column) — tighten the
   scroll-padding on the scroll container to the page gutter. */
@media (min-width: 1024px) {
    html {
        scroll-padding-top: 1.25rem;
        scroll-padding-bottom: 1.25rem;
    }
}

/* M27: a sticky bar never covers the focused field. A page with a .sticky-action-bar needs more
   than the flat 1.5rem gutter the base rule above adds — the bar's own height: below `sm` the
   Salvar/Cancelar pair stacks (two 48px/h-12 buttons, gap and p-3 padding = 129px measured), so
   8.5rem — so this extends that rule for those pages instead of duplicating it: the :has()
   selector outranks the bare `html` one, so only one scroll-padding-bottom applies. */
@media (max-width: 1023.98px) {
    html:has(.sticky-action-bar) {
        scroll-padding-bottom: calc(var(--mobile-chrome-bottom-strip) + 8.5rem);
    }
}

/* 48px minimum tap targets (M4: WCAG 2.5.5's 44px floor raised to the M3/Android 48dp metric, user 2026-09-24 "48 every").
   Below 1024 is the phone tier at every width, whatever the pointer; at 1024+ only a touch screen keeps the floor (tokens.css
   `--ctl`: the finger, not the layout, sets the target). One query, the same split as `--ctl`. */
@media (max-width: 1023.98px), (pointer: coarse) {
    .btn-sm { min-height: var(--ctl-l); }
    /* .btn-circle.btn-sm sets h/w at (0,2,0), beating the .btn-sm floor above — the thumbnail ✎/× circles stayed 32px on touch. */
    .btn-circle.btn-sm { min-height: var(--ctl-l); min-width: var(--ctl-l); }
    /* Same for the square kebab triggers (`btn-square:where(.btn-sm)` pins width to 2rem): 32px wide on every list card. */
    .btn-square.btn-sm { min-width: var(--ctl-l); }
    .menu a, .menu summary { min-height: var(--ctl-l); }
    /* Collapsible section heads are the tap target for the whole disclosure, but they are plain <summary> outside .menu, so the
       rule above never reached them: at 360px .form-section-head measured 33px and .disclosure-summary 36px, both under the 48px
       floor responsive.spec.ts asserts. Both already carry flex + items-center, so a min-height re-centres the row. */
    summary.form-section-head, summary.disclosure-summary { min-height: var(--ctl-l); }
    .join .btn { min-height: var(--ctl-l); min-width: var(--ctl-l); }
    /* The label around a 24px checkbox/radio is the thumb's target (M4): 40px with its own padding, so the row gets the floor. */
    .label:is(.cursor-pointer, .label-pick) { min-height: var(--ctl-l); }
    /* List filter pills (badgeFilter: a radio inside a .badge label) measured 24px at 384px — every categoria/status filter was a
       sub-floor target. */
    label.badge:has(> input[type=radio]) { min-height: var(--ctl-l); }
    /* /kit at 384 (M4, 2026-10-13): the colour swatch's label is inline around its 32px dot, the compact disclosure pins min-h-0
       (44px), the date picker's month arrows are --ctl-s, and the filtered empty state's "Limpar" is one 18px text line on a row
       of its own. */
    label:has(> [data-swatch-color]) { display: inline-flex; align-items: center; justify-content: center; min-height: var(--ctl-l); min-width: var(--ctl-l); }
    .detail-comments-collapse > summary.collapse-title { min-height: var(--ctl-l); }
    .date-panel .date-head .date-nav { width: var(--ctl-l); height: var(--ctl-l); min-height: var(--ctl-l); }
    .empty-note a.link { display: inline-flex; align-items: center; min-height: var(--ctl-l); }
}

/* The one rule that is about touch itself, not size: iOS zooms the page on focus under a 16px input font. Plain selector list
   (not :where) — must tie DaisyUI's .select/.input-sm 14px rules at (0,1,0) and win on source order. */
@media (pointer: coarse) {
    .input, .select, .textarea, .file-input, input, select, textarea { font-size: 16px; }
}

@property --pill-fade { syntax: "<length>"; inherits: false; initial-value: 0px; }

/* A filter pill row is one swipeable line on a phone: at 44px a wrapped row of 11 categorias
   took five lines and pushed the first item below the fold. */
@media (max-width: 1023.98px) {
    .filter-pill-row { flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none; }
    .filter-pill-row > * { flex-shrink: 0; }
    /* D5 (user 2026-10-07): the clipped edge fades so the row reads as scrollable. Where scroll-driven animations
       exist the fade is OWNED by the scroll timeline: a row that does not overflow has an inactive timeline, so the
       base 0 stays and a row of five that just fits is not faded (replica 2026-10-08); a row that overflows fades
       until it nears its end. Elsewhere it stays a plain right fade. */
    .filter-pill-row { --pill-fade: 2.5rem; mask-image: linear-gradient(90deg, #000 calc(100% - var(--pill-fade)), transparent); }
    @supports (animation-timeline: scroll()) {
        @keyframes pill-row-fade { from, 80% { --pill-fade: 2.5rem; } to { --pill-fade: 0px; } }
        .filter-pill-row { --pill-fade: 0px; animation: pill-row-fade linear both; animation-timeline: scroll(self inline); }
    }
}

/* The pill radios are `sr-only`, not `display:none`: a hidden radio is unfocusable, which left the row keyboard-inoperable and
   its phone scroll region unreachable (axe scrollable-region-focusable, 2026-10-07). The focus ring rides the visible label. */
/* The label is the sr-only radio's containing block: otherwise a pill scrolled out of the row leaves its 1 px radio at the
   page level and the document scrolls sideways (M26, 2026-10-07). */
.filter-pill-row label { position: relative; }

.filter-pill-row label:has(input:focus-visible) { outline: 2px solid currentColor; outline-offset: 2px; }

/* The `;` help line under the list search box (R2): one caption line, always in flow (F9, 2026-10-13 — as a focus-shown
   overlay it covered the status pills and the column headers under the box). It never toggles, so nothing jumps; on the
   phone it wraps. The input's aria-describedby text. */
.list-search-help {
    display: block;
    margin-top: 0.125rem;
    padding: 0 0.25rem;
    font-size: 0.75rem;
    line-height: 1.25rem;
    color: color-mix(in srgb, var(--g-900) 70%, transparent);
}

/* Active state feedback for touch */
@media (pointer: coarse) {
    .sidebar-shell .menu a:active,
    .sidebar-shell .menu summary:active { opacity: 0.7; }
    a.link:active { opacity: 0.7; }
}

/* HTMX loading indicators - use display instead of default opacity */
.htmx-indicator { display: none; }

.htmx-request .htmx-indicator { display: inline-flex; align-items: center; }

.htmx-request.htmx-indicator { display: block; }

/* An htmx write in flight shows on the control that sent it: globalHandlers.ts drops a repeat click on it, which without
   this looked like the click did nothing. A control with its own hx-indicator wears the spinner there instead (htmx puts
   htmx-request on the indicator, not on the control). */
.btn:is([hx-post], [hx-put], [hx-patch], [hx-delete]).htmx-request,
form:is([hx-post], [hx-put], [hx-patch], [hx-delete]).htmx-request .btn[type="submit"] { opacity: 0.7; cursor: progress; }

/* Dim a swap target while its request is in flight (point hx-indicator at it). */
.htmx-dim-on-request.htmx-request { opacity: 0.6; transition: opacity 0.2s ease; }

/* ── Global search (sidebar chrome + Ctrl+K dialog) ── */
/* Translucent input on the primary sidebar surface (design-system GlobalSearch). */
.sidebar-shell .global-search-section .global-search-input {
    background: rgb(255 255 255 / 0.1);
    border-color: rgb(255 255 255 / 0.18);
    color: rgb(255 255 255 / 0.95);
}

.sidebar-shell .global-search-section .global-search-input::placeholder {
    color: rgb(255 255 255 / 0.55);
}

.sidebar-shell .global-search-section .global-search-kbd {
    background: rgb(255 255 255 / 0.14);
    border-color: rgb(255 255 255 / 0.2);
    /* 0.75 composited to 4.12:1 against the chip's own tinted ground — below the 4.5 AA
       floor for this 12px text. 0.9 lands at ~5.2:1. */
    color: rgb(255 255 255 / 0.9);
}

/* The spinner and the shortcut chip share the input's right corner — hide the chip
   while a request is in flight. */
.global-search-box:has(.global-search-loading.htmx-request) .global-search-kbd {
    display: none;
}

.global-search-dialog::backdrop {
    background: rgb(0 0 0 / 0.4);
}

/* ── "Pick one unidade" attention hint ── */
/* A banner marked `.unidade-pick-required` blocks a write until exactly one unidade is selected. The ring on the
   unidade switcher's trigger lives with the switcher (components.css, lab 08 UNIDADE SWITCHER); its blink is this
   keyframe. */
@keyframes unidade-filter-attention {
    50% {
        outline-color: transparent;
    }
}

dialog:not([open]) {
    display: none;
}

.no-dialog dialog[open] {
    position: fixed;
    top: 1rem;
    right: 1rem;
    bottom: 1rem;
    left: 1rem;
    z-index: var(--z-dialog);
    display: grid;
    margin: auto;
    max-height: calc(100vh - 2rem);
}

/* No native <dialog>: the sheet sits centred over a scrim (DS-B: dialog.sheet replaced .modal/.modal-box). */
.no-dialog dialog.sheet[open] {
    box-shadow: 0 0 0 100vmax var(--scrim), var(--shadow-float);
    align-self: center;
    justify-self: center;
}

/* ── Sidebar collapse (desktop only) ── */
@media (min-width: 1024px) {
  /* Aside width + overflow */
  html[data-sidebar-collapsed] .sidebar-shell aside {
    width: 5rem;
    overflow: hidden;
  }

  /* Hide text labels visually but keep them in the a11y tree, so icon-only
     nav links retain an accessible name (display:none would strip it, leaving
     the CSS-only data-tip tooltip — invisible to screen readers — as the only
     text). Standard sr-only clip. */
  html[data-sidebar-collapsed] .sidebar-shell .sidebar-label {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
  }

  html[data-sidebar-collapsed] .sidebar-shell .menu-title {
    display: none;
  }

  /* Collapse submenu children, keep parent icon clickable for expand */
  html[data-sidebar-collapsed] .sidebar-shell .sidebar-submenu > ul {
    display: none;
  }
  html[data-sidebar-collapsed] .sidebar-shell .sidebar-submenu {
    pointer-events: none;
  }
  html[data-sidebar-collapsed] .sidebar-shell .sidebar-submenu > summary {
    pointer-events: auto;
    list-style: none;
    justify-content: center;
    padding-inline: 0;
  }
  html[data-sidebar-collapsed] .sidebar-shell .sidebar-submenu > summary::marker,
  html[data-sidebar-collapsed] .sidebar-shell .sidebar-submenu > summary::-webkit-details-marker {
    display: none;
  }
  html[data-sidebar-collapsed] .sidebar-shell .sidebar-submenu > summary::after {
    display: none;
  }

  /* Suppress DaisyUI tooltips when sidebar is EXPANDED */
  html:not([data-sidebar-collapsed]) .sidebar-shell .tooltip::before,
  html:not([data-sidebar-collapsed]) .sidebar-shell .tooltip::after {
    display: none !important;
  }

  /* Rotate collapse toggle chevron when collapsed */
  html[data-sidebar-collapsed] .sidebar-shell .collapse-icon {
    transform: rotate(180deg);
  }

  /* Center menu items when collapsed (icon centering) */
  html[data-sidebar-collapsed] .sidebar-shell .menu a,
  html[data-sidebar-collapsed] .sidebar-shell .menu summary {
    justify-content: center;
    padding-inline: 0;
  }

  /* Collapsed icon rail: swap the search input (and its in-place panel, which the
     5rem overflow-hidden rail would clip) for the magnifier trigger that opens the
     Ctrl+K dialog. */
  html[data-sidebar-collapsed] .sidebar-shell .global-search-box,
  html[data-sidebar-collapsed] .sidebar-shell .global-search-panel {
    display: none;
  }
  html[data-sidebar-collapsed] .sidebar-shell .global-search-collapsed-trigger {
    display: flex;
  }

  /* Center logo when collapsed */
  html[data-sidebar-collapsed] .sidebar-shell .sidebar-logo-link {
    justify-content: center;
  }

  /* Center logout button when collapsed */
  html[data-sidebar-collapsed] .sidebar-shell .sidebar-logout {
    justify-content: center;
  }

  /* Expanded desktop keeps the fold accordion (groups stay collapsed for a tidy
     rail), but the summary now navigates to the group's own page instead of
     toggling (sidebar.ts). So swap the whole-summary toggle marker for an
     explicit chevron control that owns the fold. Scoped to <nav> so the unidade
     filter keeps its native marker; excluded from the collapsed icon rail. */
  html:not([data-sidebar-collapsed]) .sidebar-shell nav .sidebar-submenu > summary {
    list-style: none;
  }
  html:not([data-sidebar-collapsed]) .sidebar-shell nav .sidebar-submenu > summary::marker,
  html:not([data-sidebar-collapsed]) .sidebar-shell nav .sidebar-submenu > summary::-webkit-details-marker,
  html:not([data-sidebar-collapsed]) .sidebar-shell nav .sidebar-submenu > summary::after {
    display: none;
  }
  html:not([data-sidebar-collapsed]) .sidebar-shell nav .sidebar-submenu > summary .submenu-chevron {
    display: inline-flex;
  }
}

/* Suppress sidebar tooltips on mobile: the drawer always shows labels, and the
   data-tip pseudo-elements add ~100px of horizontal scroll to the menu. */
@media (max-width: 1023.98px) {
  .sidebar-shell .tooltip::before,
  .sidebar-shell .tooltip::after {
    display: none !important;
  }
}

/* Mobile: the nav is a full-width dropdown hanging from the bottom of the top
   bar (matching the fixed inset-x-0 bar above it). Visibility is owned by the
   peer-checked utilities in layout.html; this only positions the open panel. */
.sidebar-shell {
    position: fixed;
    top: var(--mobile-menu-top-strip);
    inset-inline: 0;
}

/* Mobile dropdown sizes to its content but never past the viewport — it scrolls internally when
   the nav is taller than the space between the two fixed bars. M2 added a bottom nav bar (same
   z-50 tier as the top bar, so it paints over anything under it): --mobile-chrome-bottom-strip
   reserves its full height (bar + safe area) instead of just the safe area, so the drawer's last
   row (logout) ends above the bottom bar instead of being covered by it. */
.sidebar-shell > aside {
    max-height: calc(100vh - var(--mobile-menu-top-strip) - var(--mobile-chrome-bottom-strip));
    max-height: calc(100dvh - var(--mobile-menu-top-strip) - var(--mobile-chrome-bottom-strip));
    overflow-y: auto;
    overflow-x: hidden;
}

/* The aside (phone drawer) and its nav (desktop) scroll: thin bars drop Chromium's ▲▼ buttons, which sat right beside
   the unidade switcher's own chevron and scrollbar (user 2026-10-13). */
.sidebar-shell > aside,
.sidebar-shell > aside > nav {
    scrollbar-width: thin;
}

/* Mobile: the nav dropdown is flat, not an accordion. Every group renders
   fully expanded so all links are direct taps (foldable arrows are poor
   touch UX). Scoped to nav groups only — the unidade filter panel, which
   lives outside <nav>, keeps its fold. JS also force-opens these details
   and turns a parent-row tap into navigation (sidebar.ts). */
@media (max-width: 1023.98px) {
    .sidebar-shell nav .sidebar-submenu > ul {
        display: flex;
        flex-direction: column;
    }

    .sidebar-shell nav .sidebar-submenu > summary {
        list-style: none;
    }

    .sidebar-shell nav .sidebar-submenu > summary::marker,
    .sidebar-shell nav .sidebar-submenu > summary::-webkit-details-marker,
    .sidebar-shell nav .sidebar-submenu > summary::after {
        display: none;
    }
}

/* Desktop: the shell becomes a normal flex column; the aside fills the
   viewport height and sticks while content scrolls, so nav (flex-1)
   stretches and profile/logout pin to the bottom edge. */
@media (min-width: 1024px) {
    .sidebar-shell {
        position: static;
    }

    .sidebar-shell > aside {
        position: sticky;
        top: 0;
        height: 100vh;
        height: 100dvh;
        max-height: none;
        /* The mobile dropdown scrolls the whole aside; on desktop <nav> owns its
           own scroll, and the global-search results panel hangs outside the
           aside box (left-full) — any overflow clip here hides it. */
        overflow: visible;
    }
}

/* M21 on the phone (user 2026-09-24; D7 extends it to detail pages 2026-10-07): below lg a numbered section card is a
   heading, not a disclosure. `::details-content` lets CSS show a closed <details>' content; where the pseudo-element is
   unknown the card stays collapsible, so the summary is only made inert inside the @supports guard. */
@media (max-width: 1023.98px) {
    @supports selector(::details-content) {
        .form-section-card:not([open])::details-content { content-visibility: visible; }
        .form-section-card > summary.form-section-head { pointer-events: none; }
        .form-section-card:not([open]) > summary.form-section-head { margin-bottom: 1rem; border-bottom-width: 1px; padding-bottom: 0.5rem; }
        .form-section-card .form-section-chevron { display: none; }
    }
}

/* R25 (user 2026-10-07, "deveria ser fácil saber em qual estou"): DaisyUI fills an outline button on hover exactly like
   `.btn-active`, so a hovered segment or pill reads as the selected one. Hover is a tint; selected keeps the fill. */
@media (hover: hover) {
    .btn-outline:not(.btn-active):hover { background-color: color-mix(in srgb, var(--g-900) calc(0.1 * 100%), transparent); color: var(--g-900); border-color: color-mix(in srgb, var(--g-900) calc(0.4 * 100%), transparent); }
    .btn-outline.btn-primary:not(.btn-active):hover { background-color: color-mix(in srgb, var(--c-primary) calc(0.12 * 100%), transparent); color: var(--c-primary); border-color: var(--c-primary); }
    .btn-outline.btn-error:not(.btn-active):hover { background-color: color-mix(in srgb, var(--c-error) calc(0.12 * 100%), transparent); color: var(--c-error); border-color: var(--c-error); }
    .btn-outline.btn-warning:not(.btn-active):hover { background-color: color-mix(in srgb, var(--c-warning) calc(0.12 * 100%), transparent); color: var(--c-warning); border-color: var(--c-warning); }
}

/* Desktop twins of btn-primary / btn-outline (was `lg:btn-primary` / `lg:btn-outline`): a button that is outline on the phone
 * and primary from 1024 (gallery-pick, Media.kt) or primary on the phone and outline from 1024 (the empty-list create,
 * ListPage.kt). Declarations are the Tailwind variant expansion, verbatim. LAST in the file on purpose: Tailwind emitted its
 * variants after every other rule, so they beat the same-specificity rules above. COMPAT: replace with a kit state when the
 * DaisyUI port goes. */
@media (min-width: 1024px) {
  @media (hover: hover) {
    .btn-primary-lg.btn-outline:hover {
      --tw-text-opacity: 1;
      color: color-mix(in srgb, var(--c-primary-ink) calc(var(--tw-text-opacity) * 100%), transparent);
    }
  }
}
@media (min-width: 1024px) {
  @media (hover: hover) {
    @supports (color: color-mix(in oklab, black, black)) {
      .btn-primary-lg.btn-outline:hover {
        background-color: color-mix(in oklab, var(--c-primary) 90%, black);
        border-color: color-mix(in oklab, var(--c-primary) 90%, black);
      }
    }
  }
}
@media (min-width: 1024px) {
  @media (hover: hover) {
    .btn-outline-lg:hover {
      --tw-border-opacity: 1;
      border-color: color-mix(in srgb, var(--g-900) calc(var(--tw-border-opacity) * 100%), transparent);
      --tw-bg-opacity: 1;
      background-color: color-mix(in srgb, var(--g-900) calc(var(--tw-bg-opacity) * 100%), transparent);
      --tw-text-opacity: 1;
      color: color-mix(in srgb, var(--g-0) calc(var(--tw-text-opacity) * 100%), transparent);
    }
  }
}
@media (min-width: 1024px) {
  @media (hover: hover) {
    .btn-outline-lg.btn-primary:hover {
      --tw-text-opacity: 1;
      color: color-mix(in srgb, var(--c-primary-ink) calc(var(--tw-text-opacity) * 100%), transparent);
    }
  }
}
@media (min-width: 1024px) {
  @media (hover: hover) {
    @supports (color: color-mix(in oklab, black, black)) {
      .btn-outline-lg.btn-primary:hover {
        background-color: color-mix(in oklab, var(--c-primary) 90%, black);
        border-color: color-mix(in oklab, var(--c-primary) 90%, black);
      }
    }
  }
}
@media (min-width: 1024px) {
  @supports not (color: oklch(0% 0 0)) {
    .btn-primary-lg {
      --btn-color: var(--c-primary);
    }
  }
}
@media (min-width: 1024px) {
  .btn-primary-lg {
    --tw-text-opacity: 1;
    color: color-mix(in srgb, var(--c-primary-ink) calc(var(--tw-text-opacity) * 100%), transparent);
    outline-color: var(--c-primary);
  }
}
@media (min-width: 1024px) {
  @supports (color: oklch(0% 0 0)) {
    .btn-primary-lg {
      --btn-color: var(--c-primary);
    }
  }
}
@media (min-width: 1024px) {
  .btn-outline-lg {
    border-color: currentColor;
    background-color: transparent;
    --tw-text-opacity: 1;
    color: color-mix(in srgb, var(--g-900) calc(var(--tw-text-opacity) * 100%), transparent);
    --tw-shadow: 0 0 #0000;
    --tw-shadow-colored: 0 0 #0000;
    box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
  }
}
@media (min-width: 1024px) {
  .btn-outline-lg.btn-primary {
    --tw-text-opacity: 1;
    color: color-mix(in srgb, var(--c-primary) calc(var(--tw-text-opacity) * 100%), transparent);
  }
}
@media (min-width: 1024px) {
  .btn-primary-lg.btn-outline {
    --tw-text-opacity: 1;
    color: color-mix(in srgb, var(--c-primary) calc(var(--tw-text-opacity) * 100%), transparent);
  }
}
