/* The design's colour, shape, type, states, elevation and motion, in one place. Loaded first; every other stylesheet
 * builds on these names.
 *
 * The look is Material 3 (M3), laid out the way Google ships it in the Gemini web app. Every M3 decision is a token
 * here, so changing one characteristic later (the font, the pills, the palette) is an edit to this file rather than to
 * the rules that use it.
 *
 * Colour is an M3 scheme generated from TDRA's slate, #334155, with Google's material-color-utilities 0.4.0:
 *     new SchemeFidelity(Hct.fromInt(argbFromHex('#334155')), false, 0)      spec 2021, light, standard contrast
 * then MaterialDynamicColors for each role below, generated 2026-10-23 (it was UAsk's green, #2f7d32, before).
 * Fidelity keeps the seed itself as primary-container and makes primary a deeper tone of the same slate, so text and
 * icons on either keep their contrast. Regenerate the same way rather than editing a hex value: the roles are tuned
 * against each other. One role is moved on purpose: on-secondary-container is the secondary palette's tone 35
 * (#4e535c), not the generated #5f656e. Fidelity sets it at exactly 4.5:1 on secondary-container, and the 8-10% hover and press
 * layers then pull it under; at tone 35 it stays above 5:1 in every state.
 *
 * Shape, type, state, elevation and motion values are M3's own (material-components/material-web,
 * tokens/versions/latest/sass). */
:root {
  color-scheme: light;

  /* ---------- colour roles ---------- */
  --md-primary:#1d2b3e;
  --md-on-primary:#ffffff;
  --md-primary-container:#334155;
  --md-on-primary-container:#9eadc5;
  --md-secondary:#595f68;
  --md-on-secondary:#ffffff;
  --md-secondary-container:#dee2ee;
  --md-on-secondary-container:#4e535c;   /* secondary tone 35, see below */
  --md-tertiary:#38270a;
  --md-on-tertiary:#ffffff;
  --md-tertiary-container:#503d1e;
  --md-on-tertiary-container:#c3a881;
  --md-error:#ba1a1a;
  --md-on-error:#ffffff;
  --md-error-container:#ffdad6;
  --md-on-error-container:#93000a;
  /* The neutral surfaces are not the generated ones (a warm grey): they are Tailwind's slate greys, the family
   * #334155 comes from, which read better on this page. Panels are white on a near-white page,
   * told apart by a hairline (--ua-line) rather than by a darker tone. */
  --md-surface:#F8FAFC;
  --md-surface-dim:#dbd9db;
  --md-surface-bright:#F8FAFC;
  --md-surface-container-lowest:#FFFFFF;
  --md-surface-container-low:#FFFFFF;
  --md-surface-container:#FFFFFF;
  --md-surface-container-high:#F1F5F9;
  --md-surface-container-highest:#EBEFF4;
  --md-on-surface:#1b1b1d;
  --md-on-surface-variant:#44474c;
  --md-outline:#75777d;
  --md-outline-variant:#c5c6cd;
  --md-inverse-surface:#303032;
  --md-inverse-on-surface:#f2f0f2;
  --md-inverse-primary:#b9c7e0;
  --md-shadow:#000000;
  --md-scrim:#000000;
  /* tones of the primary palette the roles don't name: the greeting's gradient and the voice orb */
  --md-primary-30:#3a485c;
  --md-primary-40:#515f74;
  --md-primary-50:#6a788e;
  --md-primary-70:#9eacc4;
  --md-primary-80:#b9c7e0;
  /* The page's own: the hairline round a white panel, and the pale slate of a question */
  --ua-line:#E8EDF3;
  --ua-tint:#EEF2F7;
  --ua-tint-line:#DCE3EC;
  /* neutral-variant tone 20, what M3 lays its scrim in (at 40%) */
  --md-scrim-tone:#2e3036;

  /* ---------- shape ---------- */
  --md-shape-xs:4px;
  --md-shape-sm:8px;
  --md-shape-md:12px;
  --md-shape-lg:16px;
  --md-shape-lg-inc:20px;
  --md-shape-xl:28px;
  --md-shape-xl-inc:32px;
  --md-shape-xxl:48px;
  --md-shape-full:9999px;

  /* ---------- type ----------
   * Each role is a font shorthand: font:var(--md-body-large). The sizes and line heights are M3's; the weights are
   * the Ingenium design's, heavier than M3's 400/500, because Plus Jakarta Sans is drawn to be set that way and
   * the page reads as UAsk at them. Tracking is its own token, and only the greeting and the label roles have one:
   * M3's body and title tracking (+0.25 to +0.5px) was set for Roboto, which the token files still name. */
  --md-display-small:800 2.25rem/2.75rem var(--font);
  --md-headline-small:400 1.5rem/2rem var(--font);
  --md-title-large:400 1.375rem/1.75rem var(--font);
  --md-title-medium:700 1rem/1.5rem var(--font);
  --md-title-small:700 .875rem/1.25rem var(--font);
  --md-body-large:400 1rem/1.5rem var(--font);
  --md-body-medium:400 .875rem/1.25rem var(--font);
  --md-body-small:400 .75rem/1rem var(--font);
  --md-label-large:700 .875rem/1.25rem var(--font);
  --md-label-medium:600 .75rem/1rem var(--font);
  --md-label-small:600 .6875rem/1rem var(--font);
  --md-display-small-track:-.028em;
  --md-label-large-track:.1px;
  --md-label-medium-track:.5px;
  --md-label-small-track:.5px;

  /* ---------- states ----------
   * A state layer is the content colour at low opacity, laid over whatever fill the element has. It goes on as a
   * background-image, so it sits on top of any background-color without a pseudo-element:
   *     .thing:hover { background-image:var(--md-hover-layer); } */
  --md-hover-layer:linear-gradient(color-mix(in srgb, currentColor 8%, transparent) 0 0);
  --md-press-layer:linear-gradient(color-mix(in srgb, currentColor 10%, transparent) 0 0);
  --md-disabled-content:color-mix(in srgb, var(--md-on-surface) 38%, transparent);
  --md-disabled-container:color-mix(in srgb, var(--md-on-surface) 12%, transparent);

  /* ---------- elevation ----------
   * Only what floats over the page casts a shadow: menus and panels (2), the modal drawer and the bottom sheet (1),
   * dialogs (3). Everything in the page flow is told apart by a hairline instead. */
  --md-elev-1:0 1px 2px 0 color-mix(in srgb, var(--md-shadow) 30%, transparent),
              0 1px 3px 1px color-mix(in srgb, var(--md-shadow) 15%, transparent);
  --md-elev-2:0 1px 2px 0 color-mix(in srgb, var(--md-shadow) 30%, transparent),
              0 2px 6px 2px color-mix(in srgb, var(--md-shadow) 15%, transparent);
  --md-elev-3:0 1px 3px 0 color-mix(in srgb, var(--md-shadow) 30%, transparent),
              0 4px 8px 3px color-mix(in srgb, var(--md-shadow) 15%, transparent);

  /* ---------- motion ---------- */
  --md-ease-standard:cubic-bezier(.2, 0, 0, 1);
  --md-ease-emph-decel:cubic-bezier(.05, .7, .1, 1);
  --md-ease-emph-accel:cubic-bezier(.3, 0, .8, .15);
  --md-dur-short4:200ms;
  --md-dur-medium2:300ms;
  --md-dur-medium4:400ms;

  /* The names the developer-only stylesheets (inspector.css, files.css) are written against, pointed at M3
   * roles so the Inspect panel, the store manager and the playground follow the palette unchanged. */
  --bg:var(--md-surface-container-low);
  --side:var(--md-surface-container);
  --hover:var(--md-surface-container-high);
  --active:var(--md-secondary-container);
  --text:var(--md-on-surface);
  --text-2:var(--md-on-surface-variant);
  --text-3:var(--md-on-surface-variant);
  --border:var(--md-outline-variant);
  --btn:var(--md-primary);
  --btn-fg:var(--md-on-primary);
  --chip:var(--md-surface-container-high);
}


/* A touch screen has no hover, but Safari keeps :hover on the last thing touched: a chat row stayed tinted, with its
 * delete × showing, as if a mouse were over it. There hover draws nothing; the press layer still answers a tap. */
@media (hover: none) { :root { --md-hover-layer:none; } }

/* Plus Jakarta Sans is a variable font: one file per unicode range covers every weight the design uses (400-800).
 * Only the latin and latin-ext files are shipped; a file of any other subset must never claim the Arabic block,
 * or it would draw Arabic punctuation and marks inside words set in Plex (tests/test_rtl_css.py). */
@font-face {
  font-family:'Plus Jakarta Sans';
  font-style:normal;
  font-weight:200 800;
  font-display:swap;
  src:url('/static/fonts/jakarta-latin.v1.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:'Plus Jakarta Sans';
  font-style:normal;
  font-weight:200 800;
  font-display:swap;
  src:url('/static/fonts/jakarta-latin-ext.v1.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;
}

/* Plus Jakarta Sans carries no Arabic, so Arabic is set in IBM Plex Sans Arabic: an Arabic face drawn for a
 * geometric humanist sans, which is what Jakarta is. Both are SIL Open Font License. The unicode-range means a reader who never sees Arabic never downloads these 129 KB.
 *
 * Plex Arabic ships 400, 600 and 700 here, and a few rules ask for 500. Asked for 500, a browser would
 * fall back to the 400 file and every label would lose its weight in Arabic, so the 600 file is declared for
 * 500 and 600 both. */
@font-face {
  font-family:'IBM Plex Sans Arabic';
  font-style:normal;
  font-weight:400;
  font-display:swap;
  src:url('/static/fonts/plex-arabic-400.v1.woff2') format('woff2');
  unicode-range:U+0600-06FF, U+0750-077F, U+0870-088E, U+0890-0891, U+0897-08E1, U+08E3-08FF, U+200C-200E, U+2010-2011, U+204F, U+2E41, U+FB50-FDFF, U+FE70-FE74, U+FE76-FEFC;
}
@font-face {
  font-family:'IBM Plex Sans Arabic';
  font-style:normal;
  font-weight:500 600;
  font-display:swap;
  src:url('/static/fonts/plex-arabic-600.v1.woff2') format('woff2');
  unicode-range:U+0600-06FF, U+0750-077F, U+0870-088E, U+0890-0891, U+0897-08E1, U+08E3-08FF, U+200C-200E, U+2010-2011, U+204F, U+2E41, U+FB50-FDFF, U+FE70-FE74, U+FE76-FEFC;
}
@font-face {
  font-family:'IBM Plex Sans Arabic';
  font-style:normal;
  font-weight:700;
  font-display:swap;
  src:url('/static/fonts/plex-arabic-700.v1.woff2') format('woff2');
  unicode-range:U+0600-06FF, U+0750-077F, U+0870-088E, U+0890-0891, U+0897-08E1, U+08E3-08FF, U+200C-200E, U+2010-2011, U+204F, U+2E41, U+FB50-FDFF, U+FE70-FE74, U+FE76-FEFC;
}

/* Latin first: a browser takes the first family that has the glyph, so Latin text keeps Jakarta and Arabic falls
 * to Plex Arabic. The system faces stay behind them for anything neither covers. */
:root { --font:'Plus Jakarta Sans', 'IBM Plex Sans Arabic', 'Segoe UI', Tahoma, system-ui, sans-serif; }

* { box-sizing:border-box; }
html, body { height:100%; }
body {
  margin:0; background:var(--md-surface); color:var(--md-on-surface);
  font-family:var(--font); font-size:16px; line-height:1.5;
  -webkit-font-smoothing:antialiased;
}
button, input, textarea { font-family:inherit; }
::placeholder { color:var(--md-on-surface-variant); opacity:1; }
/* M3's focus ring: 3px of secondary, 2px outside the element */
:focus-visible { outline:3px solid var(--md-secondary); outline-offset:2px; }

/* An icon: <svg class="ic"><use href="#i-check-bold"></use></svg>, from the sprite the page carries (server/page.py).
 * Its symbols are filled with currentColor, so an icon takes the colour of whatever contains it. */
.ic { flex:0 0 auto; width:1em; height:1em; display:block; }
/* Right to left, an arrow or a caret that means "onward" has to point the other way. Only these: a globe, a
 * tick or the logo would be wrong mirrored, so nothing else is flipped. */
[dir="rtl"] .ic.flip { transform:scaleX(-1); }

/* Motion, from the design. Everything here is decoration, so it all stops for prefers-reduced-motion below. */
@keyframes ig-hue { 0%,100% { background-position:0% 50%; } 50% { background-position:100% 50%; } }
@keyframes ig-fadeup { from { opacity:0; transform:translateY(12px); } to { opacity:1; transform:none; } }
@keyframes ig-subin { from { opacity:0; transform:translateY(6px); } to { opacity:1; transform:none; } }
@keyframes ig-veil { from { opacity:0; } to { opacity:1; } }
@keyframes ig-eq { 0%,100% { transform:scaleY(.25); } 50% { transform:scaleY(1); } }
@keyframes ig-bounce { 0%,80%,100% { transform:translateY(0); opacity:.45; } 40% { transform:translateY(-5px); opacity:1; } }
@keyframes ig-dot { 0%,100% { opacity:.3; } 50% { opacity:1; } }
@keyframes ig-ring { 0% { transform:scale(.86); opacity:.9; } 100% { transform:scale(1.28); opacity:0; } }
@keyframes ig-shimmer { from { background-position:180% 0; } to { background-position:-180% 0; } }
@keyframes ig-drift1 { 0%,100% { transform:translate(0,0) scale(1); } 50% { transform:translate(14%,10%) scale(1.12); } }
@keyframes ig-drift2 { 0%,100% { transform:translate(0,0) scale(1); } 50% { transform:translate(-12%,-14%) scale(1.15); } }
@keyframes ig-breathe { 0%,100% { transform:scale(1); opacity:.5; } 50% { transform:scale(1.35); opacity:.12; } }
@keyframes ig-breathe2 { 0%,100% { transform:scale(1); } 50% { transform:scale(1.06); } }
@keyframes ig-spin { to { transform:rotate(360deg); } }
/* the app's own two: the dot on a chat that is still answering, and the caret at the end of streaming text */
@keyframes pulse { 0%,100% { opacity:.3; } 50% { opacity:1; } }
@keyframes blink { 50% { opacity:0; } }

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