/* ==========================================================================
   itkab.com — layout and components
   Reads tokens.css. Load tokens.css first, always.
   ========================================================================== */

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

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--graphite);
  color: var(--bone);
  font-family: var(--body);
  font-size: var(--t-body);
  line-height: 1.7;
  font-synthesis-weight: none;
  -webkit-font-smoothing: antialiased;
  overflow-wrap: break-word;
}

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

a { color: var(--bone); text-decoration-color: var(--steel-dim); text-underline-offset: 3px; }
a:hover { text-decoration-color: var(--hazard); }

:focus-visible {
  outline: 2px solid var(--hazard);
  outline-offset: 3px;
  border-radius: 2px;
}

::selection { background: var(--hazard); color: var(--on-hazard); }

/* --- Atmosphere. Hairline grid, one warm bloom, a little grain. ---------- */

.field {
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background:
    radial-gradient(58rem 34rem at 50% -14rem, var(--bloom-1), transparent 68%),
    radial-gradient(44rem 30rem at 88% 8%, var(--bloom-2), transparent 70%),
    linear-gradient(var(--graphite), var(--graphite-deep));
}

.field::before {
  content: "";
  position: absolute;
  inset: -1px;
  background-image:
    linear-gradient(to right, var(--grid-line) 1px, transparent 1px),
    linear-gradient(to bottom, var(--grid-line) 1px, transparent 1px);
  background-size: 88px 88px;
  /* #000 here is mask alpha, not a colour: opaque in both themes. */
  mask-image: radial-gradient(72rem 54rem at 50% 0%, #000 0%, transparent 82%);
}

.field::after {
  content: "";
  position: absolute;
  inset: 0;
  opacity: var(--grain-opacity);
  mix-blend-mode: var(--grain-blend);
  background-image: url("data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 width=%22140%22 height=%22140%22%3E%3Cfilter id=%22n%22%3E%3CfeTurbulence type=%22fractalNoise%22 baseFrequency=%220.85%22 numOctaves=%223%22/%3E%3C/filter%3E%3Crect width=%22140%22 height=%22140%22 filter=%22url(%23n)%22 opacity=%220.55%22/%3E%3C/svg%3E");
}

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

.shell {
  width: 100%;
  max-width: var(--shell);
  margin-inline: auto;
  padding-inline: var(--s5);
}

.skip {
  position: absolute;
  left: -9999px;
  top: var(--s3);
  z-index: 10;
  padding: var(--s2) var(--s4);
  background: var(--hazard);
  color: var(--on-hazard);
  font-family: var(--mono);
  font-size: var(--t-sm);
}
.skip:focus { left: var(--s5); }

/* --- Shared type helpers ------------------------------------------------ */

.eyebrow {
  margin: 0;
  font-family: var(--mono);
  font-size: var(--t-label);
  font-weight: 500;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--steel);
}

.mono { font-family: var(--mono); font-feature-settings: "zero" 1; }

/* Available to a screen reader, absent from the page. */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* --- Masthead ----------------------------------------------------------- */

.masthead {
  border-bottom: 1px solid var(--hairline-soft);
  background: var(--masthead-bg);
  backdrop-filter: blur(8px);
  position: sticky;
  top: 0;
  z-index: 5;
}

.masthead-inner {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--s2) var(--s5);
  padding-block: var(--s3);
}

.brand {
  margin-right: auto;   /* holds nav and toggle together at the right */
  display: inline-flex;
  align-items: baseline;
  gap: var(--s2);
  text-decoration: none;
  font-family: var(--display);
  font-weight: 800;
  font-size: var(--t-h3);
  letter-spacing: -0.03em;
  color: var(--bone);
}
.brand::before {
  content: "";
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--verdigris);
  box-shadow: 0 0 0 3px var(--verdigris-wash);
  transform: translateY(-1px);
}
.brand-tail { color: var(--steel-dim); font-weight: 400; }

.nav {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s5);
  font-family: var(--mono);
  font-size: var(--t-xs);
  letter-spacing: 0.04em;
}
.nav a {
  text-decoration: none;
  color: var(--steel);
  padding-block: var(--s1);
  border-bottom: 1px solid transparent;
  transition: color 0.18s var(--ease), border-color 0.18s var(--ease);
}
.nav a:hover, .nav a[aria-current="page"] {
  color: var(--bone);
  border-bottom-color: var(--hazard);
}

/* --- Theme toggle -------------------------------------------------------
   A contrast disc: one circle, half of it filled. It belongs to the same
   family as the brand mark and the severity dots rather than to the sun and
   moon every other site ships. The icon is inline SVG using currentColor, so
   it costs no request and needs no per-theme artwork.

   The button carries no visible text, so its accessible name has to do all
   the work. theme.js keeps it set to the ACTION ("Switch to light theme"),
   which is why there is no aria-pressed: an action name plus a pressed state
   reads as "switch to light theme, pressed".
   ---------------------------------------------------------------------- */

.theme-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: 34px;
  height: 34px;
  padding: 0;
  border: 1px solid var(--hairline);
  border-radius: 50%;
  background: transparent;
  color: var(--steel);
  cursor: pointer;
  transition: color 0.16s var(--ease), border-color 0.16s var(--ease),
              transform 0.16s var(--ease);
}

.theme-toggle svg {
  width: 15px;
  height: 15px;
  display: block;
  /* The disc reads as half dark, half light. Turning it over is the whole
     idea of the control, so the rotation is the state change, not decoration. */
  transform: rotate(0deg);
  transition: transform 0.45s var(--ease);
}
:root[data-theme="light"] .theme-toggle svg { transform: rotate(180deg); }

.theme-toggle:hover {
  color: var(--bone);
  border-color: var(--steel-dim);
  transform: translateY(-1px);
}
.theme-toggle:active { transform: translateY(0); }

/* No JavaScript, no working control. Better absent than inert. The inline
   head script sets data-js before first paint, so this hides the button
   without ever showing it and taking it away again. */
:root:not([data-js]) .theme-toggle { display: none; }

/* --- Bands. One vertical rhythm class, no competing section paddings. --- */

.band { padding-block: var(--s8); }
.band-tight { padding-block: var(--s7); }
.band-rule { border-top: 1px solid var(--hairline-soft); }

.band-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s4);
  flex-wrap: wrap;
  margin-bottom: var(--s5);
}
.band-head h2 {
  margin: 0;
  font-family: var(--display);
  font-size: var(--t-h2);
  font-weight: 700;
  letter-spacing: -0.025em;
}
.band-head p { margin: 0; color: var(--steel); font-size: var(--t-sm); max-width: 42ch; }

/* --- Hero: the decoder is the hero, not a headline above a form. -------- */

.hero { padding-block: var(--s8) var(--s7); }

/* The hero text is capped well short of the shell width, so on a wide screen
   the right half is empty. .logfield fills it (see the block near the end of
   this file). Everything else in the hero has to sit above it. */
.hero[data-logfield] { position: relative; }
/* :not(.logfield) matters. Without it this selector outranks .logfield's own
   position: absolute, which collapses the field to zero height and its
   overflow: hidden then clips the whole thing away. */
.hero[data-logfield] > *:not(.logfield) { position: relative; z-index: 1; }

.hero h1 {
  margin: var(--s4) 0 var(--s5);
  font-family: var(--display);
  font-size: var(--t-hero);
  font-weight: 800;
  font-stretch: 92%;
  line-height: 0.95;
  letter-spacing: -0.045em;
  max-width: 18ch;
}
.hero h1 em {
  font-style: normal;
  color: var(--hazard);
}

.hero-sub {
  margin: 0 0 var(--s6);
  max-width: 54ch;
  color: var(--steel);
  font-size: var(--t-lead);
}

/* --- Probe: the oversized input ---------------------------------------- */

.probe { margin: 0; }

.probe-label {
  display: block;
  font-family: var(--mono);
  font-size: var(--t-label);
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--steel-dim);
  margin-bottom: var(--s3);
}

.probe-row {
  display: flex;
  align-items: stretch;
  border: 1px solid var(--hairline);
  border-radius: var(--radius-lg);
  background: linear-gradient(180deg, var(--panel-high), var(--panel));
  box-shadow: var(--lift-2);
  overflow: hidden;
  transition: border-color 0.2s var(--ease), box-shadow 0.2s var(--ease);
}
.probe-row:focus-within {
  border-color: var(--hazard-deep);
  box-shadow: var(--lift-2), 0 0 0 4px var(--hazard-wash);
}

.probe-input {
  flex: 1 1 auto;
  min-width: 0;
  border: 0;
  background: transparent;
  color: var(--bone);
  font-family: var(--mono);
  font-size: var(--t-num);
  font-weight: var(--w-display);
  letter-spacing: -0.01em;
  padding: var(--s5);
}
.probe-input::placeholder { color: var(--steel-dim); }
.probe-input:focus { outline: none; }

.probe-go {
  flex: 0 0 auto;
  border: 0;
  border-left: 1px solid var(--hairline);
  background: var(--hazard);
  color: var(--on-hazard);
  font-family: var(--mono);
  font-size: var(--t-xs);
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  padding-inline: var(--s5);
  cursor: pointer;
  transition: transform 0.16s var(--ease), background-color 0.16s var(--ease);
}
.probe-go:hover { background: var(--hazard-lift); }
.probe-go:active { transform: translateY(1px); }

.probe-hint {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s2);
  margin-top: var(--s4);
  font-family: var(--mono);
  font-size: var(--t-dense);
  color: var(--steel-dim);
}
.chip {
  border: 1px solid var(--hairline);
  background: transparent;
  color: var(--steel);
  font-family: var(--mono);
  font-size: var(--t-dense);
  padding: var(--s1) var(--s3);
  border-radius: 999px;
  cursor: pointer;
  transition: color 0.16s var(--ease), border-color 0.16s var(--ease), transform 0.16s var(--ease);
}
.chip:hover { color: var(--bone); border-color: var(--steel-dim); transform: translateY(-1px); }

/* --- Readout: the signature. Builds line by line like console output. --- */

.readout {
  margin-top: var(--s6);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-lg);
  background: var(--panel);
  box-shadow: var(--lift-1);
  overflow: hidden;
}
.readout[hidden] { display: none; }

.readout-bar {
  display: flex;
  align-items: center;
  gap: var(--s3);
  flex-wrap: wrap;
  padding: var(--s4) var(--s5);
  border-bottom: 1px solid var(--hairline-soft);
  background: var(--panel-high);
}

.dot {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  flex: 0 0 auto;
  background: var(--steel);
}
.readout[data-severity="fail"] .dot { background: var(--oxide); box-shadow: 0 0 0 4px var(--oxide-wash); }
.readout[data-severity="warn"] .dot { background: var(--hazard); box-shadow: 0 0 0 4px var(--hazard-wash); }
.readout[data-severity="info"] .dot { background: var(--verdigris); box-shadow: 0 0 0 4px var(--verdigris-wash); }

.readout-code {
  font-family: var(--mono);
  color: var(--bone);
  font-size: var(--t-lead);
  font-weight: 600;
  letter-spacing: -0.01em;
}
.readout[data-severity="fail"] .readout-code { color: var(--oxide); }
.readout[data-severity="warn"] .readout-code { color: var(--hazard); }
.readout[data-severity="info"] .readout-code { color: var(--verdigris); }

.readout-tags {
  display: flex;
  gap: var(--s2);
  flex-wrap: wrap;
  margin-left: auto;
  font-family: var(--mono);
  font-size: var(--t-label);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--steel);
}
.readout-tags span {
  border: 1px solid var(--hairline);
  border-radius: 999px;
  padding: 2px var(--s3);
}

.row {
  display: grid;
  grid-template-columns: 8.5rem 1fr;
  gap: var(--s4);
  padding: var(--s4) var(--s5);
  border-bottom: 1px solid var(--hairline-soft);
}
.row:last-of-type { border-bottom: 0; }
.row dt {
  font-family: var(--mono);
  font-size: var(--t-label);
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--steel-dim);
  padding-top: 0.45rem;
}
.row dd { margin: 0; }
.row ol, .row ul { margin: 0; padding-left: 1.15rem; }
.row li { margin-bottom: var(--s2); }
.row li:last-child { margin-bottom: 0; }

code {
  font-family: var(--mono);
  color: var(--bone);
  font-size: 0.875em;
  background: var(--graphite-deep);
  border: 1px solid var(--hairline-soft);
  border-radius: var(--radius);
  padding: 0.1em 0.4em;
  word-break: break-word;
}

.readout-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s4);
  flex-wrap: wrap;
  padding: var(--s4) var(--s5);
  background: var(--panel-high);
  border-top: 1px solid var(--hairline-soft);
  font-family: var(--mono);
  font-size: var(--t-xs);
  color: var(--steel);
}
.readout-foot a { color: var(--hazard); text-decoration: none; }
.readout-foot a:hover { text-decoration: underline; }

.readout.is-live .readout-bar,
.readout.is-live .row,
.readout.is-live .readout-foot {
  animation: line-in 0.42s var(--ease) both;
  animation-delay: calc(var(--i, 0) * 65ms);
}

@keyframes line-in {
  from { opacity: 0; transform: translateY(6px); clip-path: inset(0 100% 0 0); }
  to   { opacity: 1; transform: none; clip-path: inset(0 0 0 0); }
}

/* --- Lists: documented codes ------------------------------------------- */

.code-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
  gap: 1px;
  background: var(--hairline-soft);
  border: 1px solid var(--hairline-soft);
  border-radius: var(--radius-lg);
  overflow: hidden;
}

.code-cell {
  display: block;
  padding: var(--s4) var(--s5);
  background: var(--panel);
  text-decoration: none;
  transition: background-color 0.18s var(--ease);
}
.code-cell:hover { background: var(--panel-high); }
.code-cell strong {
  display: block;
  font-family: var(--mono);
  font-size: var(--t-sm);
  font-weight: 600;
  color: var(--bone);
  margin-bottom: var(--s1);
}
.code-cell span { display: block; font-size: var(--t-sm); color: var(--steel); line-height: 1.5; }
.code-cell[data-severity="fail"] strong { color: var(--oxide); }
.code-cell[data-severity="warn"] strong { color: var(--hazard); }
.code-cell[data-severity="info"] strong { color: var(--verdigris); }

/* --- Lists: field notes ------------------------------------------------- */

.notes { display: grid; gap: 1px; background: var(--hairline-soft); border-block: 1px solid var(--hairline-soft); }

.note {
  display: grid;
  grid-template-columns: 9rem 1fr;
  gap: var(--s5);
  padding: var(--s5) var(--s4);
  background: var(--graphite);
  text-decoration: none;
  transition: background-color 0.18s var(--ease);
}
.note:hover { background: var(--panel); }
.note-meta {
  font-family: var(--mono);
  font-size: var(--t-label);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--steel-dim);
  padding-top: 0.4rem;
}
.note h3 {
  margin: 0 0 var(--s2);
  font-family: var(--display);
  font-size: var(--t-h3);
  font-weight: 600;
  letter-spacing: -0.02em;
  line-height: 1.25;
  transition: color 0.18s var(--ease);
}
.note p { margin: 0; color: var(--steel); font-size: var(--t-sm); max-width: 62ch; }
.note:hover h3 { color: var(--hazard); }

/* --- Ad slot. Reserved now so adding ads later shifts nothing. ---------- */

.adslot {
  min-height: 280px;
  display: grid;
  place-items: center;
  border: 1px dashed var(--hairline);
  border-radius: var(--radius-lg);
  color: var(--steel-dim);
  font-family: var(--mono);
  font-size: var(--t-label);
  letter-spacing: 0.2em;
  text-transform: uppercase;
}

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

.site-foot {
  border-top: 1px solid var(--hairline-soft);
  padding-block: var(--s6) var(--s7);
  font-size: var(--t-sm);
  color: var(--steel);
}
.foot-inner {
  display: flex;
  justify-content: space-between;
  gap: var(--s5);
  flex-wrap: wrap;
}
.foot-links { display: flex; gap: var(--s5); flex-wrap: wrap; font-family: var(--mono); font-size: var(--t-xs); }
.foot-links a { color: var(--steel); text-decoration: none; }
.foot-links a:hover { color: var(--bone); }
.foot-note { margin: 0; max-width: 46ch; color: var(--steel-dim); font-size: var(--t-sm); }

/* --- Page load: one orchestrated sequence, nothing scattered. ----------- */

.rise { animation: rise 0.75s var(--ease) both; animation-delay: calc(var(--i, 0) * 90ms); }

@keyframes rise {
  from { opacity: 0; transform: translateY(14px); }
  to   { opacity: 1; transform: none; }
}

/* --- Responsive --------------------------------------------------------- */

@media (max-width: 640px) {
  .shell { padding-inline: var(--s4); }

  /* The headline wraps ITSELF down here.

     Every hero carries a hardcoded <br> and an 18ch cap, both tuned for a wide
     screen. Keeping them on a phone is what forced --t-hero down to about
     2.07rem: "leaves your machine." is a 20 character run that overflows a
     390px viewport at anything larger. That single constraint flattened the
     whole page, because it dragged the top of the type scale down to within
     1.95x of body text while desktop enjoys 5.18x.

     Releasing both lets the headline break naturally across three lines at
     2.9rem, which restores the hierarchy to 2.73x. site-check.mjs asserts no
     horizontal overflow at 390px in both themes, and that is the real gate on
     this rule. */
  .hero h1 { max-width: none; }
  .hero h1 br { display: none; }

  .nav { gap: var(--s4); font-size: var(--t-dense); }
  /* Give the nav its own full-width row and let the brand and the toggle
     share the first one. Three stacked rows in a sticky header is a lot of a
     small screen to spend on navigation. */
  .nav { order: 3; flex: 1 0 100%; }
  .probe-row { flex-direction: column; }
  .probe-input { padding: var(--s4); }
  .probe-go { border-left: 0; border-top: 1px solid var(--hairline); padding-block: var(--s4); }
  .row { grid-template-columns: 1fr; gap: var(--s2); }
  .row dt { padding-top: 0; }
  .note { grid-template-columns: 1fr; gap: var(--s2); }
  .readout-tags { margin-left: 0; width: 100%; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-delay: 0ms !important;
    transition-duration: 0.001ms !important;
  }
}

/* --- A quiet pointer under the hero, not a second call to action. -------- */

.hero-aside {
  margin: var(--s6) 0 0;
  font-size: var(--t-sm);
  color: var(--steel-dim);
}
.hero-aside a { color: var(--hazard); text-decoration-color: var(--link-underline); }

/* --- Hero log field -----------------------------------------------------
   The site's own subject, sitting behind the claim it is making. Synthetic
   CBS lines (never anything from samples/) drift upward in the hero's empty
   right column, masked to nothing at every edge, with a slow band passing
   over them.

   Three rules this obeys:
     1. It animates transform only. Both moving parts translate; nothing else.
     2. It is absolutely positioned, so hero height stays driven by the text
        and adding it cannot reflow anything.
     3. It is desktop-only. Below 1024px it does not render at all, which is
        why the verified 390px layout cannot regress because of it.

   The markup is injected by assets/js/hero-field.js and is aria-hidden. It is
   deliberately NOT in the HTML: sixty lines of log text in index.html would
   be indexed as thin content on the site's most important page.
   ---------------------------------------------------------------------- */

.logfield {
  position: absolute;
  top: 0;
  bottom: 0;
  right: 0;
  width: 56%;
  overflow: hidden;
  pointer-events: none;
  user-select: none;
  z-index: 0;
  /* Fade toward the headline on the left and off the shell edge on the right.
     The vertical fade lives on the track, so neither element needs
     mask-composite. */
  mask-image: linear-gradient(to right, transparent 0%, #000 40%, #000 74%, transparent 97%);
}

.logfield-track {
  position: absolute;
  inset-inline: 0;
  top: 0;
  mask-image: linear-gradient(to bottom, transparent 0%, #000 14%, #000 80%, transparent 100%);
  animation: logfield-drift 96s linear infinite;
  will-change: transform;
}

/* The list is generated twice, so translating by exactly half its height
   returns to an identical frame and the loop has no seam. */
@keyframes logfield-drift {
  from { transform: translateY(0); }
  to   { transform: translateY(-50%); }
}

.logfield-line {
  font-family: var(--mono);
  font-size: var(--t-label);
  line-height: 1.95;
  white-space: pre;
  color: var(--logfield-dim);
  font-feature-settings: "zero" 1;
}

/* The message is the part worth reading; the timestamp and component columns
   stay quieter so the block reads as texture with structure in it. */
.logfield-line b { font-weight: 400; color: var(--logfield-ink); }

/* One line in roughly twenty-five is a real failure. A single Error standing
   out of a wall of Info is exactly what the tool does, so it is the detail
   that makes this mean something instead of just filling space. */
.logfield-line[data-level="Error"] b { color: var(--oxide); opacity: 0.75; }
.logfield-line[data-level="Warning"] b { color: var(--hazard); opacity: 0.7; }

.logfield-sweep {
  position: absolute;
  inset-inline: 0;
  top: 0;
  height: 34%;
  background: linear-gradient(to bottom, transparent, var(--logfield-sweep), transparent);
  animation: logfield-sweep 19s var(--ease) infinite;
  will-change: transform;
}

@keyframes logfield-sweep {
  from { transform: translateY(-120%); }
  to   { transform: translateY(400%); }
}

/* Below this the hero is a single column and there is no empty space to fill. */
@media (max-width: 1023px) {
  .logfield { display: none; }
}

/* The global reduced-motion block sets animation-duration to 0.001ms, which
   for an infinite loop parks it at the end state rather than stopping it.
   These want to actually stop, holding their first frame. */
@media (prefers-reduced-motion: reduce) {
  .logfield-track,
  .logfield-sweep {
    animation: none !important;
    transform: none;
  }
  .logfield-sweep { display: none; }
}
