/* ==========================================
   SOTIS AI - Design System: components
   Light only. Every value comes from a role of tokens.css (same folder),
   loaded before this file by base.html: fonts, colours, type scale, spacing,
   radii, shadows. This file holds components, never a literal design value.
   ========================================== */

/* ==========================================
   RESET & BASE STYLES
   ========================================== */

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

/* `clip`, NOT `hidden`, and the distinction is the whole reason the sticky
   header works.
   `overflow-x: hidden` forces the other axis to compute to `auto` (CSS Overflow
   3), which turns html AND body into scroll containers. A `position: sticky`
   header then sticks to the top of its nearest scrolling ancestor, which is the
   body box, not the viewport: it scrolls away with the page and looks like
   sticky is simply broken. `clip` clips the same overflow WITHOUT creating a
   scroll container, so the header resolves against the viewport again.
   Do not "simplify" this back to hidden. */
html {
  overflow-x: clip;
  max-width: 100vw;
  /* Anchored jumps land below the sticky header instead of under it. */
  scroll-padding-top: 5rem;
}

body {
  font-family: var(--font-sans);
  font-size: var(--text-md);
  line-height: var(--leading-normal);
  color: var(--text-primary);
  background-color: var(--bg-primary);
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  /* Meme raison que sur html : `hidden` ferait de body un conteneur de
     defilement et decrocherait le header colle. Voir le commentaire ci-dessus. */
  overflow-x: clip;
  /* Without these the text renders noticeably heavier on macOS. */
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
  font-feature-settings: 'kern' 1;
}

/* Form controls do not inherit the page font: without this a <button> with
   no font-family of its own renders in the system face, and a change of
   --font-sans would skip it. Family only, so no size moves. */
button,
input,
select,
textarea {
  font-family: inherit;
}

/* Display sizes need negative tracking; body sizes do not. Setting it here
   rather than per-component is what keeps headings consistent across the eight
   apps, none of which declare tracking of their own. */
h1, h2, h3, h4, h5, h6 {
  font-weight: var(--font-weight-bold);
  line-height: var(--leading-tight);
  letter-spacing: var(--tracking-tight);
  text-wrap: balance;
}

h1 { letter-spacing: var(--tracking-tighter); }

p {
  text-wrap: pretty;
}

a {
  color: inherit;
  text-decoration: none;
}

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

::selection {
  background: color-mix(in srgb, var(--accent) 30%, transparent);
  color: var(--text-primary);
}

/* Small uppercase monospace label. The recurring "technical signage" element:
   section eyebrows, metadata, counters. Deliberately global, so apps get it
   without redefining a mono stack (there used to be five different ones). */
/* --text-secondary, not --text-tertiary: the eyebrow is the label that says
   what a section is, so it takes the stronger of the two greys. Tertiary is
   for metadata that carries less information. */
.eyebrow {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  font-weight: var(--font-weight-medium);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--text-secondary);
}

/* ==========================================
   HEADER & NAVIGATION
   ========================================== */

/* The header is a translucent white glass rail over the canvas, with a
   hairline and a soft ink shadow, not a coloured band. It stays a full-width
   rail rather than a floating capsule: the mobile sheet unrolls inside it and
   the immo map runs edge to edge under it.

   The selector MUST stay scoped to `body > header`. A bare `header {}` here is
   a global element selector: it also matched every sectioning <header> in the
   page body (home's nine `.section-head`, `.module-header`, `.portfolio-header`,
   `.project-detail-header`, `.reco-modal-header`), which then inherited
   `position: sticky; z-index: 1100` and stuck to the top of the viewport ON TOP
   of the real navbar while scrolling. Same z-index, later in DOM order, so the
   section header won. Do not un-scope it. */
body > header {
  position: sticky;
  top: 0;
  background: var(--header-bg);
  -webkit-backdrop-filter: saturate(180%) blur(14px);
  backdrop-filter: saturate(180%) blur(14px);
  border-bottom: 1px solid var(--border-color);
  box-shadow: var(--shadow-header);
  /* Above the map UI ceiling: Leaflet control corners default to z-index 1000,
     which otherwise ties this header and wins on DOM order (the navbar dropdown
     then renders behind the immo map controls). Do NOT lower this, and do not
     introduce a positioned ancestor around <header>: that would create a new
     stacking context and put the whole rail back under the map. */
  z-index: 1100;
}

/* No backdrop-filter support: fall back to an opaque rail rather than letting
   content scroll through a translucent bar. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  body > header { background: var(--card-bg); }
}

.nav-container {
  max-width: 1200px;
  margin: 0 auto;
  padding: 0 var(--space-md);
  height: 56px;
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.logo {
  color: var(--text-primary);
  text-decoration: none;
  display: flex;
  align-items: center;
  gap: 0.5rem;
  transition: opacity var(--transition-fast);
}

.logo:hover {
  opacity: 0.8;
}

/* The brand mark, in the header and in the footer's brand block.

   26px rather than the 22px the placeholder SVG used: the mark is cut out of a
   tile that carried its own internal padding, so at equal box height it reads
   noticeably smaller than a shape drawn edge to edge. The nav row is 56px, so
   this still leaves 15px of air above and below.

   flex-shrink: 0 because .logo is a flex row and the wordmark next to it would
   otherwise squeeze the image on narrow screens. */
.logo-img {
  height: 26px;
  width: auto;
  display: block;
  flex-shrink: 0;
}

.logo-text {
  font-size: var(--text-base);
  font-weight: var(--font-weight-bold);
  letter-spacing: var(--tracking-tight);
  color: var(--text-primary);
}

.nav-links {
  list-style: none;
  display: flex;
  gap: 0.25rem;
  align-items: center;
}

.nav-links a,
.dropdown-toggle {
  color: var(--text-secondary);
  text-decoration: none;
  padding: 0.4rem 0.7rem;
  border-radius: var(--radius-full);
  font-size: var(--text-base);
  font-weight: var(--font-weight-normal);
  font-family: inherit;
  background: none;
  border: none;
  cursor: pointer;
  transition: color var(--transition-fast), background-color var(--transition-fast);
}

.nav-links a:hover,
.dropdown-toggle:hover,
.dropdown:hover .dropdown-toggle,
.dropdown.is-open .dropdown-toggle {
  color: var(--text-primary);
  background-color: var(--hover-bg);
}

/* Current page. Set by chrome.js from the URL, so it survives any nav reorder. */
.nav-links a[aria-current="page"] {
  color: var(--text-primary);
  background-color: var(--hover-bg);
}

/* ---- Nav CTA ----
   The one conversion link that is present on all 19 pages. It is an OUTLINE
   button, deliberately not `.btn-accent`: yellow is rationed to one occurrence
   per screen and the home page already spends it on the closing "Réserver un
   créneau". A yellow pill in the sticky header would fire on every page and
   collide with that one, which is exactly how the accent stops signalling.
   A graphite fill was the other candidate; it competes with `.btn-primary`
   in the hero, three centimetres below it. */
.nav-links a.nav-cta {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  margin-left: 0.4rem;
  padding: 0.4rem 0.85rem;
  color: var(--text-primary);
  background-color: var(--card-bg);
  font-weight: var(--font-weight-semibold);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-full);
  box-shadow: var(--shadow-sm);
  white-space: nowrap;
}

.nav-links a.nav-cta:hover {
  background-color: var(--accent-wash);
  border-color: var(--accent-line);
  color: var(--accent-strong);
}

/* Logout button styled as nav link */
.logout-button {
  background: none;
  border: none;
  outline: none;
  color: var(--text-secondary);
  cursor: pointer;
  font-size: var(--text-base);
  font-family: inherit;
  padding: 0.4rem 0.7rem;
  margin: 0;
  text-decoration: none;
  border-radius: var(--radius-sm);
  transition: color var(--transition-fast), background-color var(--transition-fast);
  -webkit-appearance: none;
  -moz-appearance: none;
  appearance: none;
}

.logout-button:hover {
  color: var(--text-primary);
  background-color: var(--hover-bg);
}

/* ---- Dropdown ---- */
.dropdown {
  position: relative;
}

.dropdown-caret {
  width: 14px !important;
  height: 14px !important;
  margin-right: 0 !important;
  margin-left: 0.25rem;
  opacity: 0.6;
}

.dropdown-menu {
  display: none;
  position: absolute;
  top: calc(100% + 6px);
  left: 0;
  background: var(--surface-raised);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-lg);
  min-width: max-content;
  box-shadow: var(--shadow-lg);
  list-style: none;
  padding: 0.35rem;
  margin: 0;
  z-index: 1001;
}

/* Hover for pointers, .is-open for keyboard and touch (chrome.js). The old
   markup was a hover-only <a href="#">, which no keyboard user could reach. */
.dropdown:hover .dropdown-menu,
.dropdown.is-open .dropdown-menu {
  display: block;
}

/* Bridges the 6px gap between toggle and menu so the pointer can travel down
   without the menu closing under it. */
.dropdown:hover::after {
  content: '';
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  height: 8px;
}

.dropdown-menu li {
  margin: 0;
}

.dropdown-menu a,
.dropdown-logout-button {
  display: flex;
  align-items: center;
  width: 100%;
  padding: 0.45rem 0.7rem;
  border-radius: var(--radius-sm);
  color: var(--text-secondary);
  text-decoration: none;
  background: none;
  border: none;
  text-align: left;
  cursor: pointer;
  font-family: inherit;
  font-size: var(--text-base);
  white-space: nowrap;
  transition: color var(--transition-fast), background-color var(--transition-fast);
}

.dropdown-menu a:hover,
.dropdown-menu a:focus-visible,
.dropdown-logout-button:hover,
.dropdown-logout-button:focus-visible {
  background-color: var(--hover-bg);
  color: var(--text-primary);
  outline: none;
}

/* Navigation Icons (Lucide) */
.nav-links a svg,
.dropdown-toggle svg,
.dropdown-menu a svg,
.dropdown-logout-button svg {
  width: 16px;
  height: 16px;
  vertical-align: middle;
  margin-right: 0.5rem;
  flex-shrink: 0;
  opacity: 0.75;
}

.nav-links > li > a,
.dropdown-toggle {
  display: inline-flex;
  align-items: center;
}

/* Mobile Menu Toggle Button */
.mobile-menu-toggle {
  display: none;
  background: none;
  border: 1px solid var(--border-strong);
  color: var(--text-primary);
  cursor: pointer;
  padding: 0.35rem;
  border-radius: var(--radius-sm);
  transition: background-color var(--transition-fast);
  -webkit-appearance: none;
  -moz-appearance: none;
  appearance: none;
}

.mobile-menu-toggle svg {
  width: 20px;
  height: 20px;
  display: block;
}

.mobile-menu-toggle .close-icon {
  display: none;
}

.mobile-menu-toggle.active .menu-icon {
  display: none;
}

.mobile-menu-toggle.active .close-icon {
  display: block;
}

.mobile-menu-toggle:hover {
  background-color: var(--hover-bg);
}

/* ==========================================
   MAIN CONTENT
   ========================================== */

main {
  max-width: 1200px;
  width: 100%;
  margin: var(--space-md) auto;
  padding: 0 var(--space-md);
  min-height: calc(100vh - 200px);
  flex: 1;
  overflow-x: hidden;
}

@media (max-width: 480px) {
  main {
    padding: 0 var(--space-xs);
    margin: var(--space-sm) auto;
  }
}

/* ==========================================
   MESSAGES & ALERTS
   ========================================== */

.messages {
  position: fixed;
  top: 72px;
  right: var(--space-md);
  z-index: 1000;
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
  max-width: 400px;
}

.message {
  padding: 0.7rem var(--space-sm);
  border-radius: var(--radius-md);
  border: 1px solid var(--border-strong);
  border-left: 3px solid;
  font-size: var(--text-base);
  background-color: var(--surface-raised);
  box-shadow: var(--shadow-lg);
  animation: slideInRight 0.3s ease-out;
  transition: opacity 0.5s ease-out, transform 0.5s ease-out;
}

.message.fade-out {
  opacity: 0;
  transform: translateX(20px);
}

@keyframes slideInRight {
  from {
    opacity: 0;
    transform: translateX(20px);
  }
  to {
    opacity: 1;
    transform: translateX(0);
  }
}

@keyframes slideIn {
  from {
    opacity: 0;
    transform: translateY(-10px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

/* One rule per level. The light/dark pairs these replaced disagreed on more
   than luminance: the light "success" was violet while the dark one was a
   stale indigo that matched no token.

   The status tokens are TRANSLUCENT, which is right for a badge sitting on a
   known surface and wrong for a toast: setting them as `background-color`
   replaced the opaque `--surface-raised` of `.message` instead of tinting it,
   so whatever the toast floated over showed straight through the text. It went
   unnoticed while the only toasts were server-rendered ones on quiet pages;
   `SotisDialog.notify` now raises them over the immo map and the analytics
   charts. The tint therefore goes in as a background LAYER, over the opaque
   colour rather than in place of it, which keeps the tokens as they are. */
.message.success {
  background-image: linear-gradient(var(--success-bg), var(--success-bg));
  color: var(--success-text);
  border-color: var(--success);
}

.message.error {
  background-image: linear-gradient(var(--danger-bg), var(--danger-bg));
  color: var(--danger-text);
  border-color: var(--danger);
}

.message.info {
  background-image: linear-gradient(var(--info-bg), var(--info-bg));
  color: var(--info-text);
  border-color: var(--accent);
}

.message.warning {
  background-image: linear-gradient(var(--warning-bg), var(--warning-bg));
  color: var(--warning-text);
  border-color: var(--warning);
}

/* ==========================================
   CONFIRMATION DIALOG (SotisDialog.confirm)
   ==========================================
   Above .messages (1000) and above the header (1100, itself set above the
   1000 ceiling of the Leaflet controls): a confirmation that a map control
   can overlap is a confirmation the user can misread. */

.confirm-backdrop {
  position: fixed;
  inset: 0;
  z-index: 1200;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-md);
  background: var(--scrim);
  backdrop-filter: blur(2px);
}

.confirm-dialog {
  width: 100%;
  max-width: 30rem;
  background: var(--surface-raised);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  padding: var(--space-lg);
  animation: slideIn 0.15s ease-out;
}

.confirm-message {
  margin: 0 0 var(--space-md);
  color: var(--text-primary);
  font-size: var(--text-md);
  line-height: var(--leading-normal);
}

.confirm-actions {
  display: flex;
  justify-content: flex-end;
  gap: var(--space-xs);
  flex-wrap: wrap;
}

/* "Annuler" stays the plain .btn-secondary outline and "Confirmer" the filled
   .btn-primary, even though the dialog opens focused on "Annuler": the ring
   comes from :focus-visible, which a programmatic focus does not always show,
   so the quiet button is not guaranteed to be marked. Left as is on purpose,
   the destructive answer being the one that should have to be aimed at. */

@media (max-width: 480px) {
  .confirm-actions button {
    flex: 1 1 auto;
  }
}

/* ==========================================
   BUTTONS
   ========================================== */

/* Hierarchy, in descending order of weight. All actions are pills.
     .btn-primary    graphite fill        the one action on the page
     .btn-accent     yellow fill          the single brand spark, at most once,
                                          and only on the dark inverse block:
                                          yellow never sits alone on a light
                                          surface
     .btn-secondary  white, hairline      everything else
     .btn-ghost      bare text            tertiary, inline
     .btn-violet     violet fill          rare, branded rather than neutral */

.btn-primary,
.btn-secondary,
.btn-accent,
.btn-ghost,
.btn-violet {
  padding: 0.65rem 1.2rem;
  border-radius: var(--radius-full);
  font-family: inherit;
  font-size: var(--text-base);
  font-weight: var(--font-weight-semibold);
  letter-spacing: -0.01em;
  line-height: 1.2;
  cursor: pointer;
  text-decoration: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.45rem;
  text-align: center;
  border: 1px solid transparent;
  transition: background-color var(--transition-fast),
              border-color var(--transition-fast),
              color var(--transition-fast),
              box-shadow var(--transition-fast),
              opacity var(--transition-fast);
}

.btn-primary {
  background-color: var(--surface-inverse);
  color: var(--text-on-fill);
  box-shadow: var(--shadow-button);
}

.btn-primary:hover {
  background-color: var(--surface-inverse-hover);
}

/* The yellow glow only reads on graphite, which is the only place this
   button is used. */
.btn-accent {
  background-color: var(--spark);
  color: var(--text-on-spark);
  box-shadow: 0 10px 24px -12px color-mix(in srgb, var(--spark) 55%, transparent);
}

.btn-accent:hover {
  background-color: var(--spark-hover);
}

.btn-secondary {
  background-color: var(--card-bg);
  border-color: var(--border-strong);
  color: var(--text-primary);
  box-shadow: var(--shadow-sm);
}

.btn-secondary:hover {
  background-color: var(--card-bg);
  border-color: var(--border-hover);
}

.btn-ghost {
  background: transparent;
  color: var(--text-secondary);
  padding-left: 0.6rem;
  padding-right: 0.6rem;
}

.btn-ghost:hover {
  color: var(--text-primary);
  background-color: var(--hover-bg);
}

/* Violet fill, for the rare case where an action must read as branded rather
   than neutral. --accent-fill carries white; its hover goes darker. */
.btn-violet {
  background-color: var(--accent-fill);
  color: var(--text-on-fill);
}

.btn-violet:hover {
  background-color: var(--accent-strong);
}

.btn-primary:active,
.btn-secondary:active,
.btn-accent:active,
.btn-ghost:active {
  opacity: 0.85;
}

.btn-primary:focus-visible,
.btn-secondary:focus-visible,
.btn-accent:focus-visible,
.btn-ghost:focus-visible,
.btn-violet:focus-visible {
  outline: 2px solid var(--focus-ring);
  outline-offset: 2px;
}

.btn-primary svg,
.btn-secondary svg,
.btn-accent svg,
.btn-ghost svg,
.btn-violet svg {
  width: 16px;
  height: 16px;
  flex-shrink: 0;
}

/* ==========================================
   FORMS & INPUTS
   ========================================== */

.auth-container {
  max-width: 400px;
  margin: var(--space-xl) auto;
  background: var(--card-bg);
  padding: var(--space-md);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg), var(--ring-inset);
}

.auth-container h1 {
  margin-bottom: var(--space-md);
  color: var(--text-primary);
  font-size: var(--text-xl);
}

.auth-form {
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
}

.form-group {
  display: flex;
  flex-direction: column;
}

.form-group label {
  margin-bottom: var(--space-xs);
  font-weight: var(--font-weight-medium);
  color: var(--text-primary);
}

/* Inputs used to declare a border but no background or colour, so they fell
   back to the browser's own control rendering: a grey box that matched nothing
   on the page. Both are now explicit. */
.form-group input,
.form-group textarea,
.form-group select {
  padding: 0.6rem 0.7rem;
  background: var(--input-bg);
  color: var(--text-primary);
  border: 1px solid var(--border-control);
  border-radius: var(--radius-sm);
  font-size: var(--text-base);
  font-family: inherit;
  transition: border-color var(--transition-fast), box-shadow var(--transition-fast);
}

.form-group input::placeholder,
.form-group textarea::placeholder {
  color: var(--text-tertiary);
}

.form-group input:focus,
.form-group textarea:focus,
.form-group select:focus {
  outline: none;
  border-color: var(--focus-ring);
  box-shadow: var(--shadow-focus);
}

.form-group input:hover,
.form-group textarea:hover,
.form-group select:hover {
  border-color: var(--text-tertiary);
}

.help-text {
  font-size: var(--text-ui);
  color: var(--text-secondary);
  margin-top: 0.25rem;
}

.field-error {
  color: var(--danger-text);
  font-size: var(--text-sm);
  margin-top: 0.25rem;
  font-weight: var(--font-weight-medium);
}

.form-errors {
  background-color: var(--danger-bg);
  color: var(--danger-text);
  padding: var(--space-xs) var(--space-sm);
  border: 1px solid var(--border-strong);
  border-left: 3px solid var(--danger);
  border-radius: var(--radius-sm);
  margin-bottom: var(--space-sm);
  font-size: var(--text-base);
}

.auth-link {
  text-align: center;
  margin-top: var(--space-sm);
  color: var(--text-secondary);
}

.auth-link a {
  color: var(--accent);
  text-decoration: none;
  font-weight: var(--font-weight-medium);
  transition: color var(--transition-base);
}

.auth-link a:hover {
  color: var(--text-primary);
  text-decoration: underline;
}

/* ==========================================
   PAGE HEADER (Unified style for all apps)
   ========================================== */

/* Left-aligned, with a hairline rule under it. Centred page titles are the
   single most template-looking thing on a content page; every app uses this
   class, so changing it here re-aligns all eight at once. */
.page-header {
  margin-bottom: var(--space-md);
  padding-bottom: var(--space-sm);
  border-bottom: 1px solid var(--border-color);
  max-width: 100%;
  overflow-wrap: break-word;
  word-wrap: break-word;
}

.page-header h1 {
  color: var(--text-primary);
  margin-bottom: 0.4rem;
  font-size: var(--text-3xl);
  letter-spacing: var(--tracking-tighter);
  overflow-wrap: break-word;
  word-wrap: break-word;
  hyphens: auto;
}

.page-header .subtitle,
.page-header p {
  color: var(--text-secondary);
  font-size: var(--text-md);
  max-width: 62ch;
}

/* Optional monospace kicker above the title. */
.page-header .eyebrow {
  display: block;
  margin-bottom: 0.6rem;
}

@media (max-width: 768px) {
  .page-header h1 {
    font-size: var(--text-2xl);
  }
  .page-header .subtitle,
  .page-header p {
    font-size: var(--text-base);
  }
}

@media (max-width: 480px) {
  .page-header h1 {
    font-size: var(--text-xl);
  }
}

/* ==========================================
   FOOTER
   ========================================== */

/* NOTE: `footer` is a bare element selector, so it reaches every <footer> in
   every app, including ones nested inside components. Keep the rules here
   about the page footer only, and scope anything richer to .site-footer. */
footer {
  background-color: var(--footer-bg);
  color: var(--text-secondary);
  border-top: 1px solid var(--border-color);
  padding: var(--space-xl) var(--space-md) var(--space-md);
  margin-top: var(--space-xl);
  font-size: var(--text-base);
}

footer a {
  color: var(--text-secondary);
  transition: color var(--transition-fast);
}

footer a:hover {
  color: var(--text-primary);
}

/* Two columns: the brand takes the room, Contact hugs the right edge, in line
   with the last span of .site-footer-bottom below it. */
.site-footer-inner {
  max-width: 1200px;
  margin: 0 auto;
  display: grid;
  grid-template-columns: 1fr auto;
  gap: var(--space-md);
  align-items: start;
}

.site-footer-lockup {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

/* Slightly larger than in the header: the footer has room, and the four bars
   under the cloud only separate cleanly above roughly 26px. */
.site-footer-lockup .logo-img {
  height: 28px;
}

.site-footer-brand .logo-text {
  font-size: var(--text-base);
}

.site-footer-brand p {
  margin-top: 0.6rem;
  color: var(--text-tertiary);
  font-size: var(--text-sm);
  max-width: 34ch;
}

.site-footer-col h2 {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  font-weight: var(--font-weight-medium);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--text-tertiary);
  margin-bottom: 0.7rem;
}

.site-footer-col ul {
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
}

.site-footer-bottom {
  max-width: 1200px;
  margin: var(--space-md) auto 0;
  padding-top: var(--space-sm);
  border-top: 1px solid var(--border-color);
  display: flex;
  justify-content: space-between;
  gap: var(--space-sm);
  flex-wrap: wrap;
  color: var(--text-tertiary);
  font-size: var(--text-sm);
}

/* --text-secondary, not the --text-tertiary of the line it sits on: the two
   copyright spans beside it are metadata, this one is a link the law expects a
   visitor to be able to find and follow. */
.site-footer-legal a {
  color: var(--text-secondary);
  text-decoration: none;
}

.site-footer-legal a:hover {
  color: var(--text-primary);
  text-decoration: underline;
}

@media (max-width: 768px) {
  .site-footer-inner {
    grid-template-columns: 1fr;
    gap: var(--space-sm);
  }
}

/* ==========================================
   CUSTOM SELECT COMPONENT (Reusable)
   ========================================== */

.custom-select {
  position: relative;
  width: 100%;
}

.custom-select-trigger {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  width: 100%;
  padding: 0.5rem 0.75rem;
  border: 1px solid var(--accent);
  border-radius: var(--radius-sm);
  background: var(--input-bg);
  color: var(--text-primary);
  font-size: var(--text-ui);
  cursor: pointer;
  transition: var(--transition-fast);
  text-align: left;
}

.custom-select-trigger:hover {
  border-color: var(--accent-strong);
}

.custom-select.open .custom-select-trigger {
  border-color: var(--accent-strong);
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--accent) 30%, transparent);
}

.custom-select-trigger .selected-text {
  flex: 1;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.custom-select-trigger .dropdown-arrow {
  width: 16px;
  height: 16px;
  flex-shrink: 0;
  transition: transform var(--transition-fast);
}

.custom-select.open .dropdown-arrow {
  transform: rotate(180deg);
}

.custom-select-dropdown {
  display: none;
  position: absolute;
  top: 100%;
  left: 0;
  min-width: 100%;
  width: max-content;
  max-width: min(450px, calc(100vw - 2rem));
  background: var(--card-bg);
  border: 1px solid var(--accent-strong);
  border-top: none;
  border-radius: 0 0 var(--radius-sm) var(--radius-sm);
  box-shadow: var(--shadow-lg);
  z-index: 1001;
  max-height: 350px;
  overflow: hidden;
  flex-direction: column;
}

.custom-select.open .custom-select-dropdown {
  display: flex;
}

/* Simple dropdowns (without search) */
.custom-dropdown-simple {
  max-height: 250px;
  border-radius: var(--radius-sm);
  border-top: 1px solid var(--accent-strong);
  margin-top: 2px;
}

.custom-select-simple.open .custom-select-trigger {
  border-bottom-left-radius: var(--radius-sm);
  border-bottom-right-radius: var(--radius-sm);
}

.custom-dropdown-simple .custom-dropdown-options {
  padding: 0.25rem 0;
}

/* Dropdown with search */
.custom-select.open:not(.custom-select-simple) .custom-select-trigger {
  border-bottom-left-radius: 0;
  border-bottom-right-radius: 0;
}

.custom-dropdown-search {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.5rem 0.75rem;
  border-bottom: 1px solid var(--border-color);
  background: var(--bg-secondary);
}

.custom-dropdown-search svg {
  width: 16px;
  height: 16px;
  color: var(--text-secondary);
  flex-shrink: 0;
}

.custom-dropdown-search input {
  flex: 1;
  border: none;
  background: transparent;
  color: var(--text-primary);
  font-size: var(--text-ui);
  outline: none;
}

.custom-dropdown-search input::placeholder {
  color: var(--text-secondary);
}

.custom-dropdown-options {
  flex: 1;
  overflow-y: auto;
  padding: 0 0 0.25rem 0;
}

.custom-dropdown-option {
  padding: 0.5rem 0.75rem;
  cursor: pointer;
  font-size: var(--text-ui);
  color: var(--text-primary);
  transition: background var(--transition-fast);
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

.custom-dropdown-option:hover {
  background: color-mix(in srgb, var(--accent) 15%, transparent);
}

.custom-dropdown-option.selected {
  background: color-mix(in srgb, var(--accent) 25%, transparent);
  font-weight: 500;
  color: var(--accent-strong);
}

.custom-dropdown-option-special {
  border-bottom: 1px solid var(--border-color);
  font-weight: 500;
  color: var(--accent-strong);
  padding: 0.6rem 0.75rem;
}

.custom-dropdown-option-special svg {
  width: 16px;
  height: 16px;
}

/* Grouped options */
.custom-dropdown-group {
  padding: 0;
}

.custom-dropdown-group-header {
  padding: 0.5rem 0.75rem;
  font-size: var(--text-xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  color: var(--accent-strong);
  background: var(--bg-secondary);
  position: sticky;
  top: 0;
  z-index: 1;
  border-bottom: 1px solid var(--border-color);
}

.custom-dropdown-group .custom-dropdown-option {
  padding-left: 1.25rem;
}

/* Search results (flat list when searching) */
.custom-dropdown-results {
  padding: 0.25rem 0;
}

.custom-dropdown-results .custom-dropdown-option {
  justify-content: space-between;
}

.custom-dropdown-results .result-label {
  flex: 1;
}

.custom-dropdown-results .result-tag {
  font-size: var(--text-xs);
  color: var(--text-secondary);
  background: color-mix(in srgb, var(--accent) 15%, transparent);
  padding: 0.15rem 0.5rem;
  border-radius: var(--radius-full);
  margin-left: 0.5rem;
  white-space: nowrap;
}

.custom-dropdown-no-results {
  padding: 1rem;
  text-align: center;
  color: var(--text-secondary);
  font-size: var(--text-ui);
}

/* ==========================================
   UTILITY CLASSES
   ========================================== */

.text-center {
  text-align: center;
}

.mb-1 {
  margin-bottom: var(--space-sm);
}

.mb-2 {
  margin-bottom: var(--space-md);
}

.mt-1 {
  margin-top: var(--space-sm);
}

.mt-2 {
  margin-top: var(--space-md);
}

/* ==========================================
   RESPONSIVE DESIGN
   ========================================== */

@media (max-width: 768px) {
  /* ---- Mobile navigation ----
     The nav collapses into a sheet that drops out of the sticky rail. The
     breakpoint here must stay in sync with MOBILE_BREAKPOINT in chrome.js,
     which closes the sheet when the viewport grows past it. */
  .nav-container {
    flex-direction: row;
    flex-wrap: wrap;
    gap: 0;
    position: relative;
    height: auto;
    min-height: 56px;
    padding-top: 0.5rem;
    padding-bottom: 0.5rem;
  }

  .mobile-menu-toggle {
    display: flex;
    align-items: center;
    justify-content: center;
  }

  .nav-links {
    display: none;
    flex-direction: column;
    width: 100%;
    padding: var(--space-xs) 0 0;
    gap: 0;
    order: 3;
  }

  .nav-links.mobile-open {
    display: flex;
  }

  .nav-links > li {
    width: 100%;
    border-top: 1px solid var(--border-color);
  }

  .nav-links > li > a,
  .nav-links > li > .dropdown-toggle {
    display: flex;
    padding: 0.7rem 0;
    width: 100%;
    border-radius: 0;
  }

  /* In the mobile sheet every entry is already a full-width row with its own
     hairline above it, so the CTA's pill outline would draw a second border
     inside the first. It keeps the violet ink instead, which is what makes it
     read as the action among the destinations. */
  .nav-links > li > a.nav-cta {
    margin-left: 0;
    border: none;
    background-color: transparent;
    box-shadow: none;
    color: var(--accent);
  }

  .nav-links > li > a.nav-cta:hover {
    background-color: transparent;
  }

  /* Submenus open in flow rather than floating: a popover anchored to a
     full-width row would overflow the viewport. */
  .dropdown-menu {
    position: static;
    background: transparent;
    border: none;
    border-radius: 0;
    box-shadow: none;
    padding: 0 0 0.4rem;
    min-width: 100%;
  }

  /* Hover must not open submenus on touch: the tap that "hovers" is the same
     tap that would follow the first link underneath. */
  .dropdown:hover .dropdown-menu {
    display: none;
  }

  .dropdown.is-open .dropdown-menu {
    display: block;
  }

  .dropdown-menu a,
  .dropdown-menu li form {
    padding-left: var(--space-sm);
  }

  main {
    padding: 0 var(--space-sm);
  }
}

@media (max-width: 480px) {
  .auth-container {
    padding: var(--space-sm);
  }
}

/* ==========================================
   ANIMATIONS & LOADING STATES
   ========================================== */

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

.spinner {
  display: inline-block;
  width: 20px;
  height: 20px;
  border: 3px solid var(--accent-soft);
  border-top-color: var(--accent);
  border-radius: 50%;
  animation: spin 0.8s linear infinite;
}

/* Smooth scrolling */
html {
  scroll-behavior: smooth;
}

/* Focus visible for accessibility */
:focus-visible {
  outline: 2px solid var(--focus-ring);
  outline-offset: 2px;
}
