/* ==========================================================================
   responsive.css — system-wide responsive hardening layer
   --------------------------------------------------------------------------
   Loaded LAST in base.html, after ui-fixes.css.

   This file deliberately does NOT restyle anything. It closes the structural
   gaps that make an otherwise-responsive layout break on small screens:
   overflow blowouts, unbreakable strings, oversized media, iOS zoom, and
   touch-target size.

   Almost every rule is wrapped in :where(), which has ZERO specificity, so
   any existing rule in app.css / components-extra.css / ui-fixes.css still
   wins. That makes this layer safe to load last without visual regressions.

   Breakpoints follow the ones the shell already uses:
     1024px - sidebar collapses to off-canvas drawer
      768px - mobile layout
      480px - small phone
   ========================================================================== */


/* --------------------------------------------------------------------------
   1. Page-level horizontal overflow guard
   --------------------------------------------------------------------------
   `overflow-x: clip` is used instead of `hidden` on purpose. `hidden` turns
   the element into a scroll container, which breaks `position: sticky` on
   .topbar and on the sticky table headers in the heatmap / data tables.
   `clip` does not create a scroll container, so sticky keeps working.
   Guarded by @supports so older browsers keep today's behaviour rather than
   silently losing sticky headers.
   -------------------------------------------------------------------------- */
@supports (overflow: clip) {
  html,
  body {
    overflow-x: clip;
  }
}

/* Belt-and-braces: nothing should be able to make the shell wider than the
   viewport in the first place. */
:where(.app-shell, .main-area, .content-area) {
  max-width: 100%;
}


/* --------------------------------------------------------------------------
   2. Grid / flex blowout guard
   --------------------------------------------------------------------------
   A grid or flex item defaults to `min-width: auto`, meaning it refuses to
   shrink below its content. One long email address, file path, URL or wide
   table is enough to push a whole track past the viewport edge — this is the
   single most common cause of horizontal scroll in this codebase.

   The project names its layout containers consistently (*-grid, *-row,
   *-shell, *-layout, *-strip, *-bar, *-inner), so they can be targeted
   generically instead of listing ~60 individual class names.
   -------------------------------------------------------------------------- */
:where(
  [class*="-grid"],
  [class*="-row"],
  [class*="-shell"],
  [class*="-layout"],
  [class*="-strip"],
  [class*="-bar"],
  [class*="-inner"],
  [class*="-cockpit"],
  [class*="-kpis"]
) > * {
  min-width: 0;
}

/* Flex children that hold text need the same treatment so they can ellipsize
   instead of pushing their parent wider. */
:where(.panel, .card, .stat-card, .nav-item, .sidebar-user, .company-chip) {
  min-width: 0;
}


/* --------------------------------------------------------------------------
   3. Media never overflows its container
   -------------------------------------------------------------------------- */
:where(img, svg, video, canvas, iframe, embed, object) {
  max-width: 100%;
}

/* Only raster/embedded media gets height:auto. SVG is deliberately excluded:
   Lucide icons carry explicit width/height attributes and must keep them. */
:where(img, video) {
  height: auto;
}


/* --------------------------------------------------------------------------
   4. Long unbreakable strings
   --------------------------------------------------------------------------
   Emails, URLs, file names, API keys and Nepali/Devanagari compound strings
   have no natural break point. Allow them to wrap rather than blow out the
   column. `overflow-wrap` only breaks when there is no other option, so
   normal prose is unaffected.
   -------------------------------------------------------------------------- */
:where(td, th, p, li, dd, h1, h2, h3, h4, h5, h6, .muted, .eyebrow) {
  overflow-wrap: break-word;
}

/* Code, keys and paths get the more aggressive break. */
:where(code, kbd, samp, .mono, .cred-value, .api-key) {
  overflow-wrap: anywhere;
}

/* Preformatted blocks scroll rather than stretch the page. */
:where(pre) {
  max-width: 100%;
  overflow-x: auto;
}


/* --------------------------------------------------------------------------
   5. Tables
   --------------------------------------------------------------------------
   Wide data tables live inside a scroll container (.table-scroll,
   .archive-table-wrap, .perm-matrix-wrap, .heatmap-scroll-wrap, .npt-table-wrap,
   .gantt-scroll). Give every one of them momentum scrolling on iOS and a
   contained overscroll so swiping a table does not bounce the whole page.
   -------------------------------------------------------------------------- */
/* Real class selectors (0,1,0) here, not :where() — these must actually beat
   the existing wrapper rules, which they do on source order. */
.table-scroll,
.archive-table-wrap,
.perm-matrix-wrap,
.heatmap-scroll-wrap,
.npt-table-wrap,
.gantt-scroll {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior-x: contain;
  max-width: 100%;
}

/* Any table that somehow escaped a wrapper still cannot exceed its parent. */
:where(table) {
  max-width: 100%;
}


/* --------------------------------------------------------------------------
   6. Full-height panes on mobile browsers
   --------------------------------------------------------------------------
   100vh ignores the mobile URL bar, so full-height panes get clipped and the
   page gains a phantom scroll. dvh tracks the visible viewport instead.
   -------------------------------------------------------------------------- */
@supports (height: 100dvh) {
  /* Must override .app-shell{min-height:100vh} in app.css — same specificity,
     wins on source order. */
  .app-shell,
  .main-area {
    min-height: 100dvh;
  }

  .sidebar,
  .sidebar-overlay {
    height: 100dvh;
  }
}


/* ==========================================================================
   TABLET  —  <= 1024px  (sidebar is now an off-canvas drawer)
   ========================================================================== */
@media (max-width: 1024px) {

  /* The drawer must scroll internally on short screens, and must never be
     wider than the phone it is on. */
  .sidebar {
    width: min(268px, 86vw);
    max-width: 86vw;
    overflow-y: auto;
    overscroll-behavior: contain;
  }

  /* Lock background scroll while the drawer is open, so swiping the overlay
     does not scroll the page behind it. */
  body:has(.sidebar.open) {
    overflow: hidden;
  }
}


/* ==========================================================================
   MOBILE  —  <= 768px
   ========================================================================== */
@media (max-width: 768px) {

  /* ---- iOS zoom prevention --------------------------------------------
     Safari on iOS zooms the viewport whenever a focused input has a computed
     font-size below 16px. Several forms in this system use 12-14px inputs,
     which makes every tap jump the layout. 16px is the minimum that prevents
     it. Applied only to text-entry controls, and only on mobile, so desktop
     density is untouched.

     !important is required here, not stylistic: this system styles inputs at
     8-12px through dozens of different selectors (.app-form input,
     .filter-input, .date-filter input, .checkin-action select, ...), many with
     higher specificity than anything reasonable here, and some load after this
     file via the extra_head block. Scoped to <=768px only. */
  input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]):not([type="file"]),
  select,
  textarea {
    font-size: 16px !important;
  }

  /* ---- Touch targets ---------------------------------------------------
     WCAG 2.2 AA (2.5.8 Target Size, Minimum) asks for 24px; 44px is the
     platform convention and the project target. min-height is used rather
     than height so existing padding still governs appearance, and min-height
     beats a smaller fixed height in the box model. */
  .btn,
  .icon-btn,
  .menu-btn,
  .nav-item,
  .tab,
  .chip-btn,
  .pill-btn {
    min-height: 44px;
  }

  .icon-btn,
  .menu-btn {
    min-width: 44px;
  }

  /* ---- Edge-to-edge scrollers -----------------------------------------
     Let wide tables use the full screen width instead of being boxed in by
     the content padding, so there is more to see before scrolling. */
  :where(.table-scroll, .archive-table-wrap, .heatmap-scroll-wrap) {
    margin-inline: -14px;
    padding-inline: 14px;
  }

  /* ---- Page header ----------------------------------------------------
     Action buttons wrap onto their own line rather than squeezing the title. */
  :where(.page-header) {
    gap: 12px;
  }

  :where(.header-actions) {
    flex-wrap: wrap;
  }

  /* ---- Modals / dialogs -----------------------------------------------
     Anything positioned as a floating panel must stay inside the viewport. */
  :where(.modal, .modal-card, .dialog, .popover, .dropdown-menu, .sheet) {
    max-width: calc(100vw - 24px);
    max-height: calc(100dvh - 24px);
    overflow-y: auto;
    overscroll-behavior: contain;
  }
}


/* ==========================================================================
   SMALL PHONE  —  <= 480px
   ========================================================================== */
@media (max-width: 480px) {

  /* Collapse remaining multi-column grids to a single column. These use real
     class selectors because they must override the 2-column values set at the
     768px/1024px breakpoints in app.css; equal specificity, later source. */
  .stat-grid,
  .employee-grid,
  .attendance-metrics,
  .profile-kpis,
  .metric-row,
  [class*="-kpi-grid"],
  [class*="-card-grid"] {
    grid-template-columns: 1fr;
  }

  /* Toolbars become full-width stacks so buttons stay tappable. */
  .header-actions .btn,
  .filters > *,
  .resource-filters > * {
    flex: 1 1 100%;
  }
}


/* ==========================================================================
   ACCESSIBILITY
   ========================================================================== */

/* Visible keyboard focus, app-wide.
   :focus-visible only fires for keyboard/AT navigation, so this adds a clear
   indicator for keyboard users without putting a ring around every mouse
   click. Zero specificity via :where() means any page that already defines
   its own focus treatment still wins. */
:where(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
  outline: 2px solid var(--purple, #5b5bd6);
  outline-offset: 2px;
}

/* The dark sidebar needs a light ring to stay visible against its background. */
:where(.sidebar, .notif-drawer) :where(a, button, input, [tabindex]):focus-visible {
  outline-color: #fff;
}

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


/* ==========================================================================
   SCREEN-READER-ONLY UTILITY
   --------------------------------------------------------------------------
   .sr-only was already in use (tasks.html, dashboard.html) but had never been
   defined, so that text rendered visibly. Standard clip pattern: removed from
   view, still announced, and still focusable if it ever wraps a control.
   ========================================================================== */
.sr-only {
  position: absolute !important;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}
.sr-only-focusable:focus,
.sr-only-focusable:focus-visible {
  position: static !important;
  width: auto;
  height: auto;
  margin: 0;
  overflow: visible;
  clip: auto;
  clip-path: none;
  white-space: normal;
}


/* ==========================================================================
   THE hidden ATTRIBUTE MUST ACTUALLY HIDE
   --------------------------------------------------------------------------
   The UA rule is `[hidden]{display:none}` at specificity 0,0,0, so ANY class
   rule that sets a display beats it. Several components did exactly that:

     .tm-overlay      ui-fixes.css   position:fixed; inset:0; z-index:10200;
                                     opacity:0  -> an invisible full-viewport
                                     sheet that swallowed every click on the
                                     project detail page
     .chat-typing-bar, .chat-reply-preview, .chat-tools-panel,
     .attachment-preview, .chat-member-panel                -> stayed visible

   All the JS toggles these through the `.hidden` property, so honouring the
   attribute is what every call site already assumes. !important is required
   because {% block extra_head %} loads page CSS after this file.

   `until-found` is excluded: that value is meant to stay laid out so find-in-
   page can reveal it.
   ========================================================================== */
[hidden]:not([hidden="until-found"]) {
  display: none !important;
}
