/*
 * Happ — application styles.
 *
 * Contents:
 *   1. Design tokens — every color, dimension, and layer is defined here
 *   2. Reset & base
 *   3. App shell — sticky header, sidebar and content
 *   4. Sidebar navigation
 *   5. Mobile — on phones and iPads in portrait the sidebar becomes an
 *      off-canvas drawer
 *   6. Page content — headings and flashes
 *   7. Auth pages — centered card for login / password reset
 *
 * Layout model: the header is sticky and spans the window. Under it, .app-body
 * holds the sidebar and the content side by side. The sidebar is sticky on
 * desktop and fixed as a drawer. The /me page on its own has the header
 * without text, and under it the content in a single column.
 * The sidebar is a native popover, opened by the header hamburger
 * (popovertarget) on mobile and forced visible on desktop — the browser
 * handles open/close, Escape, click-outside, aria-expanded, and the
 * backdrop. No JavaScript involved.
 *
 * Cards, the dialog, forms and pills live in cards.css, dialog.css, forms.css
 * and pills.css, and the map, settings and users pages' styles in map.css,
 * settings.css and users.css. All of them are imported below so the layout
 * still links a single stylesheet.
 *
 * Hover styles sit inside @media (hover: hover). A touch screen keeps :hover on
 * the last spot tapped, which leaves whatever lands there looking hovered.
 */

@import url("/assets/cards-03913a2e.css");
@import url("/assets/dialog-3a03c0c4.css");
@import url("/assets/forms-5d8edf31.css");
@import url("/assets/map-f08b63e6.css");
@import url("/assets/pills-d3554465.css");
@import url("/assets/settings-f83a337a.css");
@import url("/assets/users-df127065.css");

/* 1. Design tokens */

:root {
  color-scheme: light;

  --color-bg: #faf9f4; /* warm off-white page background, settings sections */
  --color-surface: #ffffff; /* sidebar, cards */
  --color-text: #2b2b26;
  --color-text-muted: #6b6b60;
  --color-border: #e0ded4;
  --color-accent: #4a7c4a; /* primary actions, links */
  --color-accent-strong: #2f4f2f; /* header, headings, action hover */
  --color-accent-soft: #eaf2ea; /* selected nav item, notice flash */
  --color-accent-muted: #a8c9a8; /* selected control on the map */
  --color-danger: #8c3b3b;
  --color-danger-soft: #fbeaea;
  --color-backdrop: rgb(0 0 0 / 35%); /* behind the drawer and dialogs */

  /* Fields on the map get one colour each, named after the colour because
     that is how people refer to them: "the red field". A new field colour
     needs a token here and a modifier class in map.css. */
  --color-field-red: #d23b3b;
  --color-field-yellow: #d2b23b;
  --color-field-green: #3bd23b;
  --color-field-blue: #3b3bd2;
  --color-field-purple: #b23bd2;
  --color-field-brown: #b2723b;

  --color-position: #2d7ff9; /* the member's own position on the map */

  --header-height: 3.5rem;
  --sidebar-width: 15rem;
  --gap: 0.75rem; /* between cards, and the page margin on phones */
  --radius: 0.5rem;
  --radius-lg: 0.75rem;
  --drawer-duration: 0.3s; /* drawer slide and backdrop fade, in step */
  --dialog-duration: 0.2s; /* dialog and backdrop fade, in step */
}

/* 2. Reset & base */

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

body {
  margin: 0;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  line-height: 1.5;
  color: var(--color-text);
  background: var(--color-bg);
}

button,
input {
  font: inherit;
}

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

/* 3. App shell */

.app-header {
  position: sticky;
  top: 0;
  height: var(--header-height);
  background: var(--color-accent-strong);
  color: white;
  z-index: 1; /* above page content scrolling underneath */
}

/* The side padding is the same as .content's, so the header's edges line up
   with the page's. */
.app-header-inner {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  height: 100%;
  padding: 0 2rem;
}

.app-header :focus-visible {
  outline-color: white; /* the accent green is invisible on the dark header */
}

.brand {
  font-size: 1.35rem;
  font-weight: 700;
  letter-spacing: 0.02em;
}

/* Shown instead of the plain name when the user has other farms to switch
   to. It opens the farm menu. */
.farm-switcher {
  anchor-name: --farm-switcher;
  min-height: 2.75rem;
  padding: 0;
  background: none;
  border: none;
  color: inherit;
  cursor: pointer;
}

.farm-switcher::after {
  content: " ▾";
}

/* The user button and its menu, on the right of the header. */
.current-user {
  margin-inline-start: auto;
}

/* Opens the user menu. */
.user-button {
  anchor-name: --user-button;
  display: flex;
  align-items: center;
  gap: 0.5rem;
  min-height: 2.75rem;
  padding: 0;
  background: none;
  border: none;
  color: inherit;
  cursor: pointer;
}

.user-button::after {
  content: "▾";
}

.user-button img {
  width: 2rem;
}

/* A header menu is a native popover: the browser closes it on a click
   outside and on Escape. It sits in the top layer, outside the header's
   layout, so anchor positioning puts it under its button. inset and margin
   undo the browser's centering of popovers. */
.menu {
  inset: auto;
  margin: 0.5rem 0 0;
  padding: 0.25rem;
  list-style: none;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  box-shadow: 0 4px 12px rgb(0 0 0 / 15%);
}

.menu a {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.625rem 0.75rem;
  border-radius: var(--radius);
  color: var(--color-text);
  text-decoration: none;
  white-space: nowrap;
}

@media (hover: hover) {
  .menu a:hover {
    background: var(--color-accent-soft);
  }
}

/* The header's white outline would vanish on the menu's white background. */
.menu a:focus-visible {
  outline-color: var(--color-accent);
}

.farm-menu {
  position-anchor: --farm-switcher;
  position-area: bottom span-right;
}

/* The user button sits on the right, so its menu opens to the left. */
.user-menu {
  position-anchor: --user-button;
  position-area: bottom span-left;
}

.hamburger {
  display: none; /* mobile only — see the media query */
  flex-direction: column;
  justify-content: center;
  gap: 5px;
  width: 2.5rem;
  height: 2.5rem;
  padding: 0.5rem;
  background: transparent;
  border: none;
  cursor: pointer;
}

.hamburger span {
  display: block;
  width: 100%;
  height: 2px;
  background: white;
  border-radius: 1px;
}

/* Everything under the header. The min-height lets the map fill the window. */
.app-body {
  display: flex;
  min-height: calc(100dvh - var(--header-height));
}

/* A native popover: hidden by browser default, opened by the hamburger on
   mobile, forced visible on desktop. margin/height/border undo the
   browser's popover defaults; display is deliberately not set here — the
   browser owns it while the popover is closed. */
.sidebar {
  position: fixed;
  inset: var(--header-height) auto 0 0;
  width: var(--sidebar-width);
  height: auto;
  margin: 0;
  flex-direction: column;
  gap: 0.25rem;
  padding: 1rem 0.75rem;
  background: var(--color-surface);
  border: none;
  border-right: 1px solid var(--color-border);
}

.sidebar::backdrop {
  background: var(--color-backdrop);
}

.content {
  flex: 1;
  padding: 2rem;
}

/* The gap spaces the parts of a page as .dialog-body does in the dialog. */
.single-column {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  max-width: 80rem;
  margin-inline: auto;
}

/* 4. Sidebar navigation */

.nav-link {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.6rem 0.85rem;
  border-radius: var(--radius);
  font-size: 0.95rem;
  color: var(--color-text);
  text-decoration: none;
}

@media (hover: hover) {
  .nav-link:hover {
    background: var(--color-accent-soft);
  }
}

.nav-link[aria-current] {
  background: var(--color-accent-soft);
  color: var(--color-accent-strong);
  font-weight: 600;
}

.nav-icon {
  width: 1.5rem;
  font-size: 1.1rem;
  text-align: center;
}

/* 5. Desktop / mobile */

/* The drawer is for phones and for iPads in portrait, which are at most
   1032px wide. Width alone can't tell those from iPads in landscape, some
   of which are only 1024px wide. */
@media (width > 768px) and ((orientation: landscape) or (width > 1100px)) {
  /* A column in .app-body. Sticky keeps it in view while the page scrolls. */
  .sidebar {
    display: flex;
    position: sticky;
    flex-shrink: 0;
    height: calc(100dvh - var(--header-height));
  }

  /* If the drawer was open when the window grew, hide its backdrop. */
  .sidebar::backdrop {
    display: none;
  }
}

@media (width <= 768px), (orientation: portrait) and (width <= 1100px) {
  .hamburger {
    display: flex;
  }

  .sidebar {
    translate: -100% 0;
    box-shadow: 2px 0 12px rgb(0 0 0 / 15%);
    /* allow-discrete keeps the drawer displayed (and in the top layer)
       until the slide-out finishes. */
    transition:
      translate var(--drawer-duration) ease,
      display var(--drawer-duration) allow-discrete,
      overlay var(--drawer-duration) allow-discrete;
  }

  .sidebar:popover-open {
    display: flex;
    translate: 0;
  }

  .sidebar::backdrop {
    opacity: 0;
    transition: opacity var(--drawer-duration) ease;
  }

  .sidebar:popover-open::backdrop {
    opacity: 1;
  }

  /* Where the slide and fade start from on open. */
  @starting-style {
    .sidebar:popover-open {
      translate: -100% 0;
    }

    .sidebar:popover-open::backdrop {
      opacity: 0;
    }
  }
}

@media (width <= 768px) {
  .app-header-inner {
    padding-inline: var(--gap);
  }

  .content {
    padding: var(--gap);
  }
}

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

/* 6. Page content */

h1 {
  margin-top: 0;
  color: var(--color-accent-strong);
}

/* At the browser's bold weight of 700, these headings look too heavy. */
h2,
h3 {
  font-weight: 600;
}

/* An h2 starts a new part of the page, like a list of cards, so it keeps its
   distance from the part above. */
h2 {
  margin: 2rem 0 0.75rem;
  font-size: 1.25rem;
  color: var(--color-accent-strong);
}

h3 {
  font-size: 1rem;
}

hgroup > * {
  margin: 0;
}

hr {
  border: none;
  border-top: 1px solid var(--color-border);
}

/* A page below another, such as a team's page under Teams, has a link back
   up right under its heading. The link's height makes the tap target, so the
   heading drops its bottom margin. */
.page-heading {
  margin-bottom: 1rem;
}

.page-heading h1 {
  margin: 0;
}

.back-link {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  min-height: 2.75rem;
  font-size: 0.9rem;
  color: var(--color-accent);
}

.muted {
  color: var(--color-text-muted);
}

.flash {
  margin-bottom: 1.25rem;
  padding: 0.75rem 1rem;
  border-radius: var(--radius);
  font-size: 0.9rem;
}

.flash-notice {
  background: var(--color-accent-soft);
  color: var(--color-accent-strong);
}

.flash-alert {
  background: var(--color-danger-soft);
  color: var(--color-danger);
}

/* A note that goes by itself, such as a flash or the map's message, driven by
   the message controller. On the way out it folds shut while it fades, so what
   is under it slides up. Its words sit in a span, the one row of a grid,
   because a grid row can animate from 1fr to 0fr where a height of auto
   cannot animate in every browser. */
.message {
  /* How long the note stays before it goes. The message controller sets this
     per note, from how much there is to read; this is the fallback. Both the
     exit's delay and the countdown bar's duration read it, so they cannot
     drift apart, and the bar inherits it as a pseudo-element. */
  --message-hold: 5s;

  display: grid;
  grid-template-rows: 1fr;
  position: relative;
  overflow: hidden; /* keeps the bar inside the rounded corners */
  animation: message-exit 300ms ease-out var(--message-hold) forwards;
}

/* The display above would otherwise beat the browser's own [hidden] rule. */
.message[hidden] {
  display: none;
}

/* Lets the row shrink below the height of its words. */
.message > span {
  overflow: hidden;
}

@keyframes message-exit {
  to {
    grid-template-rows: 0fr;
    padding-block: 0;
    margin-block: 0;
    opacity: 0;
  }
}

/* How long the note has left: a bar across the top whose right edge travels
   left. It runs for the wait, so emptying is what starts the fade. */
.message::before {
  content: "";
  position: absolute;
  inset: 0 0 auto;
  height: 3px;
  background: var(--color-accent);
  transform-origin: left;
  animation: message-countdown var(--message-hold) linear forwards;
}

@keyframes message-countdown {
  to {
    transform: scaleX(0);
  }
}

.flash-alert::before {
  background: var(--color-danger);
}

/* 7. Auth pages */

.auth {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  min-height: 100dvh;
  padding: 1.5rem;
}

.auth-card {
  width: 100%;
  max-width: 28rem;
  padding: 2rem;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
}

.auth-card h1 {
  margin-bottom: 1.5rem;
  text-align: center;
}

/* Only in development: a button per seed user that logs in without a password. */
.auth-quick-login {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin-bottom: 1.5rem;
  font-size: 0.85rem;
}

.auth-quick-login p {
  flex-basis: 100%;
  margin: 0;
  color: var(--color-text-muted);
}

.auth-quick-login button {
  min-height: 2.75rem;
  padding-inline: 1rem;
  border: none;
  border-radius: var(--radius);
  background: var(--color-accent-soft);
  color: var(--color-accent-strong);
  font-weight: 600;
  cursor: pointer;
}

@media (hover: hover) {
  .auth-quick-login button:hover {
    background: var(--color-accent-muted);
  }
}

.auth-links {
  margin-top: 1rem;
  text-align: center;
  font-size: 0.85rem;
}

.auth-links a {
  color: var(--color-accent);
}
