/*!
 * CheckrideReady Component Layer
 * ==============================
 * Shared components: layout container, buttons, cards, badges, forms,
 * skeleton loaders, empty states, modal shell, nav, footer.
 * Requires tokens.css and base.css loaded first. See README.md.
 *
 * Calibration note: this is a study tool student pilots use under time
 * pressure, often on a phone at an airport between lessons. Components
 * here are deliberately restrained -- clarity and legibility over
 * spectacle. No scroll-hijacking, no decorative motion, no maximalism.
 * Mobile-first throughout: base rules target small screens, `min-width`
 * media queries layer on enhancements for larger ones.
 */

/* =========================================================================
   CONTAINER
   ========================================================================= */
.container {
  width: 100%;
  max-width: 1280px;
  margin-inline: auto;
  padding-inline: var(--space-4);
}

@media (min-width: 768px) {
  .container {
    padding-inline: var(--space-6);
  }
}

@media (min-width: 1024px) {
  .container {
    padding-inline: var(--space-10);
  }
}

/* narrower container for reading-width content: legal pages, article body */
.container--prose {
  max-width: 760px;
}

/* =========================================================================
   BUTTONS
   Base sets the shared shape/typography; modifiers set color. Every
   variant defines :hover, :active (a real pressed state, not just a
   color swap), :disabled, and a `.is-loading` state. Minimum 44x44px
   touch target on any device, enforced via min-height + padding rather
   than a hard min-width so short labels don't get an ugly stretched box.
   ========================================================================= */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  min-height: 44px;
  padding: var(--space-3) var(--space-5);
  border-radius: var(--radius-sm);
  border: 1px solid transparent;
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
  transition: background-color var(--duration-fast) var(--ease-out),
    border-color var(--duration-fast) var(--ease-out),
    color var(--duration-fast) var(--ease-out),
    transform var(--duration-fast) var(--ease-out);
}

@media (prefers-reduced-motion: reduce) {
  .btn {
    transition: none;
  }
}

.btn:active {
  transform: translateY(1px) scale(0.98); /* physical press feedback */
}

@media (prefers-reduced-motion: reduce) {
  .btn:active {
    transform: none;
  }
}

.btn:disabled,
.btn[aria-disabled='true'] {
  cursor: not-allowed;
  opacity: 0.45;
  transform: none;
}

/* --- primary: solid amber, the one high-emphasis action per view --- */
.btn-primary {
  background: var(--amber);
  color: var(--text-on-accent);
}

.btn-primary:hover:not(:disabled):not([aria-disabled='true']) {
  background: var(--amber-bright);
}

/* --- secondary: outlined, for the paired lower-emphasis action --- */
.btn-secondary {
  background: transparent;
  border-color: var(--border-interactive);
  color: var(--text-dim);
}

.btn-secondary:hover:not(:disabled):not([aria-disabled='true']) {
  border-color: var(--text-dim);
  color: var(--text);
}

/* --- ghost: no border, quietest option -- prefer this over a second
   outlined button when a view already has a primary + secondary --- */
.btn-ghost {
  background: transparent;
  color: var(--text-dim);
}

.btn-ghost:hover:not(:disabled):not([aria-disabled='true']) {
  background: var(--surface-2);
  color: var(--text-bright);
}

/* --- danger: destructive actions (delete account, cancel subscription) --- */
.btn-danger {
  background: transparent;
  border-color: var(--red);
  color: var(--red);
}

.btn-danger:hover:not(:disabled):not([aria-disabled='true']) {
  background: var(--red-dim);
}

.btn-danger.btn-primary-danger {
  background: var(--red);
  border-color: var(--red);
  color: var(--text-bright);
}

.btn-danger.btn-primary-danger:hover:not(:disabled):not([aria-disabled='true']) {
  background: #f45252;
}

/* --- sizes --- */
.btn-sm {
  min-height: 36px;
  padding: var(--space-2) var(--space-4);
  font-size: 0.65rem;
}

.btn-lg {
  min-height: 52px;
  padding: var(--space-4) var(--space-8);
  font-size: var(--text-sm);
}

/* --- loading: keep the button's size stable, swap the label for a
   visually-hidden status + spinner so screen readers announce it,
   disable interaction without dropping opacity to the disabled look --- */
.btn.is-loading {
  position: relative;
  color: transparent;
  pointer-events: none;
}

.btn.is-loading::after {
  content: '';
  position: absolute;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  border: 2px solid currentColor;
  border-top-color: transparent;
  color: inherit;
  animation: btn-spin 0.7s linear infinite;
}

.btn-primary.is-loading::after,
.btn-danger.btn-primary-danger.is-loading::after {
  color: var(--text-on-accent);
}

.btn-secondary.is-loading::after,
.btn-ghost.is-loading::after,
.btn-danger.is-loading::after {
  color: var(--text-dim);
}

@keyframes btn-spin {
  to {
    transform: rotate(360deg);
  }
}

@media (prefers-reduced-motion: reduce) {
  .btn.is-loading::after {
    animation: none;
    /* a static half-ring still communicates "busy" without motion */
    border-color: currentColor currentColor transparent transparent;
  }
}

/* =========================================================================
   CARDS
   Used only where elevation communicates real hierarchy (a distinct
   panel of content), never as decoration around every block of text.
   ========================================================================= */
.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: var(--space-5);
}

.card-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-4);
  margin-bottom: var(--space-4);
}

.card-title {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-dim);
}

.card-body {
  color: var(--text);
  font-size: var(--text-sm);
  line-height: 1.6;
}

.card-footer {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  margin-top: var(--space-4);
  padding-top: var(--space-4);
  border-top: 1px solid var(--border);
}

/* a card that sits one level up (inside a modal, or nested inside another
   card) needs a lighter surface to stay readable as "raised" */
.card--raised {
  background: var(--surface-2);
  border-color: var(--border-2);
}

/* =========================================================================
   BADGES / CHIPS
   One base shape, color set by a semantic modifier. Replaces the old
   ad hoc `.chip.done` / `.chip.assigned` / `.chip.open` pattern with a
   generalized, documented set (superset: the app needs status semantics
   the marketing pages never touch).
   ========================================================================= */
.badge {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  font-family: var(--font-mono);
  font-size: var(--text-2xs);
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  padding: 0.2rem 0.6rem;
  border-radius: var(--radius-xs);
  border: 1px solid transparent;
  line-height: 1.6;
}

.badge--neutral {
  background: var(--surface-2);
  border-color: var(--border-interactive);
  color: var(--text-dim);
}

.badge--brand {
  background: var(--amber-dim);
  border-color: rgba(245, 158, 11, 0.3);
  color: var(--amber);
}

.badge--success {
  background: var(--green-dim);
  border-color: rgba(16, 185, 129, 0.3);
  color: var(--green);
}

.badge--info {
  background: var(--indigo-dim);
  border-color: rgba(129, 140, 248, 0.3);
  color: var(--indigo);
}

.badge--danger {
  background: var(--red-dim);
  border-color: rgba(248, 113, 113, 0.3);
  color: var(--red);
}

/* interactive variant (the old .chip.open behavior: clickable, hovers
   toward the info color to invite the click) */
.badge--interactive {
  cursor: pointer;
  transition: border-color var(--duration-fast) var(--ease-out),
    color var(--duration-fast) var(--ease-out);
}

@media (prefers-reduced-motion: reduce) {
  .badge--interactive {
    transition: none;
  }
}

.badge--interactive:hover {
  border-color: var(--indigo);
  color: var(--indigo);
}

/* rounded "pill" shape for marketing badges (hero eyebrow-style tag) --
   used sparingly; see design-taste-frontend Section 9 on eyebrow rationing */
.badge--pill {
  border-radius: var(--radius-2xl);
  padding: 0.35rem 0.85rem;
}

/* =========================================================================
   FORMS
   Label always above the input. Help text below the label row (optional).
   Error text below the input, always present in markup (empty when there
   is no error) so screen readers don't get surprised by content appearing.
   ========================================================================= */
.field {
  margin-bottom: var(--space-4);
}

.field-row {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-3);
}

@media (min-width: 480px) {
  .field-row {
    grid-template-columns: 1fr 1fr;
  }
}

.field-label {
  display: block;
  font-family: var(--font-mono);
  font-size: var(--text-2xs);
  font-weight: 700;
  color: var(--text-dim);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  margin-bottom: var(--space-2);
}

.field-label .field-optional {
  text-transform: none;
  font-weight: 400;
  letter-spacing: normal;
  color: var(--text-disabled);
}

.field-help {
  font-size: var(--text-sm);
  color: var(--text-dim);
  margin-top: var(--space-2);
}

.field-error {
  display: flex;
  align-items: center;
  gap: var(--space-1);
  font-size: var(--text-sm);
  color: var(--red);
  margin-top: var(--space-2);
}

.field-error:empty {
  display: none;
}

.field input,
.field select,
.field textarea,
.input {
  width: 100%;
  min-height: 44px;
  padding: var(--space-3) var(--space-4);
  background: var(--surface-2);
  border: 1px solid var(--border-interactive);
  border-radius: var(--radius-sm);
  color: var(--text-bright);
  font-family: var(--font-sans);
  font-size: var(--text-base);
  outline: none;
  transition: border-color var(--duration-fast) var(--ease-out),
    box-shadow var(--duration-fast) var(--ease-out);
}

@media (prefers-reduced-motion: reduce) {
  .field input,
  .field select,
  .field textarea,
  .input {
    transition: none;
  }
}

.field textarea {
  min-height: 96px;
  resize: vertical;
}

.field input::placeholder,
.field textarea::placeholder,
.input::placeholder {
  color: var(--text-dim); /* passes AA on its own, unlike a low-contrast placeholder */
}

.field input:hover:not(:disabled),
.field select:hover:not(:disabled),
.field textarea:hover:not(:disabled) {
  border-color: var(--text-dim);
}

.field input:focus,
.field select:focus,
.field textarea:focus,
.input:focus {
  border-color: var(--amber);
  box-shadow: 0 0 0 3px var(--amber-dim);
}

.field input:disabled,
.field select:disabled,
.field textarea:disabled {
  background: var(--surface);
  color: var(--text-disabled);
  cursor: not-allowed;
}

.field.has-error input,
.field.has-error select,
.field.has-error textarea {
  border-color: var(--red);
}

.field.has-error input:focus,
.field.has-error select:focus,
.field.has-error textarea:focus {
  box-shadow: 0 0 0 3px var(--red-dim);
}

.field select option {
  background: var(--surface-2);
  color: var(--text-bright);
}

/* checkbox / radio: label and control share one hit target, no dead zone
   between the box and the text, and the whole row clears 44px tall */
.field-check {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  min-height: 44px;
  cursor: pointer;
}

.field-check input[type='checkbox'],
.field-check input[type='radio'] {
  width: 20px;
  height: 20px;
  min-height: 0;
  flex-shrink: 0;
  accent-color: var(--amber);
}

.field-check span {
  font-size: var(--text-sm);
  color: var(--text);
}

/* =========================================================================
   SKELETON LOADERS
   Match the shape of the content they stand in for -- a line skeleton for
   text, a block for a card/avatar -- never a generic centered spinner for
   a whole view. The shimmer is a background-position sweep (compositor
   friendly enough at this scale) and collapses to a static, still-visible
   pulse block under reduced motion.
   ========================================================================= */
.skeleton {
  display: block;
  border-radius: var(--radius-xs);
  background: linear-gradient(
    100deg,
    var(--surface-2) 30%,
    var(--surface-3) 50%,
    var(--surface-2) 70%
  );
  background-size: 200% 100%;
  animation: skeleton-sweep 1.6s ease-in-out infinite;
}

@keyframes skeleton-sweep {
  0% {
    background-position: 150% 0;
  }
  100% {
    background-position: -50% 0;
  }
}

@media (prefers-reduced-motion: reduce) {
  .skeleton {
    animation: none;
    background: var(--surface-2);
  }
}

.skeleton-text {
  height: 0.9em;
  width: 100%;
  margin-bottom: var(--space-2);
}

.skeleton-text:last-child {
  width: 70%; /* ragged last line reads as text, not a solid bar */
  margin-bottom: 0;
}

.skeleton-title {
  height: 1.4em;
  width: 45%;
  margin-bottom: var(--space-4);
}

.skeleton-avatar {
  width: 40px;
  height: 40px;
  border-radius: 50%;
  flex-shrink: 0;
}

.skeleton-block {
  width: 100%;
  height: 120px;
  border-radius: var(--radius-md);
}

/* =========================================================================
   EMPTY STATE
   A composed "here's what to do" view, never a bare blank panel.
   ========================================================================= */
.empty-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: var(--space-3);
  padding: var(--space-12) var(--space-6);
  color: var(--text-dim);
}

.empty-state-icon {
  width: 48px;
  height: 48px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: var(--surface-2);
  color: var(--text-dim);
  margin-bottom: var(--space-2);
}

.empty-state-title {
  font-family: var(--font-mono);
  font-size: var(--text-md);
  font-weight: 700;
  color: var(--text-bright);
  letter-spacing: 0.02em;
}

.empty-state-desc {
  font-size: var(--text-sm);
  max-width: 42ch;
  line-height: 1.6;
}

.empty-state .btn {
  margin-top: var(--space-2);
}

/* =========================================================================
   MODAL / DIALOG SHELL
   Reserve modals for interruptions that genuinely need focus (upgrade
   prompt, destructive confirmation) -- prefer inline states for anything
   smaller. `overscroll-behavior: contain` stops a long dialog body from
   scrolling the page behind it.
   ========================================================================= */
.modal-overlay {
  position: fixed;
  inset: 0;
  z-index: var(--z-modal);
  background: rgba(2, 4, 8, 0.8);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-4);
  overscroll-behavior: contain;
}

.modal {
  background: var(--surface);
  border: 1px solid var(--border-2);
  border-radius: var(--radius-lg);
  padding: var(--space-8);
  width: 100%;
  max-width: 480px;
  max-height: calc(100dvh - var(--space-8));
  overflow-y: auto;
  overscroll-behavior: contain;
  box-shadow: var(--shadow-lg);
}

.modal-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-4);
  margin-bottom: var(--space-4);
}

.modal-title {
  font-family: var(--font-mono);
  font-size: var(--text-md);
  font-weight: 700;
  color: var(--text-bright);
  letter-spacing: 0.03em;
}

.modal-close {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  margin: calc(var(--space-3) * -1);
  border-radius: var(--radius-sm);
  color: var(--text-dim);
  font-size: 1.1rem;
  line-height: 1;
  transition: background-color var(--duration-fast) var(--ease-out),
    color var(--duration-fast) var(--ease-out);
}

@media (prefers-reduced-motion: reduce) {
  .modal-close {
    transition: none;
  }
}

.modal-close:hover {
  background: var(--surface-2);
  color: var(--text-bright);
}

.modal-body {
  font-size: var(--text-sm);
  color: var(--text);
  line-height: 1.6;
}

.modal-footer {
  display: flex;
  justify-content: flex-end;
  gap: var(--space-3);
  margin-top: var(--space-6);
  flex-wrap: wrap;
}

@media (max-width: 479px) {
  .modal-footer {
    flex-direction: column-reverse;
  }

  .modal-footer .btn {
    width: 100%;
  }
}

/* =========================================================================
   NAV
   Covers both the marketing top nav and the in-app tab nav. Height stays
   under the 80px cap (64px base, matching the source files) and always
   renders on one line at desktop -- collapse rules are explicit per
   context since the two navs collapse differently (marketing hides links
   behind a menu button; the in-app tab bar scrolls horizontally).
   ========================================================================= */
.site-nav {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: var(--z-sticky);
  height: 64px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  padding-inline: var(--space-4);
  background: rgba(6, 9, 15, 0.85);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  border-bottom: 1px solid var(--border);
}

@media (min-width: 768px) {
  .site-nav {
    padding-inline: var(--space-10);
  }
}

.site-nav-logo {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  font-family: var(--font-mono);
  font-size: var(--text-sm);
  color: var(--amber);
  letter-spacing: 0.15em;
  white-space: nowrap;
}

.site-nav-links {
  display: none;
  align-items: center;
  gap: var(--space-6);
}

@media (min-width: 1024px) {
  .site-nav-links {
    display: flex;
  }
}

/* Padding is load-bearing, not cosmetic: without it the clickable box is only
   as tall as the text line (~19px), well under the 44px target minimum. The
   negative inline margin keeps the enlarged hit area from visually widening
   the gap between links. */
.site-nav-link {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: var(--space-2) var(--space-3);
  margin-inline: calc(var(--space-3) * -1);
  color: var(--text-dim);
  font-size: var(--text-sm);
  font-weight: 500;
  transition: color var(--duration-fast) var(--ease-out);
}

@media (prefers-reduced-motion: reduce) {
  .site-nav-link {
    transition: none;
  }
}

.site-nav-link:hover {
  color: var(--text-bright);
}

.site-nav-link[aria-current='page'] {
  color: var(--amber);
}

/* mobile: everything but the logo and a single CTA collapses behind this
   toggle -- pages wire up the open/close behavior, this only styles it */
.site-nav-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  color: var(--text-bright);
}

@media (min-width: 1024px) {
  .site-nav-toggle {
    display: none;
  }
}

/* in-app tab nav (app.html): horizontal scroll on narrow screens instead
   of wrapping to a second line */
.app-nav {
  display: flex;
  align-items: center;
  height: 56px;
  background: var(--surface);
  border-bottom: 1px solid var(--border);
  overflow-x: auto;
  scrollbar-width: none;
}

.app-nav::-webkit-scrollbar {
  display: none;
}

.app-nav-tab {
  flex-shrink: 0;
  padding-inline: var(--space-5);
  height: 100%;
  min-width: 44px;
  display: inline-flex;
  align-items: center;
  color: var(--text-dim);
  font-size: var(--text-sm);
  font-weight: 500;
  border-bottom: 2px solid transparent;
  transition: color var(--duration-fast) var(--ease-out);
}

@media (prefers-reduced-motion: reduce) {
  .app-nav-tab {
    transition: none;
  }
}

.app-nav-tab:hover {
  color: var(--text);
}

.app-nav-tab[aria-current='page'] {
  color: var(--amber);
  border-bottom-color: var(--amber);
}

/* =========================================================================
   FOOTER
   Kept intentionally simple per the redesign audit: primary links + legal
   links + copyright, not a four-column link farm.
   ========================================================================= */
.site-footer {
  border-top: 1px solid var(--border);
  padding-block: var(--space-10);
  margin-top: var(--space-16);
}

.site-footer-row {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-4);
}

@media (min-width: 768px) {
  .site-footer-row {
    flex-direction: row;
    align-items: center;
    justify-content: space-between;
  }
}

.site-footer-links {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-5);
}

.site-footer-link {
  font-size: var(--text-sm);
  color: var(--text-dim);
  transition: color var(--duration-fast) var(--ease-out);
}

@media (prefers-reduced-motion: reduce) {
  .site-footer-link {
    transition: none;
  }
}

.site-footer-link:hover {
  color: var(--text-bright);
}

.site-footer-copy {
  font-size: var(--text-2xs);
  color: var(--text-dim);
  font-family: var(--font-mono);
}


/* =========================================================================
   SITE NAV - MOBILE PANEL, TOGGLE ICON, LOGO PULSE
   Relocated here from marketing.css so every page gets the same navigation.
   index.html does not load marketing.css, and was carrying a second,
   divergent drawer implementation; the nav is a component, so it belongs in
   the component layer where all pages already link it.
   Behaviour is wired by assets/js/site-nav.js against this same markup
   contract: .site-nav > .site-nav-toggle + .site-nav-links#site-nav-menu.
   ========================================================================= */
/* =========================================================================
   NAV LOGO PULSE
   Small decorative "live" dot next to the wordmark, carried over from the
   pre-redesign nav. Not part of components.css yet -- flagged to the lead
   as a candidate to fold in there if index.html's nav wants the same dot.
   ========================================================================= */
.nav-pulse {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--amber);
  animation: nav-pulse 2s infinite;
}

@keyframes nav-pulse {
  0%,
  100% {
    opacity: 1;
    box-shadow: 0 0 0 0 rgba(245, 158, 11, 0.5);
  }
  50% {
    opacity: 0.6;
    box-shadow: 0 0 0 5px rgba(245, 158, 11, 0);
  }
}

@media (prefers-reduced-motion: reduce) {
  .nav-pulse {
    animation: none;
  }
}

/* =========================================================================
   MOBILE NAV TOGGLE ICON
   A single element plus two pseudo-elements form the three bars; the
   middle bar fades out and the outer two rotate into an "X" when the
   panel is open. Transform/opacity/background-color only, per the motion
   rules in components.css's own header comment.
   ========================================================================= */
.site-nav-toggle {
  position: relative;
}

.nav-toggle-bar,
.nav-toggle-bar::before,
.nav-toggle-bar::after {
  content: '';
  position: absolute;
  left: 50%;
  width: 20px;
  height: 2px;
  background: currentColor;
  transform: translateX(-50%);
  transition: transform var(--duration-base) var(--ease-out),
    opacity var(--duration-base) var(--ease-out),
    background-color var(--duration-base) var(--ease-out);
}

.nav-toggle-bar {
  top: 50%;
  transform: translate(-50%, -50%);
}

.nav-toggle-bar::before {
  top: -6px;
}

.nav-toggle-bar::after {
  top: 6px;
}

.site-nav-toggle[aria-expanded='true'] .nav-toggle-bar {
  background: transparent;
}

.site-nav-toggle[aria-expanded='true'] .nav-toggle-bar::before {
  top: 0;
  transform: translateX(-50%) rotate(45deg);
}

.site-nav-toggle[aria-expanded='true'] .nav-toggle-bar::after {
  top: 0;
  transform: translateX(-50%) rotate(-45deg);
}

@media (prefers-reduced-motion: reduce) {
  .nav-toggle-bar,
  .nav-toggle-bar::before,
  .nav-toggle-bar::after {
    transition: none;
  }
}

/* =========================================================================
   MOBILE NAV PANEL
   components.css hides `.site-nav-links` with `display:none` below 1024px
   and shows it as a plain flex row at 1024px+. Below 1024px we still need
   it reachable (behind the toggle), so this overrides `display` to `flex`
   in the same range and instead uses opacity/transform/visibility to hide
   it when closed -- `display:none` can't be transitioned, and a hard cut
   would skip the motion the toggle icon already promises above.
   `visibility:hidden` (with a transition-delay on close so it lingers
   until the fade finishes) keeps the closed panel's links out of the tab
   order and the accessibility tree, on top of the JS focus trap only
   running while `.is-open` is present.
   ========================================================================= */
@media (max-width: 1023.98px) {
  .site-nav-links {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    position: fixed;
    inset: 64px 0 0 0;
    z-index: var(--z-sticky);
    gap: 0;
    padding: var(--space-4);
    background: var(--surface);
    border-top: 1px solid var(--border);
    overflow-y: auto;
    overscroll-behavior: contain;
    opacity: 0;
    transform: translateY(-8px);
    visibility: hidden;
    pointer-events: none;
    transition: opacity var(--duration-base) var(--ease-out),
      transform var(--duration-base) var(--ease-out),
      visibility 0s linear var(--duration-base);
  }

  .site-nav-links.is-open {
    opacity: 1;
    transform: translateY(0);
    visibility: visible;
    pointer-events: auto;
    transition: opacity var(--duration-base) var(--ease-out),
      transform var(--duration-base) var(--ease-out),
      visibility 0s linear 0s;
  }

  .site-nav-links .site-nav-link {
    min-height: 44px;
    display: flex;
    align-items: center;
    font-size: var(--text-md);
    border-bottom: 1px solid var(--border);
  }

  .site-nav-links .site-nav-actions {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    margin-top: var(--space-4);
  }

  .site-nav-links .site-nav-actions .btn {
    width: 100%;
  }
}

@media (prefers-reduced-motion: reduce) {
  .site-nav-links {
    transition: none;
  }
}

/* locks background scroll while the mobile panel is open (JS toggles this
   class on <body>); the panel itself scrolls independently above */
body.nav-open {
  overflow: hidden;
}

/* desktop: the sign-in/get-started actions sit inline with the links */
@media (min-width: 1024px) {
  .site-nav-actions {
    display: flex;
    align-items: center;
    gap: var(--space-3);
  }
}

