/* v0.38.0 (Max: "ok I want to redesign the login page of xcvlt.studio using this" - the Sign In handoff, design_handoff_cvlt_login).
   The sign-in page on its own: the brand's two colours on a light ground, a form only, an ink circle that inverts the page from the
   Continue button's dot. Drawn on a 1600 x 900 artboard; full viewport here, the side padding compressing below 1600. Colours are
   tokens (styles/tokens.css, --login-*); the moving parts (the ink circle, the magnetic pull, the intro and the exit) are set from
   views/login.js through the CSSOM and the Web Animations API, which the portal's CSP (style-src 'self') allows. */

body.login-page { background-color: var(--login-grey); background-image: none; color: var(--login-black); color-scheme: light; }
body.login-page #art { display: none; }

.lg {
  min-height: 100vh; min-height: 100dvh;
  display: flex; flex-direction: row; justify-content: space-between;
  /* 56 / 160 / 56 / 72 at 1600 wide; the sides scale with the window below that */
  padding: 56px clamp(32px, 10vw, 160px) 56px clamp(32px, 4.5vw, 72px);
  font-family: var(--sans); color: var(--login-black);
}
.lg-logo { flex: none; align-self: flex-start; display: block; height: 78px; width: auto; max-width: none; }   /* v0.38.2 (Max): 1.5x the handoff's 52px */

.lg-form { flex: none; align-self: center; width: 560px; max-width: 100%; margin: 0; display: flex; flex-direction: column; gap: 48px; }

/* the heading: "Sign / in" and a blinking square for its period; the wrapper clips the intro rise (and keeps the g's descender) */
.lg-head-wrap { overflow: hidden; padding-bottom: .1em; margin-bottom: -.1em; font-size: 136px; }
.lg-head { margin: 0; font-size: inherit; font-weight: 900; line-height: .88; letter-spacing: -.04em; color: var(--login-black); }
.lg-period { display: inline-block; width: .17em; height: .17em; margin-left: .06em; background: var(--login-black); animation: lg-blink 1.1s steps(1) infinite; }
@keyframes lg-blink { 0%, 49% { opacity: 1; } 50%, 100% { opacity: 0; } }

/* the fields: no dividers, a 130px label column */
.lg-fields { display: flex; flex-direction: column; }
.lg-row { display: grid; grid-template-columns: 130px minmax(0, 1fr); align-items: center; }
.lg-row.pw { grid-template-columns: 130px minmax(0, 1fr) auto; }
.lg-label { font-size: 12px; font-weight: 400; line-height: 1.2; letter-spacing: .14em; text-transform: uppercase; color: var(--login-black); }
.lg-input {
  width: 100%; min-width: 0; margin: 0; padding: 24px 0; border: 0; border-radius: 0; outline: none; background: transparent;
  font-family: var(--sans); font-size: 20px; font-weight: 400; line-height: 1.2; color: var(--login-black); caret-color: var(--login-black);
}
.lg-input::placeholder { color: var(--login-placeholder); opacity: 1; }
.lg ::selection { background: var(--login-black); color: var(--login-grey); }   /* the brand pair, not the browser's blue */
.lg-input:focus, .lg-input:focus-visible { outline: none; }
/* a browser's autofill paints its own field colour - kept to the page's */
.lg-input:-webkit-autofill, .lg-input:-webkit-autofill:hover, .lg-input:-webkit-autofill:focus {
  -webkit-text-fill-color: var(--login-black); box-shadow: 0 0 0 1000px var(--login-grey) inset; transition: background-color 600000s 0s;
}
.lg-err { margin: -10px 0 14px 130px; font-size: 14px; line-height: 1.35; color: var(--login-black); }

/* the password toggle: ••• rolls up to Aa */
.lg-eye { min-width: 44px; min-height: 44px; padding: 0; border: 0; background: none; display: flex; align-items: center; justify-content: flex-end; color: var(--login-black); }
.lg-eye-box { position: relative; display: block; width: 30px; height: 20px; overflow: hidden; font-size: 16px; font-weight: 700; line-height: 20px; text-align: center; }
.lg-eye-g { position: absolute; inset: 0; transition: transform .35s cubic-bezier(.7, 0, .2, 1); }
.lg-eye-g.aa { transform: translateY(100%); }
.lg-eye.on .lg-eye-g.dots { transform: translateY(-100%); }
.lg-eye.on .lg-eye-g.aa { transform: none; }

/* Continue: a pill the full width of the form, a grey dot at the right with the arrow in it. The wrapper is the magnetic hit area
   (16px past the button on every side) and what the intro reveals the button through. */
.lg-mag { position: relative; padding: 16px; margin: -16px; }
.lg-btn {
  position: relative; display: flex; align-items: center; width: 100%; margin: 0; padding: 24px 32px; border: 0; border-radius: 999px;
  background: var(--login-black); color: var(--login-grey); text-align: left; cursor: pointer;
  font-family: var(--sans); font-size: 19px; font-weight: 700; line-height: 1.2;
  transition: transform .45s cubic-bezier(.2, .8, .2, 1);
}
.lg-btn-label { display: inline-block; transition: transform .45s cubic-bezier(.2, .8, .2, 1); }
.lg-dot, .lg-arrow { position: absolute; right: 10px; top: 50%; width: 52px; height: 52px; margin-top: -26px; transition: transform .45s cubic-bezier(.2, .8, .2, 1); }
.lg-dot { border-radius: 50%; background: var(--login-grey); }
.lg-dot.off { opacity: 0; }
/* the arrow reads black over the grey dot and grey where its line runs over the black pill */
.lg-arrow { z-index: 2; display: flex; align-items: center; justify-content: center; color: var(--login-grey); mix-blend-mode: difference; pointer-events: none; }
.lg-arrow-box { position: relative; display: block; width: 14px; height: 18px; }
.lg-arrow svg { position: absolute; right: 0; top: -.5px; overflow: visible; }
.lg-arrow line { transform-box: fill-box; transform-origin: right center; transform: scaleX(0); transition: transform .6s cubic-bezier(.7, 0, .2, 1); }
.lg-mag.hov .lg-arrow line { transform: scaleX(1); }
.lg-btn:disabled { cursor: default; }

/* the ink: a page-sized layer, white under "difference" so it swaps the two colours, clipped to a circle round the dot */
.lg-ink { position: fixed; inset: 0; z-index: 50; pointer-events: none; mix-blend-mode: difference; opacity: 0; }
.lg-ink.on { opacity: 1; }
.lg-ink-fill { position: absolute; inset: 0; background: var(--login-ink-fill); clip-path: circle(26px at 50% 50%); }

/* keyboard users get a ring on the button and the toggle (the default outlines are off). v0.38.1 (Max: "when I am typing in email and
   then press tab it gives me a box around the password, make sure it doesnt do that"): no box round a field - the caret says
   where you are typing. */
.lg :focus-visible { outline-color: var(--login-black); }
.lg .lg-btn:focus-visible, .lg .lg-eye:focus-visible { outline: 2px solid var(--login-black); outline-offset: 4px; border-radius: 999px; }

/* no hover to follow (touch), or less motion asked for: no ink and no pull; the button darkens instead */
@media (hover: none), (prefers-reduced-motion: reduce) {
  .lg-btn:hover { opacity: .86; }
}
@media (prefers-reduced-motion: reduce) {
  .lg-period { animation: none; }
  .lg-btn, .lg-btn-label, .lg-dot, .lg-arrow, .lg-arrow line, .lg-eye-g { transition: none; }
}

/* narrower: the form under the logo */
@media (max-width: 1023px) {
  .lg { flex-direction: column; justify-content: flex-start; gap: 64px; padding: 32px; }
  .lg-form { align-self: flex-start; width: 100%; max-width: 560px; }
  .lg-head-wrap { font-size: 96px; }
}

/* ================================================================================================================================
   v0.39.0 (Max: "ok redesign the iphone version now" - the Sign In (Mobile) handoff, design_handoff_cvlt_login_mobile): a phone (under
   600px wide) gets its own page, views/login-phone.js - a black sheet at the top holding the logo and the heading, the form on the
   grey below, the sheet rising out of a black curtain on load, and on Continue the sheet closing over the screen and a bar loader
   running until the portal answers. Drawn on a 390 x 844 artboard; a real phone browser is shorter (Safari on an iPhone 14 leaves
   about 660px), so the top padding, the gaps and the heading row come down in steps below 760px tall. The sheet's height is worked
   out from the same numbers, so it always ends one gap under the heading.
   ================================================================================================================================ */
.lm {
  --lm-pt: 68px; --lm-gap: 36px; --lm-hrow: 288px; --lm-head: 104px;
  --lm-sheet-h: calc(env(safe-area-inset-top, 0px) + var(--lm-pt) + 42px + var(--lm-gap) * 2 + var(--lm-hrow));
  position: fixed; inset: 0; overflow: hidden;
  display: grid; grid-template-columns: minmax(0, 1fr); grid-template-rows: 42px var(--lm-hrow) 1fr auto auto; row-gap: var(--lm-gap);
  padding: calc(var(--lm-pt) + env(safe-area-inset-top, 0px)) 24px max(40px, calc(env(safe-area-inset-bottom, 0px) + 16px));
  font-family: var(--sans); color: var(--login-black); background: transparent;
  -webkit-tap-highlight-color: transparent;
}
/* v0.40.1 (Max: "the very top of the page where the battery and service info is, is white"): Safari colours the status bar from the
   page's full-screen fixed layer and the page behind it - which were the grey ground. The ground is now its own layer starting
   under the sheet's rounded edge, the fixed page is see-through, and behind it the page is black - so the status bar reads the
   black the sheet is. */
html:has(.lm), body.login-page:has(.lm) { background: var(--login-black); }
/* v0.40.2 (Max, on his iPhone: "the bottom of the page under the url has white when the page first loads. then the page looks weird
   when I open the keyboard"). What Safari 26 actually does: it colours each of its bars from a position:FIXED element at that edge of
   the screen spanning at least 80% of the width - its background-color - and only without one from the page's background. It ignores
   absolutely positioned children, which the sheet, the ground and the curtain were - so the top fell back to the page (black, right by
   luck) and so did the band above the keyboard (black, wrong). They are fixed elements now: the black sheet is the top edge, the grey
   ground runs to the bottom of the screen (behind the keyboard too), and the curtain - full-screen black while the page arrives or
   leaves - is both edges until it pulls back. While typing they follow the visible part (--lm-vt). On its side the side sheet is
   too narrow to count, so there the page behind is grey. */
html:has(.lm.land), body.login-page:has(.lm.land) { background: var(--login-grey); }
.lm-ground { position: fixed; z-index: 0; left: 0; right: 0; bottom: 0; top: calc(var(--lm-vt, 0px) + var(--lm-sheet-h) - 28px); background: var(--login-grey); pointer-events: none; transition: top .4s cubic-bezier(.2, .8, .2, 1), left .4s cubic-bezier(.2, .8, .2, 1); }
.lm-sheet, .lm-curtain { position: fixed; background: var(--login-black); border-radius: 0 0 28px 28px; }
.lm-sheet { z-index: 0; left: 0; right: 0; top: var(--lm-vt, 0px); height: var(--lm-sheet-h); transition: height .4s cubic-bezier(.2, .8, .2, 1); }
.lm-curtain { z-index: 1; left: -2px; right: -2px; top: calc(var(--lm-vt, 0px) - 2px); height: 0; pointer-events: none; }
.lm-logo, .lm-head-wrap, .lm-fields, .lm-cta { position: relative; z-index: 2; }
.lm-logo { justify-self: center; align-self: start; display: block; height: 42px; width: auto; max-width: 100%; }

.lm-head-wrap { align-self: end; overflow: hidden; padding-bottom: .1em; margin-bottom: -.1em; font-size: var(--lm-head); }
.lm-head { margin: 0; font-size: inherit; font-weight: 900; line-height: .88; letter-spacing: -.04em; color: var(--login-grey); }
.lm-period { display: inline-block; width: .17em; height: .17em; margin-left: .06em; background: currentColor; animation: lg-blink 1.1s steps(1) infinite; }

.lm-fields { display: flex; flex-direction: column; }
.lm-row { display: grid; grid-template-columns: 100px minmax(0, 1fr); align-items: center; }
.lm-row.pw { grid-template-columns: 100px minmax(0, 1fr) auto; }
.lm-label { font-size: 11px; font-weight: 400; line-height: 1.2; letter-spacing: .14em; text-transform: uppercase; color: var(--login-black); }
.lm-input {
  width: 100%; min-width: 0; margin: 0; padding: 20px 0; border: 0; border-radius: 0; outline: none; background: transparent; -webkit-appearance: none; appearance: none;
  font-family: var(--sans); font-size: 18px; font-weight: 400; line-height: 1.2; color: var(--login-black); caret-color: var(--login-black);
}
.lm-input::placeholder { color: var(--login-placeholder); opacity: 1; }
.lm-input:focus, .lm-input:focus-visible { outline: none; }
.lm-input:-webkit-autofill, .lm-input:-webkit-autofill:hover, .lm-input:-webkit-autofill:focus {
  -webkit-text-fill-color: var(--login-black); box-shadow: 0 0 0 1000px var(--login-grey) inset; transition: background-color 600000s 0s;
}
.lm ::selection { background: var(--login-black); color: var(--login-grey); }
.lm-err { margin: -8px 0 10px 100px; font-size: 14px; line-height: 1.35; color: var(--login-black); }

/* Continue: 64px, a 48px dot 8px in, a 120px line that runs out of it while pressed */
.lm-btn {
  position: relative; display: flex; align-items: center; width: 100%; height: 64px; margin: 0; padding: 0 24px; border: 0; border-radius: 999px; overflow: hidden;
  background: var(--login-black); color: var(--login-grey); text-align: left; cursor: pointer; -webkit-appearance: none; appearance: none;
  font-family: var(--sans); font-size: 18px; font-weight: 700; line-height: 1.2;
  transition: transform .35s cubic-bezier(.34, 1.56, .64, 1);
}
.lm-btn.press { transform: scale(.97); }
.lm-btn-label { position: relative; z-index: 2; transition: opacity .3s ease; }
.lm-dot, .lm-arrow { position: absolute; right: 8px; top: 8px; width: 48px; height: 48px; }
.lm-dot { border-radius: 50%; background: var(--login-grey); }
.lm-arrow { z-index: 2; display: flex; align-items: center; justify-content: center; color: var(--login-grey); mix-blend-mode: difference; pointer-events: none; transition: transform .4s cubic-bezier(.7, 0, .2, 1), opacity .3s ease; }
.lm-arrow-box { position: relative; display: block; width: 14px; height: 18px; }
.lm-arrow svg { position: absolute; right: 0; top: -.5px; overflow: visible; }
.lm-arrow line { transform-box: fill-box; transform-origin: right center; transform: scaleX(0); transition: transform .6s cubic-bezier(.7, 0, .2, 1); }
.lm-btn.press .lm-arrow line, .lm-btn.go .lm-arrow line { transform: scaleX(1); }
.lm-btn.go .lm-btn-label { opacity: 0; }
.lm-btn.go .lm-arrow { transform: translateX(160px); opacity: 0; transition: transform .5s cubic-bezier(.6, 0, .9, .5) .15s, opacity .25s ease .35s; }
.lm-btn:focus-visible { outline: 2px solid var(--login-black); outline-offset: 4px; }

/* typing: the keyboard is up - the heading shrinks to .55, the sheet to the logo and heading, the form sits above the keyboard.
   v0.40.1 (Max: "the second I press the email or password field it messes up the whole page"): iOS Safari does not shrink the page
   for its keyboard - it slides the visible part (the visual viewport) up over it. The page had stayed on the whole screen AND been
   padded up by the keyboard's height, so the two moves fought. Now, while typing, the page IS the visible part: login-phone.js
   copies the visual viewport's top and height into --lm-vt / --lm-vh as the keyboard moves, and the layout fits that. */
.lm.kb { --lm-pt: 16px; --lm-gap: 22px; --lm-head: calc(104px * .55); --lm-sheet-h: calc(env(safe-area-inset-top, 0px) + var(--lm-pt) + 182px);
  top: var(--lm-vt, 0px); bottom: auto; height: var(--lm-vh, 100%); overflow-y: auto; overscroll-behavior: contain;
  grid-template-rows: auto auto 1fr auto auto; padding-bottom: 20px; }
/* ...and a phone browser leaves little above the keyboard (about 320 of an iPhone's 664 upright - the design was drawn for 508):
   when the visible part is under 470 tall, the heading steps aside for the form, the sheet becomes a band behind the logo */
.lm.kb.tight { --lm-pt: 14px; --lm-gap: 14px; --lm-sheet-h: calc(env(safe-area-inset-top, 0px) + 14px + 30px + 14px); grid-template-rows: 30px 1fr auto auto; padding-bottom: 14px; }
.lm.kb.tight .lm-logo { height: 30px; }
.lm.kb.tight .lm-head-wrap { display: none; }
.lm.kb.tight .lm-input { padding: 12px 0; }

/* the bar loader: 8 bars across the screen, each two halves fading in toward the middle; taller than the screen so they run off it */
.lm-loader { position: fixed; z-index: 45; left: 0; right: 0; top: 50%; height: 980px; transform: translateY(-50%); display: flex; gap: 8px; pointer-events: none; opacity: 1; transition: opacity .35s ease; }
.lm-loader.gone { opacity: 0; }
.lm-bar { flex: 1 1 0; display: flex; flex-direction: column; transform: scaleY(1); }
.lm-half { flex: 1 1 0; transform: scaleY(0); }
.lm-half.top { transform-origin: top; background: linear-gradient(to bottom, var(--lm-fade)); }
.lm-half.bot { transform-origin: bottom; background: linear-gradient(to top, var(--lm-fade)); }
.lm-loader {
  --lm-fade: color-mix(in srgb, var(--login-grey) 0%, transparent) 0%, color-mix(in srgb, var(--login-grey) 0%, transparent) 40%,
    color-mix(in srgb, var(--login-grey) 3%, transparent) 55%, color-mix(in srgb, var(--login-grey) 10%, transparent) 65%,
    color-mix(in srgb, var(--login-grey) 25%, transparent) 75%, color-mix(in srgb, var(--login-grey) 50%, transparent) 85%,
    color-mix(in srgb, var(--login-grey) 80%, transparent) 93%, var(--login-grey) 100%;
}
.lm-loader.in .lm-half { transform: scaleY(1); }
.lm-loader.out .lm-bar { transform: scaleY(.002); }
@keyframes lm-flash { 0% { opacity: 0; animation-timing-function: steps(1, end); } 2% { opacity: 1; animation-timing-function: cubic-bezier(.25, .6, .35, 1); } 70%, 100% { opacity: 0; } }

/* shorter phones (a phone browser with its bars, an iPhone SE): less air at the top and between, a smaller heading */
@media (max-height: 760px) { .lm { --lm-pt: 44px; --lm-gap: 26px; --lm-hrow: 200px; } }
@media (max-height: 640px) { .lm { --lm-pt: 32px; --lm-gap: 20px; --lm-hrow: 150px; --lm-head: 80px; } }

/* ================================================================================================================================
   v0.40.0 (Max: "do the landscape iphone version next and the animation for when it goes from portrait to landscape" - the
   Landscape and Rotation handoffs). A phone on its side (.lm.land, set by login-phone.js): the black sheet is a SIDE sheet on the
   left holding the logo (top left, 32px) and the heading (92px), the form on the grey to the right, Continue under it. 56px sides
   clear the notch. On the 844 x 390 artboard the left column is 340 and the gap 84; a narrower phone (an SE is 667 wide) scales
   both so the form keeps room. The sheet is 28px wider than the column. The curtain slides sideways instead of up.
   ================================================================================================================================ */
.lm-spacer { min-height: 0; }
.lm.land {
  --lm-lpad: max(56px, calc(env(safe-area-inset-left, 0px) + 16px)); --lm-rpad: max(56px, calc(env(safe-area-inset-right, 0px) + 16px));
  --lm-lcol: clamp(220px, 40.3vw, 340px); --lm-cgap: clamp(32px, 10vw, 84px); --lm-head: 92px;
  grid-template-columns: var(--lm-lcol) minmax(0, 1fr); grid-template-rows: auto 1fr auto;
  grid-template-areas: "logo fields" "head fields" "head cta";
  column-gap: var(--lm-cgap); row-gap: 20px;
  padding: max(28px, env(safe-area-inset-top, 0px)) var(--lm-rpad) max(28px, calc(env(safe-area-inset-bottom, 0px) + 8px)) var(--lm-lpad);
}
.lm.land .lm-spacer { display: none; }
.lm.land .lm-logo { grid-area: logo; justify-self: start; height: 32px; }
.lm.land .lm-head-wrap { grid-area: head; }
.lm.land .lm-fields { grid-area: fields; align-self: end; }
.lm.land .lm-cta { grid-area: cta; }
.lm.land { --lm-sheet-w: calc(var(--lm-lpad) + var(--lm-lcol) + 28px); }
.lm.land .lm-sheet { right: auto; bottom: 0; height: auto; width: var(--lm-sheet-w); border-radius: 0 28px 28px 0; transition: width .4s cubic-bezier(.2, .8, .2, 1); }
.lm.land .lm-ground { top: var(--lm-vt, 0px); left: calc(var(--lm-sheet-w) - 28px); }
.lm.land .lm-curtain { right: auto; bottom: -2px; height: auto; width: 0; border-radius: 0 28px 28px 0; }
/* the keyboard up on its side (about 200 of 390): a narrower sheet, a 62px heading, tighter rows, the form 6px above the keys */
.lm.land.kb { --lm-lcol: 150px; --lm-cgap: 48px; --lm-head: 62px; --lm-sheet-w: calc(var(--lm-lpad) + 174px); grid-template-rows: auto 1fr auto; row-gap: 8px; padding-bottom: 6px; }
.lm.land.kb .lm-input { padding: 10px 0; }
.lm.land.kb .lm-sheet { height: auto; width: var(--lm-sheet-w); }
/* on its side with the keyboard up a phone browser shows a strip (well under 300 tall): only the form, scrolling if it must */
.lm.land.kb.tight { grid-template-columns: minmax(0, 1fr); grid-template-areas: "fields" "cta"; grid-template-rows: auto auto; align-content: safe end; row-gap: 8px; padding-top: 8px; padding-bottom: 8px; }
/* safe end: sitting on the keyboard when it fits; when it does not, from the top and scrolling - never pushed off the top out of reach */
.lm.land.kb.tight .lm-input { padding: 8px 0; }
.lm.land.kb.tight .lm-sheet, .lm.land.kb.tight .lm-logo, .lm.land.kb.tight .lm-head-wrap { display: none; }
.lm.land.kb.tight .lm-ground { left: 0; }
/* a short landscape phone (an SE in a browser): a smaller heading and rows, so the side column and the form both fit */
@media (orientation: landscape) and (max-height: 300px) { .lm.land { --lm-head: 72px; row-gap: 14px; } .lm.land .lm-input { padding: 14px 0; } }
/* a small phone on its side (under 700 wide: the SE class, which has no notch): 28px sides and an 80px label column, so the email
   field keeps a usable width (it was 70px at 568) */
@media (orientation: landscape) and (max-width: 700px) {
  .lm.land { --lm-lpad: max(28px, env(safe-area-inset-left, 0px)); --lm-rpad: max(28px, env(safe-area-inset-right, 0px)); }
  .lm.land .lm-row { grid-template-columns: 80px minmax(0, 1fr); }
  .lm.land .lm-row.pw { grid-template-columns: 80px minmax(0, 1fr) auto; }
  .lm.land .lm-err { margin-left: 80px; }
}

/* the curtain held over the whole screen - while the loader runs through a rotation */
.lm .lm-curtain.cover, .lm.land .lm-curtain.cover { top: -2px; left: -2px; right: -2px; bottom: -2px; width: auto; height: auto; border-radius: 0; }
/* the rotation: the screen dips to black over the old layout, the new one comes in under it already in its intro's first frame */
.lm-veil { position: fixed; inset: 0; z-index: 60; background: var(--login-black); opacity: 0; pointer-events: none; display: none; }
/* v0.40.2: NOT IN THE PAGE unless a turn is under way. Safari 26 colours its bars from any full-width fixed element at the edge and
   reads its background-color whatever its opacity - an invisible black veil made both bars black (the band above the keyboard) */
.lm-veil.on { display: block; }

@media (prefers-reduced-motion: reduce) {
  .lm-period { animation: none; }
  .lm-sheet, .lm-btn, .lm-btn-label, .lm-arrow, .lm-arrow line { transition: none; }
}
