/* =========================================================================
   buttons.css — the shared .btn family
   -------------------------------------------------------------------------
   Extracted from account.css on 4 Sep 2026, verbatim except where marked.

   WHY THIS FILE EXISTS. request.html gained a Back to Home button in #138,
   copied byte-identical from account.html so the three pages would carry one
   element rather than three that drift. The markup was identical. The CSS
   was not: `.btn` lives in account.css, and request.html does not load
   account.css. What shipped was an unstyled <a> - a 77x77 unconstrained SVG
   and an underlined browser-default link, which made .header-actions 118px
   tall and, because the row centres its children, pushed the whole cluster
   out of line with the credits button beside it.

   That is the second time a component was copied to a page its stylesheet
   did not reach; notifications.css was the first. The lesson both times is
   the same one, so it is written here rather than learned again: a component
   is its markup AND its CSS, and if the markup can travel, the CSS has to be
   somewhere that travels with it.

   WHAT IS IN SCOPE. The .btn family only - the base pill, its icon and
   label, and the header cluster's overrides of all three.

   .header-actions itself is deliberately NOT here. Each page positions that
   row for itself, and one of them differs on purpose: index.html and
   request.html set z-index 10 so the login modal and credits panel cover the
   controls, where account.html sets 80 so the toggle stays reachable above
   its confirm overlay. That divergence is Carson's, recorded on
   .theme-toggle, and verified in-browser both ways. Sharing the row would
   mean either overriding it back on two pages or resolving it by <link>
   order, and load-order-dependent correctness is exactly the kind of thing
   nobody remembers in six months. The row stays page-local; only the button
   is shared.

   TOKENS. This file references --border, --surface, --text, --light-rgb and
   --frost-p, and every page that links it declares all five (--frost-p is
   JS-set with a fallback here, as is --banner-h elsewhere). It declares no
   tokens of its own and needs none - checked against index.html and
   request.html directly rather than assumed, which is the specific mistake
   notifications.css had to be repaired for.

   --own-*, NOT the bare names. The glint and shadow read --own-glint-angle
   and --own-shadow-x/-y. In account.css these rules read --glint-angle and
   --shadow-x/-y, and there that was correct and documented: on that page an
   unprefixed custom property means "measured per element". In a SHARED file
   it is a live bug. index.html and request.html set --glint-angle on
   document.documentElement for the credits panel, custom properties inherit,
   and a shared rule reading the bare name picks up whatever the page meant
   by it - which is #130 exactly, where the bell started rendering at the
   credits panel's 260.4deg. account.html has published both names on these
   buttons since #131 specifically so this move could happen; its comment
   there names this follow-up. The bare writes stay for now: three other
   account.css rules still read them, and the collapse to one name finishes
   when those move too.
   ========================================================================= */

  /* The site-wide pill. Also used outside the header cluster - the signed-out
     and non-admin gate links on /account and /admin - so it stays a plain
     class, not a header-scoped one. */
  a.btn, button.btn {
    font-size: 13.5px; font-weight: 600; padding: 10px 16px; border-radius: 999px;
    border: 1px solid var(--border); background: var(--surface); color: var(--text);
    cursor: pointer; text-decoration: none; display: inline-flex; align-items: center; gap: 6px;
    /* Light-respecting shadow, same small-button scale as .theme-toggle
       and .notif-bell-btn. --own-shadow-x/-y is computed per-instance
       from a live getBoundingClientRect, because this class's position
       varies with its siblings' widths rather than sitting at a fixed
       CSS-constant point. Instances that nobody measures - the gate
       links, and everything on /admin, which links this file but carries
       none of the lighting subsystem - fall back to a plain 7px
       straight-down shadow. A reasonable default, not a broken one.

       The measured list used to read "#back-to-home-btn/#signout-btn"
       here. That is stale and is corrected rather than carried over:
       account.html's own measurement loop covers back-to-home-btn,
       user-chip-btn, notif-bell-btn and theme-toggle, and there is no
       #signout-btn in the header any more - it moved into the account
       dropdown. */
    box-shadow: var(--own-shadow-x, 0px) var(--own-shadow-y, 7px) 22px rgba(0, 0, 0, 0.20);
    /* box-shadow in the transition list - Carson's report was that the
       top frost bar's appearance read as "stepping" rather than one
       smooth motion. This class had no box-shadow transition at all, so
       the header instances' shadows snapped while the bar was still
       mid-fade. The rule that snapped them no longer exists (the alpha
       rides --frost-p continuously now, below), so this survives as a
       short tail on that continuous value and for the :active press.
       A no-op for every unmeasured instance, which never changes its own
       shadow value at all. */
    transition: transform 0.15s ease, background-color 2400ms ease, border-color 2400ms ease, color 2400ms ease, box-shadow 100ms ease;
  }
  a.btn:hover, button.btn:hover { transform: translateY(-1px); }

  /* .header-actions .btn specifically, not the base declaration above:
     that one is the site-wide button shadow and the gate links must keep
     it at full strength regardless of scroll. Only instances that
     actually sit on the frost bar ride --frost-p. (0,2,0) beats a.btn's
     (0,1,1), so this wins without !important. */
  .header-actions .btn {
    box-shadow: var(--own-shadow-x, 0px) var(--own-shadow-y, 7px) 22px rgba(0, 0, 0, calc(0.20 * (1 - var(--frost-p, 0))));
  }

  /* a.btn/button.btn set no position of their own, so without this the
     ::before below resolves against .header-actions (position: fixed)
     rather than against the button, and the ring lands near the corner of
     the screen instead of around the pill. Scoped to the header cluster:
     every other .btn has no ::before at all and is untouched. */
  .header-actions .btn {
    position: relative;
  }

  /* Scoped to the header cluster - account.css had this unscoped as a
     bare .btn-icon, which was safe there only because every .btn-icon on
     the two pages that loaded it happened to be in the row. In a shared
     file that is a landmine: request.html's login modal carries
     .btn-label spans of its own ("Sign in", "Use a passkey", "Send reset
     link"), and the 600px block below hides .btn-label. Unscoped, it
     would blank three buttons in a modal that has nothing to do with this
     component. Both are header-scoped here for that reason. */
  .header-actions .btn-icon { display: none; width: 16px; height: 16px; }

  /* The ring. In account.css this shared a selector with .user-chip::before;
     the halves are split here because the chip is styled per-page and the
     button is not. The declarations are unchanged.

     .header-actions .btn is a solid --surface pill with a visible --border,
     so its ring sits inboard of that border rather than replacing it -
     deliberately not a glass conversion, which would mean a -fill child in
     three HTML files and moving the 2400ms theme transition onto it. Both
     variants were rendered side by side at phone and desktop widths in both
     themes: indistinguishable in dark, and in light the only difference is
     a marginally crisper lower-left edge on this one.

     --own-glint-angle, not the shared --btn-tr-glint-angle its neighbours
     use. That one is computed once for a fixed point at (innerWidth - 18,
     18), which is right for the bell and the toggle and wrong for anything
     further left in the flex row. Measured at a 560px viewport: corner
     176.1deg, chip 189.1deg, Home button 239.7deg - a 64-degree error on
     the button, which would put its highlight on the wrong quarter.

     The 225deg fallback is what /admin gets: it links this file but carries
     none of the lighting subsystem, the same default --own-shadow-x/-y fall
     back to there. */
  .header-actions .btn::before {
    content: "";
    position: absolute;
    inset: 0;
    border-radius: inherit;
    padding: 1px;
    /* Sparkle: tight, bright hot-spot layer + background-blend-mode:screen
       on top of the original glint below. */
    background:
      linear-gradient(var(--own-glint-angle, 225deg),
        rgba(255, 255, 255, 1) 0%,
        rgba(255, 255, 255, 0.85) 1.5%,
        rgba(255, 255, 255, 0.3) 4%,
        transparent 9%),
      linear-gradient(var(--own-glint-angle, 225deg),
      rgba(255, 255, 255, 0.9) 0%,
      rgba(var(--light-rgb), 0.45) 22%,
      transparent 48%);
    background-blend-mode: screen, normal;
    -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
    -webkit-mask-composite: xor;
    mask-composite: exclude;
    pointer-events: none;
  }

  @media (max-width: 780px) {
    /* Only height (plus padding/font) changes here, NOT width or display -
       .btn-icon stays hidden and .btn-label stays visible until the 600px
       block below collapses them to icon-only circles. This just makes the
       still-full-width text pill taller in the meantime, matching what the
       other controls in the row grow to at the same breakpoint rather than
       pre-empting that later collapse. */
    .header-actions .btn {
      height: 48px;
      padding: 0 20px;
      font-size: 15px;
    }
  }

  @media (max-width: 600px) {
    .header-actions .btn-icon { display: inline-flex; }
    .header-actions .btn-label { display: none; }
    .header-actions .btn {
      /* 38px -> 48px, ~25% - Carson's own ask: fine for a mouse, too small
         a touch target on an actual phone. Rounded to a clean 48px
         (37.5*1.25=47.5) rather than a fractional value.

         This rule's comment used to end "scoped to this page only for now,
         per Carson's own call - if it looks right here, the same change
         gets carried over to index/request's own copies deliberately, not
         automatically." It looked right, and this file IS that deliberate
         carry-over: there are no other copies to carry it to. */
      padding: 0; width: 48px; height: 48px;
      justify-content: center; border-radius: 50%;
    }
    .header-actions .btn-icon { width: 20px; height: 20px; }
  }
