/*
 * surface.css
 *
 * The block visual base. Every block primitive that wants the surface
 * treatment — card, alert, toast, dialog, popover, drawer — gets it from
 * the single rule below. Adding a composite = add its name to the
 * :where() list, once.
 *
 * ── The tone recipe carries no tone names ───────────────────────────
 *
 * tones.css sets --bg-mix. Each --surface-tint-* below is computed from
 * it, so when no tone class is present --bg-mix is guaranteed-invalid,
 * the color-mix() is invalid at computed-value time, and the tint
 * variable falls back to the untoned default on the line below.
 *
 * So every tone in tones.css works on every surface composite for free —
 * Adding a tone is one line in tones.css and nothing here
 *
 * A composite opts out of tinting by resetting the tint variables to
 * `initial`, which re-fires the fallbacks (dialogs.css does this to route
 * its tone to the header instead of the modal body).
 *
 * Sub-regions (.surface-header, .surface-body, .surface-footer) are
 * shared too. Composites can adjust their bleed/padding via descendant
 * rules in their own file.
 */

:where(.surface, .card, .tile, .alert, .toast, .dialog, .popover, .drawer) {
  /*
   * The percentages are not here — they are the --tint-* ramp in tones.css,
   * so a toned Card and an app's own tinted element cannot drift apart.
   * These three names stay because the variants below override them
   * individually (a .raised Card tints from --surface-raised).
   */
  --surface-tint-bg:     var(--tint-surface);
  --surface-tint-border: var(--tint-rule);
  --surface-tint-color:  var(--tint-ink);

  /*
   * --surface-ground is the untoned ground, one step before --surface, so
   * a composite can give itself a different one without touching
   * --surface-bg. Dialog and Drawer are the callers (`--dialog-bg`), and
   * the indirection is what keeps `.outlined`/`.ghost` working on them:
   * those variants set --surface-bg, and a composite assigning it in a
   * later layer would beat them.
   */
  --surface-bg:     var(--surface-tint-bg,     var(--surface-ground, var(--surface)));
  --surface-border: var(--surface-tint-border, var(--rule));
  --surface-color:  var(--surface-tint-color,  var(--ink));

  display:       block;
  background:    var(--surface-bg);
  color:         var(--surface-color);
  border:        var(--border-width) solid var(--surface-border);
  border-radius: var(--card-radius);
  font-family:   var(--font-primary);
  /*
   * Resting elevation, `none` by default (tokens.css). A theme with a
   * shadow shape of its own — press's printing offset — reaches the Block
   * tier through this; before it, --shadow-* reached every overlay and no
   * card. `.raised` below is the elevation ladder and overrides it.
   */
  box-shadow:    var(--surface-shadow);
  transition:    background var(--motion-fast), border-color var(--motion-fast);

  /*
   * ── Variants ────────────────────────────────────────────────────
   * These sit after the tone recipe, so a variant beats the tint on
   * the properties it owns.
   */
  &.raised {
    --surface-bg:     var(--surface-tint-bg, var(--surface-raised));
    --surface-border: transparent;
    box-shadow:       var(--shadow-md);
  }
  &.outlined {
    --surface-bg:     transparent;
    --surface-border: var(--surface-tint-border, var(--rule-strong));
    box-shadow:       none;
  }
  &.ghost {
    --surface-bg:     transparent;
    --surface-border: transparent;
    box-shadow:       none;
  }
}

/*
 * ── A Surface that navigates ────────────────────────────────────
 *
 * `<a class="card">` and `<button class="tile">` are ordinary: a card that
 * opens a detail view, a stat tile that drills into a report. Until this
 * rule they got a focus ring from the a11y layer and nothing on hover, so
 * every consumer hand-wrote the same three declarations — the guide's
 * next-page footer was one of them, and it is what found this.
 *
 * ── Why the element, not a modifier ─────────────────────────────
 *
 * The elsewhere-in-this-package pattern is opt-in: `.rows.hover`,
 * `.table.hover`, `.items.menu`. Those exist because the thing being
 * styled is an `<li>` or a `<tr>` — not focusable, not operable by
 * keyboard — so an unconditional hover state would advertise an
 * interaction the markup cannot deliver. `lists.css` says so at length.
 *
 * An `<a href>` and a `<button>` have no such problem: they ARE the
 * interaction. Keying on the element instead of a class means the
 * affordance cannot be attached to something that does not have it, and
 * cannot be forgotten on something that does. There is no `.card.hover`
 * for the same reason there is no `.btn.hover`.
 *
 * ── What moves, and what deliberately does not ──────────────────
 *
 * The BORDER and the lift, not the background.
 *
 * Moving --surface-bg was the first attempt and it is wrong twice. In the
 * default theme --surface-raised IS --surface (both #ffffff), so the hover
 * did nothing at all — measured — and the affordance existed only in the
 * three themes that happen to separate them. And on `.outlined`, whose
 * whole variant is `--surface-bg: transparent`, filling the background on
 * hover erases the variant: measured, an outlined card turned solid white
 * under the pointer.
 *
 * The border is the honest channel. It reads on every theme, it survives
 * all three variants, and it is the same signal `.field:focus` and
 * `.navlink[aria-current]` already use.
 *
 * It is written as one `color-mix` toward --bg-mix rather than as a
 * fallback chain, and that is the second thing measured. The obvious form
 * — `var(--surface-tint-border, <brand>)` — only fires the fallback when
 * the tint is guaranteed-invalid, which is exactly never on a toned card:
 * a `.card.danger` therefore hovered to the SAME red it already had, so a
 * toned card got no feedback but the 1px lift. Mixing takes whichever
 * border the card actually has and pulls it further toward its own tone,
 * so an untoned card goes brand-colored and a danger card goes a deeper
 * red. One expression, both cases.
 *
 * The lift is 1px. Anything larger reads as the layout shifting rather
 * than the target responding, and a card is often directly above the fold.
 */
:where(a, button):where(.surface, .card, .tile) {
  cursor: pointer;
  transition: background var(--motion-fast), border-color var(--motion-fast),
              transform var(--motion-fast);
}

/*
 * `(hover: hover)` so a touch device does not keep the lifted state after a
 * tap — without it the last card tapped stays raised until something else
 * is touched, which reads as a stuck selection.
 */
@media (hover: hover) {
  :where(a, button):where(.surface, .card, .tile):hover {
    --surface-border: color-mix(
      in srgb,
      var(--bg-mix, var(--color-primary)) 55%,
      var(--surface-tint-border, var(--rule))
    );
    transform: translateY(-1px);
  }
}

/*
 * Pressed. Without it the card stays lifted while the pointer is down,
 * which reads as the click not having registered.
 */
:where(a, button):where(.surface, .card, .tile):active {
  transform: none;
}

/*
 * ── A closed <dialog> has to be told to stay closed ─────────────
 *
 * The UA stylesheet hides an inactive dialog with
 * `dialog:not([open]) { display: none }` — and an *author* declaration
 * beats a UA one at any specificity, including the zero-specificity
 * `display: block` above. So the base silently unhid every closed
 * `.dialog` and `.drawer` in the package: they rendered on page load,
 * before anything called showModal().
 *
 * This is the same trap frame.css documents for `.view[hidden]`.
 *
 * Scoped to the element rather than the class: `[open]` means nothing on
 * a <div>, so an unscoped `:not([open])` would hide anything that
 * borrowed the class. `dialog` + `:not()` also puts this at (0,1,1),
 * comfortably above the base it is correcting.
 */
dialog:where(.dialog, .drawer, .surface):not([open]) {
  display: none;
}

/* ── Shared sub-regions ───────────────────────────────────────── */
.surface-header,
.surface-footer {
  display:     flex;
  align-items: center;
  gap:         var(--space-md);
  padding:     var(--space-lg) var(--space-3xl);
}
.surface-header {
  justify-content: space-between;
  border-bottom:   var(--border-width) solid var(--surface-border);
  font-weight:     600;
  color:           var(--surface-color);
}
.surface-footer {
  justify-content: flex-end;
  border-top:      var(--border-width) solid var(--surface-border);
  background:      color-mix(in srgb, var(--ink) 3%, transparent);
}
.surface-body {
  padding:     var(--space-2xl) var(--space-3xl);
  line-height: 1.55;
}
.surface-body > p { margin: 0 0 10px; }
.surface-body > p:last-child { margin-bottom: 0; }
