/*------------------------------------------------------------------------------
    Login page (v3) — product showcase + quiet sign-in column
--------------------------------------------------------------------------------
    Loaded ONLY by resources/views/auth/login.blade.php.

    Deliberately a NEW file rather than an edit of pages/login.css: that file is
    still linked by auth/passwords/reset.blade.php (and carries `.login-bg`,
    the centred-card `#login-page` and `.login-brand`), all of which would
    fight this layout. login.blade.php no longer links it.

    Everything is scoped under `#login-page` for one reason: the page loads the
    full Materialize theme (panels/styles.blade.php), which styles bare
    `input[type=email]`, `button`, `label`, `p` and `h1`-`h6`, and hides native
    checkboxes. The scope both wins the cascade (an id beats any number of
    theme classes) and guarantees nothing here leaks into the rest of the app.

    Design source of truth: DESIGN.md + the approved v3 mockup
    (public/_preview-login.html in the main checkout).

    Gradients are sanctioned in exactly three places, all approved:
      1. the 3px red→gold brand stripe (the one DESIGN.md already allows)
      2. the same red→gold ramp restated as the 52px bar under the page title
      3. the aurora wash behind the product screenshot — a marketing surface,
         not a content area
    Everything else stays flat. The submit button in particular is flat --red
    per the "no gradient-filled buttons" anti-pattern; its box-shadow is a
    lift, not a fill.

    Where the mockup and DESIGN.md disagree, DESIGN.md wins and the deviation
    is commented at the rule: input/button radius (mockup drifted 8px→9px,
    system value is --radius-md 6px) and the muted text colours (mockup used
    --text-xmuted, which fails 4.5:1 on white).
------------------------------------------------------------------------------*/

#login-page {
  /* DESIGN.md tokens, scoped rather than :root so this page cannot redefine
     anything for the app chrome. --font-body matches the global definition. */
  --red: #C8282E;
  --red-hover: #A8201F;
  --red-light: #FFF0F0;
  --gold: #C9922A;
  --navy: #0F1B2D;
  --surface: #FFFFFF;
  --text-primary: #1A1A1A;
  --text-muted: #5A6478;
  --text-xmuted: #8A93A6;
  --border: #DDE1EA;
  --border-strong: #BCC3D0;
  --font-body: 'DM Sans', 'Noto Sans SC', 'PingFang SC', 'Microsoft YaHei', system-ui, sans-serif;
  --radius-sm: 3px;
  --radius-md: 6px;
  --radius-lg: 8px;

  /* --- Full-bleed break-out ---------------------------------------------
     fullLayoutMaster wraps @yield('content') in
       body > .row > .col.s12 > .container
     and Materialize's .container is width:90%;max-width:1280px while .row
     adds negative side margins and a 20px bottom margin. A split screen has
     to ignore all three, so the page is taken out of flow entirely and
     pinned to the viewport. Long-hand offsets rather than `inset` for
     older-Safari safety.

     The parents are then left holding nothing, so the document itself never
     scrolls — this element is the only scroller (overflow:auto), which is
     also why there is no double scrollbar.

     z-index:1 keeps it above .content-overlay (theme, z-index:-1 when idle). */
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  z-index: 1;
  overflow: auto;
  -webkit-overflow-scrolling: touch;

  display: flex;
  flex-direction: column;
  /* Explicit, because pages/login.css historically set justify/align:center on
     this same id — if it is ever linked again, this still lays out correctly. */
  justify-content: flex-start;
  align-items: stretch;
  height: auto;

  /* Installed boss app (PWA) draws edge-to-edge under the status bar
     (viewport-fit=cover + black-translucent in the layout head). Padding the
     shell keeps the brand stripe out from under the clock; the navy
     background paints the strip itself, matching <meta name="theme-color">.
     Resolves to 0px everywhere else, so this is a no-op in a browser. */
  padding-top: env(safe-area-inset-top, 0px);
  background: var(--navy);

  font-family: var(--font-body);
  color: var(--text-primary);
  text-align: left;
}

/* Materialize sets border-box globally, but its text-input rule flips inputs
   back to content-box. Re-assert it for the whole subtree so the 100%-wide
   inputs keep their padding inside the box. */
#login-page,
#login-page *,
#login-page *::before,
#login-page *::after {
  box-sizing: border-box;
}

/* Brand signature — the same 3px red→gold stripe the app header carries. */
#login-page .brand-stripe {
  flex: none;
  height: 3px;
  background: linear-gradient(90deg, var(--red), var(--gold));
}

/* flex:1 0 auto — grows to fill a tall viewport, and refuses to shrink below
   its content on a short one (that overflow is what #login-page scrolls). */
#login-page .login-split {
  display: flex;
  flex: 1 0 auto;
  align-items: stretch;
}

/* ---------- Left: product showcase ---------- */

#login-page .showcase {
  flex: 1;
  /* Without this a flex item refuses to shrink past its content's min-content
     width, which is what puts a horizontal scrollbar on a narrow desktop. */
  min-width: 0;
  position: relative;
  /* Clips the aurora's -20% overhang and the dashed rings at the panel edge.
     The chips hang only ~34px past the card, and the padding below is far
     wider than that, so nothing real is ever cut. */
  overflow: hidden;
  background: #FBF8F3;
  display: flex;
  align-items: center;
  justify-content: center;
  /* Deeper bottom pad reserves the band the proof pill sits in. */
  padding: 72px 64px 96px;
}

/* --- Backdrop -----------------------------------------------------------
   Brand aurora: four soft radial glows in red/gold/navy over the warm base,
   plus a second multiply layer for depth. Oversized by 20% on every side so
   the slow drift never exposes a hard edge. Long-hand offsets rather than
   `inset` for the same older-Safari reason as #login-page itself. */
#login-page .aurora {
  position: absolute;
  top: -20%;
  right: -20%;
  bottom: -20%;
  left: -20%;
  pointer-events: none;
}

#login-page .aurora::before,
#login-page .aurora::after {
  content: "";
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  background:
    radial-gradient(42% 38% at 18% 22%, rgba(200, 40, 46, .14), transparent 70%),
    radial-gradient(50% 44% at 85% 78%, rgba(201, 146, 42, .20), transparent 72%),
    radial-gradient(30% 30% at 70% 12%, rgba(201, 146, 42, .10), transparent 70%),
    radial-gradient(26% 26% at 8% 85%, rgba(15, 27, 45, .06), transparent 70%);
}

#login-page .aurora::after {
  background:
    radial-gradient(36% 32% at 75% 30%, rgba(200, 40, 46, .07), transparent 70%),
    radial-gradient(40% 36% at 25% 70%, rgba(201, 146, 42, .10), transparent 72%);
  mix-blend-mode: multiply;
}

/* Fine dot grid — the cockpit's grid discipline, faded out toward the edges
   by the radial mask so it never fights the aurora or the card shadow.
   An unsupported mask degrades to a full-bleed dot field, which is still a
   legitimate backdrop, so this is deliberately NOT behind @supports. */
#login-page .dots {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  pointer-events: none;
  background-image: radial-gradient(rgba(15, 27, 45, .075) 1px, transparent 1px);
  background-size: 20px 20px;
  -webkit-mask-image: radial-gradient(70% 70% at 50% 45%, #000 30%, transparent 100%);
  mask-image: radial-gradient(70% 70% at 50% 45%, #000 30%, transparent 100%);
}

/* Structural, not decorative-blob: two thin dashed rings that echo the
   cockpit's dial/gauge language. */
#login-page .deco-circle {
  position: absolute;
  border: 1.5px dashed rgba(15, 27, 45, .14);
  border-radius: 50%;
  pointer-events: none;
}

#login-page .deco-circle.c1 {
  width: 560px;
  height: 560px;
  top: 4%;
  right: 2%;
}

#login-page .deco-circle.c2 {
  width: 320px;
  height: 320px;
  bottom: 6%;
  left: 3%;
}

/* --- Composition --------------------------------------------------------
   Wrapper whose only jobs are to size the card and to be the positioning
   context for the chips. It must NOT get overflow:hidden — the chips are
   deliberately outside its box on all four corners. */
#login-page .composition {
  position: relative;
  width: min(820px, 94%);
}

/* The screenshot, framed as a browser window and lifted off the wash by a
   long soft shadow rather than a heavy border. */
#login-page .shot-card {
  position: relative;
  border-radius: 16px;
  overflow: hidden;
  border: 1px solid rgba(15, 27, 45, .10);
  background: var(--surface);
  box-shadow:
    0 40px 90px -20px rgba(15, 27, 45, .28),
    0 8px 28px rgba(15, 27, 45, .10);
}

#login-page .browser-bar {
  height: 40px;
  background: var(--surface-2);
  border-bottom: 1px solid var(--border);
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 0 16px;
}

#login-page .traffic {
  display: flex;
  gap: 7px;
}

#login-page .traffic span {
  width: 11px;
  height: 11px;
  border-radius: 50%;
  background: #E3E7EF;
}

/* Desaturated brand tints rather than literal macOS colours — the green in
   particular is the only non-palette hue, kept muted so it reads as chrome. */
#login-page .traffic span:nth-child(1) { background: #F4B8B8; }
#login-page .traffic span:nth-child(2) { background: #F2D9A4; }
#login-page .traffic span:nth-child(3) { background: #B9DDC6; }

#login-page .url-pill {
  flex: none;
  margin: 0 auto;
  height: 24px;
  min-width: 300px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 999px;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 7px;
  padding: 0 14px;
  font-size: 12px;
  font-weight: 500;
  color: var(--text-muted);
  white-space: nowrap;
}

#login-page .url-pill svg {
  flex: none;
  width: 11px;
  height: 11px;
  stroke: var(--success);
  fill: none;
}

/* Mirrors the traffic-light cluster's width so the pill centres optically. */
#login-page .bar-spacer {
  flex: none;
  width: 47px;
}

/* <picture> is an inline element by default, and an inline box wrapping a
   display:block child is a layout the browser has to invent an answer for —
   here it left a baseline gap under the screenshot inside the card's rounded
   clip. The wrapper carries no styling of its own; it only needs to be a
   block so .shot-img sizes against .shot-card exactly as it did when the
   <img> was .shot-card's direct child. */
#login-page .shot-card picture {
  display: block;
}

/* The asset is 2000x1333; at 16/10 `cover` trims a sliver off the bottom,
   which is why the origin is pinned top-left — the cockpit's KPI row and
   overdue table stay in frame. */
#login-page .shot-img {
  display: block;
  width: 100%;
  /* height:auto is load-bearing since the <img> gained width/height
     attributes. Those attributes map to presentational CSS hints, and while
     `width: 100%` above overrides the width hint, nothing was overriding the
     HEIGHT hint — so `height: 513px` won outright and beat aspect-ratio.
     Measured in the browser: the box came out 780x513 (1.52) instead of
     780x487 (1.60). object-fit:cover meant it read as a slightly different
     crop rather than a stretch, which is exactly the kind of wrong that
     survives a glance at a screenshot. */
  height: auto;
  aspect-ratio: 16 / 10;
  object-fit: cover;
  object-position: top left;
}

/* --- Glass chips --------------------------------------------------------
   The two numbers the cockpit exists to surface, shown as live UI rather
   than described in a bullet. The rgba(255,255,255,.86) base is opaque
   enough to carry the text on its own, so where backdrop-filter is
   unsupported these degrade to plain frosted cards — no @supports gate,
   because there is no fallback to switch to.

   HEAVY override: `.chip` is a real Materialize COMPONENT
   (materialize.css:5463), not just a name collision —
     display:inline-block; height:32px; line-height:32px; font-size:13px;
     font-weight:500; color:rgba(0,0,0,.6); padding:0 12px;
     border-radius:16px; background-color:#e4e4e4;
     margin-bottom:5px; margin-right:5px
   Left alone, `height:32px` + `line-height:32px` collapse the chip to a
   single grey 32px bar with the value and sub-line spilling out below it
   (seen in the browser before this rule existed). Every one of those
   declarations is restated. */
#login-page .chip {
  position: absolute;
  display: block;
  height: auto;
  line-height: 1.4;
  margin: 0;
  border-radius: 13px;
  padding: 14px 18px;
  font-size: 13px;
  font-weight: 400;
  color: var(--text-primary);
  background: rgba(255, 255, 255, .86);
  -webkit-backdrop-filter: blur(14px);
  backdrop-filter: blur(14px);
  border: 1px solid rgba(255, 255, 255, .65);
  box-shadow:
    0 16px 40px -8px rgba(15, 27, 45, .25),
    0 2px 8px rgba(15, 27, 45, .08);
}

/* line-height is restated on each child too: Materialize's 32px value is set
   on .chip itself, and any child that does not declare its own would inherit
   a 32px line box and blow the chip's height back out. */
#login-page .chip .chip-label {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 11px;
  line-height: 1.4;
  font-weight: 600;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--text-muted);
}

#login-page .chip .chip-label .dot {
  flex: none;
  width: 7px;
  height: 7px;
  border-radius: 50%;
}

#login-page .chip .chip-value {
  margin-top: 5px;
  font-size: 21px;
  line-height: 1.25;
  font-weight: 700;
  letter-spacing: -.01em;
  /* DESIGN.md "Data / Tables" — money lines up digit-for-digit. */
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum";
}

#login-page .chip .chip-sub {
  margin-top: 2px;
  font-size: 11.5px;
  line-height: 1.45;
  color: var(--text-muted);
}

#login-page .chip.money {
  top: -26px;
  right: -30px;
}

#login-page .chip.money .chip-label .dot { background: var(--gold); }
#login-page .chip.money .chip-value { color: var(--text-primary); }
#login-page .chip.money .chip-value .cur { color: var(--gold); }

#login-page .chip.act {
  bottom: -24px;
  left: -34px;
  padding: 13px 16px;
}

#login-page .chip.act .act-pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  background: var(--red);
  color: #fff;
  font-size: 10.5px;
  line-height: 1.4;
  font-weight: 700;
  letter-spacing: .08em;
  padding: 3px 9px;
  border-radius: 999px;
}

#login-page .chip.act .chip-sub {
  margin-top: 7px;
  font-size: 12.5px;
  font-weight: 500;
  color: var(--text-primary);
}

/* materialize.css:2273 sets `b, strong { font-weight: bolder }`, which
   resolves against the parent's 500 and lands somewhere browser-dependent.
   Pinned to 700 so the amount reads the same everywhere. */
#login-page .chip.act .chip-sub b {
  font-weight: 700;
  color: var(--red);
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum";
}

/* --- Proof pill ---------------------------------------------------------- */

#login-page .proof-line {
  position: absolute;
  left: 44px;
  bottom: 26px;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 18px;
  background: rgba(255, 255, 255, .72);
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
  border: 1px solid rgba(255, 255, 255, .6);
  border-radius: 999px;
  box-shadow: 0 8px 24px -6px rgba(15, 27, 45, .12);
  font-size: 13px;
  font-weight: 500;
  line-height: 1.5;
  /* 5.6:1 on the wash. The mockup's --text-xmuted would be 2.9:1. */
  color: var(--text-muted);
}

#login-page .proof-line .num {
  color: var(--red);
  font-weight: 700;
  font-size: 15px;
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum";
}

/* ---------- Right: sign-in column ---------- */

#login-page .auth {
  flex: none;
  width: 480px;
  background: var(--surface);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 48px 40px calc(48px + env(safe-area-inset-bottom, 0px));
}

#login-page .auth-box {
  width: 100%;
  max-width: 356px;
}

#login-page .brand-lockup {
  display: flex;
  align-items: center;
  gap: 7px;
  margin-bottom: 44px;
}

#login-page .brand-lockup .brand-word {
  font-size: 22px;
  font-weight: 700;
  line-height: 1.2;
  letter-spacing: -.01em;
  color: var(--text-primary);
}

#login-page .brand-lockup .brand-accent {
  color: var(--red);
}

/* No white backing tile here (v1 needed one on navy) — the mark is drawn for
   a light surface and this column is white. */
#login-page .brand-lockup img {
  display: block;
  flex: none;
  height: 34px;
  width: auto;
}

/* Materialize gives h1 4.2rem / weight 400 / 2.8rem margins; every one of
   those is restated. */
#login-page .auth-title {
  margin: 0;
  font-size: 27px;
  font-weight: 700;
  line-height: 1.3;
  letter-spacing: -.01em;
  color: var(--text-primary);
}

/* The brand stripe restated at heading scale — the second sanctioned
   gradient, same red→gold ramp as the 3px bar at the top of the page. */
#login-page .title-accent {
  display: block;
  width: 52px;
  height: 3px;
  margin-top: 10px;
  border-radius: 2px;
  background: linear-gradient(90deg, var(--red), var(--gold));
}

#login-page .auth-sub {
  margin: 14px 0 0;
  font-size: 14.5px;
  font-weight: 400;
  line-height: 1.6;
  color: var(--text-muted);
}

/* The promise in Chinese carries the weight; the English is the gloss. */
#login-page .auth-sub .zh {
  color: var(--red);
  font-weight: 500;
}

#login-page .fields {
  margin: 34px 0 0;
  display: flex;
  flex-direction: column;
  gap: 20px;
}

#login-page .field {
  margin: 0;
}

/* Materialize styles bare `label` at .8rem/#9e9e9e — overridden here, and the
   floating-label machinery never engages because this markup deliberately
   avoids .input-field. */
#login-page .field > label {
  display: block;
  font-size: 13px;
  font-weight: 600;
  line-height: 1.4;
  margin-bottom: 7px;
  color: var(--text-primary);
  transform: none;
  position: static;
}

/* Mockup used --text-xmuted here; #8A93A6 on white is 2.9:1, which fails the
   4.5:1 floor for real text. --text-muted (#5A6478) is 5.9:1 and reads the
   same at a glance. */
#login-page .field > label .en {
  color: var(--text-muted);
  font-weight: 500;
  margin-left: 6px;
}

#login-page .input-wrap {
  position: relative;
}

/* --- Materialize input override -----------------------------------------
   materialize.css:5613 gives every text input:
     background:transparent; border:none; border-bottom:1px solid #9e9e9e;
     border-radius:0; height:3rem; margin:0 0 8px; padding:0;
     box-shadow:none; box-sizing:content-box; transition:box-shadow .3s,border .3s
   and :focus adds `border-bottom:1px solid #ff4081; box-shadow:0 1px 0 0 #ff4081`
   (the theme's pink, which is off-palette). Every one of those declarations is
   restated below so the bordered box wins outright — the id makes this
   (1,1,1) against Materialize's (0,2,1).

   v2 drops v1's inner leading icon, so the left pad is back to the plain 14px. */
#login-page .input-wrap input {
  width: 100%;
  height: 45px;
  box-sizing: border-box;
  border: 1px solid var(--border);
  /* DESIGN.md radius-md is the token for inputs and buttons. The mockup drew
     8px (v2) then 9px (v3); both were drift, the system value wins. */
  border-radius: var(--radius-md);
  padding: 0 14px;
  margin: 0;
  background-color: var(--surface);
  box-shadow: none;
  outline: none;
  font-family: var(--font-body);
  font-size: 15px;
  line-height: normal;
  color: var(--text-primary);
  transition: border-color .15s ease-out, box-shadow .15s ease-out;
}

/* Room for the eye button so a long password never runs under it. */
#login-page .input-wrap input.has-toggle {
  padding-right: 46px;
}

#login-page .input-wrap input::placeholder {
  color: var(--text-xmuted);
  opacity: 1;
}

/* Materialize has no hover state on inputs, so this is purely additive —
   but it is still restated inside the id scope to sit at the same
   specificity as the base rule it has to beat. */
#login-page .input-wrap input:hover {
  border-color: var(--border-strong);
}

#login-page .input-wrap input:focus,
#login-page .input-wrap input:focus:not([readonly]) {
  border: 1px solid var(--red);
  box-shadow: 0 0 0 3.5px var(--red-light);
}

/* Chrome's autofill paints its own background + inset shadow. The 1000px inset
   spread repaints it white; the focus rule re-adds the ring on top. */
#login-page .input-wrap input:-webkit-autofill,
#login-page .input-wrap input:-webkit-autofill:hover,
#login-page .input-wrap input:-webkit-autofill:focus {
  -webkit-text-fill-color: var(--text-primary);
  -webkit-box-shadow: 0 0 0 1000px var(--surface) inset;
  box-shadow: 0 0 0 1000px var(--surface) inset;
}

#login-page .input-wrap input:-webkit-autofill:focus {
  -webkit-box-shadow: 0 0 0 3.5px var(--red-light), 0 0 0 1000px var(--surface) inset;
  box-shadow: 0 0 0 3.5px var(--red-light), 0 0 0 1000px var(--surface) inset;
}

/* Server-side validation failure (@error) — border echoes the message colour. */
#login-page .input-wrap input.is-invalid {
  border-color: var(--red);
}

#login-page .field-error {
  display: block;
  margin: 6px 0 0;
  font-size: 12.5px;
  line-height: 1.45;
  font-weight: 500;
  color: var(--red);
}

/* --- Password show/hide -------------------------------------------------
   A bare <button> inside the Materialize theme is NOT neutral:
     materialize.css:2371  button { font-family: sans-serif; font-size:100% }
     materialize.css:2411  button { -webkit-appearance: button }
     materialize.css:2587  button { font-family: "Muli", sans-serif }
     materialize.css:5589  button:focus { outline:none; background-color:#ff548e }
   That last one is the nasty one — without an override the eye button flashes
   the theme's pink the moment it is clicked or tabbed to. Everything below is
   an explicit reset, and the :focus background is restated so the pink can
   never win. Not styled as .btn anywhere, so the .btn ripple/uppercase/shadow
   rules are out of scope by construction. */
#login-page .pw-toggle {
  position: absolute;
  right: 5px;
  top: 50%;
  transform: translateY(-50%);
  width: 36px;
  height: 36px;
  padding: 0;
  margin: 0;
  border: 0;
  border-radius: var(--radius-md);
  background: none;
  box-shadow: none;
  -webkit-appearance: none;
  appearance: none;
  font-family: var(--font-body);
  line-height: normal;
  text-transform: none;
  cursor: pointer;
  color: var(--text-xmuted);
  display: flex;
  align-items: center;
  justify-content: center;
  transition: color .15s ease-out, background-color .15s ease-out;
}

/* Kills materialize.css:5589 `button:focus { background-color:#ff548e }`. */
#login-page .pw-toggle:hover,
#login-page .pw-toggle:focus,
#login-page .pw-toggle:active {
  background: none;
  box-shadow: none;
}

#login-page .pw-toggle:hover {
  color: var(--text-muted);
}

/* Materialize also blanks the focus ring (`outline:none` in the same rule), so
   keyboard users get it back here. */
#login-page .pw-toggle:focus-visible {
  outline: 2px solid var(--red);
  outline-offset: 1px;
  color: var(--text-muted);
}

#login-page .pw-toggle svg {
  display: block;
  width: 20px;
  height: 20px;
  stroke: currentColor;
  fill: none;
}

/* Icon states the aria-label already announces: plain eye = "will show",
   struck eye = "will hide". Class toggled by the page script. */
#login-page .pw-toggle .icon-eye-off,
#login-page .pw-toggle.is-revealed .icon-eye {
  display: none;
}

#login-page .pw-toggle.is-revealed .icon-eye-off {
  display: block;
}

#login-page .aux {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

/* --- Materialize checkbox override --------------------------------------
   materialize.css:6236 absolutely positions the native box at opacity:0 with
   pointer-events:none and rebuilds it out of the sibling <span>'s ::before
   (the box) and ::after. Its checked state turns ::before into a rotated
   two-border "tick" in the theme's pink. The mockup's `accent-color` on a
   native box therefore cannot work here — the native box is not painted at
   all. Keeping Materialize's markup (label > input + span) means the label
   click target still works; the pseudo elements below are re-specified from
   scratch:
     ::before = the 18px box, filled --red when checked
     ::after  = a white tick, scaled 0 → 1 when checked
   Each rule is id-scoped, so it beats even `[type=checkbox].tabbed:focus +
   span:not(.lever)::after` (0,4,2), which would otherwise force a grey ripple
   over the tick on keyboard focus. */
#login-page .remember {
  display: inline-flex;
  align-items: center;
  /* 44px touch target (DESIGN.md/a11y) around an 18px visual box. */
  min-height: 44px;
  cursor: pointer;
  user-select: none;
  margin: 0;
}

#login-page .remember [type="checkbox"] + span:not(.lever) {
  position: relative;
  display: inline-block;
  height: auto;
  line-height: 1.4;
  padding-left: 26px;
  font-size: 13.5px;
  font-weight: 400;
  color: var(--text-muted);
  cursor: pointer;
}

#login-page .remember [type="checkbox"] + span:not(.lever)::before {
  content: "";
  position: absolute;
  top: 50%;
  left: 0;
  margin-top: -9px;
  width: 18px;
  height: 18px;
  border: 1.5px solid var(--border-strong);
  border-radius: var(--radius-sm);
  background-color: var(--surface);
  transform: none;
  box-shadow: none;
  transition: background-color .15s ease-out, border-color .15s ease-out;
}

#login-page .remember [type="checkbox"]:checked + span:not(.lever)::before {
  top: 50%;
  left: 0;
  margin-top: -9px;
  width: 18px;
  height: 18px;
  border: 1.5px solid var(--red);
  border-radius: var(--radius-sm);
  background-color: var(--red);
  transform: none;
}

#login-page .remember [type="checkbox"] + span:not(.lever)::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 6px;
  margin-top: -6px;
  width: 6px;
  height: 10px;
  border: 0 solid #fff;
  border-right-width: 2px;
  border-bottom-width: 2px;
  border-radius: 0;
  background-color: transparent;
  box-shadow: none;
  transform: rotate(45deg) scale(0);
  transform-origin: center;
  transition: transform .15s ease-out;
}

#login-page .remember [type="checkbox"]:checked + span:not(.lever)::after {
  transform: rotate(45deg) scale(1);
}

/* The native input is invisible but still in the tab order, so the focus ring
   has to be drawn on the fake box. */
#login-page .remember [type="checkbox"]:focus-visible + span:not(.lever)::before {
  border-color: var(--red);
  box-shadow: 0 0 0 3px var(--red-light);
}

/* --- Submit ------------------------------------------------------------- */

#login-page .submit-btn {
  /* inline-flex, not block: the label and the arrow are two flow items now. */
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 9px;
  width: 100%;
  height: 47px;
  padding: 0;
  border: 0;
  border-radius: var(--radius-md);
  /* Flat --red. DESIGN.md: "Gradient-filled buttons (flat color only)".
     The shadow is a lift, not a fill — the surface stays one solid colour. */
  background-color: var(--red);
  color: #fff;
  font-family: var(--font-body);
  font-size: 15.5px;
  font-weight: 600;
  letter-spacing: .02em;
  text-transform: none;
  cursor: pointer;
  -webkit-appearance: none;
  appearance: none;
  box-shadow: 0 3px 14px rgba(200, 40, 46, .28);
  transition: background-color .15s ease-out, transform .15s ease-out, box-shadow .15s ease-out;
}

/* Scoped so Materialize's `button`/`.btn` theming cannot reach it, and so the
   `svg:not(:root){overflow:hidden}` normalize rule is the only thing the
   theme still contributes. fill:none is explicit because the paths are
   stroke-only — a UA default of fill:black would blot the arrowhead. */
#login-page .submit-btn svg {
  flex: none;
  width: 17px;
  height: 17px;
  stroke: #fff;
  fill: none;
  transition: transform .15s ease-out;
}

/* :focus is restated alongside :hover for the same reason as the eye button —
   materialize.css:5589 would otherwise paint it #ff548e. */
#login-page .submit-btn:hover,
#login-page .submit-btn:focus {
  background-color: var(--red-hover);
  box-shadow: 0 4px 18px rgba(200, 40, 46, .34);
}

#login-page .submit-btn:hover svg {
  transform: translateX(3px);
}

#login-page .submit-btn:active {
  transform: scale(.99);
}

#login-page .submit-btn:focus-visible {
  outline: 3px solid var(--red-light);
  outline-offset: 2px;
}

#login-page .foot {
  margin: 52px 0 0;
  font-size: 12px;
  line-height: 1.7;
  /* --text-xmuted in the mockup; raised to --text-muted for the 4.5:1 floor. */
  color: var(--text-muted);
  text-align: center;
}

/* ---------- Motion (minimal-functional) ---------- */
/* Every animated rule on this page lives inside this one guard, so under
   `prefers-reduced-motion: reduce` the block never applies: no drift, no bob,
   no entrance, and nothing is left stuck at opacity:0.

   Entrance is three beats, not a staggered list — v1's six-step cascade is
   exactly the "generic AI page" tell this redesign removed. */
@media (prefers-reduced-motion: no-preference) {
  /* Backdrop: a 14s breath, slow enough to register as depth rather than
     movement. Animating the wrapper (not the gradients) keeps it on the
     compositor. */
  #login-page .aurora {
    animation: sh-login-drift 14s ease-in-out infinite alternate;
  }

  @keyframes sh-login-drift {
    from { transform: translate3d(-1.5%, -1%, 0) scale(1); }
    to   { transform: translate3d(1.5%, 1.5%, 0) scale(1.04); }
  }

  /* Chips float on their own out-of-phase cycles so the pair never looks
     mechanically synced. */
  #login-page .chip.money {
    animation: sh-login-bob 6s ease-in-out infinite alternate;
  }

  #login-page .chip.act {
    animation: sh-login-bob 7s ease-in-out .8s infinite alternate;
  }

  @keyframes sh-login-bob {
    from { transform: translateY(-4px); }
    to   { transform: translateY(5px); }
  }

  /* Entrance. .composition (not .shot-card) carries the rise so the chips
     arrive with the card they belong to. */
  #login-page .composition {
    opacity: 0;
    transform: translateY(18px);
    animation: sh-login-rise .55s ease-out .05s forwards;
  }

  #login-page .proof-line {
    opacity: 0;
    animation: sh-login-fade .5s ease-out .5s forwards;
  }

  #login-page .auth-box {
    opacity: 0;
    transform: translateY(10px);
    animation: sh-login-rise .45s ease-out .15s forwards;
  }

  @keyframes sh-login-rise {
    to { opacity: 1; transform: none; }
  }

  @keyframes sh-login-fade {
    to { opacity: 1; }
  }
}

/* ---------- Responsive ---------- */

/* Below the point where the screenshot still reads as a screenshot, drop it
   entirely rather than shrinking it into an illegible smear. The sign-in
   column then owns the viewport. */
@media only screen and (max-width: 1060px) {
  #login-page .showcase {
    display: none;
  }
  #login-page .auth {
    flex: 1;
    width: auto;
  }
}

@media only screen and (max-width: 600px) {
  #login-page .auth {
    align-items: flex-start;
    padding: 40px 24px calc(40px + env(safe-area-inset-bottom, 0px));
  }
  /* Top-aligned rather than dead-centre: on a phone the keyboard eats the
     lower half as soon as the first field is focused. */
  #login-page .auth-box {
    margin-top: 7vh;
  }
}

/* ---------- v3.5: auth-column delight pass ----------
   Greeting pill, the 业绩在手 chop, submit loading morph, and a dashed arc
   echoing the showcase. Same scoping rules as everything above. */

#login-page .auth {
  position: relative;
  overflow: hidden;
}
/* dashed arc peeking in from the top-right — ties the two halves together */
#login-page .auth::before {
  content: "";
  position: absolute;
  top: -110px;
  right: -110px;
  width: 240px;
  height: 240px;
  border-radius: 50%;
  border: 1.5px dashed rgba(15, 27, 45, .12);
  pointer-events: none;
}
#login-page .auth-box {
  position: relative;
}

#login-page .greet {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 5px 13px;
  font-size: 12.5px;
  font-weight: 500;
  color: var(--text-muted);
  margin-bottom: 18px;
}
#login-page .greet svg {
  width: 14px;
  height: 14px;
  stroke: var(--gold);
  fill: none;
  flex: none;
}

/* 印章 — decorative chop; hidden on very narrow phones so it can never
   crowd the greeting pill. */
#login-page .seal {
  position: absolute;
  right: 2px;
  top: 66px;
  width: 62px;
  height: 62px;
  border: 2.5px solid rgba(200, 40, 46, .72);
  border-radius: 9px;
  color: rgba(200, 40, 46, .82);
  font-size: 16px;
  font-weight: 700;
  line-height: 1.25;
  text-align: center;
  display: grid;
  place-items: center;
  letter-spacing: .12em;
  transform: rotate(6deg);
  box-shadow: inset 0 0 10px rgba(200, 40, 46, .12);
  pointer-events: none;
  user-select: none;
}
@media (max-width: 380px) {
  #login-page .seal {
    display: none;
  }
}

/* loading morph: spinner replaces the arrow, button locks against
   double-submit. pointer-events + disabled (set a tick later in JS). */
#login-page .submit-btn .spinner {
  width: 17px;
  height: 17px;
  border-radius: 50%;
  flex: none;
  border: 2.5px solid rgba(255, 255, 255, .35);
  border-top-color: #fff;
  display: none;
}
#login-page .submit-btn.is-loading,
#login-page .submit-btn:disabled {
  pointer-events: none;
  background: var(--red-hover);
  color: #fff;
  opacity: 1; /* Materialize dims :disabled buttons; the label must stay readable */
}
#login-page .submit-btn.is-loading .btn-arrow {
  display: none;
}
#login-page .submit-btn.is-loading .spinner {
  display: block;
}

@media (prefers-reduced-motion: no-preference) {
  #login-page .submit-btn.is-loading .spinner {
    animation: sh-login-spin .7s linear infinite;
  }
  @keyframes sh-login-spin {
    to { transform: rotate(360deg); }
  }
  /* the chop stamps down after the form settles */
  #login-page .seal {
    opacity: 0;
    animation: sh-login-stamp .32s cubic-bezier(.2, 1.4, .4, 1) .75s forwards;
  }
  @keyframes sh-login-stamp {
    from { opacity: 0; transform: rotate(14deg) scale(1.9); }
    to   { opacity: 1; transform: rotate(6deg) scale(1); }
  }
}

/* ---------- language modes ----------
   The app-wide split classes (panels/styles.blade.php) cover "hidden in en"
   (.lang-cn-only) and "hidden in cn" (.lang-en-only); an element carrying
   BOTH is visible only in 双语 mode. What they cannot express is "visible
   ONLY in en" — bi deliberately leads Chinese and omits some English (the
   title). .en-solo fills that gap. */
html:not(.lang-en) #login-page .en-solo {
  display: none !important;
}

/* pre-auth language switcher — quiet pills, active mode in brand red */
#login-page .lang-switch {
  position: absolute;
  top: 22px;
  right: 26px;
  display: flex;
  gap: 4px;
  z-index: 2;
}
#login-page .lang-switch a {
  font-family: var(--font-body);
  font-size: 12px;
  font-weight: 600;
  color: var(--text-muted);
  text-decoration: none;
  padding: 5px 11px;
  border-radius: 999px;
  min-height: 24px;
  transition: color .15s ease-out, background .15s ease-out;
}
#login-page .lang-switch a:hover {
  color: var(--text-primary);
  background: var(--surface-2);
}
#login-page .lang-switch a.is-active {
  color: var(--red);
  background: var(--red-light);
}
#login-page .lang-switch a:focus-visible {
  outline: 2px solid var(--red);
  outline-offset: 1px;
}

/* Interactive cockpit: depth is confined to the product, never the form. */
#login-page { --surface-2: #F8F9FB; }
#login-page .showcase { flex-direction: column; padding: 64px 48px 80px; background: #F2F4F7; }
#login-page .showcase-heading { position: relative; width: min(820px, 94%); z-index: 1; margin-bottom: 48px; }
#login-page .showcase-heading h2 { margin: 0; color: var(--navy); font: 700 clamp(32px, 3.6vw, 60px)/1.08 var(--font-body); letter-spacing: -.045em; }
#login-page .showcase-heading h2 .lang-cn-only { display: block; font-size: .7em; margin-bottom: 14px; letter-spacing: -.02em; }
#login-page .showcase-heading p { margin: 18px 0 0; color: var(--text-muted); font-size: 14px; line-height: 1.7; }
#login-page .showcase-heading p span { display: block; }
#login-page .scene-stage { width: 100%; perspective: 1400px; padding: 18px 0 36px; }
#login-page .composition { margin: auto; transform-style: preserve-3d; transform: rotateX(var(--scene-x, 7deg)) rotateY(var(--scene-y, -10deg)); opacity: 1; animation: none; transition: transform .55s cubic-bezier(.2,.7,.2,1); }
#login-page .composition.is-tracking { transition-duration: .12s; }
#login-page .shot-card { transform: translateZ(16px); border-radius: 12px; box-shadow: 12px 24px 0 -10px #CDD3DF, 0 38px 65px -24px rgba(15,27,45,.35); }
#login-page .scene-platform { position: absolute; inset: 20% -3% -10%; border: 1px solid #BCC3D0; border-radius: 18px; background: #E5E9EF; transform: translateZ(-45px); }
#login-page .chip.money { transform: translateZ(80px); animation: none; background: #fff; }
#login-page .chip.act { transform: translateZ(100px); animation: none; background: #fff; }
#login-page .scene-hint { position: relative; margin-top: 32px; color: var(--text-muted); font-size: 11px; text-align: center; }
#login-page .scene-hint span { display: block; }
#login-page .aurora, #login-page .deco-circle, #login-page .seal, #login-page .auth::before { display: none; }
#login-page .auth { width: 440px; flex: 0 0 440px; padding: 76px 40px 48px; }
#login-page .auth-box { width: 100%; max-width: 380px; }
#login-page .lang-switch a { min-width: 44px; min-height: 44px; display: inline-flex; align-items: center; justify-content: center; }
#login-page .input-wrap input { font-size: 16px; }
#login-page .pw-toggle { min-width: 44px; min-height: 44px; }
#login-page .proof-line { left: 24px; right: 24px; bottom: 24px; text-align: center; }
@media (min-width: 1600px) {
  #login-page .auth { flex-basis: 520px; width: 520px; }
}
@media (max-width: 1060px) and (min-width: 761px) {
  #login-page .showcase { display: flex; padding: 60px 30px 76px; }
  #login-page .auth { flex-basis: 400px; width: 400px; padding-inline: 30px; }
  #login-page .showcase-heading h2 { font-size: 38px; }
  #login-page .url-pill { min-width: 0; font-size: 9px; padding: 0 6px; }
  #login-page .traffic, #login-page .bar-spacer { display: none; }
  #login-page .chip { padding: 10px; }
  #login-page .chip.money { right: -10px; }
  #login-page .chip.act { left: -10px; max-width: 95%; }
  #login-page .chip .chip-value { font-size: 18px; }
}
@media (max-width: 760px) {
  #login-page .login-split { flex-direction: column; }
  #login-page .showcase { display: flex; flex: none; min-height: 230px; padding: 26px 30px 20px; }
  #login-page .showcase-heading { margin: 0 0 14px; width: 100%; }
  #login-page .showcase-heading h2 { font-size: 26px; letter-spacing: -.025em; }
  #login-page .showcase-heading h2 br { display: none; }
  #login-page .showcase-heading h2 .lang-cn-only { font-size: 20px; margin-bottom: 5px; }
  #login-page .showcase-heading p, #login-page .proof-line, #login-page .scene-hint { display: none; }
  #login-page .scene-stage { max-width: 420px; padding: 4px 12px 20px; }
  #login-page .composition { width: 92%; }
  #login-page .shot-img { height: 125px; object-fit: cover; object-position: top; }
  #login-page .browser-bar { height: 22px; padding: 0 8px; }
  #login-page .traffic { gap: 4px; }
  #login-page .traffic span { width: 5px; height: 5px; }
  #login-page .url-pill { min-width: 0; height: 16px; padding: 0 6px; font-size: 7px; }
  #login-page .bar-spacer { display: none; }
  #login-page .chip.money { top: 18px; right: -18px; padding: 9px 12px; }
  #login-page .chip .chip-label { font-size: 9px; letter-spacing: 0; }
  #login-page .chip .chip-value { font-size: 18px; }
  #login-page .chip.money .chip-sub, #login-page .chip.act { display: none; }
  #login-page .auth { flex: 1; width: 100%; overflow: visible; align-items: flex-start; padding: 70px 24px calc(24px + env(safe-area-inset-bottom, 0px)); }
  #login-page .auth-box { margin: 0 auto; max-width: 420px; }
  #login-page .lang-switch { top: 12px; right: 18px; }
  #login-page .brand-lockup { margin-bottom: 20px; }
  #login-page .greet { margin-bottom: 12px; }
  #login-page .foot { margin-top: 28px; }
}
@media (prefers-reduced-motion: reduce) {
  #login-page .composition { transform: none; transition: none; }
  #login-page .scene-hint { visibility: hidden; }
  #login-page *, #login-page *::before, #login-page *::after { animation: none !important; transition: none !important; }
}
@media (min-width: 761px) {
  #login-page .shot-img { height: clamp(240px, 36vh, 410px); object-fit: cover; object-position: top; }
  #login-page .showcase-heading { margin-bottom: 34px; }
}
@media (max-width: 760px) {
  #login-page .showcase { min-height: 0; padding: 20px 24px 16px; }
  #login-page .showcase-heading h2 { font-size: 21px; }
  #login-page .showcase-heading h2 .lang-cn-only { font-size: 18px; }
  #login-page .showcase-heading { margin-bottom: 8px; }
  #login-page .scene-stage { padding-bottom: 10px; }
  #login-page .shot-img { height: 100px; }
  #login-page .auth { padding-top: 64px; }
  #login-page .brand-lockup { margin-bottom: 14px; }
  #login-page .greet { font-size: 11px; padding: 4px 10px; }
  #login-page .auth-sub { margin-top: 10px; font-size: 13px; }
  #login-page .fields { margin-top: 24px; gap: 14px; }
  #login-page .foot { margin-top: 20px; }
}
#login-page .scene-stage { user-select: none; -webkit-user-select: none; }
#login-page .proof-line { justify-content: center; }
