/* publicsite product layer, over go.local/ui-web.
 *
 * The rule: every value here resolves through a --factory-* custom property,
 * except where the design system has no token to reach for. That happens two
 * ways — DESIGN.md fixes the value in prose without shipping it as a
 * --factory-* property, or the value is structural or page-specific and
 * DESIGN.md never addresses it. Before writing a literal, check both: if a
 * --factory-* property already carries the value, use it; otherwise, if
 * DESIGN.md names or derives the value without exposing a property, or the
 * value has no design meaning at all — it sizes to content, or orders
 * stacking on this one page — it belongs in the list below, cited against
 * DESIGN.md where one applies. Any other literal is a defect.
 *
 * Named in DESIGN.md, but only as prose — no --factory-* property exists:
 *
 *   - `outline: 2px solid` / `outline-offset: 2px` on every focus ring
 *     (~7 rules): DESIGN.md's Elevation table and Quick Reference name
 *     "2px solid the scheme accent at outline-offset: 2px" as the focus
 *     treatment everywhere, but only in prose.
 *   - `min-width` / `min-height: 44px` on standalone icon controls (2
 *     rules): DESIGN.md § Touch Targets names 44px as the comfort target
 *     above the 24px WCAG 2.2 AA floor.
 *   - `color-mix(in oklab, ... 8%, ...)` on the status/accent washes (2
 *     rules): DESIGN.md derives a status tint as "the status colour at 8%
 *     over the current surface" — a formula against whatever the tokens
 *     resolve to, not a colour of its own to tokenize.
 *   - `1px` for hairline borders (DESIGN.md § Borders states one
 *     structural line and no heavier variant — a border weight, not a
 *     design value).
 *   - the breakpoint widths in the media queries below (600px, 834px,
 *     835px), which DESIGN.md § Breakpoints names but ships no token for.
 *
 * Structural or page-specific; DESIGN.md never addresses them:
 *
 *   - `100vh` for the viewport shell — the page's own height, not a token.
 *   - the `.publicsite-column` measures (`max-width: 1080px` / `720px` /
 *     `560px`): container widths are a per-layout choice, and DESIGN.md
 *     carries no token scale for them at all.
 *   - `min-width: 208px` on `.publicsite-nav-disclosure__panel`: sized to
 *     fit the compact nav's longest label without wrapping, not a design
 *     value.
 *   - the `z-index` literals (50, 60, 70) ordering the sticky header, the
 *     nav disclosure panel and the skip link against each other: stacking
 *     order is page-specific, and no --factory-* z-index scale exists.
 *
 * A value copied into this file instead of referenced through a token drifts
 * silently the next time DESIGN.md moves, and still renders and still
 * compiles — that risk is what the rule above guards against. The categories
 * above cannot drift the same way: the structural ones have no token to fall
 * out of sync with, and the DESIGN.md-named ones have no --factory-* property
 * to begin with, prose or not — so there is nothing here for a token update
 * to silently leave behind.
 *
 * This file deliberately re-declares none of the responsive collapses that
 * packages/ui/web/assets/theme.css already carries at 834px and 600px — the
 * display type roles, --factory-space-section (80 -> 48px) and
 * --factory-space-section-large (120 -> 64px). Referencing the token gets the
 * collapse for free; re-declaring it forks the value.
 *
 * No selector below targets a bare .factory-* class. Where a ui/web component
 * needs adjusting, the override is scoped under a .publicsite-* ancestor —
 * the convention apps/backend/dashbo's own CSS follows.
 */

/* --- Document ground ---------------------------------------------------- */

html {
  scroll-behavior: smooth;
}

body {
  margin: 0;
  background: var(--factory-color-background);
  color: var(--factory-color-text-primary);
  font-family: var(--factory-font-family);
  font-size: var(--factory-type-body-size);
  font-weight: var(--factory-type-body-weight);
  line-height: var(--factory-type-body-leading);
  -webkit-font-smoothing: antialiased;
}

/* Japanese takes looser leading and normal tracking at every size —
 * DESIGN.md § Typography, The CJK Normal-Tracking Rule. ui.Text handles this
 * per-component through its Lang prop; this covers the page defaults for text
 * that is not inside a ui.Text. */
html[lang='ja'] body {
  font-family: var(--factory-font-family-jp);
  font-size: var(--factory-type-jp-body-size);
  line-height: var(--factory-type-jp-body-leading);
  letter-spacing: var(--factory-type-jp-body-tracking);
}

/* --- Shell -------------------------------------------------------------- */

.publicsite-shell {
  display: flex;
  min-height: 100vh;
  flex-direction: column;
}

.publicsite-main {
  flex: 1;
}

/* --- Bands and columns -------------------------------------------------- */
/* DESIGN.md § Layout: full-bleed bands, each holding a centred column,
 * divided by lattice members rather than by cards. */

.publicsite-band {
  padding-block: var(--factory-space-section);
}

.publicsite-band--alt {
  background: var(--factory-color-background-alt);
}

.publicsite-band--ruled {
  border-top: 1px solid var(--factory-color-border);
}

.publicsite-column {
  width: 100%;
  max-width: 1080px;
  margin-inline: auto;
  padding-inline: var(--factory-space-xl);
}

.publicsite-column--prose {
  max-width: 720px;
}

.publicsite-column--narrow {
  max-width: 560px;
}

@media (max-width: 600px) {
  .publicsite-column {
    padding-inline: var(--factory-space-lg);
  }
}

/* --- Flow helpers ------------------------------------------------------- */

.publicsite-stack {
  display: flex;
  flex-direction: column;
  gap: var(--factory-space-lg);
}

/* display/flex-direction duplicate .publicsite-stack's on purpose: a
 * gap-only modifier silently no-ops when used without the base class on a
 * block element, since gap does nothing without a flex/grid layout. Carrying
 * its own layout declarations makes the modifier work standalone as well as
 * composed with the base class. */
.publicsite-stack--loose {
  display: flex;
  flex-direction: column;
  gap: var(--factory-space-xl);
}

.publicsite-grid {
  display: grid;
  gap: var(--factory-space-xl);
  grid-template-columns: repeat(2, minmax(0, 1fr));
}

@media (max-width: 834px) {
  .publicsite-grid {
    grid-template-columns: minmax(0, 1fr);
  }
}

/* --- Prose -------------------------------------------------------------- */
/* The legal pages. ui.Text carries the headings; this supplies the rhythm
 * around and between them, and the list styling ui/web has no component for. */

.publicsite-prose > * + * {
  margin-top: var(--factory-space-lg);
}

.publicsite-prose p {
  margin: 0;
  color: var(--factory-color-text-secondary);
  font-size: var(--factory-type-body-size);
  font-weight: var(--factory-type-body-weight);
  line-height: var(--factory-type-body-leading);
}

.publicsite-prose ul,
.publicsite-prose ol {
  margin: 0;
  padding-inline-start: var(--factory-space-xl);
  color: var(--factory-color-text-secondary);
  font-size: var(--factory-type-body-size);
  line-height: var(--factory-type-body-leading);
}

.publicsite-prose li + li {
  margin-top: var(--factory-space-md);
}

.publicsite-prose section + section {
  margin-top: var(--factory-space-xxl);
}

/* --- Links -------------------------------------------------------------- */

.publicsite-link {
  color: var(--factory-color-link);
  text-decoration: none;
  transition: color var(--factory-duration-fast) ease;
}

.publicsite-link:hover {
  text-decoration: underline;
}

.publicsite-link:focus-visible {
  outline: 2px solid var(--factory-color-focus);
  outline-offset: 2px;
  border-radius: var(--factory-radius-standard);
}

/* --- Call to action ----------------------------------------------------- */
/* ui.Button renders a <button>; several publicsite actions are navigations
 * and must be anchors. Rather than paint .factory-button — another package's
 * internal class name — onto markup that package did not render, this
 * reproduces one CTA appearance from the same tokens. */

.publicsite-cta {
  display: inline-flex;
  align-items: center;
  gap: var(--factory-space-md);
  padding: var(--factory-space-base) var(--factory-space-xl);
  border: 1px solid transparent;
  border-radius: var(--factory-radius-standard);
  background: var(--factory-color-primary);
  color: var(--factory-color-on-primary);
  font-family: inherit;
  font-size: var(--factory-type-nav-button-size);
  font-weight: var(--factory-type-nav-button-weight);
  line-height: var(--factory-type-nav-button-leading);
  letter-spacing: var(--factory-type-nav-button-tracking);
  text-decoration: none;
  transition: background var(--factory-duration-fast) ease;
}

.publicsite-cta:hover {
  background: var(--factory-color-primary-hover);
}

.publicsite-cta:focus-visible {
  outline: 2px solid var(--factory-color-focus);
  outline-offset: 2px;
}

.publicsite-cta svg {
  width: var(--factory-space-lg);
  height: var(--factory-space-lg);
}

/* --- Skip link ------------------------------------------------------------ */
/* Renders as the first element components/header.templ returns, ahead of the
 * header's own logo, nav, language switcher, theme toggle and mobile-menu
 * disclosure — six-plus focusable elements a keyboard user would otherwise
 * have to tab through on every page. Hidden via a translateY on its own box
 * rather than an off-canvas pixel offset, so nothing here needs a value
 * outside the token scale. z-index: 70 clears both the sticky header's own
 * 50 and the nav disclosure panel's 60, so the link is never painted under
 * either once focused. */

.publicsite-skip-link {
  position: absolute;
  top: var(--factory-space-md);
  left: var(--factory-space-md);
  z-index: 70;
  padding: var(--factory-space-sm) var(--factory-space-lg);
  border: 1px solid var(--factory-color-border);
  border-radius: var(--factory-radius-standard);
  background: var(--factory-color-background);
  color: var(--factory-color-text-primary);
  text-decoration: none;
  transform: translateY(-150%);
  transition: transform var(--factory-duration-fast) ease;
}

.publicsite-skip-link:focus-visible {
  transform: translateY(0);
  outline: 2px solid var(--factory-color-focus);
  outline-offset: 2px;
}

/* --- Header ------------------------------------------------------------- */

.publicsite-header {
  position: sticky;
  top: 0;
  z-index: 50;
  background: var(--factory-color-background);
  border-bottom: 1px solid var(--factory-color-border);
}

.publicsite-header__row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--factory-space-lg);
  padding-block: var(--factory-space-base);
}

.publicsite-brand {
  display: inline-flex;
  align-items: center;
  gap: var(--factory-space-md);
  color: var(--factory-color-text-primary);
  text-decoration: none;
}

.publicsite-brand:focus-visible {
  outline: 2px solid var(--factory-color-focus);
  outline-offset: 2px;
}

.publicsite-brand img {
  width: var(--factory-space-xxl);
  height: var(--factory-space-xxl);
}

.publicsite-header__actions {
  display: flex;
  align-items: center;
  gap: var(--factory-space-md);
}

/* --- Navigation --------------------------------------------------------- */

.publicsite-nav {
  display: flex;
  align-items: center;
  gap: var(--factory-space-xs);
}

.publicsite-navlink {
  padding: var(--factory-space-md) var(--factory-space-base);
  border-radius: var(--factory-radius-standard);
  color: var(--factory-color-text-secondary);
  font-size: var(--factory-type-nav-button-size);
  font-weight: var(--factory-type-nav-button-weight);
  line-height: var(--factory-type-nav-button-leading);
  letter-spacing: var(--factory-type-nav-button-tracking);
  text-decoration: none;
  transition: color var(--factory-duration-fast) ease;
}

.publicsite-navlink:hover {
  color: var(--factory-color-text-primary);
}

.publicsite-navlink:focus-visible {
  outline: 2px solid var(--factory-color-focus);
  outline-offset: 2px;
}

/* The current page. Colour alone would not carry this — the weight change is
 * the non-colour cue. */
.publicsite-navlink.is-active {
  color: var(--factory-color-text-primary);
  font-weight: var(--factory-type-body-medium-weight);
  text-decoration: underline;
  text-underline-offset: var(--factory-space-sm);
}

/* --- Icon button (theme toggle, language switch) ------------------------ */
/* 44x44: DESIGN.md § Touch Targets sets 24px as the WCAG 2.2 AA floor and
 * 44px as the comfort target. A standalone control takes the comfort target;
 * the row-laid-out .publicsite-navlink above is excluded by the same section,
 * because a 44px hit area on each would steal its neighbour's taps. */

.publicsite-iconbutton {
  display: inline-flex;
  min-width: 44px;
  min-height: 44px;
  align-items: center;
  justify-content: center;
  gap: var(--factory-space-sm);
  padding-inline: var(--factory-space-base);
  border: 1px solid transparent;
  border-radius: var(--factory-radius-standard);
  background: transparent;
  color: var(--factory-color-text-secondary);
  cursor: pointer;
  font-family: inherit;
  font-size: var(--factory-type-nav-button-size);
  font-weight: var(--factory-type-nav-button-weight);
  text-decoration: none;
  transition: color var(--factory-duration-fast) ease;
}

.publicsite-iconbutton:hover {
  color: var(--factory-color-text-primary);
}

.publicsite-iconbutton:focus-visible {
  outline: 2px solid var(--factory-color-focus);
  outline-offset: 2px;
}

.publicsite-iconbutton svg {
  width: var(--factory-space-lg);
  height: var(--factory-space-lg);
}

/* --- Mobile navigation -------------------------------------------------- */
/* A native <details> disclosure, not ui.Drawer: Drawer opens through an
 * Alpine-handled window event, so with JavaScript disabled or still loading a
 * phone visitor would have no navigation at all. <details> opens, closes and
 * takes keyboard focus with nothing running. Same reasoning
 * packages/ui/web gives for building its own Accordion on <details>
 * (CLAUDE.md, divergence 7). */

.publicsite-nav-disclosure {
  position: relative;
}

.publicsite-nav-disclosure > summary {
  display: inline-flex;
  min-width: 44px;
  min-height: 44px;
  align-items: center;
  justify-content: center;
  border-radius: var(--factory-radius-standard);
  color: var(--factory-color-text-secondary);
  cursor: pointer;
  list-style: none;
}

.publicsite-nav-disclosure > summary::-webkit-details-marker {
  display: none;
}

.publicsite-nav-disclosure > summary:focus-visible {
  outline: 2px solid var(--factory-color-focus);
  outline-offset: 2px;
}

.publicsite-nav-disclosure > summary svg {
  width: var(--factory-space-xl);
  height: var(--factory-space-xl);
}

.publicsite-nav-disclosure__panel {
  position: absolute;
  z-index: 60;
  right: 0;
  display: flex;
  min-width: 208px;
  flex-direction: column;
  padding: var(--factory-space-md);
  margin-top: var(--factory-space-md);
  border: 1px solid var(--factory-color-border);
  border-radius: var(--factory-radius-standard);
  background: var(--factory-color-surface);
}

/* Above Tablet Small the desktop nav carries everything, so the disclosure
 * has nothing left to do. DESIGN.md § Breakpoints puts that edge at 834px. */
@media (min-width: 835px) {
  .publicsite-nav-disclosure {
    display: none;
  }
}

@media (max-width: 834px) {
  .publicsite-nav {
    display: none;
  }
}

/* --- Washes ------------------------------------------------------------- */
/* A tinted plate behind an icon. DESIGN.md derives a status fill as the
 * status colour at 8% over the current surface rather than naming a tint of
 * its own, which is what lets it follow the scheme instead of staying a pale
 * daylight pill on an evening panel. color-mix does that arithmetic against
 * whatever the tokens currently resolve to. */

.publicsite-wash {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: var(--factory-space-md);
  border-radius: var(--factory-radius-standard);
  background: color-mix(in oklab, var(--factory-color-primary) 8%, var(--factory-color-surface));
  color: var(--factory-color-primary);
}

.publicsite-wash--error {
  background: color-mix(in oklab, var(--factory-color-error) 8%, var(--factory-color-surface));
  color: var(--factory-color-error);
}

.publicsite-wash svg {
  width: var(--factory-space-xl);
  height: var(--factory-space-xl);
}

/* --- Footer ------------------------------------------------------------- */

.publicsite-footer {
  margin-top: auto;
  border-top: 1px solid var(--factory-color-border);
  padding-block: var(--factory-space-xxl);
}

/* --- Callout ------------------------------------------------------------ */
/* A quoted value inside prose — commercial.templ's statutory disclosures.
 * The bar is a kumiko member turned on its side, which is the only structural
 * device DESIGN.md § Elevation allows; the fill is the panel ground, so the
 * block reads as framed rather than tinted. */

.publicsite-callout {
  margin: 0;
  padding: var(--factory-space-lg);
  border-inline-start: 1px solid var(--factory-color-border);
  background: var(--factory-color-surface);
}

.publicsite-callout p {
  margin: 0;
}

.publicsite-callout p + p {
  margin-top: var(--factory-space-base);
}

/* --- Card head ---------------------------------------------------------- */
/* An icon plate beside a title. Its own class rather than a reused
 * .publicsite-stack so the two stay on one row while the body below flows
 * vertically. */

.publicsite-card-head {
  display: flex;
  align-items: center;
  gap: var(--factory-space-base);
}

/* --- Reduced motion ------------------------------------------------------ */
/* WCAG 2.3.3. Placed last on purpose: every rule above is a single class
 * selector, so with prefers-reduced-motion's own selectors carrying equal
 * specificity, only the one appearing later in source order actually wins.
 * A reduced-motion block earlier in the file would be silently overridden by
 * the base `transition:` declaration that follows it — this has to enumerate
 * every transitioning selector in the file and come after all of them. */

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }

  .publicsite-link,
  .publicsite-cta,
  .publicsite-navlink,
  .publicsite-iconbutton,
  .publicsite-skip-link {
    transition: none;
  }
}
