/* ============================================================
   larsen.studio — THE stylesheet. One file, whole site.
   OWNERS: Hana + the Captain. Nobody else edits this file.
   (CSS law, ship doctrine 2026.)

   SYSTEM: "PANELER" — approved by the Captain 2026-08-28.
   Flat typographic panels at normal scroll (warm grey / orange /
   white) alternating with slow deep-set photo windows. Big bold
   type, constructed grid, motion that costs nothing to crawl.
   Spec: business/DESIGN-DOC-REBUILD-2026-08.md (v2).

   THE GRID (Captain's rulings, 2026-08-29 + 09-01): one unit,
   --u = 8px; every space is a named multiple. ONE GUTTER: the
   same value left, right, and between every column; everything
   flush left, no centering. Body is 20px on a 32px line (the
   vertical module). One measure for body and headings. Nothing
   is eyeballed; if a value isn't a multiple, it's a bug.

   You are reading the product demo. This file is part of it.
   ============================================================ */

/* ---------- 1 · TOKENS ------------------------------------- */
:root{
  --u: 8px;                /* THE unit — all space derives from it */

  --ink:        #0A0A0A;   /* text on light                     */
  --ground:     #FFFFFF;
  --white:      #FFFFFF;   /* text on dark grounds              */
  --photo-ground:#141414;  /* pre-load ground behind hero photos */
  --grey:       #ECEAE6;   /* warm grey panel — black text      */
  --orange:     #D84A00;   /* orange panel ground — white text  */
  --accent:     #FF5C00;   /* house orange: links/accents on light */
  --cobalt:     #1E2DB8;   /* deep panel — white text, sun links */
  --sun:        #FFC400;   /* links/accents on dark grounds ONLY */
  --meta:       #6B6B6B;   /* TRUE metadata only — never body   */

  /* type — editorial scale, unmistakable jumps                  */
  --text-sm: 16px;                            /* 2u   · label/meta/nav — line 3u  */
  --text-md: 20px;                            /* 2.5u · body — line 4u            */
  --text-lg: clamp(2.125rem, 6vw, 3.5rem);    /* heading · 34 → 56                */
  --text-xl: clamp(3.25rem, 15vw, 8.5rem);    /* display · 52 → 136               */

  /* space — named multiples of --u                              */
  --s2: 16px;  --s3: 24px;  --s4: 32px;
  --s6: 48px;  --s8: 64px;  --s12: 96px;
  --measure:     600px;                       /* 75u · ~60ch · body and headings share it */
  --gutter:      clamp(24px, 4vw, 56px);      /* THE gutter: left, right, and every gap */
  --pad:         var(--gutter);               /* alias — one value everywhere           */
  --col-gap:     var(--gutter);               /* alias — one value everywhere           */
  --block:       clamp(80px, 14svh, 160px);   /* 10u → 20u panel rhythm */
}

/* ---------- 2 · TYPE --------------------------------------- */
@font-face{
  font-family:"Familjen Grotesk";
  src:url(/fonts/FamiljenGrotesk-var.woff2) format("woff2");
  font-weight:400 700;
  font-style:normal;
  font-display:swap;
}

*{margin:0;padding:0;box-sizing:border-box}
html{-webkit-text-size-adjust:100%}
html, body{overflow-x:clip}
body{
  font-family:"Familjen Grotesk","Helvetica Neue",Helvetica,
    "PingFang TC","Microsoft JhengHei",Arial,sans-serif;
  font-size:var(--text-md);
  line-height:1.6;               /* 32px on 20 — the module */
  color:var(--ink);
  background:var(--ground);
  -webkit-font-smoothing:antialiased;
}

h1{
  font-size:var(--text-xl);
  font-weight:700;
  line-height:.98;
  letter-spacing:-.03em;
  margin-bottom:.45em;
}
/* Vertical rhythm: space above a heading BINDS it to its content,
   the gap below stays small (JMB: ~3 units above, 1 below). It was
   shipped inverted: 0 above, 22 below. Never again.              */
h2{
  font-size:var(--text-lg);
  font-weight:700;
  line-height:1.08;
  letter-spacing:-.02em;
  margin:var(--s8) 0 var(--s2);
  max-width:var(--measure);
}
h3{font-size:var(--text-lg);font-weight:700;line-height:1.1;letter-spacing:-.02em;
   margin:var(--s6) 0 var(--u);max-width:var(--measure)}
h2:first-child, h3:first-child{margin-top:0}
p, li, dd{max-width:var(--measure)}
p{margin:0 0 var(--s3)}
li{margin:var(--u) 0}
ul, ol{padding-inline-start:var(--s3)}
strong{font-weight:700}

/* zh-Hant register — no fake Latin tracking on CJK */
:lang(zh-Hant) h1{letter-spacing:0;line-height:1.12}
:lang(zh-Hant) h2{letter-spacing:0}
/* zh body copy breathes at 1.8: scoped to text elements only, so
   it can never override a component's explicit line-height (it
   once ballooned the footer mark's line box, 2026-09-01).        */
:lang(zh-Hant) :is(p, li, dd, dt, blockquote){line-height:1.8}

a{color:var(--accent);text-decoration:underline;text-underline-offset:4px;text-decoration-thickness:1px}
a:hover{text-decoration-thickness:2px}
a:focus-visible, button:focus-visible, input:focus-visible, textarea:focus-visible{
  outline:2px solid var(--accent);outline-offset:4px;
}
/* Focus must be visible on every ground: accent vanishes on the
   colour panels.                                                */
:is(.services,.cta,.proof,.storefronts,.faq,.hero-photo) :is(a,button,input,textarea):focus-visible{
  outline-color:var(--white);
}
::selection{background:var(--accent);color:var(--white)}

/* ---------- 3 · LAYOUT — panels carry the page -------------- */
/* Full-bleed panels, ONE gutter each side, everything flush
   left. The measure caps line length; nothing centers.          */
section, .footer, .nav{
  padding-left:var(--gutter);
  padding-right:var(--gutter);
}
section{padding-top:var(--block);padding-bottom:var(--block);background:var(--ground)}

/* THE MASTER GRID (Captain 2026-09-01: columns must share
   verticals across sections: a vertical line lands in a gutter
   anywhere on the page, or the grid is a lie). ONE four-column
   field grid; every layout is spans of it. Never invent a
   per-section column ratio again.                               */
.grid-2, .grid-3, .grid-split, .footer-grid{
  display:grid;
  grid-template-columns:repeat(4, minmax(0, 1fr));
  gap:var(--col-gap);
}
.grid-2 > *{grid-column:span 2}
/* A lone last card never orphans — it takes the full row.       */
.grid-2 > *:last-child:nth-child(odd){grid-column:1/-1}
.grid-3 > *{grid-column:span 1}
.grid-split{padding-top:var(--s3)}
.grid-split > .spec-k{grid-column:span 1}
.grid-split > .spec-v{grid-column:span 3}
.footer-grid > .footer-col:first-child{grid-column:span 2}
@media(max-width:700px){
  .grid-2,.grid-3,.grid-split,.footer-grid{grid-template-columns:1fr}
  .grid-2 > *, .grid-3 > *, .grid-split > *, .footer-grid > .footer-col:first-child{grid-column:auto}
  .grid-split{gap:var(--u)}
}

/* ---------- 4 · SECTION FURNITURE --------------------------- */
/* Law (Paneler): labels stand alone — the panel edge is the
   rule. No hairlines anywhere. A label sits 8u above content.   */
.label{
  display:block;
  font-size:var(--text-sm);
  font-weight:600;
  letter-spacing:.16em;
  text-transform:uppercase;
  line-height:1.5;
  margin-bottom:var(--s8);
}
:lang(zh-Hant) .label{letter-spacing:.25em}
hr{display:none}  /* ALL hairlines dead — the panel edge is the rule */

/* ---------- 5 · NAV ----------------------------------------- */
.nav{
  display:flex;flex-wrap:wrap;align-items:baseline;gap:var(--s2) var(--col-gap);
  padding-top:var(--s3);padding-bottom:var(--s3);
  background:var(--grey);
}
/* The wordmark IS the logo: it outweighs the nav links.          */
.nav-mark{font-size:var(--text-md);font-weight:700;color:var(--ink);text-decoration:none;letter-spacing:-.02em}
/* The mark IS the punctuation (Captain, 2026-09-01): the wordmark's
   full stop takes the accent. On orange grounds the dot goes ink.   */
.dot{color:var(--accent)}
.cta .dot, .services .dot{color:var(--ink)}
body:has(.hero-photo) .nav-mark .dot{color:var(--accent)}
.nav-market{
  font-size:var(--text-sm);font-weight:600;letter-spacing:.16em;
  color:var(--accent);margin-left:var(--u);vertical-align:1px;
}
.nav-links{display:flex;flex-wrap:wrap;gap:var(--u) var(--s3);list-style:none;margin-left:auto}
.nav-links a{font-size:var(--text-sm);color:var(--ink);text-decoration:none}
.nav-links a:hover{color:var(--accent);text-decoration:underline}

/* ---------- 6 · PANEL RHYTHM -------------------------------- */
/* Hero: warm grey, big type, everywhere.                        */
.hero{background:var(--grey)}

/* Photo hero — the SLAM (Captain 2026-08-29). Any page whose
   hero carries .hero-photo becomes a full-viewport window: photo
   ground, white bold nav floating over it, top inset shadow,
   bottom scrim under the type. Homepage: København (preloaded
   from markup — it is the LCP element).                          */
body:has(.hero-photo) .nav{
  position:absolute;top:0;left:0;right:0;z-index:2;
  background:transparent;
}
body:has(.hero-photo) .nav-mark,
body:has(.hero-photo) .nav-links a{color:var(--white);font-weight:700}
body:has(.hero-photo) .nav-links a:hover{color:var(--white);text-decoration:underline}
.hero-photo{
  position:relative;
  background:var(--photo-ground);
  color:var(--white);
  min-height:100svh;
  overflow:clip;                   /* clip ≠ scroll container     */
  view-timeline:--hero block;
  display:flex;flex-direction:column;justify-content:flex-end;
  padding-top:192px;               /* 24u — clears a 3-row wrapped nav */
  padding-bottom:var(--block);
}
/* The photo rides its own layer so it can scroll slow like the
   windows do.                                                   */
.hero-photo::before{
  content:"";position:absolute;left:0;top:-12%;
  width:100%;height:124%;z-index:0;
  background-image:url(/media/windows/kobenhavn.jpg);
  background-size:cover;background-position:center;
}
/* Photographic treatment in ONE layer: a grey multiply gradient
   = highlight damper + directional scrim combined. Highlights
   compress, shadows keep their depth, white type reads
   everywhere. Heroes carry type → treated; windows never.       */
.hero-photo::after{
  content:"";position:absolute;inset:0;pointer-events:none;
  mix-blend-mode:multiply;
  box-shadow:inset 0 34px 54px -18px rgba(0,0,0,.62);
  background:linear-gradient(180deg,
    #696969 0%, #969696 28%, #969696 50%, #4F4F4F 100%);
}
.hero-photo > *{position:relative;z-index:1}

/* Market hero photos — the language IS the market. The page's
   markup decides WHETHER a hero is a photo (the class); the
   language decides WHICH photo. Forms never sit on photo (law,
   Captain 2026-08-29) — they live on flat panels only.          */
:root:lang(zh-Hant) .hero-photo::before{background-image:url(/media/windows/taipei.jpg)}
:root:lang(zh-Hant) .hero-photo::after{background:linear-gradient(180deg,
    #575757 0%, #7E7E7E 30%, #7E7E7E 55%, #414141 100%)}  /* firmer for neon */
:root:lang(da) .hero-photo::before{background-image:url(/media/windows/kobenhavn-diamond.jpg)}

/* Panel registers (Captain 2026-08-29: "black on white is bland
   af") — four voices: orange = energy/conversion, cobalt =
   authority, ink = drama, grey = quiet. White is air, not a
   default. On dark grounds links speak SUN, never orange.
   Homepage sweep: photo → orange → 台北 → cobalt → 福岡 → ink →
   grey footer.                                                  */
.services{background:var(--orange);color:var(--white)}
.proof{background:var(--cobalt);color:var(--white)}
.proof a{color:var(--sun)}
.storefronts{background:var(--ink);color:var(--white)}
.storefronts a{color:var(--white)}
.storefronts .label{color:var(--sun)}

/* Honest answers live on the authority blue — site-wide.        */
.faq{background:var(--cobalt);color:var(--white)}
.faq a{color:var(--sun)}

/* Plain interior sections alternate quiet grey / air.           */
main > section:not([class]):nth-of-type(odd){background:var(--grey)}

/* Orange panels: white type, links stay white and bold.         */
.services a, .cta a{color:var(--white)}
.services h2 a, .storefronts h2 a{text-decoration-thickness:2px}

/* Conversion panels are orange. One per conversion page.        */
.cta{background:var(--orange);color:var(--white)}
.cta h2{max-width:14em}

/* Entity paragraph — the sentence machines quote. Never shrunk. */
.entity{max-width:var(--measure)}

/* "Spørg en maskine" — renders the day the first REAL dated
   citation exists (Article IX; markup commented until then).    */
.ask-machine{background:var(--ground);max-width:var(--measure);padding:var(--s4);margin-top:var(--s6)}
.ask-machine .label{color:var(--accent);margin-bottom:var(--s3)}
.ask-a{line-height:1.6;border-left:2px solid var(--accent);padding-left:var(--s3);margin:var(--s2) 0}
.ask-src{font-size:var(--text-sm);color:var(--meta)}

/* ---------- 7 · CONTENT PATTERNS ---------------------------- */
/* Steps — accent on the numeral only (ol) / dash (ul).          */
.steps{list-style:none;counter-reset:step;display:flex;flex-direction:column;gap:var(--s4);padding-top:var(--u)}
ol.steps > li{counter-increment:step;position:relative;padding-left:3em}
ol.steps > li::before{
  content:counter(step,decimal-leading-zero);
  position:absolute;left:0;top:.15em;
  font-size:var(--text-sm);font-weight:700;
  font-variant-numeric:tabular-nums;
  color:var(--accent);
}
ul.steps > li{position:relative;padding-left:1.6em}
ul.steps > li::before{
  content:"";position:absolute;left:0;top:.72em;width:.9em;height:2px;background:var(--accent);
}

/* FAQ — dt asks at heading scale, dd answers.                   */
.faq dt{font-size:var(--text-lg);font-weight:700;line-height:1.1;letter-spacing:-.02em;margin-top:var(--s8);max-width:20em}
.faq dt:first-of-type{margin-top:0}
.faq dd{margin-top:var(--s2)}

/* Spec rows (pricing) — values left-align to the column start.  */
.spec-k{font-size:var(--text-sm);font-weight:600;letter-spacing:.06em;text-transform:uppercase}
:lang(zh-Hant) .spec-k{letter-spacing:.12em}
.spec-v{font-weight:400}

/* Answers — dated, bylined articles. Articles live directly in
   main (no section), so they carry the panel formula themselves. */
main > .answer{
  padding-left:var(--gutter);
  padding-right:var(--gutter);
  padding-top:calc(var(--block) / 2);
  padding-bottom:var(--block);
  background:var(--ground);
}
.answer code{
  font-family:ui-monospace,SFMono-Regular,Menlo,monospace;
  font-size:.85em;background:var(--grey);padding:2px var(--u);
}
.answer-byline{font-size:var(--text-sm);color:var(--meta);margin-bottom:var(--s4)}
.answer-lede{margin-bottom:var(--s3)}
.answer-list{display:flex;flex-direction:column;gap:var(--s3);list-style:none}
.answer-list a{color:var(--ink)}
.answer-list a:hover{color:var(--accent)}

/* Work / case blocks.                                           */
.case{padding:var(--s4) 0 0}

/* Credits gallery — patronage shown properly.                   */
.credit-card{margin:0}
.credit-thumb{width:100%;aspect-ratio:4/3;object-fit:cover;display:block}
.credit-card figcaption{font-size:var(--text-sm);line-height:1.5;margin-top:var(--s2)}
.credit-card .label{margin-bottom:var(--u)}

/* ---------- 8 · CONVERSION ---------------------------------- */
.btn{
  display:inline-block;
  font-size:var(--text-md);font-weight:700;letter-spacing:.01em;
  background:var(--ink);color:var(--white);text-decoration:none;
  padding:var(--s2) var(--s4);
}
.btn:hover{background:var(--accent)}
.cta .btn{background:#FFF;color:var(--orange)}
.cta .btn:hover{background:var(--grey);color:var(--ink)}

/* Forms — the panel where a form lives is JMB grey (Captain,
   2026-08-29); orange stays for CTAs without forms. Fields are
   white cards straight on the grey panel.                       */
.cta:has(#contact-form){background:var(--grey);color:var(--ink)}
.cta:has(#contact-form) a{color:var(--accent)}
#contact-form{max-width:var(--measure)}
.form-row{display:grid;grid-template-columns:1fr 1fr;gap:var(--col-gap)}
@media(max-width:700px){.form-row{grid-template-columns:1fr}}
.form-field{display:flex;flex-direction:column;gap:var(--u);margin-bottom:var(--s3)}
.field-label{font-size:var(--text-sm);font-weight:700;letter-spacing:.14em;text-transform:uppercase}
input, textarea{
  font:inherit;color:var(--ink);
  background:var(--ground);
  border:0;border-radius:0;
  padding:var(--s2);width:100%;
}
input::placeholder, textarea::placeholder{color:var(--meta);opacity:1}
#contact-form button{
  font:inherit;font-weight:700;cursor:pointer;
  background:var(--ink);color:var(--white);
  border:0;border-radius:0;padding:var(--s2) var(--s4);
}
#contact-form button:hover{background:var(--accent)}
#contact-form button:disabled{opacity:.6;cursor:default}
#contact-feedback{margin-top:var(--s2);font-weight:700;min-height:1.4em}

.footer-contact span[lang="zh-Hant"],
.cta p span[lang="zh-Hant"],
.cta-alt span[lang="zh-Hant"]{white-space:nowrap}

/* .cta-alt: FOSSIL, awaiting markup removal (its market-door job
   moved into the canonical footer). Until then it reads as the
   CTA panel's quiet footnote, not an orange stripe.             */
.cta-alt{
  max-width:none;
  background:var(--grey);color:var(--ink);
  margin:calc(-1 * var(--s4)) 0 0;
  padding:0 var(--gutter) var(--s8);
  font-size:var(--text-sm);
}
.cta-alt a{color:var(--accent)}
section .cta-alt{background:none;padding:0;margin:var(--s3) 0 0}

/* Honeypot — visually gone, present for the worker.             */
.hp{position:absolute !important;left:-9999px !important;width:1px;height:1px;overflow:hidden}

/* ---------- 9 · PHOTO WINDOWS -------------------------------- */
/* <section class="window"><img class="ph" …><span class="chip">
   …</span></section>. A window doesn't exist until its photo
   does — no placeholders, ever (doc §5).
   The window carries a NAMED view-timeline: overflow:hidden
   makes it a scroll container, so the photo's own view() would
   track the wrong scroller and freeze (shipped bug, 08-29).     */
section.window{
  position:relative;height:72svh;overflow:hidden;padding:0;
  view-timeline:--win block;
}
.window .ph{
  position:absolute;left:0;top:-16%;
  width:100%;height:132%;
  object-fit:cover;display:block;
}
.window::after{
  content:"";position:absolute;inset:0;pointer-events:none;
  box-shadow:inset 0 34px 54px -18px rgba(0,0,0,.62),
             inset 0 -34px 54px -18px rgba(0,0,0,.62);
}
.window .chip{
  position:absolute;left:var(--pad);bottom:var(--s4);
  background:var(--ground);color:var(--ink);
  font-size:var(--text-sm);font-weight:600;
  letter-spacing:.12em;text-transform:uppercase;
  font-variant-numeric:tabular-nums;line-height:1.5;
  padding:var(--u) var(--s2);
}

/* ---------- 10 · FOOTER — generous grid, then THE MARK -------- */
.footer{background:var(--grey);padding-top:var(--block);padding-bottom:0;overflow:clip}
.footer .entity{font-size:var(--text-sm);line-height:1.5;color:var(--ink)}
.footer-contact{font-size:var(--text-sm);margin-top:var(--s3)}
.footer-col .label{margin-bottom:var(--s3)}
.footer-links{list-style:none;padding:0}
.footer-links li{margin:0 0 var(--s2)}
.footer-links a{color:var(--ink);text-decoration:none}
.footer-links a:hover{color:var(--accent);text-decoration:underline}
.footer-meta{margin-top:var(--s8);font-size:var(--text-sm);color:var(--meta);
  display:flex;justify-content:space-between;flex-wrap:wrap;gap:var(--s2)}
/* Captain 2026-09-01: © + credits live directly after the entity
   sentence, inside the first footer column.                     */
.footer-col .footer-meta{margin-top:var(--s4);justify-content:flex-start;gap:var(--s2) var(--s4)}
/* THE MARK. Born as a Safari accident, ruled KEEP: 'larsen.'
   runs from the left gutter to the exact right edge (ratio 2.73
   = the string's em-width), '.studio' clips INSIDE the element's
   own viewport-bound box (iOS expands the layout viewport for
   wide children, so the box may never exceed it). No descenders:
   the page's last pixel is the baseline.                        */
.footer-mark{
  display:block;
  width:calc(100vw - var(--gutter));
  overflow:clip;white-space:nowrap;
  margin-top:var(--s12);
  font-size:calc((100vw - var(--gutter)) / 2.73);  /* 'larsen.' spans gutter→edge exactly */
  font-weight:700;letter-spacing:-.045em;
  line-height:.76;color:var(--ink);
  user-select:none;
}

/* ---------- 11 · MOTION — costs nothing to crawl ------------- */
/* Scroll-driven, pure CSS, no JS, no CLS. Browsers without
   animation-timeline simply show the page. The page at rest is
   the canonical design. Reveals attach only to elements smaller
   than any viewport, so every animation completes its range.    */
@media (prefers-reduced-motion: no-preference){
  @supports (animation-timeline: view()){
    section > :is(h1,h2,p,.label,.btn,.ask-machine),
    .steps > li,
    .faq dt, .faq dd,
    .grid-split,
    .grid-2 > *, .grid-3 > *,
    .case,
    .answer-list > li{
      animation:rise linear both;
      animation-timeline:view();
      animation-range:entry 0% entry 55%;
    }
    .footer-mark{
      animation:fade linear both;   /* opacity only: transforms are the mark's own */
      animation-timeline:view();
      animation-range:entry 0% entry 70%;
    }
    .window .ph{
      animation:drift linear both;
      animation-timeline:--win;
    }
    .hero-photo::before{
      animation:drift linear both;
      animation-timeline:--hero;
    }
  }
}
@keyframes fade{
  from{opacity:0}
  to{opacity:1}
}
@keyframes rise{
  from{opacity:0;transform:translateY(24px)}
  to{opacity:1;transform:none}
}
@keyframes drift{
  from{transform:translateY(-8%)}
  to{transform:translateY(8%)}
}

/* ---------- 12 · PRINT --------------------------------------- */
@media print{
  .nav,.cta,.cta-alt,#contact-form{display:none}
  section{padding:24pt 0}
  body{color:#000}
}
