/*
 * NTWOOD core — reset, layout primitives, type, buttons, and the widget colour
 * bridge. Ported from prototype/a-rung-suong/style.css; see docs/class-map.md
 * for the `a-` → `ntw-` rename.
 *
 * Loaded on every page, by the theme AND (as a fallback copy) by the widgets
 * plugin. Depends on tokens.css.
 *
 * Four things in here are load-bearing and are commented at the point of use:
 *   1. `box-sizing: border-box`  — the widgets must not depend on a reset that
 *      ships in a different package.
 *   2. the `.ntw-w` colour bridge — one declaration per variable, in one place.
 *   3. the Elementor wrapper neutralisation, scoped INSIDE `.ntw-w`.
 *   4. `.ntw-anim` gating — animations are opt-in, never opt-out.
 */

/* =====================================================================
 * RESET
 * ================================================================== */

/*
 * Not cosmetic and not the theme's business alone: a widget sets a height and
 * then adds its own padding, so under `content-box` every full-height band
 * overflows. It lives in core.css rather than the theme's theme.css because
 * newtechwood-widgets must render correctly on a different theme, where only
 * the fallback copy of THIS file is loaded.
 */
*, *::before, *::after { box-sizing: border-box; }

/* a component's display rule must never resurrect an element someone hid */
[hidden] { display: none !important; }

html {
	scroll-behavior: smooth;
	scroll-padding-top: var(--hdr-h);
	-webkit-text-size-adjust: 100%;
}

body {
	margin: 0;
	background: var(--ink);
	color: var(--mist);
	font: 400 16px/1.7 var(--f-body);
	/*
	 * Be Vietnam Pro already ships lining figures, so this is a no-op today. It
	 * stays because the declaration is free and the failure it prevents is
	 * expensive: a display face with oldstyle figures renders "0385 630 880" with
	 * digits hanging below the baseline next to others riding above the caps, and
	 * that reads as a broken webfont rather than a missing CSS line. Helios paid
	 * for this with Cormorant Garamond.
	 *
	 * `font-variant-numeric`, never `font-feature-settings: "lnum"` — the
	 * low-level property resets every OpenType feature it does not name, so a
	 * later author silently loses kerning and ligatures.
	 */
	font-variant-numeric: lining-nums;
	-webkit-font-smoothing: antialiased;
	/*
	 * The backstop for a no-break space the Vietnamese typography filter could
	 * not avoid inserting — see newtechwood-theme/inc/typography.php.
	 */
	overflow-wrap: break-word;
	overflow-x: hidden;
}

img { display: block; max-width: 100%; height: auto; }
a { color: inherit; text-decoration: none; }

/*
 * NO ITALIC ANYWHERE — including the user-agent defaults. Be Vietnam Pro is loaded
 * without its italic axis, so the browser would synthesise a slant of the roman
 * glyphs. Measured in the P3 harness: the technology drawing's empty `<i>` slabs
 * computed `italic` from the UA sheet. Emphasis is colour.
 */
em, i, cite, dfn, var, address { font-style: normal; }

/*
 * A bare <button> inherits the user-agent `ButtonFace` background, which against
 * its own label measures about 1.05:1 — a pale rectangle with no readable text.
 * Every icon button in this project is a <button>, so the reset is not optional.
 */
button { font: inherit; color: inherit; cursor: pointer; background: transparent; border: 0; padding: 0; }

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

/* =====================================================================
 * LAYOUT PRIMITIVES
 * ================================================================== */

.ntw-wrap { width: min(100%, var(--wrap)); margin-inline: auto; padding-inline: var(--pad); }
.ntw-sec { position: relative; padding-block: clamp(88px, 12vw, 168px); }
.ntw-sec--2 { background: var(--ink-2); }
.ntw-sec--3 { background: var(--ink-3); }
.ntw-head {
	display: grid; grid-template-columns: minmax(0, 1.1fr) minmax(0, .9fr);
	gap: 40px 64px; align-items: end; margin-bottom: clamp(44px, 6vw, 80px);
}

/* `minmax(0, 1fr)` everywhere, never a bare `1fr`: a bare 1fr resolves to
   minmax(auto, 1fr) and one long unbroken word widens the whole page. */

.ntw-sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
.ntw-skip {
	position: absolute; left: -9999px; top: 8px; z-index: 200;
	background: var(--green-btn); color: #fff; padding: 10px 16px; border-radius: 999px;
}
.ntw-skip:focus { left: 12px; }

/*
 * The grain overlay. It is what stops the large flat inks reading as cheap, and
 * it renders ONCE per document from wp_body_open. `pointer-events: none` is not
 * optional — it covers the whole viewport.
 */
.ntw-grain {
	position: fixed; inset: 0; z-index: 90; pointer-events: none;
	opacity: .07; mix-blend-mode: overlay;
	background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* =====================================================================
 * TYPE
 * ================================================================== */

.ntw-eyebrow {
	display: inline-flex; align-items: center; gap: 10px; margin: 0 0 18px;
	font: 500 12px/1.2 var(--f-body); letter-spacing: .22em; text-transform: uppercase;
	color: var(--mist-faint);
}
.ntw-eyebrow::before { content: ''; width: 7px; height: 7px; border-radius: 50%; background: var(--green); }

.ntw-h1 {
	margin: 0 0 26px; max-width: 14ch;
	font: 500 clamp(2.5rem, 5.4vw, 5rem)/1.14 var(--f-display);
	letter-spacing: -.035em; font-optical-sizing: auto;
}
.ntw-h2 {
	margin: 0 0 22px; font: 500 clamp(1.9rem, 3.6vw, 3.2rem)/1.2 var(--f-display);
	letter-spacing: -.025em; font-optical-sizing: auto; text-wrap: balance;
}
.ntw-h3 { margin: 0 0 12px; font: 500 1.28rem/1.35 var(--f-display); letter-spacing: -.015em; }

/*
 * Emphasis is COLOUR, upright. `font-style: normal` on `em` is the whole point:
 * Be Vietnam Pro is loaded without its italic axis, so a real italic would be a
 * browser-synthesised slant of the roman glyphs.
 */
.ntw-h1 em, .ntw-h2 em, .ntw-h3 em, .ntw-accent { font-style: normal; color: var(--green); }

.ntw-lead { max-width: 56ch; margin: 0; color: var(--mist-dim); font-size: 1.08rem; }
.ntw-note { margin: 22px 0 0; font-size: 13px; color: var(--mist-faint); }

/* the editor-only empty state; never shown to a visitor (see the widget base) */
.ntw-empty {
	margin: 0; padding: 18px 20px; border: 1px dashed var(--line-2); border-radius: var(--r);
	color: var(--mist-faint); font-size: 14px;
}

/*
 * The rise mask. It must clear stacked marks (Đ, ế, ỗ) ABOVE the line box and
 * descenders below, or it clips them — hence the padding/negative-margin pair.
 */
.ntw-line { display: block; overflow: hidden; padding: .16em 0 .1em; margin: -.16em 0 -.1em; }
.ntw-line > span { display: block; }

/* =====================================================================
 * BUTTONS
 * ================================================================== */

.ntw-btn {
	--bg: transparent; --fg: var(--mist); --bd: var(--line-2);
	display: inline-flex; align-items: center; justify-content: center; gap: 10px;
	min-height: 48px; padding: 0 24px;
	border-radius: 999px; border: 1px solid var(--bd);
	background: var(--bg); color: var(--fg);
	font: 500 15px/1 var(--f-body); letter-spacing: .01em; white-space: nowrap;
	transition: background .25s, color .25s, border-color .25s, transform .25s var(--ease);
}
.ntw-btn:hover { --bd: var(--mist); transform: translateY(-2px); }
.ntw-btn--green {
	--bg: var(--green-btn); --fg: #fff; --bd: var(--green-btn);
	box-shadow: 0 10px 28px -12px rgba(36, 168, 0, .55);
}
.ntw-btn--green:hover { --bg: var(--green-btn-hot); --bd: var(--green-btn-hot); }
.ntw-btn--sm { min-height: 40px; padding: 0 16px; font-size: 14px; }
.ntw-btn i { font-size: .9em; transition: transform .3s var(--ease); }
.ntw-btn:hover i.fa-arrow-right { transform: translateX(4px); }

.ntw-badge {
	display: inline-grid; place-items: center; min-width: 20px; height: 20px; padding: 0 6px;
	border-radius: 999px; background: var(--green-btn); color: #fff; font: 700 11px/1 var(--f-body);
}
.ntw-btn--green .ntw-badge { background: var(--ink); color: #fff; }

/* =====================================================================
 * WIDGET COLOUR BRIDGE
 *
 * Elementor colour controls write CSS custom properties onto {{WRAPPER}} (see
 * Ntw_Widget_Base::ntw_register_color_controls). The variable → property
 * mapping lives HERE, once. Three consequences, all of them the reason:
 *
 *   · the CSS Elementor generates per widget instance is a handful of
 *     declarations instead of twenty `selectors` rules;
 *   · one control restyles every element that references the variable;
 *   · an EMPTY control means "use the design token", because each fallback is
 *     the token itself — not an inline override of it.
 *
 * EVERY WIDGET ROOT MUST CARRY `.ntw-w`. Without it none of its colour controls
 * do anything, and the widget still looks correct with its defaults — so nobody
 * notices until a client changes a colour and reports that it "will not save".
 * ================================================================== */

/*
 * ── THE SECTION BAND IS THE FALLBACK, NOT `transparent` ──
 *
 * `.ntw-sec--2 { background }` above and this rule are both (0,1,0), so on a root
 * carrying both classes source order wins — and with a bare `transparent`
 * fallback every `ink-2` band on the homepage (six of them) would have rendered
 * flat ink. The band sets `--ntw-sec-bg` instead, and the bridge reads it as its
 * fallback: an empty "Nền" control means "the band this section was designed in".
 */
.ntw-sec--2 { --ntw-sec-bg: var(--ink-2); }
.ntw-sec--3 { --ntw-sec-bg: var(--ink-3); }
.ntw-w { background-color: var(--ntw-w-bg, var(--ntw-sec-bg, transparent)); }

/*
 * Emphasis is colour, upright, EVERYWHERE inside a widget — not only inside the
 * three heading classes. The manifesto puts its accent `<em>` in a plain `<p>`,
 * where the user-agent default would synthesise a slant of the roman glyphs.
 */
.ntw-w em { font-style: normal; }

/*
 * Scoped to elements that are part of the widget's own copy. NOT a blanket
 * `.ntw-w *`: helios shipped `.hl-w :is(h1,…) { color: var(--hl-cream) }` and it
 * painted cream type onto a cream panel inside one of its own widgets, i.e.
 * invisible text. If a widget introduces a light surface, that surface overrides
 * these variables locally rather than fighting this rule.
 */
.ntw-w :is(h1, h2, h3, h4) { color: var(--ntw-w-heading, var(--mist)); }
.ntw-w :is(p, li, dd, figcaption) { color: var(--ntw-w-body, var(--mist-dim)); }
.ntw-w .ntw-eyebrow, .ntw-w dt { color: var(--ntw-w-label, var(--mist-faint)); }
.ntw-w .ntw-eyebrow::before, .ntw-w em, .ntw-w .ntw-accent { color: var(--ntw-w-accent, var(--green)); }
.ntw-w .ntw-eyebrow::before { background: var(--ntw-w-accent, var(--green)); }
.ntw-w :is(hr, .ntw-rule) { border-color: var(--ntw-w-border, var(--line)); }
.ntw-w .ntw-btn--green {
	--bg: var(--ntw-w-btn-bg, var(--green-btn));
	--fg: var(--ntw-w-btn-text, #fff);
	--bd: var(--ntw-w-btn-bg, var(--green-btn));
}
.ntw-w .ntw-btn--green:hover {
	--bg: var(--ntw-w-btn-hover-bg, var(--green-btn-hot));
	--fg: var(--ntw-w-btn-hover-text, #fff);
	--bd: var(--ntw-w-btn-hover-bg, var(--green-btn-hot));
}

/*
 * HOOK CLASSES. A widget puts one of these on an element that is not a heading,
 * paragraph or list item but still carries one of the bridged colours — a display
 * line in a <span>, a card, an icon. Generic on purpose: a widget never invents a
 * per-component variable, it opts an element into an existing one. Each widget
 * exposes only the variables it renders a hook for; the widget smoke test fails a
 * control that nothing reads ("no dead colour controls").
 */
.ntw-w .ntw-display { color: var(--ntw-w-heading, var(--mist)); }
.ntw-w .ntw-copy { color: var(--ntw-w-body, var(--mist-dim)); }
.ntw-w .ntw-meta { color: var(--ntw-w-label, var(--mist-faint)); }
.ntw-w .ntw-ico { color: var(--ntw-w-accent, var(--green)); }
.ntw-w .ntw-link:hover { color: var(--ntw-w-accent, var(--green)); }
.ntw-w .ntw-surface {
	background-color: var(--ntw-w-card-bg, var(--ink-3));
	border-color: var(--ntw-w-border, var(--line));
}
/* P4: a form field (ntw_quote_form). Only that widget exposes the control. */
.ntw-w .ntw-field { background-color: var(--ntw-w-field-bg, var(--ink-2)); }

/* The ghost (outline) button: label in the heading colour, outline in the border. */
.ntw-w .ntw-btn:not(.ntw-btn--green) {
	--fg: var(--ntw-w-heading, var(--mist));
	--bd: var(--ntw-w-border, var(--line-2));
}
.ntw-w .ntw-btn:not(.ntw-btn--green):hover { --bd: var(--ntw-w-heading, var(--mist)); }

/*
 * A round "go" arrow or a chip that FILLS on hover. It carries white text when
 * filled, so its fallback is `--green-btn` (4.97:1), never `--green` (3.15:1).
 */
.ntw-w .ntw-pill { border-color: var(--ntw-w-border, var(--line-2)); }
.ntw-w .ntw-pill:hover,
.ntw-w a:hover .ntw-pill,
.ntw-w a:focus-visible .ntw-pill {
	background-color: var(--ntw-w-btn-hover-bg, var(--green-btn));
	border-color: var(--ntw-w-btn-hover-bg, var(--green-btn));
	color: var(--ntw-w-btn-hover-text, #fff);
}

/* =====================================================================
 * ELEMENTOR WRAPPERS
 *
 * A widget renders inside .elementor-section > .elementor-container >
 * .elementor-column > .elementor-widget-wrap > .elementor-widget, and inside
 * .e-con on newer versions. A full-bleed band cannot be full-bleed through five
 * padded wrappers.
 *
 * Scoped to `:has(> … .ntw-w)` ancestors only — NEVER global. A global reset
 * would break every core Elementor widget the client adds later, and that
 * failure appears on a page nobody on our side edits.
 * ================================================================== */

.elementor-widget-wrap:has(> .elementor-widget > .ntw-w),
.elementor-widget:has(> .ntw-w),
.elementor-column:has(.ntw-w) > .elementor-widget-wrap,
.e-con:has(> .e-con-inner > .elementor-widget > .ntw-w) > .e-con-inner {
	padding: 0;
}

/* =====================================================================
 * ANIMATION — opt-in, never opt-out
 *
 * `.ntw-anim` is added to <html> by an inline script BEFORE first paint, and a
 * 4s watchdog removes it again if the main script never arrives. The hidden
 * state therefore only exists under that class.
 *
 * INVERTING THIS IS THE BUG: if `opacity: 0` were the default and JS revealed
 * it, anything that stops the JS leaves a permanently blank page. Helios shipped
 * that in 1.0.0 and it looked like an empty Elementor canvas — full-height
 * sections, invisible text.
 * ================================================================== */

.ntw-anim [data-ntw-reveal] { opacity: 0; transform: translateY(26px); }
.ntw-anim [data-ntw-reveal].is-in {
	opacity: 1; transform: none;
	transition: opacity .7s var(--ease) var(--ntw-d, 0s), transform .8s var(--ease) var(--ntw-d, 0s);
}
.ntw-anim .ntw-line > span { animation: ntw-rise 1s var(--ease) both; animation-delay: calc(650ms + var(--l, 0) * 120ms); }
.ntw-anim .ntw-fade { animation: ntw-fade .9s var(--ease) both; }

/*
 * 150%, not 105%. The mask carries extra padding for stacked marks, and the
 * marks ascend ABOVE the line box — at 105% the tops of "ế" and "ỗ" still showed
 * through before the line rose, which read as the headline leaking on load.
 */
@keyframes ntw-rise { from { transform: translateY(150%); } to { transform: none; } }
@keyframes ntw-fade { from { opacity: 0; transform: translateY(14px); } to { opacity: 1; transform: none; } }

/*
 * ── THE ELEMENTOR EDITOR NEVER HIDES ANYTHING ──
 *
 * The head bootstrap runs inside the editor's preview iframe too, so `ntw-anim` is
 * set there. chrome.js observes `[data-ntw-reveal]` ONCE, at boot — and Elementor
 * re-renders a widget over AJAX every time a control changes. The new markup is
 * never observed, so without this rule a widget stays at `opacity: 0` on the canvas
 * forever after its first edit: the helios 1.0.0 "empty canvas" bug, by another
 * route. `!important` because the hidden states are written in several widget
 * stylesheets and this has to beat all of them.
 */
.elementor-editor-active [data-ntw-reveal],
.elementor-editor-active .ntw-line > span,
.elementor-editor-active .ntw-mword {
	opacity: 1 !important;
	transform: none !important;
	animation: none !important;
}
.elementor-editor-active [data-ntw-draw] path { stroke-dasharray: none !important; stroke-dashoffset: 0 !important; }

/*
 * Self-drawing strokes (`data-ntw-draw` on an SVG). `--dl` is the ON-SCREEN length,
 * measured by the widget script: the paths carry `vector-effect: non-scaling-stroke`,
 * so their dashes are in screen space and a unitless `pathLength="1"` would draw only
 * part of any profile that is scaled up. Shared here because the product page (P4)
 * draws the same profiles. `.is-drawn` releases a path from the dash once drawn, so
 * a later resize cannot leave it half-dashed.
 */
.ntw-anim [data-ntw-draw] path:not(.is-drawn) {
	stroke-dasharray: var(--dl, 0) var(--dl, 0);
	stroke-dashoffset: var(--dl, 0);
	transition: stroke-dashoffset 1.8s var(--ease) .25s;
}
.ntw-anim [data-ntw-draw].is-in path:not(.is-drawn),
.ntw-anim .is-in [data-ntw-draw] path:not(.is-drawn) { stroke-dashoffset: 0; }

/* =====================================================================
 * RESPONSIVE (primitives only — components carry their own breakpoints)
 * ================================================================== */

@media (max-width: 960px) {
	.ntw-head { grid-template-columns: minmax(0, 1fr); }
}
@media (max-width: 720px) {
	body { font-size: 15.5px; }
}

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