/* ==========================================================================
   layout.css , THE SCAFFOLD. The structure every page hangs off.
   ==========================================================================
   NO HEX VALUES IN THIS FILE. See tokens.css.

   ==========================================================================
   THE BREAKPOINT SYSTEM , 3 named steps, mobile-first
   ==========================================================================
   v1 had ONE media query (max-width:768px). Everything from 769px to 4K got
   an identical layout, and below 768px every grid slammed to a single column
   with no intermediate step. Desktop, cliff, phone.

       MOBILE    base, no query      < 640px    single column, offcanvas drawer
       TABLET    >= 640px            640-1023   2-up grids, offcanvas drawer
       DESKTOP   >= 1024px           >= 1024    PERSISTENT sidebar, 3-4up grids

   All queries are min-width (mobile-first). We never write max-width except
   for the two genuine "only on small screens" cases, which are commented.

   ==========================================================================
   THE SHELL , CSS Grid, and the drawer is the interesting part
   ==========================================================================
   On mobile the drawer is a fixed-position offcanvas panel over the content.
   On desktop it stops being an overlay entirely and becomes a real grid
   column. Same markup, same component, completely different behaviour, zero
   JavaScript involved in the transition.

   That is the difference between "responsive" and "shrunk".
   ========================================================================== */

@layer layout {

  /* ------------------------------------------------------------------------
     APP SHELL
     ------------------------------------------------------------------------ */
  .app {
    display: grid;
    grid-template-areas:
      "topbar"
      "main";
    grid-template-rows: var(--topbar-h) 1fr;
    grid-template-columns: 100%;
    min-block-size: 100svh;
    /* Belt and braces against the horizontal-scroll bug class. */
    overflow-x: clip;
  }

  .topbar { grid-area: topbar; }
  .main   { grid-area: main; }
  /* .drawer is NOT in the grid on mobile , it is fixed/overlay. See below. */


  /* ------------------------------------------------------------------------
     TOPBAR , sticky, 56px, thumb-reachable controls at both ends
     ------------------------------------------------------------------------ */
  .topbar {
    position: sticky;
    inset-block-start: 0;
    z-index: var(--z-sticky);

    display: flex;
    align-items: center;
    gap: var(--sp-3);
    padding-inline: var(--sp-3);
    block-size: var(--topbar-h);

    background-color: var(--color-chrome);
    border-block-end: var(--bw-hair) solid var(--color-border);
  }

  .topbar__start,
  .topbar__end {
    display: flex;
    align-items: center;
    gap: var(--sp-2);
  }

  /* The brand sits centred on mobile (between two equal-weight control
     clusters) and slides left on desktop where the sidebar owns identity. */
  .topbar__brand {
    flex: 1;
    display: flex;
    justify-content: center;
    min-inline-size: 0;          /* allows the label to truncate, not overflow */
  }

  @media (min-width: 1024px) {
    .topbar {
      padding-inline: var(--sp-5);
    }
    .topbar__brand {
      flex: 0 1 auto;
      justify-content: flex-start;
    }
    .topbar__spacer { flex: 1; }
  }


  /* ------------------------------------------------------------------------
     DRAWER , offcanvas below 1024, persistent sidebar at and above it
     ------------------------------------------------------------------------ */
  .drawer {
    /* --- MOBILE / TABLET: fixed overlay panel, off to the left --- */
    position: fixed;
    inset-block: 0;
    inset-inline-start: 0;
    z-index: var(--z-drawer);

    inline-size: min(var(--drawer-w), 86vw);   /* never eat the whole screen */
    max-inline-size: 100%;

    display: flex;
    flex-direction: column;

    background-color: var(--color-chrome);
    border-inline-end: var(--bw-hair) solid var(--color-border);

    /* Hidden by translation, not display:none, so the slide can animate and
       so the contents stay in the DOM for assistive tech to announce. */
    transform: translateX(-100%);
    transition: transform var(--dur-base) var(--ease-out);

    /* Contents scroll inside the drawer; the page behind never does. */
    overflow-y: auto;
    overscroll-behavior: contain;    /* stops scroll chaining to the body */
  }

  .drawer[data-open="true"] {
    transform: translateX(0);
  }

  /* Do not let a closed offcanvas drawer be reachable by keyboard. Paired
     with inert/aria-hidden in JS, this is the belt-and-braces version. */
  .drawer:not([data-open="true"]) {
    visibility: hidden;
    transition: transform var(--dur-base) var(--ease-out),
                visibility 0s linear var(--dur-base);
  }
  .drawer[data-open="true"] {
    visibility: visible;
    transition: transform var(--dur-base) var(--ease-out),
                visibility 0s;
  }

  .drawer__header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--sp-3);
    padding: var(--sp-4);
    block-size: var(--topbar-h);
    border-block-end: var(--bw-hair) solid var(--color-border);
    flex: none;
  }

  .drawer__body {
    flex: 1;
    padding: var(--sp-3) 0;
    min-block-size: 0;
  }

  .drawer__footer {
    flex: none;
    padding: var(--sp-4);
    border-block-start: var(--bw-hair) solid var(--color-border);
    /* Clears the iOS home indicator. */
    padding-block-end: max(var(--sp-4), env(safe-area-inset-bottom));
  }

  /* --- DESKTOP: the drawer joins the grid and stops being an overlay --- */
  @media (min-width: 1024px) {
    .app {
      grid-template-areas:
        "topbar topbar"
        "drawer main";
      grid-template-columns: var(--drawer-w) 1fr;
      grid-template-rows: var(--topbar-h) 1fr;
    }

    .drawer {
      grid-area: drawer;
      position: sticky;
      inset-block-start: var(--topbar-h);
      block-size: calc(100svh - var(--topbar-h));
      inline-size: auto;

      /* Cancel every piece of the offcanvas behaviour. */
      transform: none;
      visibility: visible;
      transition: none;
      z-index: var(--z-base);
    }

    /* The drawer's own header is redundant when it is a permanent sidebar,
       and the scrim and the hamburger have nothing to do. */
    .drawer__header,
    .scrim,
    .drawer-toggle {
      display: none;
    }
  }


  /* ------------------------------------------------------------------------
     SCRIM , the dimmed backdrop behind the open offcanvas drawer
     ------------------------------------------------------------------------ */
  .scrim {
    position: fixed;
    inset: 0;
    z-index: var(--z-overlay);
    background-color: var(--scrim);
    opacity: 0;
    pointer-events: none;
    transition: opacity var(--dur-base) var(--ease-out);
  }
  .scrim[data-open="true"] {
    opacity: 1;
    pointer-events: auto;
  }
  /* The scrim must sit BELOW the drawer it dims. */
  .drawer { z-index: calc(var(--z-overlay) + 1); }
  @media (min-width: 1024px) { .drawer { z-index: var(--z-base); } }


  /* ------------------------------------------------------------------------
     MAIN + CONTAINER
     ------------------------------------------------------------------------ */
  .main {
    min-inline-size: 0;          /* THE grid-blowout fix. Without this, a wide
                                    table or <pre> forces the whole page to
                                    scroll horizontally. */
    padding-block-end: var(--sp-8);
  }

  .container {
    inline-size: 100%;
    max-inline-size: var(--content-max);
    margin-inline: auto;
    padding-inline: var(--sp-4);
  }
  @media (min-width: 640px) {
    .container { padding-inline: var(--sp-5); }
  }
  @media (min-width: 1024px) {
    .container { padding-inline: var(--sp-6); }
  }


  /* ------------------------------------------------------------------------
     SECTION RHYTHM , vertical spacing comes from here, not from components
     ------------------------------------------------------------------------ */
  .section {
    padding-block-start: var(--sp-6);
  }
  .section__head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--sp-3);
    flex-wrap: wrap;
    margin-block-end: var(--sp-4);
  }
  .section__title {
    font-size: var(--fs-5);
    font-family: var(--font-mono);
    font-weight: var(--fw-bold);
    color: var(--color-text);
  }
  .section__meta {
    font-size: var(--fs-1);
    color: var(--color-text-dim);
    font-family: var(--font-mono);
  }


  /* ------------------------------------------------------------------------
     GRIDS , intrinsically responsive, no media query needed
     ------------------------------------------------------------------------
     auto-fit + minmax means the browser decides the column count from the
     available space. One rule covers phone, tablet, desktop and ultrawide,
     and it never produces the awkward "2 columns with one orphan stretched
     across the bottom" that fixed column counts do.

     min() guards the minmax floor so a 320px phone never gets a track wider
     than its own viewport, which is the classic auto-fit overflow bug.
     ------------------------------------------------------------------------ */
  .grid {
    display: grid;
    gap: var(--sp-4);
  }

  .grid--stats    { grid-template-columns: repeat(auto-fit, minmax(min(100%, 190px), 1fr)); }
  .grid--services { grid-template-columns: repeat(auto-fill, minmax(min(100%, 260px), 1fr)); }
  .grid--wide     { grid-template-columns: repeat(auto-fit, minmax(min(100%, 380px), 1fr)); }

  /* Explicit 2-up that collapses. Used where auto-fit is wrong because the
     two children are a semantic pair, not a list. */
  .grid--pair { grid-template-columns: 1fr; }
  @media (min-width: 640px) {
    .grid--pair { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  }


  /* ------------------------------------------------------------------------
     STACK / CLUSTER , the two layout primitives that remove 90% of one-off
     margin declarations. v1 had 42 distinct padding values largely because
     it lacked these.
     ------------------------------------------------------------------------ */
  .stack       { display: flex; flex-direction: column; gap: var(--sp-4); }
  .stack--tight{ gap: var(--sp-2); }
  .stack--loose{ gap: var(--sp-6); }

  .cluster {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--sp-2);
  }
  .cluster--between { justify-content: space-between; }
  .cluster--end     { justify-content: flex-end; }


  /* ------------------------------------------------------------------------
     SCROLLER , horizontal snap rail (the mobile stats row)
     ------------------------------------------------------------------------
     On phones the 4 system stats become a swipeable rail with snap points
     instead of a 4-high stack that pushes everything else below the fold.
     Above 640px it reverts to a normal grid.
     ------------------------------------------------------------------------ */
  @media (max-width: 639px) {           /* genuine small-screen-only case */
    .scroller {
      display: grid;
      grid-auto-flow: column;
      grid-auto-columns: 78%;           /* peek the next card, signals "swipe" */
      gap: var(--sp-3);
      overflow-x: auto;
      overscroll-behavior-inline: contain;
      scroll-snap-type: x mandatory;
      scroll-padding-inline: var(--sp-4);
      /* Bleed to the viewport edges so cards can sit flush while the page
         keeps its gutter. */
      margin-inline: calc(var(--sp-4) * -1);
      padding-inline: var(--sp-4);
      padding-block-end: var(--sp-2);
      scrollbar-width: none;
    }
    .scroller::-webkit-scrollbar { display: none; }
    .scroller > * { scroll-snap-align: start; }
  }
}
