/* Fylunor — base, shell, and shared components */

* { box-sizing: border-box; }

/* The browser's own [hidden] rule is `display: none` at the lowest possible
   specificity, so ANY class that sets display beats it and the element stays on
   screen while `el.hidden` reports true. That bit us on the demo-mode chip,
   which told people Google was not configured when it was — and it had already
   been patched five separate times per component. One rule, once. */
[hidden] { display: none !important; }

html, body { height: 100%; }
body {
  margin: 0;
  font-family: var(--font);
  font-size: var(--fs-body);
  color: var(--text);
  background: var(--bg);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overscroll-behavior-y: none;
}
/* Jakarta is wider than the old system stack, so headings get tighter tracking
   and body copy a touch more line height to stay comfortable. */
h1, h2, h3, .wordmark { letter-spacing: var(--tracking-h); font-family: var(--font-brand); }
body { line-height: 1.55; }

button, input, select, textarea { font: inherit; color: inherit; }
button { background: none; border: 0; cursor: pointer; }
h1, h2, h3, h4, p { margin: 0; }
ul { margin: 0; padding: 0; list-style: none; }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 6px; }
::selection { background: var(--accent-soft); }

/* Ambient brand lighting behind every screen */
.ambient {
  position: fixed; inset: 0; z-index: 0; pointer-events: none; overflow: hidden;
  background: var(--bg);
}
.ambient::before,
.ambient::after {
  content: ""; position: absolute; border-radius: 50%; filter: blur(70px);
  opacity: .55;
}
.ambient::before {
  width: 62vmax; height: 62vmax; left: -22vmax; top: -26vmax;
  background: radial-gradient(circle, rgba(232, 213, 176, .18), transparent 66%);
  animation: drift-a 26s var(--ease) infinite alternate;
}
.ambient::after {
  width: 58vmax; height: 58vmax; right: -20vmax; bottom: -24vmax;
  background: radial-gradient(circle, rgba(232, 213, 176, .16), transparent 66%);
  animation: drift-b 31s var(--ease) infinite alternate;
}
:root[data-theme="light"] .ambient::before,
:root[data-theme="light"] .ambient::after { opacity: .32; }

.ambient .sheet-ghost {
  position: absolute; border: 1px solid var(--line);
  border-radius: 8px; opacity: .5;
}
.ambient .sheet-ghost::after {
  content: ""; position: absolute; inset: 14% 18% auto 12%; height: 2px;
  background: var(--line); box-shadow: 0 9px 0 var(--line), 0 18px 0 var(--line);
}

@keyframes drift-a { to { transform: translate3d(9vmax, 7vmax, 0) scale(1.12); } }
@keyframes drift-b { to { transform: translate3d(-8vmax, -6vmax, 0) scale(1.09); } }

/* ---------- Screen router ---------- */
#app { position: relative; z-index: 1; min-height: 100dvh; }
.screen { display: none; min-height: 100dvh; }
.screen.is-active { display: block; animation: screen-in var(--t-med) var(--ease-out) both; }
@keyframes screen-in { from { opacity: 0; transform: translateY(10px); } }

.page {
  width: min(100%, var(--page-max));
  margin-inline: auto;
  padding: 0 var(--s5);
}

/* ---------- Fylunor mark ---------- */
/* Colours live on presentation attributes in the markup so they survive
   cloning into a <use> shadow tree. */
.mark { display: block; }

.wordmark {
  font-size: var(--fs-h1); font-weight: 700;
  letter-spacing: var(--tracking-display);
  color: var(--text);
}

/* ---------- Buttons ---------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 10px;
  /* Derived, never fixed: --tap-min grows with the text-size setting, so a
     hard 50px would fall under the minimum at the largest step. */
  min-height: max(50px, var(--tap-min)); padding: 0 var(--s5); width: 100%;
  border-radius: var(--r-md); font-size: var(--fs-h3); font-weight: 600;
  transition: transform var(--t-fast) var(--ease), filter var(--t-fast), background var(--t-fast);
}
.btn:active { transform: scale(.982); }
.btn-primary { background: var(--brand-grad); color: var(--on-accent); box-shadow: var(--shadow-1); }
.btn-primary:hover { filter: brightness(1.06); }
.btn-google { background: #FFFFFF; color: #1F2430; box-shadow: var(--shadow-2); }
.btn-google:hover { filter: brightness(.97); }
.btn-ghost { background: var(--surface); color: var(--text); border: 1px solid var(--line-strong); }
.btn-ghost:hover { background: var(--surface-2); }
.btn-danger { background: var(--danger); color: #FFFFFF; }
.btn-danger:hover { filter: brightness(1.06); }
.btn-quiet { background: transparent; color: var(--text-2); font-weight: 550; }
.btn-quiet:hover { color: var(--text); }
.btn-sm { min-height: var(--tap-min); font-size: var(--fs-sm); width: auto; padding: 0 var(--s4); }
/* Icons sitting directly in a button label — an <svg> with only a viewBox
   defaults to 300x150 otherwise. */
.btn > svg { width: 18px; height: 18px; flex: none; }

/* ---------- Card ---------- */
.card {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r-lg); box-shadow: var(--shadow-1);
  backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px);
}
:root[data-theme="light"] .card { background: var(--surface-solid); }

/* ---------- Touch targets (§34) ----------
   Status chips, segmented options, switches and round icon buttons are all
   deliberately small — inflating them to 44px would coarsen the whole
   interface. Instead each carries an invisible hit area centred on it that
   grows only the axis that falls short, so the target meets the minimum while
   the design stays as drawn. Applied only where neighbours are far enough
   apart that the expanded areas cannot overlap. */
button.chip, a.chip,
.seg button,
.switch,
.icon-btn,
.recents button,
button.tag,
.star,
button.link, a.link {
  position: relative;
}
button.chip::after, a.chip::after,
.seg button::after,
.switch::after,
.icon-btn::after,
.recents button::after,
button.tag::after,
.star::after,
button.link::after, a.link::after {
  content: '';
  position: absolute; left: 50%; top: 50%;
  transform: translate(-50%, -50%);
  width: max(100%, var(--tap-min));
  height: max(100%, var(--tap-min));
}

/* ---------- Chips / pills ---------- */
.chip {
  display: inline-flex; align-items: center; gap: 6px;
  min-height: 36px; padding: 5px 11px; border-radius: var(--r-pill);
  font-size: var(--fs-xs); font-weight: 600; letter-spacing: .01em;
  background: var(--surface-2); color: var(--text-2); border: 1px solid var(--line);
}
.chip .dot { width: 7px; height: 7px; border-radius: 50%; background: currentColor; }
/* Positive and in-progress states carry the accent; "needs attention" is
   deliberately neutral so the accent still means something; only true errors
   get the one other hue in the system. */
.chip[data-tone="ok"],
.chip[data-tone="info"]   { color: var(--accent); border-color: var(--accent-line); background: var(--accent-soft); }
.chip[data-tone="warn"]   { color: var(--text-2); border-color: var(--line-strong); background: var(--surface-2); }
.chip[data-tone="danger"] { color: var(--danger); border-color: color-mix(in srgb, var(--danger) 35%, transparent); background: color-mix(in srgb, var(--danger) 10%, transparent); }
/* Selected, for chips used as a choice rather than a status. Same treatment as
   .tag.on and .filter-row button.on so "picked" reads identically everywhere. */
.chip.on { color: var(--on-accent); background: var(--brand-grad); border-color: transparent; font-weight: 640; }
.chip[data-tone="pro"] {
  color: var(--on-accent); border-color: transparent; background: var(--brand-grad);
}
.chip .dot.pulse { animation: pulse 1.6s var(--ease) infinite; }
@keyframes pulse { 50% { opacity: .25; transform: scale(.7); } }

/* ---------- Compact numeric field ----------
   For a short value sitting at the end of an .opt-row. Explicitly flex:none —
   inside a flex row an auto-grow input swallows the whole width no matter what
   its `width` says. */
.num-input {
  flex: none; height: var(--tap-min); padding: 0 13px; border-radius: 11px;
  background: var(--surface); border: 1px solid var(--line); color: var(--text);
  outline: none; font-size: var(--fs-sm); font-variant-numeric: tabular-nums;
}
.num-input:focus { border-color: var(--accent-line); }

/* ---------- Section heading ---------- */
.section { margin-top: var(--s7); }
.section-head {
  display: flex; align-items: baseline; justify-content: space-between; gap: var(--s3);
  margin-bottom: var(--s4);
}
.section-head h2 { font-size: var(--fs-h2); font-weight: 650; letter-spacing: -.015em; }
.section-head .link { font-size: var(--fs-sm); color: var(--accent); font-weight: 600; }
.muted { color: var(--text-2); }
.tiny { font-size: var(--fs-sm); color: var(--text-2); line-height: 1.5; }

/* Inline icons that sit directly in text runs, with no sized wrapper around
   them. Without this an <svg> with only a viewBox defaults to 300x150. */
.chip > svg,
.recents button > svg,
.file-meta .sub > svg { width: 14px; height: 14px; flex: none; }

/* ---------- Icon glyph box ---------- */
.glyph {
  display: grid; place-items: center; flex: none;
  width: 42px; height: 42px; border-radius: 13px;
  background: var(--surface-2); color: var(--accent);
}
.glyph svg { width: 21px; height: 21px; }

/* ---------- Reveal-on-load animation ---------- */
.rise { animation: rise var(--t-slow) var(--ease-out) both; }
@keyframes rise { from { opacity: 0; transform: translateY(14px); } }

/* ---------- Scrollbars ---------- */
.hscroll {
  display: flex; gap: var(--s3); overflow-x: auto;
  scroll-snap-type: x proximity; padding-bottom: var(--s2);
  margin-inline: calc(var(--s5) * -1); padding-inline: var(--s5);
  scrollbar-width: none;
}
.hscroll::-webkit-scrollbar { display: none; }
.hscroll > * { scroll-snap-align: start; }
