/* ============================================================
   DAYANA PORTFOLIO GATE
   ============================================================

   The art block (tokens, .dpg-art-frame, .dpg-art, .dpg-bird, the six
   keyframe sets, the responsive overrides and the 1900px grain kill
   switch) is a straight copy of the theme's hero.css with the class
   names prefixed. It is duplicated on purpose: the plugin must not
   depend on the theme, so that a theme change cannot break the gate.
   If the homepage art is ever retuned, the same numbers have to be
   changed here too. Nothing else in the theme is duplicated.

   Rules that must not be broken in this file:
   - mix-blend-mode: color-burn is per <img>, never on a container.
   - No opacity / transform / filter / z-index on .dpg-art-frame,
     .dpg-art or .dpg-bird, or on any ancestor of them. A stacking
     context there isolates the burn from the gradient and the bird
     vanishes against the white page.
   - Vertical anchoring uses top, never translateY.
   - aspect-ratio, never a padding-top hack.
   - There is no z-index anywhere in this file. Paint order is DOM order.

   Values marked PROVISIONAL were measured off the 2x Figma export, not
   read from Dev Mode. They are all variables so they can be corrected
   in the browser without touching a rule.
   ============================================================ */

:root {
  --speed: 0.6;

  --font-heading: "Poppins", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  --font-body: "Geist", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;

  --ink: #131333;
  --body-ink: #1D1D4C;
  --hairline: #EFEFFE;

  /* ---- Form palette, all Dev Mode ---- */
  --field-border: #8180FD;
  --field-bg: #FFF;
  --field-bg-hover: #F7F7FF;
  --field-ink-empty: #74757F;         /* placeholder, 4.57:1 on white */
  --field-ink-empty-hover: #70717A;   /* 4.55:1 on #F7F7FF */
  --field-ink-filled: #1D1D4C;
  --field-border-error: #D76F6F;
  --shadow-sm: 0 4px 12px 0 rgba(39, 38, 101, 0.08);

  --btn-bg: #6160FD;
  --btn-bg-hover: #5756E4;
  --btn-bg-busy: #DFDFFF;             /* the Dev Mode disabled fill, reused
                                         for the in-flight state */
  --btn-ink: #FFF;
  --btn-ring: rgba(97, 96, 253, 0.5);

  --error-bg: #FFE6E6;
  --error-ink: #984F4F;               /* 4.97:1 on #FFE6E6, passes AA */

  /* ---- Layout ---- */
  --dpg-hero-h: max(86vh, 560px);
  --dpg-row-w: 477px;                 /* field + gap + button, Dev Mode */
  --dpg-row-gap: 16px;                /* PROVISIONAL, measured 14.5 */
  --dpg-logo-top: 102px;              /* PROVISIONAL, measured */
  --dpg-logo-h: 28px;                 /* PROVISIONAL, measured */
  --dpg-logo-gap: 120px;              /* PROVISIONAL, logo to heading */
  --dpg-heading-gap: 16px;            /* PROVISIONAL, heading to subheading */
  --dpg-sub-gap: 48px;                /* Dev Mode, subheading to field */
  --dpg-error-gap: 24px;              /* Dev Mode, field to error */

  /* ---- Type ----
     Dayana has not sent Dev Mode for the gate heading and subheading.
     Both sizes are measured off the 2x export by ink height, which is
     accurate to about a pixel; the WEIGHTS and LINE HEIGHTS below are
     inferred and are the values most likely to need correcting. */
  --dpg-heading-size: 26px;           /* PROVISIONAL, measured */
  --dpg-heading-lh: 34px;             /* PROVISIONAL, inferred */
  --dpg-heading-weight: 600;          /* PROVISIONAL, inferred */
  --dpg-sub-size: 16px;               /* measured, matches Body/md */
  --dpg-sub-lh: 24px;                 /* Body/md */
  --dpg-sub-weight: 400;

  /* ---- Hairlines ----
     The two verticals sit symmetrically about the centre line. The
     export has them 620px apart centred at x 716 in a 1440 frame, four
     pixels left of the frame centre; that asymmetry is treated as a
     Figma imprecision and squared up here. Set --dpg-v-offset to
     310px to reproduce the export exactly. */
  --dpg-v-offset: 310px;
  /* Where the verticals travel to on unlock: the homepage's OUTER grid
     lines, x 120 and 1320 at 1440. Expressed against the reproduced
     container rather than in vw, because vw includes the scrollbar and
     would drift from layout-centred content. Same mechanism as the
     theme's gridline offsets. */
  --dpg-container-pad: clamp(20px, 3vw, 24px);
  --dpg-h-1: 62px;                    /* above the logo */
  --dpg-h-2: 164px;                   /* below the logo */
  --dpg-h-3: 104px;                   /* ABOVE the strip, not from the top:
                                         keeps its distance to the strip
                                         constant at every window height */

  /* ---- Unlock ----
     The lines MOVE at full opacity first and only fade at the end. If
     the two run together the fade wins and the movement is invisible,
     which is what the first build did. */
  --dpg-unlock-ms: 900ms;
  --dpg-line-move-ms: 700ms;
  --dpg-line-fade-ms: 260ms;
  --dpg-line-fade-delay: 520ms;
  --dpg-ease: cubic-bezier(0.45, 0, 0.55, 1);

  /* ---- Art, verbatim from hero.css ---- */
  --tune-body: 1;
  --tune-inner-root: 1;
  --tune-wing-left: 1;
  --tune-wing-right: 1;
  --tune-tale-bottom: 1;
  --tune-tale-top: 1;

  --bird-width: min(62vw, 110svh);
  --bird-right: 0.6vw;
  --bird-top: calc(var(--bird-width) * -0.1613);

  --grad-left: -8.4%;
  --grad-top: -20.5%;
  --grad-w: 160%;
  --grad-h: 146.1%;
}

@supports (height: 1svh) {
  :root { --dpg-hero-h: max(86svh, 560px); }
}

* { margin: 0; padding: 0; box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  /* The gate does not scroll and the homepage does. Without a reserved
     gutter the scrollbar appears at the handoff, the content box narrows
     by the scrollbar width and every centred thing jumps sideways by
     half of it. Reserving the space here means both documents have the
     same content width, so nothing moves. */
  scrollbar-gutter: stable;
}

/* Cross-document view transition. The same at-rule is injected into the
   homepage head by inc/frontend.php, and BOTH documents have to carry it
   or nothing happens. The browser holds the gate's last frame, snapshots
   both documents and cross-fades, so there is no white flash between
   them. Chromium 126+ and Safari 18.2+; anything else navigates the old
   way and loses nothing but the cross-fade.

   Deliberately no view-transition-name on the art. A named morph makes
   the browser scale a rasterised snapshot, which stutters in Safari, and
   it would promote the colour-burn layers into separately composited
   surfaces. The default root cross-fade is both safer and better here:
   the bird is in the same place in both frames, so it simply does not
   appear to move. */
@media (prefers-reduced-motion: no-preference) {
  @view-transition { navigation: auto; }
}

body.dpg {
  font-family: var(--font-body);
  color: var(--ink);
  background: #fff;      /* the burn only works over white plus gradient */
  overflow-x: clip;
  min-height: 100vh;
}

.dpg-page {
  position: relative;
  /* Fills the viewport so the two vertical hairlines run the whole
     height, as they do in the export, rather than stopping under the
     strip. */
  min-height: 100vh;
}

@supports (height: 1svh) {
  .dpg-page { min-height: 100svh; }
}

/* ============================================================
   1. ART
   ============================================================ */

/* Reproduces the theme's .hero box. The art's tablet and mobile
   vertical anchor is a percentage of this box, so it has to be the same
   height as the homepage hero or the bird lands somewhere else. */
.dpg-art-frame {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: var(--dpg-hero-h);
  overflow: hidden;
  pointer-events: none;
}

.dpg-art {
  position: absolute;
  right: var(--bird-right);
  width: var(--bird-width);
  aspect-ratio: 1500 / 1395;
  top: var(--bird-top);
  pointer-events: none;
}

.dpg-art > svg {
  position: absolute;
  /* --dpg-shift-x/y are the gate-only offset from Settings. They live
     inside calc() rather than replacing the value, so that setting them
     to 0 on unlock transitions `left` and `top` back to the homepage
     framing. Custom properties do not animate, but the properties that
     read them do. */
  left: calc(var(--grad-left) + var(--dpg-shift-x, 0px));
  top: calc(var(--grad-top) + var(--dpg-shift-y, 0px));
  width: var(--grad-w);
  height: var(--grad-h);
  display: block;
}

/* Only the bottom right ellipse is lit on the gate. The other two are
   present in the same SVG at opacity 0 and fade in on unlock, which is
   why there is no second gradient file and no cross-fade between two
   elements. Restored values are the SVG's own: 0.4, 0.4, 0.5. */
.dpg-ell-1,
.dpg-ell-2 { opacity: 0; }

.dpg-bird { position: absolute; inset: 0; }

.dpg-bird img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  mix-blend-mode: color-burn;
  transform-origin: 48% 52%;
  animation-timing-function: cubic-bezier(0.45, 0, 0.55, 1);
  animation-iteration-count: infinite;
  /* Held still until the site unlocks, per the design intent: the bird
     only comes alive once you are through. The negative delays still
     apply, so each layer is paused at its designed phase, not at 0. */
  animation-play-state: paused;
  will-change: transform, opacity;
  user-select: none;
  -webkit-user-drag: none;
}

.dpg-bird__body {
  opacity: calc(0.90 * var(--tune-body));
  animation-name: dpg-flex-body;
  animation-duration: calc(8.4s * var(--speed));
  animation-delay: calc(-8.2s * var(--speed));
}
.dpg-bird__inner-root {
  opacity: calc(0.70 * var(--tune-inner-root));
  animation-name: dpg-flex-inner-root;
  animation-duration: calc(6.3s * var(--speed));
  animation-delay: calc(-2.1s * var(--speed));
}
.dpg-bird__wing-left {
  opacity: calc(0.76 * var(--tune-wing-left));
  animation-name: dpg-flex-wing-left;
  animation-duration: calc(6.3s * var(--speed));
  animation-delay: calc(-2.1s * var(--speed));
}
.dpg-bird__wing-right {
  opacity: calc(0.85 * var(--tune-wing-right));
  animation-name: dpg-flex-wing-right;
  animation-duration: calc(5.5s * var(--speed));
  animation-delay: calc(-0.5s * var(--speed));
}
.dpg-bird__tale-bottom {
  opacity: calc(0.67 * var(--tune-tale-bottom));
  animation-name: dpg-flex-tale-bottom;
  animation-duration: calc(5.1s * var(--speed));
  animation-delay: calc(-1.8s * var(--speed));
}
.dpg-bird__tale-top {
  opacity: calc(0.72 * var(--tune-tale-top));
  animation-name: dpg-flex-tale-top;
  animation-duration: calc(7.1s * var(--speed));
  animation-delay: calc(-3.5s * var(--speed));
}

body.is-unlocking .dpg-bird img { animation-play-state: running; }

@keyframes dpg-flex-body {
  0%, 100% { transform: scale(1);     opacity: calc(0.90 * var(--tune-body)); }
  50%      { transform: scale(1.018); opacity: calc(0.98 * var(--tune-body)); }
}
@keyframes dpg-flex-inner-root {
  0%, 100% { transform: rotate(0deg);   opacity: calc(0.70 * var(--tune-inner-root)); }
  50%      { transform: rotate(1.5deg); opacity: calc(0.78 * var(--tune-inner-root)); }
}
@keyframes dpg-flex-wing-left {
  0%, 100% { transform: rotate(0deg) scale(1);    opacity: calc(0.76 * var(--tune-wing-left)); }
  50%      { transform: rotate(6deg) scale(1.02); opacity: calc(0.88 * var(--tune-wing-left)); }
}
@keyframes dpg-flex-wing-right {
  0%, 100% { transform: rotate(0deg) scale(1);     opacity: calc(0.85 * var(--tune-wing-right)); }
  50%      { transform: rotate(-8deg) scale(1.02); opacity: calc(0.95 * var(--tune-wing-right)); }
}
@keyframes dpg-flex-tale-bottom {
  0%, 100% { transform: rotate(0deg) translateY(0);    opacity: calc(0.67 * var(--tune-tale-bottom)); }
  50%      { transform: rotate(-4deg) translateY(5px); opacity: calc(0.78 * var(--tune-tale-bottom)); }
}
@keyframes dpg-flex-tale-top {
  0%, 100% { transform: rotate(0deg) translateX(0);   opacity: calc(0.72 * var(--tune-tale-top)); }
  50%      { transform: rotate(5deg) translateX(7px); opacity: calc(0.82 * var(--tune-tale-top)); }
}

/* Large-screen safeguard, carried over verbatim. At ~4K the
   feTurbulence surfaces rasterize at 10+ MP per ellipse and browsers
   can drop them, which blanks the gradient and with it the bird. */
@media (min-width: 1900px) {
  .dpg-art > svg g[filter] { filter: none; }
}

/* ============================================================
   2. HAIRLINES
   ============================================================ */

.dpg-lines {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

/* Reproduces the theme's .container so the verticals can land exactly on
   the homepage's outer grid lines. Absolutely positioned children
   measure from the PADDING box, which is why the unlock positions carry
   the padding term rather than being left: 0. Do not "simplify" them,
   same note as sections.css. */
.dpg-grid {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
  max-width: 1248px;
  margin-inline: auto;
  padding-inline: var(--dpg-container-pad);
  pointer-events: none;
}

.dpg-line {
  position: absolute;
  background: var(--hairline);
  opacity: 1;
}

.dpg-line--v { top: 0; bottom: 0; width: 1px; }
.dpg-line--h { left: 0; right: 0; height: 1px; }

/* Gate positions. */
.dpg-line--v-left  { left: calc(50% - var(--dpg-v-offset)); }
.dpg-line--v-right { left: calc(50% + var(--dpg-v-offset)); }

.dpg-line--h-1 { top: var(--dpg-h-1); }
.dpg-line--h-2 { top: var(--dpg-h-2); }
.dpg-line--h-3 { top: calc(var(--dpg-hero-h) - var(--dpg-h-3)); }

/* ============================================================
   3. LAYOUT
   ============================================================ */

.dpg-hero {
  position: relative;
  height: var(--dpg-hero-h);
  display: flex;
  flex-direction: column;
  align-items: center;
  padding-top: var(--dpg-logo-top);
  padding-inline: clamp(20px, 3vw, 24px);
}

.dpg-logo { flex: none; height: var(--dpg-logo-h); }

.dpg-logo img {
  display: block;
  height: var(--dpg-logo-h);
  width: auto;
}

.dpg-logo__text {
  font-family: var(--font-heading);
  font-size: 20px;
  font-weight: 500;
  line-height: var(--dpg-logo-h);
  color: var(--ink);
}

.dpg-panel {
  flex: none;
  width: var(--dpg-row-w);
  max-width: 100%;
  margin-top: var(--dpg-logo-gap);
  text-align: center;
}

/* The strip is empty and structural. Its two borders are the pair of
   hairlines that already match the homepage, so they need no animation
   and no coordinates: 86svh of hero, then this. */
.dpg-strip {
  position: relative;
  border-top: 1px solid var(--hairline);
  border-bottom: 1px solid var(--hairline);
  min-height: 84px;
}

/* ============================================================
   4. TYPE
   ============================================================ */

.dpg-heading {
  font-family: var(--font-heading);
  font-size: var(--dpg-heading-size);
  line-height: var(--dpg-heading-lh);
  font-weight: var(--dpg-heading-weight);
  color: var(--ink);
  letter-spacing: normal;
}

.dpg-sub {
  margin-top: var(--dpg-heading-gap);
  font-family: var(--font-body);
  font-size: var(--dpg-sub-size);
  line-height: var(--dpg-sub-lh);
  font-weight: var(--dpg-sub-weight);
  color: var(--body-ink);
}

.dpg-help {
  margin-top: 24px;
  font-family: var(--font-body);
  font-size: 14px;
  line-height: 20px;
  color: var(--body-ink);
}

.dpg-help a { color: var(--ink); text-decoration: underline; text-underline-offset: 3px; }
.dpg-help a:hover { color: #4A4290; }

.dpg-sr {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* ============================================================
   5. FORM
   ============================================================ */

.dpg-form { margin-top: var(--dpg-sub-gap); }

.dpg-row {
  display: flex;
  align-items: center;
  gap: var(--dpg-row-gap);
}

/* ---- Field ------------------------------------------------
   The box carries the border, fill, shadow and height; the <input>
   inside it is transparent and borderless. That is what lets the eye
   button sit inside the frame and lets :focus-within style the whole
   control.

   Dev Mode says padding 24px 16px 24px 24px on a 64px box. Vertical
   padding of 24 top and bottom inside a fixed 64px box leaves 14px for
   a 24px line, so the text would not fit. The box is flex-centred
   instead, which renders identically and cannot overflow. Horizontal
   padding is exactly as specified. */
.dpg-field {
  display: flex;
  align-items: center;
  gap: 8px;
  flex: 1 1 0;
  min-width: 0;
  height: 64px;
  padding: 0 16px 0 24px;
  border-radius: 8px;
  border: 1px solid var(--field-border);
  background: var(--field-bg);
  box-shadow: var(--shadow-sm);
  transition: background-color 150ms ease, border-color 150ms ease, box-shadow 150ms ease;
}

.dpg-field:hover { background: var(--field-bg-hover); }

/* Dev Mode focus is a 3px border. A 3px border inside a border-box of
   fixed height eats 2px of the content area per side and shifts the
   value sideways on focus. A 2px inset ring on top of the 1px border
   is the same 3px of colour with no layout movement. */
.dpg-field:focus-within {
  box-shadow: inset 0 0 0 2px var(--field-border), var(--shadow-sm);
}

.dpg-field.is-error { border-color: var(--field-border-error); }

.dpg-input {
  flex: 1 1 auto;
  min-width: 0;
  height: 100%;
  border: 0;
  outline: 0;
  background: transparent;
  font-family: var(--font-body);
  font-size: 16px;
  line-height: 24px;
  font-weight: 400;
  color: var(--field-ink-filled);
}

.dpg-input::placeholder { color: var(--field-ink-empty); opacity: 1; }
.dpg-field:hover .dpg-input::placeholder { color: var(--field-ink-empty-hover); }

/* Chrome paints its own autofill background over the field fill. */
.dpg-input:-webkit-autofill,
.dpg-input:-webkit-autofill:focus {
  -webkit-text-fill-color: var(--field-ink-filled);
  transition: background-color 100000s ease 0s;
}

/* ---- Eye toggle ----
   Icon is 24px as designed; the padding and matching negative margin
   grow the hit area to 44x44 (WCAG 2.2 target size) without changing
   anything visible or the 16px gap to the right edge. */
.dpg-eye {
  flex: none;
  display: grid;
  place-items: center;
  width: 24px;
  height: 24px;
  padding: 10px;
  margin: -10px -10px -10px 0;
  box-sizing: content-box;
  border: 0;
  background: none;
  color: var(--btn-bg);
  cursor: pointer;
  border-radius: 6px;
}

.dpg-eye svg { display: block; width: 24px; height: 24px; grid-area: 1 / 1; }
.dpg-eye .dpg-eye__hide { display: none; }
.dpg-eye[aria-pressed="true"] .dpg-eye__show { display: none; }
.dpg-eye[aria-pressed="true"] .dpg-eye__hide { display: block; }

.dpg-eye:hover { color: var(--btn-bg-hover); }
.dpg-eye:focus-visible {
  outline: 3px solid var(--btn-ring);
  outline-offset: 0;
}

/* ---- Submit ---- */
.dpg-submit {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  height: 64px;
  padding: 0 24px;
  border-radius: 8px;
  border: 1px solid var(--btn-bg);
  background: var(--btn-bg);
  box-shadow: var(--shadow-sm);
  color: var(--btn-ink);
  font-family: var(--font-body);
  font-size: 18px;
  line-height: 28px;
  font-weight: 600;
  cursor: pointer;
  transition: background-color 150ms ease, border-color 150ms ease;
}

.dpg-submit:hover,
.dpg-submit:active {
  background: var(--btn-bg-hover);
  border-color: var(--btn-bg-hover);
}

/* Dev Mode focus was a 3px inner border in rgba(97,96,253,.5) ON the
   same #6160FD fill. Composited that is exactly #6160FD: a 1.00:1 ring,
   invisible. Moved outside the button as agreed, where it sits on white
   and is actually visible. */
.dpg-submit:focus-visible {
  outline: 3px solid var(--btn-ring);
  outline-offset: 2px;
}

/* In flight. Reuses the Dev Mode disabled fill, which is the only place
   that treatment is still needed now that the button is always enabled. */
.dpg-submit[aria-busy="true"],
.dpg-submit:disabled {
  background: var(--btn-bg-busy);
  border-color: var(--btn-bg-busy);
  cursor: default;
}

/* ---- Error ----
   Always in the DOM so role="alert" can announce a change. Hidden by
   :empty rather than by [hidden] or display:none on a populated node,
   because a live region that was removed from the box tree is
   unreliable across screen readers. */
.dpg-error {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  min-height: 56px;
  margin-top: var(--dpg-error-gap);
  padding: 5px 12px;
  border-radius: 8px;
  background: var(--error-bg);
  color: var(--error-ink);
  font-family: var(--font-heading);
  font-size: 13px;
  /* Dev Mode says `normal`, which resolves to Poppins' own metric
     (about 19.5px at 13px) and drifts slightly per platform. Kept as
     specified, exposed as a var so it can be pinned to a number. */
  line-height: var(--dpg-error-lh, normal);
  font-weight: 500;
  text-align: left;
}

/* Dev Mode said justify-content: space-between, which on a two child
   row pushes the text away from the icon to the far right edge. The
   Figma screenshot shows them adjacent on the left, which is what
   ships. Set --dpg-error-justify: space-between to follow Dev Mode. */
.dpg-error { justify-content: var(--dpg-error-justify, flex-start); }

.dpg-error:empty { display: none; }

.dpg-error__icon { flex: none; width: 20px; height: 20px; }

/* ============================================================
   6. UNLOCK
   ============================================================ */

.dpg--animate .dpg-ell,
.dpg--animate .dpg-art > svg,
.dpg--animate .dpg-hero {
  transition-duration: var(--dpg-unlock-ms);
  transition-timing-function: var(--dpg-ease);
}

.dpg--animate .dpg-ell       { transition-property: opacity; }
.dpg--animate .dpg-art > svg { transition-property: left, top; }
.dpg--animate .dpg-hero      { transition-property: opacity; }

/* Position and opacity are timed separately on purpose: the line travels
   for 700ms at full strength and only starts fading at 520ms, so the
   movement is the thing you see and the fade just finishes it off.
   `left` and `top` are layout properties rather than transforms, which
   is the slower path, but this is five one-pixel elements animating once
   and it buys an exact landing on the homepage grid, which a transform
   in mixed units cannot give. */
.dpg--animate .dpg-line {
  transition-property: left, top, opacity;
  transition-duration: var(--dpg-line-move-ms), var(--dpg-line-move-ms), var(--dpg-line-fade-ms);
  transition-delay: 0ms, 0ms, var(--dpg-line-fade-delay);
  transition-timing-function: var(--dpg-ease);
}

/* THE VERTICALS TRAVEL TO THE HOMEPAGE'S OUTER GRID LINES.
   x 120 and 1320 at 1440, measured off the homepage export and
   reproduced structurally through .dpg-grid rather than in pixels. The
   homepage hero itself carries no verticals (all six live below the
   strip), so once they arrive they fade. The 1px subtraction on the
   right puts the line inside the content edge, matching the export,
   which reads 1319. */
body.is-unlocking .dpg-line--v-left  { left: var(--dpg-container-pad); }
body.is-unlocking .dpg-line--v-right { left: calc(100% - var(--dpg-container-pad) - 1px); }

/* THE HORIZONTALS COLLAPSE ONTO THE STRIP.
   All three run down to the strip's top border, which is the one
   horizontal that stays and is already exactly where the homepage puts
   it, then fade. The extra rules fold into the one that survives. */
body.is-unlocking .dpg-line--h { top: var(--dpg-hero-h); }

body.is-unlocking .dpg-line--go { opacity: 0; }

/* The two hidden ellipses arrive at their own SVG opacities. */
body.is-unlocking .dpg-ell-1 { opacity: 0.4; }
body.is-unlocking .dpg-ell-2 { opacity: 0.5; }

/* Only moves when a gate offset is set in Settings. */
body.is-unlocking .dpg-art { --dpg-shift-x: 0px; --dpg-shift-y: 0px; }

/* Fading the copy out before the navigation means the view transition
   only has to cross-fade two frames that are already nearly identical,
   which is the smoothest possible handoff and sidesteps the Safari
   snapshot-scaling stutter entirely. */
body.is-unlocking .dpg-hero { opacity: 0; }

/* ============================================================
   7. RESPONSIVE
   Art overrides are verbatim from hero.css so the bird lands in the
   same place at every breakpoint on both screens.
   ============================================================ */

@media (max-width: 900px) {
  :root {
    --bird-width: min(52vw, 76svh);
    --bird-right: 3vw;
    --bird-top: calc(44% - var(--bird-width) * 0.465);
    --grad-left: -81%;
    --grad-top: -16%;
    --grad-w: 228%;
    --grad-h: 198%;

    --dpg-logo-top: 64px;
    --dpg-logo-gap: 72px;
  }

  /* The decorative grid fights a single centred column, same call as
     the homepage sections. The strip borders stay: they are the two
     that match. */
  .dpg-lines { display: none; }
}

@media (max-width: 600px) {
  :root {
    --bird-width: min(80vw, 66svh);
    --bird-right: -12vw;
    --bird-top: calc(38% - var(--bird-width) * 0.465);

    --dpg-logo-top: 48px;
    --dpg-logo-gap: 56px;
    --dpg-sub-gap: 32px;
  }

  /* No mobile design exists for this screen. The row stacks so the
     field and the button both stay full width and comfortably tappable
     rather than being squeezed side by side. INFERRED. */
  .dpg-row { flex-direction: column; align-items: stretch; }
  .dpg-submit { width: 100%; }
}

/* ============================================================
   8. REDUCED MOTION
   ============================================================ */

@media (prefers-reduced-motion: reduce) {
  .dpg-bird img { animation: none; }

  .dpg--animate .dpg-line,
  .dpg--animate .dpg-ell,
  .dpg--animate .dpg-art > svg,
  .dpg--animate .dpg-hero,
  .dpg-field,
  .dpg-submit {
    transition: none;
  }
}
