/* ==========================================================================
   EPA MEMBERSHIP · THE AUTH SCREEN
   Full viewport. One row, two columns: media left, form right.

   This stylesheet ships its OWN reset, because the screen is a standalone
   document — the theme's stylesheet and Elementor's kit are never loaded on
   it, deliberately. That also means none of the kit-defence rules in
   src/03-components.css are needed here: there is no hostile kit to beat.

   PALETTE — the client's own, from "EPA Brand (1).pdf". Values identical to
   src/01-tokens.css. Measured from the actual sRGB values:
     ink-950 #3D3829 on cream #FCF8F1   11.04:1   headings, body, buttons
     ink-800 #544E39 on cream            7.85:1   secondary body
     olive   #625B42 on cream            6.41:1   input text, meta, hints
     brown   #726050 on cream            5.66:1   uppercase micro-labels
     sage    #C2C1AF on cream            1.72:1   ✗ NEVER text — hairline only
     beige   #E2D9CF on cream            1.32:1   ✗ NEVER text — fill only
     cream   #FCF8F1 on ink-950         11.04:1   the wordmark over the video

   TYPE — the site's pairing. Display is the system serif stack, so there is
   no second webfont request on the one screen a visitor is waiting at.
   ========================================================================== */

/* --- Reset, scoped to this document ------------------------------------- */

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

html.epa-auth-root {
  /* ScrollTrigger is not on this page, but the rule costs nothing and keeps
     the whole site honest about smooth scrolling. START-HERE §6. */
  scroll-behavior: auto;
  -webkit-text-size-adjust: 100%;
  block-size: 100%;
}

body.epa-auth-body {
  margin: 0;
  min-block-size: 100svh;      /* svh, never dvh — dvh relayouts mid-scroll */
  background: #FCF8F1;
  color: #3D3829;
  font-family: "Jost", "Futura", "Century Gothic", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  font-size: 16px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}

/* ⚠ BARE TAGS, DELIBERATELY — specificity (0,0,1), so every class rule below
   beats it. The first version of this line read
   `body.epa-auth-body :is(h1, p, form, fieldset) { margin: 0 }`, which is
   (0,1,2) and quietly out-specified every `.epa-auth__* { margin-block-start }`
   on the panel. MEASURED: the whole right column collapsed to a tight stack
   with no rhythm at all. That is the neutraliser trap from START-HERE §5, and
   it is just as easy to walk into in your own stylesheet as in a kit.
   Bare tags are safe here BECAUSE this is a standalone document — no theme
   stylesheet and no Elementor kit are loaded on this screen. */
h1, p, form, fieldset { margin: 0; }

/* --- The frame ----------------------------------------------------------- */

.epa-auth {
  display: grid;
  /* 40 / 60, client revision 2026-09-08. The panel is the working half of
     this screen and the video is the mood, so the video gives up the
     space. The lockup came down a size to match — see lockup.css. */
  grid-template-columns: 40fr 60fr;
  min-block-size: 100svh;
}

/* --- LEFT · media -------------------------------------------------------- */

.epa-auth__media {
  position: relative;
  overflow: hidden;
  background: #3D3829;
  isolation: isolate;
}

.epa-auth__video {
  position: absolute;
  inset: 0;
  inline-size: 100%;
  block-size: 100%;
  object-fit: cover;
  object-position: center;
  display: block;
  border: 0;
}

/* One flat gradient, no blending. mix-blend-mode on a full-bleed layer is
   what took the previous build off the compositor on mobile. */
/* ⚠ TWO LAYERS, AND THE SECOND ONE IS NEW IN 1.7.
   The linear wash alone was built for a mark pinned to the BOTTOM of this
   column, where it reaches 0.78. The mark is centred now, and at the middle
   that wash is only about 0.28 — which put the wordmark straight across the
   chandelier's cut glass. MEASURED on the client's own poster frame at
   720x900: the mark line's worst point was 2.51:1, with 4% of the line below
   the readable threshold.
   The ellipse is a pool of the same tint under the lockup only. At 0.6 in
   the centre the worst point measures 4.79:1 and nothing on either line
   falls below 4.5, while the edges of the frame keep the picture: the
   ellipse is already at zero by the time it reaches them, so the room, the
   flowers and the windows are untouched. A flat lift over the whole column
   would have cost the photograph for no extra legibility. */
.epa-auth__scrim {
  position: absolute;
  inset: 0;
  background:
    radial-gradient(
      ellipse 92% 34% at 50% 54.5%,
      rgba(61, 56, 41, 0.60) 0%,
      rgba(61, 56, 41, 0.34) 55%,
      rgba(61, 56, 41, 0.00) 100%
    ),
    linear-gradient(
      to top,
      rgba(61, 56, 41, 0.78) 0%,
      rgba(61, 56, 41, 0.34) 42%,
      rgba(61, 56, 41, 0.16) 100%
    );
  pointer-events: none;
}

/* ⚠ CENTRED IN THE COLUMN, not pinned bottom-left. The mark is one line now
   and carries a logo above it, which is a centred lockup, not a corner
   signature. Absolute still — it sits over the video, not in flow — but
   inset on all four sides with the grid doing the centring, so it stays put
   whatever the column's height turns out to be. */
.epa-auth__mark {
  position: absolute;
  inset: clamp(1.75rem, 3.5vw, 3.5rem);
  display: grid;
  place-content: center;
  justify-items: center;
  gap: clamp(1.1rem, 2vw, 1.75rem);
  color: #FCF8F1;
}

/* The logo above the mark. Cream, because this sits over a dark video —
   the green file is for the light panel. */
.epa-auth__mark .epa-auth__logo {
  inline-size: clamp(64px, 7vw, 96px);
  max-inline-size: none;
}

/* --- The lockup ----------------------------------------------------------
   THE COMPONENT LIVES IN lockup.css and is shared with the page-transition
   curtain, so both inherit the same wording, the same width matching and the
   same divider. All this file does is say what colour it is in each of its
   two placements — the component itself is entirely currentColor.

   Over the video: cream, 11.04:1 on the ink behind the scrim.
   On the panel:   ink-950, 11.04:1 on cream.                              */

.epa-auth__mark  { color: #FCF8F1; }
.epa-auth__brand { color: #3D3829; }

/* --- The mark is the way home -------------------------------------------
   This screen renders standalone: no header, no menu, no footer. Somebody who
   lands here from a members-only link has the back button and nothing else,
   and back returns them to the page that bounced them here. So the mark is an
   <a> now, which needs three things and only three.

   ⚠ NO UNDERLINE, and it is forced. The lockup already defends itself against
   a kit's blanket `text-decoration: underline`; the anchor wrapping it is a
   new surface and needs the same guard.
   ⚠ A VISIBLE FOCUS RING. It is the only link in the left column and the
   first thing a keyboard reaches, so it cannot be the one control with no
   focus state. Offset outward, away from the lettering.
   ⚠ THIS RULE SETS NO COLOUR — see the note inside it. */
.epa-auth__home {
  /* ⚠ NO color PROPERTY HERE, AND THIS LINE USED TO SET ONE. The two
     placements sit on opposite grounds — cream over the video, ink on the
     cream panel — and .epa-auth__mark and .epa-auth__brand above already
     set each. `color: inherit` here looked harmless and was not: this
     selector is (0,1,0), the SAME weight as .epa-auth__mark, and it comes
     LATER in the file, so it won the cascade. The left column's lettering
     then inherited ink from its ancestor and vanished into the dark video.
     The disc is an <img> and kept rendering, which made the panel look as
     though the words had been deleted rather than hidden. */
  text-decoration: none !important;
  -webkit-text-decoration: none !important;
  cursor: pointer;
  transition: opacity 320ms cubic-bezier(0.22, 1, 0.36, 1);
}
.epa-auth__home:hover { opacity: 0.82; }
.epa-auth__home:focus-visible {
  outline: 2px solid currentColor;
  outline-offset: 6px;
  border-radius: 4px;
}
@media (prefers-reduced-motion: reduce) {
  .epa-auth__home { transition: none; }
}

/* --- RIGHT · the panel --------------------------------------------------- */

.epa-auth__panel {
  display: grid;
  place-items: center;
  padding: clamp(2rem, 5vw, 4.5rem) clamp(1.5rem, 4vw, 4rem);
  background: #FCF8F1;
}

.epa-auth__inner {
  inline-size: min(24rem, 100%);
}

/* --- Brand -----------------------------------------------------------------
   HIDDEN BY DEFAULT. The lockup already sits over the video in the left
   column, so a second one above the form is a duplicate — the right column
   starts at the heading.

   It comes back only below 768px, where the media column is display:none and
   the screen would otherwise carry no mark at all. See the phone block at the
   bottom of this file. LEFT-ALIGNED, not centred. */

/* ⚠ CENTRED, and this REVERSES the 2026-08-20 morning instruction to
   left-align it. The client asked for centred when they asked for the
   divider. The lockup over the video is still bottom-LEFT — that is a
   different placement and they have not asked for it to move. */
.epa-auth__brand {
  display: none;
  justify-items: center;
  text-align: center;
  margin-block-end: clamp(1.75rem, 3vw, 2.75rem);
}

.epa-auth__logo {
  display: block;
  block-size: auto;
  max-inline-size: 6rem;
}

.epa-auth__vh {
  position: absolute;
  inline-size: 1px; block-size: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* --- The lede -------------------------------------------------------------
   Four headings in one block, one shown at a time. `display: none` and not
   `visibility` or opacity, so the three that are off are out of the
   accessibility tree entirely and a screen reader announces one heading,
   not four. */
.epa-auth__lede [data-epa-head] { display: none; }
body[data-epa-state="login"]  .epa-auth__lede [data-epa-head="login"],
body[data-epa-state="signup"] .epa-auth__lede [data-epa-head="signup"],
body[data-epa-state="forgot"] .epa-auth__lede [data-epa-head="forgot"],
body[data-epa-state="reset"]  .epa-auth__lede [data-epa-head="reset"] { display: block; }

/* The switch used to be the first thing in the panel; the lede is now, so
   the spacing moves with it. */
.epa-auth__lede { margin-block-end: clamp(1.25rem, 2.4vw, 1.75rem); }

/* --- The Sign in / Sign up switch -----------------------------------------
   ⚠ DRIVEN ENTIRELY FROM `body[data-epa-state]`, WITH NO JAVASCRIPT OF ITS
   OWN. auth.js already writes that attribute on every view change, so the
   thumb follows the real state however it was reached — a click on the
   switch, a click on the "New here?" link at the bottom, a page load with
   ?epa_view=signup, or the back button. A switch with its own internal
   `is-on` flag would have gone out of sync with all four.

   The thumb is a separate absolutely-positioned element rather than a
   background on the active button, so it can TRANSITION BETWEEN the two
   positions. Backgrounds cannot slide from one element to another. */
.epa-auth__seg {
  position: relative;
  display: grid;
  grid-template-columns: 1fr 1fr;
  margin-block-end: clamp(1.5rem, 3vw, 2.25rem);
  margin-inline: auto;
  inline-size: min(19rem, 100%);
  padding: 4px;
  background: rgba(194, 193, 175, 0.30);
  border-radius: 999px;
  isolation: isolate;
}

.epa-auth__seg-thumb {
  position: absolute;
  z-index: 0;
  inset-block: 4px;
  inset-inline-start: 4px;
  inline-size: calc(50% - 4px);
  background: #FCF8F1;
  border-radius: 999px;
  box-shadow: 0 1px 2px rgba(61, 56, 41, 0.16), 0 0 0 1px rgba(61, 56, 41, 0.05);
  transition: transform 380ms cubic-bezier(0.22, 0.20, 0, 1);
  will-change: transform;
}
body[data-epa-state="signup"] .epa-auth__seg-thumb { transform: translateX(100%); }

.epa-auth__seg-btn {
  position: relative;
  z-index: 1;
  appearance: none;
  margin: 0;
  padding-block: 0.7rem;
  background: transparent;
  border: 0;
  border-radius: 999px;
  font-family: inherit;
  font-size: 0.875rem;
  font-weight: 500;
  letter-spacing: 0.02em;
  color: #625B42;               /* 4.9:1 on the sage track */
  cursor: pointer;
  transition: color 380ms cubic-bezier(0.22, 0.20, 0, 1);
}
body[data-epa-state="login"]  [data-epa-swap="login"].epa-auth__seg-btn,
body[data-epa-state="signup"] [data-epa-swap="signup"].epa-auth__seg-btn {
  color: #3D3829;               /* 12.6:1 on the cream thumb */
  font-weight: 600;
}
.epa-auth__seg-btn:focus-visible { outline: 2px solid #625B42; outline-offset: 2px; }

/* The switch belongs to the two views that have a counterpart. On a reset or
   a pending screen there is nothing to switch to. */
body[data-epa-state="forgot"] .epa-auth__seg,
body[data-epa-state="reset"] .epa-auth__seg,
body[data-epa-state="pending"] .epa-auth__seg,
body[data-epa-state="declined"] .epa-auth__seg { display: none; }

@media (prefers-reduced-motion: reduce) {
  .epa-auth__seg-thumb { transition: none; }
}

/* --- Heads --------------------------------------------------------------- */

/* CENTRED, client revision 2026-09-08 — the panel now reads as one centred
   column: switch, heading, lead, form, note. */
.epa-auth__title {
  text-align: center;
  font-family: "Times New Roman", Times, "Liberation Serif", Georgia, serif;
  font-size: clamp(1.5rem, 1.2rem + 1.1vw, 2.05rem);
  font-weight: 400;
  line-height: 1.12;
  letter-spacing: -0.01em;
  color: #3D3829;
}

.epa-auth__lead {
  text-align: center;
  margin-block-start: 0.6rem;
  font-size: 0.9375rem;
  color: #544E39;               /* 7.85:1 */
}

.epa-auth__view { display: block; }
.epa-auth__view[hidden] { display: none; }

/* --- Form ---------------------------------------------------------------- */

.epa-auth__form {
  display: grid;
  gap: 1.1rem;
  margin-block-start: clamp(1.5rem, 3vw, 2.25rem);
}

.epa-auth__field { display: grid; gap: 0.45rem; }

.epa-auth__label {
  font-size: 0.6875rem;
  font-weight: 500;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: #726050;               /* 5.66:1 */
}

/* A password field is an input with the reveal control sitting inside it. */
.epa-auth__inputwrap { position: relative; display: block; }

.epa-auth__input {
  inline-size: 100%;
  padding: 0.9em 1em;
  font-family: inherit;
  font-size: 0.9375rem;
  line-height: 1.4;
  color: #3D3829;
  background: transparent;
  border: 1px solid rgba(98, 91, 66, 0.30);
  border-radius: 0;
  transition:
    border-color 240ms cubic-bezier(0.22, 1, 0.36, 1),
    background-color 240ms cubic-bezier(0.22, 1, 0.36, 1);
}

.epa-auth__input::placeholder { color: #726050; opacity: 1; }

/* The reset code. Tracked so eight digits can be read back off an email
   without losing your place, and the trailing space cancelled so the value
   still sits flush inside the field. */
/* Room for the eye, so a long password never runs under it. */
.epa-auth__inputwrap .epa-auth__input { padding-inline-end: 3.4rem; }

.epa-auth__input.is-code {
  --_ls: 0.32em;
  font-size: 1.05rem;
  letter-spacing: var(--_ls);
  padding-inline-end: calc(1em - var(--_ls));
}

/* --- Focus: exactly ONE ring ----------------------------------------------
   ⚠ THIS BLOCK IS THE FIX FOR A DOUBLE BORDER ON FOCUS, AND THE BUG WAS MINE.
   The first version set `:focus { outline: none; border-color: … }` and then
   `:focus-visible { outline: 2px solid … }`, which stacked a 2px outline on
   top of a changed border — two rings on every keyboard focus.

   Now: outline and box-shadow are both forced off, and the SINGLE indicator
   is the border going to ink-950. No layout shift (the width does not
   change), and it is not colour alone — the field also takes a beige tint.
   The !important is deliberate: it also beats a theme or Elementor kit
   adding its own :focus chrome if this screen is ever rendered inside one.

   MEASURED on the rendered field, not read off the source — see the report.  */

.epa-auth__input:focus,
.epa-auth__input:focus-visible {
  outline: none !important;
  box-shadow: none !important;
  border-color: #3D3829 !important;        /* the one ring — 11.04:1 on cream */
  background: rgba(226, 217, 207, 0.34);   /* beige as a fill, never as type  */
}

.epa-auth__input[aria-invalid="true"] { border-color: #726050; border-inline-start-width: 3px; }

/* Autofill paints its own background straight over the field and ignores
   `background` entirely. The inset shadow is the only way to repaint it, and
   the absurd transition delay stops Chrome re-applying its colour a frame
   later. Same fix as the rest of the site, in this screen's colours. */
.epa-auth__input:is(:-webkit-autofill, :-webkit-autofill:hover, :-webkit-autofill:focus) {
  -webkit-text-fill-color: #3D3829;
  -webkit-box-shadow: 0 0 0 100px #FCF8F1 inset;
          box-shadow: 0 0 0 100px #FCF8F1 inset;
  caret-color: #3D3829;
  transition: background-color 100000s ease-in-out 0s;
  font-family: inherit;
}

/* --- The rule, shown before anybody submits ------------------------------ */

.epa-auth__hint {
  font-size: 0.8125rem;
  line-height: 1.45;
  color: #625B42;               /* 6.41:1 */
}

/* --- Show / hide password ------------------------------------------------
   An eye, not the word "Show" — client instruction, 2026-08-20.

   IT IS STILL A REAL <button type="button">: focusable, driven by Enter and
   Space, and it announces its state. type="button" is load-bearing — a
   <button> inside a <form> defaults to submit, and "I revealed my password
   and the form sent itself" is a bad way to discover that.

   THE ACCESSIBLE NAME NOW COMES ENTIRELY FROM VISUALLY HIDDEN TEXT, because
   there is no visible label left. The whole phrase is in there — "Show
   password", not a bare "password" — and it is swapped with the icon, so
   name and state never disagree (WCAG 4.1.2). WCAG 2.5.3, Label in Name, no
   longer applies here: it only bites when a VISIBLE label exists.

   THE BOX IS THE INPUT'S FULL HEIGHT AND 3.4rem WIDE — comfortably past the
   24x24 that WCAG 2.5.8 asks for and into the 44x44 that a thumb wants, even
   though the eye itself draws at 20px. */

.epa-auth__peek {
  position: absolute;
  inset-block: 0;
  inset-inline-end: 0;
  inline-size: 3.4rem;          /* ~54px against a ~46px tall field */

  display: grid;
  place-items: center;
  appearance: none;
  margin: 0;
  padding: 0;
  color: #726050;               /* 5.66:1 */
  cursor: pointer;

  /* ⚠ FORCED, for the same reason as the icon's fill. MEASURED against the
     hostile harness: a kit shipping
     `button { background: hotpink !important; border-radius: 999px !important }`
     puts a pink pill behind the eye. Appearance only — never padding or
     display, which is the neutraliser trap that collapsed a tap target to
     zero on this project once already (docs/design-system.md §6). */
  background: none !important;
  border: 0 !important;
  border-radius: 0 !important;
  box-shadow: none !important;
  transition: color 240ms cubic-bezier(0.22, 1, 0.36, 1);
}

.epa-auth__peek:hover,
.epa-auth__peek[aria-pressed="true"] { color: #3D3829; }

.epa-auth__peek:focus-visible {
  outline: 2px solid #625B42;
  outline-offset: -2px;
  color: #3D3829;
}

/* ⚠ KIT DEFENCE, AND THIS ONE IS NOT HYPOTHETICAL — it has bitten this
   project twice. A theme or an Elementor kit that ships `svg { fill: … }`
   turns a stroked icon into a solid blob. The auth screen loads no theme CSS
   of its own, but this component is shared with the curtain, which paints
   inside the theme's document where a kit absolutely can reach it. Forced,
   not hoped for. Same convention as the header's icons: 24x24 box, stroked,
   1.5, currentColor. */
.epa-auth__peek-i {
  display: block;
  inline-size: 1.25rem;
  block-size: 1.25rem;
  fill: none !important;
  stroke: currentColor !important;
  stroke-width: 1.5;
  stroke-linecap: round;
  stroke-linejoin: round;
  pointer-events: none;         /* clicks belong to the button */
}

/* [hidden] loses to display:block from the rule above, so it is restated. */
.epa-auth__peek-i[hidden] { display: none; }

.epa-auth__row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  margin-block-start: -0.2rem;
}

.epa-auth__check {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.8125rem;
  color: #544E39;
  cursor: pointer;
}

.epa-auth__check input {
  inline-size: 1rem;
  block-size: 1rem;
  accent-color: #625B42;
  margin: 0;
}

/* Honeypot. Off-screen rather than display:none, because some bots skip
   anything that is hidden outright. */
.epa-auth__pot {
  position: absolute;
  inline-size: 1px; block-size: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* --- Button --------------------------------------------------------------
   The site's one button gesture: the ground rises from the floor and the
   label rolls. NO ARROW, NO ICON, NO CHEVRON — standing client rule.
   Both labels sit in the SAME grid cell, so the button is sized by the wider
   of the two and its width never changes on hover. Here they are identical
   ("a straight roll is better than a mismatch" — docs/design-system.md §3). */

.epa-auth__btn {
  position: relative;
  isolation: isolate;
  overflow: hidden;

  display: inline-flex;
  align-items: center;
  justify-content: center;
  inline-size: 100%;
  margin-block-start: 0.35rem;
  padding: 1.35em 2.4em;

  font-family: inherit;
  font-size: 0.6875rem;
  font-weight: 500;
  line-height: 1;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  white-space: nowrap;

  color: #FCF8F1;
  background: #3D3829;
  border: 1px solid #3D3829;
  border-radius: 0;
  cursor: pointer;
  transition: color 520ms cubic-bezier(0.22, 1, 0.36, 1),
              border-color 520ms cubic-bezier(0.22, 1, 0.36, 1);
}

.epa-auth__btn::before {
  content: "";
  position: absolute;
  z-index: -1;
  inset: 0;
  background: #C2C1AF;          /* ink-950 on sage measures 6.43:1 */
  transform: scaleY(0);
  transform-origin: bottom;
  transition: transform 500ms cubic-bezier(0.22, 1, 0.36, 1);
}

.epa-auth__btn:hover::before,
.epa-auth__btn:focus-visible::before { transform: scaleY(1); }

.epa-auth__btn:hover,
.epa-auth__btn:focus-visible { color: #3D3829; border-color: #C2C1AF; }

.epa-auth__btn:focus-visible { outline: 2px solid #625B42; outline-offset: 3px; }

.epa-auth__btn-t { display: grid; overflow: hidden; text-align: center; }

.epa-auth__btn-t > * {
  grid-area: 1 / 1;
  display: block;
  font-style: normal;
  transition: transform 550ms cubic-bezier(0.22, 1, 0.36, 1);
}

.epa-auth__btn-t > em { transform: translateY(105%); }

.epa-auth__btn:hover .epa-auth__btn-t > i,
.epa-auth__btn:focus-visible .epa-auth__btn-t > i { transform: translateY(-105%); }

.epa-auth__btn:hover .epa-auth__btn-t > em,
.epa-auth__btn:focus-visible .epa-auth__btn-t > em { transform: translateY(0); }

.epa-auth__btn[aria-busy="true"] { pointer-events: none; opacity: 0.62; }

/* ==========================================================================
   LINKS — a RESTING underline, plus the house sweep on top
   --------------------------------------------------------------------------
   ⚠ THE RESTING RULE IS NOT OPTIONAL. An earlier version had no underline at
   rest, relying on colour and weight alone, and the client hit exactly the
   failure that predicts: "New here? Join the membership" read as a sentence,
   not as something you could click. That is WCAG 1.4.1 (Use of Colour), and
   it is now fixed in their favour.

   TWO PSEUDO-ELEMENTS AT IDENTICAL COORDINATES, which is what guarantees they
   line up. Matching a `text-decoration: underline` against an absolutely
   positioned rule means chasing text-underline-offset across every font size;
   two absolutely positioned rules with the same `bottom` cannot drift.

     ::before  the resting rule. Always there. currentColor at 0.72.
     ::after   the house sweep. Full strength, draws in from the LEFT on
               hover and, on release, KEEPS TRAVELLING and leaves by the
               RIGHT — never retracing, by swapping transform-origin rather
               than reversing the animation.

   So hovering reads as the underline darkening left-to-right along a line
   that was already there.

   MEASURED, composited over cream #FCF8F1:
     ink-950 at 0.72  →  rgb(115,110,98)   4.72:1
     olive   at 0.72  →  rgb(142,136,115)  3.35:1
   Both clear the 3:1 that a non-text indicator needs. 0.55 was the break-even
   (3.07:1) and left no margin, so 0.72 it is.

   0.55s / cubic-bezier(0.4, 0, 0, 1) is the site's own overlay ease
   (--epa-ease-sweep in src/01-tokens.css). Those numbers were FITTED to the
   reference build frame by frame — do not round them.
   ========================================================================== */

.epa-auth__link {
  position: relative;
  color: #3D3829;
  text-decoration: none;
  font-weight: 500;            /* a second, non-colour cue on top of the rule */
}

.epa-auth__link::before,
.epa-auth__link::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: -2px;
  block-size: 1px;
  background: currentColor;
  pointer-events: none;
}

/* Resting. Present before anybody touches anything. */
.epa-auth__link::before { opacity: 0.72; }

/* The sweep, riding on top of it. */
.epa-auth__link::after {
  transform: scaleX(0);
  transform-origin: right center;          /* ← the EXIT origin */
  transition: transform 0.55s cubic-bezier(0.4, 0, 0, 1);
}

/* Keyboard focus draws the rule everywhere, touch device or not. */
.epa-auth__link:focus-visible::after {
  transform: scaleX(1);
  transform-origin: left center;           /* ← the ENTRY origin */
}

.epa-auth__link:focus-visible {
  outline: 2px solid #625B42;
  outline-offset: 3px;
}

/* Hover is gated on a real pointer. On a touch screen :hover sticks after a
   tap and the rule would sit there drawn until something else is tapped. */
@media (hover: hover) and (pointer: fine) {
  .epa-auth__link:hover::after {
    transform: scaleX(1);
    transform-origin: left center;
  }
}

.epa-auth__link.is-quiet { color: #625B42; font-size: 0.8125rem; font-weight: 400; }

/* --- The switch block ---------------------------------------------------- */

.epa-auth__swap {
  margin-block-start: clamp(1.5rem, 3vw, 2.25rem);
  padding-block-start: 1.25rem;
  border-block-start: 1px solid rgba(194, 193, 175, 0.65);  /* sage, hairline only */
}

.epa-auth__swap-line {
  text-align: center;
  font-size: 0.875rem;
  color: #544E39;               /* 7.85:1 */
}

/* The supporting line. Restored 2026-08-20 at the client's request — every
   one of these says something the plugin actually does. No timeframes, no
   benefits, nothing a visitor could act on that is not already true. */
.epa-auth__swap-note {
  text-align: center;
  margin-block-start: 0.45rem;
  font-size: 0.8125rem;
  line-height: 1.5;
  color: #625B42;               /* 6.41:1 */
}

.epa-auth__meta { margin-block-start: 1rem; font-size: 0.875rem; color: #544E39; }

/* ⚠ .epa-auth__foot IS GONE AGAIN, AND FOR GOOD THIS TIME.
   It carried the site name under the form. The lockup at the top of the
   screen now says exactly that, and the client's objection was seeing it
   twice on one screen. There is no empty slot left behind — the element is
   not printed at all. */


/* ⚠ NOT LEGAL WORDING — MUST NOT GO LIVE. Off by default; the setting exists
   only so the client can see the shape of the line. → Q24 */
.epa-auth__terms {
  font-size: 0.75rem;
  line-height: 1.55;
  color: #625B42;
}

/* --- The no-JavaScript notice --------------------------------------------
   With JavaScript on, toast.js lifts this into a toast and empties the box,
   so the message is never shown twice. */

.epa-auth__notice {
  margin-block-end: 1.25rem;
  padding: 0.85rem 1rem;
  font-size: 0.875rem;
  border: 1px solid rgba(98, 91, 66, 0.30);
  background: rgba(226, 217, 207, 0.5);
  color: #3D3829;
}

.epa-auth__notice.is-error { border-color: #726050; border-inline-start-width: 3px; }
.epa-auth__notice:empty    { display: none; }

/* ==========================================================================
   Narrower viewports
   ========================================================================== */

/* ⚠ THERE IS NO "MEDIA BAND ACROSS THE TOP" BREAKPOINT, AND THERE MUST NOT BE.
   The client called this out specifically: the video is beside the form or it
   is not there at all. It never becomes a strip above the form with the
   fields underneath.

   THE BREAKPOINT IS 1100px, CHOSEN FROM WHAT THE LAYOUT CAN ACTUALLY HOLD.
   The form is min(24rem, 100%) = 384px inside padding of up to 4vw a side. In
   the two-column layout each half gets 50% of the viewport, so the form's half
   needs 384 + 2 x 44 = 472px to sit properly. Two of those is 944px, and the
   first round number clear of it is 1100 — which also puts BOTH tablet
   orientations on the no-video layout, as asked:

       768 x 1024  portrait   → no video   ✓
      1024 x  768  landscape  → no video   ✓   (1024 < 1100)
      1280 x  800  laptop     → two columns
      1440 x  900  desktop    → two columns, 720px a side

   A 1024-wide landscape tablet would have kept the video under the old 768
   rule. That is the bug this number fixes. */
@media (max-width: 1099px) {
  .epa-auth {
    grid-template-columns: 1fr;
    grid-template-rows: auto;
  }

  /* display:none, so the <video> is never fetched or decoded — the same rule
     as the menu panel's clip in src/04-header.css. (display:none ALONE does
     not stop the fetch when a video autoplays — MEASURED. auth.js withholds
     the src as well; see the template.) */
  .epa-auth__media { display: none; }

  .epa-auth__panel {
    align-content: start;
    padding-block-start: clamp(3rem, 9vw, 5rem);
  }

  /* The media column is gone, so this is the only place the lockup can be —
     centred above the form, with its divider under it. */
  .epa-auth__brand { display: grid; }
}

@media (max-width: 600px) {
  .epa-lockup { --epa-lockup-max: 46px; }
  .epa-lockup__sub { --_ls: 0.24em; font-size: 0.5625rem; }
}

/* ==========================================================================
   Reduced motion — every transition here is transform or opacity, so there is
   nothing to re-engineer, only to switch off.
   ========================================================================== */

@media (prefers-reduced-motion: reduce) {
  .epa-auth__btn,
  .epa-auth__btn::before,
  .epa-auth__btn-t > *,
  .epa-auth__link::after,
  .epa-auth__input,
  .epa-auth__peek {
    transition-duration: 1ms !important;
  }
  .epa-auth__btn::before { transform: scaleY(1); opacity: 0; }
  .epa-auth__btn:hover::before,
  .epa-auth__btn:focus-visible::before { opacity: 1; }

  /* The sweep still appears and still disappears — it just stops travelling.
     The RESTING rule is untouched: it is an accessibility affordance, not
     decoration, and it never animated in the first place. */
  .epa-auth__link::after { transform-origin: center center !important; }
}
