/*
Theme Name: David Lee
Theme URI: https://david-lee.dev
Author: David Lee
Description: Portfolio theme for david-lee.dev. Bilingual (EN/ES via Polylang), WCAG 2.2 AA.
Version: 0.8.2
Requires at least: 6.5
Tested up to: 6.7
Requires PHP: 7.4
License: GPL-2.0-or-later
License URI: https://www.gnu.org/licenses/gpl-2.0.html
Text Domain: davidlee
*/

*{box-sizing:border-box}

/* --------------------------------------------------------------------------
   Tokens
   Light is the base. Dark is applied either by OS preference (when the user
   has expressed no preference and so no data-theme attribute is present) or
   by explicit choice. The two dark blocks must stay in sync.

   --line matches the reference for borders that sit beside a text label, where
   the label identifies the control. --line-interactive is reserved for the one
   place the border is the *sole* boundary — the form fields — so they keep the
   3:1 UI-component contrast WCAG 1.4.11 asks for.
   -------------------------------------------------------------------------- */
:root,
:root[data-theme="light"]{
  color-scheme:light;
  --bg:oklch(0.98 0.004 240);
  --surface:oklch(0.995 0.003 240);
  --fg:oklch(0.27 0.012 250);
  --muted:oklch(0.52 0.012 250);
  --line:oklch(0.89 0.005 240);
  --line-interactive:oklch(0.65 0.005 240);
  --accent:oklch(0.54 0.13 250);
  --accent-fg:oklch(0.99 0.005 240);
  --error:oklch(0.55 0.19 25);
}
@media (prefers-color-scheme:dark){
  :root:not([data-theme]){
    color-scheme:dark;
    --bg:oklch(0.18 0.008 250);
    --surface:oklch(0.225 0.008 250);
    --fg:oklch(0.92 0.006 240);
    --muted:oklch(0.68 0.01 245);
    --line:oklch(0.31 0.008 250);
    --line-interactive:oklch(0.49 0.008 250);
    --accent:oklch(0.70 0.13 250);
    --accent-fg:oklch(0.18 0.008 250);
    --error:oklch(0.72 0.17 25);
  }
}
:root[data-theme="dark"]{
  color-scheme:dark;
  --bg:oklch(0.18 0.008 250);
  --surface:oklch(0.225 0.008 250);
  --fg:oklch(0.92 0.006 240);
  --muted:oklch(0.68 0.01 245);
  --line:oklch(0.31 0.008 250);
  --line-interactive:oklch(0.49 0.008 250);
  --accent:oklch(0.70 0.13 250);
  --accent-fg:oklch(0.18 0.008 250);
  --error:oklch(0.72 0.17 25);
}

/* Enhancement over an already-conforming baseline, not a rescue. */
@media (prefers-contrast:more){
  :root,:root[data-theme="light"]{--muted:oklch(0.42 0.012 250);--line:oklch(0.72 0.005 240);--line-interactive:oklch(0.50 0.005 240)}
  :root[data-theme="dark"]{--muted:oklch(0.80 0.01 245);--line:oklch(0.46 0.008 250);--line-interactive:oklch(0.62 0.008 250)}
}

body{margin:0;background:var(--bg);color:var(--fg);font-family:'Space Grotesk',system-ui,sans-serif;transition:background 300ms,color 300ms;-webkit-font-smoothing:antialiased}

/* In-page anchors (the hero's "Start a project" / "See the work", the header
   nav, the skip link) ease to their target instead of jumping. Gated on
   no-preference so a reduced-motion visitor still gets the instant jump. The
   scroll-margin lifts the landing point clear of the sticky header. */
@media (prefers-reduced-motion:no-preference){ html{scroll-behavior:smooth} }
:where(section[id],#main,[id]:target){scroll-margin-top:84px}
a{color:inherit;text-decoration:none}
a:hover{color:var(--fg)}
input,textarea,button{font:inherit;color:inherit}
textarea{resize:none}
.mono{font-family:'JetBrains Mono',monospace}
.wrap{max-width:100%;margin:0 auto}
header,section,footer{padding-left:22px;padding-right:22px}

/* --------------------------------------------------------------------------
   Focus. Replaces the original outline:none, which left every control on the
   page without a visible focus indicator (WCAG 2.4.7).
   -------------------------------------------------------------------------- */
:focus-visible{outline:3px solid var(--accent);outline-offset:2px;border-radius:4px}
.skip-link{position:absolute;left:-9999px;top:0;z-index:100;padding:12px 18px;background:var(--bg);color:var(--fg);border:1px solid var(--line);border-radius:0 0 10px 0;font-family:'JetBrains Mono',monospace;font-size:13px}
.skip-link:focus{left:0}

.site-header{display:flex;align-items:center;justify-content:space-between;padding-top:20px;padding-bottom:20px;border-bottom:1px solid var(--line);position:sticky;top:0;background:var(--bg);z-index:10}
.brand{font-family:'JetBrains Mono',monospace;font-size:14px;letter-spacing:0.02em;font-weight:500;color:var(--fg);text-decoration:none}
.brand:hover{color:var(--accent)}
.hdr-controls{display:flex;gap:10px;align-items:center}
.btn-theme{min-height:44px;min-width:64px;padding:0 16px;display:inline-flex;align-items:center;justify-content:center;background:transparent;border:1px solid var(--line);border-radius:999px;font-family:'JetBrains Mono',monospace;font-size:12px;letter-spacing:0.04em;cursor:pointer;color:var(--muted);transition:border-color 200ms,color 200ms}
.btn-theme:hover{border-color:var(--fg);color:var(--fg)}

/* Language switcher (Polylang). Identical pill to the theme toggle — same
   min-width, padding and --line border — so the two header controls read as a
   matched set. hide_current is on, so normally only the other language shows. */
.lang-switch{display:flex;gap:10px;align-items:center;margin:0;padding:0;list-style:none}
.lang-item{margin:0;padding:0}
.lang-item a{min-height:44px;min-width:64px;padding:0 16px;display:inline-flex;align-items:center;justify-content:center;background:transparent;border:1px solid var(--line);border-radius:999px;font-family:'JetBrains Mono',monospace;font-size:12px;letter-spacing:0.04em;text-transform:uppercase;color:var(--muted);text-decoration:none;transition:border-color 200ms,color 200ms}
.lang-item a:hover{border-color:var(--fg);color:var(--fg)}
.lang-item.current-lang a{color:var(--fg);border-color:var(--fg)}

/* Show whichever theme the button switches *to*. No data-theme attribute means
   the visitor has not chosen, so the OS setting decides; once they have, the
   attribute wins. Hidden labels leave the accessibility tree with display:none,
   so the accessible name only ever contains the visible word. */
.theme-to-dark,.theme-to-light{display:none}
:root:not([data-theme]) .theme-to-dark{display:inline}
@media (prefers-color-scheme:dark){
  :root:not([data-theme]) .theme-to-dark{display:none}
  :root:not([data-theme]) .theme-to-light{display:inline}
}
:root[data-theme="light"] .theme-to-dark{display:inline}
:root[data-theme="dark"] .theme-to-light{display:inline}

.kicker{font-family:'JetBrains Mono',monospace;font-size:12px;letter-spacing:0.04em;text-transform:uppercase;color:var(--muted);margin-bottom:24px}
.hero{padding-top:48px;padding-bottom:48px;border-bottom:1px solid var(--line)}
/* Named areas so the graphic can sit between the tag line and the headline on
   small screens, where source order would otherwise put it after the CTAs. */
.hero-grid{display:grid;gap:40px;align-items:center;grid-template-columns:1fr;grid-template-areas:'tag' 'media' 'copy'}
.hero .tag{grid-area:tag;font-family:'JetBrains Mono',monospace;font-size:12px;letter-spacing:0.02em;color:var(--muted);margin-bottom:0}
.hero-copy{grid-area:copy}
.hero h1{font-weight:700;line-height:1.06;letter-spacing:-0.02em;margin:0 0 20px;text-wrap:balance;font-size:34px;max-width:20ch}
.hero p{line-height:1.55;color:var(--muted);margin:0 0 32px;max-width:52ch;font-size:16px}
.cta{display:flex;gap:12px;flex-direction:column}
/* Master switch: the plugin adds .dl-hide-work when the work section is turned
   off, so the hero's "See the work" button hides to match. Attribute selector
   because the button carries no class of its own. */
body.dl-hide-work .cta a[href="#work"]{display:none}
.btn{display:inline-flex;align-items:center;justify-content:center;min-height:50px;padding:0 26px;border:none;border-radius:12px;font-size:15px;font-weight:600;cursor:pointer;transition:filter 200ms,border-color 200ms}
.btn-primary{background:var(--accent);color:var(--accent-fg)}
.btn-primary:hover{filter:brightness(1.06);color:var(--accent-fg)}
.btn-ghost{background:transparent;border:1px solid var(--line);font-weight:500;color:var(--fg)}
.btn-ghost:hover{border-color:var(--fg)}

/* .hero-media is owned by the solar system in the Portfolio Site plugin — it
   sizes and shows itself at every breakpoint, including mobile. */

section.block{padding-top:40px;padding-bottom:40px;border-bottom:1px solid var(--line)}
.grid{display:grid;gap:2px;grid-template-columns:1fr}

/* Numbering is generated so reordering or deleting a service cannot produce
   01, 02, 04. */
.grid.services{counter-reset:service}
.service{display:flex;gap:16px;padding:20px 0;border-top:1px solid var(--line);counter-increment:service}
.service .n{font-family:'JetBrains Mono',monospace;font-size:12px;color:var(--accent);padding-top:3px}
.service .n::before{content:counter(service,decimal-leading-zero)}
.service h3{font-size:17px;font-weight:600;margin:0 0 5px}
.service p{font-size:14px;line-height:1.5;color:var(--muted);margin:0;max-width:42ch}

.work{display:block;width:100%;text-align:left;font:inherit;color:inherit;cursor:pointer;border:1px solid var(--line);border-radius:16px;overflow:hidden;background:var(--surface);transition:border-color 200ms,transform 200ms}
.work:hover{border-color:var(--accent);transform:translateY(-2px)}
.work .shot{aspect-ratio:16/9;background-color:var(--surface);background-image:repeating-linear-gradient(45deg,var(--line) 0 1px,transparent 1px 11px);display:flex;align-items:center;justify-content:center}
.work .shot img{width:100%;height:100%;object-fit:cover}
.work .shot span{font-family:'JetBrains Mono',monospace;font-size:11px;letter-spacing:0.06em;color:var(--muted);background:var(--surface);padding:5px 10px;border-radius:6px}
.work .meta{padding:16px 18px}
.work .row{display:flex;align-items:center;justify-content:space-between;gap:10px;margin-bottom:5px}
.work .name{font-size:16px;font-weight:600}
.work .badge{font-family:'JetBrains Mono',monospace;font-size:11px;color:var(--accent);white-space:nowrap}
.work .desc{font-size:14px;line-height:1.5;color:var(--muted);display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;line-clamp:2;overflow:hidden}
.btn-more{width:100%;margin-top:20px;min-height:46px;background:transparent;border:1px solid var(--line);border-radius:11px;font-family:'JetBrains Mono',monospace;font-size:12px;letter-spacing:0.04em;color:var(--muted);cursor:pointer;transition:border-color 200ms,color 200ms}
.btn-more:hover{border-color:var(--fg);color:var(--fg)}

.contact{background:var(--surface)}
.contact-grid{display:grid;gap:32px;grid-template-columns:1fr}
.contact h2{font-weight:700;font-size:26px;letter-spacing:-0.01em;margin:0 0 8px}
.contact .lede{font-size:14px;line-height:1.5;color:var(--muted);margin:0 0 24px;max-width:38ch}
.links{display:flex;gap:10px;max-width:420px}
.links a{flex:1;min-height:44px;display:flex;align-items:center;justify-content:center;border:1px solid var(--line);border-radius:10px;font-family:'JetBrains Mono',monospace;font-size:12px;transition:border-color 200ms}
.links a:hover{border-color:var(--fg)}
.links a.copied{border-color:var(--fg)}

/* Labels are required, not optional — placeholders alone fail 1.3.1 and 3.3.2
   and vanish as soon as the user types. */
/* :not(.frm-fluent-form) matters — otherwise this flex column overrides
   Fluent Forms' own layout, which is the plugin's job to provide. */
form:not(.frm-fluent-form){display:flex;flex-direction:column;gap:12px;max-width:480px}
form:not(.frm-fluent-form) label{font-family:'JetBrains Mono',monospace;font-size:12px;letter-spacing:0.03em;color:var(--muted);margin-bottom:-6px}
form:not(.frm-fluent-form) input,form:not(.frm-fluent-form) textarea{min-height:48px;padding:0 16px;background:var(--bg);border:1px solid var(--line-interactive);border-radius:11px;font-size:16px;font-family:'Space Grotesk',sans-serif}
form:not(.frm-fluent-form) textarea{padding:14px 16px;line-height:1.5}
form:not(.frm-fluent-form) input:focus,form:not(.frm-fluent-form) textarea:focus{border-color:var(--accent)}
form:not(.frm-fluent-form) button{min-height:50px;background:var(--accent);color:var(--accent-fg);border:none;border-radius:12px;font-weight:600;font-size:15px;cursor:pointer;transition:filter 200ms}
form:not(.frm-fluent-form) button:hover{filter:brightness(1.06)}
.field-error{font-size:13px;color:var(--accent);margin-top:-4px}

/* --------------------------------------------------------------------------
   Fluent Forms

   Fluent Forms keeps its own stylesheet — we override rather than replace it,
   so plugin updates keep supplying their own layout, honeypot hiding and any
   new field types without us having to re-implement them.

   Every rule is anchored on #contact. An ID scores 1,x,x, which outranks any
   class-based rule the plugin ships now or adds later, so this does not need
   revisiting each time they touch their CSS. The .dl-form fallback covers the
   form rendered anywhere outside the contact section.

   Only visual tokens are set here — colour, border, radius, type. Layout is
   left to the plugin except where the design differs (full-width submit).
   -------------------------------------------------------------------------- */
#contact .frm-fluent-form,
.dl-form .frm-fluent-form{max-width:480px}
#contact .frm-fluent-form .ff-el-input--label label,
.dl-form .frm-fluent-form .ff-el-input--label label{margin:0 0 6px;font-family:'JetBrains Mono',monospace;font-size:12px;font-weight:400;letter-spacing:0.03em;color:var(--muted)}
#contact .frm-fluent-form .ff-el-form-control,
.dl-form .frm-fluent-form .ff-el-form-control{min-height:48px;padding:0 16px;background:var(--bg);color:var(--fg);border:1px solid var(--line-interactive);border-radius:11px;font-size:16px;font-family:'Space Grotesk',sans-serif;box-shadow:none}
#contact .frm-fluent-form textarea.ff-el-form-control,
.dl-form .frm-fluent-form textarea.ff-el-form-control{min-height:120px;padding:14px 16px;line-height:1.5}
#contact .frm-fluent-form .ff-el-form-control::placeholder,
.dl-form .frm-fluent-form .ff-el-form-control::placeholder{color:var(--muted);opacity:1}
#contact .frm-fluent-form .ff-el-form-control:hover,
.dl-form .frm-fluent-form .ff-el-form-control:hover{border-color:var(--fg)}
#contact .frm-fluent-form .ff-el-form-control:focus,
.dl-form .frm-fluent-form .ff-el-form-control:focus{border-color:var(--accent);background:var(--bg);color:var(--fg);box-shadow:none;outline:none}
#contact .frm-fluent-form .ff-el-form-control:focus-visible,
.dl-form .frm-fluent-form .ff-el-form-control:focus-visible{outline:3px solid var(--accent);outline-offset:2px}

/* Submit spans the form, matching the original design. */
#contact .frm-fluent-form .ff-btn-submit,
.dl-form .frm-fluent-form .ff-btn-submit{width:100%;min-height:50px;padding:0 26px;background:var(--accent);color:var(--accent-fg);border:none;border-radius:12px;font-size:15px;font-weight:600;cursor:pointer;transition:filter 200ms}
#contact .frm-fluent-form .ff-btn-submit:hover,
.dl-form .frm-fluent-form .ff-btn-submit:hover{background:var(--accent);color:var(--accent-fg);filter:brightness(1.06)}
#contact .frm-fluent-form .ff-btn-submit:focus-visible,
.dl-form .frm-fluent-form .ff-btn-submit:focus-visible{outline:3px solid var(--accent);outline-offset:2px}

/* Our border rule above outranks Fluent Forms' error border, so the invalid
   state has to be restored here or the field never changes colour.
   --error is measured: 5.05:1 light, 7.04:1 dark — clears 3:1 for a border
   and 4.5:1 as text, so it is safe for the message too. */
#contact .frm-fluent-form .ff-el-is-error .ff-el-form-control,
#contact .frm-fluent-form .ff-el-form-control[aria-invalid="true"],
.dl-form .frm-fluent-form .ff-el-is-error .ff-el-form-control,
.dl-form .frm-fluent-form .ff-el-form-control[aria-invalid="true"]{border-color:var(--error)}

/* Required markers and validation errors keep Fluent Forms' own red. Recolouring
   them to --accent read as "highlighted" rather than "wrong", and red is the
   convention users expect. Spacing only. */
#contact .frm-fluent-form .error-text,
#contact .frm-fluent-form .text-danger,
.dl-form .frm-fluent-form .error-text,
.dl-form .frm-fluent-form .text-danger{margin-top:6px;font-size:13px}
#contact .ff-message-success,
.dl-form .ff-message-success{padding:24px;background:transparent;border:1px dashed var(--line);border-radius:14px;color:var(--fg);text-align:center}

.site-footer{display:flex;align-items:center;justify-content:space-between;gap:12px;padding-top:22px;padding-bottom:22px;border-top:1px solid var(--line)}
.site-footer .c{font-family:'JetBrains Mono',monospace;font-size:12px;color:var(--muted)}
.to-top{display:inline-flex;align-items:center;gap:6px;min-height:44px;padding:0 14px;border:1px solid var(--line);border-radius:999px;font-family:'JetBrains Mono',monospace;font-size:12px;color:var(--muted);transition:border-color 200ms,color 200ms}
.to-top:hover{border-color:var(--fg);color:var(--fg)}

.hidden{display:none}
.visually-hidden{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}
.scroll-progress{position:fixed;top:0;left:0;height:3px;width:0;background:var(--accent);z-index:50;transition:width 80ms linear}

/* Language suggestion bar. Injected client-side so it cannot poison a cached
   page. First element in <body> so tab order matches visual order. */
.lang-suggest{display:flex;align-items:center;justify-content:center;gap:14px;flex-wrap:wrap;padding:12px 22px;background:var(--surface);border-bottom:1px solid var(--line);font-size:14px}
.lang-suggest a{text-decoration:underline;color:var(--accent)}
.lang-suggest button{min-height:36px;padding:0 12px;background:transparent;border:1px solid var(--line);border-radius:999px;font-family:'JetBrains Mono',monospace;font-size:12px;color:var(--muted);cursor:pointer}

.modal{position:fixed;inset:0;z-index:60;display:none;align-items:flex-end;justify-content:center;padding:0}
.modal.open{display:flex}
.modal-backdrop{position:absolute;inset:0;background:oklch(0.2 0.02 250 / 0.5);opacity:0;transition:opacity 240ms}
.modal.open .modal-backdrop{opacity:1}
/* Mobile is a bottom sheet: the whole card scrolls as one, which is the
   natural sheet gesture. The desktop breakpoint pins the shot and scrolls only
   the body — see the min-width:768px block below. */
.modal-card{position:relative;width:100%;max-width:640px;max-height:92vh;overflow-y:auto;background:var(--bg);border:1px solid var(--line);border-radius:22px 22px 0 0;transform:translateY(24px);opacity:0;transition:transform 260ms cubic-bezier(.16,1,.3,1),opacity 260ms}
.modal.open .modal-card{transform:translateY(0);opacity:1}
.modal-shot{aspect-ratio:16/9;background-color:var(--surface);background-image:repeating-linear-gradient(45deg,var(--line) 0 1px,transparent 1px 11px);display:flex;align-items:center;justify-content:center}
.modal-shot img{width:100%;height:100%;object-fit:cover}
.modal-shot span{font-family:'JetBrains Mono',monospace;font-size:12px;letter-spacing:0.06em;color:var(--muted);background:var(--surface);padding:6px 12px;border-radius:8px}
.modal-body{padding:20px 28px 28px}
.modal-body .mrow{display:flex;align-items:center;gap:10px;margin-bottom:6px}
.modal-body h2{font-weight:700;font-size:26px;letter-spacing:-0.01em;margin:0}
.mbadge{font-family:'JetBrains Mono',monospace;font-size:11px;color:var(--accent-fg);background:var(--accent);padding:2px 8px;border-radius:5px}

/* Gallery thumbnails. Border is the only affordance distinguishing the active
   shot, so it uses the 3:1 token rather than the decorative one. */
.modal-thumbs{display:flex;gap:8px;flex-wrap:wrap;margin-bottom:20px}
.mthumb{width:76px;aspect-ratio:16/9;border-radius:8px;overflow:hidden;background-color:var(--surface);border:2px solid transparent;padding:0;cursor:pointer;display:flex;align-items:center;justify-content:center;transition:border-color 160ms}
.mthumb img{width:100%;height:100%;object-fit:cover;display:block}
.mthumb:hover{border-color:var(--line)}
.mthumb.active{border-color:var(--accent)}

/* Lede and features both come from post content — no custom fields. The first
   paragraph is the lede; a heading labels the list; items get the marker. */
.entry>p:first-of-type{font-size:16px;line-height:1.55;color:var(--muted);margin:12px 0 24px}
/* Any heading level, because the block editor's Heading block defaults to h2
   and authors rarely change it. Whatever level "Key features" ends up as, it
   reads as the small mono label the reference uses — and this sits after
   .modal-body h2 so it wins for headings inside the entry, never the title. */
.entry :is(h1,h2,h3,h4,h5,h6){font-family:'JetBrains Mono',monospace;font-size:11px;font-weight:500;text-transform:uppercase;letter-spacing:0.04em;color:var(--muted);margin:0 0 12px}
.entry ul{list-style:none;margin:0 0 24px;padding:0;display:grid;gap:9px}
.entry li{position:relative;padding-left:20px;font-size:15px;line-height:1.5}
.entry li::before{content:'';position:absolute;left:0;top:8px;width:6px;height:6px;border-radius:2px;background:var(--accent)}

.mtags{display:flex;flex-wrap:wrap;gap:8px;margin:0 0 24px;padding:0;list-style:none}
.mtag{font-family:'JetBrains Mono',monospace;font-size:11px;letter-spacing:0.03em;color:var(--muted);background:var(--surface);border:1px solid var(--line);padding:6px 11px;border-radius:999px}

.modal-actions{display:flex;flex-wrap:wrap;gap:12px}
.modal-actions .btn{flex:1 1 auto;min-width:140px}
.modal-close{position:absolute;top:16px;right:16px;width:40px;height:40px;display:flex;align-items:center;justify-content:center;background:var(--surface);border:1px solid var(--line);border-radius:999px;font-size:18px;line-height:1;cursor:pointer;color:var(--fg);transition:border-color 200ms,color 200ms}
.modal-close:hover{border-color:var(--fg);color:var(--fg)}

/* Analytics consent banner — EU only, shown by davidlee_analytics(). */
.dl-consent{position:fixed;left:16px;right:16px;bottom:16px;z-index:80;max-width:520px;margin:0 auto;padding:18px 20px;background:var(--surface);border:1px solid var(--line-interactive);border-radius:14px;box-shadow:0 12px 40px oklch(0.2 0.02 250 / 0.28)}
.dl-consent[hidden]{display:none}
.dl-consent-text{margin:0 0 14px;font-size:14px;line-height:1.5;color:var(--fg)}
.dl-consent-actions{display:flex;gap:10px}
.dl-consent-actions .btn{flex:1 1 auto;min-width:0}

@media (min-width:480px){ .cta{flex-direction:row} }
@media (min-width:768px){
  header,section,footer{padding-left:48px;padding-right:48px}
  .hero{padding-top:72px;padding-bottom:72px}
  section.block{padding-top:56px;padding-bottom:56px}
  .hero h1{font-size:52px}
  .hero p{font-size:18px}
  .grid{gap:20px;grid-template-columns:1fr 1fr}
  .modal{align-items:center;padding:24px}
  /* Centered dialog now, not a sheet: pin the shot and scroll only the body,
     so the screenshot stays in view while the copy moves under it. The card
     stops scrolling; its children own the overflow. */
  .modal-card{border-radius:22px;display:flex;flex-direction:column;overflow:hidden}
  .modal-card>[data-modal-content]{display:flex;flex-direction:column;flex:1 1 auto;min-height:0}
  .modal-shot{flex:0 0 auto}
  .modal-body{flex:1 1 auto;min-height:0;overflow-y:auto}
}
@media (min-width:1024px){
  header,section,footer{padding-left:72px;padding-right:72px}
  .hero{padding-top:104px;padding-bottom:104px}
  section.block{padding-top:72px;padding-bottom:72px}
  .wrap{max-width:1100px}
  .hero h1{font-size:60px}
  .hero-grid{grid-template-columns:1.35fr 1fr;grid-template-areas:'tag media' 'copy media'}

  .grid.services{grid-template-columns:repeat(4,1fr)}
  .grid.work-grid{grid-template-columns:repeat(3,1fr)}
  .contact-grid{grid-template-columns:1fr 1fr}
  .contact h2{font-size:34px}
}
@media (min-width:1440px){
  header,section,footer{padding-left:72px;padding-right:72px}
  .wrap{max-width:1100px}
  .hero h1{font-size:72px}
}
@media (min-width:1920px){
  header,section,footer{padding-left:112px;padding-right:112px}
  .wrap{max-width:1320px}
  .hero h1{font-size:84px}
}
@media (prefers-reduced-motion:reduce){
  *{transition-duration:0.01ms !important}
}
