/* NoWP — the entire client-side runtime.
   No JavaScript is served with this site, so everything interactive here is
   CSS: the responsive grid, the sticky header, focus states, dark mode. */

:root {
  --ink: #16181d;
  /* Secondary text: FAQ answers, standfirsts, card copy, captions. 7.8:1 on
     the paper — dark enough to read as text rather than as a caption, while
     staying clearly a step below --ink at 17.2:1. */
  --ink-soft: #4a505c;
  /* Same paper as the homepage sections, so the header and footer sit on one
     continuous background rather than a white strip against #fbfbfa. */
  --bg: #fbfbfa;
  --bg-soft: #f2f2f0;
  --line: #e2e5ea;
  /* One accent for the whole site. 5.65:1 on the paper below; #1f6feb, the
     obvious brighter blue, only manages 4.48 and fails AA. */
  --accent: #1a5fd0;
  --accent-ink: #ffffff;
  --radius: 10px;
  /* 82.5rem = the 1320px container the homepage was designed against. The
     header and footer share it so their edges line up with the page content. */
  --wrap: 82.5rem;
  --measure: 38rem;
  --font: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Arial, sans-serif;
  --font-mono: ui-monospace, SFMono-Regular, "Cascadia Mono", Consolas, monospace;
}

/* Light only, matching the live site. The dark hero band and the security
   panel are dark by design, not by scheme — every other section is --bg.
   `color-scheme: light` keeps form controls and scrollbars light too, so a
   visitor with a dark OS theme doesn't get dark widgets on a light page. */
:root { color-scheme: light; }

*, *::before, *::after { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font);
  font-size: 1.0625rem;
  line-height: 1.65;
  -webkit-text-size-adjust: 100%;
}

.wrap {
  width: 100%;
  max-width: var(--wrap);
  margin-inline: auto;
  padding-inline: 1.25rem;
}

img { max-width: 100%; height: auto; }

a { color: var(--accent); text-underline-offset: 0.15em; }
a:hover { text-decoration-thickness: 2px; }

:focus-visible {
  outline: 3px solid var(--accent);
  outline-offset: 2px;
  border-radius: 3px;
}

.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  background: var(--accent);
  color: var(--accent-ink);
  padding: 0.6rem 1rem;
  z-index: 10;
}
.skip-link:focus { left: 0; }

/* ---------------------------------------------------------------- header */

.site-header {
  position: sticky;
  top: 0;
  z-index: 5;
  background: color-mix(in srgb, var(--bg) 88%, transparent);
  backdrop-filter: blur(8px);
  border-bottom: 1px solid var(--line);
}

.site-header .wrap {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1.5rem;
  align-items: center;
  justify-content: space-between;
  min-height: 3.75rem;
  padding-block: 0.6rem;
}

/* The logo is the link's only content, so its alt text carries the site name.
   Height is fixed and width follows the aspect ratio, so swapping in a logo of
   different proportions doesn't need a CSS change. */
.brand { display: flex; align-items: center; text-decoration: none; }
.brand img { display: block; height: 30px; width: auto; }
@media (max-width: 30rem) { .brand img { height: 26px; } }

/* The nav is a plain wrapped list at every width. No collapse, so no toggle,
   so no JavaScript. */
.site-header nav ul {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem 1.75rem;
  list-style: none;
  margin: 0;
  padding: 0;
}
.site-header nav a {
  color: var(--ink-soft);
  text-decoration: none;
  font-weight: 500;
}
.site-header nav a:hover { color: var(--ink); }
.site-header nav a[aria-current="page"] {
  color: var(--ink);
  text-decoration: underline;
  text-decoration-thickness: 2px;
  text-underline-offset: 0.35em;
}

.header-actions {
  display: flex;
  align-items: center;
  gap: 1rem;
}
/* Dropped on small screens, where the brand and three nav links are all the
   header has room for. The Free Trial CTA is repeated in the hero, so nothing
   is lost there; Login is only in the header, so it goes away on mobile. */
@media (max-width: 48rem) {
  .header-actions { display: none; }
}
.header-link {
  color: var(--ink-soft);
  text-decoration: none;
  font-weight: 500;
  font-size: 0.95rem;
}
.header-link:hover { color: var(--ink); }

/* ---------------------------------------------------------------- breadcrumbs */

.breadcrumbs { padding-top: 1.25rem; }
.breadcrumbs ol {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  list-style: none;
  margin: 0;
  padding: 0;
  font-size: 0.875rem;
  color: var(--ink-soft);
}
.breadcrumbs li + li::before {
  content: "/";
  margin-right: 0.5rem;
  color: var(--line);
}

/* ---------------------------------------------------------------- typography */

h1, h2, h3, h4 {
  line-height: 1.2;
  letter-spacing: -0.02em;
  margin-block: 1.8em 0.6em;
  text-wrap: balance;
}
h1 { font-size: clamp(1.9rem, 4vw, 2.5rem); margin-top: 1rem; }
h2 { font-size: clamp(1.4rem, 3vw, 1.75rem); }
h3 { font-size: 1.2rem; }

.lede {
  font-size: 1.2rem;
  color: var(--ink-soft);
  max-width: var(--measure);
  text-wrap: pretty;
}

.meta {
  font-size: 0.875rem;
  color: var(--ink-soft);
  margin-block: 0.25rem;
}

.prose { padding-block: 1rem 4rem; }

/* ---------------------------------------------------------------- post page

   The reading column plus a rail, centred together. Without a cap the article
   inherits the 1320px .wrap and the text sits pinned to its left edge with
   hundreds of pixels of nothing beside it. Everything on the page — breadcrumb,
   header, grid — shares one width so their left edges line up. */

body.post {
  --rail: 20rem;
  /* Same container as the rest of the site, so the breadcrumb, title and first
     paragraph all start at the header's left edge. The reading column keeps its
     measure and the rail sits at the far right — the slack between them becomes
     gutter rather than over-long lines. */
  --post-wrap: var(--wrap);
}
body.post .breadcrumbs,
body.post .post-grid,
body.post .related { max-width: var(--post-wrap); }

/* No width cap, and no balancing: the title fills each line to the edge of the
   article column before wrapping. `balance` (set on headings globally) does the
   opposite — it shortens the first line to even the two out, so the heading
   stops short of the space available. */
.post-head h1 { margin-block: 0 0.3em; text-wrap: wrap; }
.post-head .meta { padding-bottom: 1.25rem; }

.post-grid {
  display: grid;
  /* minmax(0, 1fr), not the default auto: an auto column sizes to its widest
     content, so one long line inside a <pre> pushes the column past the
     viewport and the whole page scrolls sideways. This caps it, and the <pre>
     scrolls inside itself instead. */
  grid-template-columns: minmax(0, 1fr);
  gap: 2.5rem 3rem;
  align-items: start;
  margin-top: 2rem;
}
/* Grid and flex children default to min-width:auto, which has the same effect
   one level down. */
.post-grid > * { min-width: 0; }
/* Source order is rail-then-article so the contents list follows the title on a
   phone. On desktop the rail is placed in column two, which puts the article
   back on the left visually without moving it in the DOM. */
@media (min-width: 62rem) {
  .post-grid {
    grid-template-columns: minmax(0, 1fr) var(--rail);
    /* The header and the article stack in column one; the rail occupies column
       two across both of them, so it starts level with the title. */
    grid-template-rows: auto 1fr;
    row-gap: 0;
  }
  .post-head { grid-column: 1; grid-row: 1; }
  .prose { grid-column: 1; grid-row: 2; }
  .post-rail {
    grid-column: 2;
    grid-row: 1 / span 2;
    position: sticky;
    /* clears the sticky site header */
    top: 5rem;
  }
}
.post-grid .prose { padding-top: 0; }
/* The first paragraph carries a top margin, which pushed the article a line
   below the rail. Dropping it lines the opening line up with "On this page". */
.post-grid .prose > :first-child { margin-top: 0; }
/* The article column fills the space rather than holding to a 38rem measure,
   so paragraphs and tables span the full column width.
   `img` is excluded deliberately: imported posts use raw <img> tags so they can
   carry width/height, which makes them direct children here — and lifting the
   cap would override the global `img { max-width: 100% }` and let a 1024px
   screenshot overflow the column and slide under the rail. */
.post-grid .prose > *:not(img):not(.hero-image):not(.tags):not(table):not(pre) { max-width: none; }

.post-rail { display: grid; gap: 1.5rem; }
.rail-label {
  font-family: var(--font-mono);
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-soft);
  margin: 0 0 0.6rem;
}
.toc ol {
  list-style: none;
  margin: 0;
  padding: 0;
  border-left: 1px solid var(--line);
}
.toc li { margin: 0; }
.toc a {
  display: block;
  padding: 0.3rem 0 0.3rem 0.85rem;
  margin-left: -1px;
  border-left: 2px solid transparent;
  font-size: 0.9rem;
  line-height: 1.35;
  color: var(--ink-soft);
  text-decoration: none;
}
.toc a:hover { color: var(--accent); border-left-color: var(--accent); }

/* `img` is exempt from the reading measure — screenshots are sized by their own
   width/height attributes and bounded by the global `img { max-width: 100% }`,
   so they fill up to the column width instead of being squeezed to 608px. */
.prose > *:not(img):not(.hero-image):not(.tags):not(table):not(pre) { max-width: var(--measure); }
.prose p, .prose li { text-wrap: pretty; }
.prose blockquote {
  margin-inline: 0;
  padding-left: 1.25rem;
  border-left: 3px solid var(--line);
  color: var(--ink-soft);
}
.prose code {
  font-family: var(--font-mono);
  font-size: 0.9em;
  background: var(--bg-soft);
  padding: 0.15em 0.4em;
  border-radius: 4px;
}
/* Code blocks. Shiki emits its own <pre class="shiki"> with the token colours
   inline, so the rules here handle the box only — padding, border, scrolling —
   and leave the colours alone. Untagged blocks get markdown-it's plain <pre>
   and are styled identically, so a highlighted and an unhighlighted block sit
   together without looking like different components. */
.prose pre,
.prose pre.shiki {
  /* A slate rather than the near-black of --ink. These posts are full of
     PowerShell console screenshots, which are themselves near-black, and a
     near-black code block next to one reads as the same object. The blue cast
     and the lift off pure black are what separate "code you can copy" from
     "a picture of a terminal". Kept in sync with colorReplacements in
     lib/content.js, which repaints Shiki's own background to this value. */
  background: #1b2029;
  color: #d7dae0;
  border: 0;
  border-radius: var(--radius);
  padding: 1.1rem 1.2rem;
  overflow-x: auto;
  font-size: 0.875rem;
  line-height: 1.6;
  /* Long PowerShell one-liners scroll rather than wrapping — a wrapped cmdlet
     is much harder to read, and harder still to copy correctly. */
  tab-size: 4;
}
/* The language name above the code. A positive label is what a screenshot can
   never have, so it identifies the block as code on sight. Deliberately not a
   bordered bar across the top: that is exactly what a terminal title bar looks
   like, which would undo the point. Untagged blocks have no data-lang and get
   no label. */
.prose pre[data-lang]::before {
  content: attr(data-lang);
  display: block;
  /* The <pre> scrolls horizontally, and in-flow content scrolls with it. Sticky
     pins the label to the left edge so it stays readable on a wide one-liner. */
  position: sticky;
  left: 0;
  margin-bottom: 0.85rem;
  font-family: var(--font-mono);
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  /* 4.8:1 on the surface above: legible, but a clear step below the code. */
  color: #8e97a6;
}
.prose pre code {
  background: none;
  padding: 0;
  font-size: inherit;
  /* Shiki wraps each line in a <span class="line">; without this the block
     collapses the indentation that makes a script readable. */
  white-space: pre;
}

.hero-image {
  width: 100%;
  border-radius: var(--radius);
  border: 1px solid var(--line);
  margin-block: 1.5rem;
}

table {
  width: 100%;
  border-collapse: collapse;
  margin-block: 1.5rem;
  font-size: 0.95rem;
}
/* A table with more columns than the screen has room for scrolls in its own
   box rather than widening the page. */
.prose table { display: block; overflow-x: auto; max-width: 100%; }
th, td {
  text-align: left;
  padding: 0.6rem 0.75rem;
  border-bottom: 1px solid var(--line);
  vertical-align: top;
}
th { font-weight: 600; }

/* ---------------------------------------------------------------- buttons */

.button {
  display: inline-block;
  background: var(--accent);
  color: var(--accent-ink);
  text-decoration: none;
  font-weight: 600;
  padding: 0.7rem 1.4rem;
  border-radius: var(--radius);
  border: 1px solid var(--accent);
}
.button:hover { filter: brightness(1.08); }
.button-sm { padding: 0.45rem 0.95rem; font-size: 0.95rem; }

/* ---------------------------------------------------------------- sections */

main > section.wrap { padding-block: 1rem 3rem; }
main > section.wrap:first-child { padding-top: 0; }
main > section.wrap > h2 { margin-top: 0; }

/* ---------------------------------------------------------------- cards */

.grid {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 1.5rem;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 17rem), 1fr));
}

/* Exactly three columns, not auto-fill. The container is wide enough for four
   at the 17rem minimum above, which left the sixth featured card alone on a
   second row. A fixed count keeps the six cards as two even rows of three. */
.grid-3 { grid-template-columns: repeat(3, 1fr); }
@media (max-width: 60rem) { .grid-3 { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 38rem) { .grid-3 { grid-template-columns: 1fr; } }

.card {
  display: flex;
  flex-direction: column;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
  background: var(--bg);
}
.card-media { display: block; }
.card-media img {
  display: block;
  width: 100%;
  /* 1200x628, the Open Graph share shape these featured images are actually
     authored at: 31 of 33 are within a third of a percent of this ratio. The
     previous 16/9 was narrower than the artwork, so `cover` cropped the sides
     and took the title text off the image.

     `contain`, not `cover`: the artwork carries text to its own edges, so any
     crop loses words. One post's featured image is nearly square (see
     how-to-create-dynamic-groups-in-entra-id) and letterboxes against
     --bg-soft rather than losing a third of its height. */
  aspect-ratio: 1200 / 628;
  object-fit: contain;
  background: var(--bg-soft);
}
.card-body { padding: 1rem 1.1rem 1.25rem; }
/* A card heading is an h2 on a listing page (it sits under the page h1) and an
   h3 inside a section that has its own h2, so both levels need the styling —
   otherwise the h2 falls back to default link blue at full heading size. */
.card-body :is(h2, h3) { margin-block: 0 0.35rem; font-size: 1.05rem; }
.card-body :is(h2, h3) a { color: var(--ink); text-decoration: none; }
.card-body :is(h2, h3) a:hover { color: var(--accent); }
.card-body p { margin-block: 0.35rem 0; font-size: 0.95rem; color: var(--ink-soft); }

section.related { padding-bottom: 4rem; }

/* ---------------------------------------------------------------- footer */

.site-footer {
  border-top: 1px solid var(--line);
  margin-top: 2rem;
  padding-block: 2rem 3rem;
  color: var(--ink-soft);
  font-size: 0.9rem;
}
.site-footer .wrap {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem 2rem;
  justify-content: space-between;
  align-items: center;
}
.footer-links {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1.5rem;
  list-style: none;
  margin: 0;
  padding: 0;
}
/* Muted and unstyled until hover. Footer links are wayfinding, not calls to
   action — the default blue-and-underlined treatment makes eight of them shout. */
.footer-links a {
  color: var(--ink-soft);
  text-decoration: none;
}
.footer-links a:hover {
  color: var(--ink);
  text-decoration: underline;
  text-underline-offset: 0.2em;
}
.site-footer p { margin: 0; }

@media print {
  .site-header, .site-footer, .breadcrumbs, .related { display: none; }
}
/* ========================================================= page sections
   REMOVED. The shared marketing section library (s-hero, s-features, s-pricing,
   s-faq, s-products, s-quotes and the rest) lived here, styling the components
   in templates/sections.js. This build renders only the post listing, the posts
   and a 404, so none of it was ever served — it was 16KB of the render-blocking
   stylesheet, half the file.

   templates/sections.js is still present. If you add a marketing page that uses
   it, restore these rules from git history (they are in the commit before this
   one) or the page will render unstyled. */
