/* ==========================================================================
   Vyte marketing site stylesheet.

   Transcribed from the Claude Design export "Vyte Website.dc.html", a
   read-only reference kept outside this repository. This file is added to
   by later tasks: Task 3 appends the home page section rules and Task 4
   appends the remaining six pages. See the section boundary comment at the
   end of this file, which is where they append.

   Every colour, size and spacing value that has a matching custom property
   below is consumed through that property. The :root block is the only
   place a hex colour literal may appear anywhere in this repository.
   ========================================================================== */

:root {
  /* Core palette. */
  --ink: #0b0c0e;
  --bone: #f4f3ef;
  --grey-1: #55575a;
  --grey-2: #9a9c9e;
  --grey-3: #3c3e40;
  --paper: #edebe5;
  --accent: #3dff8c;
  --accent-dim: rgba(61, 255, 140, 0.35);
  --error: #e24b4a;

  /* Hairline and rule scale: bone variants sit on dark (ink) surfaces,
     ink variants sit on light (bone/paper) surfaces. */
  --hair-bone: rgba(244, 243, 239, 0.16);
  --hair-bone-2: rgba(244, 243, 239, 0.32);
  --rule-bone: rgba(244, 243, 239, 0.9);
  --bar-bone: rgba(244, 243, 239, 0.22);
  --hair-ink: rgba(11, 12, 14, 0.16);
  --hair-ink-2: rgba(11, 12, 14, 0.3);
  --hair-ink-3: rgba(11, 12, 14, 0.55);
  --rule-ink: rgba(11, 12, 14, 0.9);
  --bar-ink: rgba(11, 12, 14, 0.22);
  --wash-ink: rgba(11, 12, 14, 0.04);

  /* Type scale: fixed sizes for small labels, fluid clamp() sizes for
     headings and display type. */
  --fs-0: 9px;
  --fs-1: 10px;
  --fs-2: 11px;
  --fs-3: 12px;
  --fs-4: 13px;
  --fs-5: 14px;
  --fs-6: 15px;
  --fs-7: 16px;
  --fs-h3s: 20px;
  --fs-h3: 22px;
  --fs-word: 26px;
  --fs-h3l: clamp(26px, 3vw, 40px);
  --fs-h2s: clamp(30px, 4vw, 56px);
  --fs-h2: clamp(34px, 5vw, 68px);
  --fs-quote1: clamp(28px, 4.5vw, 60px);
  --fs-quote2: clamp(30px, 5vw, 72px);
  --fs-cta2: clamp(36px, 6vw, 88px);
  --fs-cta1: clamp(40px, 7vw, 104px);
  --fs-h1s: clamp(44px, 7vw, 110px);
  --fs-h1: clamp(44px, 8vw, 128px);
  --fs-hero: clamp(40px, 10.5vw, 172px);
  --fs-lead: clamp(15px, 1.4vw, 17px);
  --fs-lead-lg: clamp(15px, 1.4vw, 18px);

  /* Spacing scale: fluid clamp() values used for section and component
     spacing throughout every page. */
  --sp-x: clamp(24px, 5vw, 64px);
  --sp-head: clamp(28px, 4vw, 48px);
  --sp-gap: clamp(32px, 5vw, 72px);
  --sp-gap-sm: clamp(24px, 4vw, 64px);
  --sp-sec: clamp(56px, 9vw, 120px);
  --sp-sec-lg: clamp(56px, 9vw, 128px);
  --sp-hero-top: clamp(64px, 10vw, 140px);
  --sp-hero-btm: clamp(48px, 7vw, 88px);
  --sp-band: clamp(72px, 11vw, 140px);
  --sp-band-lg: clamp(72px, 12vw, 160px);
  --sp-foot: clamp(40px, 6vw, 72px);

  /* Motion easing. */
  --ease-out: cubic-bezier(0,0,0.2,1);

  /* Tick marks and hairline glow used by the grid textures below. */
  --tick-bone: rgba(244, 243, 239, 0.08);
  --gl-bone: rgba(244, 243, 239, 0.03);
  --gl-ink: rgba(11, 12, 14, 0.03);

  /* Grid line textures used as background-image on dark (ink) surfaces. */
  --grid-ink-img: linear-gradient(var(--tick-bone),var(--tick-bone)),linear-gradient(var(--tick-bone),var(--tick-bone)),linear-gradient(var(--tick-bone),var(--tick-bone)),linear-gradient(var(--tick-bone),var(--tick-bone)),linear-gradient(var(--tick-bone),var(--tick-bone)),linear-gradient(var(--tick-bone),var(--tick-bone)),linear-gradient(var(--tick-bone),var(--tick-bone)),linear-gradient(var(--tick-bone),var(--tick-bone)),linear-gradient(var(--gl-bone) 1px,transparent 1px),linear-gradient(90deg,var(--gl-bone) 1px,transparent 1px);
  --grid-ink-size: 9px 1px,1px 9px,9px 1px,1px 9px,9px 1px,1px 9px,9px 1px,1px 9px,64px 64px,64px 64px;
  --grid-ink-pos: 4px 8px,8px 4px,calc(100% - 13px) 8px,calc(100% - 9px) 4px,4px calc(100% - 9px),8px calc(100% - 13px),calc(100% - 13px) calc(100% - 9px),calc(100% - 9px) calc(100% - 13px),0 0,0 0;
  --grid-ink-rep: no-repeat,no-repeat,no-repeat,no-repeat,no-repeat,no-repeat,no-repeat,no-repeat,repeat,repeat;
  --grid-bone-img: linear-gradient(var(--gl-ink) 1px,transparent 1px),linear-gradient(90deg,var(--gl-ink) 1px,transparent 1px);

  /* Outer ring of the focus indicator. Not from the export: added for WCAG
     1.4.11, since the accent ring alone is 1.19:1 against --bone. It is
     always the opposite of the surface it sits on. The document background
     is --ink, so --bone is the default and light sections override it. */
  /* Trailing space. A section's bottom padding is deliberately one step
     below its top padding so the space after content reads as a settle
     rather than as a layout that ran out. Content sections use --sp-trail,
     centred display and CTA bands use --sp-trail-lg. */
  --sp-trail: clamp(40px, 6vw, 84px);
  --sp-trail-lg: clamp(56px, 8vw, 112px);

  --focus-halo: var(--bone);
}

/* ==========================================================================
   Base and component rules, transcribed verbatim from the design export,
   lines 48 to 102. Selectors, declarations, !important flags and media
   query conditions are unchanged from the export; only whitespace and line
   breaks differ from its minified single-line form, for readability.
   ========================================================================== */

html {
  scroll-behavior: auto;
}

body {
  margin: 0;
  background: var(--ink);
  color: var(--bone);
  font-family: Archivo, sans-serif;
  -webkit-font-smoothing: antialiased;
}

a {
  color: inherit;
  text-decoration: none;
  transition: color 200ms var(--ease-out), background-color 200ms var(--ease-out), border-color 200ms var(--ease-out), transform 200ms var(--ease-out), filter 200ms var(--ease-out);
}

a:hover {
  color: var(--grey-2);
}

:focus {
  outline: none;
}

/* WCAG 1.4.11. The accent ring alone is 1.19:1 against --bone, so on light
   sections it was not discernible. The accent stays the focus colour; an
   outer ring carries the contrast. --focus-halo defaults to --ink for light
   surfaces and is switched to --bone on dark ones, so the halo is always the
   opposite of whatever it sits on. */
:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  box-shadow: 0 0 0 4px var(--focus-halo);
}

input,
textarea {
  outline: none;
  transition: border-color 200ms var(--ease-out), box-shadow 200ms var(--ease-out);
}

input:focus-visible,
textarea:focus-visible {
  outline: none;
}

.v-und {
  background-image: linear-gradient(var(--accent), var(--accent));
  background-repeat: no-repeat;
  background-size: 0% 1px;
  background-position: left bottom;
  transition: background-size 200ms var(--ease-out), color 200ms var(--ease-out);
}

.v-und:hover {
  background-size: 100% 1px;
}

.v-arw {
  display: inline-block;
  transition: transform 200ms var(--ease-out);
}

a:hover .v-arw {
  transform: translateX(4px);
}

.v-lb {
  transition: color 200ms var(--ease-out);
}

.v-rl,
.v-rd {
  transition: border-color 200ms var(--ease-out);
}

.v-rl:hover {
  border-color: var(--hair-ink-2);
}

.v-rl:hover .v-lb {
  color: var(--ink);
}

.v-rd:hover {
  border-color: var(--hair-bone-2);
}

.v-rd:hover .v-lb {
  color: var(--bone);
}

[data-pcard] [data-pline] {
  opacity: 0.65;
  transition: transform 600ms var(--ease-out), opacity 200ms var(--ease-out);
}

[data-pcard]:hover [data-pline] {
  opacity: 1;
}

.v-field label {
  transition: color 200ms var(--ease-out);
}

.v-field:focus-within label {
  color: var(--accent);
}

@media (pointer: fine) and (prefers-reduced-motion: no-preference) {
  body.v-cur,
  body.v-cur a {
    cursor: none;
  }

  body.v-cur input,
  body.v-cur textarea {
    cursor: text;
  }
}

::selection {
  background: var(--grey-2);
  color: var(--ink);
}

@media (max-width: 1100px) {
  #vyte-ticker,
  #vyte-prov {
    display: none !important;
  }
}

a:active {
  opacity: 0.8;
}

@media (max-width: 767.98px) {
  #vyte-links {
    display: none !important;
  }

  #vyte-burger {
    display: flex !important;
  }

  #vyte-flow {
    padding-top: 0 !important;
    padding-left: 30px !important;
  }

  #vyte-flow-h {
    display: none !important;
  }

  #vyte-flow-v {
    display: block !important;
  }

  #vyte-flow-steps {
    grid-template-columns: 1fr !important;
  }

  #vyte-footgrid {
    grid-template-columns: 1fr !important;
  }

  #vyte-footgrid a,
  #vyte-footlegal a {
    padding-top: 12px !important;
    padding-bottom: 12px !important;
  }

  #vyte-send {
    display: block !important;
    width: 100% !important;
    text-align: center !important;
    box-sizing: border-box !important;
  }

  #vyte-specs > div {
    border-right: none !important;
    border-bottom: 1px solid var(--hair-bone);
  }

  #vyte-specs > div:last-child {
    border-bottom: none;
  }

  .v-rl,
  .v-rd {
    flex-direction: column !important;
    gap: 6px !important;
    align-items: flex-start !important;
  }

  .v-rl > *:last-child,
  .v-rd > *:last-child {
    text-align: left !important;
  }

  #vyte-nums {
    grid-template-columns: 1fr 1fr !important;
  }

  #vyte-nums [data-num-val] {
    font-size: 32px !important;
  }

  #vyte-nums > div:nth-child(2) {
    border-right: none !important;
  }

  #vyte-nums > div:nth-child(n+3) {
    border-top: 1px solid rgba(244,243,239,0.14);
  }
}

@media (min-width: 768px) {
  #vyte-menu {
    display: none !important;
  }
}

@media (max-width: 479.98px) {
  #vyte-nav {
    padding: 0 14px !important;
    gap: 10px !important;
  }

  #vyte-cta {
    font-size: 10px !important;
    letter-spacing: 0.04em !important;
    padding: 12px 9px !important;
  }

  #vyte-nums {
    grid-template-columns: 1fr !important;
  }

  #vyte-nums > div {
    border-right: none !important;
  }

  #vyte-nums > div:nth-child(n+2) {
    border-top: 1px solid rgba(244,243,239,0.14);
  }
}

@media (max-width: 559.98px) {
  #vyte-demo-track {
    flex-direction: column !important;
    align-items: stretch !important;
    gap: 18px !important;
  }

  #vyte-demo-track [data-rail] {
    top: 7px !important;
    bottom: 7px !important;
    left: 7px !important;
    right: auto !important;
    width: 1px !important;
    height: auto !important;
  }

  #vyte-demo-track > div {
    flex-direction: row !important;
    align-items: center !important;
    gap: 14px !important;
  }

  #vyte-demo-track > div span:last-child {
    text-align: left !important;
  }
}

@media (pointer: coarse) {
  #vyte-footgrid a,
  #vyte-footlegal a {
    padding-top: 12px !important;
    padding-bottom: 12px !important;
  }
}

@media (prefers-reduced-motion: reduce) {
  * {
    animation: none !important;
    transition: none !important;
  }
}

/* ==========================================================================
   Shared chrome: fixed navigation bar.

   Markup transcribed from export lines 106 to 116. #vyte-nav, #vyte-links,
   #vyte-cta and #vyte-burger keep their original ids because the media
   queries above target those ids directly; the classes below carry the
   visual styling the inline style="" attributes used to.
   ========================================================================== */

.nav {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 100;
  height: 60px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 0 clamp(16px, 4vw, 48px);
  background: var(--ink);
  border-bottom: 1px solid transparent;
  transition: border-color 300ms var(--ease-out);
}

.nav__brand {
  font-family: Oswald, sans-serif;
  font-size: var(--fs-h3);
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--bone);
  cursor: pointer;
  line-height: 1;
}

.nav__brand:hover {
  color: var(--grey-2);
}

.nav__group {
  display: flex;
  align-items: center;
  gap: clamp(12px, 2.5vw, 32px);
}

.nav__links {
  display: flex;
  align-items: center;
  gap: clamp(12px, 2.5vw, 32px);
}

.nav__link {
  display: flex;
  align-items: center;
  gap: 7px;
  font-family: 'IBM Plex Mono', monospace;
  font-size: var(--fs-3);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--grey-2);
  cursor: pointer;
  padding: 14px 0;
  background-position: left calc(100% - 10px);
}

.nav__link:hover {
  color: var(--bone);
}

.nav__link-dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--accent);
}

.nav__cta {
  font-family: Archivo, sans-serif;
  font-size: var(--fs-3);
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink);
  background: var(--accent);
  padding: 16px 18px;
  cursor: pointer;
  white-space: nowrap;
}

.nav__cta:hover {
  filter: brightness(1.08);
  transform: translateY(-1px);
}

.nav__cta:active {
  filter: brightness(1);
  transform: translateY(0);
}

/* #vyte-burger is a real <button> (export line 114 is an <a>, but an
   anchor is keyboard-incomplete as a toggle control: Enter fires click,
   Space does not, and href="#" pushes a history entry). The first six
   declarations undo native button chrome so the rendered result matches
   the export's anchor-based appearance exactly. */
.nav__burger {
  appearance: none;
  background: transparent;
  border: none;
  padding: 0;
  font: inherit;
  color: inherit;
  display: none;
  width: 44px;
  height: 44px;
  margin: 0 -6px;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  flex: none;
}

.nav__burger-icon {
  display: flex;
  flex-direction: column;
  gap: 5px;
}

.nav__burger-bar {
  width: 20px;
  height: 2px;
  background: var(--bone);
}

/* Resting state is hidden. Task 9 (burger menu and scroll lock) toggles
   this to display:block, matching the export's own declared value, when
   the menu is open, and hides .nav__burger-icon in turn. */
.nav__burger-icon--open {
  display: none;
  position: relative;
  width: 20px;
  height: 20px;
}

/* Task 9: src/app.ts toggles .nav__burger--open on #vyte-burger itself,
   which swaps the resting three-bar icon for the cross above. */
.nav__burger--open .nav__burger-icon {
  display: none;
}

.nav__burger--open .nav__burger-icon--open {
  display: block;
}

.nav__burger-bar--a {
  position: absolute;
  top: 9px;
  left: 0;
  width: 20px;
  height: 2px;
  background: var(--bone);
  transform: rotate(45deg);
}

.nav__burger-bar--b {
  position: absolute;
  top: 9px;
  left: 0;
  width: 20px;
  height: 2px;
  background: var(--bone);
  transform: rotate(-45deg);
}

/* ==========================================================================
   Shared chrome: mobile menu overlay.

   Markup transcribed from export lines 119 to 130. #vyte-menu keeps its
   original id: it is forced hidden on desktop by the min-width:768px rule
   above. On narrow viewports it is hidden by default here (mobile-first);
   Task 9 shows it (display:flex, matching the export's own declared value)
   when the burger is activated.
   ========================================================================== */

.menu {
  display: none;
  position: fixed;
  top: 60px;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 99;
  background: var(--ink);
  flex-direction: column;
  justify-content: space-between;
  gap: 32px;
  padding: clamp(24px, 6vh, 48px) var(--sp-x) 28px;
  overflow: auto;
}

/* Task 9: src/app.ts toggles this modifier via classList when the burger
   opens the menu, matching the export's own declared display:flex value.
   The min-width:768px rule below carries !important, so this can never
   show the menu at desktop widths even if the class is somehow left set. */
.menu--open {
  display: flex;
}

.menu__links {
  display: flex;
  flex-direction: column;
}

.menu__link {
  display: flex;
  align-items: center;
  gap: 14px;
  font-family: Oswald, sans-serif;
  font-weight: 600;
  text-transform: uppercase;
  font-size: clamp(32px, 9vw, 44px);
  line-height: 1.15;
  color: var(--bone);
  padding: 14px 0;
  cursor: pointer;
  border-bottom: 1px solid var(--hair-bone);
}

.menu__link:first-child {
  border-top: 1px solid var(--hair-bone);
}

.menu__link-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--accent);
  flex: none;
}

.menu__meta {
  display: flex;
  flex-direction: column;
  gap: 14px;
}

.menu__email {
  font-family: 'IBM Plex Mono', monospace;
  font-size: var(--fs-4);
  letter-spacing: 0.08em;
  color: var(--grey-2);
  width: fit-content;
  padding: 6px 0;
}

.menu__copy {
  font-family: 'IBM Plex Mono', monospace;
  font-size: var(--fs-2);
  letter-spacing: 0.1em;
  color: var(--grey-2);
}

/* ==========================================================================
   Shared chrome: film grain overlay.

   Markup transcribed from export line 133. The background-image is a
   data-URI SVG noise filter, kept exactly as exported: it carries no colour
   and has no matching custom property.
   ========================================================================== */

.grain {
  position: fixed;
  inset: 0;
  z-index: 200;
  pointer-events: none;
  opacity: 0.025;
  background-size: 240px 240px;
  background-image: url(data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='240'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='240' height='240' filter='url(%23n)'/%3E%3C/svg%3E);
}

/* ==========================================================================
   Shared chrome: boot intro overlay.

   Markup transcribed from export lines 135 to 137. Two independent removal
   paths exist for the overlay: Task 11 adds a JavaScript timer that removes
   it in the normal case, and the intro-failsafe animation below removes it
   after 2 seconds regardless, even if that script throws. Both must exist.

   Under prefers-reduced-motion:reduce the intro is gated off entirely by
   Task 11's script (it never gains the --on modifier), so the failsafe
   animation is never needed there; the global reduced-motion rule above
   would disable it in any case.
   ========================================================================== */

.intro {
  display: none;
  position: fixed;
  inset: 0;
  z-index: 400;
  background: var(--ink);
  transition: transform 400ms var(--ease-out);
}

.intro--on {
  display: block;
  animation: intro-failsafe 2s step-end forwards;
}

@keyframes intro-failsafe {
  to {
    visibility: hidden;
    pointer-events: none;
  }
}

.intro__lines {
  position: absolute;
  left: var(--sp-x);
  bottom: var(--sp-x);
  display: flex;
  flex-direction: column;
  gap: 12px;
  font-family: 'IBM Plex Mono', monospace;
  font-size: var(--fs-3);
  letter-spacing: 0.1em;
  color: var(--grey-2);
}

/* ==========================================================================
   Shared chrome: custom cursor ring and dot.

   Markup transcribed from export lines 138 to 139. Only shown once Task 11
   adds body.v-cur under (pointer:fine) and
   (prefers-reduced-motion:no-preference), per the cursor rule already
   transcribed in the base rules above.
   ========================================================================== */

.cursor-ring {
  display: none;
  opacity: 0;
  position: fixed;
  left: 0;
  top: 0;
  width: 28px;
  height: 28px;
  margin: -14px 0 0 -14px;
  border-radius: 50%;
  border: 1px solid var(--bone);
  z-index: 300;
  pointer-events: none;
  transition: transform 120ms var(--ease-out), width 200ms var(--ease-out), height 200ms var(--ease-out), margin 200ms var(--ease-out), border-color 200ms var(--ease-out), opacity 200ms var(--ease-out);
}

.cursor-dot {
  display: none;
  opacity: 0;
  position: fixed;
  left: 0;
  top: 0;
  width: 6px;
  height: 6px;
  margin: -3px 0 0 -3px;
  border-radius: 50%;
  background: var(--bone);
  z-index: 301;
  pointer-events: none;
  transition: opacity 200ms var(--ease-out);
}

/* ==========================================================================
   Shared chrome: footer.

   Markup transcribed from export lines 774 to 802. #vyte-footgrid and
   #vyte-footlegal keep their original ids because the media queries above
   target those ids directly.
   ========================================================================== */

.footer {
  background: var(--ink);
  background-image: var(--grid-ink-img);
  background-size: var(--grid-ink-size);
  background-position: var(--grid-ink-pos);
  background-repeat: var(--grid-ink-rep);
  color: var(--bone);
  border-top: 1px solid var(--hair-bone);
  padding: var(--sp-foot) var(--sp-x) 28px;
}

.footer__grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: var(--sp-head);
  margin-bottom: var(--sp-foot);
}

.footer__brand {
  font-family: Oswald, sans-serif;
  font-size: var(--fs-word);
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  margin-bottom: 14px;
}

.footer__tagline {
  font-family: 'IBM Plex Mono', monospace;
  font-size: var(--fs-2);
  letter-spacing: 0.1em;
  color: var(--grey-2);
  line-height: 1.8;
}

.footer__col {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.footer__col-title {
  font-family: 'IBM Plex Mono', monospace;
  font-size: var(--fs-2);
  letter-spacing: 0.14em;
  color: var(--grey-2);
  margin-bottom: 4px;
}

.footer__link {
  font-size: var(--fs-5);
  color: var(--grey-2);
  cursor: pointer;
  width: fit-content;
  padding: 4px 0;
}

.footer__link:hover {
  color: var(--bone);
}

.footer__email {
  font-family: 'IBM Plex Mono', monospace;
  font-size: var(--fs-4);
  color: var(--grey-2);
  width: fit-content;
  padding: 4px 0;
}

.footer__email:hover {
  color: var(--bone);
}

.footer__legal {
  display: flex;
  flex-wrap: wrap;
  gap: clamp(16px, 4vw, 40px);
  border-top: 1px solid var(--hair-bone);
  padding: 12px 0;
  font-family: 'IBM Plex Mono', monospace;
  font-size: var(--fs-2);
  letter-spacing: 0.06em;
}

.footer__legal-link {
  color: var(--grey-2);
  cursor: pointer;
  padding: 4px 0;
}

.footer__legal-link:hover {
  color: var(--bone);
}

.footer__bottom {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 12px;
  border-top: 1px solid var(--hair-bone);
  padding-top: 20px;
  font-family: 'IBM Plex Mono', monospace;
  font-size: var(--fs-2);
  letter-spacing: 0.06em;
  color: var(--grey-2);
}

/* ==========================================================================
   End of Task 2.

   Tasks 3 and 4 append their own page-section rules below this line: home
   page sections first (Task 3), then the remaining six pages and 404 (Task
   4). Nothing above this line should need to change for that work.
   ========================================================================== */

/* ==========================================================================
   Home page: shared utilities.

   These classes cover declaration sets that repeat, byte-for-byte in the
   export, across more than one home section (the two full-bleed grid
   textures, the "01 / label" eyebrow row, section headings, the accent and
   ghost button treatments, and the three sketch-frame previews). Each is
   combined with a section-specific class in markup rather than duplicated.
   ========================================================================== */

.grid-ink {
  background: var(--ink);
  background-image: var(--grid-ink-img);
  background-size: var(--grid-ink-size);
  background-position: var(--grid-ink-pos);
  background-repeat: var(--grid-ink-rep);
}

.grid-bone {
  background: var(--bone);
  background-image: var(--grid-bone-img);
  background-size: 64px 64px;
  /* Light surface: the focus halo flips to ink so it stays the opposite of
     its background. Inherits to every descendant of the section. */
  --focus-halo: var(--ink);
}

/* Dark panels nested inside a light section flip the halo back, otherwise an
   ink halo would sit invisibly on an ink panel. */
.pf-fig3,
.wl-card--dark {
  --focus-halo: var(--bone);
}

/* Export lines 206-209, 233-236, 261-264, 329-332: the numbered eyebrow row
   ("01 / The problem" and so on) repeated at the top of every home section.
   Order flow (259-325) sits on an ink background, so its eyebrow row uses
   the accent/bone colour variant via the --on-ink modifier; the rest sit on
   bone and use the default ink/grey-1 variant. */
.eyebrow {
  display: flex;
  align-items: baseline;
  gap: 18px;
  border-top: 1px solid var(--rule-ink);
  padding-top: 14px;
  margin-bottom: var(--sp-head);
}

.eyebrow--on-ink {
  border-top-color: var(--rule-bone);
}

.eyebrow__num {
  font-family: 'IBM Plex Mono', monospace;
  font-size: var(--fs-4);
  color: var(--ink);
}

.eyebrow--on-ink .eyebrow__num {
  color: var(--accent);
}

.eyebrow__label {
  font-family: 'IBM Plex Mono', monospace;
  font-size: var(--fs-3);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--grey-1);
}

.eyebrow--on-ink .eyebrow__label {
  color: var(--grey-2);
}

/* Shared heading treatment for the problem, platform and order flow
   section headings (export 210, 237, 265) and the security heading (334),
   which needs no override. Each section's margin-bottom/max-width differ
   slightly, so they are added as a second class alongside this base. */
.h2 {
  margin: 0;
  font-family: Oswald, sans-serif;
  font-weight: 600;
  text-transform: uppercase;
  font-size: var(--fs-h2);
  line-height: 1;
  text-wrap: balance;
}

/* Export lines 159/320/321/350: the accent-bordered and ghost-bordered
   button treatments reused by the hero primary CTA, the lifecycle demo's
   run/cancel buttons and the CTA band button. Padding differs per usage,
   so it is added by a second, more specific class in markup. */
.btn-accent {
  font-family: Archivo, sans-serif;
  font-size: var(--fs-5);
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--bone);
  background: transparent;
  border: 1px solid var(--accent);
  cursor: pointer;
}

.btn-accent:hover {
  background: var(--accent);
  color: var(--ink);
}

.btn-accent:active {
  transform: translateY(1px);
}

.btn-ghost {
  font-family: Archivo, sans-serif;
  font-size: var(--fs-5);
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--bone);
  background: transparent;
  border: 1px solid var(--hair-bone-2);
  cursor: pointer;
}

.btn-ghost:hover {
  background: var(--bone);
  color: var(--ink);
}

.btn-ghost:active {
  transform: translateY(1px);
}

/* Export lines 241/246/251/349: the three sketch-frame previews (student
   app, kitchen display, management dashboard), reused unchanged in both
   the platform section and the CTA band. */
.frame {
  aspect-ratio: 16 / 10;
  background: var(--ink);
  border: 1px solid var(--grey-3);
  position: relative;
  overflow: hidden;
  transition: border-color 200ms var(--ease-out);
}

.frame:hover {
  border-color: var(--accent-dim);
}

.frame__label {
  position: absolute;
  top: 10px;
  left: 12px;
  font-family: 'IBM Plex Mono', monospace;
  font-size: var(--fs-0);
  letter-spacing: 0.16em;
  color: var(--grey-2);
}

.frame__sketch {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}

/* ==========================================================================
   Home page: shared page wrapper.

   Export line 142: every page's content sits in a wrapper offset by the
   fixed nav's height. Reused unchanged by Task 4's six remaining pages.
   ========================================================================== */

.page {
  padding-top: 60px;
}

/* ==========================================================================
   Home page: hero.

   Markup transcribed from export lines 144 to 164. The ticker list (150 to
   152) renders as an empty container here; src/app.ts (Task 6) builds its
   rows.
   ========================================================================== */

.hero {
  min-height: calc(100vh - 60px);
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  padding: var(--sp-x);
  position: relative;
  overflow: hidden;
}

.hero__label {
  position: absolute;
  top: clamp(24px, 5vw, 56px);
  left: var(--sp-x);
  display: flex;
  align-items: center;
  gap: 12px;
  font-family: 'IBM Plex Mono', monospace;
  font-size: var(--fs-3);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--grey-2);
}

.hero__label-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--accent);
}

.hero__ticker {
  position: absolute;
  top: 22%;
  right: var(--sp-x);
  width: 320px;
  display: flex;
  flex-direction: column;
  gap: 14px;
  opacity: 0.5;
  pointer-events: none;
}

.hero__body {
  position: relative;
}

.hero__title {
  margin: 0 0 28px;
  font-family: Oswald, sans-serif;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: -0.005em;
  font-size: var(--fs-hero);
  line-height: 0.94;
  color: var(--bone);
  max-width: 14ch;
  text-wrap: balance;
}

.hero__foot {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: space-between;
  gap: 28px;
  border-top: 1px solid var(--hair-bone);
  padding-top: 28px;
}

.hero__lead {
  margin: 0;
  max-width: 52ch;
  font-size: var(--fs-lead-lg);
  line-height: 1.6;
  color: var(--grey-2);
}

.hero__ctas {
  display: flex;
  align-items: center;
  gap: 24px;
  flex-wrap: wrap;
}

.hero__cta-primary {
  padding: 15px 29px;
  white-space: nowrap;
}

/* Export line 160: mono, not Archivo, so self-contained rather than
   combined with .btn-accent (which sets a conflicting font-family). */
.hero__cta-secondary {
  font-family: 'IBM Plex Mono', monospace;
  font-size: var(--fs-4);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--bone);
  border: 1px solid var(--accent);
  padding: 15px 24px;
  cursor: pointer;
}

.hero__cta-secondary:hover {
  background: var(--accent);
  color: var(--ink);
}

.hero__cta-secondary:active {
  transform: translateY(1px);
}

/* ==========================================================================
   Home page: numbers strip.

   Markup transcribed from export lines 166 to 183. #vyte-nums keeps its
   original id and data-numstrip="1": both are targeted by media queries
   above and by src/app.ts (Task 5).
   ========================================================================== */

.numstrip {
  border-top: 1px solid var(--hair-bone);
  display: grid;
  grid-template-columns: repeat(4, 1fr);
}

.numstrip__item {
  padding: clamp(24px, 3.5vw, 40px) clamp(24px, 4vw, 48px);
  border-right: 1px solid rgba(244, 243, 239, 0.14);
}

.numstrip__item:last-child {
  border-right: none;
}

.numstrip__value-wrap {
  display: inline-flex;
  flex-direction: column;
  gap: 8px;
  margin-bottom: 14px;
}

.numstrip__value {
  font-family: Oswald, sans-serif;
  font-weight: 600;
  font-size: 48px;
  line-height: 1;
  color: var(--bone);
}

.numstrip__line {
  display: block;
  height: 1px;
  background: var(--accent);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 600ms var(--ease-out);
}

.numstrip__caption {
  font-family: 'IBM Plex Mono', monospace;
  font-size: 11px;
  letter-spacing: 0.08em;
  color: var(--grey-2);
  line-height: 1.6;
}

/* ==========================================================================
   Home page: specs strip.

   Markup transcribed from export lines 185 to 202. #vyte-specs keeps its
   original id: the 767.98px media query above targets it.
   ========================================================================== */

.specs {
  border-top: 1px solid var(--hair-bone);
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
}

.specs__item {
  padding: clamp(20px, 3vw, 32px) clamp(24px, 4vw, 48px);
  border-right: 1px solid var(--hair-bone);
}

.specs__item:last-child {
  border-right: none;
}

.specs__eyebrow {
  font-family: 'IBM Plex Mono', monospace;
  font-size: var(--fs-2);
  letter-spacing: 0.12em;
  color: var(--grey-2);
  margin-bottom: 10px;
}

.specs__title {
  font-family: 'IBM Plex Mono', monospace;
  font-size: var(--fs-4);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--bone);
  line-height: 1.5;
}

/* ==========================================================================
   Home page: the problem.

   Markup transcribed from export lines 204 to 229.
   ========================================================================== */

.problem {
  padding: var(--sp-sec-lg) var(--sp-x) var(--sp-trail);
  color: var(--ink);
}

.problem__heading {
  margin-bottom: clamp(40px, 6vw, 80px);
  max-width: 20ch;
}

.problem__grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: clamp(28px, 4vw, 56px);
}

.problem__card {
  position: relative;
  padding-top: 20px;
}

.problem__card-rule {
  position: absolute;
  top: 0;
  left: 0;
  height: 1px;
  width: 100%;
  background: var(--hair-ink);
}

/* [data-pcard] [data-pline] above (export 66-67, verbatim base rules)
   already supplies the opacity and its hover transition; this class adds
   only the positioning and colour export line 212 also carries. */
.problem__card-progress {
  position: absolute;
  top: 0;
  left: 0;
  height: 1px;
  width: 100%;
  background: var(--accent);
  transform: scaleX(0);
  transform-origin: left;
}

.problem__card-title {
  margin: 0 0 12px;
  font-family: Oswald, sans-serif;
  font-weight: 500;
  text-transform: uppercase;
  font-size: var(--fs-h3);
  letter-spacing: 0.02em;
}

.problem__card-text {
  margin: 0;
  font-size: var(--fs-6);
  line-height: 1.65;
  color: var(--grey-3);
}

.problem__card-stat {
  margin-top: 20px;
  width: fit-content;
  border-bottom: 2px solid var(--accent);
  padding-bottom: 6px;
}

.problem__card-stat-value {
  font-family: 'IBM Plex Mono', monospace;
  font-size: var(--fs-h3);
  letter-spacing: 0.04em;
}

/* ==========================================================================
   Home page: the platform.

   Markup transcribed from export lines 231 to 257.
   ========================================================================== */

.platform {
  padding: 0 var(--sp-x) var(--sp-trail);
  color: var(--ink);
}

.platform__heading {
  margin-bottom: var(--sp-foot);
  max-width: 22ch;
}

.platform__grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(290px, 100%), 1fr));
  gap: clamp(24px, 3vw, 40px);
}

.platform__caption {
  margin-top: 18px;
  display: flex;
  align-items: baseline;
  gap: 12px;
}

.platform__letter {
  font-family: 'IBM Plex Mono', monospace;
  font-size: var(--fs-2);
  color: var(--grey-1);
}

.platform__card-title {
  margin: 0 0 6px;
  font-family: Oswald, sans-serif;
  font-weight: 500;
  text-transform: uppercase;
  font-size: var(--fs-h3s);
}

.platform__card-text {
  margin: 0;
  font-size: var(--fs-5);
  line-height: 1.6;
  color: var(--grey-3);
}

/* ==========================================================================
   Home page: order flow and lifecycle demo.

   Markup transcribed from export lines 259 to 325. #vyte-flow, #vyte-flow-h,
   #vyte-flow-v, #vyte-flow-steps and #vyte-demo-track keep their original
   ids: the media queries above target them directly. The demo nodes list
   (sc-for at 311 to 316) renders as an empty container here; src/app.ts
   (Task 8) builds its children.
   ========================================================================== */

.order-flow {
  color: var(--bone);
  padding: var(--sp-sec-lg) var(--sp-x) var(--sp-trail);
  border-top: 1px solid var(--hair-bone);
}

.flow-heading {
  margin-bottom: var(--sp-hero-btm);
  max-width: 22ch;
}

.flow {
  position: relative;
  padding-top: 40px;
}

.flow__rail-h {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 14px;
  overflow: visible;
  display: block;
}

.flow__rail-v {
  display: none;
  position: absolute;
  top: 0;
  left: 0;
  width: 14px;
  height: 100%;
  overflow: visible;
}

.flow__dot {
  position: absolute;
  top: 3px;
  left: 0;
  width: 9px;
  height: 9px;
  margin-left: -4px;
  border-radius: 50%;
  background: var(--accent);
  box-shadow: 0 0 14px var(--accent-dim);
  opacity: 0;
}

.flow__steps {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: clamp(20px, 3vw, 40px);
}

.flow__step {
  border-left: 1px solid var(--hair-bone-2);
  padding-left: 18px;
}

.flow__step-num {
  font-family: 'IBM Plex Mono', monospace;
  font-size: var(--fs-2);
  letter-spacing: 0.12em;
  color: var(--grey-2);
  margin-bottom: 12px;
}

.flow__step-title {
  margin: 0 0 10px;
  font-family: Oswald, sans-serif;
  font-weight: 500;
  text-transform: uppercase;
  font-size: var(--fs-h3);
}

.flow__step-detail {
  font-family: 'IBM Plex Mono', monospace;
  font-size: var(--fs-2);
  line-height: 1.8;
  color: var(--grey-2);
  letter-spacing: 0.04em;
}

.demo {
  margin-top: clamp(36px, 5vw, 64px);
  border-top: 1px solid var(--hair-bone);
  padding-top: clamp(28px, 4vw, 44px);
}

.demo__eyebrow {
  font-family: 'IBM Plex Mono', monospace;
  font-size: var(--fs-2);
  letter-spacing: 0.12em;
  color: var(--grey-2);
  margin-bottom: 32px;
}

.demo__track {
  position: relative;
  display: flex;
  align-items: flex-start;
  margin-bottom: 28px;
}

.demo__rail {
  position: absolute;
  top: 7px;
  left: 10%;
  right: 10%;
  height: 1px;
  background: var(--grey-3);
}

.demo__status {
  font-family: 'IBM Plex Mono', monospace;
  font-size: var(--fs-3);
  letter-spacing: 0.08em;
  color: var(--grey-2);
  min-height: 1.7em;
  margin-bottom: 24px;
}

.demo__actions {
  display: flex;
  align-items: center;
  gap: 16px;
  flex-wrap: wrap;
}

/* Export line 320: opacity is driven by the dead runOp binding
   (0.6 while running, 1 at rest per the export's own component script,
   lines 1225-1228). Reproduced here against aria-disabled, which
   src/app.ts drives instead of the disabled property, so a keyboard user
   who activates this button keeps focus on it while the order runs. */
.demo__run {
  appearance: none;
  padding: 15px 29px;
  transition: opacity 200ms var(--ease-out), background-color 200ms var(--ease-out), color 200ms var(--ease-out);
}

.demo__run[aria-disabled="true"] {
  opacity: 0.6;
}

/* Export line 321: cancelOp is 1 while a cancellable order is running and
   0.4 at rest (export lines 1225-1228), reproduced the same way. */
.demo__cancel {
  appearance: none;
  padding: 15px 29px;
  transition: opacity 200ms var(--ease-out), background-color 200ms var(--ease-out), color 200ms var(--ease-out);
}

.demo__cancel:disabled {
  opacity: 0.4;
}

/* ==========================================================================
   Home page: security posture.

   Markup transcribed from export lines 327 to 344.
   ========================================================================== */

.security {
  padding: var(--sp-sec-lg) var(--sp-x) var(--sp-trail);
  color: var(--ink);
}

.security__grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(300px, 100%), 1fr));
  gap: var(--sp-gap);
  align-items: start;
}

.security__row {
  display: flex;
  justify-content: space-between;
  gap: 20px;
  align-items: baseline;
  border-top: 1px solid var(--hair-ink);
  padding: 16px 0;
}

.security__row--assurance {
  border-bottom: 1px solid var(--hair-ink);
}

.security__row-label {
  font-family: 'IBM Plex Mono', monospace;
  font-size: var(--fs-2);
  letter-spacing: 0.12em;
  color: var(--grey-1);
  min-width: 110px;
}

.security__row-value {
  font-size: var(--fs-6);
  text-align: right;
}

.security__docs-link {
  display: inline-block;
  margin-top: 28px;
  font-family: 'IBM Plex Mono', monospace;
  font-size: var(--fs-4);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink);
  border-bottom: 1px solid var(--hair-ink-3);
  padding-bottom: 3px;
  cursor: pointer;
}

.security__docs-link:hover {
  border-bottom: 1px solid var(--ink);
}

/* ==========================================================================
   Home page: CTA band.

   Markup transcribed from export lines 346 to 352.
   ========================================================================== */

.cta-band {
  padding: var(--sp-band-lg) var(--sp-x) var(--sp-trail-lg);
  border-top: 1px solid var(--hair-bone);
  text-align: center;
  color: var(--bone);
}

.cta-band__inner {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 32px;
}

.cta-band__heading {
  margin: 0;
  font-family: Oswald, sans-serif;
  font-weight: 600;
  text-transform: uppercase;
  font-size: var(--fs-cta1);
  line-height: 0.96;
  text-wrap: balance;
}

.cta-band__button {
  padding: 17px 35px;
}

/* End of Task 3. */

/* ==========================================================================
   Platform page (platform.html).

   Markup transcribed from export lines 360 to 526. The hero banner
   (.doc-hero) is shared with security.html, whose banner (export 534-538)
   is structurally identical.
   ========================================================================== */

.doc-hero {
  color: var(--bone);
  padding: var(--sp-hero-top) var(--sp-x) var(--sp-hero-btm);
}

.doc-hero__eyebrow {
  font-family: 'IBM Plex Mono', monospace;
  font-size: var(--fs-3);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--grey-2);
  margin-bottom: 24px;
}

.doc-hero__title {
  margin: 0 0 28px;
  font-family: Oswald, sans-serif;
  font-weight: 600;
  text-transform: uppercase;
  font-size: var(--fs-h1);
  line-height: 0.95;
  max-width: 16ch;
  text-wrap: balance;
}

.doc-hero__lead {
  margin: 0;
  max-width: 58ch;
  font-size: var(--fs-lead);
  line-height: 1.65;
  color: var(--grey-2);
}

/* Feature sections 01-05 (export 366-519). Bone sections use .pf-section
   with .grid-bone; ink sections use .pf-section-ink with .grid-ink. Every
   section's eyebrow row (export 368-370, 408-410, 432-434, 461-463,
   495-497) is byte-identical to the home page's eyebrow markup, so it
   reuses .eyebrow / .eyebrow__num / .eyebrow__label / .eyebrow--on-ink
   verbatim rather than duplicating them here. */
.pf-section {
  padding: var(--sp-sec) var(--sp-x) var(--sp-trail);
  color: var(--ink);
}

.pf-section-ink {
  padding: var(--sp-sec) var(--sp-x) var(--sp-trail);
  color: var(--bone);
  border-top: 1px solid var(--hair-bone);
}

.pf-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(320px, 100%), 1fr));
  gap: var(--sp-gap);
  align-items: start;
}

.pf-heading {
  margin: 0 0 24px;
  font-family: Oswald, sans-serif;
  font-weight: 600;
  text-transform: uppercase;
  font-size: var(--fs-h2s);
  line-height: 1;
  text-wrap: balance;
}

.pf-text {
  margin: 0 0 18px;
  font-size: var(--fs-6);
  line-height: 1.7;
  color: var(--grey-3);
}

.pf-text--on-ink {
  color: var(--grey-2);
}

.pf-text--tight {
  margin-bottom: 28px;
}

.pf-text--last {
  margin-bottom: 0;
}

.pf-row {
  display: flex;
  gap: 20px;
  border-top: 1px solid var(--hair-ink);
  padding: 13px 0;
}

.pf-row--last {
  border-bottom: 1px solid var(--hair-ink);
}

.pf-row-label {
  font-family: 'IBM Plex Mono', monospace;
  font-size: var(--fs-2);
  letter-spacing: 0.1em;
  color: var(--grey-1);
  min-width: 130px;
}

.pf-row-value {
  font-size: var(--fs-5);
}

.pf-dot {
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--accent);
}

/* Figure 01: student app filtering (export 383-401). */
.pf-fig1 {
  border: 1px solid var(--hair-ink-2);
  background: var(--paper);
  padding: 24px;
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.pf-fig1__head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  font-family: 'IBM Plex Mono', monospace;
  font-size: var(--fs-1);
  letter-spacing: 0.1em;
  color: var(--grey-1);
  padding-bottom: 12px;
  border-bottom: 1px solid var(--hair-ink);
}

.pf-fig1__tags {
  display: flex;
  gap: 6px;
  flex-wrap: wrap;
}

.pf-fig1__tags--bordered {
  padding-bottom: 12px;
  border-bottom: 1px solid var(--hair-ink);
}

.pf-tag {
  font-family: 'IBM Plex Mono', monospace;
  font-size: var(--fs-1);
  letter-spacing: 0.08em;
  padding: 6px 10px;
}

.pf-tag--active {
  background: var(--ink);
  color: var(--bone);
}

.pf-tag--inactive {
  border: 1px solid var(--hair-ink-2);
  color: var(--grey-3);
}

.pf-fig1__item {
  display: flex;
  justify-content: space-between;
  align-items: center;
  border: 1px solid var(--hair-ink-2);
  padding: 13px 15px;
  background: var(--bone);
}

.pf-fig1__item-title {
  font-size: var(--fs-4);
  font-weight: 600;
}

.pf-fig1__item-meta {
  font-family: 'IBM Plex Mono', monospace;
  font-size: var(--fs-0);
  color: var(--grey-1);
  margin-top: 4px;
}

.pf-fig1__item-price {
  font-family: 'IBM Plex Mono', monospace;
  font-size: var(--fs-3);
}

.pf-fig1__foot {
  display: flex;
  justify-content: space-between;
  align-items: center;
  font-family: 'IBM Plex Mono', monospace;
  font-size: var(--fs-1);
  letter-spacing: 0.08em;
  color: var(--grey-1);
}

.pf-fig1__foot-live {
  display: flex;
  align-items: center;
  gap: 6px;
}

/* Figure 02: checkout / settlement (export 413-420). Figure 04's head
   (export 467) reuses .pf-fig2__head, byte-identical between the two. */
.pf-fig2 {
  border: 1px solid var(--hair-bone);
  padding: 24px;
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.pf-fig2__head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  font-family: 'IBM Plex Mono', monospace;
  font-size: var(--fs-1);
  letter-spacing: 0.1em;
  color: var(--grey-2);
  padding-bottom: 12px;
  border-bottom: 1px solid var(--hair-bone);
}

.pf-fig2__line {
  display: flex;
  justify-content: space-between;
  font-size: var(--fs-5);
  padding: 6px 0;
}

.pf-fig2__line--divider {
  border-bottom: 1px solid var(--hair-bone);
  padding-bottom: 14px;
}

.pf-fig2__price {
  font-family: 'IBM Plex Mono', monospace;
  font-size: var(--fs-3);
}

.pf-fig2__allowance {
  display: flex;
  justify-content: space-between;
  align-items: center;
  font-family: 'IBM Plex Mono', monospace;
  font-size: var(--fs-2);
  letter-spacing: 0.08em;
  color: var(--grey-2);
  padding: 4px 0;
}

.pf-fig2__allowance-label {
  display: flex;
  align-items: center;
  gap: 8px;
}

.pf-fig2__total {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  border-top: 1px solid var(--hair-bone-2);
  padding-top: 14px;
}

.pf-fig2__total-label {
  font-family: 'IBM Plex Mono', monospace;
  font-size: var(--fs-2);
  letter-spacing: 0.1em;
  color: var(--grey-2);
}

.pf-fig2__total-value {
  font-family: 'IBM Plex Mono', monospace;
  font-size: var(--fs-h3s);
}

.pf-fig2__note {
  font-family: 'IBM Plex Mono', monospace;
  font-size: var(--fs-1);
  letter-spacing: 0.06em;
  color: var(--grey-2);
  line-height: 1.7;
  border-top: 1px solid var(--hair-bone);
  padding-top: 12px;
}

/* Figure 03: kitchen queue board (export 447-454). */
.pf-fig3 {
  border: 1px solid var(--hair-ink-2);
  background: var(--ink);
  color: var(--bone);
  padding: 24px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.pf-fig3__head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  font-family: 'IBM Plex Mono', monospace;
  font-size: var(--fs-1);
  letter-spacing: 0.1em;
  color: var(--grey-2);
  padding-bottom: 12px;
  border-bottom: 1px solid var(--hair-bone);
}

.pf-fig3__live {
  display: flex;
  align-items: center;
  gap: 6px;
}

.pf-fig3__row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  border: 1px solid var(--hair-bone);
  padding: 13px 15px;
}

.pf-fig3__id {
  font-family: 'IBM Plex Mono', monospace;
  font-size: var(--fs-3);
}

.pf-fig3__slot {
  font-family: 'IBM Plex Mono', monospace;
  font-size: var(--fs-1);
  color: var(--grey-2);
  margin-left: 12px;
}

.pf-fig3__status {
  font-family: 'IBM Plex Mono', monospace;
  font-size: var(--fs-1);
  letter-spacing: 0.08em;
}

.pf-fig3__status--dot {
  display: flex;
  align-items: center;
  gap: 6px;
}

.pf-fig3__status--muted {
  color: var(--grey-2);
}

.pf-fig3__foot {
  display: flex;
  justify-content: space-between;
  font-family: 'IBM Plex Mono', monospace;
  font-size: var(--fs-1);
  letter-spacing: 0.1em;
  color: var(--grey-2);
  border-top: 1px solid var(--hair-bone);
  padding-top: 12px;
}

/* Figure 04: management analytics bar chart (export 466-483). Bar heights
   are the export's own static percentages, not generated. */
.pf-fig4 {
  border: 1px solid var(--hair-bone);
  padding: 24px;
  display: flex;
  flex-direction: column;
  gap: 14px;
}

.pf-fig4__chart {
  display: flex;
  align-items: flex-end;
  gap: 5px;
  height: 120px;
  border-bottom: 1px solid var(--hair-bone-2);
  padding: 0 2px;
}

.pf-fig4__bar {
  flex: 1;
  background: var(--bar-bone);
}

.pf-fig4__bar--1 { height: 30%; }
.pf-fig4__bar--2 { height: 44%; }
.pf-fig4__bar--3 { height: 58%; }
.pf-fig4__bar--peak { height: 91%; background: var(--bone); position: relative; }
.pf-fig4__bar--5 { height: 72%; }
.pf-fig4__bar--6 { height: 48%; }
.pf-fig4__bar--7 { height: 33%; }
.pf-fig4__bar--8 { height: 21%; }

.pf-fig4__marker {
  position: absolute;
  top: -8px;
  left: 50%;
  transform: translateX(-50%);
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--accent);
}

.pf-fig4__days {
  display: flex;
  justify-content: space-between;
  font-family: 'IBM Plex Mono', monospace;
  font-size: var(--fs-0);
  letter-spacing: 0.06em;
  color: var(--grey-2);
}

.pf-fig4__stats {
  display: flex;
  flex-direction: column;
  gap: 9px;
  border-top: 1px solid var(--hair-bone);
  padding-top: 12px;
}

.pf-fig4__stat-row {
  display: flex;
  justify-content: space-between;
  font-family: 'IBM Plex Mono', monospace;
  font-size: var(--fs-1);
  letter-spacing: 0.06em;
  color: var(--grey-2);
}

/* Figure 05: white-label brand cards (export 505-516). */
.pf-fig5 {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 16px;
}

.pf-fig5__card {
  border: 1px solid var(--hair-ink-2);
  background: var(--paper);
  padding: 18px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.pf-fig5__card--inverted {
  background: var(--ink);
  color: var(--bone);
}

.pf-fig5__card-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.pf-fig5__card-name {
  font-family: Oswald, sans-serif;
  font-size: var(--fs-6);
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.pf-fig5__swatches {
  display: flex;
  gap: 5px;
}

.pf-fig5__swatch {
  width: 16px;
  height: 16px;
}

.pf-fig5__swatch--ink { background: var(--ink); }
.pf-fig5__swatch--grey1 { background: var(--grey-1); }
.pf-fig5__swatch--outline { border: 1px solid var(--hair-ink-2); }
.pf-fig5__swatch--bone { background: var(--bone); }
.pf-fig5__swatch--grey2 { background: var(--grey-2); }
.pf-fig5__swatch--outline-bone { border: 1px solid var(--hair-bone-2); }

.pf-fig5__meta {
  font-family: 'IBM Plex Mono', monospace;
  font-size: var(--fs-0);
  letter-spacing: 0.08em;
  color: var(--grey-1);
  line-height: 1.8;
}

.pf-fig5__meta--on-ink {
  color: var(--grey-2);
}

/* Platform CTA band (export 521-525). .cta-band__inner is reused verbatim
   from the home page (byte-identical), and the link combines .btn-accent
   (rest/hover/active declarations byte-identical to export 524's inline
   style/style-hover/style-active) with .cta-band__button (padding
   byte-identical to export 524's padding). */
.doc-cta {
  padding: var(--sp-band) var(--sp-x) var(--sp-trail-lg);
  border-top: 1px solid var(--hair-bone);
  text-align: center;
  color: var(--bone);
}

.doc-cta__heading {
  margin: 0;
  font-family: Oswald, sans-serif;
  font-weight: 600;
  text-transform: uppercase;
  font-size: var(--fs-cta2);
  line-height: 0.96;
  text-wrap: balance;
}

/* ==========================================================================
   Security page (security.html).

   Markup transcribed from export lines 534 to 590. The hero banner reuses
   .doc-hero, defined above for platform.html (export 534-538 is
   structurally identical to 360-364).
   ========================================================================== */

.sd-stack {
  display: flex;
  flex-direction: column;
  gap: clamp(48px, 7vw, 80px);
}

.sd-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(300px, 100%), 1fr));
  gap: var(--sp-gap-sm);
}

.sd-head {
  border-top: 1px solid var(--rule-ink);
  padding-top: 14px;
}

.sd-head__num {
  font-family: 'IBM Plex Mono', monospace;
  font-size: var(--fs-4);
  margin-right: 18px;
}

.sd-head__label {
  font-family: 'IBM Plex Mono', monospace;
  font-size: var(--fs-3);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--grey-1);
}

.sd-head__title {
  margin: 18px 0 0;
  font-family: Oswald, sans-serif;
  font-weight: 600;
  text-transform: uppercase;
  font-size: var(--fs-h3l);
  line-height: 1.05;
}

.sd-list {
  border-top: 1px solid var(--hair-ink);
}

.sd-row-item {
  display: flex;
  gap: 24px;
  border-bottom: 1px solid var(--hair-ink);
  padding: 16px 4px;
}

.sd-row-label {
  font-family: 'IBM Plex Mono', monospace;
  font-size: var(--fs-2);
  letter-spacing: 0.1em;
  color: var(--grey-1);
  min-width: 130px;
  padding-top: 2px;
}

.sd-row-value {
  font-size: var(--fs-6);
  line-height: 1.6;
}

/* Philosophy band (export 584-589). .doc-hero__eyebrow is reused verbatim
   for the "Philosophy" label: byte-identical to the hero eyebrow above. */
.sd-philosophy {
  padding: var(--sp-band) var(--sp-x) var(--sp-trail-lg);
  border-top: 1px solid var(--hair-bone);
  color: var(--bone);
}

.sd-philosophy__inner {
  max-width: 900px;
}

.sd-philosophy__quote {
  margin: 0 0 40px;
  font-family: Oswald, sans-serif;
  font-weight: 500;
  text-transform: uppercase;
  font-size: var(--fs-quote1);
  line-height: 1.1;
  text-wrap: balance;
}

.sd-philosophy__link {
  font-family: 'IBM Plex Mono', monospace;
  font-size: var(--fs-4);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--bone);
  border-bottom: 1px solid var(--hair-bone-2);
  padding-bottom: 3px;
  cursor: pointer;
}

.sd-philosophy__link:hover {
  border-bottom: 1px solid var(--bone);
}

/* ==========================================================================
   About page (about.html).

   Markup transcribed from export lines 598 to 627. #vyte-prov keeps its
   original id: the 1100px media query above (export-transcribed, base
   rules) targets it directly alongside #vyte-ticker.
   ========================================================================== */

.ab-hero {
  color: var(--bone);
  padding: var(--sp-hero-top) var(--sp-x) clamp(56px, 8vw, 100px);
  position: relative;
}

.ab-hero__title {
  margin: 0;
  font-family: Oswald, sans-serif;
  font-weight: 600;
  text-transform: uppercase;
  font-size: var(--fs-h1);
  line-height: 0.95;
  max-width: 15ch;
  text-wrap: balance;
}

/* The motif's first node (the COMMIT circle, cy=25 in a 250 tall viewBox, so
   25px below the block's top) is aligned to the cap height of the headline
   rather than floated against nothing. Derived, not a magic number:
     cap top  = --sp-hero-top + 39px eyebrow block + 0.245 * --fs-h1
   where 0.245em is Oswald's cap top below the em box at line-height 0.95
   (0.27 cap inset, less 0.025 half-leading), and the eyebrow block is a
   constant 39px because its type and margin are both fixed. Subtracting the
   circle's own 25px offset leaves the 14px term. Scales with the headline;
   the motif is hidden below 1100px anyway. */
.ab-prov {
  position: absolute;
  top: calc(var(--sp-hero-top) + 14px + 0.245 * var(--fs-h1));
  right: var(--sp-x);
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 16px;
}

.ab-prov__sketch {
  overflow: visible;
}

.ab-prov__caption {
  font-family: 'IBM Plex Mono', monospace;
  font-size: var(--fs-3);
  letter-spacing: 0.12em;
  color: var(--grey-2);
}

.ab-stats {
  color: var(--bone);
  padding: 0 var(--sp-x) var(--sp-trail);
}

.ab-stats__grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(300px, 100%), 1fr));
  gap: var(--sp-gap);
  border-top: 1px solid var(--hair-bone);
  padding-top: clamp(32px, 5vw, 56px);
}

.ab-stats__lead {
  margin: 0 0 18px;
  font-size: var(--fs-lead);
  line-height: 1.7;
  color: var(--bone);
}

.ab-stats__sub {
  margin: 0;
  font-size: var(--fs-lead);
  line-height: 1.7;
  color: var(--grey-2);
}

.ab-row {
  display: flex;
  gap: 24px;
  border-top: 1px solid var(--hair-bone);
  padding: 14px 0;
}

.ab-row--last {
  border-bottom: 1px solid var(--hair-bone);
}

.ab-row-label {
  font-family: 'IBM Plex Mono', monospace;
  font-size: var(--fs-2);
  letter-spacing: 0.1em;
  color: var(--grey-2);
  min-width: 130px;
}

.ab-row-value {
  font-size: var(--fs-5);
  color: var(--bone);
}

.ab-quote {
  color: var(--bone);
  padding: var(--sp-band-lg) var(--sp-x) var(--sp-trail-lg);
  border-top: 1px solid var(--hair-bone);
}

.ab-quote__inner {
  max-width: 1100px;
  margin: 0 auto;
  text-align: center;
}

.ab-quote__dot {
  display: inline-block;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--accent);
  margin-bottom: 32px;
}

.ab-quote__text {
  margin: 0;
  font-family: Oswald, sans-serif;
  font-weight: 500;
  text-transform: uppercase;
  font-size: var(--fs-quote2);
  line-height: 1.08;
  text-wrap: balance;
}

/* ==========================================================================
   Contact page (contact.html).

   Markup transcribed from export lines 635 to 690. The export's dead
   sc-if/onChange/onClick form (built by a since-removed reactive
   framework) is rendered here as a real <form> with five named fields;
   error messages are not in this markup, Task 10 builds them. #vyte-send
   keeps its id: the 767.98px media query above (base rules) targets it.
   ========================================================================== */

.ct-section {
  color: var(--ink);
  padding: var(--sp-hero-top) var(--sp-x) var(--sp-trail);
}

.ct-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(320px, 100%), 1fr));
  gap: clamp(40px, 6vw, 96px);
  align-items: start;
}

.ct-eyebrow {
  font-family: 'IBM Plex Mono', monospace;
  font-size: var(--fs-3);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--grey-1);
  margin-bottom: 24px;
}

.ct-title {
  margin: 0 0 28px;
  font-family: Oswald, sans-serif;
  font-weight: 600;
  text-transform: uppercase;
  font-size: var(--fs-h1s);
  line-height: 0.95;
  text-wrap: balance;
}

.ct-lead {
  margin: 0 0 32px;
  max-width: 46ch;
  font-size: var(--fs-6);
  line-height: 1.7;
  color: var(--grey-3);
}

.ct-row {
  display: flex;
  gap: 24px;
  border-top: 1px solid var(--hair-ink);
  padding: 14px 0;
}

.ct-row--last {
  border-bottom: 1px solid var(--hair-ink);
}

.ct-row-label {
  font-family: 'IBM Plex Mono', monospace;
  font-size: var(--fs-2);
  letter-spacing: 0.1em;
  color: var(--grey-1);
  min-width: 110px;
}

.ct-row-value {
  font-size: var(--fs-5);
}

.ct-email-link {
  font-family: 'IBM Plex Mono', monospace;
  font-size: var(--fs-4);
  color: var(--ink);
  border-bottom: 1px solid var(--hair-ink-3);
}

.ct-email-link:hover {
  border-bottom: 1px solid var(--ink);
}

.ct-form {
  display: flex;
  flex-direction: column;
  gap: 28px;
  border-top: 1px solid var(--rule-ink);
  padding-top: 28px;
}

/* Task 10 shows the success panel and hides the form by toggling these
   two modifiers (e.g. classList.add) once an enquiry submits. */
.ct-form--hidden {
  display: none;
}

.ct-field {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.ct-field__label {
  font-family: 'IBM Plex Mono', monospace;
  font-size: var(--fs-2);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--grey-1);
}

.ct-field__input,
.ct-field__textarea {
  border: none;
  /* Persistent field boundary, matching the left column's .ct-row hairline
     exactly so the form reads as a form rather than as loose labels. The
     focus state below thickens this to a 2px accent rule. */
  border-bottom: 1px solid var(--hair-ink);
  background: transparent;
  font-family: Archivo, sans-serif;
  font-size: var(--fs-7);
  color: var(--ink);
  padding: 8px 0;
  width: 100%;
  box-sizing: border-box;
}

.ct-field__textarea {
  resize: vertical;
}

/* Export lines 653, 658, 662, 666, 671: the dead style-hover attribute on
   every field, transcribed into a real :hover rule. */
.ct-field__input:hover,
.ct-field__textarea:hover {
  border-bottom-color: var(--hair-ink-3);
}

/* Export lines 653, 658, 662, 666, 671: the dead style-focus attribute on
   every field. :focus-visible is not stripped by the input/textarea
   outline:none rule above (base rules, export line 55): that rule only
   removes the outline, so this box-shadow and border colour are the only
   visible keyboard focus indicator on these five fields. Required: every
   interactive element must show a visible focus state. */
.ct-field__input:focus-visible,
.ct-field__textarea:focus-visible {
  border-bottom-color: var(--accent);
  /* Accent underline kept as the export drew it, plus the 1.4.11 halo. The
     fields carry outline:none from the base rules, so without the halo the
     accent underline would be the whole indicator at 1.19:1 on --bone. */
  box-shadow: 0 1px 0 var(--accent), 0 0 0 4px var(--focus-halo);
}

/* Task 10: src/app.ts toggles these modifiers on a field's input/textarea
   while its validation error is showing. */
.ct-field__input--error,
.ct-field__textarea--error {
  border-bottom-color: var(--error);
}

/* Task 10: the error message src/app.ts builds with createElement and
   attaches after a field's input/textarea, carrying data-error-for. */
.ct-field__error {
  font-family: 'IBM Plex Mono', monospace;
  font-size: var(--fs-2);
  letter-spacing: 0.06em;
  color: var(--error);
}

.ct-actions {
  display: flex;
  align-items: center;
  gap: 24px;
  flex-wrap: wrap;
}

.ct-submit {
  appearance: none;
  font-family: Archivo, sans-serif;
  font-size: var(--fs-5);
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink);
  background: transparent;
  border: 1px solid var(--accent);
  padding: 15px 31px;
  cursor: pointer;
}

.ct-submit:hover {
  background: var(--accent);
  color: var(--ink);
}

.ct-submit:active {
  transform: translateY(1px);
}

/* Export line 676: the sc-if(sending) span, shown in place of #vyte-send
   while src/app.ts holds the form in its 800ms simulated submit window. */
.ct-submit--hidden {
  display: none;
}

.ct-sending {
  display: none;
  font-family: 'IBM Plex Mono', monospace;
  font-size: var(--fs-4);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink);
  border: 1px solid var(--accent);
  padding: 15px 31px;
  opacity: 0.7;
}

.ct-sending--visible {
  display: inline-block;
}

.ct-note {
  font-family: 'IBM Plex Mono', monospace;
  font-size: var(--fs-2);
  letter-spacing: 0.08em;
  color: var(--grey-1);
}

/* Honeypot trap for the enquiry form (contact.html). A naive bot filling
   every input on the page still finds and fills this one, since it stays
   in the render tree at all times: never display:none or
   visibility:hidden, only pushed off-canvas and collapsed to a zero-area
   box (the border, padding and min-width resets stop the UA's default
   input chrome from giving it any rendered size). tabindex="-1" and
   aria-hidden="true" on the input itself (in the markup, not here) keep
   it out of the tab order and the accessibility tree for real users; the
   zero-area box also keeps it out of the site's own 44x44 touch-target
   check, which exempts elements with no rendered box. */
.ct-field__honeypot {
  position: absolute;
  left: -9999px;
  top: -9999px;
  width: 0;
  height: 0;
  min-width: 0;
  margin: 0;
  padding: 0;
  border: 0;
  overflow: hidden;
}

/* Turnstile mount point (contact.html): src/app.ts renders the widget
   into this element with size: 'flexible', which fills the element's
   width. Cloudflare renders into a closed shadow root this page cannot
   inspect or style directly, and its internal content is not always
   clipped to the host element's own box (confirmed: the local test key
   renders a few pixels of unclipped content that forced horizontal
   scroll at 320px even though the container's own box measured well
   within the column). overflow: hidden clips whatever it renders,
   visible or not, to this element's box; max-width keeps that box itself
   inside the narrow contact form column. */
[data-turnstile-container] {
  max-width: 100%;
  overflow: hidden;
}

/* Form-level failure banner: src/app.ts shows this when /api/enquiry
   responds with anything other than 200, or the request never reaches
   the server at all. Same error treatment as .ct-field__error above;
   role="alert" in the markup gets it announced without a focus change. */
.ct-form-error {
  display: none;
  font-family: 'IBM Plex Mono', monospace;
  font-size: var(--fs-2);
  letter-spacing: 0.06em;
  color: var(--error);
}

.ct-form-error--visible {
  display: block;
}

.ct-success {
  display: none;
  border: 1px solid var(--hair-ink-2);
  background: var(--paper);
  padding: var(--sp-head);
  flex-direction: column;
  gap: 18px;
}

.ct-success--visible {
  display: flex;
}

.ct-success__badge {
  display: flex;
  align-items: center;
  gap: 10px;
  font-family: 'IBM Plex Mono', monospace;
  font-size: var(--fs-3);
  letter-spacing: 0.12em;
  color: var(--grey-1);
}

.ct-success__dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--accent);
}

.ct-success__heading {
  margin: 0;
  font-family: Oswald, sans-serif;
  font-weight: 600;
  text-transform: uppercase;
  font-size: var(--fs-h3l);
  line-height: 1.05;
}

.ct-success__text {
  margin: 0;
  font-family: 'IBM Plex Mono', monospace;
  font-size: var(--fs-3);
  letter-spacing: 0.08em;
  color: var(--grey-3);
}

/* ==========================================================================
   Legal pages: privacy notice and accessibility statement.

   Markup transcribed from export lines 697 to 734 (privacy.html) and 740
   to 770 (accessibility.html). The two pages share an identical structure
   (hero band plus a numbered row list), so one set of classes covers both.
   ========================================================================== */

.legal-hero {
  color: var(--ink);
  padding: var(--sp-hero-top) var(--sp-x) var(--sp-head);
}

.legal-hero__eyebrow {
  font-family: 'IBM Plex Mono', monospace;
  font-size: var(--fs-3);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--grey-1);
  margin-bottom: 24px;
}

.legal-hero__title {
  margin: 0 0 24px;
  font-family: Oswald, sans-serif;
  font-weight: 600;
  text-transform: uppercase;
  font-size: var(--fs-h1s);
  line-height: 0.95;
  max-width: 18ch;
  text-wrap: balance;
}

.legal-hero__lead {
  margin: 0 0 20px;
  max-width: 58ch;
  font-size: var(--fs-lead);
  line-height: 1.65;
  color: var(--grey-3);
}

.legal-hero__updated {
  font-family: 'IBM Plex Mono', monospace;
  font-size: var(--fs-2);
  letter-spacing: 0.1em;
  color: var(--grey-1);
}

.legal-body {
  color: var(--ink);
  padding: var(--sp-head) var(--sp-x) var(--sp-trail);
}

.legal-body__inner {
  display: flex;
  flex-direction: column;
  max-width: 980px;
}

.legal-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(260px, 100%), 1fr));
  gap: clamp(12px, 2vw, 40px);
  border-top: 1px solid var(--hair-ink);
  padding: 22px 0;
}

.legal-row--last {
  border-bottom: 1px solid var(--hair-ink);
}

.legal-row__label {
  font-family: 'IBM Plex Mono', monospace;
  font-size: var(--fs-2);
  letter-spacing: 0.12em;
  color: var(--grey-1);
  padding-top: 3px;
}

.legal-row__list {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.legal-row__text {
  margin: 0;
  font-size: var(--fs-6);
  line-height: 1.7;
}

.legal-link {
  border-bottom: 1px solid var(--hair-ink-3);
}

.legal-link:hover {
  border-bottom: 1px solid var(--ink);
}

/* ==========================================================================
   404 page (404.html).

   Markup transcribed from 404.dc.html lines 25 to 30, the standalone
   layout with no nav, menu or footer. The five hardcoded hex colours in
   that export are replaced here with their matching custom properties:
   #0b0c0e -> var(--ink), #f4f3ef -> var(--bone), #9a9c9e -> var(--grey-2),
   #3dff8c -> var(--accent) (used twice, background and border). The
   "Return home" link reuses .btn-accent verbatim: its rest, hover and
   active declarations are byte-identical to the export's inline
   style/style-hover/style-active on that link.
   ========================================================================== */

.nf-page {
  min-height: 100vh;
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  gap: 28px;
  padding: clamp(24px, 5vw, 64px);
  background: var(--ink);
  background-image: linear-gradient(var(--gl-bone) 1px, transparent 1px), linear-gradient(90deg, var(--gl-bone) 1px, transparent 1px);
  background-size: 64px 64px;
}

.nf-eyebrow {
  display: flex;
  align-items: center;
  gap: 12px;
  font-family: 'IBM Plex Mono', monospace;
  font-size: var(--fs-3);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--grey-2);
}

.nf-eyebrow__dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--accent);
}

.nf-title {
  margin: 0;
  font-family: Oswald, sans-serif;
  font-weight: 600;
  text-transform: uppercase;
  font-size: clamp(40px, 9vw, 128px);
  line-height: 0.95;
  max-width: 14ch;
  text-wrap: balance;
  color: var(--bone);
}

.nf-meta {
  font-family: 'IBM Plex Mono', monospace;
  font-size: var(--fs-3);
  letter-spacing: 0.1em;
  color: var(--grey-2);
}

.nf-actions {
  display: flex;
}

.nf-cta {
  padding: 15px 29px;
}

/* ==========================================================================
   ACCESSIBILITY LAYER
   Not from the design export. Added to meet WCAG 2.4.1 (bypass blocks) and
   2.5.8 (target size). No copy, colour, type scale or layout value changes:
   targets grow through padding and pseudo-element hit areas only, never by
   increasing font size.
   ========================================================================== */

/* Skip link. First focusable element on every page, off-screen until
   focused, then drawn at top-left in the established mono label style. */
.skip-link {
  position: fixed;
  top: 0;
  left: 0;
  z-index: 500;
  transform: translateY(-120%);
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  font-family: 'IBM Plex Mono', monospace;
  font-size: var(--fs-3);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink);
  background: var(--accent);
  padding: 14px 18px;
  transition: transform 200ms var(--ease-out);
}

.skip-link:focus {
  transform: translateY(0);
}

/* The main landmark takes focus from the skip link, so it must not paint a
   focus ring of its own: the destination is the content, not a control. */
main:focus,
main:focus-visible {
  outline: none;
  box-shadow: none;
}

/* Target size. Every interactive element reaches at least 44x44 on mobile.
   A centred pseudo-element carries the hit area so that line height, type
   scale and layout are all untouched. */
@media (max-width: 767.98px) {
  .nav__brand,
  .nav__cta,
  .security__docs-link,
  .sd-philosophy__link,
  .footer__link,
  .footer__email,
  .footer__legal-link,
  .ct-email-link,
  .legal-link,
  .doc-index__link {
    position: relative;
  }

  .nav__brand::after,
  .nav__cta::after,
  .security__docs-link::after,
  .sd-philosophy__link::after,
  .footer__link::after,
  .footer__email::after,
  .footer__legal-link::after,
  .ct-email-link::after,
  .legal-link::after,
  .doc-index__link::after {
    content: '';
    position: absolute;
    top: 50%;
    left: 50%;
    width: 100%;
    height: 100%;
    min-width: 44px;
    min-height: 44px;
    transform: translate(-50%, -50%);
  }

  /* Replaced elements do not render pseudo-elements, so the fields grow
     through min-height instead. Font size is unchanged. */
  .ct-field__input,
  .ct-field__textarea {
    min-height: 44px;
  }
}

/* ==========================================================================
   SECURITY DOSSIER CONTENTS INDEX
   The hero's right half was empty while the four dossier sections started
   below the fold. The index lists those four section labels, using the
   strings already on the page, in the established mono label treatment with
   the existing .v-und hover underline.
   ========================================================================== */

.doc-hero__grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: var(--sp-gap);
  align-items: start;
}

.doc-index {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 14px;
  text-align: right;
}

.doc-index__link {
  display: flex;
  align-items: baseline;
  justify-content: flex-end;
  gap: 14px;
  font-family: 'IBM Plex Mono', monospace;
  font-size: var(--fs-3);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--grey-2);
  padding: 6px 0;
  background-position: right calc(100% - 4px);
}

.doc-index__link:hover {
  color: var(--bone);
}

.doc-index__num {
  color: var(--accent);
}

/* The nav bar is fixed at 60px, so an anchored section must clear it. */
.sd-row {
  scroll-margin-top: calc(60px + var(--sp-head));
}

/* The index is a navigational aid, not content: below the two-column
   breakpoint it stacks under the lead rather than competing with it. */
@media (max-width: 899.98px) {
  .doc-hero__grid {
    grid-template-columns: minmax(0, 1fr);
    gap: var(--sp-head);
  }

  .doc-index {
    align-items: flex-start;
    text-align: left;
  }

  .doc-index__link {
    justify-content: flex-start;
    background-position: left calc(100% - 4px);
  }
}
