/* ==========================================================================
   GlucoRead theme: the tokens and primitives shared by every page — the
   landing page, the auth screens, and the authenticated app.

   Design language ported from the "Hospital Data Management Dashboard" Figma
   Make file (NSR3WfZlAKJSfIMPWmhgSu). That file is React + Tailwind; its
   globals.css is stock shadcn boilerplate, so the real tokens are the Tailwind
   literals in its components. Mapped here:

     teal-600  #0d9488  -> --accent          the one brand/action colour
     teal-500  #14b8a6  -> --accent-bright   chart strokes and fills
     blue-600  #2563eb  -> --insulin         insulin is blue throughout
     orange-600 #ea580c -> --meal            meals/carbs are orange
     green-600 #16a34a  -> --range           in-range readings
     red-600   #dc2626  -> --danger          low readings, destructive actions
     gray-50   #f9fafb  -> --paper           the page ground
     gray-200  #e5e7eb  -> --line
     radius    0.625rem -> --r-lg (10px)

   Shape rule, held everywhere: surfaces 10px, controls and inputs 8px, small
   chrome 6px. Only icon pucks, avatars and status dots are circles. Nothing
   else is a pill — the previous cobalt theme made every button a pill, and
   mixing pill buttons into a 10px card grid is what made the old app read as
   two designs stapled together.

   Theme resolution, in order:
     1. html[data-theme="light" | "dark"] - an explicit choice, stored by
        main/js/theme.js and applied before first paint.
     2. prefers-color-scheme - the system setting, when no choice is stored.
   ========================================================================== */

:root {
  /* ---- light: the Figma's palette, which is the designed one ---- */
  --paper-l: #f9fafb;
  --paper-2-l: #f3f4f6;
  --surface-l: #ffffff;
  --ink-l: #111827;
  --ink-2-l: #4b5563;
  --ink-3-l: #6b7280;
  --line-l: #e5e7eb;
  --line-soft-l: #f3f4f6;

  --accent-l: #0d9488;
  --accent-hover-l: #0f766e;
  --accent-ink-l: #ffffff;
  --accent-bright-l: #14b8a6;
  --accent-soft-l: #ccfbf1;
  --accent-wash-l: #f0fdfa;
  --accent-line-l: #99f6e4;
  --accent-deep-l: #115e59;
  /* teal-700. --accent is teal-600, and white on teal-600 is 3.7:1 — under AA
     for the primary button's label. The brand colour itself is unchanged;
     this is only what a solid button and a pressed segment are filled with. */
  --accent-strong-l: #0f766e;
  --accent-strong-hover-l: #115e59;

  --insulin-l: #2563eb;
  --insulin-soft-l: #dbeafe;
  --insulin-wash-l: #eff6ff;
  --insulin-deep-l: #1d4ed8;
  --meal-l: #ea580c;
  --meal-soft-l: #ffedd5;
  --meal-wash-l: #fff7ed;
  --meal-deep-l: #9a3412;

  /* The -deep variants exist for text on a -soft or -wash fill. A badge's
     label is 12px, so it needs the 4.5:1 threshold, and the 600-weight hue
     that reads well as a dot or a chart stroke does not clear it on its own
     tint. Dark mode needs no equivalent — its tints are translucent over a
     dark surface, where the base hue already passes — so the dark bindings
     below simply point --*-deep at the base tone. */
  --range-l: #16a34a;
  --range-soft-l: #dcfce7;
  --range-wash-l: #f0fdf4;
  --range-deep-l: #15803d;
  --warn-l: #d97706;
  --warn-soft-l: #fef3c7;
  --warn-wash-l: #fffbeb;
  --warn-deep-l: #92400e;
  --danger-l: #dc2626;
  --danger-soft-l: #fee2e2;
  --danger-wash-l: #fef2f2;
  --danger-deep-l: #b91c1c;

  --shadow-sm-l: 0 1px 2px rgba(17, 24, 39, 0.06);
  --shadow-lg-l: 0 1px 3px rgba(17, 24, 39, 0.08), 0 12px 32px -16px rgba(17, 24, 39, 0.22);

  /* ---- dark: derived, not designed. The source file's .dark block is the
     unmodified shadcn grayscale, so it carries no intent to port. These keep
     the same hue relationships (teal leads, blue/orange/green/red separate the
     three log types and the range states) at dark-surface luminance. ---- */
  --paper-d: #0d1214;
  --paper-2-d: #151d20;
  --surface-d: #121a1d;
  --ink-d: #e6edf0;
  --ink-2-d: #9fb0b6;
  --ink-3-d: #7d9099;
  --line-d: rgba(255, 255, 255, 0.11);
  --line-soft-d: rgba(255, 255, 255, 0.06);

  --accent-d: #2dd4bf;
  --accent-hover-d: #5eead4;
  --accent-ink-d: #04211d;
  --accent-bright-d: #2dd4bf;
  --accent-soft-d: rgba(45, 212, 191, 0.16);
  --accent-wash-d: rgba(45, 212, 191, 0.08);
  --accent-line-d: rgba(45, 212, 191, 0.32);
  --accent-deep-d: #99f6e4;
  --accent-strong-d: #2dd4bf;
  --accent-strong-hover-d: #5eead4;

  --insulin-d: #7dabff;
  --insulin-soft-d: rgba(125, 171, 255, 0.18);
  --insulin-wash-d: rgba(125, 171, 255, 0.09);
  --insulin-deep-d: #7dabff;
  --meal-d: #fb923c;
  --meal-soft-d: rgba(251, 146, 60, 0.18);
  --meal-wash-d: rgba(251, 146, 60, 0.09);
  --meal-deep-d: #fb923c;

  --range-d: #4ade80;
  --range-soft-d: rgba(74, 222, 128, 0.17);
  --range-wash-d: rgba(74, 222, 128, 0.08);
  --range-deep-d: #4ade80;
  --warn-d: #fbbf24;
  --warn-soft-d: rgba(251, 191, 36, 0.17);
  --warn-wash-d: rgba(251, 191, 36, 0.08);
  --warn-deep-d: #fbbf24;
  --danger-d: #f87171;
  --danger-soft-d: rgba(248, 113, 113, 0.17);
  --danger-wash-d: rgba(248, 113, 113, 0.09);
  --danger-deep-d: #f87171;

  --shadow-sm-d: 0 1px 2px rgba(0, 0, 0, 0.5);
  --shadow-lg-d: 0 1px 3px rgba(0, 0, 0, 0.5), 0 16px 40px -20px rgba(0, 0, 0, 0.8);

  /* ---- light is the default binding ---- */
  --paper: var(--paper-l);
  --paper-2: var(--paper-2-l);
  --surface: var(--surface-l);
  --ink: var(--ink-l);
  --ink-2: var(--ink-2-l);
  --ink-3: var(--ink-3-l);
  --line: var(--line-l);
  --line-soft: var(--line-soft-l);
  --accent: var(--accent-l);
  --accent-hover: var(--accent-hover-l);
  --accent-ink: var(--accent-ink-l);
  --accent-bright: var(--accent-bright-l);
  --accent-soft: var(--accent-soft-l);
  --accent-wash: var(--accent-wash-l);
  --accent-line: var(--accent-line-l);
  --accent-deep: var(--accent-deep-l);
  --accent-strong: var(--accent-strong-l);
  --accent-strong-hover: var(--accent-strong-hover-l);
  --insulin: var(--insulin-l);
  --insulin-soft: var(--insulin-soft-l);
  --insulin-wash: var(--insulin-wash-l);
  --insulin-deep: var(--insulin-deep-l);
  --meal: var(--meal-l);
  --meal-soft: var(--meal-soft-l);
  --meal-wash: var(--meal-wash-l);
  --meal-deep: var(--meal-deep-l);
  --range: var(--range-l);
  --range-soft: var(--range-soft-l);
  --range-wash: var(--range-wash-l);
  --range-deep: var(--range-deep-l);
  --warn: var(--warn-l);
  --warn-soft: var(--warn-soft-l);
  --warn-wash: var(--warn-wash-l);
  --warn-deep: var(--warn-deep-l);
  --danger: var(--danger-l);
  --danger-soft: var(--danger-soft-l);
  --danger-wash: var(--danger-wash-l);
  --danger-deep: var(--danger-deep-l);
  --shadow-sm: var(--shadow-sm-l);
  --shadow-lg: var(--shadow-lg-l);
  --select-chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%236b7280' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");

  color-scheme: light;

  --r-lg: 10px;
  --r-md: 8px;
  --r-sm: 6px;
  --r-pill: 999px;
  --ease: cubic-bezier(0.16, 1, 0.3, 1);
  --maxw: 1160px;
  --gutter: clamp(1.25rem, 4vw, 2.5rem);
  --font-sans: "Geist", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --font-mono: "Geist Mono", ui-monospace, "SFMono-Regular", Menlo, monospace;

  /* app shell metrics, straight from the source layout */
  --rail-w: 256px;
  --header-h: 64px;
}

/* The dark bindings are identical in both selectors below; they differ only in
   what triggers them (system setting vs. explicit choice), so they are kept in
   step by hand. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --paper: var(--paper-d);
    --paper-2: var(--paper-2-d);
    --surface: var(--surface-d);
    --ink: var(--ink-d);
    --ink-2: var(--ink-2-d);
    --ink-3: var(--ink-3-d);
    --line: var(--line-d);
    --line-soft: var(--line-soft-d);
    --accent: var(--accent-d);
    --accent-hover: var(--accent-hover-d);
    --accent-ink: var(--accent-ink-d);
    --accent-bright: var(--accent-bright-d);
    --accent-soft: var(--accent-soft-d);
    --accent-wash: var(--accent-wash-d);
    --accent-line: var(--accent-line-d);
    --accent-deep: var(--accent-deep-d);
  --accent-strong: var(--accent-strong-d);
  --accent-strong-hover: var(--accent-strong-hover-d);
    --insulin: var(--insulin-d);
    --insulin-soft: var(--insulin-soft-d);
    --insulin-wash: var(--insulin-wash-d);
  --insulin-deep: var(--insulin-deep-d);
    --meal: var(--meal-d);
    --meal-soft: var(--meal-soft-d);
    --meal-wash: var(--meal-wash-d);
  --meal-deep: var(--meal-deep-d);
    --range: var(--range-d);
    --range-soft: var(--range-soft-d);
    --range-wash: var(--range-wash-d);
  --range-deep: var(--range-deep-d);
    --warn: var(--warn-d);
    --warn-soft: var(--warn-soft-d);
    --warn-wash: var(--warn-wash-d);
  --warn-deep: var(--warn-deep-d);
    --danger: var(--danger-d);
    --danger-soft: var(--danger-soft-d);
    --danger-wash: var(--danger-wash-d);
  --danger-deep: var(--danger-deep-d);
    --shadow-sm: var(--shadow-sm-d);
    --shadow-lg: var(--shadow-lg-d);
    --select-chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%237d9099' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");

    color-scheme: dark;
  }
}

:root[data-theme="dark"] {
  --paper: var(--paper-d);
  --paper-2: var(--paper-2-d);
  --surface: var(--surface-d);
  --ink: var(--ink-d);
  --ink-2: var(--ink-2-d);
  --ink-3: var(--ink-3-d);
  --line: var(--line-d);
  --line-soft: var(--line-soft-d);
  --accent: var(--accent-d);
  --accent-hover: var(--accent-hover-d);
  --accent-ink: var(--accent-ink-d);
  --accent-bright: var(--accent-bright-d);
  --accent-soft: var(--accent-soft-d);
  --accent-wash: var(--accent-wash-d);
  --accent-line: var(--accent-line-d);
  --accent-deep: var(--accent-deep-d);
  --accent-strong: var(--accent-strong-d);
  --accent-strong-hover: var(--accent-strong-hover-d);
  --insulin: var(--insulin-d);
  --insulin-soft: var(--insulin-soft-d);
  --insulin-wash: var(--insulin-wash-d);
  --insulin-deep: var(--insulin-deep-d);
  --meal: var(--meal-d);
  --meal-soft: var(--meal-soft-d);
  --meal-wash: var(--meal-wash-d);
  --meal-deep: var(--meal-deep-d);
  --range: var(--range-d);
  --range-soft: var(--range-soft-d);
  --range-wash: var(--range-wash-d);
  --range-deep: var(--range-deep-d);
  --warn: var(--warn-d);
  --warn-soft: var(--warn-soft-d);
  --warn-wash: var(--warn-wash-d);
  --warn-deep: var(--warn-deep-d);
  --danger: var(--danger-d);
  --danger-soft: var(--danger-soft-d);
  --danger-wash: var(--danger-wash-d);
  --danger-deep: var(--danger-deep-d);
  --shadow-sm: var(--shadow-sm-d);
  --shadow-lg: var(--shadow-lg-d);
  --select-chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%237d9099' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");

  color-scheme: dark;
}

/* --------------------------------- tones ---------------------------------
   A component asks for a hue by setting --tone / --tone-soft / --tone-wash
   through a .t-* class, and every coloured part (icon puck, badge, value,
   action tile, legend dot) reads those. One variable per component keeps a
   card's colour from drifting between its puck and its badge.

   These live here rather than in app.css because the landing page loads only
   this stylesheet, and it colour-codes glucose/insulin/meals the same way the
   dashboard does. Two copies would drift.
   ------------------------------------------------------------------------ */
.t-glucose {
  --tone: var(--accent);
  --tone-soft: var(--accent-soft);
  --tone-wash: var(--accent-wash);
  --tone-line: var(--accent-line);
  --tone-ink: var(--accent-deep);
}

.t-insulin {
  --tone: var(--insulin);
  --tone-soft: var(--insulin-soft);
  --tone-wash: var(--insulin-wash);
  --tone-line: var(--insulin-soft);
  --tone-ink: var(--insulin-deep);
}

.t-meal {
  --tone: var(--meal);
  --tone-soft: var(--meal-soft);
  --tone-wash: var(--meal-wash);
  --tone-line: var(--meal-soft);
  --tone-ink: var(--meal-deep);
}

.t-range {
  --tone: var(--range);
  --tone-soft: var(--range-soft);
  --tone-wash: var(--range-wash);
  --tone-line: var(--range-soft);
  --tone-ink: var(--range-deep);
}

.t-warn {
  --tone: var(--warn);
  --tone-soft: var(--warn-soft);
  --tone-wash: var(--warn-wash);
  --tone-line: var(--warn-soft);
  --tone-ink: var(--warn-deep);
}

.t-danger {
  --tone: var(--danger);
  --tone-soft: var(--danger-soft);
  --tone-wash: var(--danger-wash);
  --tone-line: var(--danger-soft);
  --tone-ink: var(--danger-deep);
}

/* The quiet tone, for a value that is deliberately not colour-coded — basal
   insulin, which is the flat background dose. --surface rather than --paper-2
   for the soft fill: rows are themselves --paper-2, so a puck filled with it
   vanished into the row it sat on. This pairs with the grey half of the
   basal/bolus split bar, so the two say the same thing. */
.t-neutral {
  --tone: var(--ink-2);
  --tone-ink: var(--ink-2);
  --tone-soft: var(--surface);
  --tone-wash: var(--surface);
  --tone-line: var(--line);
}

/* ------------------------- shared small primitives ------------------------
   Icons, badges and the range meter are used by the authenticated app AND by
   the landing page, which loads only this stylesheet. They sit here for the
   same reason the tones above do: two copies would drift, and the landing
   page's whole argument is that it shows the real product's parts.
   ------------------------------------------------------------------------ */

/* Every glyph is a <use> into the sprite in main/_icon_sprite.html. Stroke
   presentation lives here rather than on each symbol so one symbol can be
   drawn at any size and inherit the colour of its container. */
.icon {
  width: 20px;
  height: 20px;
  flex: none;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.icon-sm {
  width: 16px;
  height: 16px;
}

.icon-lg {
  width: 24px;
  height: 24px;
}

/* Status pill. Reads --tone/--tone-soft, so a .t-* class on the badge or on
   any ancestor colours it. */
.badge {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  padding: 0.15rem 0.55rem;
  border-radius: var(--r-sm);
  font-size: 0.75rem;
  font-weight: 500;
  white-space: nowrap;
  /* --tone-ink, not --tone: at 12px this label needs 4.5:1 against its own
     tint, which the 600-weight hue does not reach in light mode. */
  color: var(--tone-ink, var(--tone));
  background: var(--tone-soft);
}

.badge-outline {
  color: var(--ink-2);
  background: transparent;
  border: 1px solid var(--line);
}

/* Time-in-range meter: the rail's progress card, and the landing page's
   targets section. */
.meter {
  margin-top: 0.5rem;
  height: 8px;
  border-radius: var(--r-pill);
  background: var(--accent-soft);
  overflow: hidden;
}

.meter > span {
  display: block;
  height: 100%;
  border-radius: var(--r-pill);
  background: var(--accent);
}

/* Icon puck and the header's latest-reading chip, both driven by --tone. */
.puck {
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  flex: none;
  border-radius: var(--r-pill);
  color: var(--tone);
  background: var(--tone-soft);
}

.puck-sm {
  width: 36px;
  height: 36px;
}

.reading-chip {
  display: flex;
  align-items: center;
  gap: 0.65rem;
  padding: 0.4rem 0.75rem;
  background: var(--tone-wash);
  border: 1px solid var(--tone-line);
  border-radius: var(--r-md);
}

.reading-chip-label {
  font-size: 0.6875rem;
  color: var(--tone-ink, var(--tone));
  line-height: 1.2;
}

.reading-chip-value {
  font-size: 0.875rem;
  font-weight: 500;
  color: var(--ink);
  line-height: 1.3;
  white-space: nowrap;
}

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

html {
  scroll-behavior: smooth;
  scroll-padding-top: 5.5rem;
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-sans);
  font-size: 1rem;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

h1,
h2,
h3 {
  margin: 0;
  font-weight: 600;
  letter-spacing: -0.025em;
  line-height: 1.1;
  text-wrap: balance;
}

p {
  margin: 0;
}

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

svg {
  display: block;
  max-width: 100%;
}

/* The rule above is a type selector, so it outranks the user-agent's
   `[hidden] { display: none }` — which made the inlined icon sprite paint as
   an empty 300x150 replaced element at the top of every page. Anything marked
   hidden stays hidden. */
[hidden] {
  display: none !important;
}

::selection {
  background: var(--accent-soft);
}

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

.container {
  width: 100%;
  max-width: var(--maxw);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 100;
  padding: 0.75rem 1.25rem;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
}

.skip-link:focus {
  left: 1rem;
  top: 1rem;
}

/* Two very soft washes so the paper is not flat. Fixed and pointer-inert, so
   it never repaints during scroll. */
.ambience {
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background:
    radial-gradient(46rem 30rem at 78% -8%, var(--accent-soft), transparent 68%),
    radial-gradient(38rem 26rem at 4% 32%, var(--range-soft), transparent 70%);
}

/* -------------------------------- topbar --------------------------------- */
.topbar {
  position: sticky;
  top: 0;
  z-index: 30;
  height: 68px;
  display: flex;
  align-items: center;
  border-bottom: 1px solid transparent;
  transition: border-color 0.3s var(--ease);
}

/* The frosted panel is painted by a pseudo-element, never by .topbar itself.
   backdrop-filter (like transform and filter) turns an element into the
   containing block for every fixed-position descendant. With the blur on the
   bar, the mobile drawer below — position: fixed; inset: 68px 0 0 0 — resolved
   against the 68px bar instead of the viewport the moment the bar went sticky,
   collapsing to nothing somewhere off the top of the screen. The pseudo-element
   is a sibling of the drawer, not an ancestor, so it blurs without capturing
   it. */
.topbar::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background: transparent;
  transition: background 0.3s var(--ease);
}

.topbar.is-stuck::before {
  background: var(--paper); /* fallback where color-mix is unsupported */
  background: color-mix(in srgb, var(--paper) 82%, transparent);
  backdrop-filter: blur(14px) saturate(150%);
  -webkit-backdrop-filter: blur(14px) saturate(150%);
}

.topbar.is-stuck {
  border-bottom-color: var(--line-soft);
}

.topbar-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  font-weight: 600;
  letter-spacing: -0.02em;
}

/* the brand mark is the target-range band, reduced to a single dot */
.brand-mark {
  width: 12px;
  height: 12px;
  border-radius: var(--r-pill);
  background: var(--accent);
  box-shadow: 0 0 0 4px var(--accent-soft);
  flex: none;
}

.menu {
  display: flex;
  align-items: center;
  gap: clamp(0.75rem, 1.9vw, 1.5rem);
  font-size: 0.94rem;
  white-space: nowrap;
}

.menu > a:not(.btn) {
  color: var(--ink-2);
  padding-block: 0.35rem;
  background-image: linear-gradient(var(--accent), var(--accent));
  background-size: 0% 1.5px;
  background-position: 0 100%;
  background-repeat: no-repeat;
  transition: color 0.25s var(--ease), background-size 0.35s var(--ease);
}

.menu > a:not(.btn):hover {
  color: var(--ink);
  background-size: 100% 1.5px;
}

.menu-btn {
  display: none;
  font: inherit;
  font-size: 0.9rem;
  color: var(--ink);
  background: transparent;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  padding: 0.45rem 1rem;
  cursor: pointer;
}

/* Watched by the topbar: while this strip is in view the page is at the top,
   so the bar stays transparent. */
.top-sentinel {
  position: absolute;
  top: 0;
  left: 0;
  width: 1px;
  height: 68px;
  pointer-events: none;
}

/* -------------------------- segmented controls ---------------------------- */
/* Used for the theme switch and the unit switch, so both read as the same
   kind of control. */
.segmented {
  display: inline-flex;
  padding: 3px;
  gap: 3px;
  background: var(--paper-2);
  border-radius: var(--r-md);
}

.segmented button {
  font: inherit;
  font-size: 0.84rem;
  color: var(--ink-2);
  background: transparent;
  border: 0;
  border-radius: var(--r-sm);
  padding: 0.35rem 0.85rem;
  cursor: pointer;
  transition: color 0.25s var(--ease), background 0.25s var(--ease);
}

.segmented button[aria-pressed="true"] {
  color: var(--accent-ink);
  background: var(--accent-strong);
}

.segmented button:hover:not([aria-pressed="true"]) {
  color: var(--ink);
}

/* ----------------------------- theme switch ------------------------------ */
/* A two-state switch: sun on the left, moon on the right, thumb slides. */
/* Bare `button { ... }` rules in the app stylesheets would otherwise paint a
   filled box behind the switch, so hold the reset through every state. */
.theme-switch,
.theme-switch:hover,
.theme-switch:active,
.theme-switch:focus {
  padding: 0;
  border: 0;
  background: none;
  box-shadow: none;
  cursor: pointer;
  line-height: 0;
}

.theme-switch-track {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.35rem;
  width: 58px;
  height: 30px;
  padding: 0 7px;
  border-radius: var(--r-pill);
  background: var(--paper-2);
  border: 1px solid var(--line-soft);
}

.theme-icon {
  position: relative;
  z-index: 1;
  width: 15px;
  height: 15px;
  color: var(--ink-3);
  transition: color 0.25s var(--ease);
}

:root[data-theme="light"] .theme-switch .is-sun,
:root[data-theme="dark"] .theme-switch .is-moon,
.theme-switch[aria-checked="false"] .is-sun,
.theme-switch[aria-checked="true"] .is-moon {
  color: var(--accent-ink);
}

.theme-switch-thumb {
  position: absolute;
  top: 50%;
  left: 3px;
  width: 22px;
  height: 22px;
  margin-top: -11px;
  border-radius: var(--r-pill);
  background: var(--accent);
  box-shadow: var(--shadow-sm);
  transition: transform 0.28s var(--ease);
}

:root[data-theme="dark"] .theme-switch-thumb,
.theme-switch[aria-checked="true"] .theme-switch-thumb {
  transform: translateX(28px);
}

:root[data-theme="light"] .theme-switch-thumb {
  transform: none;
}

.theme-switch:hover .theme-switch-track {
  border-color: var(--line);
}

.theme-switch:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
  border-radius: var(--r-pill);
}

.theme-switch:active .theme-switch-thumb {
  width: 26px;
}

/* -------------------------------- buttons -------------------------------- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  white-space: nowrap;
  font: inherit;
  font-size: 0.9rem;
  font-weight: 500;
  padding: 0.6rem 1.1rem;
  border-radius: var(--r-md);
  border: 1px solid transparent;
  cursor: pointer;
  transition: transform 0.2s var(--ease), background 0.2s var(--ease),
    border-color 0.2s var(--ease), box-shadow 0.2s var(--ease);
}

.btn-sm {
  font-size: 0.84rem;
  padding: 0.42rem 0.85rem;
}

.btn-full {
  width: 100%;
}

.btn-primary {
  background: var(--accent-strong);
  color: var(--accent-ink);
  box-shadow: var(--shadow-sm);
}

.btn-primary:hover {
  background: var(--accent-strong-hover);
  transform: translateY(-2px);
  box-shadow: var(--shadow-lg);
}

.btn-quiet {
  color: var(--ink);
  border-color: var(--line);
  background: transparent;
}

.btn-quiet:hover {
  border-color: var(--ink-3);
  transform: translateY(-2px);
}

.btn:active {
  transform: translateY(1px);
}

.actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
}

/* --------------------------------- forms --------------------------------- */
/* Label above the input, help text under the label, error under the field. */
.field {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
}

.field > label {
  font-size: 0.88rem;
  font-weight: 500;
  color: var(--ink);
}

.field-help {
  font-size: 0.8rem;
  color: var(--ink-2);
}

.field input,
.field select,
.field textarea {
  font: inherit;
  width: 100%;
  color: var(--ink);
  background-color: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  padding: 0.7rem 0.85rem;
  transition: border-color 0.2s var(--ease), box-shadow 0.2s var(--ease);
}

.field input::placeholder {
  color: var(--ink-3);
}

.field input:focus,
.field select:focus,
.field textarea:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
}

.field-errors {
  margin: 0;
  padding: 0;
  list-style: none;
  font-size: 0.84rem;
  color: var(--danger);
}

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

.form-errors {
  margin: 0 0 1.25rem;
  padding: 0.85rem 1rem;
  list-style: none;
  font-size: 0.9rem;
  color: var(--danger);
  background: var(--surface);
  border: 1px solid var(--danger);
  border-radius: var(--r-md);
}


/* -------------------------------- selects -------------------------------- */
/* Native select chrome ignores the theme entirely — on macOS it paints its own
   grey capsule, which sits in a teal-and-white card looking like a control from
   a different application. `appearance: none` strips that and the rules below
   put it back in the app's own language.

   Still a real <select>: the options list stays the platform's own, so keyboard
   behaviour, type-ahead, screen readers and mobile pickers all keep working. A
   JS-driven listbox would let the popup be styled too, and would forfeit every
   one of those unless painstakingly rebuilt. Not a trade worth making for a
   chevron.

   The chevron is lucide's chevron-down as a data URI, held in --select-chevron
   so the light and dark variants are set once, next to the other tokens. Its
   stroke colour has to be baked in — a data URI cannot read a custom property —
   so the two hexes are --ink-3 light and dark, and MUST be updated with that
   token. Routing it through a variable also means exactly one rule sets
   background-image on a select, which is what lets the list-box rule below
   override it; setting the image directly in each theme block outranked that
   override and put a chevron on multi-selects. */
select {
  appearance: none;
  -webkit-appearance: none;
  cursor: pointer;
  background-image: var(--select-chevron);
  background-repeat: no-repeat;
  background-position: right 0.7rem center;
  background-size: 16px 16px;
}

/* :root deliberately raises specificity above the page stylesheets' own
   `padding` shorthands (.form-card select, .profile-container select), which
   would otherwise reset the gutter and let a long option run under the
   chevron. */
:root select:not([multiple]) {
  padding-right: 2.4rem;
}

select:hover {
  border-color: var(--ink-3);
}

/* A list box, not a drop-down: no collapsed state, so a chevron would point at
   nothing. Covers <select multiple> and any sized select. */
select[multiple],
select[size]:not([size="1"]) {
  background-image: none;
  cursor: default;
}

select[multiple] option {
  padding: 0.3rem 0.4rem;
  border-radius: var(--r-sm);
}

/* Windows and Linux paint the popup from these; macOS uses the system menu and
   ignores them, which is why `color-scheme` on :root carries the dark popup. */
select option {
  background-color: var(--surface);
  color: var(--ink);
}

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

  *,
  *::before,
  *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    animation-delay: 0ms !important;
    transition-duration: 0.001ms !important;
    transition-delay: 0ms !important;
  }
}

/* ------------------------------- responsive ------------------------------ */
@media (max-width: 860px) {
  .menu-btn {
    display: inline-flex;
  }

  /* A full-screen drawer, not a small dropdown: at phone widths there isn't
     room for a card floating over the hero, and a short card left the hero's
     own "Create account"/"Sign in" buttons visible (and overlapping) right
     behind it. Fixed to the viewport, below the topbar, with its own scroll,
     so every item is reachable without the page needing to zoom or scroll. */
  .menu {
    position: fixed;
    inset: 68px 0 0 0;
    flex-direction: column;
    align-items: stretch;
    gap: 0.35rem;
    margin: 0;
    padding: 1rem var(--gutter) 1.5rem;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    background: var(--surface);
    border: 0;
    border-radius: 0;
    box-shadow: none;
    opacity: 0;
    transform: translateY(-8px);
    pointer-events: none;
    transition: opacity 0.25s var(--ease), transform 0.25s var(--ease);
    /* Keeps a swipe inside the drawer from chaining into the page behind it
       once the drawer's own scroll hits either end. This replaces an
       `overflow: hidden` lock on <html>: a non-scrolling root has no
       scrollport for `position: sticky` to resolve against, so the topbar fell
       back to its static position — scrolled off the top of the screen, taking
       the button that closes the drawer with it — and the page jumped as the
       scroll offset was clamped. */
    overscroll-behavior: contain;
  }

  .menu.open {
    opacity: 1;
    transform: none;
    pointer-events: auto;
  }

  .menu > a:not(.btn) {
    padding: 0.65rem 0.75rem;
    background-size: 0 0;
  }

  .menu .theme-switch {
    align-self: flex-start;
    margin: 0.35rem 0.25rem;
  }

  .menu .btn {
    margin-top: 0.25rem;
    padding-block: 0.7rem;
  }
}
