/* The shared Landometer bar, and the shell web-v3 puts around every page, for
   the static home. Three parts:

   1. What web-v3's `_app` supplies at run time: the faces `next/font` serves,
      bound here to the files this page self-hosts, and MUI's CssBaseline with
      the app theme.
   2. web-v3's `src/styles/globals.css`.
   3. web-v3's `src/core/navigation/components/AppNavbar.module.css`.

   2 and 3 are copied unchanged but for their font paths, so a fix to the bar is
   the same diff here as there. */

/* 1 ------------------------------------------------------------------------ */

/* next/font's variables, which web-v3 sets on <html>. */
:root {
  --lm-font-body: "Bai Jamjuree", "Noto Sans Thai", "Leelawadee UI", Tahoma,
    sans-serif;
  --lm-font-display: "Arvo", Georgia, Cambria, "Times New Roman", serif;
  --lm-font-technical: "JetBrains Mono", SFMono-Regular, Consolas,
    "Liberation Mono", monospace;
  --lm-font-display-th: "IBM Plex Sans Thai Looped", "Noto Sans Thai Looped",
    "Leelawadee UI", Tahoma, sans-serif;
}

html {
  font-family: var(--lm-font-body);
  font-style: normal;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  box-sizing: border-box;
  -webkit-text-size-adjust: 100%;
}

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

strong,
b {
  font-weight: 700;
}

/* body1 of the app theme, on its background.default. */
body {
  margin: 0;
  color: hsl(220, 30%, 6%);
  font-family: var(--lm-font-body);
  font-weight: 400;
  font-size: 0.875rem;
  line-height: 1.5;
  letter-spacing: 0.00938em;
  background-color: hsl(210, 31%, 95%);
}

body::backdrop {
  background-color: hsl(210, 31%, 95%);
}

@media print {
  body {
    background-color: #fff;
  }
}

[data-color-scheme="light"] {
  color-scheme: light;
}

[data-color-scheme="dark"] {
  color-scheme: dark;
}

[data-color-scheme="dark"] body {
  color: hsl(0, 0%, 100%);
  background-color: hsl(220, 35%, 3%);
}

[data-color-scheme="dark"] body::backdrop {
  background-color: hsl(220, 35%, 3%);
}

/* React unmounts the closed menu; this page keeps it in the document and hides
   it, so the closed state needs a rule — one that outranks the bare class the
   copy below gives a `display`. */
.menuPanel[hidden],
.menuBackdrop[hidden] {
  display: none;
}

/* 2 ------------------------------------------------------------------------ */

/* Nav tokens. Not a CSS Module: the css-loader rejects :root there.
   --lm- keeps them clear of MUI's --lando- and the per-module tokens.
   Faces come from next/font in theme/themePrimitives.ts. */

/* Hand-written: next/font drops size-adjust under Turbopack.
   102% sets Thai level with the JetBrains Mono beside it. */

@font-face {
  font-family: "IBM Plex Sans Thai";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  size-adjust: 102%;
  src: url("/home/assets/fonts/ibm-plex-sans-thai-thai-400-normal.woff2")
    format("woff2");
  unicode-range: U+0020, U+00A0, U+02BC, U+02D7, U+0303, U+0331, U+0E01-0E3A,
    U+0E3F-0E5B, U+200B-200D, U+25CC;
}

@font-face {
  font-family: "IBM Plex Sans Thai";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  size-adjust: 102%;
  src: url("/home/assets/fonts/ibm-plex-sans-thai-latin-400-normal.woff2")
    format("woff2");
  unicode-range: U+0020-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0303, U+200B, U+2013-2014, U+2018-201A, U+201C-201E, U+2022,
    U+2026, U+2039-203A, U+2044, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215;
}

:root {
  --lm-font-technical-th: "IBM Plex Sans Thai", "Noto Sans Thai",
    "Leelawadee UI", Tahoma, sans-serif;

  /* The bar on a page that scrolls: full height at the top of the document,
     stepping back as you read. */
  --lm-nav-height: 76px;
  /* The calm bar is the full row at scale(.5), less the border it keeps. */
  --lm-nav-calm-height: 29px;
  /* The bar on an app surface, which never scrolls: the calm step that pays for
     the 76px row cannot run there, and every panel under the map is measured
     from this number. Same 48px as APP_BAR_HEIGHT_PX in
     components/AppNavbar.tsx — change the two together. */
  --lm-app-nav-height: 48px;

  /* Calm reading state: the whole row is drawn at half size and doubled in
     width, so nothing inside it is measured twice. */
  --lm-nav-content-calm-scale: 0.5;
  --lm-nav-content-calm-opacity: 0.72;
  --lm-nav-surface-prominent-alpha: 92%;
  --lm-nav-surface-calm-alpha: 26%;
  --lm-nav-state-duration: 560ms;

  --lm-surface-canvas: #f6f7f3;
  --lm-surface-alt: #eef1ee;
  --lm-surface-card: #fcfcfa;
  --lm-surface-raised: #ffffff;
  --lm-surface-soft: #e5e9e6;
  --lm-surface-blue-tint: #e2e9ed;
  /* Identity, not a surface: one value in both themes. */
  --lm-brand-blue: #1d4497;
  --lm-brand-beige: #f2f1df;
  --lm-text-primary: #182327;
  --lm-text-secondary: #5f635a;
  --lm-text-metadata: #5c6a61;
  --lm-border-hairline: #dce1dd;
  --lm-border-default: #c9d0cb;
  --lm-interaction-accent: #176b82;
  --lm-interaction-focus-ring: #176b82;
  --lm-energy-yellow: #ffbc1f;
  --lm-fg-on-light-primary: #182327;
  /* The rail's tooltip keeps one ink pair in both themes: it floats over page
     content, not over a navbar surface. */
  --lm-overlay-glass: rgba(17, 25, 29, 0.88);
  --lm-overlay-glass-ink: #ffffff;
  --lm-elevation-xs: 0 1px 2px rgba(30, 34, 48, 0.08);
  --lm-elevation-sm: 0 4px 12px rgba(30, 34, 48, 0.1);

  --lm-motion-duration-state: 200ms;
  --lm-motion-duration-feedback: 120ms;
  --lm-motion-duration-emphasis: 560ms;
  --lm-motion-ease-state: cubic-bezier(0.2, 0, 0, 1);
  --lm-motion-ease-press: cubic-bezier(0.3, 0, 0.6, 1);

}

/* Keyed to MUI's own colorSchemeSelector so one control moves the whole page.
   The media query covers the moment before the attribute is written, and the
   :not() keeps an explicit light choice from being overridden by the OS. */
@media (prefers-color-scheme: dark) {
  :root:not([data-color-scheme="light"]) {
    --lm-surface-canvas: #11191d;
    --lm-surface-alt: #172126;
    --lm-surface-card: #20292d;
    --lm-surface-raised: #293337;
    --lm-surface-soft: #2b3534;
    --lm-surface-blue-tint: #18333e;
    --lm-text-primary: #f1f4ef;
    --lm-text-secondary: #c4ceca;
    --lm-text-metadata: #a6b5b1;
    --lm-border-hairline: #33403d;
    --lm-border-default: #46524f;
    --lm-interaction-accent: #68c4e2;
    --lm-interaction-focus-ring: #68c4e2;
  }
}

:root[data-color-scheme="dark"] {
  --lm-surface-canvas: #11191d;
  --lm-surface-alt: #172126;
  --lm-surface-card: #20292d;
  --lm-surface-raised: #293337;
  --lm-surface-soft: #2b3534;
  --lm-surface-blue-tint: #18333e;
  --lm-text-primary: #f1f4ef;
  --lm-text-secondary: #c4ceca;
  --lm-text-metadata: #a6b5b1;
  --lm-border-hairline: #33403d;
  --lm-border-default: #46524f;
  --lm-interaction-accent: #68c4e2;
  --lm-interaction-focus-ring: #68c4e2;
}

/* The row is shorter here, so the type inside it is too. */
@media (max-width: 600px) {
  :root {
    --lm-nav-height: 68px;
    --lm-nav-calm-height: 27px;
  }
}

/* An in-page anchor has to clear the sticky bar, plus a little air.
   Smooth belongs on the scrolling element, and the document is it: a rail stop
   sets the hash, so a wrapper div carrying `scroll-behavior` never sees the
   scroll. */
html {
  scroll-padding-top: calc(var(--lm-nav-height) + 20px);
  scroll-behavior: smooth;
}

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }
}

/* Selected text takes the brand pair, not the browser's blue. */
::selection {
  background: var(--lm-energy-yellow);
  color: var(--lm-fg-on-light-primary);
}

/* 3 ------------------------------------------------------------------------ */

/* The unified Landometer navigation shell. Tokens and faces come from
   styles/globals.css; everything here is geometry, state and motion.

   The bar looks the same on every public page — only the name after "/", which
   site is selected, and the CTA label change. Page-specific links are never on
   the bar: they are the bookmark rail on desktop and the first group in the
   menu below 820px. */

.siteHeader,
.siteHeader * {
  box-sizing: border-box;
}

/* The block keeps its full height at every state, and the bar inside it is what
   resizes. Animating this one instead would relayout the whole document on each
   of the transition's frames, and — the bar being in flow — shorten the page by
   the height it gave up, sliding the content the reader is on out from under
   them. Nothing below the header moves now; the bar steps back over it.

   `pointer-events` follow the bar rather than the block, so the ground the calm
   bar no longer covers belongs to the page again. */
.siteHeader {
  position: sticky;
  top: 0;
  z-index: 100;
  width: 100%;
  height: var(--lm-nav-height);
  color: var(--lm-text-primary);
  font-family: var(--lm-font-body);
  isolation: isolate;
  pointer-events: none;
}

/* The app form of the bar: a map shell holds the viewport and never scrolls, so
   the bar has no reading position to step back from and would sit at 76px over
   a surface every panel measures from 48px. Overriding the one height token is
   enough — the header, the menu panel and its backdrop all read it, which is
   why each carries this class rather than a rule of its own. */
.isCompact {
  --lm-nav-height: var(--lm-app-nav-height);
}

/* The lockup is the only part that does not follow the token: 54px does not fit
   a 48px bar. 34px is what the app chrome's own lockup sits at, so the mark
   keeps the size it had on these pages. */
.siteHeader.isCompact .brandSymbol {
  width: 34px;
  height: 34px;
}

.siteHeader.isCompact .brandWordmark {
  font-size: 19px;
}

.siteHeader.isCompact .productName {
  font-size: 15px;
}

/* The two controls that paint a box give some of it back here: 32px leaves 8px
   of air above and below inside the 48px row, where a 44px capsule would sit
   2px off both edges and read as touching them. The 44px target around each is
   untouched. */
.siteHeader.isCompact .headerControlVisualCta {
  min-height: 32px;
}

.siteHeader.isCompact .headerControlVisual {
  min-height: 32px;
}

/* The line under a link follows the box that is painted, not the 44px target:
   on this bar the box gives up 6px at each end and the line comes with it. */
.siteHeader.isCompact .headerLink::after {
  bottom: 6px;
}

.siteHeader.isCompact .menuToggleVisual {
  width: 32px;
  height: 32px;
}

/* The surface is a layer behind the row rather than paint on the block itself,
   so it can fade on its own timing while the block resizes. */
.siteHeader::before {
  content: "";
  position: absolute;
  z-index: -1;
  inset: 0 0 auto;
  height: var(--lm-nav-height);
  border-bottom: 1px solid var(--lm-border-hairline);
  background: color-mix(
    in srgb,
    var(--lm-surface-canvas) var(--lm-nav-surface-prominent-alpha),
    transparent
  );
  -webkit-backdrop-filter: blur(10px) saturate(1.2);
  backdrop-filter: blur(10px) saturate(1.2);
  transition:
    height var(--lm-nav-state-duration) var(--lm-motion-ease-state),
    background-color var(--lm-nav-state-duration) var(--lm-motion-ease-state),
    border-color var(--lm-nav-state-duration) var(--lm-motion-ease-state);
}

/* The bar proper — the box that shrinks. `contain` keeps the row's own resize
   inside it: the row changes width as it scales, and without this the browser
   would walk back out to the document to find out what that width costs. */
.navViewport {
  width: 100%;
  height: var(--lm-nav-height);
  padding-inline: 24px;
  overflow-x: clip;
  contain: layout;
  pointer-events: auto;
  transition: height var(--lm-nav-state-duration) var(--lm-motion-ease-state);
}

.navRow {
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  gap: 14px;
  opacity: 1;
  transform: scale(1);
  transform-origin: left center;
  transition:
    width var(--lm-nav-state-duration) var(--lm-motion-ease-state),
    opacity var(--lm-nav-state-duration) var(--lm-motion-ease-state),
    transform var(--lm-nav-state-duration) var(--lm-motion-ease-state);
}

/* Reading: the bar steps back to a scaled-down copy of itself. One transform on
   the row, so every control keeps its proportions and nothing inside it is
   sized a second time. */
.siteHeader.isCalm::before {
  border-bottom-color: color-mix(
    in srgb,
    var(--lm-border-hairline) 20%,
    transparent
  );
  background: color-mix(
    in srgb,
    var(--lm-surface-canvas) var(--lm-nav-surface-calm-alpha),
    transparent
  );
}

.siteHeader.isCalm::before,
.siteHeader.isCalm .navViewport {
  height: var(--lm-nav-calm-height);
}

/* Doubled in width, because the half-size row would otherwise leave half the
   bar bare. */
.siteHeader.isCalm .navRow {
  width: calc(100% / var(--lm-nav-content-calm-scale));
  opacity: var(--lm-nav-content-calm-opacity);
  transform: scale(var(--lm-nav-content-calm-scale));
}

.skipLink {
  position: fixed;
  pointer-events: auto;
  top: 10px;
  left: 16px;
  z-index: 1002;
  min-height: 44px;
  display: inline-flex;
  align-items: center;
  padding: 8px 18px;
  border: 1px solid var(--lm-border-default);
  border-radius: 999px;
  background: var(--lm-surface-raised);
  color: var(--lm-interaction-accent);
  font-weight: 600;
  text-decoration: none;
  transform: translateY(-180%);
  transition: transform var(--lm-motion-duration-state)
    var(--lm-motion-ease-state);
}

.skipLink:focus {
  outline: 3px solid var(--lm-interaction-focus-ring);
  outline-offset: 2px;
  transform: translateY(0);
}

.brand,
.brandLockup,
.productLockup,
.headerActions {
  display: inline-flex;
  align-items: center;
}

.brand {
  min-width: 0;
  min-height: 44px;
  flex: none;
  border-radius: 6px;
  color: inherit;
  text-decoration: none;
  transition: transform var(--lm-motion-duration-feedback)
    var(--lm-motion-ease-press);
}

.brandLockup {
  gap: 10px;
  transform-origin: left center;
  transition: transform var(--lm-nav-state-duration) var(--lm-motion-ease-state);
}

/* Sits transparent on the surface with no plate or frame behind it, and the
   one approved colour rendition serves both themes unmodified. */
/* No scale on the artwork, unlike the showcase's own bar. Its symbol file is
   full-bleed, so it shrinks the mark to .558 to sit right beside the wordmark;
   ours already carries that reduction as transparent padding — the drawn mark
   is .558 of the file's own canvas — so the 34px slot renders it at ~19px on
   its own. Scaling here would apply the reduction twice. */
.brandSymbol {
  width: 54px;
  height: 54px;
  flex: none;
  object-fit: contain;
}

/* Type, not an image. It takes the metadata ink rather than a fixed grey, so
   it lifts against a dark canvas instead of staying at its light-theme
   value. */
.brandWordmark {
  color: var(--lm-text-metadata);
  font-family: var(--lm-font-display);
  font-size: 23px;
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1.02;
  white-space: nowrap;
  transition: font-size var(--lm-motion-duration-emphasis)
    var(--lm-motion-ease-state);
}

.productLockup {
  min-width: 0;
  gap: 14px;
  white-space: nowrap;
}

.productDivider {
  color: var(--lm-text-metadata);
  font-family: var(--lm-font-technical);
  font-size: 15px;
}

.productName {
  color: var(--lm-text-primary);
  font-size: 16.5px;
  font-weight: 600;
}

.headerActions {
  min-width: 0;
  justify-content: flex-end;
  /* The row's own spacing, between the group of site links, the CTA and the
     menu button. The links sit closer to each other than that, which is why
     they are a group of their own rather than three more children here. */
  gap: 14px;
  margin-left: auto;
}

.headerMainLinks {
  display: flex;
  align-items: center;
  gap: 2px;
}

.headerLink {
  position: relative;
  min-height: 44px;
  display: inline-flex;
  align-items: center;
  padding: 0;
  color: var(--lm-text-primary);
  font-size: 15px;
  font-weight: 400;
  text-decoration: none;
  white-space: nowrap;
  transition: transform var(--lm-motion-duration-feedback)
    var(--lm-motion-ease-press);
}

/* The box a control paints at rest, inside the target it is given. Scaling
   this rather than the link is what lets calm shrink the chrome and its label
   as one piece. */
.headerControlVisual {
  box-sizing: border-box;
  min-height: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding-inline: 13px;
  border-radius: 10px;
  transform-origin: center;
  transition:
    transform var(--lm-nav-state-duration) var(--lm-motion-ease-state),
    background-color var(--lm-motion-duration-state) var(--lm-motion-ease-state),
    color var(--lm-motion-duration-state) var(--lm-motion-ease-state);
}

/* Selected reads from ink, weight and the underline together — no motion, and
   no inset bar down the side. */
.headerLink[aria-current="page"] {
  color: var(--lm-interaction-accent);
  font-weight: 600;
}

/* One line under the word answers hover, focus and selected alike, drawn inside
   the label's own padding rather than around it. Pointing at a link draws the
   line from the centre out; the stop you are on keeps it drawn. */
.headerLink::after {
  content: "";
  position: absolute;
  right: 13px;
  bottom: 0;
  left: 13px;
  height: 2px;
  border-radius: 2px 2px 0 0;
  background: var(--lm-interaction-accent);
  opacity: 0;
  transform: scaleX(0);
  transform-origin: center;
  transition:
    height var(--lm-motion-duration-state) var(--lm-motion-ease-state),
    opacity var(--lm-motion-duration-state) var(--lm-motion-ease-state),
    transform var(--lm-motion-duration-state) var(--lm-motion-ease-state);
}

.headerLink:hover::after,
.headerLink:focus-visible::after {
  opacity: 1;
  transform: scaleX(1);
}

/* Twice the weight of the hover line, and after it so it holds that weight
   while the pointer is on it: being on a page is a state, pointing at a link
   is not. */
.headerLink[aria-current="page"]::after {
  height: 4px;
  opacity: 1;
  transform: scaleX(1);
}

/* Holds the button and the sweep in one positioning context. The spacing and
   the no-wrap live here rather than on the button, so the layer above it is
   measured against the same box. */
.navCta {
  position: relative;
  display: inline-flex;
  flex: none;
  white-space: nowrap;
}

/* The target: full height, no paint of its own. Hover and focus are read here
   and drawn on the capsule inside it. */
.secondaryButton {
  position: relative;
  z-index: 0;
  isolation: isolate;
  min-height: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  border: 0;
  background: transparent;
  color: var(--lm-text-primary);
  font-size: 15px;
  font-weight: 600;
  text-decoration: none;
  white-space: nowrap;
  transition: transform var(--lm-motion-duration-feedback)
    var(--lm-motion-ease-press);
}

/* The only control in the row that paints a box at rest, so it is the only one
   whose height is read against the bar's. In the 76px row it takes the whole
   44px target, the way the showcase's own capsule does. Clipped, because the
   sweep runs inside it. */
.headerControlVisualCta {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  box-sizing: border-box;
  min-height: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding-inline: 24px;
  border: 1px solid var(--lm-interaction-accent);
  border-radius: 999px;
  background: transparent;
  color: inherit;
  transform-origin: center;
  transition:
    transform var(--lm-nav-state-duration) var(--lm-motion-ease-state),
    background-color var(--lm-motion-duration-state) var(--lm-motion-ease-state),
    color var(--lm-motion-duration-state) var(--lm-motion-ease-state);
}

/* A yellow band carrying its own copy of the word, moving across the label on a
   loop of its own — the showcase's moving highlight, not a hover response. What
   travels is the clip, so the copy underneath never moves and the word stays
   readable in every frame. Inset 24px on both sides is the capsule's own
   padding, so the band lands on the word rather than around it. */
.navCtaLabel {
  position: relative;
  z-index: 0;
}

.navCtaSweep {
  position: absolute;
  top: 50%;
  right: 24px;
  left: 24px;
  z-index: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  margin-inline: -5px;
  padding: 2px 5px;
  overflow: hidden;
  border-radius: 2px;
  background: var(--lm-energy-yellow);
  color: var(--lm-fg-on-light-primary);
  font: inherit;
  line-height: 1.35;
  clip-path: inset(0 68% 0 2%);
  pointer-events: none;
  transform: translateY(-50%);
  animation:
    navCtaSweep 3.7s var(--lm-motion-ease-state) infinite,
    navCtaFlick 1.09s steps(1, end) infinite;
}

/* The band's own travel: it opens from the left edge, jumps back and forth
   across the word, and closes off the right. */
@keyframes navCtaSweep {
  0%,
  5% {
    clip-path: inset(0 98% 0 0);
  }
  9% {
    clip-path: inset(0 68% 0 2%);
  }
  11% {
    clip-path: inset(0 76% 0 0);
  }
  16% {
    clip-path: inset(0 42% 0 24%);
  }
  18% {
    clip-path: inset(0 51% 0 16%);
  }
  23%,
  27% {
    clip-path: inset(0 0 0 0);
  }
  30% {
    clip-path: inset(0 22% 0 46%);
  }
  33% {
    clip-path: inset(0 30% 0 38%);
  }
  39% {
    clip-path: inset(0 0 0 74%);
  }
  44% {
    clip-path: inset(0 62% 0 4%);
  }
  47% {
    clip-path: inset(0 54% 0 12%);
  }
  53%,
  55% {
    clip-path: inset(0 0 0 0);
  }
  58% {
    clip-path: inset(0 36% 0 30%);
  }
  61% {
    clip-path: inset(0 44% 0 22%);
  }
  69% {
    clip-path: inset(0 6% 0 60%);
  }
  72% {
    clip-path: inset(0 16% 0 50%);
  }
  79% {
    clip-path: inset(0 0 0 90%);
  }
  84%,
  89% {
    clip-path: inset(0 0 0 0);
  }
  93%,
  100% {
    clip-path: inset(0 0 0 100%);
  }
}

/* The flicker over it, on its own cycle so the two never line up twice the
   same way. Stepped, because a fade would read as a pulse. */
@keyframes navCtaFlick {
  0%,
  21% {
    opacity: 1;
  }
  22% {
    opacity: 0.1;
  }
  23%,
  38% {
    opacity: 1;
  }
  39% {
    opacity: 0.52;
  }
  40% {
    opacity: 0.08;
  }
  41%,
  64% {
    opacity: 1;
  }
  65% {
    opacity: 0.26;
  }
  66%,
  85% {
    opacity: 1;
  }
  86% {
    opacity: 0.12;
  }
  87%,
  100% {
    opacity: 1;
  }
}

/* No border of its own: in the panel these sit on a raised surface among
   links, where a ring would read as a fifth control rather than a utility. */
.utilityCircle {
  width: 44px;
  height: 44px;
  min-width: 44px;
  display: grid;
  place-items: center;
  padding: 0;
  border: 0;
  border-radius: 999px;
  background: transparent;
  color: var(--lm-text-primary);
  font: inherit;
  cursor: pointer;
  transition:
    background-color var(--lm-motion-duration-state) var(--lm-motion-ease-state),
    color var(--lm-motion-duration-state) var(--lm-motion-ease-state),
    transform var(--lm-motion-duration-feedback) var(--lm-motion-ease-press);
}

.menuToggle {
  width: 44px;
  height: 44px;
  min-width: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  border: 0;
  background: transparent;
  color: var(--lm-text-primary);
  font: inherit;
  cursor: pointer;
  transition: transform var(--lm-motion-duration-feedback)
    var(--lm-motion-ease-press);
}

/* No ring at rest: the button carries nothing but its glyph, and the circle is
   only what hover and focus paint.

   32px, not the button's 44px — the same height as the CTA capsule beside it,
   so the two controls sit on one optical line and the highlight keeps 8px of
   air off the top and bottom of the 48px row instead of reading as though it
   were touching them. The 44px target is unchanged; only the paint is
   smaller. */
.menuToggleVisual {
  width: 44px;
  height: 44px;
  box-sizing: border-box;
  display: grid;
  place-items: center;
  border-radius: 999px;
  background: transparent;
  color: inherit;
  transform-origin: center;
  transition:
    transform var(--lm-nav-state-duration) var(--lm-motion-ease-state),
    background-color var(--lm-motion-duration-state) var(--lm-motion-ease-state),
    color var(--lm-motion-duration-state) var(--lm-motion-ease-state);
}

/* One outline recipe for every nav glyph, drawn inline. The stroke is held at
   its authored width through the calm scale, so a shrinking control does not
   also thin its icon. */
/* The self-hosted nav subset: the 23 Material Symbols Rounded ligatures
   `NavIcon` names, instanced at the cut the r7 handoff specifies — wght 300 /
   opsz 24 / GRAD 0 / FILL 0 — so the face is static and carries no axes to set.

   `block`, not `swap`: a ligature name rendered as its own raw text while the
   face loads is a word sitting in the bar, not a fallback glyph. */
@font-face {
  font-family: "Landometer Nav Symbols";
  src: url("/home/assets/fonts/material-symbols-rounded-nav-r1.woff2")
    format("woff2");
  font-weight: 300;
  font-style: normal;
  font-display: block;
}

/* Sized by type, not by box: the glyph is a character, and every override
   below moves `font-size`. `1em` square keeps the control's geometry the same
   as the drawings this replaced. */
.navInlineIcon {
  display: block;
  width: 1em;
  height: 1em;
  font-family: "Landometer Nav Symbols";
  font-size: 22px;
  font-weight: 300;
  font-style: normal;
  line-height: 1;
  letter-spacing: normal;
  text-transform: none;
  white-space: nowrap;
  direction: ltr;
  -webkit-font-smoothing: antialiased;
}

/* 18px inside the 32px circle, so the glyph keeps 7px of ground on each side
   rather than filling the tint to its edge. */
.menuToggleVisual .navInlineIcon {
  font-size: 18px;
}

/* Hover tints rather than darkens, and paints the box the control actually
   shows rather than the invisible rectangle around it. */
/* The word takes the same tint as the other bar controls, painted on the box
   the control shows rather than on the 44px target — so it keeps air above and
   below instead of filling the row. The line under it stays: the tint answers
   the pointer, the line answers where you are. */
.headerLink:hover,
.headerLink:focus-visible {
  color: var(--lm-interaction-accent);
}

.headerLink:hover .headerControlVisual,
.headerLink:focus-visible .headerControlVisual {
  background: var(--lm-surface-blue-tint);
}

.utilityCircle:hover,
.utilityCircle:focus-visible {
  background: var(--lm-surface-blue-tint);
  color: var(--lm-interaction-accent);
}

.menuToggle:hover .menuToggleVisual,
.menuToggle:focus-visible .menuToggleVisual,
.menuToggle[aria-expanded="true"] .menuToggleVisual {
  background: var(--lm-surface-blue-tint);
  color: var(--lm-interaction-accent);
}

/* The capsule inverts rather than tinting: it is the one control already
   carrying a border, so a tint alone would barely read. */
.secondaryButton:hover .headerControlVisualCta,
.secondaryButton:focus-visible .headerControlVisualCta {
  background: var(--lm-interaction-accent);
  color: var(--lm-surface-canvas);
}

/* Press moves down 2px and nothing else — no scale, no bounce. */
.brand:active,
.headerLink:active,
.menuToggle:active,
.utilityCircle:active,
.pageLink:active,
.ecosystemLink:active,
.accountLink:active,
.menuAll:active,
.railLink:active {
  background: var(--lm-surface-soft);
  transform: translateY(2px);
}

.secondaryButton:active {
  transform: translateY(2px);
}

/* What is already current does not move when pressed. */
.headerLink[aria-current]:active,
.pageLink[aria-current]:active,
.railLink[aria-current]:active {
  background: var(--lm-surface-blue-tint);
  transform: none;
}

.ecosystemLink[aria-current]:active {
  background: var(--lm-surface-blue-tint);
  transform: none;
}

.brand:focus-visible,
.headerLink:focus-visible,
.secondaryButton:focus-visible,
.menuToggle:focus-visible,
.utilityCircle:focus-visible,
.pageLink:focus-visible,
.ecosystemLink:focus-visible,
.accountLink:focus-visible,
.menuAll:focus-visible,
.railLink:focus-visible {
  outline: 3px solid var(--lm-interaction-focus-ring);
  outline-offset: 2px;
}

/* Rows draw the ring inside, where a 2px offset would collide with the row
   next to them. */
.pageLink:focus-visible,
.ecosystemLink:focus-visible,
.accountLink:focus-visible,
.menuAll:focus-visible {
  outline-offset: -3px;
}

/* --- menu ---------------------------------------------------------------- */

.menuBackdrop {
  position: fixed;
  inset: var(--lm-nav-height) 0 0;
  z-index: 900;
  width: 100%;
  padding: 0;
  border: 0;
  background: transparent;
  cursor: default;
}

/* Pinned to the bar's own right edge, which is now the gutter at every width. */
.menuPanel {
  position: fixed;
  top: calc(var(--lm-nav-height) + 6px);
  right: 24px;
  z-index: 901;
  width: min(340px, calc(100% - 48px));
  max-height: calc(100svh - var(--lm-nav-height) - 24px);
  overflow: auto;
  display: flex;
  flex-direction: column;
  padding: 8px;
  border: 1px solid var(--lm-border-default);
  border-radius: 16px;
  background: var(--lm-surface-raised);
  color: var(--lm-text-primary);
  /* sm, not md — md is reserved for dialogs that take the whole screen. */
  box-shadow: var(--lm-elevation-sm);
  font-family: var(--lm-font-body);
}

.menuGroup,
.menuLinks {
  display: grid;
  gap: 4px;
}

.menuGroup {
  padding: 8px;
}

/* A section is divided from whatever precedes it, rather than each one being
   told by hand whether it needs a line.
   `~` rather than `+`, and the mobile-only group named explicitly: a section
   hidden at this width is still a sibling, so a rule that only looked at the
   element immediately before would take its line from something invisible and
   draw it across the top of the panel. Naming a section that is actually shown
   means the first visible one is the one with nothing above it. */
.menuGroup:not(.menuMobileOnly) ~ .utilityRow,
.menuGroup:not(.menuMobileOnly) ~ .menuGroup,
.utilityRow ~ .menuGroup {
  border-top: 1px solid var(--lm-border-hairline);
}

.menuMobileOnly {
  display: none;
}

/* Every section is headed the same way — the ecosystem group no longer gets a
   treatment of its own. */
.menuLabel {
  margin: 0;
  padding: 4px 10px;
  color: var(--lm-text-metadata);
  font-family: var(--lm-font-technical);
  font-size: 0.75rem;
  font-weight: 400;
  letter-spacing: 0.05em;
  text-transform: uppercase;
}

.pageLink,
.ecosystemLink,
.accountLink {
  min-height: 44px;
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 8px 13px;
  border-radius: 10px;
  color: var(--lm-text-primary);
  font-size: 14.5px;
  font-weight: 600;
  text-align: left;
  text-decoration: none;
  transition:
    background-color var(--lm-motion-duration-state) var(--lm-motion-ease-state),
    color var(--lm-motion-duration-state) var(--lm-motion-ease-state),
    transform var(--lm-motion-duration-feedback) var(--lm-motion-ease-press);
}

.accountLink {
  width: 100%;
  border: 0;
  background: none;
  font-family: inherit;
  font-size: 15.5px;
  font-weight: 400;
  cursor: pointer;
}

.accountLink .navInlineIcon,
.pageLink .navInlineIcon {
  flex: none;
  font-size: 20px;
  color: var(--lm-text-metadata);
}

.pageLink {
  font-size: 15px;
  font-weight: 400;
}

/* The stop you are at is tinted, with accent ink on it. No band down the
   leading edge and nothing said in words: the rows in this group are the
   sections of one page, so the highlight alone places you. */
.pageLink[aria-current] {
  background: var(--lm-surface-blue-tint);
  color: var(--lm-interaction-accent);
}

.pageLink[aria-current] .navInlineIcon {
  color: var(--lm-interaction-accent);
}

.pageLink:hover,
.pageLink:focus-visible,
.ecosystemLink:hover,
.ecosystemLink:focus-visible,
.accountLink:hover,
.accountLink:focus-visible {
  background: var(--lm-surface-blue-tint);
}

.accountIdentity {
  display: grid;
  gap: 2px;
  padding: 8px 14px 10px;
}

.accountIdentity strong {
  font-size: 14.5px;
  font-weight: 600;
}

.accountIdentity small {
  color: var(--lm-text-metadata);
  font-size: 13px;
  overflow-wrap: anywhere;
}

.menuCtaWrap {
  padding: 4px 0 0;
}

.menuCtaWrap .navCta {
  width: 100%;
}

/* In the panel there is no bar height to sit inside, so the capsule takes the
   full 44px itself and hands back the padding that stood in for it. */
.menuCtaWrap .secondaryButton {
  width: 100%;
  min-height: 44px;
}

.menuCtaWrap .headerControlVisualCta {
  width: 100%;
  min-height: 44px;
}

/* The button goes full width here, which would stretch the band across the
   whole capsule. The sweep sizes to its own text instead and centres on the
   button, so it hugs the label the way it does on the bar. */
.menuCtaWrap .navCtaSweep {
  right: auto;
  left: 50%;
  width: max-content;
  margin-inline: 0;
  transform: translate(-50%, -50%);
}

.utilityRow {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 16px;
}

.utilityCircle {
  font-family: var(--lm-font-technical);
  font-size: 0.75rem;
  font-weight: 400;
  letter-spacing: 0.04em;
}

.utilityCircle .navInlineIcon {
  font-size: 20px;
}

.ecosystemLink {
  align-items: flex-start;
  justify-content: space-between;
}

/* Above 820px the bar shows these itself. Below it the bar keeps only the
   hamburger, so this is where they are reached. */
.ecosystemOnBar {
  display: none;
}

.ecosystemCopy {
  min-width: 0;
  display: grid;
  gap: 2px;
}

.ecosystemCopy strong {
  font: inherit;
  font-weight: 600;
}

.ecosystemCopy small {
  color: var(--lm-text-metadata);
  font-size: 13px;
  font-weight: 400;
  line-height: 1.35;
}

/* The same mark as a current page stop: accent ink and the phrase after it. */
.ecosystemLink[aria-current="page"] {
  color: var(--lm-interaction-accent);
}

/* The phrase itself. Trailing and right-aligned so the names stay in one
   column, in the technical face the panel gives its metadata, and carried in an
   attribute so the two navbar copies share one rule. It is the ecosystem group
   alone that needs it: those rows are other sites, where a highlight would say
   less than the words do. */
.ecosystemLink[aria-current="page"]::after {
  content: attr(data-here);
  margin-left: auto;
  padding-left: 10px;
  color: var(--lm-interaction-accent);
  font-family: var(--lm-font-technical);
  font-size: 11px;
  font-weight: 400;
  letter-spacing: 0.02em;
  white-space: nowrap;
}

.menuAll {
  min-height: 44px;
  display: flex;
  align-items: center;
  padding: 12px 18px;
  border-top: 1px solid var(--lm-border-hairline);
  color: var(--lm-interaction-accent);
  font-size: 13.5px;
  font-weight: 600;
  text-decoration: none;
}

/* Announcements for a change a sighted reader sees happen — the theme and the
   language both change the page around the button rather than the button. */
.srOnly {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* --- bookmark rail ------------------------------------------------------- */

.bookmarkRail {
  position: fixed;
  top: 50%;
  right: 16px;
  z-index: 95;
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 6px;
  /* No outline of its own: the dock reads from its own surface and the shadow
     under it, so it floats over page content instead of framing it. */
  border-radius: 16px;
  background: var(--lm-surface-canvas);
  background: color-mix(in srgb, var(--lm-surface-canvas) 92%, transparent);
  box-shadow: var(--lm-elevation-sm);
  -webkit-backdrop-filter: blur(10px) saturate(1.2);
  backdrop-filter: blur(10px) saturate(1.2);
  transform: translateY(-50%);
}

.railLink {
  position: relative;
  width: 44px;
  height: 44px;
  display: grid;
  place-items: center;
  border: 1px solid transparent;
  border-radius: 10px;
  background: transparent;
  color: var(--lm-text-secondary);
  text-decoration: none;
  transition:
    border-color var(--lm-motion-duration-state) var(--lm-motion-ease-state),
    border-radius var(--lm-motion-duration-state) var(--lm-motion-ease-state),
    background-color var(--lm-motion-duration-state) var(--lm-motion-ease-state),
    color var(--lm-motion-duration-state) var(--lm-motion-ease-state),
    transform var(--lm-motion-duration-feedback) var(--lm-motion-ease-press);
}

/* The same circle the selected stop takes, without its ring: pointing at a stop
   shows where the tap would land, being on one is what the border says. */
.railLink:hover,
.railLink:focus-visible {
  border-radius: 999px;
  background: var(--lm-surface-blue-tint);
  color: var(--lm-interaction-accent);
}

/* The stop you are at reads from its surface and its shape — the square becomes
   a circle — never from a ring around it or a filled, heavier glyph. Every icon
   on the rail keeps one outline cut, selected or not. */
.railLink[aria-current] {
  border-radius: 999px;
  background: var(--lm-surface-blue-tint);
  color: var(--lm-interaction-accent);
}

.railLink[aria-current] .navInlineIcon {
  transform: scale(1.08);
}

/* The label an icon-only control cannot show, on hover and on focus. It floats
   over page content rather than a bar surface, so it keeps one ink pair. */
.railLink::after {
  content: attr(data-label);
  position: absolute;
  top: 50%;
  right: calc(100% + 10px);
  z-index: 1;
  max-width: 220px;
  padding: 7px 10px;
  border-radius: 999px;
  background: var(--lm-overlay-glass);
  color: var(--lm-overlay-glass-ink);
  box-shadow: var(--lm-elevation-xs);
  font-size: 13px;
  font-weight: 600;
  line-height: 1.25;
  white-space: nowrap;
  opacity: 0;
  pointer-events: none;
  transform: translate(6px, -50%);
  transition:
    opacity var(--lm-motion-duration-state) var(--lm-motion-ease-state),
    transform var(--lm-motion-duration-state) var(--lm-motion-ease-state);
}

.railLink:hover::after,
.railLink:focus-visible::after {
  opacity: 1;
  transform: translate(0, -50%);
}

/* --- breakpoints --------------------------------------------------------- */

/* The name after "/" is the first thing to go: the page's own H1 and the
   current row in the menu still say which site this is. */
@media (max-width: 900px) {
  .productLockup {
    display: none;
  }
}

/* Controls collapse into the menu before the size tokens change at 600px,
   because the four-control row stops fitting first. */
@media (max-width: 820px) {
  .desktopOnly {
    display: none !important;
  }

  .menuMobileOnly {
    display: grid;
  }

  /* Shown here, so it divides and is divided like any other section. */
  .menuMobileOnly ~ .utilityRow,
  .menuMobileOnly ~ .menuGroup,
  .menuGroup ~ .menuMobileOnly {
    border-top: 1px solid var(--lm-border-hairline);
  }

  /* The bar has dropped its links, so the ecosystem carries them again. */
  .ecosystemOnBar {
    display: flex;
  }

  .menuPanel {
    top: var(--lm-nav-height);
    right: 0;
    width: 100%;
    max-height: calc(100svh - var(--lm-nav-height));
    border-radius: 0 0 16px 16px;
  }

  .bookmarkRail {
    display: none;
  }
}

@media (max-width: 600px) {
  .navViewport {
    padding-inline: 16px;
  }

  .navRow {
    gap: 10px;
  }

  .brandSymbol {
    width: 45px;
    height: 45px;
  }

  .brandWordmark {
    font-size: 19px;
  }
}

@media (max-width: 360px) {
  .brandWordmark {
    font-size: 18px;
  }
}

@media print {
  .siteHeader,
  .menuPanel,
  .menuBackdrop,
  .bookmarkRail {
    display: none !important;
  }
}

/* The kit's single kill switch. */
@media (prefers-reduced-motion: reduce) {
  .siteHeader,
  .siteHeader *,
  .menuPanel,
  .menuPanel *,
  .bookmarkRail,
  .bookmarkRail * {
    animation: none !important;
    transition: none !important;
  }

  /* Stopping the loop would leave the band parked over part of the word, so the
     band goes instead of freezing. */
  .navCtaSweep {
    display: none !important;
  }

  /* Stopping the sweep would leave the band frozen mid-word, which reads as a
     stuck highlight. The decorative copy goes instead. */
  .navCtaSweep {
    display: none !important;
  }
}
