/* =====================================================
   IMAT Quest — Ω Layout Primitives + a11y utilities
   css/primitives.css

   Intrinsic layout primitives (stack, cluster, sidebar, switcher,
   cover, auto-grid, frame) adapted from Heydon Pickering and
   Andy Bell's "Every Layout". Plus adopted a11y utilities
   (skip-link, sr-only, num, scrollable) promoted from per-page
   duplication across about-imat, courses, landing.

   Consumed by: every page's HTML + any component using
   `class="stack"`, `class="cluster"`, etc.

   Load order: AFTER tokens.css, BEFORE any component CSS.

   See docs/active/omega/RESPONSIVE-SYSTEM.md §3 (Intrinsic
   layout primitives).

   This file is populated incrementally during Phase 2 (Tasks
   2–5). Each task adds a primitive + tests.

     Task 2 — skip-link, sr-only  (this commit)
     Task 3 — stack, cluster
     Task 4 — sidebar, switcher, cover
     Task 5 — auto-grid, frame, num, scrollable, mobile-nav-visibility
   ===================================================== */

@layer primitives {
  /* ─── a11y: skip-link ────────────────────────────────
     Keyboard users press Tab first — skip-link jumps past
     repeated navigation straight to <main>. Off-screen by
     default, animates into view on :focus. Uses logical
     properties (inset-block / inset-inline) for RTL. */
  .skip-link {
    position: absolute;
    inset-block-start: calc(-1 * var(--space-2xl, 5rem));
    inset-inline-start: 0;
    background: var(--color-burgundy, #6b2838);
    color: var(--color-white, #ffffff);
    padding: var(--space-2xs, 0.5rem) var(--space-s, 1rem);
    font-family: var(--font-heading, Outfit), system-ui, sans-serif;
    font-weight: 600;
    text-decoration: none;
    z-index: 9999;
    transition: inset-block-start var(--dur-fast, 180ms)
      var(--ease-out-quart, cubic-bezier(0.25, 1, 0.5, 1));
    border-end-end-radius: 6px;
  }
  .skip-link:focus,
  .skip-link:focus-visible {
    inset-block-start: 0;
    outline: 2px solid var(--color-amber, #d99b47);
    outline-offset: 2px;
  }

  /* ─── a11y: sr-only ──────────────────────────────────
     Screen-reader-only content — visually hidden but in
     the accessibility tree. Clips to 1×1 px (not
     display:none which hides from SR). When focused (e.g.
     a "sr-only" link tabbed to), reveals. */
  .sr-only {
    position: absolute;
    inline-size: 1px;
    block-size: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
  }
  .sr-only:focus-visible {
    position: static;
    inline-size: auto;
    block-size: auto;
    margin: 0;
    overflow: visible;
    clip: auto;
    white-space: normal;
  }

  /* ─── .stack — vertical rhythm ───────────────────────
     Every-Layout "Stack". Adds top margin between sibling
     children so the stack itself owns the rhythm (no need
     for children to know about each other). Modifier
     classes select a different spacing step. */
  .stack {
    display: block;
  }
  .stack > * + * {
    margin-block-start: var(--space-s, 1rem);
  }
  .stack--2xs > * + * {
    margin-block-start: var(--space-2xs, 0.5rem);
  }
  .stack--xs > * + * {
    margin-block-start: var(--space-xs, 0.75rem);
  }
  .stack--m > * + * {
    margin-block-start: var(--space-m, 1.5rem);
  }
  .stack--l > * + * {
    margin-block-start: var(--space-l, 2rem);
  }
  .stack--xl > * + * {
    margin-block-start: var(--space-xl, 3rem);
  }
  .stack--2xl > * + * {
    margin-block-start: var(--space-2xl, 4rem);
  }

  /* ─── .cluster — horizontal wrapping group ──────────
     Every-Layout "Cluster". Flex with wrap — children
     flow in a row, wrap when they outgrow the container.
     Nav lists, tag/chip rows, inline-CTA groups. */
  .cluster {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-xs, 0.75rem);
    align-items: center;
  }
  .cluster--tight {
    gap: var(--space-2xs, 0.5rem);
  }
  .cluster--loose {
    gap: var(--space-s, 1rem);
  }

  /* ─── .sidebar — main + aside, auto-stack ────────────
     Every-Layout "Sidebar". The aside has a min-width
     (--sidebar-aside-width, default 16rem). Main takes
     the rest. When main can't be ≥50% of container, both
     stack. Replaces most viewport queries for 2-col layouts.
     Override --sidebar-aside-width to change the aside bias. */
  .sidebar {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-m, 1.5rem);
  }
  .sidebar > aside {
    flex-grow: 1;
    flex-basis: var(--sidebar-aside-width, 16rem);
  }
  .sidebar > :not(aside) {
    flex-basis: 0;
    flex-grow: 999;
    min-inline-size: 50%;
  }

  /* ─── .switcher — N columns that stack ───────────────
     Every-Layout "Switcher". N equal columns at wide,
     collapses to 1 column when container < threshold.
     Calc magic: when threshold > 100%, flex-basis becomes
     huge positive → each child takes full width. */
  .switcher {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-m, 1.5rem);
    --switcher-threshold: var(--cq-col-2, 320px);
  }
  .switcher > * {
    flex-grow: 1;
    flex-basis: calc((var(--switcher-threshold) - 100%) * 999);
  }
  .switcher--3 {
    --switcher-threshold: var(--cq-col-3, 480px);
  }
  .switcher--4 {
    --switcher-threshold: var(--cq-col-4, 640px);
  }

  /* ─── .cover — full-height centered ──────────────────
     Every-Layout "Cover" (simplified). Flex column with
     centered children. Useful for hero CTAs, loading
     states, empty states, error states. */
  .cover {
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: stretch;
    min-block-size: 100%;
    padding: var(--space-m, 1.5rem);
  }

  /* ─── .auto-grid — intrinsic grid ────────────────────
     `auto-fit` + `minmax()` creates columns that fill
     available space with a minimum column width. No media
     queries needed — grid reflows as container width
     changes. Override --auto-grid-min (default 16rem) for
     a wider/narrower card grid. */
  .auto-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--auto-grid-min, 16rem)), 1fr));
    gap: var(--space-m, 1.5rem);
  }
  .auto-grid--s {
    --auto-grid-min: 10rem;
  }
  .auto-grid--l {
    --auto-grid-min: 22rem;
  }

  /* ─── .frame — aspect-ratio media wrapper ────────────
     Reserves space via aspect-ratio so media load doesn't
     cause CLS (cumulative layout shift). Default 16/9 for
     video / hero; modifiers for 4/3, 1/1, 3/4, 21/9. */
  .frame {
    aspect-ratio: 16 / 9;
    overflow: hidden;
    position: relative;
  }
  .frame > img,
  .frame > video,
  .frame > picture,
  .frame > iframe {
    inline-size: 100%;
    block-size: 100%;
    object-fit: cover;
  }
  .frame--4-3 {
    aspect-ratio: 4 / 3;
  }
  .frame--1-1 {
    aspect-ratio: 1 / 1;
  }
  .frame--3-4 {
    aspect-ratio: 3 / 4;
  }
  .frame--21-9 {
    aspect-ratio: 21 / 9;
  }

  /* ─── .num — tabular numeric utility ─────────────────
     Brand rule: numbers always sans-serif. Use inside any
     text element (including Georgia paragraphs) to force
     Outfit/Inter/system-ui rendering with tabular alignment.
     See CLAUDE.md §Typography. */
  .num {
    font-family:
      var(--font-heading, Outfit),
      var(--font-body, Inter),
      system-ui,
      -apple-system,
      sans-serif;
    font-variant-numeric: tabular-nums;
    font-feature-settings: "tnum";
  }

  /* ─── .scrollable — horizontal overflow wrapper ──────
     For tables / wide data / long chip rows that must not
     blow out narrow viewports. Adds native scrollbar with
     momentum scrolling on iOS. */
  .scrollable {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: thin;
  }

  /* ─── .mobile-nav visibility pattern ─────────────────
     Adopted from courses/css/courses.css §A5. When the
     mobile nav is transform-hidden (off-screen slide), its
     links remain focusable — axe flags aria-hidden-focus.
     Adding visibility: hidden makes them keyboard-inert.
     Pair with aria-hidden="true"/"false" toggled in JS. */
  .mobile-nav:not(.is-open) {
    visibility: hidden;
  }
  .mobile-nav.is-open {
    visibility: visible;
  }
}
