/* Personic Labs marketing site — base layer.
   Ported verbatim from the design handoff (design_handoff_personic_labs_site/README.md
   § Design tokens → Base CSS). Identical on all four pages; the keyframe set here is the
   union of the four prototypes. Everything else is inline on the elements, which is where
   the design's source of truth lives — do not extract it without a parity pass. */

/* --- logo bars ---------------------------------------------------------- */
@keyframes lgb { from { transform: scaleY(0); } to { transform: scaleY(1); } }

@media (prefers-reduced-motion: reduce) {
  @keyframes lgb { from { transform: none; } to { transform: none; } }
  @keyframes lgbLoop { 0%, 100% { transform: none; } }
}

/* --- base --------------------------------------------------------------- */
* { box-sizing: border-box; }
html { scroll-behavior: smooth; scroll-padding-top: 132px; }
body { margin: 0; background: #F1F4F5; color: #14181A;
       font-family: "Inter", system-ui, sans-serif; -webkit-font-smoothing: antialiased; }
a { color: #14181A; text-decoration: none; transition: color .2s ease, opacity .2s ease; }
a:hover { color: #35606E; }
p { text-wrap: pretty; }
h1, h2, h3, h4 { font-family: "Onest", system-ui, sans-serif; }
button { font: inherit; }
::selection { background: #35606E; color: #F1F4F5; }

/* --- section reveals and transitions ------------------------------------ */
@keyframes sec { from { opacity: 0; } to { opacity: 1; } }
@keyframes rv { from { opacity: 0; transform: translateY(20px); } to { opacity: 1; transform: none; } }
@keyframes fadeOut { from { opacity: 1; } to { opacity: 0; } }
@keyframes riseIn { from { opacity: 0; transform: translateY(56px); } to { opacity: 1; transform: none; } }
@keyframes handoffOut { from { opacity: 1; transform: none; } to { opacity: 0; transform: translateY(-48px); } }
@keyframes handoffIn { from { opacity: 0; transform: translateY(64px); } to { opacity: 1; transform: none; } }
@keyframes nudge { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(6px); } }
@keyframes marq { from { transform: translateX(0); } to { transform: translateX(-50%); } }
@keyframes pulse { 0%, 100% { opacity: .35; } 50% { opacity: 1; } }

:root { --chrome-h: 132px; }

/* The design hides the announcement pill under 700px. The prototypes carry this rule
   verbatim, but the pill also sets display:flex inline — which wins — so the pill has in
   fact been showing on phones the whole time, adding a third layer of fixed chrome to
   the viewport that can least afford it. !important is what the rule always meant. */
@media (max-width: 700px) { [data-announce] { display: none !important; } }

/* --- mobile chrome ------------------------------------------------------- */

/* Above the breakpoint the panel is transparent to layout, so the nav and CTA sit in
   the header row exactly as the design has them, and the menu button does not exist. */
[data-pl-menu-panel] { display: contents; }
[data-pl-menu-btn] { display: none; }

/* The header's own styles are inline — that is where the design's source of truth lives
   — so the mobile overrides below have to out-specify them. Every !important here is
   overriding an inline style, not another rule. */
@media (max-width: 700px) {

  /* One row: brand left, menu button right. */
  [data-pl-headerbar] {
    flex-wrap: nowrap !important;
    padding: 8px 8px 8px 18px !important;
    min-height: 54px !important;
    gap: 12px !important;
  }

  [data-pl-menu-btn] {
    display: inline-flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    gap: 5px;
    width: 44px;
    height: 44px;
    flex-shrink: 0;
    margin-left: auto;
    padding: 0;
    background: none;
    border: 0;
    border-radius: 12px;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
  }
  [data-pl-menu-btn] span {
    display: block;
    width: 19px;
    height: 1.5px;
    border-radius: 2px;
    background: #EAF0F2;
    transition: transform .22s cubic-bezier(.22,.61,.36,1), opacity .16s ease;
  }
  [data-pl-menu-btn]:hover { background: rgba(255, 255, 255, .08); }

  /* Closed → open: the three bars become a cross. */
  .pl-menu-open [data-pl-menu-btn] span:nth-child(1) { transform: translateY(6.5px) rotate(45deg); }
  .pl-menu-open [data-pl-menu-btn] span:nth-child(2) { opacity: 0; }
  .pl-menu-open [data-pl-menu-btn] span:nth-child(3) { transform: translateY(-6.5px) rotate(-45deg); }

  /* The panel drops below the brand row, inside the same glass pill. */
  [data-pl-menu-panel] {
    display: none;
    width: 100%;
    flex-direction: column;
    align-items: stretch;
    gap: 2px;
    margin-top: 6px;
    padding: 8px 2px 4px;
    border-top: 1px solid rgba(255, 255, 255, .14);
  }
  .pl-menu-open [data-pl-menu-panel] { display: flex; }
  .pl-menu-open [data-pl-headerbar] { flex-wrap: wrap !important; }
  /* A pill radius cannot hold a stacked menu; soften it while open. */
  .pl-menu-open [data-chrome="stack"] > header { border-radius: 26px !important; }

  [data-pl-menu-panel] nav {
    flex-direction: column !important;
    align-items: stretch !important;
    flex-wrap: nowrap !important;
    gap: 0 !important;
    margin-left: 0 !important;
    font-size: 16px !important;
  }
  [data-pl-menu-panel] nav a {
    display: flex;
    align-items: center;
    min-height: 46px;
    padding: 0 14px;
    border-radius: 13px;
    color: rgba(255, 255, 255, .92) !important;
  }
  [data-pl-menu-panel] nav a:hover,
  [data-pl-menu-panel] nav a:focus-visible { background: rgba(255, 255, 255, .09); }

  /* The CTA keeps its pill, full width at the foot of the menu. */
  [data-pl-menu-panel] > a {
    margin: 10px 4px 2px;
    padding: 15px 21px !important;
    font-size: 15px !important;
    text-align: center;
    justify-content: center;
  }

  /* The Home sticky bar is off on phones. It clipped its own CTA — every child is
     white-space: nowrap inside a max-width: calc(100vw - 24px) pill — and it repeats
     the header CTA on the one viewport that cannot spare the height. */
  [data-pl-sticky] { display: none !important; }

  /* --- background video focal points --------------------------------------
     object-fit: cover keeps the middle of the frame, which is right on a wide viewport
     where the crop is gentle. On a phone the container is far narrower than the 1.9:1
     footage, so cover throws away most of the width — and neither of these shots is
     centre-weighted. Both subjects sit right of centre against empty space on the left,
     so the default crop keeps the empty half and discards the subject.

     Values below are measured off the actual frames, not the poster images: the hero's
     poster is from a different moment of the shoot and is not representative. */

  /* Hero: phones get their own clip (see heroSource() in pl.js), framed for a portrait
     crop. The subject sits at 28–48% of that frame; 30% holds her whole face, glasses
     and the near ear cup with room to spare. */
  [data-pl-vid="hero"] { object-position: 30% center !important; }

  /* Second band: he runs from about 58% to the right edge, against a bare grey wall.
     At this band's height the crop keeps only ~55% of the width, so centred it lands
     almost entirely on the wall. Pin right — the wall is what should be lost. */
  [data-pl-vid="listening"] { object-position: right center !important; }

  /* --- video band headline ------------------------------------------------
     At this width the band renders at its 280px min-height, so the whole frame is
     visible at once and a top-left headline lands on top of the subject. Drop it to
     the foot, where the gradient is darkest and the frame is quietest. */
  [data-pl-band="foot"] { justify-content: flex-end !important; }
  [data-pl-band="foot"] > div {
    padding-top: 0 !important;
    padding-bottom: clamp(22px, 6vw, 40px) !important;
  }
}

@media (max-width: 700px) and (prefers-reduced-motion: reduce) {
  [data-pl-menu-btn] span { transition: none; }
}

/* --- production additions ----------------------------------------------- */

/* The clip rotator's pagination dots are 7px, which the README flags: a supplementary
   control, but "if you can enlarge their tap area without changing the visual, do."
   On a phone a 7px target is barely hittable.

   An invisible ::after gives each dot a 16 x 44 hit area — the full 16px pitch between
   dots, so neighbours never overlap and you cannot tap the wrong clip, and 44px tall
   because there is nothing above or below to collide with. The dot itself is untouched;
   this is ~10x the area for no visual change. */
[data-pl-clip] { position: relative; }
[data-pl-clip]::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: 16px;
  height: 44px;
  transform: translate(-50%, -50%);
}

/* The prototypes rely on the browser default ring. README § Accessibility asks for an
   explicit glacier focus-visible ring on every interactive element in production. */
a:focus-visible,
button:focus-visible,
input:focus-visible,
[tabindex]:focus-visible {
  outline: 2px solid #35606E;
  outline-offset: 3px;
  border-radius: 4px;
}

/* Scroll-driven section reveals run on `animation-timeline: view()`, which Safari and
   older Firefox do not support. There the inline animation would run once on load against
   the document timeline — effectively "always visible", which the README rules out: the
   staged reveal is part of the design. An inline head script adds .pl-io when view() is
   missing, this block neutralises the animation before first paint, and pl.js drives the
   same reveal with an IntersectionObserver. Where view() works, none of this applies. */
.pl-io [data-pl-reveal] {
  animation: none !important;
  opacity: 0;
  transition: opacity .55s cubic-bezier(.22,.61,.36,1), transform .55s cubic-bezier(.22,.61,.36,1);
}
.pl-io [data-pl-reveal="rv"] { transform: translateY(20px); }
.pl-io [data-pl-reveal].pl-seen { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  /* Reduced motion gets the finished state immediately, in both reveal paths. */
  .pl-io [data-pl-reveal] { opacity: 1; transform: none; transition: none; }
  [data-pl-reveal] { animation: none !important; opacity: 1 !important; transform: none !important; }
}
