/* rotascale.com — the layout grammar.
 *
 * subhadipmitra@: Rules, alignment and tabular figures. No card borders, no
 * shadow, no radius except where a control genuinely needs one.
 *
 * The reason is not taste. The page is arguing that this product produces
 * records a stranger can check, and a record is set as ruled columns with
 * figures that line up — not as a soft-cornered tile floating over a
 * background. Every visual decision below is downstream of that.
 */

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

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 16px;
  line-height: 1.56;
  font-variant-numeric: tabular-nums;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

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

/* subhadipmitra@: The browser default is a blue-grey that belongs to no design
   system on this page. Selection is one of the few surfaces a reader creates
   themselves, and it should look like the site did it. Tinted from the accent
   rather than set to it — a full-strength magenta wash makes the text under it
   harder to read, and the point of selecting text is to read it. */
/* subhadipmitra@: `background-color`, not the `background` shorthand, and no
   `color` at all.
   The first version set `background: …; color: …` and on some browsers only the
   colour landed — so selecting text changed the letters and painted nothing
   behind them, which reads as the text darkening rather than as a highlight.
   The shorthand is the unreliable half here. Leaving `color` unset also means
   the highlight cannot make text less readable than it was, which is the one
   thing a selection style must never do. */
::selection { background-color: var(--select); }
::-moz-selection { background-color: var(--select); }

.wrap { max-width: var(--wrap); margin: 0 auto; padding: 0 var(--gutter); }

/* Anything that can scroll sideways does so inside its own box. The page body
   never does. */
.scroll-x { overflow-x: auto; }
/* A scrolling block is a box; give it the space a box needs below it. */
.scroll-x + .note, .scroll-x + .limit { margin-top: 30px; }
.defs + .note, .defs + .limit, .claims + .note, .claims + .limit { margin-top: 30px; }

a { color: inherit; }

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

.skip {
  position: absolute; left: -9999px;
  background: var(--ink); color: var(--on-ink);
  padding: 10px 16px; z-index: 100;
}
.skip:focus { left: var(--gutter); top: 10px; }

/* --- type ---------------------------------------------------------------- */

h1, h2, h3 { text-wrap: balance; }

h1 {
  font-family: var(--serif);
  font-size: clamp(40px, 5.9vw, 72px);
  line-height: 1.03;
  font-weight: 600;
  letter-spacing: -0.021em;
  margin: 0 0 24px;
  max-width: 17ch;
}
h1 em { font-style: italic; font-weight: 500; color: var(--accent); }

h2 {
  font-family: var(--serif);
  font-size: clamp(27px, 3.3vw, 38px);
  line-height: 1.12;
  font-weight: 600;
  letter-spacing: -0.017em;
  margin: 0 0 16px;
  max-width: 21ch;
}

h3 { font-size: 15.5px; font-weight: 600; margin: 0; letter-spacing: -0.004em; }

.lead {
  font-size: 18.5px;
  line-height: 1.6;
  color: var(--ink-2);
  max-width: 58ch;
  margin: 0;
}
.lead b, .lead strong { font-weight: 600; color: var(--ink); }

.kicker {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: var(--muted);
  margin: 0 0 24px;
}
.kicker b { color: var(--accent); font-weight: 500; }

.note { font-size: 13.5px; color: var(--muted); margin: 26px 0 0; max-width: 66ch; }

/* --- the claim mark ------------------------------------------------------
 *
 * The organising idea of this site: every claim carries the product's own
 * three-state discipline. `observed` links to the thing itself — the running
 * demo, the published specification, the source. `asserted` says plainly that
 * there is nothing here a reader can check from outside.
 *
 * It costs us something, which is exactly why it is worth having. A page that
 * marks its own unverifiable claims is not a device a competitor copies.
 */

.mark {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  padding: 2px 6px;
  white-space: nowrap;
  border: 1px solid currentColor;
  display: inline-block;
}
.mark--observed { color: var(--allow); }
.mark--asserted { color: var(--muted); }
a.mark { text-decoration: none; }
a.mark:hover { background: var(--allow); color: var(--paper); border-color: var(--allow); }

/* --- masthead ------------------------------------------------------------ */

.mast { border-bottom: 1px solid var(--rule-hard); }
/* subhadipmitra@: `>` matters. The panel reuses `.wrap` for its own gutter, so
   a descendant selector here reached inside it and applied `display:flex;
   align-items:center` to the panel's grid — which centred the columns and
   dropped the shorter one by half the height difference. Second time a
   contextual class rule has quietly reformatted a component on this site; the
   fix both times is to stop the ancestor rule travelling. */
.mast > .wrap { display: flex; align-items: center; gap: 18px; padding-top: 13px; padding-bottom: 11px; }

.brand { display: flex; align-items: center; gap: 9px; text-decoration: none; }
/* subhadipmitra@: No `display`, for the reason spelled out at `.shot__img` —
   `.brand img` scores (0,1,1) and would beat the unscoped `.m-dark`
   (0,1,0), so both cuts of the logo rendered. Unscoping the swap moved
   this fight here; removing the declaration ends it. */
.brand img { height: 20px; width: auto; vertical-align: middle; }
.brand .word { font-size: 17px; font-weight: 700; letter-spacing: -0.012em; align-self: baseline; }
.brand .desc { font-size: 12.5px; font-weight: 400; color: var(--muted); white-space: nowrap; }
/* subhadipmitra@: The descriptor is the first thing to go. Five menu buttons
   plus a call to action need the room more than a subtitle does, and a masthead
   that wraps to two lines looks broken in a way a missing tagline does not. */
@media (max-width: 1220px) { .brand .desc { display: none; } }

/* Two cuts of one asset; each hides in the other's theme.
 *
 * subhadipmitra@: UNSCOPED. These rules lived under `.brand` and did nothing
 * anywhere else — so the console screenshots, which use the same two classes,
 * rendered both cuts stacked on every page. Reused mechanism, reused bug: the
 * class name promised a behaviour the selector only delivered in one place.
 * One rule for "this asset has a light and a dark cut", wherever it appears. */
.m-dark { display: none; }
:root[data-theme="dark"] .m-light { display: none; }
:root[data-theme="dark"] .m-dark { display: block; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .m-light { display: none; }
  :root:not([data-theme="light"]) .m-dark { display: block; }
}

/* --- the menu -----------------------------------------------------------
 *
 * subhadipmitra@: A ruled panel, not a card. Columns divided by hairlines, mono
 * labels, no icons, no shadow, no radius — because a mega menu that looked like
 * every other one would quietly undo the argument the rest of the page is
 * making about what this product's surfaces look like.
 */

.mast { position: relative; }
.mast__nav { margin-left: auto; display: flex; gap: 2px; flex-shrink: 0; }

.navitem { position: static; }

.navitem__btn {
  display: inline-flex; align-items: center; gap: 6px;
  font: 400 14px/1 var(--sans); color: var(--ink-2);
  background: none; border: 0; padding: 8px 10px; cursor: pointer;
}
.navitem__btn svg { transition: transform 120ms ease; opacity: .55; }
.navitem__btn[aria-expanded="true"] { color: var(--ink); }
.navitem__btn[aria-expanded="true"] svg { transform: rotate(180deg); opacity: 1; }
.navitem__btn:hover { color: var(--ink); }
.navitem__btn[data-current="true"] { color: var(--ink); box-shadow: inset 0 -1px 0 var(--ink); }
@media (prefers-reduced-motion: reduce) { .navitem__btn svg { transition: none; } }

/* Full-bleed under the masthead: the panel belongs to the rule above it. */
.panel {
  position: absolute; left: 0; right: 0; top: 100%;
  background: var(--paper);
  border-bottom: 1px solid var(--rule-hard);
  z-index: 40;
}
.panel[hidden] { display: none; }

.panel__grid {
  display: grid;
  /* subhadipmitra@: A bounded track, not `1fr`. With `auto-fit` and a fraction
     the browser made six tracks for three columns of links and the panel
     emptied into the right half of the page. Columns are 200–250px and pack
     left, so two groups and five groups both look deliberate. */
  grid-template-columns: repeat(auto-fit, minmax(200px, 250px));
  justify-content: start; align-items: start;
  gap: 0; padding-top: 26px; padding-bottom: 30px;
}
.panel__col { padding-right: 28px; border-right: 1px solid var(--rule); }
.panel__col:last-child { border-right: 0; padding-right: 0; }
/* subhadipmitra@: …and the one before the feature column, which is no longer
   `:last-child` once a feature exists. Without this its rule hangs in the gap
   between the links and the feature's own border, dividing nothing from
   nothing. */
.panel__col:has(+ .panel__feature) { border-right: 0; padding-right: 0; }
.panel__col + .panel__col { padding-left: 28px; }

.panel__label {
  font-family: var(--mono); font-size: 10.5px; letter-spacing: 0.1em;
  text-transform: uppercase; color: var(--muted); margin-bottom: 12px;
}
.panel ul, .mobilenav ul { list-style: none; margin: 0; padding: 0; }
.panel li { margin-bottom: 2px; }
.panel a {
  display: block; text-decoration: none; padding: 7px 0; font-size: 14.5px;
  border-bottom: 1px solid transparent;
}
.panel a:hover { color: var(--accent); }
.panel a[aria-current="page"] { color: var(--ink); font-weight: 600; }
.panel__note {
  display: block; font-size: 12.5px; color: var(--muted); margin-top: 2px;
  max-width: 30ch;
}

/* --- mobile -------------------------------------------------------------- */

.mast__burger {
  display: none; background: none; border: 1px solid var(--rule);
  color: var(--ink-2); width: 32px; height: 32px; cursor: pointer;
  place-items: center;
}
.mobilenav {
  position: absolute; left: 0; right: 0; top: 100%; z-index: 40;
  background: var(--paper); border-bottom: 1px solid var(--rule-hard);
  max-height: 78vh; overflow-y: auto;
}
.mobilenav[hidden] { display: none; }
.mobilenav__group { padding: 20px 0 4px; border-bottom: 1px solid var(--rule); }
.mobilenav a { display: block; text-decoration: none; padding: 9px 0; font-size: 15.5px; }
.mobilenav a[aria-current="page"] { font-weight: 600; }

.mast .cta {
  font-size: 13.5px; font-weight: 500; padding: 9px 15px; white-space: nowrap;
  background: var(--ink); color: var(--on-ink); text-decoration: none; flex-shrink: 0;
}
.mast .cta:hover { background: var(--accent); color: #fff; }

.theme-toggle {
  background: none; border: 1px solid var(--rule); color: var(--muted);
  width: 32px; height: 32px; cursor: pointer; display: grid; place-items: center;
  font-family: inherit;
}
.theme-toggle:hover { color: var(--ink); border-color: var(--ink); }

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

.btn {
  display: inline-block;
  font: 500 14.5px/1 var(--sans);
  padding: 13px 19px;
  text-decoration: none;
  background: var(--ink);
  color: var(--on-ink);
  border: 1px solid var(--ink);
  cursor: pointer;
}
.btn:hover { background: var(--accent); border-color: var(--accent); color: #fff; }
.btn--ghost { background: none; color: var(--ink); }

.acts { display: flex; gap: 12px; margin: 32px 0 0; align-items: center; flex-wrap: wrap; }

/* --- the record ----------------------------------------------------------
 * Set as a ruled document because it IS one. A card would make it a
 * screenshot of a UI, which is a weaker claim.
 */

.record { margin: 54px 0 0; border-top: 1px solid var(--rule-hard); }

.record__head {
  display: flex; align-items: baseline; gap: 13px; flex-wrap: wrap;
  padding: 13px 0 11px; border-bottom: 1px solid var(--rule);
  font-family: var(--mono); font-size: 12.5px;
}
.record__head .who { color: var(--muted); }
.record__state {
  margin-left: auto; font-size: 10.5px; letter-spacing: 0.09em;
  text-transform: uppercase; padding: 2px 8px; border: 1px solid currentColor;
}
.record__state--deny { color: var(--deny); }
.record__state--allow { color: var(--allow); }
.record__state--review { color: var(--review); }

.rows { display: grid; grid-template-columns: 1fr 1fr; }
.rows > div { padding: 14px 0; border-bottom: 1px solid var(--rule); }
.rows > div:nth-child(odd) { padding-right: 30px; border-right: 1px solid var(--rule); }
.rows > div:nth-child(even) { padding-left: 30px; }

.k {
  font-size: 11.5px; font-weight: 500; letter-spacing: 0.06em;
  text-transform: uppercase; color: var(--muted); margin-bottom: 4px;
}
/* subhadipmitra@: A `<label>` is inline, and vertical margins do nothing on a
   non-replaced inline box — so `.k`'s `margin-bottom` was silently discarded on
   every form label on the site, and the only gap was the input's own
   `margin-top`. The label looked attached to the field above it rather than to
   the one below. */
label.k { display: block; margin-bottom: 7px; }
.v { font-family: var(--mono); font-size: 14px; }
.v--deny { color: var(--deny); font-weight: 500; }

/* --- the gate rail -------------------------------------------------------
 * Nine gates in a FIXED order is the one structural fact no competitor's
 * diagram has, so it is drawn as a sequence that visibly stops rather than as
 * nine equal boxes.
 */

.rail { padding: 20px 0 0; }
.rail__k {
  font-size: 11.5px; font-weight: 500; letter-spacing: 0.06em;
  text-transform: uppercase; color: var(--muted); margin-bottom: 11px;
}
.rail__track { display: grid; grid-template-columns: repeat(9, 1fr); gap: 3px; }
.rail__track span { height: 6px; background: var(--allow); }
.rail__track span.is-stop { background: var(--deny); }
.rail__track span.is-off { background: var(--rule); }
.rail__names {
  display: grid; grid-template-columns: repeat(9, 1fr); gap: 3px; margin-top: 9px;
  font-family: var(--mono); font-size: 10.5px; color: var(--muted);
  letter-spacing: -0.01em; word-break: break-word; line-height: 1.3;
}
.rail__names b { color: var(--deny); font-weight: 600; }
.rail__names i { font-style: normal; opacity: 0.45; }

.hero { padding: 86px 0 76px; }
.hero .lead { margin-top: 4px; }

/* --- sections and claim lists -------------------------------------------- */

.sec { padding: 72px 0; border-top: 1px solid var(--rule); }
/* subhadipmitra@: `:not()` because this rule was silently winning against the
   utility classes. `.sec > .wrap > p` scores 0,2,1 and `.note` scores 0,1,0, so
   a `.note` or `.limit` sitting directly in a section lost its top margin and
   collided with whatever was above it — visible after a `.defs` list and after
   a `.scroll-x` table. A section-level type selector fighting a component class
   over spacing is the classic way a stylesheet develops mystery gaps. */
.sec > .wrap > p:not(.note):not(.limit):not(.lead):not(.legend):not(.sub__fine) {
  font-size: 17px; color: var(--ink-2); max-width: 63ch; margin: 0;
}

.claims { margin: 36px 0 0; border-top: 1px solid var(--rule-hard); }
.claim {
  display: grid; grid-template-columns: 230px 1fr 108px; gap: 32px;
  align-items: start; padding: 19px 0; border-bottom: 1px solid var(--rule);
}
.claim p { font-size: 14.8px; color: var(--ink-2); margin: 0; max-width: 60ch; }

.legend { margin: 30px 0 0; font-size: 13.5px; color: var(--muted); max-width: 66ch; }
.legend .mark { margin-right: 5px; }

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

.foot { border-top: 1px solid var(--rule-hard); padding: 54px 0 40px; margin-top: 20px; }
.foot__grid { display: grid; grid-template-columns: 1.4fr repeat(4, 1fr); gap: 32px; }
.foot h4 {
  font-family: var(--mono); font-size: 10.5px; letter-spacing: 0.1em;
  text-transform: uppercase; color: var(--muted); margin: 0 0 12px; font-weight: 500;
}
.foot ul { list-style: none; margin: 0; padding: 0; font-size: 14px; }
.foot li { margin-bottom: 7px; }
.foot a { color: var(--ink-2); text-decoration: none; }
.foot a:hover { color: var(--ink); box-shadow: inset 0 -1px 0 var(--ink); }
.foot__legal {
  display: flex; gap: 20px; flex-wrap: wrap; align-items: baseline;
  margin-top: 40px; padding-top: 18px; border-top: 1px solid var(--rule);
  font-size: 13px; color: var(--muted);
}
.foot__legal .spacer { margin-left: auto; }

@media (max-width: 900px) {
  :root { --gutter: 20px; }
  .rows { grid-template-columns: 1fr; }
  .rows > div:nth-child(odd) { border-right: 0; padding-right: 0; }
  .rows > div:nth-child(even) { padding-left: 0; }
  .claim { grid-template-columns: 1fr; gap: 8px; }
  .foot__grid { grid-template-columns: 1fr 1fr; }
  .rail__names { font-size: 8px; }
  .mast__nav, .mast .cta, .brand .desc { display: none; }
  .mast__burger { display: grid; }
}

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


/* --- components the platform pages need ---------------------------------- */

/* A code sample. Ruled top and bottom rather than boxed, same as a record. */
.code {
  font-family: var(--mono); font-size: 13px; line-height: 1.7;
  background: var(--paper-2); padding: 18px 20px; margin: 26px 0 0;
  overflow-x: auto; border-left: 2px solid var(--rule-hard);
}
.code .c { color: var(--muted); }
.code .s { color: var(--accent); }

/* The gate table: nine rows, in order, with what each one asks. */
.gates { width: 100%; border-collapse: collapse; margin: 34px 0 0; }
.gates th {
  text-align: left; font-size: 11.5px; font-weight: 500; letter-spacing: 0.06em;
  text-transform: uppercase; color: var(--muted); padding: 0 0 10px;
  border-bottom: 1px solid var(--rule-hard);
}
.gates td { padding: 14px 0; border-bottom: 1px solid var(--rule); vertical-align: top; font-size: 14.5px; }
.gates td:first-child { font-family: var(--mono); font-size: 13px; color: var(--muted); width: 56px; }
.gates td:nth-child(2) { font-family: var(--mono); font-size: 13.5px; width: 168px; }
.gates td:nth-child(2) b { font-weight: 500; }
.gates td:last-child { color: var(--ink-2); }

/* The enforcement ladder: four rungs, and only two of them refuse. */
.ladder { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1px; margin: 32px 0 0;
  background: var(--rule); border-top: 1px solid var(--rule-hard); }
.ladder > div { background: var(--paper); padding: 18px 20px 20px; }
.ladder h4 { font-family: var(--mono); font-size: 12.5px; font-weight: 500; margin: 0 0 8px; }
.ladder p { font-size: 13.5px; color: var(--ink-2); margin: 0; }
.ladder .is-enforcing h4 { color: var(--allow); }
.ladder .is-watching h4 { color: var(--review); }
.ladder__note { font-size: 13.5px; color: var(--muted); margin: 14px 0 0; }

/* Two-column definition rows: term on the left, what it means on the right. */
.defs { margin: 32px 0 0; border-top: 1px solid var(--rule-hard); }
.def { display: grid; grid-template-columns: 230px 1fr; gap: 32px; padding: 18px 0;
  border-bottom: 1px solid var(--rule); }
.def dt { font-weight: 600; font-size: 15px; }
.def dd { margin: 0; font-size: 14.8px; color: var(--ink-2); max-width: 64ch; }
.def dd code, .def dt code { font-family: var(--mono); font-size: 13px; }

/* A comparison: what this is not. */
.compare { width: 100%; border-collapse: collapse; margin: 32px 0 0; }
.compare th { text-align: left; font-size: 11.5px; font-weight: 500; letter-spacing: 0.06em;
  text-transform: uppercase; color: var(--muted); padding: 0 16px 10px 0;
  border-bottom: 1px solid var(--rule-hard); }
.compare td { padding: 15px 16px 15px 0; border-bottom: 1px solid var(--rule);
  vertical-align: top; font-size: 14.5px; color: var(--ink-2); }
.compare td:first-child { color: var(--ink); font-weight: 500; width: 24%; }

/* A stated limit. Used where the honest answer is "we do not do that". */
.limit { border-left: 2px solid var(--review); padding: 6px 0 6px 20px;
  margin: 34px 0 0; font-size: 15px; color: var(--ink-2); max-width: 64ch; }
.limit b { color: var(--ink); }

/* Page navigation between siblings. */
.siblings { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 1px; background: var(--rule); border-top: 1px solid var(--rule-hard);
  margin: 0; }
.siblings a { background: var(--paper); padding: 18px 20px; text-decoration: none; display: block; }
.siblings a:hover { background: var(--paper-2); }
.siblings .k { margin-bottom: 5px; }
.siblings span { font-size: 15px; font-weight: 600; }

@media (max-width: 900px) {
  .ladder { grid-template-columns: 1fr; }
  .def { grid-template-columns: 1fr; gap: 6px; }
  .gates td:nth-child(2) { width: auto; }
}


/* --- the verifier -------------------------------------------------------- */

.vinput {
  width: 100%; font-family: var(--mono); font-size: 13px; line-height: 1.6;
  background: var(--paper-2); color: var(--ink);
  border: 1px solid var(--rule); border-left: 2px solid var(--rule-hard);
  padding: 14px 16px; resize: vertical;
}
/* The gap belongs to the label, which is next to the thing it names. An input
   carrying its own top margin also pushed itself away from a preceding
   paragraph, which is not the same relationship. */
label.k + .vinput { margin-top: 0; }
.vinput:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.vinput::placeholder { color: var(--muted); }

.vout:not(:empty) { margin: 30px 0 0; border-top: 1px solid var(--rule-hard); }
.vrow { display: grid; grid-template-columns: 92px 1fr; gap: 20px; align-items: start;
  padding: 16px 0; border-bottom: 1px solid var(--rule); }
.vrow b { font-size: 15px; font-weight: 600; }
.vdetail { font-size: 14px; color: var(--ink-2); margin-top: 5px; max-width: 62ch; }
.vdetail code { font-family: var(--mono); font-size: 12px; word-break: break-all; }
.vstate { font-family: var(--mono); font-size: 10px; letter-spacing: 0.09em;
  text-transform: uppercase; padding: 2px 6px; border: 1px solid currentColor;
  display: inline-block; }
.vstate--passed { color: var(--allow); }
.vstate--failed { color: var(--deny); }
.vstate--unknown { color: var(--review); }

@media (max-width: 900px) { .vrow { grid-template-columns: 1fr; gap: 8px; } }


/* --- long-form ------------------------------------------------------------
 *
 * subhadipmitra@: Twenty-five posts were rendering with no prose styles at all,
 * because the stylesheet was rebuilt around the marketing pages and `.prose`
 * never came with it. They were readable only in the sense that a browser
 * default is readable.
 *
 * Measure first: the posts use h2/h3 heavily, fenced code, tables and long
 * lists, so those are what this has to get right. Body copy sits at 65-ish
 * characters, which is where reading stops being work.
 */

.prose { max-width: 68ch; font-size: 17px; line-height: 1.68; }
.prose > * + * { margin-top: 1.1em; }

.prose h2 {
  font-family: var(--serif); font-size: 28px; line-height: 1.2; font-weight: 600;
  letter-spacing: -0.015em; margin: 2em 0 0; max-width: 24ch;
  padding-top: 0.7em; border-top: 1px solid var(--rule);
}
.prose h3 {
  font-size: 18px; font-weight: 600; letter-spacing: -0.005em; margin: 1.8em 0 0;
}
.prose h4 { font-size: 15.5px; font-weight: 600; margin: 1.5em 0 0; color: var(--ink-2); }

.prose p { margin: 0; }
.prose a { color: var(--ink); box-shadow: inset 0 -1px 0 var(--rule-hard); text-decoration: none; }
.prose a:hover { color: var(--accent); box-shadow: inset 0 -1px 0 var(--accent); }

.prose ul, .prose ol { margin: 1.1em 0 0; padding-left: 1.3em; }
.prose li { margin-bottom: 0.45em; }
.prose li > ul, .prose li > ol { margin-top: 0.45em; }

.prose blockquote {
  margin: 1.6em 0 0; padding: 2px 0 2px 20px; border-left: 2px solid var(--accent);
  color: var(--ink-2);
}
.prose blockquote p + p { margin-top: 0.8em; }

.prose code {
  font-family: var(--mono); font-size: 0.86em;
  background: var(--paper-2); padding: 1px 5px;
}
.prose pre {
  font-family: var(--mono); font-size: 13px; line-height: 1.7;
  background: var(--paper-2); border-left: 2px solid var(--rule-hard);
  padding: 16px 18px; overflow-x: auto; margin: 1.5em 0 0;
}
.prose pre code { background: none; padding: 0; font-size: inherit; }

/* A table in a post is data; it gets the same rules the rest of the site uses. */
.prose table { width: 100%; border-collapse: collapse; margin: 1.6em 0 0; font-size: 15px; }
.prose th {
  text-align: left; font-size: 11.5px; font-weight: 500; letter-spacing: 0.06em;
  text-transform: uppercase; color: var(--muted); padding: 0 14px 9px 0;
  border-bottom: 1px solid var(--rule-hard);
}
.prose td { padding: 12px 14px 12px 0; border-bottom: 1px solid var(--rule); vertical-align: top; }

.prose hr { border: 0; border-top: 1px solid var(--rule); margin: 2.4em 0 0; }
.prose img { display: block; margin: 1.6em 0 0; }
.prose strong { font-weight: 600; }

/* --- post listing --------------------------------------------------------- */

.posts { margin: 40px 0 0; border-top: 1px solid var(--rule-hard); list-style: none; padding: 0; }
.posts li { border-bottom: 1px solid var(--rule); }
.posts a { display: grid; grid-template-columns: 118px 1fr; gap: 28px;
  padding: 20px 0; text-decoration: none; align-items: baseline; }
.posts a:hover h3 { color: var(--accent); }
.posts time { font-family: var(--mono); font-size: 12.5px; color: var(--muted); }
.posts h3 { font-size: 17px; font-weight: 600; margin: 0 0 5px; max-width: 46ch; }
.posts p { font-size: 14.5px; color: var(--ink-2); margin: 0; max-width: 62ch; }

.postmeta {
  font-family: var(--mono); font-size: 12px; color: var(--muted);
  letter-spacing: 0.03em; margin: 0 0 30px;
}

@media (max-width: 900px) {
  .prose { font-size: 16.5px; }
  .posts a { grid-template-columns: 1fr; gap: 6px; }
}

/* A rendered diagram is a figure, not a code block. */
.prose .mermaid { margin: 1.8em 0 0; text-align: center; overflow-x: auto; }
.prose .mermaid svg { max-width: 100%; height: auto; }


/* --- the subscribe block -------------------------------------------------
 *
 * subhadipmitra@: It sits at the end of a post, where somebody has just
 * finished reading and is the most likely they will ever be to want the next
 * one. `--paper-2` rather than a card: a tint and two rules mark it as a
 * different KIND of thing from the article without borrowing the boxed-CTA
 * idiom the rest of the site avoids.
 *
 * `.sub__fine` is in the `:not()` chain of the section paragraph rule above,
 * because that selector scores 0,2,1 and would otherwise win the font-size
 * back — the same collision documented there, which is why it is worth
 * repeating the fix rather than discovering it a third time.
 */
.sec--sub {
  background: var(--paper-2);
  border-top: 1px solid var(--rule-hard);
  border-bottom: 1px solid var(--rule);
  padding: 54px 0 56px;
}
.sec--sub h2 { margin: 10px 0 0; max-width: 22ch; }
.sub__lead {
  font-size: 16px; color: var(--ink-2); max-width: 60ch; margin: 14px 0 0;
}
.sub__form { align-items: flex-end; margin-top: 26px; }
.sub__field { flex: 1; max-width: 360px; }
.sub__fine {
  font-family: var(--mono); font-size: 11.5px; letter-spacing: 0.02em;
  color: var(--muted); margin: 18px 0 0;
}
.sub__fine a { color: var(--muted); }
.sub__fine a:hover { color: var(--accent); }

@media (max-width: 620px) {
  .sub__form { align-items: stretch; }
  .sub__field { max-width: none; }
  .sub__form .btn { width: 100%; text-align: center; }
}

/* --- latest posts, on the home page --------------------------------------
 * The compact cut of `.posts`: no descriptions, so three of them cost the
 * height of one paragraph.
 */
.posts--tight a { grid-template-columns: 96px 1fr; gap: 20px; padding: 15px 0; }
.posts--tight h3 { margin: 0; font-size: 16.5px; }

/* A second line inside a `.rows` cell — where to go for the policy, not the
   policy itself. Muted so the address above it stays the thing you read. */
.muted-note { font-size: 13px; color: var(--muted); }
.rows p { margin: 6px 0 0; font-size: 15px; line-height: 1.6; }

/* Three fields rather than one, so the subscribe row's `flex:1` would squeeze
   them all onto one line at a width nobody can type into. */
/* subhadipmitra@: A GRID, not wrapped flex.
 *
 * Three fields and a button in a `flex-wrap` row is a layout that decides
 * itself: every item took a line of its own, and because `gap` only applies
 * BETWEEN items on the cross axis the button ended up flush against the email
 * input with no space at all. Reasoning about which line an item lands on is
 * not worth it for a form with four controls.
 *
 * One column, generous rows, and the button on its own row. Two columns once
 * there is room for two fields to sit side by side without either becoming a
 * slot too narrow to read what you typed. */
.demo__form { display: grid; grid-template-columns: 1fr; gap: 20px; align-items: end; }
.demo__form .sub__field { flex: none; max-width: none; }
.demo__form button[type="submit"] { justify-self: start; }

@media (min-width: 720px) {
  .demo__form { grid-template-columns: 1fr 1fr; column-gap: 24px; }
  /* The email is the field people mistype; it gets the full width. */
  .demo__form .sub__field:nth-of-type(3) { grid-column: 1 / -1; }
}

/* --- the mega menu's right-hand column -----------------------------------
 *
 * subhadipmitra@: Two groups of links left a wide empty half on four of the
 * five menus. The fix is not an illustration — this site has no ornament
 * anywhere, and adding some in the navigation would announce that the empty
 * space was a problem being covered up.
 *
 * It was briefly the nine gates as a numbered list. True, and nine rows tall: a
 * menu is scanned in a second, and a column that takes longer to read than the
 * links beside it has stopped helping. One statement and one sentence now, the
 * same shape in every menu, so the panel's height does not lurch as the reader
 * moves across the bar.
 *
 * `margin-left:auto` via `justify-self`, not a grid track, so it reaches the
 * far edge on a two-column menu and simply follows the last column on a
 * four-column one — `Solutions` never needed it and must not be pushed around
 * by it.
 */
.panel__feature {
  /* `span 2` because the grid's tracks are a bounded 200–250px, and a single
     track would squeeze the statement to three words a line. */
  grid-column: span 2;
  justify-self: end;
  width: 100%;
  max-width: 340px;
  padding-left: 30px;
  border-left: 1px solid var(--rule);
}

.panel__statement {
  margin: 12px 0 0;
  font-family: var(--serif);
  font-size: 19px;
  line-height: 1.3;
  color: var(--ink);
  text-wrap: balance;
}

/* subhadipmitra@: NOT `.panel__note`. That class already belongs to the small
   note under each nav link, and a second rule of the same name later in the
   file won the cascade on `margin` — every link note in every menu quietly
   gained ten pixels. The one-word-longer name is the whole fix. */
.panel__feature-note {
  margin: 11px 0 0;
  font-size: 12.5px;
  line-height: 1.55;
  color: var(--muted);
}

.panel__more {
  display: inline-block;
  margin-top: 14px;
  font-family: var(--mono);
  font-size: 10.5px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-2);
  text-decoration: none;
  border-bottom: 1px solid var(--rule-hard);
}
.panel__more:hover { color: var(--accent); border-color: var(--accent); }

/* Below the mega-menu breakpoint the panel stacks; the feature column would be
   a screenful of scrolling before the reader reaches a link. */
@media (max-width: 900px) { .panel__feature { display: none; } }

/* --- the hero wave -------------------------------------------------------
 *
 * subhadipmitra@: Carried over from v1, where it was the piece of the design
 * people remembered. It stays on the home page and nowhere else: one ornament,
 * once, on a site that otherwise has none — and never in the console, where
 * something moving behind the evidence would be exactly the wrong idea.
 *
 * It stops before the record. The artefact below the fold is the page's
 * argument and it is set as a document; a field of dots drifting behind it
 * would turn evidence into a background.
 */
.hero--wave { position: relative; overflow: hidden; }
.hero--wave > .wrap { position: relative; z-index: 1; }

.wave {
  position: absolute;
  top: 0;
  right: 0;
  /* Wider than the column and pushed right, so the curve reads as passing
     behind the headline rather than sitting under it. */
  width: 92%;
  height: 62%;
  z-index: 0;
  pointer-events: none;
}

@media (max-width: 900px) {
  /* A phone gets the static frame the script already paints, at a size that
     does not compete with a headline it has to share the fold with. */
  .wave { width: 100%; height: 45%; opacity: 0.6; }
}

/* subhadipmitra@: The section landings get it quieter than the home page.
 *
 * The home page is where somebody decides whether to keep reading; a landing
 * page is where they are already reading, and the same intensity twice in two
 * clicks stops being a signature and becomes wallpaper. Deeper pages get none
 * at all — fifty pages of drifting dots is a texture, not a decision. */
.hero--wave-quiet .wave { height: 100%; opacity: 0.55; }

/* --- a screenshot of the running console ---------------------------------
 *
 * subhadipmitra@: A hairline and a caption. No shadow, no radius, no browser
 * chrome mockup — the site separates things with rules, and a screenshot
 * floating in a fake window would be the one element pretending to be
 * something it is not, on the pages that argue hardest about evidence.
 *
 * `.m-light` / `.m-dark` are the logo's own swap classes, reused deliberately:
 * one mechanism for "this asset has two cuts", so a future third asset does not
 * invent a third way of doing it.
 */
.shot { margin: 34px 0 0; }
/* subhadipmitra@: No `display` here, deliberately. `.shot__img` and `.m-dark`
   score the same, this file loads later, and `display: block` therefore beat
   `display: none` — so the light cut and the dark cut both rendered, stacked,
   in light mode. Removing the competing declaration is a better fix than
   winning the fight with a more specific selector, which only moves the
   argument somewhere harder to find. `vertical-align` kills the inline
   descender gap that block was incidentally solving. */
.shot__img {
  width: 100%;
  height: auto;
  vertical-align: middle;
  border: 1px solid var(--rule);
  background: var(--paper-2);
}
.shot figcaption {
  display: flex;
  gap: 16px;
  align-items: baseline;
  justify-content: space-between;
  flex-wrap: wrap;
  margin-top: 11px;
  font-size: 13px;
  line-height: 1.55;
  color: var(--muted);
  max-width: 78ch;
}

/* --- the region map ------------------------------------------------------
 *
 * subhadipmitra@: The land is one `<path>` of small squares, coloured with
 * `currentColor` so it inherits the theme rather than carrying two hardcoded
 * fills. Deliberately faint: the map is context, and the five markers are the
 * content. If the land competes with the pins the whole thing has inverted.
 */
.map { margin: 40px 0 0; }
.map__frame {
  border: 1px solid var(--rule);
  background: var(--paper-2);
  padding: 22px 26px;
}
/* The pins' positioning context is the MAP, not the padded frame — see the
   note in `region-map.html`. */
.map__plot { position: relative; }
.map__land { display: block; width: 100%; height: auto; color: var(--rule-hard); opacity: 0.17; }
:root[data-theme="dark"] .map__land { opacity: 0.26; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .map__land { opacity: 0.26; }
}

.map__pin {
  position: absolute;
  transform: translate(-50%, -50%);
  display: flex;
  align-items: center;
  gap: 7px;
  text-decoration: none;
  white-space: nowrap;
}
.map__dot {
  width: 9px; height: 9px;
  border: 1.5px solid var(--muted);
  background: var(--paper);
  flex: none;
}
.map__code {
  font-family: var(--mono);
  font-size: 10.5px;
  letter-spacing: 0.09em;
  color: var(--muted);
}
.map__pin:hover .map__dot { border-color: var(--ink); }
.map__pin:hover .map__code { color: var(--ink); }

/* The one you are on. Filled rather than merely recoloured — on a small mark a
   colour change alone is easy to miss, and this is the whole job of the map. */
.map__pin.is-active .map__dot { background: var(--accent); border-color: var(--accent); }
.map__pin.is-active .map__code { color: var(--accent); font-weight: 600; }

.map figcaption {
  margin-top: 12px;
  font-size: 13px;
  line-height: 1.55;
  color: var(--muted);
  max-width: 72ch;
}

@media (max-width: 620px) {
  /* Codes only — two-letter labels survive; the frame does not need padding it
     cannot afford at this width. */
  .map__frame { padding: 14px 12px; }
  .map__code { font-size: 9.5px; }
  .map__dot { width: 7px; height: 7px; }
}
