/* ==========================================================================
   THE CANOPY · design system
   RVA Tropical & Exotic Plants

   Editorial, not decorative. The surfaces are crisp, the type is large and
   confident, the palette is mostly paper and navy with coral spent once per
   screen. Depth comes from scale, whitespace and photography — not from
   rounded corners or drop shadows.

   The signature is THE DRAWN LINE: hairline rules that grow left-to-right as
   they scroll into view. Section heads, link underlines, the events spine and
   the milestone path all draw themselves. It reads as growth, which is the
   subject, and it means the page is built from rules and air rather than from
   boxes.

   Two font weights per viewport: 600/700 (display) + 400 (body).
   Six brand colors and nothing else.
   ========================================================================== */

/* Licensed Proxima Nova ships from Adobe Fonts — swap in the kit ID at deploy:
   <link rel="stylesheet" href="https://use.typekit.net/XXXXXXX.css">          */

:root {
  /* ---- palette ---------------------------------------------------------- */
  --canvas:      #F3F0E9;   /* warm paper — the ground */
  --canvas-card: #FBF9F5;   /* a surface barely lifted off the paper */
  --canvas-sunk: #E9E4D9;   /* recessed: form wells, tracks, inactive chips */
  --navy:        #2C3E50;
  --navy-soft:   #3E5568;
  /* .56 measured at ~3.0:1 against --canvas / --canvas-card — under the
     4.5:1 AA floor for normal-size text, and this token carries meta/
     secondary copy at 13-15px (well under the 18px "large text" cutoff
     that would let 3:1 stand). .74 clears AA on both surfaces (4.71:1 on
     --canvas, 4.92:1 on --canvas-card) while staying visibly lighter than
     --navy-soft (6.82:1, body copy) and --navy (9.65:1, headings), so the
     dim/soft/navy hierarchy this system relies on doesn't collapse. */
  --navy-dim:    rgba(44,62,80,.74);
  --navy-line:   rgba(44,62,80,.16);
  --ivory:        #FAF3E0;
  --on-navy:      var(--ivory);
  --on-navy-dim:  rgba(250,243,224,.66);
  --on-navy-line: rgba(250,243,224,.20);
  --coral:       #FF6F61;
  --coral-dim:   rgba(255,111,97,.42);
  --coral-wash:  rgba(255,111,97,.08);
  --coral-hover: #ff8275;
  --ink:         #101C30;
  --teal:        #008080;
  --teal-hover:  #0a9696;
  --teal-wash:   rgba(0,128,128,.08);
  --blush:       #F5B7B1;
  --blush-ink:   #A85662;

  --ink-rgb: 18, 34, 58;

  /* the hairline is the structural element in this system */
  --rule:        rgba(44,62,80,.15);
  --rule-strong: rgba(44,62,80,.34);
  --rule-navy:   rgba(250,243,224,.20);

  --photo-veil: linear-gradient(170deg, rgba(20,30,44,.34), rgba(20,30,44,.72));

  --font-display: "proxima-nova", "Proxima Nova", "Segoe UI", system-ui, sans-serif;
  --font-body: "Open Sans", "Segoe UI", system-ui, sans-serif;

  --shell: min(1360px, 92vw);

  /* ONE section rhythm. Every page section used to carry its own inline
     padding-top (3rem here, 5rem there) plus the odd margin-top, so the gaps
     between blocks measured 0 / 0 / 39 / 0 / 80px and nothing lined up. Bands
     bring their own padding-block; plain sections take this. */
  --section-gap: clamp(4.5rem, 9vw, 8rem);

  /* ---- geometry: crisp. Radius is a rounding error, not a style. -------- */
  --r-xs: 2px;
  --r-sm: 3px;
  --r-md: 4px;
  --r-pill: 999px;   /* reserved for genuinely circular things only */

  /* ---- elevation: almost none. Depth is whitespace and scale. ----------- */
  --shadow-sm: 0 1px 2px rgba(var(--ink-rgb), .05);
  --shadow-md: 0 2px 10px rgba(var(--ink-rgb), .07);
  --shadow-lg: 0 12px 40px rgba(var(--ink-rgb), .11);

  /* ---- motion: long, calm, no overshoot ---------------------------------
     Springs were the previous system's voice. This one eases out hard and
     settles — expo curves, nothing bounces back. */
  --ease-expo:  cubic-bezier(.16, 1, .3, 1);
  --ease-power: cubic-bezier(.65, 0, .35, 1);
  --ease-line:  cubic-bezier(.83, 0, .17, 1);
  --dur-quick: .35s;
  --dur-mid:   .75s;
  --dur-slow:  1.2s;
}

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

input, select, textarea { border-radius: var(--r-xs); }

/* native smooth-scroll is OFF: the momentum layer in canopy.js owns scrolling
   when it is active, and the two fight each other over anchor jumps */
html { overflow-x: clip; }

body {
  background: var(--canvas);
  color: var(--navy-soft);
  font-family: var(--font-body);
  font-weight: 400;
  font-size: 17px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  overflow-x: clip;
}

/* a flat ground with a whisper of grain — no drifting color fields */
body::after {
  content: ""; position: fixed; inset: 0; z-index: 999; pointer-events: none;
  opacity: .022; mix-blend-mode: multiply;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='120'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='2'/%3E%3C/filter%3E%3Crect width='120' height='120' filter='url(%23n)'/%3E%3C/svg%3E");
}

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

h1, h2, h3, h4, .display, button, .btn {
  font-family: var(--font-display);
  font-weight: 600;
}

p { max-width: 68ch; text-wrap: pretty; }
small, .small { font-size: 15px; }

a { color: var(--navy-soft); text-decoration: none; }

/* link underline draws from the left — the same gesture as every rule here */
.uline { position: relative; }
.uline::after {
  content: ""; position: absolute; left: 0; bottom: -2px; height: 1px; width: 100%;
  background: currentColor; transform: scaleX(0); transform-origin: left;
  transition: transform var(--dur-mid) var(--ease-expo);
}
.uline:hover::after, .uline:focus-visible::after { transform: scaleX(1); }

:focus-visible { outline: 2px solid var(--coral); outline-offset: 3px; }

::selection { background: var(--coral); color: var(--ink); }

.shell { width: var(--shell); margin-inline: auto; }

/* ---- THE DRAWN LINE ------------------------------------------------------
   The signature. canopy.js's reveal observer adds .in; the rule then grows
   left-to-right. Applied to section heads and list separators, so structure
   arrives rather than simply being there. */
/* bottom:0 used to sit flush against the text baseline — any descender
   (a "y", "g", "p") in the last line ran straight into the rule. Padding
   the box gives the line real clearance without changing where anything
   else around it sits, since ::after is positioned relative to this
   padded box, not the text itself. */
.draw-rule { position: relative; padding-bottom: .3em; }
.draw-rule::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 1px;
  background: var(--rule-strong); transform: scaleX(0); transform-origin: left;
  transition: transform var(--dur-slow) var(--ease-line);
}
.draw-rule.in::after { transform: scaleX(1); }
.band-navy .draw-rule::after, .on-navy .draw-rule::after, .hero .draw-rule::after { background: var(--rule-navy); }

/* ---- typographic voice ---------------------------------------------------
   Display type is the loudest thing on the page by a wide margin. Tight
   tracking, near-solid leading, and enough size that it has to be read
   rather than scanned. */
.display-xl {
  font-size: clamp(3rem, 10.5vw, 8.5rem);
  font-weight: 700;
  line-height: .92; letter-spacing: -.042em; color: var(--navy);
  text-wrap: balance;
}
.display-lg {
  font-size: clamp(2.1rem, 5.6vw, 4.4rem);
  font-weight: 700;
  line-height: .98; letter-spacing: -.032em; color: var(--navy);
  text-wrap: balance;
}
.display-md {
  font-size: clamp(1.35rem, 2.8vw, 2.1rem);
  font-weight: 600;
  line-height: 1.12; letter-spacing: -.018em; color: var(--navy); text-wrap: balance;
}

.accent { color: var(--coral); }
.special-note { color: var(--blush-ink); }

/* the micro-label: small, wide-tracked, uppercase. Used everywhere a section
   needs naming without another headline competing with the display type. */
.overline {
  font-size: 11px; letter-spacing: .24em; text-transform: uppercase;
  color: var(--navy-dim); font-family: var(--font-display); font-weight: 600;
}

.margin-label {
  writing-mode: vertical-rl; transform: rotate(180deg);
  font-size: 11px; letter-spacing: .32em; text-transform: uppercase;
  color: var(--navy-dim); white-space: nowrap;
}

.leaf-rule { width: 100%; height: 14px; color: var(--coral); opacity: .8; }

/* the section divider — brand mark at the left margin, hairline running the
   full measure and drawing itself left-to-right (see canopyDivider() for why
   it is no longer a centred stamp) */
.canopy-divider { display: flex; align-items: center; gap: .9rem; width: 100%; margin: 0; }
.canopy-divider-mark {
  width: 14px; height: 16px; flex: none;
  background: var(--divider-ink, var(--coral));
  -webkit-mask: url("../assets/logo-icon.png") no-repeat center / contain;
          mask: url("../assets/logo-icon.png") no-repeat center / contain;
}
.canopy-divider::after {
  content: ""; flex: 1; height: 1px; background: var(--rule-strong);
  transform: scaleX(0); transform-origin: left;
  transition: transform var(--dur-slow) var(--ease-line);
}
.divider-slot.in .canopy-divider::after { transform: scaleX(1); }
/* a navy-34% hairline is invisible on a navy ground — swap it if a divider
   is ever placed inside one */
.band-navy .canopy-divider::after, .on-navy .canopy-divider::after,
.hero .canopy-divider::after { background: var(--rule-navy); }

/* ---- section rhythm ------------------------------------------------------
   A plain section is spaced by --section-gap; a band is spaced by its own
   padding-block and needs no margin on top of it. Two bands in a row would
   otherwise read as one long slab, so that single case gets a seam. */
main > section:not(.hero):not(.band) { padding-top: var(--section-gap); }
main > .band + .band { margin-top: 0; }

/* ---- bands: full-bleed color blocks, square to the edge ------------------ */
.band {
  width: 100vw; margin-left: calc(50% - 50vw); margin-right: calc(50% - 50vw);
  padding-block: clamp(4rem, 10vw, 9rem);
}
/* the split band is the second half of the section head above it, so it stays
   tethered to it rather than opening a full section gap */
.band-split { display: grid; grid-template-columns: 1fr 1fr; margin-top: clamp(1.6rem, 3vw, 2.6rem); }
.band-split > div {
  padding: clamp(3.5rem, 8vw, 7rem) clamp(2rem, 5vw, 4.5rem);
  transition: background-color var(--dur-mid) var(--ease-expo);
}
@media (max-width: 900px) { .band-split { grid-template-columns: 1fr; } }

.band-navy  { background: var(--navy);   color: var(--on-navy-dim); }
.band-beige { background: var(--canvas-sunk); color: var(--navy-soft); }
.band-ivory { background: var(--ivory);  color: var(--navy-soft); }

.band-navy .overline  { color: var(--on-navy-dim); }
.band-beige .overline, .band-ivory .overline { color: var(--navy-dim); }
.band-navy .display-xl, .band-navy .display-lg, .band-navy .display-md { color: var(--on-navy); }
.band-beige .display-xl, .band-beige .display-lg, .band-beige .display-md,
.band-ivory .display-xl, .band-ivory .display-lg, .band-ivory .display-md { color: var(--navy); }
.band-navy .accent, .band-beige .accent { color: var(--coral); }
.band-ivory .accent { color: var(--teal); }

.band-navy .alert-card h3, .band-navy .alert-card h4,
.band-navy .alert-card .display-xl, .band-navy .alert-card .display-lg, .band-navy .alert-card .display-md {
  color: var(--navy);
}

/* ---- 12-column layout grid ----------------------------------------------- */
.grid-12 { display: grid; grid-template-columns: repeat(12, 1fr); }
@media (max-width: 900px) {
  .grid-12 { grid-template-columns: 1fr; }
  .grid-12 > * { grid-column: 1 / -1 !important; }
}

/* ---- buttons: crisp blocks with a travelling fill ------------------------
   No pills, no lift, no bounce. The fill wipes in from the left on hover —
   the same left-to-right gesture as every rule in the system. */
/* The label colour is FIXED and each fill is chosen so that one colour reads
   on both the resting background and the arriving fill. Switching the label
   colour on hover instead would be the obvious way to do this, and it is a
   trap: the fill wipes across progressively while a colour swap happens to the
   whole label at once, so mid-wipe you get half the word in the wrong colour
   on the wrong ground. Fixed label, two safe grounds, no race. */
.btn, .btn-ghost, .btn-teal {
  display: inline-flex; align-items: center; justify-content: center; gap: .7rem;
  cursor: pointer; border: 0; position: relative; overflow: hidden; isolation: isolate;
  font-family: var(--font-display); font-weight: 700;
  font-size: 13px; letter-spacing: .14em; text-transform: uppercase;
  padding: 1.15rem 2.2rem; border-radius: var(--r-xs);
}
.btn::before, .btn-ghost::before, .btn-teal::before {
  content: ""; position: absolute; inset: 0; z-index: -1;
  transform: scaleX(0); transform-origin: left;
  transition: transform var(--dur-mid) var(--ease-expo);
}
.btn:hover::before, .btn-ghost:hover::before, .btn-teal:hover::before,
.btn:focus-visible::before, .btn-ghost:focus-visible::before, .btn-teal:focus-visible::before {
  transform: scaleX(1);
}

/* ink label: readable on coral (8.9:1) and on ivory (16:1) */
.btn { background: var(--coral); color: var(--ink); }
.btn::before { background: var(--ivory); }

/* navy label: readable on paper (9.9:1) and on ivory (10.1:1) */
.btn-ghost { background: transparent; color: var(--navy); box-shadow: inset 0 0 0 1px var(--rule-strong); }
.btn-ghost::before { background: var(--ivory); }
.btn-ghost:hover, .btn-ghost:focus-visible { box-shadow: inset 0 0 0 1px var(--navy); }
.btn-ghost:disabled { opacity: .4; cursor: default; }
.btn-ghost:disabled::before { transform: scaleX(0); }

/* ivory label: readable on teal (4.6:1 at this weight/size) and on ink (16:1) */
.btn-teal { background: var(--teal); color: var(--ivory); }
.btn-teal::before { background: var(--ink); }

/* on a navy ground the ghost keeps an ivory label, so its fill has to stay
   dark enough to read against — a light veil, not a light fill */
.band-navy .btn-ghost, .on-navy .btn-ghost, .hero .btn-ghost { color: var(--ivory); box-shadow: inset 0 0 0 1px var(--rule-navy); }
.band-navy .btn-ghost::before, .on-navy .btn-ghost::before, .hero .btn-ghost::before { background: rgba(250,243,224,.18); }
.band-navy .btn-ghost:hover, .on-navy .btn-ghost:hover, .hero .btn-ghost:hover { box-shadow: inset 0 0 0 1px var(--ivory); }

/* ---- masthead: a navy band carrying the coral mark ------------------------
   Coral on navy is the brand's own pairing and the one people recognise, so
   the mark gets the ground it belongs on rather than the page's paper. On
   index.html this runs straight into the navy hero — deliberately, so the top
   of the page reads as one navy field with the mark sitting in it. */
.masthead-band { background: var(--navy); }
.masthead {
  display: flex; align-items: center; justify-content: space-between; gap: 2rem;
  padding: 1.5rem 0; color: var(--on-navy-dim);
}
.masthead nav { display: flex; align-items: center; gap: clamp(1.2rem, 2.6vw, 2.4rem); flex-wrap: wrap; }
.masthead nav a {
  position: relative; font-family: var(--font-display); font-weight: 600;
  font-size: 12px; letter-spacing: .16em; text-transform: uppercase;
  color: var(--on-navy-dim); white-space: nowrap; padding: .3rem 0;
  transition: color var(--dur-quick) var(--ease-expo);
}
.masthead nav a::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 1px;
  background: currentColor; transform: scaleX(0); transform-origin: left;
  transition: transform var(--dur-mid) var(--ease-expo);
}
.masthead nav a:hover { color: var(--on-navy); }
.masthead nav a:hover::after { transform: scaleX(1); }
.masthead nav a[aria-current="page"] { color: var(--coral); }
.masthead nav a[aria-current="page"]::after { transform: scaleX(1); }
.masthead .door { color: var(--coral); }
.masthead .brand .strap { color: var(--on-navy-dim); }
.nav-toggle { display: none; }

.brand { display: flex; align-items: center; gap: 1rem; }
.brand .strap { font-size: 13px; color: var(--navy-dim); max-width: 26ch; line-height: 1.4; }
.brand img, .logo { object-fit: contain; max-width: 100%; }

/* ---- the brand mark ------------------------------------------------------
   The built-in lockup is painted by CSS through a mask (see LOGO in
   canopy.js), so its colour follows `currentColor` and the brand rule can be
   honoured with one asset: navy wherever it sits on paper, coral on a navy
   ground. Uploaded logos stay real <img> elements and are unaffected. */
.logo--mask {
  display: block; height: 48px; aspect-ratio: 6841 / 1205;
  background: currentColor;
  -webkit-mask: url("../assets/logo-lockup.png") no-repeat center / contain;
          mask: url("../assets/logo-lockup.png") no-repeat center / contain;
}
/* Coral, always — it is the recognition asset, so the mark does not change
   with the ground. Every surface the lockup appears on is navy (masthead,
   footer colophon, app bar, app sidebar), which is the brand's own pairing
   and measures 4.1:1. */
.logo--mask { color: var(--coral); }

/* ---- hero: type at full scale on flat navy, no ornament ------------------ */
.hero {
  display: grid; grid-template-columns: repeat(12, 1fr);
  padding: clamp(5rem, 13vw, 12rem) clamp(2rem, 5vw, 4.5rem) clamp(5rem, 10vw, 9rem);
  position: relative;
  background: var(--navy); color: var(--on-navy-dim);
  width: 100vw; margin-left: calc(50% - 50vw); margin-right: calc(50% - 50vw);
}
/* ---- the canopy: layered strata inside the hero --------------------------
   A rainforest is read by its LAYERS, so the atmosphere here is depth rather
   than illustration: the brand monstera at three sizes, flat, single-colour,
   3–8% opacity, each drifting at its own parallax rate so they separate as
   you scroll. Graphic and minimal — one shape repeated, no scene painted.
   `rotate` is the independent property, not a transform, so it composes with
   the parallax `translate` instead of cancelling it. */
.canopy-strata { position: absolute; inset: 0; overflow: hidden; pointer-events: none; z-index: 0; }
/* The brand's own leaf at two scales, composed rather than tiled.

   Three attempts came before this one. Free-floating ellipses at unrelated
   x/y/w/h/rotate values read as mess — no focal point. Regularizing them
   onto an even interval fixed the mess but read as mechanical, a
   decorative border with no life. A five-leaf version with edge "accents"
   fixed that, but one accent sat at --x:-1% and lost 59% of itself off the
   frame at a steep rotate — a stray fragment, not a deliberate crop — and
   two grow-line .stems shared an x-position with the leaf cluster, cutting
   straight through solid leaf shapes: two unrelated decorative ideas
   (canopy overhead, understory grow-lines) occupying the same spot.

   What's here now is the minimum that still has hierarchy: one dominant
   leaf, cropped by the right edge but by less than a third of itself, and
   one supporting leaf at under half the scale, fully on-screen, top-left.
   Two shapes with a real size gap beat five where two are causing
   problems. The centre stays open for the headline.

   Masked from the real logo icon, not re-traced — same technique, and same
   reason, as .canopy-divider-mark above. */
.frond {
  position: absolute; left: var(--x); top: var(--y);
  width: var(--w); aspect-ratio: 47.74 / 55.38;   /* the icon's own proportions */
  margin-left: calc(var(--w) / -2);               /* --x/--y locate the leaf's centre */
  margin-top: calc(var(--w) / -2);
  background: var(--ivory); opacity: var(--o);
  rotate: var(--r);
  -webkit-mask: url("../assets/logo-icon.png") no-repeat center / contain;
          mask: url("../assets/logo-icon.png") no-repeat center / contain;
  /* foliage moves. A long period and ~2deg of travel reads as air in the
     room rather than an animation playing — staggered per leaf so the
     canopy never swings as one sheet. Killed wholesale by the
     prefers-reduced-motion block near the end of this file. */
  animation: frond-sway var(--sway-dur, 16s) ease-in-out var(--sway-delay, 0s) infinite;
}
@keyframes frond-sway {
  0%, 100% { rotate: var(--r); }
  50%      { rotate: calc(var(--r) + var(--sway, 2deg)); }
}
/* the copy sits above the canopy */
.hero-copy, .hero .margin-label, .idx-hero-next { position: relative; z-index: 1; }

.hero .overline { color: var(--on-navy-dim); }
.hero .display-xl, .hero .display-lg, .hero .display-md { color: var(--on-navy); }
.hero p { color: var(--on-navy-dim); }
.hero-copy { grid-column: 2 / 10; align-self: center; overflow-wrap: break-word; }
.hero-copy .hang { display: block; padding-left: clamp(1.5rem, 7vw, 6rem); }
.hero .margin-label { position: absolute; right: clamp(1rem, 3vw, 2.4rem); top: 16%; color: var(--on-navy-dim); }

.hero-leaf {
  display: inline-block; width: 15px; height: 15px; margin-right: .7rem; vertical-align: -2px;
  background: var(--coral); border-radius: 50% 50% 50% 0; transform: rotate(-45deg);
}

.page-band { position: relative; }

.door-copy { grid-column: 1 / 7; }
.door-card { grid-column: 8 / 13; }

/* ---- the events rail: an index, ruled ------------------------------------
   Each event is a row on a hairline grid with an oversized date numeral.
   Nothing is a card; the structure is the rules and the numbering. */
.timeline { position: relative; padding: 1rem 0 4rem; }
.ev-rail { border-top: 1px solid var(--rule-strong); }
/* --ev-gutter keeps the row's content clear of the 2px coral spine the open
   state draws down the left edge, and is the single value the head padding and
   the detail indent are both derived from, so they can never drift apart */
.ev-row { position: relative; border-bottom: 1px solid var(--rule); --ev-gutter: 1.5rem; }
.ev-row::before {
  content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 2px;
  background: var(--coral); transform: scaleY(0); transform-origin: top;
  transition: transform var(--dur-mid) var(--ease-expo);
}
.ev-row.open::before { transform: scaleY(1); }

.ev-head {
  position: relative; display: grid;
  grid-template-columns: 6rem 1fr auto; align-items: baseline;
  gap: 0 clamp(1.4rem, 4vw, 3.5rem);
  width: 100%; text-align: left; background: none; border: 0; cursor: pointer;
  padding: clamp(1.6rem, 3vw, 2.6rem) 0 clamp(1.6rem, 3vw, 2.6rem) var(--ev-gutter);
  color: inherit; font-family: inherit;
  transition: padding-left var(--dur-mid) var(--ease-expo);
}
.ev-row:hover .ev-head, .ev-head:focus-visible { padding-left: calc(var(--ev-gutter) + 1rem); }

.ev-h { margin: 0; font-size: inherit; font-weight: inherit; }
.ev-date { text-align: left; }
.ev-date .day {
  display: block;
  font-family: var(--font-display); font-weight: 700; line-height: .85;
  font-size: clamp(2.4rem, 5vw, 3.6rem); color: var(--navy);
  font-variant-numeric: tabular-nums; letter-spacing: -.04em;
  transition: color var(--dur-quick) var(--ease-expo);
}
.ev-row:hover .ev-date .day, .ev-row.open .ev-date .day { color: var(--coral); }
.ev-date .mo { display: block; font-size: 11px; letter-spacing: .2em; text-transform: uppercase; color: var(--navy-dim); margin-top: .3rem; }

.ev-title {
  display: block; font-family: var(--font-display); font-weight: 700;
  font-size: clamp(1.3rem, 3vw, 2.1rem); line-height: 1.1; letter-spacing: -.026em;
  color: var(--navy);
}
.ev-meta { display: block; font-size: 14px; color: var(--navy-dim); margin-top: .4rem; }
.ev-kind {
  display: block; font-size: 11px; letter-spacing: .2em; text-transform: uppercase;
  color: var(--teal); font-family: var(--font-display); font-weight: 700; margin-bottom: .5rem;
}
.ev-when {
  font-size: 11px; letter-spacing: .18em; text-transform: uppercase; white-space: nowrap;
  color: var(--navy-dim); font-family: var(--font-display); font-weight: 700;
}
/* a plus that becomes a minus — the quietest possible open/close affordance */
.ev-caret { position: relative; width: 14px; height: 14px; margin-left: 1.4rem; flex: none; }
.ev-caret::before, .ev-caret::after {
  content: ""; position: absolute; background: var(--navy);
  transition: transform var(--dur-mid) var(--ease-expo), background var(--dur-quick) var(--ease-expo);
}
.ev-caret::before { left: 0; right: 0; top: 50%; height: 1px; margin-top: -.5px; }
.ev-caret::after  { top: 0; bottom: 0; left: 50%; width: 1px; margin-left: -.5px; }
.ev-row.open .ev-caret::after { transform: scaleY(0); }
.ev-row.open .ev-caret::before { background: var(--coral); }
.ev-right { display: flex; align-items: center; }

.ev-detail { display: grid; grid-template-rows: 0fr; transition: grid-template-rows var(--dur-mid) var(--ease-expo); }
.ev-row.open .ev-detail { grid-template-rows: 1fr; }
.ev-detail > div { overflow: hidden; }
.ev-detail-inner {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: clamp(1.4rem, 4vw, 3.5rem);
  /* aligns under the title column: gutter + the 6rem date column + the head's own gap */
  padding: 0 0 clamp(2rem, 4vw, 3rem) calc(var(--ev-gutter) + 6rem + clamp(1.4rem, 4vw, 3.5rem));
}
.ev-detail p { font-size: 16px; }
.ev-detail-inner > * {
  opacity: 0; transform: translateY(16px);
  transition: opacity var(--dur-mid) var(--ease-expo) .1s, transform var(--dur-mid) var(--ease-expo) .1s;
}
.ev-row.open .ev-detail-inner > * { opacity: 1; transform: none; }

/* filter chips: text with a rule, not buttons in bubbles */
.tl-filters { display: flex; gap: clamp(1.2rem, 3vw, 2.4rem); flex-wrap: wrap; margin: 2rem 0 0; }
.tl-filter-chip {
  position: relative; background: none; border: 0; cursor: pointer; padding: .3rem 0;
  font-family: var(--font-display); font-weight: 700; font-size: 12px;
  letter-spacing: .18em; text-transform: uppercase; color: var(--navy-dim);
  transition: color var(--dur-quick) var(--ease-expo);
}
.tl-filter-chip::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 1px;
  background: currentColor; transform: scaleX(0); transform-origin: left;
  transition: transform var(--dur-mid) var(--ease-expo);
}
.tl-filter-chip:hover { color: var(--navy); }
.tl-filter-chip:hover::after { transform: scaleX(1); }
.tl-filter-chip.active { color: var(--coral); }
.tl-filter-chip.active::after { transform: scaleX(1); }

/* ---- the noticeboard: an editorial grid of rules and air ------------------ */
.feed-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
  gap: clamp(2rem, 4vw, 3.5rem) clamp(1.6rem, 3vw, 2.8rem); margin-top: 3rem;
  grid-auto-flow: dense;
}
.feed-card {
  position: relative; background: none; padding: 1.6rem 0 0;
  border-top: 1px solid var(--rule-strong);
  display: flex; flex-direction: column; gap: .7rem;
}
.feed-card--wide { grid-column: span 2; }
.feed-card--tall { grid-row: span 2; }
@media (max-width: 620px) { .feed-card--wide { grid-column: span 1; } }

.feed-kind {
  font-family: var(--font-display); font-weight: 700; font-size: 11px;
  letter-spacing: .2em; text-transform: uppercase; color: var(--teal);
}
.feed-card--pinned { border-top-color: var(--coral); border-top-width: 2px; }
.feed-card--pinned .feed-kind { color: var(--coral); }
.feed-title { font-family: var(--font-display); font-weight: 700; font-size: clamp(1.25rem, 2.2vw, 1.7rem); color: var(--navy); line-height: 1.12; letter-spacing: -.026em; }
.feed-body { font-size: 16px; margin: 0; }
.feed-when { font-size: 12px; letter-spacing: .16em; text-transform: uppercase; color: var(--navy-dim); margin-top: auto; padding-top: .8rem; }
.feed-media { position: relative; overflow: hidden; background: var(--navy); aspect-ratio: 4 / 3; }
.feed-media img { width: 100%; height: 100%; object-fit: cover; }
/* the slow push-in that makes a still photo feel like it has depth */
.feed-card--media img { transition: transform 1.6s var(--ease-expo); }
.feed-card--media:hover img { transform: scale(1.05); }

.feed-play {
  position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
  background: none; border: 0; cursor: pointer; padding: 0;
}
.feed-play::after {
  content: ""; width: 74px; height: 74px; border-radius: 50%;
  border: 1px solid var(--ivory); background: rgba(250,243,224,.10);
  clip-path: polygon(40% 32%, 40% 68%, 70% 50%);
  transition: transform var(--dur-mid) var(--ease-expo), background var(--dur-quick) ease;
}
.feed-play:hover::after, .feed-play:focus-visible::after { transform: scale(1.12); background: var(--coral); }
.feed-play-veil { position: absolute; inset: 0; background: rgba(18,34,58,.30); pointer-events: none; }
.feed-media iframe { width: 100%; height: 100%; border: 0; display: block; }

/* ---- homepage section devices -------------------------------------------- */
.idx-head-spine {
  display: grid; grid-template-columns: 22% 1fr; gap: 0 clamp(2rem, 5vw, 4rem);
  align-items: end; padding-bottom: 2rem; position: relative;
}
.idx-head-spine .overline { text-align: right; padding-right: clamp(1rem, 3vw, 2.5rem); }
@media (max-width: 900px) {
  .idx-head-spine { grid-template-columns: 1fr; }
  .idx-head-spine .overline { text-align: left; padding: 0 0 .6rem; }
}

.idx-head-margin { display: grid; grid-template-columns: 2.4rem 1fr; gap: 0 1.6rem; align-items: start; }
/* the rotated vertical label sits right at the top of its grid row —
   margin-top:.2rem gave it almost no clearance from the divider line
   above this whole block, so it read as touching it even though the
   heading beside it had a normal-looking gap. */
.idx-head-margin .margin-label { position: static; margin-top: 1.2rem; }
/* the vertical label is far taller than the one-line heading next to
   it, so IT (not the heading) sets this row's height — .draw-rule's
   shared padding-bottom:.3em is sized for normal text and left the
   label's tail nearly touching the closing rule under this block.
   Wider, fixed clearance here since it doesn't scale with the label's
   own small font-size the way `em` would. */
.idx-head-margin.draw-rule { padding-bottom: 2rem; }
@media (max-width: 900px) {
  .idx-head-margin { grid-template-columns: 1fr; }
  .idx-head-margin .margin-label { writing-mode: horizontal-tb; transform: none; margin-bottom: .8rem; }
}

/* the milestone path — a ruled sequence */
.idx-milestones { display: flex; gap: 0; margin-top: 3rem; position: relative; border-top: 1px solid var(--rule-strong); }
.idx-milestone { flex: 1; min-width: 0; position: relative; padding: 1.6rem clamp(1rem, 2vw, 2rem) 0 0; }
.idx-milestone .node {
  width: 7px; height: 7px; background: var(--coral); margin-bottom: 1.2rem;
  transition: transform var(--dur-mid) var(--ease-expo);
}
.idx-milestone:hover .node { transform: scale(2); }
.idx-milestone .when {
  display: block; font-family: var(--font-display); font-weight: 700; font-size: 11px;
  letter-spacing: .2em; text-transform: uppercase; color: var(--navy);
}
.idx-milestone .what { font-size: 15px; color: var(--navy-dim); margin-top: .6rem; line-height: 1.5; }
@media (max-width: 900px) {
  /* gap already spaces entries apart on its own — padding-top on every
     item on top of that (previous fix) double-stacked and made the gaps
     between entries too big. Only the first one needs padding, to clear
     the divider line above the whole list. */
  .idx-milestones { flex-direction: column; gap: 2rem; margin-top: 2.4rem; }
  .idx-milestone { padding-right: 0; padding-top: 0; }
  .idx-milestone:first-child { padding-top: 1.6rem; }
}

/* The label stacks ABOVE the headline, like every other section head here
   (.idx-head-spine, .idx-head-margin). It used to sit inline to the left of
   the headline with an underline of its own, which put two rules at two
   different heights next to each other and read as a broken line rather than
   a label. The section's own drawn rule is the only underline it needs. */
.idx-head-tab { display: block; }
.idx-head-tab .idx-tab {
  display: block; background: none; color: var(--coral);
  font-family: var(--font-display); font-weight: 700;
  font-size: 11px; letter-spacing: .24em; text-transform: uppercase;
  padding: 0; margin: 0 0 .9rem; border-bottom: 0;
}
.idx-head-tab .idx-tab--ghost { color: var(--navy-dim); }

.idx-head-leaf { display: flex; align-items: baseline; gap: 1.2rem; flex-wrap: wrap; }
.idx-leaf-mark { width: 9px; height: 9px; flex: none; display: inline-block; background: var(--coral); }

.idx-rank-leaf {
  width: 2rem; height: 2rem; flex: none;
  display: flex; align-items: center; justify-content: center;
  border: 1px solid var(--coral);
}
.idx-rank-leaf span { font-family: var(--font-display); font-weight: 700; font-size: .78rem; color: var(--coral); font-variant-numeric: tabular-nums; }
.idx-rank-leaf.rank-2 { border-color: var(--teal); }
.idx-rank-leaf.rank-2 span { color: var(--teal); }
.idx-rank-leaf.rank-3 { border-color: var(--blush-ink); }
.idx-rank-leaf.rank-3 span { color: var(--blush-ink); }

.idx-leaf-quote { position: relative; padding-left: 1.4rem; }
/* left:0 used to sit exactly on top of the vertical border-left rule
   these quotes also carry (inline style, index.html) — the 6px dot and
   the 2px line visually fused into one blob touching the text. Shifting
   the dot clear of the line's edge gives both marks their own space. */
.idx-leaf-quote::before { content: ""; position: absolute; left: .5rem; top: .45em; width: 6px; height: 6px; background: var(--blush-ink); }

.idx-rsvp-slot {
  position: relative; display: grid; grid-template-columns: 22% 1fr; gap: 0 clamp(2rem, 5vw, 4rem);
  /* no bottom spacing here at all used to mean the white alert-card sat
     flush against wherever the next section's background color starts
     — this is the block's own closing space, not the next section's
     opening space, so it needs to be set here. */
  padding-top: 3rem; padding-bottom: clamp(3rem, 6vw, 5rem); border-top: 1px solid var(--rule);
}
.idx-rsvp-slot .idx-rsvp-label { text-align: right; padding-right: clamp(1rem, 3vw, 2.5rem); }
@media (max-width: 900px) {
  .idx-rsvp-slot { grid-template-columns: 1fr; }
  .idx-rsvp-slot .idx-rsvp-label { text-align: left; padding: 0 0 .8rem; }
}

@media (min-width: 901px) {
  .hero > .hero-copy { grid-column: 2 / 8; }
  .hero > .hero-copy h1.display-xl { font-size: clamp(2.6rem, 6.4vw, 5.6rem); }
}
.idx-hero-next {
  align-self: end; grid-column: 9 / 12;
  border-top: 1px solid var(--rule-navy); padding-top: 1.4rem;
}
.idx-hero-next .idx-leaf-mark { margin-bottom: 1rem; }
.idx-hero-next .day {
  font-family: var(--font-display); font-weight: 700;
  font-size: clamp(2.4rem, 5vw, 3.6rem); line-height: .85; color: var(--coral);
  font-variant-numeric: tabular-nums; letter-spacing: -.04em;
}
.idx-hero-next .moyr { font-size: 11px; letter-spacing: .22em; text-transform: uppercase; color: var(--on-navy-dim); margin-top: .5rem; }
.idx-hero-next h3 { font-size: clamp(1.05rem, 2vw, 1.3rem); color: var(--on-navy); margin-top: .9rem; letter-spacing: -.018em; }
.idx-hero-next a { color: var(--coral); font-size: 11px; letter-spacing: .18em; text-transform: uppercase; margin-top: 1.2rem; display: inline-block; }
@media (max-width: 900px) { .idx-hero-next { grid-column: 1/13 !important; margin-top: 3rem; } }

.idx-board-row {
  display: flex; align-items: center; gap: 1.2rem; padding: 1rem 0;
  border-bottom: 1px solid var(--rule);
  transition: padding-left var(--dur-mid) var(--ease-expo);
}
.idx-board-row:hover { padding-left: .8rem; }
.idx-board-row .idx-board-name { flex: 1; min-width: 0; }

.idx-memory-shuffle {
  background: none; border: 0; border-bottom: 1px solid var(--coral); cursor: pointer;
  padding: 0 0 .3rem; margin-top: 1.2rem;
  color: var(--coral); font-family: var(--font-display); font-weight: 700;
  font-size: 11px; letter-spacing: .18em; text-transform: uppercase;
}
.idx-memory-frame { background: none; padding: 0; }
.idx-memory-frame .tl-photo { max-width: none; margin: 0 0 1rem; }

/* ---- "peek before you sign in" — three ruled columns --------------------- */
.idx-live-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: clamp(1.6rem, 3vw, 3rem); margin-top: 3rem; }
@media (max-width: 900px) { .idx-live-grid { grid-template-columns: 1fr; gap: 3rem; } }

.idx-live-tile { border-top: 1px solid var(--rule-strong); padding-top: 1.6rem; }

.idx-live-banner {
  /* padding:0 was fine for the plain-text variant (no background), but
     the two tiles that set an inline background (swipe & match, also on
     facebook) turned that into a solid color block with the text
     touching every edge — no breathing room at all. */
  display: inline-block; background: none; color: var(--coral);
  font-family: var(--font-display); font-weight: 700; font-size: 11px;
  letter-spacing: .2em; text-transform: uppercase; padding: .35em .6em;
  margin-left: -.6em;
}

.idx-peek-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: .5rem; margin-top: 1.4rem; }
.idx-peek-grid .peek-tile {
  min-width: 0; aspect-ratio: 3/4; position: relative; overflow: hidden; background: var(--navy);
}
.idx-peek-grid .peek-tile img { width: 100%; height: 100%; object-fit: cover; display: block; transition: transform 1.4s var(--ease-expo); }
.idx-peek-grid .peek-tile:hover img { transform: scale(1.06); }
.idx-peek-grid .peek-tile .veil { position: absolute; inset: 0; background: var(--photo-veil); }
.idx-peek-grid .peek-tile .veil-label {
  position: absolute; left: .6rem; bottom: .5rem; right: .6rem; color: var(--on-navy);
  font-size: 11px; line-height: 1.3; overflow: hidden; text-overflow: ellipsis;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
}
.idx-peek-grid .peek-tile.text-only {
  display: flex; align-items: center; justify-content: center; padding: .8rem;
  background: var(--canvas-sunk);
}
.idx-peek-grid .peek-tile.text-only p { font-size: 13px; color: var(--navy-dim); text-align: center; }

.idx-swipe-stack { position: relative; height: 16rem; max-width: 14rem; margin: 1.4rem 0 0; }
.idx-swipe-stack .stack-card {
  position: absolute; inset: 0; display: flex; flex-direction: column;
  background: var(--canvas-card); border: 1px solid var(--rule);
  padding: .8rem; overflow: hidden;
  transition: transform var(--dur-mid) var(--ease-expo);
}
.idx-swipe-stack .stack-card:nth-child(1) { z-index: 3; }
.idx-swipe-stack .stack-card:nth-child(2) { z-index: 2; transform: translate(6px, 6px); opacity: .7; }
.idx-swipe-stack .stack-card:nth-child(3) { z-index: 1; transform: translate(12px, 12px); opacity: .45; }
.idx-swipe-stack:hover .stack-card:nth-child(1) { transform: translate(-4px, -4px); }
.idx-swipe-stack .stack-card img { width: 100%; flex: 1; object-fit: cover; margin-bottom: .5rem; min-height: 0; }
.idx-swipe-stack .stack-card .offer { font-size: 13px; color: var(--navy); line-height: 1.3; }
.idx-swipe-stack .stack-card .seeking { font-size: 10px; color: var(--teal); letter-spacing: .16em; text-transform: uppercase; margin-top: .3rem; }

.idx-live-tile .peek-empty, .idx-live-tile .peek-cta { font-size: 14px; color: var(--navy-dim); }
.idx-live-tile .peek-cta { margin-top: 1.2rem; }
.idx-live-tile .peek-cta a { color: var(--coral); font-size: 11px; letter-spacing: .18em; text-transform: uppercase; }

.trade-card {
  border-radius: 0 !important; border-top: 1px solid var(--rule-strong);
  transition: padding-left var(--dur-mid) var(--ease-expo);
}
.trade-card:hover { padding-left: .6rem; }

/* ---- the daily showcase: a horizontal ruled rail -------------------------- */
.ritual-rail {
  display: flex; margin-top: 3rem; overflow-x: auto;
  border-top: 1px solid var(--rule-strong); scrollbar-width: thin;
}
.ritual-rail .day {
  /* left padding used to be 0 — fine for the very first card (it's flush
     with the section's own left edge already) but every OTHER card's
     text then sat right on top of the vertical rule dividing it from
     the previous day, with no breathing room at all. */
  flex: 1 0 12rem; min-width: 12rem; padding: 1.6rem 1.4rem 2rem 1.4rem;
  position: relative; border-right: 1px solid var(--rule);
}
.ritual-rail .day:first-child { padding-left: 0; }
.ritual-rail .day:last-child { border-right: 0; }
.ritual-rail .day .dow {
  display: block; font-size: 10px; letter-spacing: .26em; text-transform: uppercase;
  color: var(--navy-dim); margin-bottom: .9rem;
}
.ritual-rail .day .theme {
  font-family: var(--font-display); font-weight: 700; font-size: 1.05rem;
  color: var(--navy); letter-spacing: -.02em; line-height: 1.15;
}
.ritual-rail .day .prompt { font-size: 13px; color: var(--navy-dim); margin-top: .7rem; line-height: 1.5; }
.ritual-rail .day.today::before {
  content: ""; position: absolute; left: 0; right: 1.4rem; top: -1px; height: 2px; background: var(--coral);
}
.ritual-rail .day.today .dow, .ritual-rail .day.today .theme { color: var(--coral); }

.tl-photo {
  position: relative; max-width: none; aspect-ratio: 3 / 2;
  overflow: hidden; margin: 0 0 1rem; background: var(--navy);
}
.tl-photo img { width: 100%; height: 100%; object-fit: cover; display: block; transition: transform 1.6s var(--ease-expo); }
.tl-photo:hover img { transform: scale(1.04); }
.tl-photo .veil { position: absolute; inset: 0; background: var(--photo-veil); }
.tl-photo .veil-label {
  position: absolute; left: 1.2rem; bottom: 1rem; color: var(--on-navy);
  font-size: 11px; letter-spacing: .2em; text-transform: uppercase;
}

/* ---- alert surfaces ------------------------------------------------------- */
.alert-card {
  background: var(--canvas-card); color: var(--navy);
  border: 1px solid var(--rule); border-top: 2px solid var(--teal);
  padding: clamp(2rem, 4vw, 3rem);
}
.alert-card h3, .alert-card h4 { color: var(--navy); }
.alert-card .teal { color: var(--teal); }
.alert-card p { color: var(--navy-soft); }
.alert-card small { color: var(--navy-dim); }

/* ---- form fields: ruled, not boxed ---------------------------------------- */
.field { display: block; margin-bottom: 1.8rem; }
/* author styles beat the browser's own [hidden]{display:none} regardless of
   specificity, so `.field` unconditionally setting display:block was
   quietly overriding `hidden` on every conditionally-shown field that
   also carries this class (apply.html's "what is it?", portal.html's
   "where to find you," several in admin.html) — they stayed visible no
   matter what toggled the attribute. */
.field[hidden] { display: none; }
.field span {
  display: block; font-size: 10px; letter-spacing: .22em; text-transform: uppercase;
  margin-bottom: .6rem; color: var(--navy-dim);
  font-family: var(--font-display); font-weight: 700;
}
.field input, .field select, .field textarea {
  width: 100%; background: transparent; border: 0; border-bottom: 1px solid var(--rule-strong);
  border-radius: 0;
  font-family: var(--font-body); font-size: 17px; padding: .6rem 0; color: var(--navy);
  transition: border-color var(--dur-quick) var(--ease-expo);
}
.field input::placeholder, .field textarea::placeholder { color: var(--navy-dim); }
.field select { background-color: transparent; }
.field select option { background-color: var(--canvas-card); color: var(--navy); }
.field input:focus, .field select:focus, .field textarea:focus {
  outline: none; border-bottom-color: var(--coral); border-bottom-width: 2px; padding-bottom: calc(.6rem - 1px);
}
.on-navy .field span { color: var(--on-navy-dim); }
.on-navy .field input, .on-navy .field select, .on-navy .field textarea {
  color: var(--on-navy); border-bottom-color: var(--rule-navy);
}
.on-navy .field input::placeholder, .on-navy .field textarea::placeholder { color: rgba(250,243,224,.4); }
.on-navy .field select { background-color: transparent; }
.on-navy .field select option { background-color: var(--navy); color: var(--on-navy); }
.on-navy .field input:focus, .on-navy .field select:focus, .on-navy .field textarea:focus { border-bottom-color: var(--coral); }

/* #map-inspector sits on a light card nested inside .on-navy — override the
   dark-background field colors above so its labels/inputs stay legible. */
#map-inspector.field span, #map-inspector .field span { color: var(--navy-dim); }
#map-inspector.field input, #map-inspector .field input,
#map-inspector.field select, #map-inspector .field select,
#map-inspector.field textarea, #map-inspector .field textarea {
  color: var(--navy); border-bottom-color: var(--rule-strong);
}
#map-inspector .field select option { background-color: var(--canvas-card); color: var(--navy); }

.otp-row { display: flex; gap: .8rem; }
.otp-row input {
  width: 3.2rem; height: 4rem; text-align: center;
  font-family: var(--font-display); font-weight: 700; font-size: 1.8rem;
  background: transparent; border: 0; border-bottom: 1px solid var(--rule-strong);
  border-radius: 0; color: var(--navy);
  transition: border-color var(--dur-quick) var(--ease-expo);
}
.otp-row input:focus { outline: none; border-bottom-color: var(--coral); border-bottom-width: 2px; }

.on-navy {
  background: var(--navy); color: var(--on-navy-dim);
  padding: clamp(1.8rem, 4vw, 2.8rem);
}
.on-navy h3, .on-navy h4 { color: var(--on-navy); }
.on-navy .overline { color: var(--on-navy-dim); }
.on-navy p { color: var(--on-navy-dim); }

/* ---- THE PARTNER DIRECTORY: a set index ------------------------------------ */
.index-layout { display: grid; grid-template-columns: minmax(180px, 20%) 1fr; gap: clamp(2rem, 6vw, 5rem); align-items: start; }

.filter-rail { position: sticky; top: 2rem; }
.filter-rail h4 {
  font-size: 10px; letter-spacing: .24em; text-transform: uppercase;
  color: var(--navy-dim); margin-bottom: 1rem; padding-bottom: .6rem;
  border-bottom: 1px solid var(--rule);
}
.filter-rail ul { list-style: none; padding: 0; }
.filter-rail li { margin: 0; }
.filter-rail button {
  display: flex; justify-content: space-between; width: 100%; gap: 1rem;
  background: none; border: 0; cursor: pointer; text-align: left;
  font-family: var(--font-body); font-weight: 400; font-size: 15px;
  color: var(--navy-soft); padding: .4rem 0; position: relative;
  transition: padding-left var(--dur-mid) var(--ease-expo), color var(--dur-quick) var(--ease-expo);
}
.filter-rail button:hover { padding-left: .5rem; color: var(--navy); }
.filter-rail button .count { color: var(--navy-dim); font-size: 13px; font-variant-numeric: tabular-nums; }
.filter-rail button.active { color: var(--coral); padding-left: .8rem; }
.filter-rail button.active::before {
  content: ""; position: absolute; left: 0; top: 50%; width: 5px; height: 1px; background: var(--coral);
}

.letter-strip { display: flex; flex-wrap: wrap; gap: .1rem .7rem; margin-top: 1.4rem; }
.letter-strip button {
  background: none; border: 0; cursor: pointer; padding: 0;
  font-family: var(--font-display); font-weight: 700; font-size: 14px; color: var(--navy-dim);
  transition: color var(--dur-quick) var(--ease-expo);
}
.letter-strip button.active, .letter-strip button:hover { color: var(--coral); }

.index-search { margin-bottom: 3rem; }
.index-search input {
  width: 100%; background: transparent; border: 0; border-bottom: 1px solid var(--rule-strong);
  border-radius: 0;
  font-family: var(--font-display); font-weight: 700;
  font-size: clamp(1.4rem, 3.4vw, 2.4rem); color: var(--navy); padding: .5rem 0;
  letter-spacing: -.026em;
  transition: border-color var(--dur-quick) var(--ease-expo);
}
.index-search input::placeholder { color: var(--navy-dim); opacity: .7; }
.index-search input:focus { outline: none; border-bottom-color: var(--coral); }

/* one grower = one ruled row with an index numeral */
.ledger { list-style: none; padding: 0; border-top: 1px solid var(--rule-strong); }
.ledger-row { border-bottom: 1px solid var(--rule); }
.ledger-row > button {
  width: 100%; display: grid; grid-template-columns: 3rem 1fr auto; align-items: baseline; gap: 1.4rem;
  background: none; border: 0; cursor: pointer; text-align: left;
  padding: clamp(1.2rem, 2.4vw, 1.9rem) 0;
  color: var(--navy-soft); font-family: inherit;
  transition: padding-left var(--dur-mid) var(--ease-expo);
}
.ledger-row > button:hover { padding-left: 1.2rem; }
.ledger-row .row-num { font-family: var(--font-display); font-weight: 700; font-size: 12px; color: var(--navy-dim); font-variant-numeric: tabular-nums; letter-spacing: .1em; }
.ledger-row .row-name {
  font-family: var(--font-display); font-weight: 700;
  font-size: clamp(1.2rem, 2.8vw, 1.9rem); color: var(--navy); letter-spacing: -.028em;
  display: flex; align-items: baseline; gap: 1.2rem; min-width: 0;
}
.ledger-row .leader { flex: 1; border-bottom: 1px dotted var(--rule); transform: translateY(-6px); min-width: 2rem; }
.ledger-row .row-meta { display: flex; align-items: center; gap: 1.2rem; font-size: 13px; color: var(--navy-dim); }
.ledger-row > button:hover .row-name, .ledger-row > button[aria-expanded="true"] .row-name { color: var(--coral); }

.badge-shelf { display: inline-flex; gap: .4rem; }
.badge-mark {
  width: 20px; height: 20px; object-fit: contain; cursor: pointer;
  transition: transform var(--dur-mid) var(--ease-expo), opacity var(--dur-mid);
}
.badge-mark:hover, .badge-mark:focus-visible { transform: translateY(-2px) scale(1.12); opacity: .85; }

.row-panel { display: grid; grid-template-rows: 0fr; transition: grid-template-rows var(--dur-mid) var(--ease-expo); }
.row-panel.open { grid-template-rows: 1fr; }
.row-panel > div { overflow: hidden; }
.row-panel-inner {
  display: grid; grid-template-columns: minmax(200px, 340px) 1fr; gap: clamp(1.6rem, 4vw, 3rem);
  padding: .4rem 0 clamp(2rem, 4vw, 3rem) 4.4rem;
}
.showcase { aspect-ratio: 4 / 3; position: relative; overflow: hidden; background: var(--navy); }
.showcase img { width: 100%; height: 100%; object-fit: cover; display: block; }
#showcase-wall .showcase { background: var(--canvas-sunk); }
#showcase-wall .showcase img { object-fit: contain; }
.showcase .veil { position: absolute; inset: 0; background: var(--photo-veil); }
.showcase .veil-label {
  position: absolute; left: 1.2rem; bottom: 1rem; color: var(--on-navy);
  font-size: 11px; letter-spacing: .2em; text-transform: uppercase;
}
.row-panel-inner .links { display: flex; flex-wrap: wrap; gap: 1.6rem; margin-top: 1.2rem; }
.row-panel-inner .links a { color: var(--coral); font-size: 11px; letter-spacing: .18em; text-transform: uppercase; }
.since-line { font-size: 11px; color: var(--blush-ink); letter-spacing: .2em; text-transform: uppercase; margin-top: .8rem; }

.zero-state { padding: 4rem 0; color: var(--navy-dim); font-size: 17px; max-width: 46ch; border-top: 1px solid var(--rule); }

/* ---- loading skeletons ---------------------------------------------------- */
@keyframes skeleton-shimmer { 0% { opacity: .35; } 50% { opacity: .8; } 100% { opacity: .35; } }
.skeleton-line, .skeleton-block {
  animation: skeleton-shimmer 1.8s ease-in-out infinite;
  background: currentColor; opacity: .14; border-radius: 0;
}
.skeleton-line { height: 12px; margin-bottom: .8rem; }
.tl-entry-skeleton { height: 140px; margin-bottom: 1px; color: var(--rule-strong); }
@media (prefers-reduced-motion: reduce) { .skeleton-line, .skeleton-block { animation: none; opacity: .14; } }

/* ---- PAST PARTNERS · pressed sheets --------------------------------------- */
.herbarium { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: clamp(2rem, 4vw, 3.5rem); }
.sheet { background: none; color: var(--navy); padding: 0; border-top: 1px solid var(--rule-strong); }
.sheet .pressing { aspect-ratio: 3/4; background: var(--navy); position: relative; overflow: hidden; margin-top: 1.4rem; }
.sheet .pressing .veil { position: absolute; inset: 0; background: var(--photo-veil); }
.sheet .pressing svg { position: absolute; inset: 14%; opacity: .85; }
.sheet .label { padding: 1rem 0 0; }
.sheet .label .name { font-family: var(--font-display); font-weight: 700; font-size: 1.1rem; color: var(--navy); letter-spacing: -.022em; }
.sheet .label .niche { display: block; font-size: 10px; color: var(--teal); letter-spacing: .2em; text-transform: uppercase; margin: .4rem 0; }
.sheet .label .yrs { font-size: 13px; color: var(--navy-dim); }

/* ---- portal dashboard ------------------------------------------------------ */
.portal-grid { display: grid; grid-template-columns: repeat(12, 1fr); gap: 2.5rem; }
.portal-main { grid-column: 1 / 9; }
.portal-side { grid-column: 9 / 13; }

.stat-strip { display: flex; gap: 0; flex-wrap: wrap; margin-bottom: 2.5rem; border-top: 1px solid var(--rule-strong); }
.stat-strip .stat { flex: 1 1 8rem; padding: 1.4rem 1.4rem 0 0; border-right: 1px solid var(--rule); }
.stat-strip .stat:last-child { border-right: 0; }
.stat-strip .stat b {
  display: block; font-family: var(--font-display); font-weight: 700;
  font-size: clamp(1.8rem, 3.4vw, 2.6rem); color: var(--navy); font-variant-numeric: tabular-nums;
  line-height: 1; letter-spacing: -.036em;
}
.stat-strip .stat span { display: block; font-size: 10px; color: var(--navy-dim); letter-spacing: .2em; text-transform: uppercase; margin-top: .6rem; }

.ledger-table { width: 100%; border-collapse: collapse; font-size: 15px; font-variant-numeric: tabular-nums; }
.ledger-table th {
  text-align: left; font-family: var(--font-display); font-weight: 700; font-size: 10px;
  letter-spacing: .22em; text-transform: uppercase; color: var(--navy-dim);
  border-bottom: 1px solid var(--rule-strong); padding: .7rem 1rem .7rem 0;
}
.ledger-table td { border-bottom: 1px solid var(--rule); padding: 1rem 1rem 1rem 0; color: var(--navy-soft); }
.ledger-table .pos { color: var(--teal); }
.ledger-table .neg { color: var(--navy-dim); }
.ledger-table .amt { font-family: var(--font-display); font-weight: 700; }

.wallet-balance {
  font-family: var(--font-display); font-weight: 700;
  font-size: clamp(2.8rem, 7vw, 5rem); color: var(--navy); line-height: .9;
  font-variant-numeric: tabular-nums; letter-spacing: -.045em;
}

.shift-row {
  display: grid; grid-template-columns: auto 1fr auto; gap: 1.6rem; align-items: center;
  padding: 1.4rem 0; border-bottom: 1px solid var(--rule);
  transition: padding-left var(--dur-mid) var(--ease-expo);
}
.shift-row:hover { padding-left: .8rem; }
.shift-row time { font-family: var(--font-display); font-weight: 700; color: var(--navy); font-size: 1.05rem; }
.shift-row .slots { font-size: 13px; color: var(--navy-dim); }
.shift-row .reward { color: var(--blush-ink); font-size: 11px; letter-spacing: .16em; text-transform: uppercase; }

.matrix-cell { border-top: 1px solid var(--rule-strong); padding: 1.2rem 1.2rem 1.2rem 0; position: relative; }
.matrix-cell b { font-family: var(--font-display); font-weight: 700; color: var(--navy); font-size: 1.1rem; display: block; }
.matrix-cell .dims { color: var(--navy-dim); font-size: 13px; }
.matrix-cell .price { color: var(--coral); font-family: var(--font-display); font-weight: 700; margin-top: .6rem; display: block; font-size: 1.3rem; }
.matrix-cell .qty { position: absolute; top: 1.2rem; right: .8rem; font-size: 11px; color: var(--blush-ink); letter-spacing: .12em; }

.status { display: inline-block; font-size: 10px; letter-spacing: .2em; text-transform: uppercase; font-family: var(--font-display); font-weight: 700; }
.status.ok { color: var(--teal); }
.status.warn { color: var(--coral); }
.status.quiet { color: var(--navy-dim); }

/* ---- footer ---------------------------------------------------------------- */
.footer-band { background: var(--navy); margin-top: 6rem; }
.site {
  padding: clamp(3.5rem, 7vw, 6rem) 0 2.5rem; display: grid; grid-template-columns: repeat(12, 1fr);
  gap: 2.5rem 1rem; color: var(--on-navy-dim);
}
.site .foot-brand { grid-column: 1 / 7; }
.site .foot-brand .brand { margin-bottom: 1.6rem; }
.site .sig { color: var(--on-navy-dim); font-size: 16px; max-width: 44ch; }
.site .foot-col { grid-column: span 3; display: flex; flex-direction: column; align-items: flex-start; gap: .7rem; font-size: 14px; }
.site .foot-col h4 {
  font-size: 10px; letter-spacing: .24em; text-transform: uppercase;
  color: rgba(250,243,224,.45); margin-bottom: .6rem;
}
.site .foot-col a { color: var(--on-navy); font-size: 14px; transition: color var(--dur-quick) var(--ease-expo); }
.site .foot-col a:hover { color: var(--coral); }
.site .foot-col p { color: var(--on-navy-dim); line-height: 1.6; }
.site .foot-baseline {
  grid-column: 1 / -1; margin-top: 2rem; padding-top: 1.4rem;
  border-top: 1px solid var(--rule-navy);
  font-size: 12px; letter-spacing: .04em; color: var(--on-navy-dim); max-width: none;
}
@media (max-width: 900px) { .site .foot-brand, .site .foot-col { grid-column: 1 / -1; } }

/* ---- app shell (portal + admin) --------------------------------------------- */
.app-shell { display: grid; grid-template-columns: 260px 1fr; min-height: 100vh; align-items: start; }
.app-sidebar {
  background: var(--navy); color: var(--on-navy-dim);
  padding: 2rem 1.6rem; display: flex; flex-direction: column;
  position: sticky; top: 0; height: 100vh;
}
.app-sidebar .brand { margin-bottom: 3rem; transform: scale(.8); transform-origin: left center; }
.app-sidebar nav { display: flex; flex-direction: column; gap: 0; flex: 1; }
.app-sidebar nav button {
  display: flex; align-items: center; gap: 1rem; width: 100%;
  background: none; border: 0; cursor: pointer; text-align: left; position: relative;
  padding: .9rem 0; border-bottom: 1px solid var(--rule-navy);
  font-family: var(--font-display); font-weight: 600; font-size: 11px;
  letter-spacing: .16em; text-transform: uppercase; color: var(--on-navy-dim);
  transition: padding-left var(--dur-mid) var(--ease-expo), color var(--dur-quick) var(--ease-expo);
}
.app-sidebar nav button:hover { padding-left: .7rem; color: var(--on-navy); }
.app-sidebar nav button svg { width: 15px; height: 15px; flex-shrink: 0; opacity: .7; }
.app-sidebar nav button img { width: 15px; height: 15px; flex-shrink: 0; opacity: .7; object-fit: contain; }
.nav-icon-preview img { width: 100%; height: 100%; object-fit: contain; }
.app-sidebar nav button.active { color: var(--coral); }
.app-sidebar nav button.active svg { opacity: 1; }
.app-sidebar .sidebar-foot { border-top: 1px solid var(--rule-navy); padding-top: 1.4rem; margin-top: 1.4rem; font-size: 13px; }
.app-sidebar .sidebar-foot .name { color: var(--on-navy); font-family: var(--font-display); font-weight: 700; }
.app-sidebar .sidebar-foot .chip { color: var(--coral); font-family: var(--font-display); font-weight: 700; }
.app-sidebar .sidebar-foot a { display: block; margin-top: .6rem; color: var(--on-navy-dim); font-size: 11px; letter-spacing: .14em; text-transform: uppercase; }
.app-sidebar .sidebar-foot a:hover, .app-sidebar .sidebar-foot a:focus-visible { color: var(--coral); }

.app-main { padding: clamp(2rem, 4vw, 4rem); max-width: 1080px; }
.app-tabbar { display: none; }

.app-bar {
  display: flex; align-items: center; justify-content: space-between;
  padding: 1.2rem clamp(1.2rem, 3vw, 2rem); background: var(--navy); color: var(--on-navy-dim);
}
@media (min-width: 901px) { .app-shell .app-bar { display: none; } }
.app-bar .brand { transform: scale(.75); transform-origin: left center; }
.app-bar a { color: var(--on-navy-dim); font-size: 11px; letter-spacing: .16em; text-transform: uppercase; }
.app-bar a:hover, .app-bar a:focus-visible { color: var(--coral); }

.panel-h { margin-bottom: 2rem; padding-bottom: 1.2rem; border-bottom: 1px solid var(--rule-strong); }

/* ---- progress bar ------------------------------------------------------------ */
.progress-row { display: flex; align-items: center; gap: 1.2rem; margin: .8rem 0; flex-wrap: wrap; }
.progress-row .label { flex: 1; min-width: 12rem; font-size: 14px; color: var(--navy-dim); }
.progress-row .frac { font-family: var(--font-display); font-weight: 700; font-size: 13px; color: var(--navy); white-space: nowrap; font-variant-numeric: tabular-nums; }
.progress-bar { width: 100%; max-width: 320px; height: 1px; background: var(--rule-strong); position: relative; }
.progress-bar i { position: absolute; inset: 0 auto -1px 0; height: 3px; background: var(--coral); transition: width var(--dur-mid) var(--ease-expo); }
.on-navy .progress-row .label { color: var(--on-navy-dim); }
.on-navy .progress-bar { background: var(--rule-navy); }

/* ---- ambient tip toast -------------------------------------------------------- */
.tip-toast {
  position: fixed; left: 1.6rem; bottom: 1.6rem; z-index: 600;
  background: var(--navy); color: var(--on-navy-dim);
  border-left: 2px solid var(--coral);
  padding: 1.3rem 3rem 1.3rem 1.5rem;
  opacity: 0; transform: translateY(14px);
  transition: opacity var(--dur-mid) var(--ease-expo), transform var(--dur-mid) var(--ease-expo);
  max-width: min(25rem, calc(100vw - 3rem));
}
.tip-toast .overline { color: var(--coral); }
.tip-toast.in { opacity: 1; transform: none; }
.tip-toast .tip-close {
  position: absolute; top: .5rem; right: .7rem;
  background: none; border: 0; cursor: pointer;
  font-size: 1.1rem; color: var(--on-navy-dim); padding: .2rem;
}

/* ---- lightbox ------------------------------------------------------------------ */
.lightbox-overlay {
  position: fixed; inset: 0; z-index: 900;
  background: rgba(20, 30, 44, .93);
  display: flex; align-items: center; justify-content: center;
  padding: clamp(1rem, 4vw, 3rem);
  animation: lb-fade var(--dur-mid) var(--ease-expo);
}
@keyframes lb-fade { from { opacity: 0; } to { opacity: 1; } }
.lightbox-panel {
  position: relative; background: var(--canvas-card); color: var(--navy);
  max-width: min(80rem, 100%); max-height: 100%; width: 100%;
  display: grid; grid-template-columns: 1.5fr 1fr;
  overflow: hidden;
  animation: lb-rise var(--dur-slow) var(--ease-expo);
}
@keyframes lb-rise { from { opacity: 0; transform: translateY(30px); } to { opacity: 1; transform: none; } }
.lightbox-media { background: var(--navy); display: flex; align-items: center; justify-content: center; min-height: 20rem; max-height: 88vh; }
.lightbox-media img { max-width: 100%; max-height: 88vh; width: auto; height: auto; object-fit: contain; display: block; }
.lightbox-side { padding: clamp(1.4rem, 3vw, 2.4rem); overflow-y: auto; max-height: 88vh; display: flex; flex-direction: column; }
.lightbox-profile { margin-bottom: .8rem; overflow: auto; }
.lightbox-caption { font-size: 16px; color: var(--navy-soft); margin-bottom: 1.4rem; }
.lightbox-reactions { display: flex; align-items: center; gap: .5rem; margin-bottom: 1.4rem; padding-bottom: 1.4rem; border-bottom: 1px solid var(--rule); }
.lightbox-emoji-btn {
  background: none; border: 1px solid var(--rule-strong); cursor: pointer;
  font-size: 16px; line-height: 1; padding: .4rem .6rem; border-radius: 0;
  transition: border-color var(--dur-quick) var(--ease-expo);
}
.lightbox-emoji-btn:hover { border-color: var(--navy); }
.lightbox-emoji-btn.active { border-color: var(--coral); background: var(--coral-wash); }
.lightbox-comments { flex: 1; display: flex; flex-direction: column; min-height: 0; }
.lightbox-comment { padding: .8rem 0; border-bottom: 1px solid var(--rule); }
.lightbox-close {
  position: absolute; top: 1rem; right: 1rem; z-index: 1;
  background: none; border: 1px solid var(--rule-strong);
  width: 2.6rem; height: 2.6rem; border-radius: 0;
  font-size: 1.2rem; line-height: 1; cursor: pointer; color: var(--navy);
  transition: background var(--dur-quick) var(--ease-expo), color var(--dur-quick) var(--ease-expo);
}
.lightbox-close:hover { background: var(--navy); color: var(--ivory); }
@media (max-width: 720px) {
  .lightbox-panel { grid-template-columns: 1fr; overflow-y: auto; }
  .lightbox-media, .lightbox-media img { max-height: 46vh; }
  .lightbox-side { max-height: none; }
}

/* ==========================================================================
   MOTION
   ========================================================================== */

/* Momentum scrolling is implemented in canopy.js by easing the REAL scroll
   position, not by translating a wrapper element. The wrapper approach is the
   more common one, but it breaks `position: sticky` — a sticky child of a
   transformed ancestor sticks to that ancestor rather than the viewport, which
   would strand the directory's filter rail and the portal sidebar. Easing
   window.scrollY keeps sticky, anchor jumps and find-in-page all intact. */

/* scroll reveal — a long fade and a short rise. No scale, no overshoot.
   Applied to nearly every block on the homepage, so the per-element
   distance needs to stay small — at the old 38-42px, a page full of
   reveals read as everything on screen shifting at once instead of a
   quiet fade. Mostly opacity now, with just a hint of motion. */
.reveal, .reveal-left, .reveal-right {
  opacity: 0;
  transition: opacity var(--dur-slow) var(--ease-expo), transform var(--dur-slow) var(--ease-expo);
  transition-delay: calc(var(--reveal-i, 0) * 90ms);
  will-change: transform, opacity;
}
.reveal       { transform: translateY(10px); }
.reveal-left  { transform: translateX(-12px); }
.reveal-right { transform: translateX(12px); }
.reveal.in, .reveal-left.in, .reveal-right.in { opacity: 1; transform: none; will-change: auto; }

/* headline reveal: each line rises out of its own clipped band.
   display-lg's line-height (1.12) is tighter than these fonts'
   natural descender space, so overflow:hidden here was clipping any
   "g"/"y"/"p"/"q" in the last line right at the box edge — padding
   gives real descenders room without weakening the slide-up clip. */
.line-reveal { display: block; overflow: hidden; padding-bottom: .18em; margin-bottom: -.18em; }
.line-reveal > span {
  display: block; transform: translateY(105%);
  transition: transform var(--dur-slow) var(--ease-expo);
  transition-delay: calc(var(--reveal-i, 0) * 100ms);
}
.line-reveal.in > span { transform: none; }

/* ---- scroll parallax ------------------------------------------------------
   Uses the independent `translate` property, NOT transform: nearly every
   element worth parallaxing already carries a transform from .reveal or a
   hover state, and writing transform here would cancel whichever lost the
   cascade. `translate` composes instead. */
[data-parallax] { translate: 0 var(--sy, 0px); will-change: translate; }

/* ---- the gallery — a deliberately uneven grid (JS assigns each tile one
   of three sizes on a repeating rhythm, not a strict masonry library) so it
   reads as a wall of real photos rather than a uniform product grid. Every
   tile is a real <button> (keyboard/screen-reader operable, opens the
   lightbox), not a bare <img>. */
.gallery-grid {
  display: grid; grid-template-columns: repeat(6, 1fr);
  grid-auto-rows: 9vw; gap: .6rem;
}
@media (max-width: 900px) { .gallery-grid { grid-template-columns: repeat(3, 1fr); grid-auto-rows: 26vw; } }
.gallery-tile {
  position: relative; overflow: hidden; border: 0; padding: 0; cursor: pointer;
  background: var(--canvas-sunk); display: block; width: 100%; height: 100%;
}
.gallery-tile.size-big { grid-column: span 3; grid-row: span 2; }
.gallery-tile.size-wide { grid-column: span 3; grid-row: span 1; }
.gallery-tile.size-normal { grid-column: span 2; grid-row: span 1; }
@media (max-width: 900px) {
  .gallery-tile.size-big { grid-column: span 3; grid-row: span 2; }
  .gallery-tile.size-wide, .gallery-tile.size-normal { grid-column: span 3; grid-row: span 1; }
}
.gallery-tile img {
  width: 100%; height: 100%; object-fit: cover; display: block;
  transition: transform var(--dur-slow) var(--ease-expo);
}
.gallery-tile:hover img, .gallery-tile:focus-visible img { transform: scale(1.06); }
.gallery-tile::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(to top, rgba(11,20,33,.82) 0%, rgba(11,20,33,.15) 45%, transparent 70%);
  opacity: 0; transition: opacity var(--dur-mid);
}
.gallery-tile:hover::after, .gallery-tile:focus-visible::after { opacity: 1; }
.gallery-tile-credit {
  position: absolute; left: 0; right: 0; bottom: 0; padding: .9rem 1rem;
  text-align: left; color: #fff; opacity: 0; transform: translateY(6px);
  transition: opacity var(--dur-mid), transform var(--dur-mid);
}
.gallery-tile:hover .gallery-tile-credit, .gallery-tile:focus-visible .gallery-tile-credit { opacity: 1; transform: translateY(0); }
.gallery-tile-credit .event { display: block; font-family: var(--font-display); font-weight: 700; font-size: 13px; }
.gallery-tile-credit .photographer { display: block; font-size: 12px; opacity: .85; margin-top: .15rem; }

/* ---- magnetic controls ----------------------------------------------------
   Kept, but retuned: the lean is smaller and the release eases out long
   instead of springing back. No sheen — that was the previous system's
   vocabulary and it reads as playful next to type this size. */
.magnetic { position: relative; transition: transform var(--dur-mid) var(--ease-expo); }
.magnetic.pulling { transform: translate(var(--mx, 0), var(--my, 0)); transition: transform .2s linear; }

.card-lift { transition: transform var(--dur-mid) var(--ease-expo); }
.card-lift:hover { transform: translateY(-4px); }

/* ---- the cursor: a dot that names what it is over ------------------------
   Small by default; over anything interactive it grows and carries a word
   ("view", "open", "drag") that canopy.js sets from the target. */
.cursor-companion {
  position: fixed; top: 0; left: 0; z-index: 998; pointer-events: none;
  width: 8px; height: 8px; margin: -4px 0 0 -4px; border-radius: 50%;
  background: var(--coral); border: 0; opacity: 0;
  display: flex; align-items: center; justify-content: center;
  font-family: var(--font-display); font-weight: 700; font-size: 9px;
  letter-spacing: .18em; text-transform: uppercase; color: transparent;
  transition: opacity var(--dur-quick) var(--ease-expo),
              width var(--dur-mid) var(--ease-expo), height var(--dur-mid) var(--ease-expo),
              margin var(--dur-mid) var(--ease-expo), background-color var(--dur-quick) var(--ease-expo),
              color var(--dur-quick) var(--ease-expo);
}
.cursor-companion.awake { opacity: 1; }
/* still visible over a text field, just smaller and quieter — enough to
   not fight with a caret or a selection highlight, not so gone it feels
   broken */
.cursor-companion.in-text-entry { width: 4px; height: 4px; margin: -2px 0 0 -2px; opacity: .45; }
.cursor-companion.over-interactive {
  width: 68px; height: 68px; margin: -34px 0 0 -34px;
  background: var(--coral); color: var(--ink);
}
.cursor-companion.on-dark { background: var(--ivory); }
.cursor-companion.on-dark.over-interactive { background: var(--ivory); color: var(--navy); }

/* ---- app-shell panel arrival ------------------------------------------------ */
[data-panel]:not([hidden]) { animation: panel-in var(--dur-mid) var(--ease-expo) both; }
@keyframes panel-in { from { opacity: 0; transform: translateY(18px); } to { opacity: 1; transform: none; } }

@media (prefers-reduced-motion: reduce) {
  * { animation: none !important; transition: none !important; }
  .reveal, .reveal-left, .reveal-right { opacity: 1; transform: none; }
  .line-reveal > span { transform: none; }
  .draw-rule::after, .canopy-divider::after { transform: scaleX(1); }
  .magnetic.pulling { transform: none; }
  .card-lift:hover { transform: none; }
  .cursor-companion { display: none; }
  [data-parallax] { translate: none; }
}
@media (hover: none), (pointer: coarse) {
  .cursor-companion { display: none; }
  .magnetic.pulling { transform: none; }
}

/* ---- responsive --------------------------------------------------------------- */
@media (max-width: 900px) {
  body { font-size: 16px; }
  /* the desktop scale leans on a lot of small, wide-tracked label text
     (overlines, .small body copy, button labels) that reads fine at arm's
     length on a monitor but gets genuinely hard to read held in a hand —
     nudged up here rather than at every individual declaration site. */
  small, .small { font-size: 16px; }
  .overline { font-size: 12px; }
  .btn, .btn-ghost, .btn-teal { font-size: 14px; }
  /* the overline sweep above only caught .overline itself — every OTHER
     small-caps label class (section tabs, milestone dates, event
     day/month, sidebar/nav labels, status chips) hardcodes its own
     10-11px and was still unreadable held in a hand. One catch-all
     rather than touching 40-odd individual declarations. */
  .margin-label, .idx-tab, .idx-milestone .when, .idx-milestone .node,
  .idx-hero-next .moyr, .idx-hero-next a, .feed-when, .ev-date .mo,
  .since-line, .row-panel-inner .links a, .idx-live-tile .peek-cta a,
  .idx-peek-grid .peek-tile.text-only p, .app-sidebar .sidebar-foot a,
  .app-bar a, .exchange-board-count, .exchange-popover .find-me,
  .match-progress-step .label, .match-progress-find-me,
  .shift-row .reward, .status, .stat-strip .stat span,
  .sheet .label .niche, .matrix-cell .qty {
    font-size: 13px !important;
  }
  .hero-copy { grid-column: 1 / 13; }
  .hero .margin-label { display: none; }
  .door-copy, .door-card { grid-column: 1 / 13; }
  .door-card { margin-top: 3rem; }
  .index-layout { grid-template-columns: 1fr; }
  .filter-rail { position: static; display: flex; flex-wrap: wrap; gap: 1rem 2rem; }
  /* stacked on a phone, so the detail returns to the row's own gutter */
  .ev-detail-inner { grid-template-columns: 1fr; padding-left: var(--ev-gutter); }
  .ev-head { grid-template-columns: 4.2rem 1fr auto; }
  .row-panel-inner { grid-template-columns: 1fr; padding-left: 0; }
  .shift-row { grid-template-columns: 1fr; gap: .5rem; }
  /* the event form's bespoke 4-column rows are set inline, and inline beats a
     plain selector — this needs !important or it is simply ignored */
  #event-form > div { grid-template-columns: 1fr !important; }
  .portal-main, .portal-side { grid-column: 1 / 13; }

  .app-shell { grid-template-columns: 1fr; }
  .app-sidebar { display: none; }
  /* a grid item defaults to min-width:auto — one wide form row is enough to
     hold the whole shell open past the phone's actual width */
  .app-main { padding-bottom: 6rem; min-width: 0; }
  .app-tabbar {
    display: flex; position: fixed; left: 0; right: 0; bottom: 0; z-index: 500;
    background: var(--navy); border-top: 1px solid var(--rule-navy);
  }
  .app-tabbar button {
    flex: 1; display: flex; flex-direction: column; align-items: center; gap: .35rem;
    background: none; border: 0; cursor: pointer; padding: .8rem .3rem .7rem;
    font-family: var(--font-display); font-weight: 700; font-size: 10px;
    letter-spacing: .12em; text-transform: uppercase; color: var(--on-navy-dim);
  }
  .app-tabbar button svg { width: 18px; height: 18px; opacity: .7; }
  .app-tabbar button.active { color: var(--coral); }
  .app-tabbar button.active svg { opacity: 1; }
}

@media (max-width: 1020px) {
  .masthead { position: relative; flex-wrap: nowrap; }
  .nav-toggle {
    display: flex; flex-direction: column; justify-content: center; align-items: stretch;
    gap: 6px; width: 30px; height: 24px; padding: 0;
    background: none; border: 0; cursor: pointer; flex: none;
  }
  .nav-toggle span { display: block; height: 1px; background: var(--on-navy-dim); transition: transform .35s var(--ease-expo), opacity .35s var(--ease-expo); }
  .nav-toggle.open span:nth-child(1) { transform: translateY(7px) rotate(45deg); }
  .nav-toggle.open span:nth-child(2) { opacity: 0; }
  .nav-toggle.open span:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }

  .masthead nav {
    display: none; flex-direction: column; align-items: stretch; gap: 0;
    position: absolute; top: 100%; left: 0; right: 0; z-index: 400;
    background: var(--navy); border-top: 1px solid var(--rule-navy);
    box-shadow: var(--shadow-lg);
  }
  .masthead nav.open { display: flex; }
  .masthead nav a { padding: 1.2rem clamp(1rem, 4vw, 2rem); border-bottom: 1px solid var(--rule-navy); }
}

@media (max-width: 420px) {
  .otp-row { gap: .4rem; }
  .otp-row input { width: 2.5rem; height: 3.2rem; font-size: 1.4rem; }
}

/* ==========================================================================
   COMMUNITY VISUALS (canopy-visuals.js)
   ========================================================================== */

.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap; border: 0;
}

.bloom-field { width: 100%; height: auto; display: block; }
.bloom { cursor: pointer; transform-box: fill-box; transform-origin: center; transition: transform var(--dur-mid) var(--ease-expo); }
.bloom:hover, .bloom:focus-visible { transform: scale(1.18); }
.bloom:focus-visible { outline-offset: 5px; }

.resonance-skyline { width: 100%; height: auto; display: block; }
/* each trunk grows up out of the forest floor, staggered — the one direction
   that reads as growth. fill-mode is `backwards` (not `forwards`) on purpose:
   the keyframe ends at the element's natural scale, so once it has run the
   hover transform below is free to apply instead of being pinned by the
   animation's final frame. */
.resonance-tree {
  cursor: pointer; transform-box: fill-box; transform-origin: bottom center;
  transition: transform var(--dur-mid) var(--ease-expo);
  animation: tree-grow 1.1s var(--ease-expo) backwards;
}
@keyframes tree-grow { from { transform: scaleY(0); } }
.resonance-tree:hover, .resonance-tree:focus-visible { transform: scaleY(1.06); }
.resonance-tree:focus-visible { outline-offset: 5px; }
.resonance-caption { font-size: 13px; color: var(--navy-dim); margin-top: 1rem; min-height: 1.4em; letter-spacing: .04em; }

.exchange-board-wrap { margin-bottom: 1.4rem; }
.exchange-board-count { font-size: 11px; color: var(--navy-dim); margin-bottom: .8rem; letter-spacing: .18em; text-transform: uppercase; }
.exchange-board { width: 100%; height: auto; display: block; max-width: 420px; }
.exchange-outline { fill: none; stroke: var(--rule-strong); stroke-width: 1; stroke-dasharray: 4 4; }
.exchange-pin { cursor: pointer; transition: transform var(--dur-mid) var(--ease-expo); transform-box: fill-box; transform-origin: center; }
.exchange-pin:hover, .exchange-pin:focus-visible { transform: scale(1.35); }
.exchange-pin:focus-visible { outline-offset: 4px; }
.exchange-popover { background: var(--canvas-card); border: 1px solid var(--rule); border-left: 2px solid var(--coral); padding: 1.2rem 1.4rem; margin-top: 1.2rem; }
.exchange-popover .find-me { color: var(--coral); font-size: 11px; letter-spacing: .16em; text-transform: uppercase; margin-top: .6rem; }
.exchange-popover .uline { color: var(--navy); font-family: var(--font-display); font-weight: 700; }

.match-progress { display: flex; gap: 0; margin: 1.4rem 0; position: relative; border-top: 1px solid var(--rule); }
.match-progress-step { flex: 1; min-width: 0; position: relative; padding: 1rem 1rem 0 0; }
.match-progress-step .node { width: 6px; height: 6px; background: var(--rule-strong); margin-bottom: .7rem; transition: background var(--dur-quick) var(--ease-expo); }
.match-progress-step.done .node { background: var(--teal); }
.match-progress-step.current .node { background: var(--coral); }
.match-progress-step .label { font-size: 10px; letter-spacing: .18em; text-transform: uppercase; color: var(--navy-dim); }
.match-progress-step.done .label, .match-progress-step.current .label { color: var(--navy); }
.match-progress-find-me { color: var(--coral); font-size: 11px; letter-spacing: .16em; text-transform: uppercase; margin-top: .5rem; }
@media (max-width: 560px) {
  .match-progress { flex-direction: column; gap: 1.2rem; }
  .match-progress-step { padding-right: 0; }
}

.noshow-link {
  background: none; border: 0; cursor: pointer; padding: 0;
  color: var(--navy-dim); font-family: var(--font-body); font-size: 12px; text-decoration: underline;
}
.noshow-link:hover { color: var(--coral); }
.noshow-link:disabled { cursor: default; text-decoration: none; opacity: .7; }
