/* Wrapped in @layer m3e — the layer order is declared as the first style in
   base.html: @layer properties, theme, base, m3e, components, utilities.
   This makes Tailwind utilities (@layer utilities) win over M3E component
   rules at equal specificity, which is the intended semantics. */
@layer m3e {
/* ═══════════════════════════════════════════════════════════════════════════
 * M3E Layout Tokens & Grid System
 * Reference: docs/m3e/guidelines/layout.md
 *
 * Breakpoints: compact(<600px) / medium(600-840px) / expanded(840-1200px)
 *              / large(≥1200px)
 * Grid: 4→8→12→12 columns with responsive margins and gutters
 * Spacing: 4px base scale (10 tokens)
 * Density: 3 touch target sizes
 * ═══════════════════════════════════════════════════════════════════════════ */

:root {
  /* ── Spacing scale (4px base) ── */
  --md-sys-spacing-1: 4px;
  --md-sys-spacing-2: 8px;
  --md-sys-spacing-3: 12px;
  --md-sys-spacing-4: 16px;
  --md-sys-spacing-5: 20px;
  --md-sys-spacing-6: 24px;
  --md-sys-spacing-8: 32px;
  --md-sys-spacing-10: 40px;
  --md-sys-spacing-12: 48px;
  --md-sys-spacing-16: 64px;

  /* ── Density touch targets ── */
  --md-sys-density-touch-target-default: 48px;
  --md-sys-density-touch-target-comfortable: 40px;
  --md-sys-density-touch-target-compact: 36px;

  /* ── Shell chrome heights ──
   * --shell-top-bar-height is defined in components.css alongside the bar
   * itself. --m3e-bottom-nav-height is the mobile tab bar; every sticky header
   * and every page that must clear the bar reads these tokens rather than
   * hard-coding 64/80px. */
  --m3e-bottom-nav-height: 80px;

  /* ── The page column (A2 · Decision 1 · D1 System 1, D6-20, D3-59) ──
   *
   * Seven content widths shipped before this: 448 / 576 / 768 / 913 / 1024 /
   * 1152 / 1382, decided one template at a time, and sibling pages in the same
   * chip row disagreed. The column is now a token the SHELL applies, once, to
   * `#page-content`; no page sets its own.
   *
   *   --page-width   the working column. 1120px on member/public (no drawer,
   *                  so the shell would otherwise hand a 1,222px line to a
   *                  reading surface), 1280px on committee/auditor (a drawer
   *                  already takes 240px and the tables need the room).
   *   --measure-prose  45–75 characters is the readable band; 68ch is the
   *                  middle of it. Applied to p/li/subtitles/helper text from
   *                  the shell — the member surface measured 147 characters a
   *                  line before this and the app-wide median was 98.
   *   --measure-doc  statutory documents (notice, minutes, waiver, policy) on
   *                  the --paper surface.
   *   --paper        a document is a depiction of paper: white in BOTH themes
   *                  with dark ink, so the club's statutory record does not go
   *                  charcoal in dark mode while its scanned signature stays a
   *                  bright white rectangle (D3-65).
   */
  --page-width: 1120px;
  --measure-prose: 68ch;
  --measure-doc: 68ch;
  --paper: #ffffff;
  --paper-on: #16181c;
  --paper-border: rgb(0 0 0 / 0.14);
}

[data-portal-surface="committee"],
[data-portal-surface="auditor"] {
  --page-width: 1280px;
}

/* The shell content column. One rule, every surface, every page.
 *
 * It sits on `#page-content` (base.html) rather than on the padded wrapper so
 * the gutter stays flush to the viewport while the column centres inside it,
 * and so an htmx `innerHTML` swap can never replace it. */
#page-content {
  max-width: var(--page-width);
  margin-inline: auto;
}
/* Full-bleed is an explicit opt-in, for registers and ledgers that are wider
 * than any reading column and would otherwise scroll sideways inside a
 * narrower one. Put `npsc-full-bleed` on the page's own outermost element. */
#page-content:has(> .npsc-full-bleed),
#page-content:has(> * > .npsc-full-bleed) {
  max-width: none;
}

/* ── The prose measure ──
 * `p` and `li` inside the page, plus anything that opts in with `npsc-prose`
 * (subtitles, helper text, empty-state copy that is not a <p>).
 * These rules are `@layer m3e`, so an explicit `max-w-*` utility on a template
 * still wins — a page that genuinely needs a wider line says so. */
#page-content p,
#page-content li,
.npsc-prose,
.m3e-page-header__subtitle,
.m3e-empty-state__description {
  max-width: var(--measure-prose);
}
/* Not prose: a cell, a nav item, a tab, a chip row, a definition value, and
 * anything explicitly excused. Specificity has to clear `#page-content p`. */
#page-content td p,
#page-content th p,
#page-content td li,
#page-content th li,
#page-content nav li,
#page-content nav p,
#page-content [role="tablist"] li,
#page-content .m3e-tabs li,
#page-content .m3e-chip p,
#page-content .npsc-measure-none,
#page-content .npsc-measure-none p,
#page-content .npsc-measure-none li,
#page-content .npsc-full-bleed td p,
#page-content .npsc-full-bleed th p {
  max-width: none;
}

/* ── The paper surface (statutory documents) ──
 * White in both themes, one reading measure, generous margin, and a real
 * border rather than a card. `color-scheme: light` is what keeps native
 * scrollbars and form controls inside it light too. */
.npsc-paper {
  color-scheme: light;
  /* The ink tokens are REDEFINED on the paper, not merely overridden by a
     `color` declaration. Every descendant in these documents carries a
     Tailwind `text-[var(--fg1)]` / `text-[var(--fg2)]` / `border-[var(--border)]`
     utility, and a utility beats anything in `@layer m3e` whatever its
     specificity (the cascade-layer trap). A custom property set on the element
     itself is not in that fight: `var(--fg1)` inside the paper simply resolves
     to the paper's own ink, in both themes, wherever it is read from. */
  --fg1: #16181c;
  --fg2: #44474e;
  --border: rgb(0 0 0 / 0.14);
  --border-bold: rgb(0 0 0 / 0.34);
  --surface-0: #ffffff;
  --surface-1: #ffffff;
  --surface-2: #f4f4f7;
  --surface-3: #ececef;
  --brand: #415f91;
  background: var(--paper);
  color: var(--paper-on);
  border: 1px solid var(--paper-border);
  border-radius: var(--radius-lg, 16px);
  padding: 40px clamp(20px, 5vw, 56px);
  max-width: calc(var(--measure-doc) + 2 * clamp(20px, 5vw, 56px));
  margin-inline: auto;
}
.npsc-paper > * { max-width: var(--measure-doc); }
/* Every descendant takes the paper's ink, including the ones that would
 * otherwise read a theme token and go pale-on-white in dark mode. */
.npsc-paper :where(h1, h2, h3, h4, h5, h6, p, li, dt, dd, td, th, strong, em, span, div, a) {
  color: inherit;
}
.npsc-paper a { text-decoration: underline; }
/* The one place the house allows a serif in body copy: a statutory document
 * set in the display face reads as the record it is. Opt in per document. */
.npsc-paper--serif :where(p, li, dd) {
  font-family: var(--font-display, Georgia, "Times New Roman", serif);
  font-size: 17px;
  line-height: 1.65;
}
@media print {
  .npsc-paper { border: 0; padding: 0; max-width: none; }
}

/* A11Y-TOUCH-01: 36px is a pointer-precision density, correct only where a fine pointer is
 * guaranteed. Below the 840px breakpoint used everywhere else in the shell (see layout.md /
 * UX-NAV-01) touch is the primary input, so bump the compact token to the 44px WCAG 2.5.5/2.5.8
 * minimum. The ≥840px, 36px value stands as a documented desktop-density exception — this
 * viewport is treated as pointer-capable and is not required to hit 44px. Every consumer of
 * the token (currently `.m3e-button--sm`) inherits the fix automatically. */
@media (max-width: 839px) {
  :root {
    --md-sys-density-touch-target-compact: 44px;
  }
}


/* ═══════════════════════════════════════════════════════════════════════════
 * Platform floors below the 840px chrome boundary (r4 · A6-06, A6-10, A2-07)
 *
 * These use !important deliberately. Since r4 the M3E stylesheets live in
 * `@layer m3e`, below `@layer utilities`, so a plain declaration here loses to
 * any `text-sm` / `pb-0` a template happens to carry. Important declarations
 * reverse the layer order, which is exactly the semantics wanted: these are
 * floors the utilities are not allowed to undercut, not defaults.
 * ═══════════════════════════════════════════════════════════════════════════ */

@media (max-width: 839px), (pointer: coarse) {
  /* MN-06: and on any coarse pointer — a phone in landscape is 844-932px wide.
     A6-06: iOS zooms the viewport when a focused control is under 16px, and
     the member has to pinch back out after every field. 16px is the floor on
     every touch-primary viewport. Tom Select renders its own control and its
     own inner input, so both are named. */
  input:not([type="hidden"]):not([type="checkbox"]):not([type="radio"]),
  select,
  textarea,
  .ts-control,
  .ts-control input {
    font-size: 16px !important;
  }
}

/* A2-07 / A6-10: the bottom tab bar is visible until 840px, but pages keyed
   their clearance to Tailwind's `md:` (768px), leaving a 72px band where the
   last action on the page sits under the bar. Reserve the clearance once, on
   the shell, for every authenticated surface. Pages must not re-add their own.
   `.m3e-shell__content--has-bottom-nav` already does this for the main region;
   this covers pages that scroll their own inner container. */
@media (max-width: 839px) {
  .m3e-bottom-nav-clearance {
    padding-bottom: calc(var(--m3e-bottom-nav-height) + env(safe-area-inset-bottom, 0px) + var(--md-sys-spacing-4));
  }
}

/* Sticky headers inside the page must clear the fixed top app bar. Anything
   pinned with `sticky top-0` disappears under it (A2-06). This is the one
   correct offset — use it instead of a literal. */
.m3e-sticky-below-top-bar {
  position: sticky;
  top: calc(var(--shell-top-bar-height) + env(safe-area-inset-top, 0px));
  z-index: var(--z-sticky);
}


/* ── Responsive Grid ── */

.m3e-grid {
  display: grid;
  gap: var(--md-sys-spacing-2);              /* 8px gutter */
  padding-inline: var(--md-sys-spacing-4);   /* 16px margin */
  grid-template-columns: repeat(4, 1fr);     /* 4 columns */
}

/* Medium: 600px+ */
@media (min-width: 600px) {
  .m3e-grid {
    gap: var(--md-sys-spacing-4);            /* 16px gutter */
    padding-inline: var(--md-sys-spacing-6); /* 24px margin */
    grid-template-columns: repeat(8, 1fr);   /* 8 columns */
  }
}

/* Expanded: 840px+ */
@media (min-width: 840px) {
  .m3e-grid {
    gap: var(--md-sys-spacing-6);            /* 24px gutter */
    padding-inline: var(--md-sys-spacing-6); /* 24px margin */
    grid-template-columns: repeat(12, 1fr);  /* 12 columns */
  }
}

/* Large: 1200px+ */
@media (min-width: 1200px) {
  .m3e-grid {
    max-width: 1200px;
    margin-inline: auto;
  }
}


/* ── Spacing utility classes ── */

.m3e-gap-1 { gap: var(--md-sys-spacing-1); }
.m3e-gap-2 { gap: var(--md-sys-spacing-2); }
.m3e-gap-3 { gap: var(--md-sys-spacing-3); }
.m3e-gap-4 { gap: var(--md-sys-spacing-4); }
.m3e-gap-5 { gap: var(--md-sys-spacing-5); }
.m3e-gap-6 { gap: var(--md-sys-spacing-6); }
.m3e-gap-8 { gap: var(--md-sys-spacing-8); }

.m3e-p-1 { padding: var(--md-sys-spacing-1); }
.m3e-p-2 { padding: var(--md-sys-spacing-2); }
.m3e-p-3 { padding: var(--md-sys-spacing-3); }
.m3e-p-4 { padding: var(--md-sys-spacing-4); }
.m3e-p-5 { padding: var(--md-sys-spacing-5); }
.m3e-p-6 { padding: var(--md-sys-spacing-6); }
.m3e-p-8 { padding: var(--md-sys-spacing-8); }
}
