/**
 * YWA Components
 * ---------------------------------------------------------------------------
 * Buttons, form controls and cards.
 *
 * WHAT IS CERTAIN vs WHAT NEEDS DESIGN REVIEW
 *
 * Colour and state behaviour here is derived directly from tokens-spec.md,
 * which commits every action tier across bg / fg / border for rest, hover,
 * active, focus and disabled. Those bindings are faithful and should not need
 * revisiting.
 *
 * Dimensions — padding, control height, which radius each component takes —
 * are NOT in the spec at component level. They are set here from the space and
 * radius scales as reasonable defaults, and must be checked against the Figma
 * designs. Anywhere that applies, it is marked VERIFY.
 *
 * Nothing here invents a colour. Every value routes through a token.
 */

/* ===========================================================================
   BUTTONS
   =========================================================================== */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-200);

  /* Measured from the `Button` component set in the live Figma file
     (2026-07-20): 43px tall, 12/20 padding, SQUARE corners. The square corner
     is deliberate across all 10 variants, not an oversight. */
  padding: var(--space-300) var(--space-500);
  border-radius: var(--radius-none);

  font-family: var(--type-family-sans);
  font-size: var(--type-size-action);
  font-weight: var(--type-weight-medium);
  line-height: var(--type-leading-tight);
  letter-spacing: var(--type-tracking-none);

  border: 1px solid transparent;
  text-decoration: none;
  cursor: pointer;

  transition:
    background-color var(--motion-duration-fast) var(--motion-easing-standard),
    border-color var(--motion-duration-fast) var(--motion-easing-standard),
    color var(--motion-duration-fast) var(--motion-easing-standard);
}

/* Focus ring is keyboard-only by design — spec states the focus state applies
   to :focus-visible, not :focus, so pointer users never see a ring. */
.btn:focus-visible {
  outline: 2px solid var(--color-focus-ring);
  outline-offset: 2px;
}

.btn:disabled,
.btn[aria-disabled="true"] {
  cursor: not-allowed;
}

/* Media Library scale.
   The `/whiffs` Media Library uses a distinctly smaller, denser button than the
   marketing pages — 27px tall vs 43px — because those screens are data-heavy
   tables and detail views where a full-size button would dominate. Measured
   from the `ML Button` component set (2026-07-20).

   NOTE: 6px and 14px are NOT on the space scale (which has 4/8 and 12/16), so
   they are literals here rather than tokens. Flagged as a standardization gap —
   the WordPress button uses on-scale 12/20. Worth reconciling in a design pass. */
.btn--ml {
  padding: 6px 14px;
  border-radius: var(--radius-sm);
  font-size: var(--type-size-action-small);
}

/* Media Library secondary fills with surface/raised rather than the
   transparent action/secondary/bg/rest that the WordPress secondary uses.
   Faithful to the current design; also flagged as a standardization gap. */
.btn--ml.btn--secondary {
  background-color: var(--color-surface-raised);
}

/* Generic small — retained for UI that is neither WordPress-scale nor a
   Media Library table control. */
.btn--small {
  padding: var(--space-200) var(--space-400);
  font-size: var(--type-size-action-small);
}

/* --- primary: filled Yale Blue ------------------------------------------- */
.btn--primary {
  background-color: var(--color-action-primary-bg-rest);
  color: var(--color-action-primary-fg-rest);
}
.btn--primary:hover {
  background-color: var(--color-action-primary-bg-hover);
}
.btn--primary:active {
  background-color: var(--color-action-primary-bg-active);
}
.btn--primary:disabled,
.btn--primary[aria-disabled="true"] {
  background-color: var(--color-action-primary-bg-disabled);
  color: var(--color-action-primary-fg-disabled);
}

/* --- secondary: ink text, neutral outline -------------------------------- */
.btn--secondary {
  background-color: var(--color-action-secondary-bg-rest);
  color: var(--color-action-secondary-fg-rest);
  border-color: var(--color-action-secondary-border-rest);
}
.btn--secondary:hover {
  background-color: var(--color-action-secondary-bg-hover);
  border-color: var(--color-action-secondary-border-hover);
}

/* --- tertiary: subtle Yale Blue ghost ------------------------------------ */
.btn--tertiary {
  background-color: var(--color-action-tertiary-bg-rest);
  color: var(--color-action-tertiary-fg-rest);
}
.btn--tertiary:hover {
  background-color: var(--color-action-tertiary-bg-hover);
  color: var(--color-action-tertiary-fg-hover);
}

/* --- ghost: ink text, neutral hover -------------------------------------- */
.btn--ghost {
  background-color: var(--color-action-ghost-bg-rest);
  color: var(--color-action-ghost-fg-rest);
}
.btn--ghost:hover {
  background-color: var(--color-action-ghost-bg-hover);
  color: var(--color-action-ghost-fg-hover);
}

/* --- danger: primitive red, deliberately NOT brand red -------------------- */
.btn--danger {
  background-color: var(--color-action-danger-bg-rest);
  color: var(--color-action-danger-fg-rest);
}
.btn--danger:hover {
  background-color: var(--color-action-danger-bg-hover);
}
.btn--danger:active {
  background-color: var(--color-action-danger-bg-active);
}

/* ===========================================================================
   FORM CONTROLS
   =========================================================================== */

.field {
  display: flex;
  flex-direction: column;
  gap: var(--space-200);
}

.field__label {
  font-family: var(--type-family-sans);
  font-size: var(--type-size-action-small);
  font-weight: var(--type-weight-medium);
  color: var(--color-text-default);
}

.field__hint {
  font-size: var(--type-size-meta);
  color: var(--color-text-subdued);
}

.field__error {
  font-size: var(--type-size-meta);
  color: var(--color-status-danger-fg);
}

.input,
.textarea,
.select {
  /* VERIFY against Figma: field padding and radius */
  padding: var(--space-300) var(--space-400);
  border-radius: var(--radius-sm);

  font-family: var(--type-family-sans);
  font-size: var(--type-size-body);
  line-height: var(--type-leading-body);

  color: var(--color-text-default);
  background-color: var(--color-surface-raised);
  border: 1px solid var(--color-border-default);

  transition: border-color var(--motion-duration-fast) var(--motion-easing-standard);
}

.input::placeholder,
.textarea::placeholder {
  color: var(--color-text-subtle);
}

.input:hover,
.textarea:hover,
.select:hover {
  border-color: var(--color-border-strong);
}

.input:focus-visible,
.textarea:focus-visible,
.select:focus-visible {
  outline: 2px solid var(--color-focus-ring);
  outline-offset: 1px;
  border-color: var(--color-border-focus);
}

.input[aria-invalid="true"],
.textarea[aria-invalid="true"] {
  border-color: var(--color-status-danger-border);
}

.input:disabled,
.textarea:disabled,
.select:disabled {
  background-color: var(--color-surface-sunken);
  color: var(--color-text-subtle);
  cursor: not-allowed;
}

.textarea {
  min-height: 8rem;
  resize: vertical;
}

/* ===========================================================================
   CARD
   ---------------------------------------------------------------------------
   Elevation-first: a card floats above the page, so it takes surface.raised
   AND an elevation. The shadow is what makes "raised" read as floating —
   a lighter fill alone does not.

   HUG on the variable axis: cards holding variable-length text must not fix
   the dimension that text flows into, or captions truncate.
   =========================================================================== */

/* ===========================================================================
   PLACEHOLDER IMAGE
   ---------------------------------------------------------------------------
   Stands in wherever the client has not supplied a photo yet — homepage event
   cards, the interior pages' intro photo, the board grid. Deliberately striped
   rather than a plain grey block, so an empty slot reads as "awaiting a photo"
   and never as a design decision.

   Lives here, in the always-loaded sheet, rather than in home.css where it
   started: blocks load their own stylesheet only on pages where they appear, so
   a placeholder defined in one section's sheet is invisible in every other
   section's. Deletable in one piece once the real photos land.
   =========================================================================== */

.ph-img {
  background:
    repeating-linear-gradient(45deg, var(--primitive-neutral-100) 0 12px, var(--primitive-neutral-200) 12px 24px);
  display: grid;
  place-items: center;
  color: var(--color-text-subtle);
  font-family: var(--type-family-mono);
  font-size: 12px;
  border-radius: var(--radius-md);
}

.card {
  display: flex;
  flex-direction: column;

  background-color: var(--color-surface-raised);
  box-shadow: var(--elevation-card);

  /* VERIFY against Figma: card padding and radius */
  border-radius: var(--radius-lg);
  padding: var(--space-600);

  transition: box-shadow var(--motion-duration-standard) var(--motion-easing-standard);
}

/* Only for cards that are genuinely a link target */
.card--interactive:hover {
  box-shadow: var(--elevation-raised);
}

.card__media {
  margin: calc(var(--space-600) * -1) calc(var(--space-600) * -1) var(--space-600);
  border-start-start-radius: var(--radius-lg);
  border-start-end-radius: var(--radius-lg);
  overflow: hidden;
}

.card__eyebrow {
  font-size: var(--type-size-eyebrow);
  font-weight: var(--type-weight-medium);
  letter-spacing: var(--type-tracking-eyebrow);
  text-transform: uppercase;
  color: var(--color-accent-text);
  margin-block-end: var(--space-200);
}

.card__title {
  font-size: var(--type-size-heading-3);
  font-weight: var(--type-weight-semibold);
  line-height: var(--type-leading-heading-3);
  color: var(--color-text-strong);
}

.card__meta {
  font-size: var(--type-size-meta);
  color: var(--color-text-subdued);
  margin-block-start: var(--space-200);
}

.card__body {
  font-size: var(--type-size-body);
  line-height: var(--type-leading-body);
  color: var(--color-text-default);
  margin-block-start: var(--space-300);
}

/* Push footer content to the bottom on equal-height card grids */
.card__footer {
  margin-block-start: auto;
  padding-block-start: var(--space-500);
}

/* ===========================================================================
   BADGE / TAG
   =========================================================================== */

.badge {
  display: inline-flex;
  align-items: center;
  gap: var(--space-100);
  padding: var(--space-100) var(--space-300);
  border-radius: var(--radius-pill);

  font-family: var(--type-family-sans);
  font-size: var(--type-size-action-small);
  font-weight: var(--type-weight-medium);
  line-height: var(--type-leading-tight);

  background-color: var(--color-surface-sunken);
  color: var(--color-text-subdued);
}

.badge--accent {
  background-color: var(--color-accent-bg-subtle);
  color: var(--color-accent-text);
}

.badge--success {
  background-color: var(--color-status-success-bg);
  color: var(--color-status-success-fg);
}

.badge--warning {
  background-color: var(--color-status-warning-bg);
  color: var(--color-status-warning-fg);
}

.badge--danger {
  background-color: var(--color-status-danger-bg);
  color: var(--color-status-danger-fg);
}

.badge--info {
  background-color: var(--color-status-info-bg);
  color: var(--color-status-info-fg);
}


/* ===========================================================================
   MEDIA CARD (.event-card)
   ---------------------------------------------------------------------------
   Image, meta, title, description, action. Used by the homepage News & Events
   carousel and by the News & Announcements grid on the News & Events page.

   Lives here rather than in home.css because block stylesheets load only on
   pages where their block appears — a card defined in home.css renders
   unstyled anywhere else. That exact failure already cost a debugging round
   once this build (the .ph-img placeholder, invisible on interior pages).

   Placement — fixed width, scroll snapping — is NOT here; it belongs to
   whatever is arranging the cards. See .home-news__track in home.css.
   =========================================================================== */

/* --- event card ---
   DESKTOP is double-bordered (Figma): an outer frame (6px radius + border, 4px
   inset) wrapping an inner card (2px radius + border). Mobile drops both borders
   — deferred to the responsive pass. */
.event-card {
  display: flex;                      /* the single inner child fills for equal height */
  padding: var(--space-100);          /* MEASURED — 4px gap between the two borders */
  background-color: var(--color-surface-raised);
  border: 1px solid var(--color-border-default);
  border-radius: 6px;                 /* MEASURED — design outer radius */
}

.event-card__inner {
  display: flex;
  flex-direction: column;
  flex: 1;                            /* fill the outer frame → equal-height cards */
  width: 100%;
  background-color: var(--color-surface-raised);
  border: 1px solid var(--color-border-default);
  border-radius: 2px;                 /* MEASURED — design inner radius */
  overflow: hidden;                   /* clip the image to the inner corners */
}

.event-card__media { position: relative; }

.event-card__img {
  aspect-ratio: 3 / 2;                /* MEASURED — 405×270 */
  border-radius: 0;                   /* image is flush inside the card frame */
  width: 100%;
}

/* Category tag, overlaid on the image top-right — translucent white pill so it
   reads on any photo (design: white @ ~80%, ink text). */
.event-card__tag {
  position: absolute;
  top: var(--space-300);
  right: var(--space-300);
  display: inline-flex;
  align-items: center;
  padding: var(--space-100) var(--space-300);
  border-radius: var(--radius-pill);
  background-color: rgba(255, 255, 255, 0.9);
  color: var(--color-text-strong);
  font-family: var(--type-family-sans);
  font-size: var(--type-size-action-small);
  font-weight: var(--type-weight-medium);
  line-height: var(--type-leading-tight);
}

.event-card__body {
  display: flex;
  flex-direction: column;
  gap: var(--space-300);              /* 12 — was 16; tightened to cut card height (Josh) */
  flex: 1;                            /* fill the card so zones can align + CTA drops to the bottom */
  padding: var(--space-400) var(--space-600) var(--space-500); /* 16/24/20 — was 20/24/24 */
}

/* date + location meta row */
.event-card__meta {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-400);              /* MEASURED — 16px between items */
  line-height: 1;                     /* tight line-box so icons center on the text */
  color: var(--color-text-subdued);
}
.event-card__meta-item { display: inline-flex; align-items: center; gap: var(--space-200); }
/* filled Material glyphs, sized to sit with the 12px meta text */
.event-card__meta-item svg { width: 14px; height: 14px; flex: 0 0 auto; }

/* Reserve 2 lines so a 1-line and a 2-line title occupy the same zone height
   (derived from the heading-3 tokens, so it tracks the type scale). */
/* Title: one line, ellipsis on overflow (Josh) — clamping to a single line also
   makes every card's title zone identical, so no min-height reservation needed. */
.event-card__title {
  color: var(--color-text-strong);
  margin: 0;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 1;
  line-clamp: 1;
  overflow: hidden;
}
/* Description: three lines, ellipsis on overflow. min-height reserves the 3 lines
   so a short description doesn't shrink its card below the others (equal height). */
.event-card__desc {
  color: var(--color-text-subdued);
  margin: 0;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 3;
  line-clamp: 3;
  overflow: hidden;
  min-height: calc(var(--type-size-body-compact) * var(--type-leading-body) * 3);
}

/* "View event" / "Read more" — ink text button with a trailing chevron */
.event-card__action {
  display: inline-flex;
  align-items: center;
  gap: var(--space-200);
  align-self: flex-start;              /* the link hugs its text, not full width */
  color: var(--color-text-strong);
  font-family: var(--type-family-sans);
  font-size: var(--type-size-action);
  font-weight: var(--type-weight-medium);
  text-decoration: none;
}
.event-card__action:hover { text-decoration: underline; text-underline-offset: 0.3em; }
.event-card__action svg { width: 1.25em; height: 1.25em; }

/* Mobile: the design drops both borders and lets the media corners carry the
   card. Component-level, not carousel-level — it applies wherever the card is
   used.

   768 rather than the 767 used elsewhere in sections.css — deliberately, because
   this is a MOVE of an existing rule and its breakpoint is part of what is being
   moved. Changing it here would silently alter the homepage at exactly 768px. */
@media (max-width: 768px) {
  .event-card {
    padding: 0;                       /* drop the double-border inset */
    border: 0;
    border-radius: 0;
    background-color: transparent;
  }
  .event-card__inner {
    border: 0;
    border-radius: var(--radius-md);  /* keep the media corners soft */
  }
}

/* ===========================================================================
   SPLIT PANEL — shared mechanism
   ---------------------------------------------------------------------------
   READ THIS BEFORE CHANGING ANYTHING BELOW.

   Two different blocks lay out as "text one half, photo bleeding off the other
   half": the FEATURE section (Meet the Whiffs, on the homepage) and the PAGE
   HEADER in its photo mode (About, Donate, Contact). They look similar; they
   are NOT the same component and are not meant to stay identical.

   The split is deliberate (Josh, 2026-07-28), and it is the thing to preserve:

     SHARED — everything in this file. The parts that were arrived at by
     measurement and have no reason to differ between the two:
       · the gutter fill's self-disabling anchoring
       · the photo bleeding to the panel's outer edge
       · the mirrored version for image-on-the-left

     PER-BLOCK — everything expressive, set as custom properties by each block
     in its OWN stylesheet, so changing one never moves the other:
       · --ywa-split-cap          how wide the panel grows before the gutter
                                  fill appears
       · --ywa-split-min-height   how tall the panel is at minimum
       · padding, tone, watermark, default image side

   HOW TO TWEAK, depending on what you actually want:

     "Make the About header shorter / narrower, leave the homepage alone."
        → change --ywa-split-* on `.page-intro--split` in sections.css.

     "Make Meet the Whiffs shorter, leave the header alone."
        → change --ywa-split-* on `.ywa-feature` in home.css.

     "The blur is anchoring wrong / the photo is not bleeding properly."
        → that is mechanism. Fix it HERE, once, and both get it.

   WHY THIS FILE. components.css is enqueued on every page. home.css and
   sections.css are BLOCK stylesheets, loaded only where their blocks appear —
   so a mechanism living in home.css would simply be absent on About, which
   loads sections.css and not home.css. That is not a style preference; putting
   these rules in either block stylesheet breaks the other block's pages.

   A block opts in by carrying `ywa-split` alongside its own class, and its
   inner parts by carrying `ywa-split__panel` / `ywa-split__media` alongside
   theirs. Double classes rather than a selector list, so adding a third user
   later costs nothing here.
   =========================================================================== */

.ywa-split {
  --ywa-split-cap: 1728px;      /* per-block override; see above */
  --ywa-split-min-height: 30rem;

  position: relative;
  overflow: hidden;             /* clip the blurred backdrop's halo */
  /* background comes from the tone class (ywa_section_tone) */
}

/* The panel. Capped rather than full-bleed so the square photo stops growing
   before object-fit starts over-cropping the group on very wide screens. */
.ywa-split__panel {
  position: relative;
  z-index: 1;
  display: grid;
  grid-template-columns: 1fr 1fr;
  /* Stretch: the photo fills the column top-to-bottom. On desktop it is the
     taller element, so it lands as a clean square; at narrow tablet widths the
     text column runs taller and the square zooms to fill — trading a side-crop
     for an edge-to-edge photo (Josh, 2026-07-24). */
  align-items: stretch;
  max-width: var(--ywa-split-cap);
  margin-inline: auto;
  min-height: var(--ywa-split-min-height);
}

/* WIDE-SCREEN GUTTER FILL. Past the cap the square photo leaves empty space to
   its outer side; fill it with a blurred, darkened copy of the same photo so
   the image dissolves into an ambient haze rather than floating in white.

   Anchored to the PANEL's outer edge, not to a percentage of the section. That
   is what makes it self-disabling: at or below the cap, `50% + 50vw` resolves
   to 100%, so the element has zero width and nothing renders — no media query,
   and the threshold is not written down in two places that could drift apart.

   It used to be `left: 53%`, a fixed slice of the section, which is why a strip
   of blur showed at every width above ~1300 no matter where the photo ended. */
.ywa-split::after {
  content: "";
  position: absolute;
  top: -40px; bottom: -40px; right: -40px;
  left: calc(50% + min(50vw, var(--ywa-split-cap) / 2));
  z-index: 0;
  /* --ywa-split-photo is set inline by each block from whatever image was
     actually chosen. Naming a file here instead is how an earlier version ended
     up blurring the OLD photo behind a newly-chosen one. */
  background: var(--brand-ink-950) var(--ywa-split-photo) center / cover no-repeat;
  filter: blur(30px) brightness(0.5);
  pointer-events: none;
}

/* No photo: nothing to blur, and blurring the striped placeholder would only
   smear it. */
.ywa-split--no-photo::after { content: none; }

/* Photo on the left. Mirrored the same self-disabling way — otherwise the
   flipped layout would keep an always-on blur after the default one lost it. */
@media (min-width: 769px) {
  .ywa-split--media-start .ywa-split__panel > :first-child { grid-column: 2; }
  .ywa-split--media-start .ywa-split__media { grid-column: 1; grid-row: 1; }

  .ywa-split--media-start::after {
    left: -40px;
    right: calc(50% + min(50vw, var(--ywa-split-cap) / 2));
  }
}

/* The photo itself. Square by nature of the panel's halves; object-fit keeps it
   filling its column at any ratio. */
.ywa-split__media {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  min-width: 0;
}

/* Narrow: one column, photo on top — the design's mobile order. The flip rules
   above are scoped to ≥769 so they cannot invent a second column here. */
@media (max-width: 768px) {
  .ywa-split__panel { grid-template-columns: 1fr; min-height: 0; }
  .ywa-split__media { order: -1; width: 100%; }
}
