/* ============================================================================
   Pursula design system
   Implements DESIGN.md v1.0. Tokens only, no raw hex outside the token block.

   Theme model
   -----------
   DESIGN.md 5 says consecutive sections alternate ink and bone, and that
   alternation IS the page structure. DESIGN.md 1.2 says ink is the primary
   brand surface and bone is the relief surface for reading.

   So sections come in two kinds and both survive a theme switch:
     .surf-brand  always ink family. Hero, CTA, product blocks. Identity stays
                  constant across themes, which is why the hero looks the same
                  in light and dark.
     .surf-read   the relief surface. Bone in light theme, ink-deep in dark.

   Accent tokens are re-declared per surface kind so the contrast rules in
   DESIGN.md 3.3 can never be violated by a component that moved sections:
     pine  is text on bone only.  pine-bright is text on ink only.
     ember and sand are dark surfaces only. ember-deep is ember as text on bone.
   ========================================================================= */

/* ---------- fonts: self-hosted. Google Fonts CDN is not used, because an
   uncontrolled request to a third-party host is a cross-border transfer of the
   visitor's IP address under KVKK m.9 with no transfer mechanism behind it. --- */

@font-face {
  font-family: 'Bricolage Grotesque';
  font-style: normal;
  font-weight: 200 800;
  font-stretch: 75% 100%;
  font-display: swap;
  src: url('../fonts/bricolage-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Bricolage Grotesque';
  font-style: normal;
  font-weight: 200 800;
  font-stretch: 75% 100%;
  font-display: swap;
  src: url('../fonts/bricolage-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('../fonts/plexmono-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('../fonts/plexmono-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}

/* ---------------------------------------------------------------- tokens -- */

:root {
  /* Surfaces and core. DESIGN.md 9. */
  --pu-ink: #1c2826;
  --pu-ink-deep: #0f1615;
  --pu-ink-raised: #314643;
  --pu-bone: #f3ebe2;
  --pu-bone-shade: #eadccc;

  /* Accents */
  --pu-pine: #1f5a54;
  --pu-pine-bright: #379e94;
  --pu-ember: #d97b47;
  --pu-ember-ui: #d4692e;
  --pu-ember-deep: #a75222;
  --pu-sand: #e8c097;

  /* Semantic */
  --pu-success: #3f8f62;
  --pu-warning: #c98a21;
  --pu-danger: #c0442f;
  --pu-focus: #2b7c73;

  /* Type */
  --pu-font: 'Bricolage Grotesque', ui-sans-serif, system-ui, sans-serif;
  --pu-font-mono: 'IBM Plex Mono', ui-monospace, monospace;

  /* Space */
  --pu-1: 4px;   --pu-2: 8px;   --pu-3: 12px;  --pu-4: 16px;
  --pu-5: 24px;  --pu-6: 32px;  --pu-7: 48px;  --pu-8: 64px;
  --pu-9: 96px;  --pu-10: 128px; --pu-11: 192px;

  /* Radius */
  --pu-r-sm: 6px; --pu-r-md: 10px; --pu-r-lg: 16px; --pu-r-full: 9999px;

  /* Elevation */
  --pu-shadow: 0 1px 2px rgba(28, 40, 38, .06), 0 8px 24px rgba(28, 40, 38, .08);

  /* Motion */
  --pu-ease: cubic-bezier(0.22, 1, 0.36, 1);
  --pu-ease-in: cubic-bezier(0.7, 0, 0.84, 0);
  --pu-dur-fast: 160ms;
  --pu-dur-base: 240ms;
  --pu-dur-slow: 400ms;
  --pu-dur-trail: 900ms;

  /* Containers. DESIGN.md 5. */
  --pu-w-prose: 680px;
  --pu-w-std: 1200px;
  --pu-w-wide: 1440px;
  --pu-gutter: 24px;

  /* The header row plus its 1px hairline. The nav sheet hangs off the bottom
     of the header and the hero subtracts it from the viewport; a literal in
     either place drifts the next time this is tuned, and the sheet was in
     fact sitting 8px above the header it drops out of. */
  --chrome-h: 73px;

  /* build.py ships viewport-fit=cover, so layout extends under the display
     cutout. In landscape on a notched phone the side insets are 44-59px
     against a 24px gutter, and only the BOTTOM inset was ever honoured. The
     max() resolves to the plain gutter on every device without a cutout, and
     the `, 0px` fallback matters: without it a browser that does not know
     env() makes the whole custom property invalid and .wrap loses its gutter
     altogether. */
  --pu-safe-l: max(var(--pu-gutter), env(safe-area-inset-left, 0px));
  --pu-safe-r: max(var(--pu-gutter), env(safe-area-inset-right, 0px));

  /* DESIGN.md 5 specifies 16px on mobile and the site was using 24 at every
     width, which is 16px the narrowest phones cannot spare. */

  /* Layered surface roles, light theme is the default declaration. */
  --s-read: var(--pu-bone);
  --s-read-fg: var(--pu-ink);
  --s-read-muted: #4a5a57;          /* ink at 78% toward bone, 6.2:1 on bone   */
  --s-read-card: var(--pu-card-white);
  --s-read-card-alt: var(--pu-bone-shade);
  --s-read-rule: rgba(28, 40, 38, .12);
  --s-read-link: var(--pu-pine);
  --s-read-signal: var(--pu-ember-deep);
  --s-read-signal-ui: var(--pu-ember-ui);
  --s-read-notice: var(--pu-ember-notice);
  --s-read-shadow: var(--pu-shadow);
  --s-read-danger: var(--pu-danger-on-bone);

  /* Header chrome follows the reading surface. */
  --chrome-bg: rgba(243, 235, 226, .86);
  --chrome-bg-solid: var(--pu-bone);
  --chrome-fg: var(--pu-ink);
  --chrome-rule: rgba(28, 40, 38, .12);

  /* Derived values that DESIGN.md 3.2 does not list but components need.
     They live here so "no raw hex in component code" stays literally true and
     so every one of them is auditable in a single place.
       ink-muted   bone stepped back for secondary text on ink, 9.1:1
       *-press     the pressed/hover step of each button fill
       card-white  the card surface on bone, per DESIGN.md 8 */
  /* --pu-danger from DESIGN.md 3.5 measures 4.33:1 on bone and 3.59:1 on
     ink-deep, so error TEXT fails AA on both surfaces. These two are the
     text-safe pair; --pu-danger itself stays for borders and icons, where the
     3:1 non-text floor applies. Measured, not estimated. */
  --pu-danger-on-bone: #b33d29;   /* 4.92:1 on bone    */
  /* Ember-deep is 4.59:1 on plain bone, but the notice sits on its own 8%
     ember wash, which lifts the background to rgb(237,223,211) and drops the
     title to 4.16:1. Measured after compositing, not against plain bone. */
  --pu-ember-notice: #94481d;     /* 4.97:1 on that wash, 5.55:1 on bone */
  --pu-danger-on-ink: #e8705c;    /* 6.02:1 on ink-deep, 5.00:1 on ink */

  --pu-ink-muted: #b9c4c1;
  --pu-pine-press: #17443f;
  --pu-ember-press: #e08b5c;
  --pu-ember-deep-press: #8d4319;
  --pu-card-white: #ffffff;

  /* Brand mark facets. Resolved per surface so the pine facet never lands as
     pine-on-ink (1.92:1) and never drops below the 3:1 floor for a non-text
     graphic. ember-ui is 3.04:1 on bone, pine is 6.72:1 on bone. */
  /* Ember-ui is 3.04:1 on plain bone, but the only surface reading this :root
     pair is the HEADER, whose background is 86% bone over whatever scrolls
     behind it: 2.34:1 composited over an ink block, 2.61:1 over the open-sheet
     scrim. Ember-deep holds the 3:1 non-text floor in all three states (4.59
     on bone, 3.53 over ink, 3.95 over the scrim). Measured, not estimated.
     This is the same per-surface facet resolution .site-footer, .page-head and
     .surf-brand already perform, not the recolour DESIGN.md 2.5 forbids. */
  --mark-a: var(--pu-ember-deep);
  --mark-b: var(--pu-pine);

  color-scheme: light dark;
}

@media (max-width: 767px) {
  :root { --chrome-h: 65px; }
}
@media (max-width: 479px) {
  :root { --pu-gutter: 16px; }
}

/* THE THEME IS THE VISITOR'S, NOT A SWITCH ON THIS SITE.
   There used to be a toggle, a localStorage key and an inline pre-paint script
   to stop the first frame flashing the wrong surface. All three are gone: the
   light/dark preference is one the visitor has already expressed once, for
   every site they open, and honouring it needs no storage, no script and no
   consent record. It also removes the FOUC problem entirely rather than
   patching it, because a media query is resolved before the first paint.
   .surf-brand is deliberately NOT in here: the brand surface is ink in both
   themes, which is what keeps the identity constant. DESIGN.md 1.2. */
@media (prefers-color-scheme: dark) {
:root {
  --s-read: var(--pu-ink-deep);
  --s-read-fg: var(--pu-bone);
  --s-read-muted: #a9b5b2;          /* 8.4:1 on ink-deep                        */
  --s-read-card: var(--pu-ink);
  --s-read-card-alt: var(--pu-ink);
  --s-read-rule: rgba(243, 235, 226, .12);
  --s-read-link: var(--pu-pine-bright);
  --s-read-signal: var(--pu-ember);
  --s-read-signal-ui: var(--pu-ember);
  --s-read-notice: var(--pu-ember);   /* 5.46:1 on the wash over ink-deep */
  --s-read-shadow: none;
  --s-read-danger: var(--pu-danger-on-ink);

  --chrome-bg: rgba(15, 22, 21, .86);
  --chrome-bg-solid: var(--pu-ink-deep);
  --chrome-fg: var(--pu-bone);
  --chrome-rule: rgba(243, 235, 226, .12);

  /* ember 4.98:1 and pine-bright 4.69:1, both on ink. */
  --mark-a: var(--pu-ember);
  --mark-b: var(--pu-pine-bright);
}
}

/* ------------------------------------------------------------ base reset -- */

*, *::before, *::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: 96px;
}
/* The consent bar is fixed to the bottom until a choice is recorded, so focus
   moved onto a link near the end of the page lands underneath it. WCAG 2.2 AA
   2.4.11. Reserved only while the bar is really up: pursula.js close() sets
   [hidden], which retracts this with no extra code. Browsers without :has()
   behave exactly as they do today. */
html:has(.consent:not([hidden])) { scroll-padding-bottom: calc(var(--consent-h, 20rem) + var(--pu-4)); }
/* A reserve is useless at the END of the document if there is nothing left to
   scroll, so the footer grows by the bar's height while the bar is up. On the
   footer, not the body: a reading-surface strip under the ink footer would be
   worse than the problem. --consent-h is measured by pursula.js. */
html:has(.consent:not([hidden])) .site-footer { padding-bottom: var(--consent-h, 20rem); }
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
}

body {
  margin: 0;
  font-family: var(--pu-font);
  font-optical-sizing: auto;
  font-size: 1rem;
  line-height: 1.6;
  background: var(--s-read);
  color: var(--s-read-fg);
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

/* Turkish localised forms. DESIGN.md 4.4. */
[lang='tr'] { font-feature-settings: 'locl' 1; }

img, svg, video { max-width: 100%; height: auto; display: block; }

h1, h2, h3, h4, p, figure, blockquote, dl, dd { margin: 0; }
ul, ol { margin: 0; padding: 0; }

a { color: inherit; }

button, input, textarea, select { font: inherit; color: inherit; }

/* Focus. DESIGN.md 8. Visible on every interactive element, both surfaces. */
:focus-visible {
  outline: 2px solid var(--pu-focus);
  outline-offset: 2px;
  border-radius: var(--pu-r-sm);
}
:focus:not(:focus-visible) { outline: none; }

::selection { background: var(--pu-sand); color: var(--pu-ink); }

.skip-link {
  position: absolute;
  left: var(--pu-4);
  top: -100px;
  z-index: 100;
  padding: var(--pu-3) var(--pu-5);
  background: var(--pu-ink);
  color: var(--pu-bone);
  border-radius: var(--pu-r-md);
  font-weight: 600;
  text-decoration: none;
  transition: top var(--pu-dur-base) var(--pu-ease);
}
.skip-link:focus { top: var(--pu-4); }

.visually-hidden {
  position: absolute !important;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* -------------------------------------------------------- surface kinds -- */

.surf-read {
  background: var(--s-read);
  color: var(--s-read-fg);
  --fg: var(--s-read-fg);
  --muted: var(--s-read-muted);
  --card: var(--s-read-card);
  --card-alt: var(--s-read-card-alt);
  --rule: var(--s-read-rule);
  --link: var(--s-read-link);
  --signal: var(--s-read-signal);
  --signal-ui: var(--s-read-signal-ui);
  --notice-fg: var(--s-read-notice);
  --shadow: var(--s-read-shadow);
  /* Sand and ember are banned as text here, so the trail uses pine on bone. */
  --trail: var(--s-read-link);
  --trail-op: .34;
  --danger-text: var(--s-read-danger);
}

/* Ink block. Identical in both themes, which is what keeps the brand constant. */
.surf-brand {
  background: var(--pu-ink);
  color: var(--pu-bone);
  --fg: var(--pu-bone);
  --muted: var(--pu-ink-muted);     /* 9.1:1 on ink */
  --card: var(--pu-ink-raised);
  --card-alt: var(--pu-ink-raised);
  --rule: rgba(243, 235, 226, .12);
  --link: var(--pu-pine-bright);
  --signal: var(--pu-ember);
  --signal-ui: var(--pu-ember);
  --shadow: none;
  --trail: var(--pu-sand);
  --trail-op: .5;
  --mark-a: var(--pu-ember);
  --mark-b: var(--pu-pine-bright);
  --danger-text: var(--pu-danger-on-ink);
}
.surf-brand--deep { background: var(--pu-ink-deep); }

/* In dark theme --s-read resolves to --pu-ink-deep, which is exactly what
   .surf-brand--deep paints, so the ink/bone alternation that IS the page
   structure disappears at this one join. DESIGN.md 5: separation on ink is a
   hairline, never a shadow. */
@media (prefers-color-scheme: dark) {
  .surf-brand--deep + .surf-read,
  .surf-read + .surf-brand--deep {
    border-top: 1px solid var(--pu-ink-raised);
  }
  /* The footer is a sibling of <main>, not of the sections, so no + selector
     from a section can reach it. In dark --s-read IS ink-deep, so a page that
     ends on a reading section meets an ink-deep footer at 1.00:1 and the
     footer has no beginning at all. */
  .site-footer { border-top: 1px solid var(--pu-ink-raised); }
}

/* ------------------------------------------------------------ typography -- */

.display {
  font-size: clamp(2.75rem, 1.2rem + 6.4vw, 7.5rem);
  line-height: .95;
  font-weight: 700;
  font-stretch: 100%;
  letter-spacing: -0.03em;
  text-wrap: balance;
}
h1, .h1 {
  font-size: clamp(2.125rem, 1.3rem + 3.3vw, 3rem);
  line-height: 1.05;
  font-weight: 700;
  letter-spacing: -0.025em;
  text-wrap: balance;
}
h2, .h2 {
  font-size: clamp(1.625rem, 1.2rem + 1.8vw, 2rem);
  line-height: 1.15;
  font-weight: 600;
  letter-spacing: -0.02em;
  text-wrap: balance;
}
h3, .h3 {
  font-size: clamp(1.25rem, 1.1rem + .7vw, 1.5rem);
  line-height: 1.25;
  font-weight: 600;
  letter-spacing: -0.01em;
}
.lead {
  font-size: clamp(1.0625rem, 1rem + .4vw, 1.25rem);
  line-height: 1.5;
  color: var(--muted);
  max-width: 46ch;
  text-wrap: pretty;
}
p { max-width: 68ch; text-wrap: pretty; }
.small { font-size: .875rem; line-height: 1.5; }

/* The compressed eyebrow against full-width display type is the signature. */
.eyebrow {
  display: block;
  font-size: .75rem;
  line-height: 1.2;
  font-weight: 600;
  font-stretch: 82%;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--muted);
}
.eyebrow--signal { color: var(--signal); }

.metric-label {
  display: block;
  font-size: .75rem;
  line-height: 1.2;
  font-weight: 500;
  font-stretch: 78%;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}
.metric-value {
  font-size: clamp(2rem, 1.4rem + 2.4vw, 3.5rem);
  line-height: 1;
  font-weight: 600;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
}

code, .mono {
  font-family: var(--pu-font-mono);
  font-size: .875rem;
  line-height: 1.6;
  font-variant-numeric: tabular-nums;
}

.prose { max-width: var(--pu-w-prose); }
.prose > * + * { margin-top: var(--pu-5); }
.prose h2 { margin-top: var(--pu-8); }
.prose h3 { margin-top: var(--pu-7); }
.prose ul, .prose ol { padding-left: 1.25em; }
.prose li + li { margin-top: var(--pu-2); }
.prose li { max-width: 66ch; }
.prose a { color: var(--link); text-underline-offset: .18em; }
.prose a:hover { text-decoration-thickness: 2px; }

/* ---------------------------------------------------------------- layout -- */

.wrap { width: 100%; max-width: var(--pu-w-std); margin-inline: auto; padding-inline: var(--pu-safe-l) var(--pu-safe-r); }
.wrap--wide { max-width: var(--pu-w-wide); }
.wrap--prose { max-width: calc(var(--pu-w-prose) + var(--pu-gutter) * 2); }

/* DESIGN.md 5 sets 128px desktop / 64px mobile. The third step is not an
   invention: it is the same 192px value already in the spacing scale, and it
   is what makes a section read as a held pause rather than as the next thing
   in a list once the viewport is wide enough to show two of them at once. */
.section { padding-block: var(--pu-8); }
@media (min-width: 768px) { .section { padding-block: var(--pu-10); } }
@media (min-width: 1280px) { .section { padding-block: var(--pu-11); } }
.section--tight { padding-block: var(--pu-8); }

.stack > * + * { margin-top: var(--pu-4); }
.stack-5 > * + * { margin-top: var(--pu-5); }
.stack-6 > * + * { margin-top: var(--pu-6); }
.stack-7 > * + * { margin-top: var(--pu-7); }

@media (min-width: 1024px) {
  .gutter-inline { padding-inline: var(--pu-gutter); }
}

hr, .rule {
  border: 0;
  border-top: 1px solid var(--rule);
  margin: 0;
}

/* ------------------------------------------------------------- controls -- */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--pu-2);
  min-height: 44px;
  padding: 0 var(--pu-5);
  /* Explicit, because a <button> otherwise inherits the UA's `buttonface`
     grey. On an ink surface that put bone text on #F0F0F0 at 1.04:1, which is
     exactly what the consent bar's reject and manage buttons were doing. An
     <a class="btn"> looked fine, so the defect only showed on real buttons. */
  background: transparent;
  border: 1px solid transparent;
  border-radius: var(--pu-r-md);
  font-weight: 600;
  font-size: 1rem;
  line-height: 1.2;
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
  transition: transform var(--pu-dur-fast) var(--pu-ease),
              background-color var(--pu-dur-fast) var(--pu-ease),
              border-color var(--pu-dur-fast) var(--pu-ease),
              color var(--pu-dur-fast) var(--pu-ease);
}
.btn:active { transform: translateY(1px); }

/* Button variants resolve through the SURFACE TOKENS, not through a
   .surf-read / .surf-brand ancestor selector.

   Scoping them to those two classes was a real defect: every button outside
   them rendered with no background and no border, which is every CTA in a
   .page-head, both consent-bar buttons, and the cookie panel's controls. The
   tokens below are declared by :root, .surf-read, .surf-brand, .page-head,
   .consent and .site-footer, so a button is styled correctly wherever it is
   placed, and moving one between sections cannot silently break its
   contrast. */
:root, .surf-read {
  --btn-primary-bg: var(--pu-pine);
  --btn-primary-fg: var(--pu-bone);
  --btn-primary-bg-hover: var(--pu-pine-press);
  --btn-outline: var(--pu-pine);
  --btn-outline-fg: var(--pu-pine);
  --btn-outline-wash: rgba(31, 90, 84, .08);
  --btn-signal-bg: var(--pu-ember-deep);
  --btn-signal-fg: var(--pu-bone);
  --btn-signal-bg-hover: var(--pu-ember-deep-press);
}

/* Every ink-family surface. The outline is .45, not the .28 it used to be:
   .btn is background:transparent, so that border IS the control's boundary,
   and .28 composites to 2.31:1 on ink. .45 is 3.79:1, over the 1.4.11 floor.
   --btn-outline-wash stays at .08; it is a hover fill, not a boundary. */
.surf-brand, .page-head, .consent, .site-footer {
  --btn-primary-bg: var(--pu-bone);
  --btn-primary-fg: var(--pu-ink);
  --btn-primary-bg-hover: var(--pu-card-white);
  --btn-outline: rgba(243, 235, 226, .45);
  --btn-outline-fg: var(--pu-bone);
  --btn-outline-wash: rgba(243, 235, 226, .08);
  --btn-signal-bg: var(--pu-ember);
  --btn-signal-fg: var(--pu-ink);
  --btn-signal-bg-hover: var(--pu-ember-press);
}
/* In dark theme .surf-read is ink-deep, so it takes the ink pair too: pine as
   text on ink is 1.92:1 and is forbidden (3.3). Equal specificity to the light
   rule above and later in the file, which is what makes it win. */
@media (prefers-color-scheme: dark) {
  :root, .surf-read {
    --btn-primary-bg: var(--pu-bone);
    --btn-primary-fg: var(--pu-ink);
    --btn-primary-bg-hover: var(--pu-card-white);
    --btn-outline: rgba(243, 235, 226, .45);
    --btn-outline-fg: var(--pu-bone);
    --btn-outline-wash: rgba(243, 235, 226, .08);
    --btn-signal-bg: var(--pu-ember);
    --btn-signal-fg: var(--pu-ink);
    --btn-signal-bg-hover: var(--pu-ember-press);
  }
}
/* The dialog body is the reading surface in BOTH themes, so its footer takes
   whatever the reading surface takes and is never pinned to the ink pair. */
.consent-panel__foot {
  --btn-primary-bg: var(--pu-pine);
  --btn-primary-fg: var(--pu-bone);
  --btn-primary-bg-hover: var(--pu-pine-press);
  --btn-outline: var(--pu-pine);
  --btn-outline-fg: var(--pu-pine);
  --btn-outline-wash: rgba(31, 90, 84, .08);
  --btn-signal-bg: var(--pu-ember-deep);
  --btn-signal-fg: var(--pu-bone);
  --btn-signal-bg-hover: var(--pu-ember-deep-press);
}
@media (prefers-color-scheme: dark) {
  .consent-panel__foot {
    --btn-primary-bg: var(--pu-bone);
    --btn-primary-fg: var(--pu-ink);
    --btn-primary-bg-hover: var(--pu-card-white);
    --btn-outline: rgba(243, 235, 226, .45);
    --btn-outline-fg: var(--pu-bone);
    --btn-outline-wash: rgba(243, 235, 226, .08);
    --btn-signal-bg: var(--pu-ember);
    --btn-signal-fg: var(--pu-ink);
    --btn-signal-bg-hover: var(--pu-ember-press);
  }
}

.btn--primary { background: var(--btn-primary-bg); color: var(--btn-primary-fg); }
.btn--primary:hover { background: var(--btn-primary-bg-hover); }

.btn--secondary { border-color: var(--btn-outline); color: var(--btn-outline-fg); }
.btn--secondary:hover { background: var(--btn-outline-wash); border-color: var(--btn-outline-fg); }

/* Signal: one per page, the single most important action. */
.btn--signal { background: var(--btn-signal-bg); color: var(--btn-signal-fg); }
.btn--signal:hover { background: var(--btn-signal-bg-hover); }

.btn--ghost { color: var(--fg); }
.btn--ghost:hover { background: color-mix(in srgb, var(--fg) 8%, transparent); }

.btn--sm { min-height: 40px; padding: 0 var(--pu-4); font-size: .9375rem; }

/* Inline link that carries the trajectory idea: the underline extends on hover. */
.link-arrow {
  display: inline-flex;
  align-items: center;
  gap: var(--pu-2);
  color: var(--link);
  font-weight: 600;
  text-decoration: none;
  min-height: 44px;
}
.link-arrow::after {
  content: '';
  /* The final length is RESERVED and the line is scaled, never widened:
     animating width reflows the flex row and slides the next link away from
     under the cursor. 1.1 / 1.9 = .579, so the resting line is unchanged. */
  width: 1.9em; height: 1px;
  background: currentColor;
  transform: scaleX(.579);
  transform-origin: left center;
  transition: transform var(--pu-dur-base) var(--pu-ease);
}
.link-arrow:hover::after,
.link-arrow:focus-visible::after { transform: none; }
.link-arrow:hover { text-decoration: underline; text-underline-offset: .2em; }

/* ------------------------------------------------------------------ nav -- */

.site-header {
  position: sticky;
  top: 0;
  /* Above the consent bar, which is fixed to the bottom at z-80. The mobile
     sheet is a DESCENDANT of this sticky header, so it inherits this stacking
     context and cannot outrank the bar on its own however high its own
     z-index goes. Without this the bar painted over the last nav row and the
     language toggle, opaque and fully live. */
  z-index: 90;
  background: var(--chrome-bg);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  border-bottom: 1px solid transparent;
  transition: border-color var(--pu-dur-base) var(--pu-ease);
}
.site-header[data-scrolled='true'] { border-bottom-color: var(--chrome-rule); }
@supports not (backdrop-filter: blur(4px)) {
  .site-header { background: var(--s-read); }
}

.site-header__inner {
  display: flex;
  flex-wrap: nowrap;
  align-items: center;
  gap: var(--pu-5);
  height: calc(var(--chrome-h) - 1px);
  color: var(--chrome-fg);
}

/* THE LOCKUP IS THE WORDMARK, and nothing else. DESIGN.md 2.3 gives the site
   header the full wordmark; 2.5 bans rebuilding it by typing "pursula" in
   Bricolage, and bans combining it with the circular mark. So there is one
   inline SVG and no text node beside it. Its letterforms are currentColor,
   which inherits --chrome-fg here and bone in the footer; its two facets are
   --mark-a / --mark-b, which every surface redeclares. */
.brand-link {
  display: inline-flex;
  align-items: center;
  text-decoration: none;
  color: inherit;
  flex-shrink: 0;
  /* The wordmark IS the link, so the link has to clear the touch floor even
     though the glyph is shorter than 44px. Below 480px the only child is the
     32px mark, so the box has to carry the floor on BOTH axes. */
  min-height: 44px;
  min-width: 44px;
}
/* 4.083:1, so 30px tall is 122px wide, comfortably over the 96px minimum
   width DESIGN.md 2.4 sets. */
.brand-link__logo { height: 30px; width: auto; flex-shrink: 0; display: block; }
/* The viewBox is tight to the artwork, so 32px wide IS 32px of delta (26.2px
   tall at 72.19:59.19). Both clear the 24px minimum in DESIGN.md 2.4. The
   favicon tile's own 122.87 box left 41% of itself empty, which rendered the
   lockup at 16.4 x 13.5px and pushed it below the row's optical centre. */
.brand-link__mark { display: none; width: 32px; height: auto; flex-shrink: 0; }
@media (max-width: 767px) { .brand-link__logo { height: 26px; } }

/* Measured with the wordmark shown: the header row's right edge lands at 344
   on a 360px viewport, so it clears the 16px gutter from about 344px up and
   only eats into it on the 320px class of phone. Above that the wordmark is
   106px wide, over the 96px minimum, and DESIGN.md 2.3 gives the site header
   the full wordmark. Exactly one of the two ever renders, which is not the
   combined lockup 2.5 forbids. */
@media (max-width: 359px) {
  .brand-link__logo { display: none; }
  .brand-link__mark { display: block; }
}

/* Logo hard left, destinations pushed right, one action at the far right.
   The language control lives INSIDE .site-nav so that on a phone it travels
   into the sheet with the links instead of competing with the action for the
   200px the header bar has left. */
/* min-width:0 so the destinations shrink before anything is pushed out of
   the row. The logo and the action both refuse to shrink, so without it a
   narrow desktop window overflows instead of tightening. */
.site-nav { margin-left: auto; min-width: 0; display: flex; align-items: center; gap: var(--pu-4); }
.site-nav__list {
  display: flex;
  align-items: center;
  gap: var(--pu-1);
  list-style: none;
}
.site-nav__link {
  position: relative;
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding-inline: var(--pu-3);
  font-size: .9375rem;
  font-weight: 500;
  text-decoration: none;
  color: inherit;
  white-space: nowrap;
  transition: color var(--pu-dur-fast) var(--pu-ease);
}
/* A hairline that grows from the middle, not a filled pill. The reference the
   founder picked all mark the current page with a rule under the word, which
   is the quietest mark that still reads at a glance. */
.site-nav__link::after {
  content: '';
  position: absolute;
  left: var(--pu-3);
  right: var(--pu-3);
  bottom: 14px;
  height: 1px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: center;
  transition: transform var(--pu-dur-base) var(--pu-ease);
}
.site-nav__link[aria-current='page'] { font-weight: 600; }
.site-nav__link[aria-current='page']::after { transform: scaleX(1); }

.site-nav__tools {
  display: flex;
  align-items: center;
  gap: var(--pu-1);
  padding-left: var(--pu-4);
  border-left: 1px solid var(--chrome-rule);
}

/* The one action in the chrome, in the signal colour. --btn-signal-* is
   already declared per surface, which is what makes this safe: ember on ink
   with ink text (4.98:1), ember-deep on bone with bone text (4.59:1). Ember
   as text on bone is 2.59:1 and is forbidden, which is exactly why this is a
   FILL and never a coloured label. DESIGN.md 3.3 and 8.

   It is also the reason the pages carry no second .btn--signal: DESIGN.md 8,
   "if two buttons are signal, neither is". The in-page contact actions were
   demoted to primary when this took the slot. */
.btn--chrome {
  flex-shrink: 0;
  min-height: 40px;
  padding: 0 var(--pu-5);
  font-size: .9375rem;
  background: var(--btn-signal-bg);
  color: var(--btn-signal-fg);
  border-radius: var(--pu-r-full);
}

.icon-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--pu-1);
  min-width: 44px;
  min-height: 44px;
  padding-inline: var(--pu-2);
  background: none;
  border: 0;
  border-radius: var(--pu-r-sm);
  color: inherit;
  cursor: pointer;
  font-size: .8125rem;
  font-weight: 600;
  font-stretch: 82%;
  letter-spacing: .06em;
  transition: background-color var(--pu-dur-fast) var(--pu-ease);
}
.icon-btn svg { width: 18px; height: 18px; stroke: currentColor; fill: none;
  stroke-width: 1.5; stroke-linecap: round; stroke-linejoin: round; }

/* Guarded: on touch, :hover is applied on tap and stays until something else
   is tapped. On the language toggle, which stays on screen after being
   pressed, that lingering wash reads as "currently selected". */
@media (hover: hover) and (pointer: fine) {
  .site-nav__link:hover::after { transform: scaleX(1); }
  .icon-btn:hover { background: color-mix(in srgb, var(--chrome-fg) 8%, transparent); }
  .btn--chrome:hover { background: var(--btn-signal-bg-hover); }
}

.nav-toggle { display: none; }
@media (max-width: 1023px) {
  .nav-toggle { display: inline-flex; }
  .site-header__inner { gap: var(--pu-3); }
  .btn--chrome { margin-left: auto; }
  .site-nav {
    position: fixed;
    inset: var(--chrome-h) 0 auto;
    margin: 0;
    background: var(--s-read);
    color: var(--s-read-fg);
    /* --chrome-rule, not --rule: --rule is declared by the SURFACE classes and
       the header is outside all of them, so --rule resolves to nothing here
       and the sheet had no edge and no dividers at all. */
    border-bottom: 1px solid var(--chrome-rule);
    padding: var(--pu-2) var(--pu-safe-r) var(--pu-5) var(--pu-safe-l);
    display: none;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    /* A long nav on a short phone in landscape must not become unreachable. */
    max-height: calc(100svh - var(--chrome-h));
    overflow-y: auto;
    overscroll-behavior: contain;
  }
  .site-nav[data-open='true'] { display: flex; }
  .site-nav__list { flex-direction: column; align-items: stretch; gap: 0; }
  /* flex, not inline-flex: the sheet draws each row full width with a divider
     under it, so the target has to be the ROW and not just the word. */
  .site-nav__link { display: flex; min-height: 56px; padding-inline: 0; font-size: 1.125rem; }
  .site-nav__link::after { left: 0; right: auto; width: 1.25em; bottom: 16px; }
  .site-nav__list li + li { border-top: 1px solid var(--chrome-rule); }
  .site-nav__tools {
    padding-left: 0;
    border-left: 0;
    border-top: 1px solid var(--chrome-rule);
    padding-top: var(--pu-3);
    margin-top: var(--pu-2);
  }
}
@media (max-width: 420px) {
  .btn--chrome { padding: 0 var(--pu-3); font-size: .875rem; }
}

/* The sheet is about 200px tall, so most of the page stays visible while it
   is open, and inert, which makes a normal-looking hero button do nothing
   when it is tapped. The dim says the page is out of play and gives the tap
   somewhere to land. NOT the gradient scrim home.css forbids across the
   photographs: a flat dim over the whole viewport, only while the menu is
   open. The header is z-index 50 and the sheet is its descendant, so both
   stay above this. */
.nav-scrim { display: none; }
@media (max-width: 1023px) {
  .nav-scrim:not([hidden]) {
    display: block;
    position: fixed;
    inset: 0;
    z-index: 85;
    background: color-mix(in srgb, var(--pu-ink-deep) 55%, transparent);
  }
}
@media (max-width: 1023px) and (prefers-color-scheme: dark) {
  /* 55% ink-deep over an ink-deep page composites back to ink-deep: no scrim
     can darken the darkest token in the palette, so the separation moves onto
     the SHEET instead. Ink over ink-deep is the step the section alternation
     already uses, plus the hairline of DESIGN.md 5. */
  .site-nav {
    background: var(--s-read-card);
    border-bottom-color: var(--pu-ink-raised);
  }
}

/* --------------------------------------------------------------- footer -- */

/* Always ink-deep, in both themes, so it carries the ink-safe accent set.
   Without this the mark's pine facet renders at 2.31:1 here in light theme. */
.site-footer {
  background: var(--pu-ink-deep);
  color: var(--pu-bone);
  --mark-a: var(--pu-ember);
  --mark-b: var(--pu-pine-bright);
  --danger-text: var(--pu-danger-on-ink);
}
.site-footer a { color: var(--pu-bone); text-decoration: none; }
.site-footer a:hover { text-decoration: underline; text-underline-offset: .2em; }

.footer-grid {
  display: grid;
  gap: var(--pu-7);
  grid-template-columns: 1fr;
  padding-block: var(--pu-8);
}
/* Four blocks, so three columns orphaned the KVKK group onto row two with two
   empty cells beside it. Two by two until 1024 has room for the real four. */
/* THREE blocks now that the KVKK column is gone, so the track count follows.
   A four-track rule would leave the last one empty, which is not neutral: the
   footer's content would sit left of centre with a hole where a column used
   to be, and it reads as a rendering fault rather than as a shorter footer.
   Two by two on tablet, three across from 1024. */
@media (min-width: 768px) { .footer-grid { grid-template-columns: 1fr 1fr; gap: var(--pu-7) var(--pu-6); } }
@media (min-width: 1024px) { .footer-grid { grid-template-columns: 1.7fr 1fr 1.1fr; } }

.footer-heading {
  font-size: .75rem;
  font-weight: 600;
  font-stretch: 82%;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--pu-ink-muted);
  margin-bottom: var(--pu-4);
}
.footer-list { list-style: none; }
.footer-list li + li { margin-top: var(--pu-1); }
.footer-list a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  font-size: .9375rem;
}

.legal-identity {
  border-top: 1px solid rgba(243, 235, 226, .12);
  padding-block: var(--pu-6);
  font-size: .8125rem;
  line-height: 1.7;
  color: var(--pu-ink-muted);
}
.legal-identity strong { color: var(--pu-bone); font-weight: 600; }
.legal-identity p { max-width: 92ch; }
.legal-identity .placeholder { color: var(--pu-sand); }

/* Bracketed field that is not yet filled from an official document. */
/* These are the fields that block publication, so they must always be fully
   readable. nowrap plus the body's overflow-x:hidden clipped them off-screen
   on a phone, which is the one place they most need to be noticed. */
.placeholder {
  font-family: var(--pu-font-mono);
  font-size: .9em;
  color: var(--signal);
  overflow-wrap: anywhere;
}

/* ---------------------------------------------------------------- cards -- */

.card {
  border-radius: var(--pu-r-lg);
  padding: var(--pu-5);
  background: var(--card);
  box-shadow: var(--shadow);
}
@media (min-width: 768px) { .card { padding: var(--pu-6); } }
.surf-read .card { border: 1px solid var(--rule); }

.def-list { display: grid; gap: 0; }
.def-row {
  display: grid;
  gap: var(--pu-1);
  padding-block: var(--pu-4);
  border-top: 1px solid var(--rule);
}
.def-row:last-child { border-bottom: 1px solid var(--rule); }
@media (min-width: 640px) {
  .def-row { grid-template-columns: minmax(160px, 30%) 1fr; gap: var(--pu-5); align-items: baseline; }
}
.def-row dt {
  font-size: .75rem;
  font-weight: 600;
  font-stretch: 82%;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--muted);
}
.def-row dd { margin: 0; }

/* Values in a def-list sit outside .prose, so the base `a { color: inherit }`
   painted them as body text: a link that looks exactly like the value beside
   it. --link is redeclared by every surface class, so pine can never land on
   ink here. */
.def-row dd a { color: var(--link); text-underline-offset: .18em; }
.def-row dd a:hover { text-decoration-thickness: 2px; }

/* The 404 index IS that page's navigation, so its links take the 44px floor
   .breadcrumb a and .link-arrow already carry. Scoped to the modifier so the
   identity def-rows keep their baseline-aligned single-line values. */
.def-list--nav dd { display: flex; flex-wrap: wrap; gap: var(--pu-3); }
.def-list--nav dd a { display: inline-flex; align-items: center; min-height: 44px; }

/* Two-column interior layout: a sticky rail of verifiable facts beside the
   page's main block. It lives HERE, not in home.css, because /iletisim/ and
   /kurumsal/ use it and neither of them loads home.css, so the grid never
   applied and both pages rendered as one full-width stack. home.css's
   .what__body paragraph size is deliberately NOT carried over: at 0,1,1 it
   outranks .form-note, .field__hint and .field__error and would blow the
   contact form's small print up to 19px. */
.rail-grid { display: grid; gap: var(--pu-6); }
@media (min-width: 900px) {
  .rail-grid { grid-template-columns: 3fr 8fr; gap: var(--pu-8); }
  .rail-grid__rail { position: sticky; top: 108px; align-self: start; }
  /* The rail is 3fr but its min-content floor pins it near 318px, and
     .def-row's minmax(160px, 30%) label column then leaves the VALUE 134px,
     which wraps the registered address to ten lines. Inside the rail the rows
     stay stacked. Below 900 the rail is full width and the two-column rows are
     correct, which is why this is scoped here. */
  .rail-grid__rail .def-row { grid-template-columns: 1fr; gap: var(--pu-1); }
}
.rail-grid__body > * + * { margin-top: var(--pu-6); }

.identity__grid { display: grid; gap: var(--pu-7); }
/* 4fr of twelve minus a 96px gutter is 247px at 900px, about 12em for the
   19.6px lead inside it: six lines of roughly 24 characters. 5fr against a
   64px gutter is 328px, and the heading tracks that column, not the viewport. */
@media (min-width: 900px) {
  .identity__grid { grid-template-columns: 5fr 7fr; gap: var(--pu-8); }
  .identity__grid > div > .h1 { font-size: clamp(1.625rem, 0.6rem + 2.2vw, 3rem); }
}

/* ------------------------------------------------------------------ SEO -- */

.tag {
  display: inline-flex;
  align-items: center;
  gap: var(--pu-2);
  padding: var(--pu-1) var(--pu-3);
  border: 1px solid var(--rule);
  border-radius: var(--pu-r-sm);
  font-size: .75rem;
  font-weight: 600;
  font-stretch: 82%;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--muted);
}
.tag--signal { border-color: var(--signal-ui); color: var(--signal); }

/* --------------------------------------------------------------- motion -- */

/* Discrete reveal. IntersectionObserver adds .is-in. Works everywhere, one shot.
   Arrival along a path with deceleration, per DESIGN.md 6. Nothing bounces. */
.reveal {
  opacity: 0;
  transform: translate3d(0, 18px, 0);
  transition: opacity 700ms var(--pu-ease), transform 700ms var(--pu-ease);
  transition-delay: var(--reveal-delay, 0ms);
}
.reveal.is-in { opacity: 1; transform: none; }
.js-off .reveal, .no-js .reveal { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important;
    transition-duration: .01ms !important;
    animation-iteration-count: 1 !important;
  }
  .reveal { opacity: 1; transform: none; }
}

/* -------------------------------------------------------- cookie consent -- */

.consent {
  position: fixed;
  inset-inline: 0;
  bottom: 0;
  z-index: 80;
  padding: var(--pu-4) var(--pu-safe-r) max(var(--pu-4), env(safe-area-inset-bottom, 0px)) var(--pu-safe-l);
  background: var(--pu-ink);
  color: var(--pu-bone);
  border-top: 1px solid rgba(243, 235, 226, .16);
}
.consent[hidden] { display: none; }
.consent__inner {
  max-width: var(--pu-w-std);
  margin-inline: auto;
  display: grid;
  gap: var(--pu-4);
}
@media (min-width: 900px) {
  .consent__inner { grid-template-columns: 1fr auto; align-items: center; gap: var(--pu-6); }
}
.consent__text { font-size: .9375rem; line-height: 1.55; max-width: 72ch; color: var(--pu-ink-muted); }
.consent__text a { color: var(--pu-pine-bright); }
/* Reject is exactly as prominent as accept. KVKK, no dark patterns, and that
   has to hold at every width. A flex row with min-width put the third button,
   accept, the FILLED one, alone on its own line and grew it to full width
   between roughly 410px and 560px, which is the shape of a nudge nobody
   wrote. A grid makes the three equal by construction. */
.consent__actions { display: grid; gap: var(--pu-2); }
@media (min-width: 600px) {
  .consent__actions { grid-auto-flow: column; grid-auto-columns: 1fr; }
}

/* In dark theme --s-read is ink-deep and ::backdrop is ink-deep at 60%, so a
   borderless panel is 1.00:1 against its own backdrop: it has no edge at all.
   DESIGN.md 5, separation on ink is a hairline and never a shadow. */
.consent-panel {
  border: 1px solid var(--s-read-rule);
  border-radius: var(--pu-r-lg);
  padding: 0;
  max-width: min(560px, calc(100vw - 2 * var(--pu-4)));
  width: 100%;
  background: var(--s-read);
  color: var(--s-read-fg);
  /* The dialog is body-level, outside every .surf-* class, so the surface
     aliases the utility classes read are unset here and .u-muted rendered at
     the inherited colour. Same reason .site-nav restates its own pair. */
  --muted: var(--s-read-muted);
}
@media (prefers-color-scheme: dark) {
  /* bone at 12% is 1.36:1 on ink-deep, which is not an edge. ink-raised is the
     same hairline the dark section joins already use. */
  .consent-panel { border-color: var(--pu-ink-raised); }
}
.consent-panel::backdrop { background: rgba(15, 22, 21, .6); }
/* Without dialog support the element is a plain block and would sit open on
   every page. Closed means hidden, whatever the browser thinks a dialog is. */
.consent-panel:not([open]) { display: none; }
.consent-panel__body { padding: var(--pu-6); }
.consent-panel__foot {
  display: flex; flex-wrap: wrap; gap: var(--pu-2);
  padding: var(--pu-5) var(--pu-6);
  border-top: 1px solid var(--s-read-rule);
}

.switch-row {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: var(--pu-3) var(--pu-4);
  align-items: start;
  padding-block: var(--pu-4);
  border-top: 1px solid var(--s-read-rule);
}
.switch-row:first-of-type { border-top: 0; }
.switch-row p { font-size: .875rem; color: var(--s-read-muted); margin-top: var(--pu-1); }

.switch { position: relative; display: inline-flex; align-items: center; min-height: 44px; }
.switch input { position: absolute; opacity: 0; width: 44px; height: 44px; margin: 0; cursor: pointer; }
.switch__track {
  width: 44px; height: 26px;
  border-radius: var(--pu-r-full);
  background: color-mix(in srgb, var(--s-read-fg) 22%, transparent);
  transition: background-color var(--pu-dur-base) var(--pu-ease);
  pointer-events: none;
}
.switch__track::after {
  content: '';
  position: absolute;
  top: 50%; left: 3px;
  width: 20px; height: 20px;
  margin-top: -10px;
  border-radius: var(--pu-r-full);
  background: var(--s-read);
  transition: transform var(--pu-dur-base) var(--pu-ease);
}
.switch input:checked + .switch__track { background: var(--s-read-link); }
.switch input:checked + .switch__track::after { transform: translateX(18px); }
.switch input:disabled + .switch__track { opacity: .5; }
.switch input:focus-visible + .switch__track { outline: 2px solid var(--pu-focus); outline-offset: 2px; }

/* ----------------------------------------------------------------- forms -- */

.field { display: grid; gap: var(--pu-2); }
.field__label { font-weight: 600; font-size: .9375rem; }
.field__hint { font-size: .8125rem; color: var(--muted); }
.field input[type='text'],
.field input[type='email'],
.field input[type='tel'],
.field select,
.field textarea {
  width: 100%;
  min-height: 44px;
  padding: var(--pu-3) var(--pu-4);
  background: var(--card);
  color: var(--fg);
  border: 1px solid color-mix(in srgb, var(--fg) 20%, transparent);
  border-radius: var(--pu-r-sm);
  transition: border-color var(--pu-dur-fast) var(--pu-ease);
}
.field textarea { min-height: 148px; resize: vertical; line-height: 1.6; }
.field input::placeholder, .field textarea::placeholder { color: var(--muted); opacity: 1; }
.field input:hover, .field textarea:hover, .field select:hover {
  border-color: color-mix(in srgb, var(--fg) 38%, transparent);
}
.field[data-invalid='true'] input,
.field[data-invalid='true'] textarea { border-color: var(--pu-danger); border-width: 2px; }

.field__error {
  display: none;
  align-items: center;
  gap: var(--pu-2);
  font-size: .8125rem;
  font-weight: 600;
  color: var(--danger-text, var(--pu-danger-on-bone));
}
.field[data-invalid='true'] .field__error { display: flex; }
.field__error svg { width: 16px; height: 16px; flex-shrink: 0; }

.check-row {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: var(--pu-3);
  align-items: start;
  padding-block: var(--pu-2);
}
/* The box itself clears the 24px WCAG 2.5.8 floor; the associated <label> is
   part of the activation area and supplies the larger comfortable target. */
.check-row input[type='checkbox'] {
  width: 24px; height: 24px;
  margin: 10px 0 0;
  accent-color: var(--link);
  flex-shrink: 0;
  cursor: pointer;
}
.check-row label { padding-block: var(--pu-2); font-size: .9375rem; line-height: 1.5; cursor: pointer; }
.check-row a { color: var(--link); }

.form-note {
  padding: var(--pu-4);
  border-inline-start: 2px solid var(--rule);
  font-size: .875rem;
  line-height: 1.6;
  color: var(--muted);
}
.form-note a { color: var(--link); }

/* A live region has to be in the accessibility tree BEFORE its text changes,
   or the first message is the CREATION of a region and no screen reader reads
   it. So it is present and named from load, and collapsed with the same idiom
   .visually-hidden uses rather than display:none. The margin:0 matters: the
   form is .stack-5, and this selector at 0,2,0 outranks .stack-5 > * + * at
   0,1,1, so no phantom gap appears under the submit button. */
.form-status {
  display: flex;
  gap: var(--pu-3);
  padding: var(--pu-4);
  border-radius: var(--pu-r-md);
  font-size: .9375rem;
  align-items: flex-start;
}
.form-status:not([data-state]) {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: 0;
  overflow: hidden;
  clip-path: inset(50%);
}
.form-status[data-state='ok'] { background: color-mix(in srgb, var(--pu-success) 16%, transparent); }
.form-status[data-state='error'] { background: color-mix(in srgb, var(--pu-danger) 16%, transparent); }
.form-status svg { width: 20px; height: 20px; flex-shrink: 0; margin-top: 2px; }

/* --------------------------------------------------------------- utility -- */

.u-muted { color: var(--muted); }
.u-signal { color: var(--signal); }
.u-nowrap { white-space: nowrap; }
.u-center { text-align: center; }
/* .u-mt-5 was in the markup on four pages and defined in none of them, so
   every paragraph that asked for a 24px top margin got zero. */
.u-mt-5 { margin-top: var(--pu-5); }
.u-mt-6 { margin-top: var(--pu-6); }
.u-mt-7 { margin-top: var(--pu-7); }
.u-mt-8 { margin-top: var(--pu-8); }

.cluster { display: flex; flex-wrap: wrap; gap: var(--pu-3); align-items: center; }

/* Same promise-not-status rule for the nav toggle: the glyph shows what the
   button will DO, and aria-expanded carries the state, so the accessible name
   stays the plain noun "Menu" instead of contradicting itself with
   "Open menu, expanded". */
.nav-toggle .icon-close { display: none; }
.nav-toggle[aria-expanded='true'] .icon-menu { display: none; }
.nav-toggle[aria-expanded='true'] .icon-close { display: block; }

/* Scroll-driven scrubs must be linear. An arrival ease on a scrubbed timeline
   lies about position: the drawing runs ahead of or behind the scrollbar.
   --pu-ease is for time-based arrivals only. */

/* Cross-document view transitions. This is a real multi-page site with real
   navigations, so the browser can cross-fade one document into the next
   instead of flashing white between them. Two lines, no JavaScript, no
   router: browsers without it navigate exactly as they do today.

   The header and the footer are named, so they stay PUT while the page under
   them changes, which is what makes the chrome read as chrome rather than as
   part of the page that just left. */
@view-transition { navigation: auto; }
.site-header { view-transition-name: site-header; }
.site-footer { view-transition-name: site-footer; }

::view-transition-group(root) { animation-duration: var(--pu-dur-base); }
::view-transition-old(root) {
  animation: vt-out var(--pu-dur-fast) var(--pu-ease-in) both;
}
::view-transition-new(root) {
  animation: vt-in var(--pu-dur-base) var(--pu-ease) both;
}
@keyframes vt-out { to { opacity: 0; } }
@keyframes vt-in { from { opacity: 0; transform: translate3d(0, 8px, 0); } }

@media (prefers-reduced-motion: reduce) {
  /* Not a zeroed animation: `animation: none` on root alone leaves the old and
     the new snapshot stacked under the UA's plus-lighter blend for as long as
     the NAMED header and footer groups keep the transition alive, which is a
     double exposure of the whole page. A visitor who asked for no motion gets
     no transition at all. */
  @view-transition { navigation: none; }

  /* Fallback for engines that ignore @view-transition inside @media. The
     wildcard is load-bearing: (root) does not cover site-header/site-footer. */
  ::view-transition-group(*),
  ::view-transition-new(*) { animation: none !important; }
  ::view-transition-old(*) { animation: none !important; opacity: 0; }
}

/* ======================================================== interior pages -- */

/* Every page below the home page opens on an ink block, so the brand surface
   is what the visitor lands on and the reading surface is what follows.
   DESIGN.md 1.2: ink is the primary surface, bone is the relief surface. */
.page-head {
  background: var(--pu-ink);
  color: var(--pu-bone);
  --fg: var(--pu-bone);
  --muted: var(--pu-ink-muted);
  --link: var(--pu-pine-bright);
  --signal: var(--pu-ember);
  --notice-fg: var(--pu-ember);
  --rule: rgba(243, 235, 226, .12);
  --mark-a: var(--pu-ember);
  --mark-b: var(--pu-pine-bright);
  --danger-text: var(--pu-danger-on-ink);
  padding-block: var(--pu-8) var(--pu-8);
}
@media (min-width: 768px) { .page-head { padding-block: var(--pu-9) var(--pu-9); } }
.page-head__title { max-width: 20ch; }
.page-head .lead { margin-top: var(--pu-5); max-width: 52ch; }

.breadcrumb {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--pu-2);
  margin-bottom: var(--pu-5);
  font-size: .75rem;
  font-weight: 600;
  font-stretch: 82%;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--muted);
}
.breadcrumb a { color: inherit; text-decoration: none; min-height: 44px; display: inline-flex; align-items: center; }
.breadcrumb a:hover { color: var(--fg); text-decoration: underline; text-underline-offset: .2em; }
.breadcrumb span[aria-hidden] { opacity: .5; }

/* A visible, unmissable statement that a page is not yet cleared for
   publication. Never styled to blend in: the point is that it is noticed. */
.notice {
  display: grid;
  gap: var(--pu-3);
  padding: var(--pu-5);
  border: 1px solid var(--signal-ui, var(--signal));
  border-inline-start-width: 3px;
  border-radius: var(--pu-r-md);
  background: color-mix(in srgb, var(--signal) 8%, transparent);
}
.notice__title {
  font-size: .75rem;
  font-weight: 600;
  font-stretch: 82%;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--notice-fg, var(--signal));
}
.notice p { font-size: .9375rem; line-height: 1.6; }
.notice ul { padding-left: 1.25em; font-size: .9375rem; }
.notice li + li { margin-top: var(--pu-1); }

.doc-meta {
  display: flex;
  flex-wrap: wrap;
  gap: var(--pu-2) var(--pu-5);
  padding-block: var(--pu-4);
  border-top: 1px solid var(--rule);
  border-bottom: 1px solid var(--rule);
  font-size: .8125rem;
  color: var(--muted);
}
.doc-meta dl { display: flex; gap: var(--pu-2); margin: 0; }
.doc-meta dt { font-weight: 600; }
.doc-meta dd { margin: 0; }

/* Numbered legal sections. One hairline above each group, never a rule under
   every row: a hairline per row is the laziest possible layout. */
.doc-section { padding-top: var(--pu-7); }
.doc-section + .doc-section { margin-top: var(--pu-7); border-top: 1px solid var(--rule); }
.doc-section > h2 { display: flex; gap: var(--pu-4); align-items: baseline; }
.doc-section > h2 > .doc-num {
  font-family: var(--pu-font-mono);
  font-size: .8125rem;
  color: var(--link);
  font-variant-numeric: tabular-nums;
  flex-shrink: 0;
}
.doc-section > * + * { margin-top: var(--pu-5); }

/* The legal pages use .wrap--prose, which is a container WIDTH, and never
   .prose, so the .prose ul / .prose li rules never reached them: markers hung
   in the gutter outside the text column, items ran together at line-height
   1.6, and an <li> measured about 82ch against the 68ch cap on the <p> above
   it. DESIGN.md 4.2. The values are the .prose ones so the two cannot drift,
   and the margin is :where()-wrapped so an explicit .stack still wins. */
/* Legal documents are deliberately NOT .prose: their rhythm comes from
   .doc-section, and adding .prose would also recolour the identity block's
   mono e-mail on /yasal-bilgiler/, which is a VALUE on every other page. So
   the reading rules .prose supplies are restated for this container. --link
   is redeclared by every surface class, so this is pine on bone and
   pine-bright on ink by construction. */
.doc-section a { color: var(--link); text-underline-offset: .18em; }
.doc-section a:hover { text-decoration-thickness: 2px; }
.doc-section ul, .doc-section ol { padding-left: 1.25em; }
.doc-section li { max-width: 66ch; }
:where(.doc-section li + li) { margin-top: var(--pu-2); }

.table-wrap { overflow-x: auto; }
table.data {
  width: 100%;
  min-width: 520px;
  border-collapse: collapse;
  font-size: .9375rem;
}
table.data caption { text-align: left; font-size: .875rem; color: var(--muted); padding-bottom: var(--pu-3); }
table.data th, table.data td { text-align: left; padding: var(--pu-3) var(--pu-4) var(--pu-3) 0; vertical-align: top; }
table.data td:last-child, table.data th:last-child { padding-right: 0; }
table.data thead th {
  font-size: .75rem;
  font-weight: 600;
  font-stretch: 82%;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--muted);
  border-bottom: 1px solid var(--rule);
}
table.data tbody tr + tr td { border-top: 1px solid var(--rule); }
table.data .num { text-align: right; font-variant-numeric: tabular-nums; }

/* Numbered steps as a plain list. NOTHING USES THIS TODAY: both places that
   did - the /urunler/ sidebar card and the /urunler/madvise/ section - are now
   the four animated step cards in steps.css. It stays because it is the shape
   any future numbered how-it-works reaches for when a scene would be noise,
   and because it costs nine lines. */
.step-list { counter-reset: s; list-style: none; }
.step-list li { counter-increment: s; display: grid; grid-template-columns: auto 1fr; gap: var(--pu-4); padding-block: var(--pu-4); }
.step-list li + li { border-top: 1px solid var(--rule); }
.step-list li::before {
  content: counter(s, decimal-leading-zero);
  font-family: var(--pu-font-mono);
  font-size: .8125rem;
  color: var(--link);
  font-variant-numeric: tabular-nums;
}

.footer-blurb { color: var(--pu-ink-muted); max-width: 34ch; }

/* ------------------------------------------------------------------ print --
   Browsers drop background colours by default, and .page-head, .surf-brand,
   .site-footer, .legal-identity and, in dark theme, .surf-read each declare a
   BONE colour ON THEMSELVES, so a rule on `body` never reached them: the page
   title, the lead and the whole footer legal-identity block printed bone on
   white at 1.05:1, and with the dark theme on so did the entire document.
   That is a definition-of-done failure, not a nicety: CLAUDE.md 9 requires the
   footer to carry the full legal name on every page, and a printed or PDF-ed
   page did not.

   Force the bone-surface pair and re-point the per-surface accents at their
   bone-safe values, so a printed link is pine (6.72:1) and never pine-bright
   (2.75:1 on paper). DESIGN.md 3.3.

   THIS BLOCK MUST STAY LAST IN THE FILE. It has the same specificity as the
   rules it corrects, so source order is what makes it win. */
@media print {
  .site-header, .consent, .site-nav, .site-nav__tools, .nav-toggle,
  .nav-scrim, .btn--chrome { display: none !important; }
  body { background: white; color: black; }

  .page-head, .surf-read, .surf-brand, .surf-brand--deep,
  .site-footer, .legal-identity, .footer-blurb {
    background: none !important;
    color: var(--pu-ink) !important;
    --fg: var(--pu-ink) !important;
    --muted: var(--pu-ink) !important;
    --rule: rgba(28, 40, 38, .35) !important;
    --link: var(--pu-pine) !important;
    --signal: var(--pu-ember-deep) !important;
    --signal-ui: var(--pu-ember-ui) !important;
    --notice-fg: var(--pu-ember-notice) !important;
    --danger-text: var(--pu-danger-on-bone) !important;
    --mark-a: var(--pu-ember-ui) !important;
    --mark-b: var(--pu-pine) !important;
  }
  .site-footer a, .legal-identity strong, .legal-identity .placeholder {
    color: var(--pu-ink) !important;
  }

  .doc-section, .notice, .def-row, .doc-meta, table.data tr { break-inside: avoid; }
  .doc-section > h2 { break-after: avoid; }
}
